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  }