12 // ConnTimeout is the amount of time after no packets being received
13 // from a Peer that it is automatically disconnected.
14 ConnTimeout = 30 * time.Second
16 // ConnTimeout is the amount of time after no packets being sent
17 // to a Peer that a CtlPing is automatically sent to prevent timeout.
18 PingTimeout = 5 * time.Second
21 // A Peer is a connection to a client or server.
27 disco chan struct{} // close-only
32 errs chan error // don't close
33 timedOut chan struct{} // close-only
35 chans [ChannelCount]pktchan // read/write
43 // Conn returns the net.PacketConn used to communicate with the Peer.
44 func (p *Peer) Conn() net.PacketConn { return p.pc }
46 // Addr returns the address of the Peer.
47 func (p *Peer) Addr() net.Addr { return p.addr }
49 // Disco returns a channel that is closed when the Peer is closed.
50 func (p *Peer) Disco() <-chan struct{} { return p.disco }
52 // ID returns the ID of the Peer.
53 func (p *Peer) ID() PeerID { return p.id }
55 // IsSrv reports whether the Peer is a server.
56 func (p *Peer) IsSrv() bool {
57 return p.ID() == PeerIDSrv
60 // TimedOut reports whether the Peer has timed out.
61 func (p *Peer) TimedOut() bool {
76 // Only accessed by Peer.processRawPkt.
77 inSplit *[65536]*inSplit
81 ackChans sync.Map // map[seqnum]chan struct{}
91 // Recv recieves a packet from the Peer.
92 // You should keep calling this until it returns net.ErrClosed
93 // so it doesn't leak a goroutine.
94 func (p *Peer) Recv() (Pkt, error) {
96 case pkt, ok := <-p.pkts:
102 return Pkt{}, net.ErrClosed
106 case err := <-p.errs:
111 // Close closes the Peer but does not send a disconnect packet.
112 func (p *Peer) Close() error {
132 func newPeer(pc net.PacketConn, addr net.Addr, id, idOfPeer PeerID) *Peer {
139 pkts: make(chan Pkt),
140 disco: make(chan struct{}),
141 errs: make(chan error),
144 if conn, ok := pc.(net.Conn); ok && conn.RemoteAddr() != nil {
148 for i := range p.chans {
149 p.chans[i] = pktchan{
150 inSplit: new([65536]*inSplit),
151 inRel: new([65536][]byte),
154 outSplitSN: seqnumInit,
155 outRelSN: seqnumInit,
156 outRelWin: seqnumInit,
160 p.timedOut = make(chan struct{})
161 p.timeout = time.AfterFunc(ConnTimeout, func() {
168 p.ping = time.NewTicker(PingTimeout)
169 go p.sendPings(p.ping.C)
174 func (p *Peer) sendPings(ping <-chan time.Time) {
175 pkt := rawPkt{Data: []byte{uint8(rawTypeCtl), uint8(ctlPing)}}
180 if _, err := p.sendRaw(pkt); err != nil {
181 if errors.Is(err, net.ErrClosed) {
184 p.errs <- fmt.Errorf("can't send ping: %w", err)
192 // Connect connects to addr using pc
193 // and closes pc when the returned *Peer disconnects.
194 func Connect(pc net.PacketConn, addr net.Addr) *Peer {
195 srv := newPeer(pc, addr, PeerIDSrv, PeerIDNil)
197 pkts := make(chan netPkt)
198 go readNetPkts(pc, pkts, srv.errs)
199 go srv.processNetPkts(pkts)