package nslcd_proto import ( "encoding/binary" "fmt" "io" "net" "reflect" "syscall" ) 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 = syscall.AF_INET case net.IPv6len: af = syscall.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 syscall.AF_INET: _len = net.IPv4len case syscall.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") }