github.com/weedge/lib@v0.0.0-20230424045628-a36dcc1d90e4/poller/conn.go (about)

     1  package poller
     2  
     3  import (
     4  	"sync/atomic"
     5  	"syscall"
     6  	"time"
     7  
     8  	"github.com/weedge/lib/log"
     9  )
    10  
    11  // Conn keepalive connection
    12  type Conn struct {
    13  	server       *Server     // server reference
    14  	pollerFD     int         // event poller File descriptor
    15  	fd           int         // socket connect File descriptor
    16  	addr         string      // peer address
    17  	buffer       *Buffer     // Read the buffer
    18  	lastReadTime time.Time   // Time of last read
    19  	data         interface{} // Business custom data, used as an extension
    20  }
    21  
    22  // newConn create tcp connection
    23  func newConn(pollerFD, fd int, addr string, server *Server) *Conn {
    24  	return &Conn{
    25  		server:       server,
    26  		pollerFD:     pollerFD,
    27  		fd:           fd,
    28  		addr:         addr,
    29  		buffer:       NewBuffer(server.readBufferPool.Get().([]byte)),
    30  		lastReadTime: time.Now(),
    31  	}
    32  }
    33  
    34  // GetFd gets the file descriptor
    35  func (c *Conn) GetFd() int {
    36  	return c.fd
    37  }
    38  
    39  // GetAddr gets the client address
    40  func (c *Conn) GetAddr() string {
    41  	return c.addr
    42  }
    43  
    44  // GetAddr gets the conn buff
    45  func (c *Conn) GetBuff() *Buffer {
    46  	return c.buffer
    47  }
    48  
    49  // Read
    50  // block read bytes until read readBufferLen bytes from connect fd
    51  func (c *Conn) Read() error {
    52  	c.lastReadTime = time.Now()
    53  	fd := c.GetFd()
    54  	for {
    55  		err := c.buffer.ReadFromFD(fd)
    56  		if err != nil {
    57  			// There is no data to read in the buffer
    58  			if err == syscall.EAGAIN {
    59  				return nil
    60  			}
    61  			return err
    62  		}
    63  
    64  		err = c.MsgFilter()
    65  		if err != nil {
    66  			log.Errorf("msg filter err:%s", err.Error())
    67  			continue
    68  		}
    69  	}
    70  }
    71  
    72  // MsgFilter
    73  // use msg decoder and onmessage handle
    74  func (c *Conn) MsgFilter() (err error) {
    75  	if c.server.options.decoder == nil {
    76  		c.server.handler.OnMessage(c, c.buffer.ReadAll())
    77  		return
    78  	}
    79  
    80  	val, err := c.server.options.decoder.Decode(c.buffer)
    81  	if err != nil {
    82  		return
    83  	}
    84  	c.server.handler.OnMessage(c, val)
    85  
    86  	return
    87  }
    88  
    89  // AsyncBlockRead  trigger a async kernerl block read from connect socket fd to buff
    90  func (c *Conn) AsyncBlockRead() {
    91  	c.lastReadTime = time.Now()
    92  	fd := c.GetFd()
    93  	ring := c.server.GetIoUring(fd)
    94  	c.buffer.AsyncReadFromFD(fd, ring, c.getReadCallback())
    95  }
    96  
    97  func (c *Conn) getReadCallback() EventCallBack {
    98  	return func(e *eventInfo) (err error) {
    99  		err = c.MsgFilter()
   100  		return
   101  	}
   102  }
   103  
   104  // processReadEvent
   105  // process connect read complete event
   106  // add async block read bytes event until read readBufferLen bytes from connect fd
   107  func (c *Conn) processReadEvent(e *eventInfo) (err error) {
   108  	err = e.cb(e)
   109  	if err != nil {
   110  		// There is no data to read in the buffer
   111  		if err == syscall.EAGAIN {
   112  			return nil
   113  		}
   114  		return err
   115  	}
   116  	// if un use poll in ready, need add read event op again
   117  	c.AsyncBlockRead()
   118  	return
   119  }
   120  
   121  // AsyncBlockWrite
   122  // async block write bytes
   123  func (c *Conn) AsyncBlockWrite(bytes []byte) {
   124  	ring := c.server.GetIoUring(c.fd)
   125  	ring.addSendSqe(noOpsEventCb, c.fd, bytes, len(bytes), 0)
   126  }
   127  
   128  func (c *Conn) processWirteEvent(e *eventInfo) (err error) {
   129  	if e.cqe.Res < 0 {
   130  		err = ErrIOUringWriteFail
   131  		return
   132  	}
   133  
   134  	err = e.cb(e)
   135  	if err != nil {
   136  		return
   137  	}
   138  
   139  	return
   140  }
   141  
   142  // Write Writer impl
   143  // notice: if use iouring async write to fd, return 0, nil
   144  func (c *Conn) Write(bytes []byte) (int, error) {
   145  	if c.server.options.ioMode == IOModeUring {
   146  		c.AsyncBlockWrite(bytes)
   147  		return 0, nil
   148  	}
   149  
   150  	return syscall.Write(c.fd, bytes)
   151  }
   152  
   153  // WriteWithEncoder
   154  // write with encoder, encode bytes to writer
   155  func (c *Conn) WriteWithEncoder(bytes []byte) error {
   156  	return c.server.options.encoder.EncodeToWriter(c, bytes)
   157  }
   158  
   159  // Close Closes the connection
   160  func (c *Conn) Close() {
   161  	// Remove from the file descriptor that epoll is listening for
   162  	err := closeFD(c.pollerFD, c.fd)
   163  	if err != nil {
   164  		log.Error(err)
   165  	}
   166  	c.CloseConnect()
   167  }
   168  
   169  func (c *Conn) CloseConnect() {
   170  	// Remove conn from conns
   171  	c.server.conns.Delete(c.fd)
   172  	// Return the cache
   173  	c.server.readBufferPool.Put(c.buffer.buf)
   174  	// Subtract one from the number of connections
   175  	atomic.AddInt64(&c.server.connsNum, -1)
   176  }
   177  
   178  // CloseRead closes connection
   179  func (c *Conn) CloseRead() error {
   180  	err := closeFDRead(int(c.fd))
   181  	if err != nil {
   182  		log.Error(err)
   183  		return err
   184  	}
   185  	return nil
   186  }
   187  
   188  // GetData gets the data
   189  func (c *Conn) GetData() interface{} {
   190  	return c.data
   191  }
   192  
   193  // SetData sets the data
   194  func (c *Conn) SetData(data interface{}) {
   195  	c.data = data
   196  }