github.com/anacrolix/torrent@v1.61.0/tracker/udp/dispatcher.go (about) 1 package udp 2 3 import ( 4 "bytes" 5 "fmt" 6 "net" 7 "sync" 8 ) 9 10 // Maintains a mapping of transaction IDs to handlers. 11 type Dispatcher struct { 12 mu sync.RWMutex 13 transactions map[TransactionId]Transaction 14 } 15 16 // The caller owns b. 17 func (me *Dispatcher) Dispatch(b []byte, addr net.Addr) error { 18 buf := bytes.NewBuffer(b) 19 var rh ResponseHeader 20 err := Read(buf, &rh) 21 if err != nil { 22 return err 23 } 24 me.mu.RLock() 25 defer me.mu.RUnlock() 26 if t, ok := me.transactions[rh.TransactionId]; ok { 27 t.h(DispatchedResponse{ 28 Header: rh, 29 Body: append([]byte(nil), buf.Bytes()...), 30 Addr: addr, 31 }) 32 return nil 33 } else { 34 return fmt.Errorf("unknown transaction id %v", rh.TransactionId) 35 } 36 } 37 38 func (me *Dispatcher) forgetTransaction(id TransactionId) { 39 me.mu.Lock() 40 defer me.mu.Unlock() 41 delete(me.transactions, id) 42 } 43 44 func (me *Dispatcher) NewTransaction(h TransactionResponseHandler) Transaction { 45 me.mu.Lock() 46 defer me.mu.Unlock() 47 for { 48 id := RandomTransactionId() 49 if _, ok := me.transactions[id]; ok { 50 continue 51 } 52 t := Transaction{ 53 d: me, 54 h: h, 55 id: id, 56 } 57 if me.transactions == nil { 58 me.transactions = make(map[TransactionId]Transaction) 59 } 60 me.transactions[id] = t 61 return t 62 } 63 } 64 65 type DispatchedResponse struct { 66 Header ResponseHeader 67 // Response payload, after the header. 68 Body []byte 69 // Response source address 70 Addr net.Addr 71 }