github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/libs/fastudp/socket.go (about) 1 package fastudp 2 3 import ( 4 "io" 5 "log" 6 "net" 7 "runtime" 8 "time" 9 10 "golang.org/x/net/ipv4" 11 "golang.org/x/time/rate" 12 "gopkg.in/tomb.v1" 13 ) 14 15 const sendQuantum = 128 16 17 // Conn wraps an underlying UDPConn and batches stuff to it. 18 type Conn struct { 19 sock *net.UDPConn 20 pconn *ipv4.PacketConn 21 death *tomb.Tomb 22 23 writeBuf chan ipv4.Message 24 readBuf []ipv4.Message 25 readPtr int 26 } 27 28 // NewConn creates a new Conn. 29 func NewConn(conn *net.UDPConn) net.PacketConn { 30 err := conn.SetWriteBuffer(261244) 31 if err != nil { 32 panic(err) 33 } 34 err = conn.SetReadBuffer(261244) 35 if err != nil { 36 panic(err) 37 } 38 //return conn 39 if runtime.GOOS != "linux" { 40 return conn 41 } 42 c := &Conn{ 43 sock: conn, 44 pconn: ipv4.NewPacketConn(conn), 45 writeBuf: make(chan ipv4.Message, sendQuantum*2), 46 death: new(tomb.Tomb), 47 readPtr: -1, 48 } 49 for i := 0; i < sendQuantum; i++ { 50 c.readBuf = append(c.readBuf, ipv4.Message{ 51 Buffers: [][]byte{malloc(2048)}, 52 }) 53 } 54 go c.bkgWrite() 55 return c 56 } 57 58 // 1000Hz syscall limiter 59 var limiter = rate.NewLimiter(1000, 100) 60 61 var spamLimiter = rate.NewLimiter(1, 10) 62 63 func (conn *Conn) bkgWrite() { 64 defer conn.pconn.Close() 65 defer conn.sock.Close() 66 // 67 //log.Println("bkgWrite started") 68 var towrite []ipv4.Message 69 for { 70 //limiter.Wait(context.Background()) 71 select { 72 case first := <-conn.writeBuf: 73 towrite = append(towrite, first) 74 for len(towrite) < sendQuantum { 75 select { 76 case next := <-conn.writeBuf: 77 towrite = append(towrite, next) 78 default: 79 goto out 80 } 81 } 82 out: 83 for len(towrite) > 0 { 84 n, err := conn.pconn.WriteBatch(towrite, 0) 85 if err != nil { 86 log.Println("kill", err) 87 conn.death.Kill(err) 88 return 89 } 90 for i := 0; i < n; i++ { 91 free(towrite[i].Buffers[0]) 92 towrite[i].Buffers = nil 93 } 94 towrite = towrite[n:] 95 } 96 case <-conn.death.Dying(): 97 return 98 } 99 } 100 } 101 102 // ReadFrom reads a packet from the connection. 103 func (conn *Conn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { 104 // if OOB, reset 105 if conn.readPtr >= len(conn.readBuf) { 106 conn.readPtr = -1 107 } 108 // read more data if needed 109 for conn.readPtr < 0 { 110 // first, extend readBuf to its full size. 111 conn.readBuf = conn.readBuf[:sendQuantum] 112 // then, we fill readBuf as much as we can. 113 fillCnt, e := conn.pconn.ReadBatch(conn.readBuf, 0) 114 if e != nil { 115 conn.death.Kill(e) 116 err = e 117 return 118 } 119 if fillCnt > 0 { 120 // finally, we resize readBuf to its proper size. 121 conn.readBuf = conn.readBuf[:fillCnt] 122 conn.readPtr = 0 123 } 124 } 125 // get the data 126 gogo := conn.readBuf[conn.readPtr] 127 conn.readPtr++ 128 copy(p, gogo.Buffers[0]) 129 n = gogo.N 130 addr = gogo.Addr 131 return 132 } 133 134 // WriteTo writes to a given address. 135 func (conn *Conn) WriteTo(p []byte, addr net.Addr) (n int, err error) { 136 pCopy := malloc(len(p)) 137 copy(pCopy, p) 138 msg := ipv4.Message{ 139 Buffers: [][]byte{pCopy}, 140 Addr: addr, 141 } 142 select { 143 case conn.writeBuf <- msg: 144 case <-conn.death.Dying(): 145 err = conn.death.Err() 146 return 147 // default: 148 // free(pCopy) 149 } 150 return len(p), nil 151 } 152 153 // Close closes the connection. 154 func (conn *Conn) Close() error { 155 err := conn.sock.Close() 156 conn.death.Kill(io.ErrClosedPipe) 157 return err 158 } 159 160 // SetDeadline sets a deadline. 161 func (conn *Conn) SetDeadline(t time.Time) error { 162 return conn.sock.SetDeadline(t) 163 } 164 165 // SetReadDeadline sets a read deadline. 166 func (conn *Conn) SetReadDeadline(t time.Time) error { 167 return conn.sock.SetReadDeadline(t) 168 } 169 170 // SetWriteDeadline sets a write deadline. 171 func (conn *Conn) SetWriteDeadline(t time.Time) error { 172 return conn.sock.SetWriteDeadline(t) 173 } 174 175 // LocalAddr returns the local address. 176 func (conn *Conn) LocalAddr() net.Addr { 177 return conn.sock.LocalAddr() 178 } 179 180 // RemoteAddr returns the remote address. 181 func (conn *Conn) RemoteAddr() net.Addr { 182 return conn.sock.RemoteAddr() 183 }