github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/net/eventloop_unix.go (about) 1 // +build linux darwin netbsd freebsd openbsd dragonfly 2 3 package net 4 5 import ( 6 nt "net" 7 "time" 8 9 "github.com/angenalZZZ/gofunc/net/internal/netpoll" 10 "golang.org/x/sys/unix" 11 ) 12 13 type eventloop struct { 14 idx int // loop index in the server loops list 15 svr *server // server in loop 16 codec ICodec // codec for TCP 17 packet []byte // read packet buffer 18 poller *netpoll.Poller // epoll or kqueue 19 connCount int32 // number of active connections in event-loop 20 connections map[int]*conn // loop connections fd -> conn 21 eventHandler EventHandler // user eventHandler 22 calibrateCallback func(*eventloop, int32) // callback func for re-adjusting connCount 23 } 24 25 func (el *eventloop) closeAllConns() { 26 // Close loops and all outstanding connections 27 for _, c := range el.connections { 28 _ = el.loopCloseConn(c, nil) 29 } 30 } 31 32 func (el *eventloop) loopRun() { 33 defer func() { 34 el.closeAllConns() 35 if el.idx == 0 && el.svr.opts.Ticker { 36 close(el.svr.ticktock) 37 } 38 el.svr.signalShutdown() 39 }() 40 41 if el.idx == 0 && el.svr.opts.Ticker { 42 go el.loopTicker() 43 } 44 45 el.svr.logger.Printf("event-loop:%d exits with error: %v\n", el.idx, el.poller.Polling(el.handleEvent)) 46 } 47 48 func (el *eventloop) loopAccept(fd int) error { 49 if fd == el.svr.ln.fd { 50 if el.svr.ln.pconn != nil { 51 return el.loopReadUDP(fd) 52 } 53 nfd, sa, err := unix.Accept(fd) 54 if err != nil { 55 if err == unix.EAGAIN { 56 return nil 57 } 58 return err 59 } 60 if err = unix.SetNonblock(nfd, true); err != nil { 61 return err 62 } 63 c := newTCPConn(nfd, el, sa) 64 if err = el.poller.AddRead(c.fd); err == nil { 65 el.connections[c.fd] = c 66 el.calibrateCallback(el, 1) 67 return el.loopOpen(c) 68 } 69 return err 70 } 71 return nil 72 } 73 74 func (el *eventloop) loopOpen(c *conn) error { 75 c.opened = true 76 c.localAddr = el.svr.ln.lnaddr 77 c.remoteAddr = netpoll.SockaddrToTCPOrUnixAddr(c.sa) 78 out, action := el.eventHandler.OnOpened(c) 79 if el.svr.opts.TCPKeepAlive > 0 { 80 if _, ok := el.svr.ln.ln.(*nt.TCPListener); ok { 81 _ = netpoll.SetKeepAlive(c.fd, int(el.svr.opts.TCPKeepAlive/time.Second)) 82 } 83 } 84 if out != nil { 85 c.open(out) 86 } 87 88 if !c.outboundBuffer.IsEmpty() { 89 _ = el.poller.AddWrite(c.fd) 90 } 91 92 return el.handleAction(c, action) 93 } 94 95 func (el *eventloop) loopRead(c *conn) error { 96 n, err := unix.Read(c.fd, el.packet) 97 if n == 0 || err != nil { 98 if err == unix.EAGAIN { 99 return nil 100 } 101 return el.loopCloseConn(c, err) 102 } 103 c.buffer = el.packet[:n] 104 105 for inFrame, _ := c.read(); inFrame != nil; inFrame, _ = c.read() { 106 out, action := el.eventHandler.React(inFrame, c) 107 if out != nil { 108 outFrame, _ := el.codec.Encode(c, out) 109 el.eventHandler.PreWrite() 110 c.write(outFrame) 111 } 112 switch action { 113 case None: 114 case Close: 115 return el.loopCloseConn(c, nil) 116 case Shutdown: 117 return errServerShutdown 118 } 119 if !c.opened { 120 return nil 121 } 122 } 123 _, _ = c.inboundBuffer.Write(c.buffer) 124 125 return nil 126 } 127 128 func (el *eventloop) loopWrite(c *conn) error { 129 el.eventHandler.PreWrite() 130 131 head, tail := c.outboundBuffer.LazyReadAll() 132 n, err := unix.Write(c.fd, head) 133 if err != nil { 134 if err == unix.EAGAIN { 135 return nil 136 } 137 return el.loopCloseConn(c, err) 138 } 139 c.outboundBuffer.Shift(n) 140 141 if len(head) == n && tail != nil { 142 n, err = unix.Write(c.fd, tail) 143 if err != nil { 144 if err == unix.EAGAIN { 145 return nil 146 } 147 return el.loopCloseConn(c, err) 148 } 149 c.outboundBuffer.Shift(n) 150 } 151 152 if c.outboundBuffer.IsEmpty() { 153 _ = el.poller.ModRead(c.fd) 154 } 155 return nil 156 } 157 158 func (el *eventloop) loopCloseConn(c *conn, err error) error { 159 if !c.outboundBuffer.IsEmpty() && err == nil { 160 _ = el.loopWrite(c) 161 } 162 err0, err1 := el.poller.Delete(c.fd), unix.Close(c.fd) 163 if err0 == nil && err1 == nil { 164 delete(el.connections, c.fd) 165 el.calibrateCallback(el, -1) 166 switch el.eventHandler.OnClosed(c, err) { 167 case Shutdown: 168 return errServerShutdown 169 } 170 c.releaseTCP() 171 } else { 172 if err0 != nil { 173 el.svr.logger.Printf("failed to delete fd:%d from poller, error:%v\n", c.fd, err0) 174 } 175 if err1 != nil { 176 el.svr.logger.Printf("failed to close fd:%d, error:%v\n", c.fd, err1) 177 } 178 } 179 return nil 180 } 181 182 func (el *eventloop) loopWake(c *conn) error { 183 //if co, ok := el.connections[c.fd]; !ok || co != c { 184 // return nil // ignore stale wakes. 185 //} 186 out, action := el.eventHandler.React(nil, c) 187 if out != nil { 188 frame, _ := el.codec.Encode(c, out) 189 c.write(frame) 190 } 191 return el.handleAction(c, action) 192 } 193 194 func (el *eventloop) loopTicker() { 195 var ( 196 delay time.Duration 197 open bool 198 err error 199 ) 200 for { 201 err = el.poller.Trigger(func() (err error) { 202 delay, action := el.eventHandler.Tick() 203 el.svr.ticktock <- delay 204 switch action { 205 case None: 206 case Shutdown: 207 err = errServerShutdown 208 } 209 return 210 }) 211 if err != nil { 212 el.svr.logger.Printf("failed to awake poller with error:%v, stopping ticker\n", err) 213 break 214 } 215 if delay, open = <-el.svr.ticktock; open { 216 time.Sleep(delay) 217 } else { 218 break 219 } 220 } 221 } 222 223 func (el *eventloop) handleAction(c *conn, action Action) error { 224 switch action { 225 case None: 226 return nil 227 case Close: 228 return el.loopCloseConn(c, nil) 229 case Shutdown: 230 return errServerShutdown 231 default: 232 return nil 233 } 234 } 235 236 func (el *eventloop) loopReadUDP(fd int) error { 237 n, sa, err := unix.Recvfrom(fd, el.packet, 0) 238 if err != nil || n == 0 { 239 if err != nil && err != unix.EAGAIN { 240 el.svr.logger.Printf("failed to read UDP packet from fd:%d, error:%v\n", fd, err) 241 } 242 return nil 243 } 244 c := newUDPConn(fd, el, sa) 245 out, action := el.eventHandler.React(el.packet[:n], c) 246 if out != nil { 247 el.eventHandler.PreWrite() 248 _ = c.sendTo(out) 249 } 250 switch action { 251 case Shutdown: 252 return errServerShutdown 253 } 254 c.releaseUDP() 255 return nil 256 }