completed string

This commit is contained in:
Hayden Parker
2016-02-15 00:34:29 -08:00
parent 9ccd358086
commit 5677126bd7
4 changed files with 151 additions and 63 deletions

View File

@ -33,6 +33,12 @@ func (destination Destination) Certificate() (Certificate, error) {
return KeysAndCert(destination).Certificate() return KeysAndCert(destination).Certificate()
} }
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error) {
keys_and_cert, remainder, err := ReadKeysAndCert(data)
destination = Destination(keys_and_cert)
return
}
// //
// Generate the I2P base32 address for this Destination. // Generate the I2P base32 address for this Destination.
// //

View File

@ -1,14 +1,54 @@
package common package common
/*
I2P RouterAddress
https://geti2p.net/en/docs/spec/common-structures#struct_RouterAddress
Accurate for version 0.9.24
+----+----+----+----+----+----+----+----+
|cost| expiration
+----+----+----+----+----+----+----+----+
| transport_style |
+----+----+----+----+-//-+----+----+----+
| |
+ +
| options |
~ ~
~ ~
| |
+----+----+----+----+----+----+----+----+
cost :: Integer
length -> 1 byte
case 0 -> free
case 255 -> expensive
expiration :: Date (must be all zeros, see notes below)
length -> 8 bytes
case null -> never expires
transport_style :: String
length -> 1-256 bytes
options :: Mapping
*/
import ( import (
"errors" "errors"
log "github.com/Sirupsen/logrus"
)
const (
ROUTER_ADDRESS_MIN_LENGTH = 9
) )
type RouterAddress []byte type RouterAddress []byte
// //
// Return the cost integer for this RouterAddress and any errors // Return the cost integer for this RouterAddress and any errors encountered
// encountered parsing the RouterAddress. // parsing the RouterAddress.
// //
func (router_address RouterAddress) Cost() (cost int, err error) { func (router_address RouterAddress) Cost() (cost int, err error) {
verr, exit := router_address.checkValid() verr, exit := router_address.checkValid()
@ -21,8 +61,8 @@ func (router_address RouterAddress) Cost() (cost int, err error) {
} }
// //
// Return the Date this RouterAddress expires and any errors // Return the Date this RouterAddress expires and any errors encountered
// encountered parsing the RouterAddress. // parsing the RouterAddress.
// //
func (router_address RouterAddress) Expiration() (date Date, err error) { func (router_address RouterAddress) Expiration() (date Date, err error) {
verr, exit := router_address.checkValid() verr, exit := router_address.checkValid()
@ -30,14 +70,13 @@ func (router_address RouterAddress) Expiration() (date Date, err error) {
if exit { if exit {
return return
} }
copy(date[:], router_address[1:9]) copy(date[:], router_address[1:ROUTER_ADDRESS_MIN_LENGTH])
return return
} }
// //
// Return the Transport type for this RouterAddress expire // Return the Transport type for this RouterAddress and any errors encountered
// and any errors encountered parsing the RouterAddress. // parsing the RouterAddress.
//
// //
func (router_address RouterAddress) TransportStyle() (str String, err error) { func (router_address RouterAddress) TransportStyle() (str String, err error) {
verr, exit := router_address.checkValid() verr, exit := router_address.checkValid()
@ -45,13 +84,13 @@ func (router_address RouterAddress) TransportStyle() (str String, err error) {
if exit { if exit {
return return
} }
str, _, err = ReadString(router_address[9:]) str, _, err = ReadString(router_address[ROUTER_ADDRESS_MIN_LENGTH:])
return return
} }
// //
// Return the Mapping containing the options for this // Return the Mapping containing the options for this RouterAddress and any
// RouterAddress and any parsing errors. // errors encountered parsing the RouterAddress.
// //
func (router_address RouterAddress) Options() (mapping Mapping, err error) { func (router_address RouterAddress) Options() (mapping Mapping, err error) {
verr, exit := router_address.checkValid() verr, exit := router_address.checkValid()
@ -59,7 +98,7 @@ func (router_address RouterAddress) Options() (mapping Mapping, err error) {
if exit { if exit {
return return
} }
_, remainder, _ := ReadString(router_address[9:]) _, remainder, err := ReadString(router_address[ROUTER_ADDRESS_MIN_LENGTH:])
if len(remainder) == 0 { if len(remainder) == 0 {
return return
} }
@ -68,24 +107,29 @@ func (router_address RouterAddress) Options() (mapping Mapping, err error) {
} }
// //
// Check if the RouterAddress is empty or if it is too small // Check if the RouterAddress is empty or if it is too small to contain valid data.
// to contain valid data
// //
func (router_address RouterAddress) checkValid() (err error, exit bool) { func (router_address RouterAddress) checkValid() (err error, exit bool) {
addr_len := len(router_address) addr_len := len(router_address)
exit = false exit = false
if addr_len == 0 { if addr_len == 0 {
log.WithFields(log.Fields{
"reason": "no data",
}).Error("invalid router address")
err = errors.New("error parsing RouterAddress: no data") err = errors.New("error parsing RouterAddress: no data")
exit = true exit = true
} else if addr_len < 9 { } else if addr_len < ROUTER_ADDRESS_MIN_LENGTH {
log.WithFields(log.Fields{
"reason": "data too small (len < ROUTER_ADDRESS_MIN_LENGTH)",
}).Warn("router address format warning")
err = errors.New("warning parsing RouterAddress: data too small") err = errors.New("warning parsing RouterAddress: data too small")
} }
return return
} }
// //
// Given a slice of bytes, read a RouterAddress, returning the remaining // Given a slice of bytes, read a RouterAddress, returning the remaining bytes and any
// bytes and any errors encountered parsing the RouterAddress // errors encountered parsing the RouterAddress.
// //
func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error) { func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error) {
test_address := RouterAddress(data) test_address := RouterAddress(data)
@ -93,8 +137,8 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
if err != nil { if err != nil {
return return
} }
router_address = append(router_address, data[:9]...) router_address = append(router_address, data[:ROUTER_ADDRESS_MIN_LENGTH]...)
str, remainder, err := ReadString(data[9:]) str, remainder, err := ReadString(data[ROUTER_ADDRESS_MIN_LENGTH:])
if err != nil { if err != nil {
return return
} }
@ -106,6 +150,6 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
mapping = remainder[:map_size+2] mapping = remainder[:map_size+2]
router_address = append(router_address, mapping...) router_address = append(router_address, mapping...)
} }
remainder = data[9+len(str)+len(mapping):] remainder = data[ROUTER_ADDRESS_MIN_LENGTH+len(str)+len(mapping):]
return return
} }

View File

@ -1,9 +1,20 @@
package common package common
/*
I2P RouterIdentity
https://geti2p.net/en/docs/spec/common-structures#struct_RouterIdentity
Accurate for version 0.9.24
Identical to KeysAndCert
*/
import ( import (
"github.com/bounce-chat/go-i2p/lib/crypto" "github.com/bounce-chat/go-i2p/lib/crypto"
) )
//
// A RouterIdentity is identical to KeysAndCert.
//
type RouterIdentity []byte type RouterIdentity []byte
func (router_identity RouterIdentity) PublicKey() (crypto.PublicKey, error) { func (router_identity RouterIdentity) PublicKey() (crypto.PublicKey, error) {
@ -18,7 +29,8 @@ func (router_identity RouterIdentity) Certificate() (Certificate, error) {
return KeysAndCert(router_identity).Certificate() return KeysAndCert(router_identity).Certificate()
} }
func ReadRouterIdentity(data []byte) (RouterIdentity, []byte, error) { func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error) {
keys_and_certs, remainder, err := ReadKeysAndCert(data) keys_and_cert, remainder, err := ReadKeysAndCert(data)
return RouterIdentity(keys_and_certs), remainder, err router_identity = RouterIdentity(keys_and_cert)
return
} }

View File

@ -1,84 +1,110 @@
package common package common
/*
I2P String
https://geti2p.net/en/docs/spec/common-structures#type_String
Accurate for version 0.9.24
*/
import ( import (
"errors" "errors"
log "github.com/Sirupsen/logrus"
)
const (
STRING_MAX_LENGTH = 256
) )
type String []byte type String []byte
// //
// Look up the length of the string, reporting // Look up the length of the string, reporting errors if the string is
// errors if the string is invalid or the specified // invalid or the specified length does not match the provided data.
// length does not match the provided data.
// //
func (str String) Length() (int, error) { func (str String) Length() (length int, err error) {
if len(str) == 0 { if len(str) == 0 {
// log log.WithFields(log.Fields{
return 0, errors.New("error parsing string: zero length") "reason": "no data",
}).Error("error parsing string")
err = errors.New("error parsing string: zero length")
return
} }
length := Integer([]byte{byte(str[0])}) length = Integer([]byte{byte(str[0])})
inferred_len := length + 1 inferred_len := length + 1
str_len := len(str) str_len := len(str)
if inferred_len > str_len { if inferred_len > str_len {
// log log.WithFields(log.Fields{
return length, errors.New("string parsing warning: string data is shorter than specified by length") "string_bytes_length": str_len,
"string_length_field": length,
"expected_bytes_length": inferred_len,
"reason": "data shorter than specified",
}).Warn("string format warning")
err = errors.New("string parsing warning: string data is shorter than specified by length")
} else if str_len > inferred_len { } else if str_len > inferred_len {
//log log.WithFields(log.Fields{
return length, errors.New("string parsing warning: string contains data beyond length") "string_bytes_length": str_len,
"string_length_field": length,
"expected_bytes_length": inferred_len,
"reason": "data longer than specified",
}).Warn("string format warning")
err = errors.New("string parsing warning: string contains data beyond length")
} }
return length, nil return
} }
// //
// Return the string data and any errors // Return the string data and any errors encountered by Length.
// encountered by Length.
// //
func (str String) Data() (string, error) { func (str String) Data() (data string, err error) {
length, err := str.Length() length, err := str.Length()
if err != nil { if err != nil {
switch err.Error() { switch err.Error() {
case "error parsing string: zero length": case "error parsing string: zero length":
return "", err return
case "string parsing warning: string data is shorter than specified by length": case "string parsing warning: string data is shorter than specified by length":
return string(str[1:]), err data = string(str[1:])
return
case "string parsing warning: string contains data beyond length": case "string parsing warning: string contains data beyond length":
return string(str[1 : length+1]), err data = string(str[1 : length+1])
return
} }
} }
return string(str[1:]), nil data = string(str[1:])
return
} }
// //
// This function takes an unformatted go string // This function takes an unformatted Go string and returns a String
// and returns a String and any errors encountered // and any errors encountered during the encoding.
// during the encoding.
// //
func ToI2PString(data string) (String, error) { func ToI2PString(data string) (str String, err error) {
data_len := len(data) data_len := len(data)
if data_len >= 256 { if data_len >= STRING_MAX_LENGTH {
return make([]byte, 0), errors.New("cannot store that much data in I2P string") log.WithFields(log.Fields{
"string_len": data_len,
"max_len": STRING_MAX_LENGTH,
"reason": "too much data",
}).Error("cannot create I2P string")
err = errors.New("cannot store that much data in I2P string")
return
} }
i2p_string := []byte{byte(data_len)} i2p_string := []byte{byte(data_len)}
i2p_string = append(i2p_string, []byte(data)...) i2p_string = append(i2p_string, []byte(data)...)
return String(i2p_string), nil str = String(i2p_string)
return
} }
// //
// Read a string from a slice of bytes, returning // Read a string from a slice of bytes, returning any extra data on the end
// any extra data on the end of the slice. // of the slice and any errors encountered parsing the String.
// //
func ReadString(data []byte) (String, []byte, error) { func ReadString(data []byte) (str String, remainder []byte, err error) {
str := String(data) str = String(data)
length, err := String(data).Length() length, err := String(data).Length()
if err != nil { if err != nil && err.Error() == "string parsing warning: string contains data beyond length" {
switch err.Error() { str = String(data[:length+1])
case "error parsing string: zero length": remainder = data[length+1:]
return String{}, make([]byte, 0), err err = nil
case "string parsing warning: string data is shorter than specified by length":
return str, make([]byte, 0), err
case "string parsing warning: string contains data beyond length":
return String(str[:length+1]), str[length+1:], nil //err
}
} }
return str, make([]byte, 0), nil return
} }