github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/libs/niaucchi4/e2e.go (about) 1 package niaucchi4 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "encoding/hex" 7 "errors" 8 "fmt" 9 "log" 10 "net" 11 "time" 12 13 "github.com/ethereum/go-ethereum/rlp" 14 "github.com/patrickmn/go-cache" 15 ) 16 17 // SessionAddr is a net.Addr that represents the ultimate counterparty in an e2e session. 18 type SessionAddr [16]byte 19 20 // NewSessAddr generates a new random sess addr 21 func NewSessAddr() SessionAddr { 22 var k SessionAddr 23 rand.Read(k[:]) 24 return k 25 } 26 27 func (sa SessionAddr) String() string { 28 return fmt.Sprintf("SA-%v", hex.EncodeToString(sa[:])) 29 } 30 31 // Network fulfills net.Addr 32 func (sa SessionAddr) Network() string { 33 return "SESS" 34 } 35 36 type pcReadResult struct { 37 Contents []byte 38 Host net.Addr 39 } 40 41 // E2EConn is a PacketConn implementing the E2E protocol. 42 type E2EConn struct { 43 sidToSess *cache.Cache 44 readQueue chan pcReadResult 45 wire net.PacketConn 46 pktbuf [2048]byte 47 Closed bool 48 } 49 50 // NewE2EConn creates a new e2e connection. 51 func NewE2EConn(wire net.PacketConn) *E2EConn { 52 return &E2EConn{ 53 sidToSess: cache.New(time.Hour, time.Hour), 54 readQueue: make(chan pcReadResult, 1024), 55 wire: wire, 56 } 57 } 58 59 func (e2e *E2EConn) DebugInfo() [][]LinkInfo { 60 var tr [][]LinkInfo 61 for _, v := range e2e.sidToSess.Items() { 62 if !v.Expired() { 63 tr = append(tr, v.Object.(*e2eSession).DebugInfo()) 64 } 65 } 66 return tr 67 } 68 69 func (e2e *E2EConn) genSendCallback() func(e2ePacket, net.Addr) { 70 return func(toSend e2ePacket, dest net.Addr) { 71 buffer := malloc(2048) 72 defer free(buffer) 73 buf := bytes.NewBuffer(buffer[:0]) 74 err := rlp.Encode(buf, toSend) 75 if err != nil { 76 panic(err) 77 } 78 e2e.wire.WriteTo(buf.Bytes(), dest) 79 } 80 } 81 82 // SetSessPath is used by clients to have certain sessions go along certain paths. 83 func (e2e *E2EConn) SetSessPath(sid SessionAddr, host net.Addr) { 84 var sess *e2eSession 85 if sessi, ok := e2e.sidToSess.Get(sid.String()); ok { 86 sess = sessi.(*e2eSession) 87 } else { 88 sess = newSession(sid, e2e.genSendCallback()) 89 } 90 e2e.sidToSess.SetDefault(sid.String(), sess) 91 sess.AddPath(host) 92 } 93 94 // ReadFrom implements PacketConn. 95 func (e2e *E2EConn) ReadFrom(p []byte) (n int, from net.Addr, err error) { 96 for { 97 select { 98 case prr := <-e2e.readQueue: 99 n = copy(p, prr.Contents) 100 from = prr.Host 101 return 102 default: 103 err = e2e.readOnePacket() 104 if err != nil { 105 return 106 } 107 } 108 } 109 } 110 111 // WriteTo implements PacketConn. 112 func (e2e *E2EConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { 113 sessid := addr.(SessionAddr) 114 sessi, ok := e2e.sidToSess.Get(sessid.String()) 115 if !ok { 116 err = errors.New("session is dead") 117 return 118 } 119 sess := sessi.(*e2eSession) 120 e2e.sidToSess.SetDefault(sessid.String(), sess) 121 err = sess.Send(p) 122 if err != nil { 123 return 124 } 125 return 126 } 127 128 // UnderlyingLoss returns the underlying loss. 129 func (e2e *E2EConn) UnderlyingLoss(destAddr net.Addr) (frac float64) { 130 sessid := destAddr.(SessionAddr) 131 sessi, ok := e2e.sidToSess.Get(sessid.String()) 132 if !ok { 133 log.Println("cannot find underlying loss") 134 return 135 } 136 sess := sessi.(*e2eSession) 137 sess.lock.Lock() 138 defer sess.lock.Unlock() 139 rem := sess.info[sess.lastRemid] 140 frac = rem.remoteLoss 141 return 142 } 143 144 // Close closes the underlying socket. 145 func (e2e *E2EConn) Close() error { 146 e2e.Closed = true 147 return e2e.wire.Close() 148 } 149 150 // LocalAddr returns the local address. 151 func (e2e *E2EConn) LocalAddr() net.Addr { 152 return e2e.wire.LocalAddr() 153 } 154 155 // SetDeadline lala 156 func (e2e *E2EConn) SetDeadline(t time.Time) error { 157 return e2e.wire.SetDeadline(t) 158 } 159 160 // SetWriteDeadline lala 161 func (e2e *E2EConn) SetWriteDeadline(t time.Time) error { 162 return e2e.wire.SetDeadline(t) 163 } 164 165 // SetReadDeadline lala 166 func (e2e *E2EConn) SetReadDeadline(t time.Time) error { 167 return e2e.wire.SetDeadline(t) 168 } 169 170 func (e2e *E2EConn) readOnePacket() error { 171 n, from, err := e2e.wire.ReadFrom(e2e.pktbuf[:]) 172 if err != nil { 173 return err 174 } 175 var pkt e2ePacket 176 err = rlp.DecodeBytes(e2e.pktbuf[:n], &pkt) 177 if err != nil { 178 return err 179 } 180 var sess *e2eSession 181 if sessi, ok := e2e.sidToSess.Get(pkt.Session.String()); ok { 182 sess = sessi.(*e2eSession) 183 } else { 184 sess = newSession(pkt.Session, e2e.genSendCallback()) 185 } 186 e2e.sidToSess.SetDefault(pkt.Session.String(), sess) 187 sess.AddPath(from) 188 sess.Input(pkt, from) 189 sess.FlushReadQueue(func(b []byte) { 190 select { 191 case e2e.readQueue <- pcReadResult{b, pkt.Session}: 192 default: 193 if doLogging { 194 log.Println("N4: dropping packet of size", len(b), "because overfull e2e.readQueue") 195 } 196 } 197 }) 198 return nil 199 }