Example #1
0
File: tcp.go Project: dulumao/goim
// 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
}
Example #2
0
File: tcp.go Project: dulumao/goim
// 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
}