github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/libs/niaucchi4/wrapper.go (about) 1 package niaucchi4 2 3 import ( 4 "io" 5 "log" 6 "math/rand" 7 "net" 8 "sync" 9 "time" 10 11 "gopkg.in/tomb.v1" 12 ) 13 14 type wrapperRead struct { 15 bts []byte 16 rmAddr net.Addr 17 } 18 19 // Wrapper is a PacketConn that can be hot-replaced by other PacketConns on I/O failure or manually. It squelches any errors bubbling up. 20 type Wrapper struct { 21 wireMap map[net.Addr]net.PacketConn 22 expireMap map[net.Addr]time.Time 23 getConn func() net.PacketConn 24 wmlock sync.Mutex 25 incoming chan wrapperRead 26 death tomb.Tomb 27 } 28 29 // Wrap creates a new Wrapper instance. 30 func Wrap(getConn func() net.PacketConn) *Wrapper { 31 return &Wrapper{ 32 wireMap: make(map[net.Addr]net.PacketConn), 33 expireMap: make(map[net.Addr]time.Time), 34 getConn: getConn, 35 incoming: make(chan wrapperRead, 128), 36 } 37 } 38 39 func (w *Wrapper) getExpire(addr net.Addr) time.Time { 40 w.wmlock.Lock() 41 defer w.wmlock.Unlock() 42 return w.expireMap[addr] 43 } 44 45 func (w *Wrapper) setExpire(addr net.Addr, t time.Time) { 46 w.wmlock.Lock() 47 defer w.wmlock.Unlock() 48 w.expireMap[addr] = t 49 } 50 51 func (w *Wrapper) getWire(addr net.Addr) net.PacketConn { 52 w.wmlock.Lock() 53 defer w.wmlock.Unlock() 54 retry: 55 wire, ok := w.wireMap[addr] 56 if !ok { 57 newWire := w.getConn() 58 incrOpenWires() 59 w.wireMap[addr] = newWire 60 if doLogging { 61 log.Println("N4: set", addr, "=>", newWire.LocalAddr()) 62 } 63 go func() { 64 defer newWire.Close() 65 // delete on exit 66 defer func() { 67 w.wmlock.Lock() 68 if w.wireMap[addr] != newWire { 69 if doLogging { 70 log.Println("N4: wire already replaced, don't delete") 71 } 72 } else { 73 delete(w.wireMap, addr) 74 } 75 w.wmlock.Unlock() 76 }() 77 buf := malloc(2048) 78 for { 79 n, a, err := newWire.ReadFrom(buf) 80 if err != nil { 81 return 82 } 83 newbuf := malloc(n) 84 copy(newbuf, buf) 85 select { 86 case w.incoming <- wrapperRead{newbuf, a}: 87 case <-w.death.Dying(): 88 return 89 } 90 } 91 }() 92 goto retry 93 } 94 return wire 95 } 96 97 func (w *Wrapper) ReadFrom(p []byte) (n int, addr net.Addr, err error) { 98 select { 99 case wrapped := <-w.incoming: 100 n = copy(p, wrapped.bts) 101 addr = wrapped.rmAddr 102 free(wrapped.bts) 103 case <-w.death.Dying(): 104 err = w.death.Err() 105 } 106 return 107 } 108 109 var openWires int64 110 111 func incrOpenWires() { 112 //log.Println("openWires => ", atomic.AddInt64(&openWires, 1)) 113 } 114 115 func decrOpenWires() { 116 //log.Println("openWires => ", atomic.AddInt64(&openWires, -1)) 117 } 118 119 func (w *Wrapper) WriteTo(b []byte, addr net.Addr) (int, error) { 120 wire := w.getWire(addr) 121 wire.WriteTo(b, addr) 122 now := time.Now() 123 expire := w.getExpire(addr) 124 delayTime := time.Second 125 if now.After(expire) { 126 w.setExpire(addr, now.Add(delayTime+time.Millisecond*time.Duration(rand.ExpFloat64()*1000))) 127 zeroTime := time.Time{} 128 if expire != zeroTime { 129 w.wmlock.Lock() 130 if w.wireMap[addr] == wire { 131 delete(w.wireMap, addr) 132 } 133 w.wmlock.Unlock() 134 go func() { 135 time.Sleep(delayTime * 2) 136 decrOpenWires() 137 wire.Close() 138 }() 139 if doLogging { 140 log.Println("N4: wrapper killing", wire.LocalAddr()) 141 } 142 } 143 } 144 return len(b), nil 145 } 146 147 func (w *Wrapper) Close() error { 148 w.wmlock.Lock() 149 defer w.wmlock.Unlock() 150 w.death.Kill(io.ErrClosedPipe) 151 for _, conn := range w.wireMap { 152 conn.Close() 153 } 154 return nil 155 } 156 157 func (w *Wrapper) LocalAddr() net.Addr { 158 w.wmlock.Lock() 159 defer w.wmlock.Unlock() 160 return nil 161 } 162 163 func (w *Wrapper) SetDeadline(t time.Time) error { 164 w.wmlock.Lock() 165 defer w.wmlock.Unlock() 166 return nil 167 } 168 169 func (w *Wrapper) SetReadDeadline(t time.Time) error { 170 w.wmlock.Lock() 171 defer w.wmlock.Unlock() 172 return nil 173 } 174 func (w *Wrapper) SetWriteDeadline(t time.Time) error { 175 w.wmlock.Lock() 176 defer w.wmlock.Unlock() 177 return nil 178 } 179 180 var bufPool = &sync.Pool{ 181 New: func() interface{} { 182 return make([]byte, 2048) 183 }, 184 } 185 186 func malloc(n int) []byte { 187 return bufPool.Get().([]byte)[:n] 188 } 189 190 func free(bts []byte) { 191 bufPool.Put(bts[:2048]) 192 }