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  }