diff options
Diffstat (limited to 'src/nslcd_proto/io.go')
-rw-r--r-- | src/nslcd_proto/io.go | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/src/nslcd_proto/io.go b/src/nslcd_proto/io.go new file mode 100644 index 0000000..0804e98 --- /dev/null +++ b/src/nslcd_proto/io.go @@ -0,0 +1,149 @@ +package nslcd_proto + +import ( + "encoding/binary" + "fmt" + "io" + "net" + "reflect" +) + +//#include <sys/socket.h> +import "C" + +type NslcdObject interface { + NslcdWrite(fd io.Writer) +} +type NslcdObjectPtr interface { + NslcdRead(fd io.Reader) +} + +func write(fd io.Writer, data interface{}) { + switch data := data.(type) { + // basic data types + case []byte: + _, err := fd.Write(data) + if err != nil { + panic(err) + } + case int32: + err := binary.Write(fd, binary.BigEndian, data) + if err != nil { + panic(err) + } + case NslcdObject: + data.NslcdWrite(fd) + // composite datatypes + case string: + write(fd, int32(len(data))) + write(fd, []byte(data)) + case []string: + write(fd, int32(len(data))) + for _, item := range data { + write(fd, item) + } + case net.IP: + var af int32 = -1 + switch len(data) { + case net.IPv4len: + af = C.AF_INET + case net.IPv6len: + af = C.AF_INET6 + } + var bytes []byte + if af < 0 { + bytes = make([]byte, 0) + } else { + bytes = data + } + write(fd, af) + write(fd, int32(len(bytes))) + write(fd, bytes) + case []net.IP: + write(fd, int32(len(data))) + for _, item := range data { + write(fd, item) + } + default: + v := reflect.ValueOf(data) + switch v.Kind() { + case reflect.Struct: + for i, n := 0, v.NumField(); i < n; i++ { + write(fd, v.Field(i).Interface()) + } + default: + panic("Invalid structure for NSLCD protocol data") + } + } + panic("not reached") +} + +func read(fd io.Reader, data interface{}) { + switch data := data.(type) { + // basic data types + case *[]byte: + _, err := fd.Read(*data) + if err != nil { + panic(err) + } + case *int32: + err := binary.Read(fd, binary.BigEndian, data) + if err != nil { + panic(err) + } + case NslcdObjectPtr: + data.NslcdRead(fd) + // composite datatypes + case *string: + var len int32 + read(fd, &len) + buf := make([]byte, len) + read(fd, &buf) + *data = string(buf) + case *[]string: + var num int32 + read(fd, &num) + *data = make([]string, num) + for i := 0; i < int(num); i++ { + read(fd, &((*data)[i])) + } + case *net.IP: + var af int32 + read(fd, &af) + var _len int32 + switch af { + case C.AF_INET: + _len = net.IPv4len + case C.AF_INET6: + _len = net.IPv6len + default: + panic(NslcdError(fmt.Sprintf("incorrect address family specified: %d", af))) + } + var len int32 + read(fd, &len) + if len != _len { + panic(NslcdError(fmt.Sprintf("address length incorrect: %d", len))) + } + buf := make([]byte, len) + read(fd, &buf) + *data = buf + case *[]net.IP: + var num int32 + read(fd, &num) + *data = make([]net.IP, num) + for i := 0; i < int(num); i++ { + read(fd, &((*data)[i])) + } + default: + v := reflect.ValueOf(data) + switch v.Kind() { + case reflect.Struct: + for i, n := 0, v.NumField(); i < n; i++ { + read(fd, v.Field(i).Interface()) + } + default: + panic("Invalid structure for NSLCD protocol data") + } + } + panic("not reached") +} |