]> Sergey Matveev's repositories - btrtrc.git/blob - peer_protocol/ut-holepunch/ut-holepunch.go
WIP support for ut_holepunch
[btrtrc.git] / peer_protocol / ut-holepunch / ut-holepunch.go
1 package utHolepunch
2
3 import (
4         "bytes"
5         "encoding/binary"
6         "fmt"
7         "net/netip"
8 )
9
10 const ExtensionName = "ut_holepunch"
11
12 type (
13         Msg struct {
14                 MsgType  MsgType
15                 AddrPort netip.AddrPort
16                 ErrCode  ErrCode
17         }
18         MsgType  byte
19         AddrType byte
20         ErrCode  uint32
21 )
22
23 const (
24         Rendezvous MsgType = iota
25         Connect
26         Error
27 )
28
29 const (
30         Ipv4 AddrType = iota
31         Ipv6 AddrType = iota
32 )
33
34 const (
35         NoSuchPeer ErrCode = iota + 1
36         NotConnected
37         NoSupport
38         NoSelf
39 )
40
41 func (m *Msg) UnmarshalBinary(b []byte) error {
42         if len(b) < 12 {
43                 return fmt.Errorf("buffer too small to be valid")
44         }
45         m.MsgType = MsgType(b[0])
46         b = b[1:]
47         addrType := AddrType(b[0])
48         b = b[1:]
49         var addr netip.Addr
50         switch addrType {
51         case Ipv4:
52                 addr = netip.AddrFrom4([4]byte(b[:4]))
53                 b = b[4:]
54         case Ipv6:
55                 if len(b) < 22 {
56                         return fmt.Errorf("not enough bytes")
57                 }
58                 addr = netip.AddrFrom16([16]byte(b[:16]))
59                 b = b[16:]
60         default:
61                 return fmt.Errorf("unhandled addr type value %v", addrType)
62         }
63         port := binary.BigEndian.Uint16(b[:])
64         b = b[2:]
65         m.AddrPort = netip.AddrPortFrom(addr, port)
66         m.ErrCode = ErrCode(binary.BigEndian.Uint32(b[:]))
67         b = b[4:]
68         if len(b) != 0 {
69                 return fmt.Errorf("%v trailing unused bytes", len(b))
70         }
71         return nil
72 }
73
74 func (m *Msg) MarshalBinary() (_ []byte, err error) {
75         var buf bytes.Buffer
76         buf.Grow(24)
77         buf.WriteByte(byte(m.MsgType))
78         addr := m.AddrPort.Addr()
79         switch {
80         case addr.Is4():
81                 buf.WriteByte(byte(Ipv4))
82         case addr.Is6():
83                 buf.WriteByte(byte(Ipv6))
84         default:
85                 err = fmt.Errorf("unhandled addr type: %v", addr)
86                 return
87         }
88         buf.Write(addr.AsSlice())
89         binary.Write(&buf, binary.BigEndian, m.AddrPort.Port())
90         binary.Write(&buf, binary.BigEndian, m.ErrCode)
91         return buf.Bytes(), nil
92 }