package server import ( "bytes" "encoding/binary" "errors" "fmt" "io" "net" ) const ( Magic uint32 = 0xDEADBEEF ) const ( PacketVersion int = 1 ) type RawPacket struct { Magic uint32 Version uint8 Flags uint8 HeaderSize uint16 PayloadSize uint32 Header []byte Payload []byte } type Packet struct { Version int Flags int Headers map[string]string Payload []byte } type PacketDuplex struct { conn net.Conn } func BuildPacket(headers map[string]string, payload []byte) *Packet { return &Packet{ Version: PacketVersion, Flags: 0, // TODO: Headers: headers, Payload: payload, } } func ParseHeaders(rawHeaders []byte, headers *map[string]string) error { i := 0 for i < len(rawHeaders) { if rawHeaders[i] == '\n' { break } var key string for rawHeaders[i] != ':' { if rawHeaders[i] != ' ' { key += string(rawHeaders[i]) } i++ } i++ var value string for rawHeaders[i] != '\n' { if rawHeaders[i] != ' ' { value += string(rawHeaders[i]) } i++ } i++ (*headers)[key] = value } return nil } func SerializeHeaders(headers *map[string]string) []byte { buf := new(bytes.Buffer) for k, v := range(*headers) { fmt.Fprintf(buf, "%s:%s\n", k, v) } fmt.Fprintf(buf, "\n") return buf.Bytes() } func NewPacketDuplex(conn net.Conn) *PacketDuplex { return &PacketDuplex{ conn, } } func (r *PacketDuplex) ReadPacket() (*Packet, error) { rpkt := &RawPacket{} err := binary.Read(r.conn, binary.BigEndian, &rpkt.Magic) if err != nil { return nil, err } if rpkt.Magic != Magic { return nil, errors.New("Magic bytes are invalid") } err = binary.Read(r.conn, binary.BigEndian, &rpkt.Version) if err != nil { return nil, err } err = binary.Read(r.conn, binary.BigEndian, &rpkt.Flags) if err != nil { return nil, err } err = binary.Read(r.conn, binary.BigEndian, &rpkt.HeaderSize) if err != nil { return nil, err } err = binary.Read(r.conn, binary.BigEndian, &rpkt.PayloadSize) if err != nil { return nil, err } rpkt.Header = make([]byte, rpkt.HeaderSize) if _, err := io.ReadFull(r.conn, rpkt.Header); err != nil { return nil, err } rpkt.Payload = make([]byte, rpkt.PayloadSize) if _, err := io.ReadFull(r.conn, rpkt.Payload); err != nil { return nil, err } pkt := &Packet{ Version: int(rpkt.Version), Flags: int(rpkt.Flags), Headers: make(map[string]string), Payload: rpkt.Payload, } ParseHeaders(rpkt.Header, &pkt.Headers) return pkt, nil } func (r *PacketDuplex) WritePacket(packet *Packet) (int, error) { buf := new(bytes.Buffer) if err := binary.Write(buf, binary.BigEndian, Magic); err != nil { return 0, errors.New(fmt.Sprintf("Failed to write magic into packet: %s", err.Error())) } if err := binary.Write(buf, binary.BigEndian, uint8(packet.Version)); err != nil { return 0, errors.New(fmt.Sprintf("Failed to write version into packet: %s", err.Error())) } if err := binary.Write(buf, binary.BigEndian, uint8(packet.Flags)); err != nil { return 0, errors.New(fmt.Sprintf("Failed to write flags into packet: %s", err.Error())) } rawHeaders := SerializeHeaders(&packet.Headers) headerSize := len(rawHeaders) payloadSize := len(packet.Payload) if err := binary.Write(buf, binary.BigEndian, uint16(headerSize)); err != nil { return 0, errors.New(fmt.Sprintf("Failed to write header size into packet: %s", err.Error())) } if err := binary.Write(buf, binary.BigEndian, uint32(payloadSize)); err != nil { return 0, errors.New(fmt.Sprintf("Failed to write payload size into packet: %s", err.Error())) } if _, err := buf.Write(rawHeaders[:headerSize]); err != nil { return 0, errors.New(fmt.Sprintf("Failed to write raw headers: %s", err.Error())) } if _, err := buf.Write(packet.Payload[:payloadSize]); err != nil { return 0, errors.New(fmt.Sprintf("Failed to write payload: %s", err.Error())) } n, err := r.conn.Write(buf.Bytes()) if err != nil { return 0, errors.New(fmt.Sprintf("Failed to send packet over connection: %s", err.Error())) } return n, nil }