Is UDP supposed to be Half-Duplex?

1,264 views
Skip to first unread message

Uriel Fanelli

unread,
May 24, 2015, 5:14:18 PM5/24/15
to golan...@googlegroups.com
Hello all

I am trying to develop a UDP server and I am falling into some strange issue.

First: the configuration is 

MACHINE ==> UDP NAT ==> INTERNET ==> PEER

Given that, I am trying to use http://tools.ietf.org/html/rfc4787 (almost all routers are implementing it) , which means my "MACHINE" should 
answer to "PEER" using the same port the "MACHINE" uses to receive.

Basically "MACHINE" sends some UDP packet to "PEER". "UDP NAT" remembers this, and associates the port  to a NAT. So, then PEER answers back, the UDP packet is forwarded.

Now, this is the problem.

I can open a listener on "MACHINE" ( https://github.com/uriel-fanelli/tribes/blob/master/3be/UDP_server.go ) and it works perfectly.

Being a non-connection protocol, I expected I was permitted also to send packet FROM the port I use for listening: given there is no connection, how can i answer back from the open port, by example?

But, this is not what happens. After I open a listener and I receive a packet, there is no way to answer re-using this source:port UDPConn.

Or: "is there a way to answer re-using the same udpConn?" 

As it is, seems I can only read from a UDP Listener, but not answer using this port.

Seems UDP was implemented one-direction only, or I am missing something. How can I compose and send a UDP datagram having as a origin a port I am listening at?

thanks in advance

Uriel


Gerard

unread,
May 24, 2015, 6:26:53 PM5/24/15
to golan...@googlegroups.com
Stupid thing, but since when is UDP full duplex? UDP isn't TCP.

Dmitri Shuralyov

unread,
May 24, 2015, 7:13:28 PM5/24/15
to golan...@googlegroups.com
It's certainly possible to both send and receive from a UDP port. You just have to use lower level UDP-specific methods, not the connection-oriented ones (since UDP is not connection oriented, although it can be treated that way if you care about a subset of its functionality).

Look into:

http://godoc.org/net#UDPConn.WriteToUDP

Here's a snippet where I've done this, in case it's helpful (full source at https://github.com/shurcooL/eX0/blob/master/eX0-go/net.go).

func listenAndHandleUdp() {
	udpAddr, err := net.ResolveUDPAddr("udp", ":25045")
	if err != nil {
		panic(err)
	}
	ln, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		panic(err)
	}
	mux := &Connection{udp: ln}

	handleUdp(mux)
}

func handleUdp(mux *Connection) {
	for {
		buf, c, udpAddr, err := receiveUdpPacketFrom(mux)
		if err != nil {
			panic(err)
		}

		// ...
}

// ---

func sendUdpPacket(c *Connection, b []byte) error {
	if c.UdpAddr != nil {
		_, err := c.udp.WriteToUDP(b, c.UdpAddr)
		return err
	} else {
		_, err := c.udp.Write(b)
		return err
	}
}

func receiveUdpPacket(c *Connection) (io.Reader, error) {
	var b [packet.MAX_UDP_SIZE]byte
	n, err := c.udp.Read(b[:])
	if err != nil {
		return nil, err
	}
	return bytes.NewReader(b[:n]), nil
}

func receiveUdpPacketFrom(mux *Connection) (io.Reader, *Connection, *net.UDPAddr, error) {
	var b [packet.MAX_UDP_SIZE]byte
	n, udpAddr, err := mux.udp.ReadFromUDP(b[:])
	if err != nil {
		return nil, nil, nil, err
	}

	var from *Connection
	state.Lock()
	for _, connection := range state.connections {
		if connection.UdpAddr != nil &&
			connection.UdpAddr.IP.Equal(udpAddr.IP) &&
			connection.UdpAddr.Port == udpAddr.Port &&
			connection.UdpAddr.Zone == udpAddr.Zone {

			from = connection
			break
		}
	}
	state.Unlock()

	return bytes.NewReader(b[:n]), from, udpAddr, nil
}

Uriel Fanelli

unread,
May 25, 2015, 5:55:38 AM5/25/15
to golan...@googlegroups.com
Hi

thank you, but I have a question: if my understanding is ok,
c.udp.WriteToUDP(b, c.UdpAddr)
is reusing the properties of "c" , which is the listening port, and then c.UdpAddr is the destination
IP you want to send packets. correct?

Uriel
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Dmitri Shuralyov

unread,
May 25, 2015, 6:03:53 AM5/25/15
to golan...@googlegroups.com
Yep.

Uriel Fanelli

unread,
May 25, 2015, 8:54:15 AM5/25/15
to golan...@googlegroups.com
Hi Gerard

many applications (just think to VPN tunneling on UDP) are doing what I am trying to do.
The goal is to use the UDP NAT feature of the router.

As you can see below, there is a way.

Milan P. Stanic

unread,
May 25, 2015, 9:26:09 AM5/25/15
to golan...@googlegroups.com
On Sun, 2015-05-24 at 14:14, Uriel Fanelli wrote:
> Hello all
>
> I am trying to develop a UDP server and I am falling into some strange
> issue.
>
> First: the configuration is
>
> MACHINE ==> UDP NAT ==> INTERNET ==> PEER
>
> Given that, I am trying to use http://tools.ietf.org/html/rfc4787 (almost
> all routers are implementing it) , which means my "MACHINE" should
> answer to "PEER" using the same port the "MACHINE" uses to receive.
>
> Basically "MACHINE" sends some UDP packet to "PEER". "UDP NAT" remembers
> this, and associates the port to a NAT. So, then PEER answers back, the
> UDP packet is forwarded.
>
> Now, this is the problem.
>
> I can open a listener on "MACHINE"
> ( https://github.com/uriel-fanelli/tribes/blob/master/3be/UDP_server.go )
> and it works perfectly.
>
> Being a non-connection protocol, I expected I was permitted also to send
> packet FROM the port I use for listening: given there is no connection, how
> can i answer back from the open port, by example?
>
> But, this is not what happens. After I open a listener and I receive a
> packet, there is no way to answer re-using this source:port UDPConn.
>
> *Or: "is there a way to answer re-using the same udpConn?" *
>
> As it is, seems I can only read from a UDP Listener, but not answer using
> this port.
>
> Seems UDP was implemented *one-direction only*, or I am missing something.
> How can I compose and send a UDP datagram having as a origin a port I am
> listening at?

UDP (a protocol) is connection-less i.e. does not handle retransmission,
recovery, reordering or reassembly of packets. It 'throws packet to the
net' and forget about it. It does not expect any response from the
receiving end.

All this (retransmission, recovery, reordering or reassembly) must be
implemented at the application level if one needs that.

I didn't worked with low level networking in go (so I cannot provide
example) but from my reading of go docs it looks like this should be
easy.


Reply all
Reply to author
Forward
0 new messages