// handle incoming packets on the listening socket
handle incoming packets on the listening socket
// handle incoming packets on the listening socket
func (twoway *Bilateral) listenHandler() error {
	from, command, data, err := receivePacket(twoway.listenSocket)
	if nil != err {
		log.Errorf("listen: from: %q: error: %v", from, err)
		return err
	}
	if twoway.serverName == from {
		log.Errorf("disconnect(loop to self): %q", from)
		err := twoway.listenSocket.Disconnect(from)
		if nil != err {
			log.Errorf("disconnect(loop) error: %v", err)
		}
		twoway.connections[from].state = stateDestroy
		return nil
	}
	log.Debugf("From←: %q  command: %q  data: %x", from, command, data)
	switch command {
	case "JOIN": 
		stay := false
		if c, ok := twoway.connections[from]; ok {
			if stateConnected == c.state || stateCheck == c.state || stateHandshake == c.state {
				stay = false
			} else {
				c.state = stateMakeServer
				stay = true
			}
			log.Debugf("From←: %q  command: %q  stay: %v", from, command, stay)
		} else if string(data) != twoway.networkName {
			stay = false
		} else {
			twoway.connections[from] = &connect{
				timestamp: time.Now().Add(SERVE_TIME),
				address:   "",
				state:     stateServing,
				joinCount: 0,
				backoff:   0,
				outgoing:  false,
				tick:      0,
			}
			stay = true
		}
		if stay {
			err = sendPacket(twoway.listenSocket, from, "STAY", []byte{})
		} else {
			err = sendPacket(twoway.listenSocket, from, "PART", []byte{})
		}
		if nil != err {
			log.Errorf("join: %v  error: %v", stay, err)
		}
	case "TICK": 
		if c, ok := twoway.connections[from]; ok && stateServing == c.state {
			c.timestamp = time.Now().Add(SERVE_TIME)
			c.backoff = 0
			log.Infof("tock %x → %q", data, from)
			err = sendPacket(twoway.listenSocket, from, "TOCK", data)
			if nil != err {
				log.Errorf("tick: %v  error: %v", data, err)
			}
		}
	case "CALL": 
		if c, ok := twoway.connections[from]; ok && stateServing == c.state {
			c.timestamp = time.Now().Add(SERVE_TIME)
			c.backoff = 0
			twoway.rpcServerCallChannel <- rpcServerCallData{
				socket:    twoway.listenSocket,
				from:      from,
				request:   data,
				wantReply: true,
			}
		}
	case "CAST": 
		if c, ok := twoway.connections[from]; ok && stateServing == c.state {
			c.timestamp = time.Now().Add(SERVE_TIME)
			c.backoff = 0
			twoway.rpcServerCallChannel <- rpcServerCallData{
				socket:    twoway.listenSocket,
				from:      from,
				request:   data,
				wantReply: false,
			}
		}
	case "BACK": 
		if c, ok := twoway.connections[from]; ok && stateServing == c.state {
			c.timestamp = time.Now().Add(SERVE_TIME)
			c.backoff = 0
			twoway.rpcClientResponseChannel <- rpcClientResponseData{
				from:     from,
				response: data,
			}
		}
	default: 
		log.Errorf("listenHandler unknown command: %q", command)
	}
	if nil != err {
		log.Errorf("listenHandler error: %v", err)
	}
	return err
}
func ( twoway * Bilateral ) listenHandler ( ) error { from , command , data , err := receivePacket ( twoway . listenSocket ) if nil != err { log . Errorf ( " " , from , err ) return err } if twoway . serverName == from { log . Errorf ( " " , from ) err := twoway . listenSocket . Disconnect ( from ) if nil != err { log . Errorf ( " " , err ) } twoway . connections [ from ] . state = stateDestroy return nil } log . Debugf ( " f om,  c mmand,  d ta) switch command { case " " : stay := false if c , ok := twoway . connections [ from ] ; ok { if stateConnected == c . state || stateCheck == c . state || stateHandshake == c . state { stay = false } else { c . state = stateMakeServer stay = true } log . Debugf ( " f om,  c mmand,  s ay) } else if string ( data ) != twoway . networkName { stay = false } else { twoway . connections [ from ] = & connect { timestamp : time . Now ( ) . Add ( SERVE_TIME ) , address : " " , state : stateServing , joinCount : 0 , backoff : 0 , outgoing : false , tick : 0 , } stay = true } if stay { err = sendPacket ( twoway . listenSocket , from , " " , [ ] byte { } ) } else { err = sendPacket ( twoway . listenSocket , from , " " , [ ] byte { } ) } if nil != err { log . Errorf ( " " , stay , err ) } case " " : if c , ok := twoway . connections [ from ] ; ok && stateServing == c . state { c . timestamp = time . Now ( ) . Add ( SERVE_TIME ) c . backoff = 0 log . Infof ( " d ta,  f om) err = sendPacket ( twoway . listenSocket , from , " " , data ) if nil != err { log . Errorf ( " " , data , err ) } } case " " : if c , ok := twoway . connections [ from ] ; ok && stateServing == c . state { c . timestamp = time . Now ( ) . Add ( SERVE_TIME ) c . backoff = 0 twoway . rpcServerCallChannel <- rpcServerCallData { socket : twoway . listenSocket , from : from , request : data , wantReply : true , } } case " " : if c , ok := twoway . connections [ from ] ; ok && stateServing == c . state { c . timestamp = time . Now ( ) . Add ( SERVE_TIME ) c . backoff = 0 twoway . rpcServerCallChannel <- rpcServerCallData { socket : twoway . listenSocket , from : from , request : data , wantReply : false , } } case " " : if c , ok := twoway . connections [ from ] ; ok && stateServing == c . state { c . timestamp = time . Now ( ) . Add ( SERVE_TIME ) c . backoff = 0 twoway . rpcClientResponseChannel <- rpcClientResponseData { from : from , response : data , } } default : log . Errorf ( " " , command ) } if nil != err { log . Errorf ( " " , err ) } return err }
handle incoming packets on the listening socket
handle incoming packets on the listening socket
// prevent loopback // client wants to connect // already have a connection to remote - tell client to disconnect // remote trying to connect, so disconnect my client socket, become server //c.timestamp = time.Now().Add(SERVE_TIME) // mismatched network name // no connection, so put into serving mode // client checking the connection // client submits a request for us to process // client submits a request for us to process // clients "server-side" replied to our request // ignore others