diff options
| author | Felix Hanley <felix@userspace.com.au> | 2018-02-09 08:42:22 +0000 |
|---|---|---|
| committer | Felix Hanley <felix@userspace.com.au> | 2018-02-09 08:42:22 +0000 |
| commit | 2ded0704c8f675c3d92cf2b4874a32c65faf2553 (patch) | |
| tree | c3b437cbe7129ea300d7a98e438b0f5fd3fd8344 /dht/krpc.go | |
| parent | be4f4b36cc7fb46c70364d524d64c7188c1ae0f3 (diff) | |
| download | dhtsearch-2ded0704c8f675c3d92cf2b4874a32c65faf2553.tar.gz dhtsearch-2ded0704c8f675c3d92cf2b4874a32c65faf2553.tar.bz2 | |
Basic DHT functions
Diffstat (limited to 'dht/krpc.go')
| -rw-r--r-- | dht/krpc.go | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/dht/krpc.go b/dht/krpc.go new file mode 100644 index 0000000..a926e81 --- /dev/null +++ b/dht/krpc.go @@ -0,0 +1,103 @@ +package dht + +import ( + "errors" + "fmt" + "math/rand" + "net" +) + +const transIDBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +func newTransactionID() string { + b := make([]byte, 2) + for i := range b { + b[i] = transIDBytes[rand.Int63()%int64(len(transIDBytes))] + } + return string(b) +} + +// makeQuery returns a query-formed data. +func makeQuery(t, q string, a map[string]interface{}) map[string]interface{} { + return map[string]interface{}{ + "t": t, + "y": "q", + "q": q, + "a": a, + } +} + +// makeResponse returns a response-formed data. +func makeResponse(t string, r map[string]interface{}) map[string]interface{} { + return map[string]interface{}{ + "t": t, + "y": "r", + "r": r, + } +} + +// parseMessage parses the basic data received from udp. +// It returns a map value. +func parseMessage(data interface{}) (map[string]interface{}, error) { + response, ok := data.(map[string]interface{}) + if !ok { + return nil, errors.New("response is not dict") + } + + if err := checkKeys(response, [][]string{{"t", "string"}, {"y", "string"}}); err != nil { + return nil, err + } + + return response, nil +} + +// parseKeys parses keys. It just wraps parseKey. +func checkKeys(data map[string]interface{}, pairs [][]string) (err error) { + for _, args := range pairs { + key, t := args[0], args[1] + if err = checkKey(data, key, t); err != nil { + break + } + } + return err +} + +// parseKey parses the key in dict data. `t` is type of the keyed value. +// It's one of "int", "string", "map", "list". +func checkKey(data map[string]interface{}, key string, t string) error { + val, ok := data[key] + if !ok { + return fmt.Errorf("krpc: missing key %s", key) + } + + switch t { + case "string": + _, ok = val.(string) + case "int": + _, ok = val.(int) + case "map": + _, ok = val.(map[string]interface{}) + case "list": + _, ok = val.([]interface{}) + default: + return errors.New("krpc: invalid type") + } + + if !ok { + return errors.New("krpc: key type mismatch") + } + + return nil +} + +// Swiped from nictuku +func compactNodeInfoToString(cni string) string { + if len(cni) == 6 { + return fmt.Sprintf("%d.%d.%d.%d:%d", cni[0], cni[1], cni[2], cni[3], (uint16(cni[4])<<8)|uint16(cni[5])) + } else if len(cni) == 18 { + b := []byte(cni[:16]) + return fmt.Sprintf("[%s]:%d", net.IP.String(b), (uint16(cni[16])<<8)|uint16(cni[17])) + } else { + return "" + } +} |
