Example #1
0
// checkMessage checks peer message sequence
func (p *peer) checkMessage(t msg.Transit) bool {
	p.wantSequence++
	valid := p.wantSequence == t.Sequence()
	if !valid {
		p.wantSequence--
	}

	return valid
}
Example #2
0
// send sends message to peer
func (p *peer) send(t msg.Transit) (err error) {
	if p.connected {
		p.sentSequence++
		t.SetSequence(p.sentSequence)
		err = t.Send(p.mailbox)
		if err != nil {
			p.disconnect()
		}
	}

	return
}
Example #3
0
// recvFromPeer handles messages coming from other peers
func (n *node) recvFromPeer(transit msg.Transit) {
	if transit == nil {
		// Invalid transit
		return
	}

	routingID := transit.RoutingID()
	if len(routingID) < 1 {
		// Invalid routing id, ignore the peer
		return
	}

	// Router socket tells us the identity of this peer
	// Identity must be [1] followed by 16-byte UUID, ignore the [1]
	identity := fmt.Sprintf("%X", routingID[1:])

	peer := n.peers[identity]

	if n.verbose {
		for i, str := range strings.Split(transit.String(), "\n") {
			if len(str) <= 0 {
				continue
			}

			if i == 0 && peer != nil {
				log.Printf("[%s] %s %s", n.name, peer.name, str)
			} else {
				log.Printf("[%s] %s", n.name, str)
			}
		}
	}

	switch m := transit.(type) {
	case *msg.Hello:
		// On HELLO we may create the peer if it's unknown
		// On other cmds the peer must already exist
		if peer != nil {
			// Remove fake peers
			if peer.ready {
				n.removePeer(peer)
			} else if n.endpoint == peer.endpoint {
				// We ignore HELLO, if peer has same endpoint as current node
				return
			}
		}
		var err error
		peer, err = n.requirePeer(identity, m.Endpoint)
		if err == nil {
			peer.ready = true
		} else if n.verbose {
			log.Printf("[%s] %s", n.name, err)
		}
	}

	// Ignore command if peer isn't ready
	if peer == nil || !peer.ready {
		if peer != nil {
			n.removePeer(peer)
		}
		return
	}

	if !peer.checkMessage(transit) {
		log.Printf("[%s] lost messages from %s", n.name, identity)
		return
	}

	// Now process each command
	switch m := transit.(type) {
	case *msg.Hello:
		// Store properties from HELLO command into peer
		peer.name = m.Name
		peer.status = m.Status

		event := &Event{
			eventType: EventEnter,
			sender:    peer.identity,
			name:      peer.name,
			address:   strings.SplitN(strings.TrimPrefix(m.Endpoint, "tcp://"), ":", 2)[0],
			headers:   make(map[string]string),
		}

		// Store peer headers for future reference
		for key, val := range m.Headers {
			peer.headers[key] = val
			event.headers[key] = val
		}

		select {
		case n.events <- event:
		default:
			if n.verbose {
				log.Printf("[%s] Dropping event: %s", n.name, EventEnter)
			}
		}

		// Join peer to listed groups
		for _, group := range m.Groups {
			n.joinPeerGroup(peer, group)
		}

		// TODO(armen): If peer is a ZRE/LOG collector, connect to it

	case *msg.Whisper:
		// Pass up to caller API as WHISPER event
		select {
		case n.events <- &Event{eventType: EventWhisper, sender: identity, name: peer.name, msg: m.Content}:
		default:
			if n.verbose {
				log.Printf("[%s] Dropping event: %s", n.name, EventWhisper)
			}
		}

	case *msg.Shout:
		// Pass up to caller as SHOUT event
		select {
		case n.events <- &Event{eventType: EventShout, sender: identity, name: peer.name, group: m.Group, msg: m.Content}:
		default:
			if n.verbose {
				log.Printf("[%s] Dropping event: %s", n.name, EventShout)
			}
		}

	case *msg.Ping:
		ping := msg.NewPingOk()
		peer.send(ping)

	case *msg.Join:
		n.joinPeerGroup(peer, m.Group)
		if m.Status != peer.status {
			panic(fmt.Sprintf("[%X] message status isn't equal to peer status, %d != %d", n.uuid, m.Status, peer.status))
		}

	case *msg.Leave:
		n.leavePeerGroup(peer, m.Group)
		if m.Status != peer.status {
			panic(fmt.Sprintf("[%X] message status isn't equal to peer status, %d != %d", n.uuid, m.Status, peer.status))
		}
	}

	// Activity from peer resets peer timers
	peer.refresh()
}