// dispatch accepts connections on the listener and serves requests // for each incoming connection. dispatch blocks; the caller typically // invokes it in a go statement. func (server *Server) dispatchTCP(key string, conn *net.TCPConn, wr *bufio.Writer, wp *bytes.Pool, wb *bytes.Buffer, ch *Channel) { var ( p *Proto err error ) if Debug { log.Debug("key: %s start dispatch tcp goroutine", key) } for { if !ch.Ready() { if Debug { log.Debug("key: %s wakeup exit dispatch goroutine", key) } break } // fetch message from svrbox(server send) for { if p, err = ch.SvrProto.Get(); err != nil { // must be empty error err = nil break } // just forward the message if err = server.writeTCPResponse(wr, p); err != nil { goto failed } p.Body = nil // avoid memory leak ch.SvrProto.GetAdv() } // only hungry flush response if err = wr.Flush(); err != nil { break } } failed: log.Error("key: %s dispatch tcp error(%v)", key, err) conn.Close() wp.Put(wb) if Debug { log.Debug("key: %s dispatch goroutine exit", key) } return }
// TODO linger close? func (server *Server) serveTCP(conn *net.TCPConn, rp, wp *bytes.Pool, tr *itime.Timer) { var ( b *Bucket key string hb time.Duration // heartbeat err error trd *itime.TimerData rb = rp.Get() wb = wp.Get() ch = NewChannel(server.Options.Proto, define.NoRoom) rr = &ch.Reader wr = &ch.Writer p = &ch.CliProto ) ch.Reader.ResetBuffer(conn, rb.Bytes()) ch.Writer.ResetBuffer(conn, wb.Bytes()) // handshake trd = tr.Add(server.Options.HandshakeTimeout, func() { conn.Close() }) if key, ch.RoomId, hb, err = server.authTCP(rr, wr, p); err != nil { conn.Close() rp.Put(rb) wp.Put(wb) tr.Del(trd) log.Error("key: %s handshake failed error(%v)", key, err) return } trd.Key = key tr.Set(trd, hb) b = server.Bucket(key) b.Put(key, ch, tr) // hanshake ok start dispatch goroutine go server.dispatchTCP(key, conn, wr, wp, wb, ch) for { if err = server.readTCPRequest(rr, p); err != nil { break } if p.Operation == define.OP_HEARTBEAT { tr.Set(trd, hb) p.Body = nil p.Operation = define.OP_HEARTBEAT_REPLY if Debug { log.Debug("key: %s receive heartbeat", key) } } else { if err = server.operator.Operate(p); err != nil { break } } if err = ch.Reply(); err != nil { break } } log.Error("key: %s server tcp failed error(%v)", key, err) conn.Close() ch.Close() rp.Put(rb) b.Del(key) tr.Del(trd) if err = server.operator.Disconnect(key, ch.RoomId); err != nil { log.Error("key: %s operator do disconnect error(%v)", key, err) } if Debug { log.Debug("key: %s server tcp goroutine exit", key) } return }