The uTP-over-DiscV5 document specifies that all uTP traffic is encapsulated into TALKREQ packets while TALKRESP is not used. The problem is that the current DiscV5 implementation kind of insists on doing TALKREQ / TALKRESP packet exchanges and expects a response to every request. See the existing interface here:
type TalkRequestHandler func(enode.ID, *net.UDPAddr, []byte) []byte
func (t *UDPv5) RegisterTalkHandler(protocol string, handler TalkRequestHandler) {
func (t *UDPv5) TalkRequest(n *enode.Node, protocol string, request []byte) ([]byte, error) {
In order to interface uTP to DiscV5 we need to somehow circumvent the internal request/reply logic and just send and receive TALKREQ packets. I'd suggest modifying handleTalkRequest so that if the TalkRequestHandler returns a nil byte slice then it does not send a response at all. This way the uTP handler can register itself with RegisterTalkHandler('utp', handler) where the handler processes incoming messages and always returns nil. For sending messages without expecting a response I`d suggest adding an alternative send method:
func (t *UDPv5) TalkRequestNoResponse(n *enode.Node, protocol string, message []byte) error {
_, err := t.send(n.ID(), &net.UDPAddr{IP: n.IP(), Port: n.UDP()}, &v5wire.TalkRequest{Protocol: protocol, Message: message})
return err
}
The exported interface of the uTP logic should look something like this:
func (t *UTP) Send(n *enode.Node, connectionID, message []byte) error
func (t *UTP) Receive(n *enode.Node, connectionID []byte) ([]byte, error)