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.
26 disco chan struct{} // close-only
31 errs chan error // don't close
32 timedout chan struct{} // close-only
34 chans [ChannelCount]pktchan // read/write
43 // Only accessed by Peer.processRawPkt.
44 insplit map[seqnum][][]byte
45 inrel map[seqnum][]byte
48 ackchans sync.Map // map[seqnum]chan struct{}
58 // Conn returns the net.PacketConn used to communicate with the Peer.
59 func (p *Peer) Conn() net.PacketConn { return p.conn }
61 // Addr returns the address of the Peer.
62 func (p *Peer) Addr() net.Addr { return p.addr }
64 // Disco returns a channel that is closed when the Peer is closed.
65 func (p *Peer) Disco() <-chan struct{} { return p.disco }
67 // ID returns the ID of the Peer.
68 func (p *Peer) ID() PeerID { return p.id }
70 // IsSrv reports whether the Peer is a server.
71 func (p *Peer) IsSrv() bool {
72 return p.ID() == PeerIDSrv
75 // TimedOut reports whether the Peer has timed out.
76 func (p *Peer) TimedOut() bool {
85 // Recv recieves a packet from the Peer.
86 // You should keep calling this until it returns net.ErrClosed
87 // so it doesn't leak a goroutine.
88 func (p *Peer) Recv() (Pkt, error) {
90 case pkt, ok := <-p.pkts:
96 return Pkt{}, net.ErrClosed
100 case err := <-p.errs:
105 // Close closes the Peer but does not send a disconnect packet.
106 func (p *Peer) Close() error {
126 func newPeer(conn net.PacketConn, addr net.Addr, id, idOfPeer PeerID) *Peer {
133 pkts: make(chan Pkt),
134 disco: make(chan struct{}),
135 errs: make(chan error),
138 for i := range p.chans {
139 p.chans[i] = pktchan{
140 insplit: make(map[seqnum][][]byte),
141 inrel: make(map[seqnum][]byte),
144 outsplitsn: seqnumInit,
145 outrelsn: seqnumInit,
146 outrelwin: seqnumInit,
150 p.timedout = make(chan struct{})
151 p.timeout = time.AfterFunc(ConnTimeout, func() {
158 p.ping = time.NewTicker(PingTimeout)
159 go p.sendPings(p.ping.C)
164 func (p *Peer) sendPings(ping <-chan time.Time) {
165 pkt := rawPkt{Data: []byte{uint8(rawTypeCtl), uint8(ctlPing)}}
170 if _, err := p.sendRaw(pkt); err != nil {
171 if errors.Is(err, net.ErrClosed) {
174 p.errs <- fmt.Errorf("can't send ping: %w", err)
182 // Connect connects to the server on conn
183 // and closes conn when the returned *Peer disconnects.
184 func Connect(conn net.PacketConn, addr net.Addr) *Peer {
185 srv := newPeer(conn, addr, PeerIDSrv, PeerIDNil)
187 pkts := make(chan netPkt)
188 go readNetPkts(conn, pkts, srv.errs)
189 go srv.processNetPkts(pkts)