www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Good way to send/receive UDP packets?

reply Dukc <ajieskola gmail.com> writes:
I have a project where I need to take and send UDP packets over 
the Internet. Only raw UDP - my application uses packets 
directly, with their starting `[0x5a, packet.length.to!ubyte]` 
included. And only communication with a single address, no need 
to communicate with multiple clients concurrently.

I understand that I could do it either with the Curl library 
bundled with Phobos, or use Vibe.D or Hunt instead. But it's the 
first time I'm dealing with low-level networking like this, and 
my knowledge about it is lacking. So seek opinions about what 
library I should use, and more importantly, why.

Other advice about projects like this is also welcome, should 
anyone wish to share it.
Jul 18 2020
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Jul 18, 2020 at 04:00:09PM +0000, Dukc via Digitalmars-d-learn wrote:
 I have a project where I need to take and send UDP packets over the
 Internet. Only raw UDP - my application uses packets directly, with
 their starting `[0x5a, packet.length.to!ubyte]` included. And only
 communication with a single address, no need to communicate with
 multiple clients concurrently.
 
 I understand that I could do it either with the Curl library bundled
 with Phobos, or use Vibe.D or Hunt instead. But it's the first time
 I'm dealing with low-level networking like this, and my knowledge
 about it is lacking.  So seek opinions about what library I should
 use, and more importantly, why.
If you already have the raw packets, there is no need for any library, just call the OS's C API directly (such as core.sys.posix.sys.socket). For UDP you don't even need to set up anything, just create a socket and fire the packets away. --T
Jul 18 2020
prev sibling next sibling parent IGotD- <nise nise.com> writes:
On Saturday, 18 July 2020 at 16:00:09 UTC, Dukc wrote:
 I have a project where I need to take and send UDP packets over 
 the Internet. Only raw UDP - my application uses packets 
 directly, with their starting `[0x5a, packet.length.to!ubyte]` 
 included. And only communication with a single address, no need 
 to communicate with multiple clients concurrently.

 I understand that I could do it either with the Curl library 
 bundled with Phobos, or use Vibe.D or Hunt instead. But it's 
 the first time I'm dealing with low-level networking like this, 
 and my knowledge about it is lacking. So seek opinions about 
 what library I should use, and more importantly, why.

 Other advice about projects like this is also welcome, should 
 anyone wish to share it.
D has socket wrapper interfaces just as many other languages. https://dlang.org/phobos/std_socket.html
Jul 18 2020
prev sibling next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 18 July 2020 at 16:00:09 UTC, Dukc wrote:
 I have a project where I need to take and send UDP packets over 
 the Internet. Only raw UDP
I wrote an example using phobos on my blog a while ago that might help you get started: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_11_11.html#communication-by-datagram
Jul 18 2020
prev sibling next sibling parent reply notna <notna.remove.this ist-einmalig.de> writes:
On Saturday, 18 July 2020 at 16:00:09 UTC, Dukc wrote:
 I have a project where I need to take and send UDP packets over 
 the Internet. Only raw UDP - my application uses packets 
 directly, with their starting `[0x5a, packet.length.to!ubyte]` 
 included. And only communication with a single address, no need 
 to communicate with multiple clients concurrently.

 I understand that I could do it either with the Curl library 
 bundled with Phobos, or use Vibe.D or Hunt instead. But it's 
 the first time I'm dealing with low-level networking like this, 
 and my knowledge about it is lacking. So seek opinions about 
 what library I should use, and more importantly, why.

 Other advice about projects like this is also welcome, should 
 anyone wish to share it.
Someone once wrote about a UDP library, which was used to sync data to somewhere in APAC (Hongkong?) and by doing so the data transfer was magnitudes faster then before (over TCP)... I couldn't find this info now, neither in the forum not something meaningful in code.dlang.org... Maybe the author is still around or someone else has this post at hand and could share it?! Beside this, there is: - https://dlang.org/blog/2016/10/21/project-highlight-libasync/ Hope this helps...
Jul 19 2020
parent reply wjoe <invalid example.com> writes:
On Sunday, 19 July 2020 at 09:48:24 UTC, notna wrote:
 Someone once wrote about a UDP library, which was used to sync 
 data to somewhere in APAC (Hongkong?) and by doing so the data 
 transfer was magnitudes faster then before (over TCP)...
In the best case scenario, and orders of magnitude more unreliable otherwise. Choosing UDP over TCP because speed is like choosing a hammer over a screwdriver to drive in a screw because it works and is faster. But it's still the wrong tool for the job. UDP is a protocol for broadcasting messages which means it's connection less, unreliable (as in no guarantees for delivery of datagrams or that they'll be delivered only once, order i.e. datagrams sent in order A B C D can be delivered like e.g B C A D), and data integrity. It's insecure (as in everyone who listens can receive it). Once you need any of these features/guarantees you'll lose performance just as you would by using TCP, plus you pay the cost for re-inventing the wheel, bugs, testing, maintenance, support and all. UDP is the protocol of choice when you want to broadcast, the data you send isn't important or the TCP overhead is bigger than the transmitted message. Like broadcasting radio/podcasts, weather updates for your status bar or some such or DNS queries. If you need reliable transmission you need to use a reliable protocol.
Jul 21 2020
parent reply notna <notna.remove.this ist-einmalig.de> writes:
On Tuesday, 21 July 2020 at 13:05:21 UTC, wjoe wrote:
 On Sunday, 19 July 2020 at 09:48:24 UTC, notna wrote:
 Someone once wrote about a UDP library, which was used to sync 
 data to somewhere in APAC (Hongkong?) and by doing so the data 
 transfer was magnitudes faster then before (over TCP)...
In the best case scenario, and orders of magnitude more unreliable otherwise. Choosing UDP over TCP because speed is like choosing a hammer over a screwdriver to drive in a screw because it works and is faster. But it's still the wrong tool for the job. UDP is a protocol for broadcasting messages which means it's connection less, unreliable (as in no guarantees for delivery of datagrams or that they'll be delivered only once, order i.e. datagrams sent in order A B C D can be delivered like e.g B C A D), and data integrity. It's insecure (as in everyone who listens can receive it). Once you need any of these features/guarantees you'll lose performance just as you would by using TCP, plus you pay the cost for re-inventing the wheel, bugs, testing, maintenance, support and all. UDP is the protocol of choice when you want to broadcast, the data you send isn't important or the TCP overhead is bigger than the transmitted message. Like broadcasting radio/podcasts, weather updates for your status bar or some such or DNS queries. If you need reliable transmission you need to use a reliable protocol.
well, I guess all your remarks are true... and irrelevant at the same time. please go back and read his first post.... starts with "I have a project where I need to take and send UDP packets over the Internet"...
Jul 21 2020
parent reply wjoe <invalid example.com> writes:
On Tuesday, 21 July 2020 at 18:35:34 UTC, notna wrote:
 well, I guess all your remarks are true... and irrelevant at 
 the same time.

 please go back and read his first post.... starts with "I have 
 a project where I need to take and send UDP packets over the 
 Internet"...
... and continues with: On Saturday, 18 July 2020 at 16:00:09 UTC, Dukc wrote:
 [...] And only communication with a single address, no need to 
 communicate with multiple clients concurrently.
Let me elaborate on why what I wrote is both, on topic and relevant at the same time: It's a fundamental characteristic of UDP that you can't communicate with a single client only but you always are communicating with everyone who listens concurrently. The combination of the Internet and theoretically only 65535 available ports means that (mis)communication with other clients is likely to happen. OP's client may receive datagrams that are broadcast on that port by other programs (port forwarding). Likewise, other programs, which have a socket bound to the same port, may receive OP's data. Examples: - You behaving correctly yourself doesn't make others behave correctly now or retroactively. - Choosing a port which isn't in use right now isn't good enough because a few minutes later there may be another program using it, too, and for the same reason. - Checking a magic byte at offset 0 followed by the size isn't good enough. Let's say I decide my magic is a word because I want to be able to determine byte order - I choose 0x015a. When I broadcast a packet, e.g. [[0x015a], [0x0, 0x5a, 0xff]], but because I sent this from a little endian machine, the datagram will be delivered like so [0x5a, 0x01, 0x0, 0x5a, 0xff]. When OP's client receives this message it goes like so: Read 2 bytes: [0x5a, 0x1] 0x5a, oh that's me, 0x01 aha length of 1 byte - except it's not even a valid packet in the context of their program... Using UDP in a good way is far more complicated than it first appears to be.
Jul 22 2020
parent reply Dukc <ajieskola gmail.com> writes:
On Wednesday, 22 July 2020 at 13:17:11 UTC, wjoe wrote:
 - Choosing a port which isn't in use right now isn't good 
 enough because a few minutes later there may be another program 
 using it, too, and for the same reason.
But doesn't the UDP header include the sender IP address? So together with the magic number, shouldn't it be good enough? I know it definitely is not going to hold against jamming or a man in the middle, but it isn't supposed to, at this stage. It's used only for simulations that have the criticality of a casual Tetris server. I do acknowledge that the needs may rise later on. And if so, I understand that I'm much better off switching the protocol than trying to hardening the UDP.
Jul 22 2020
parent reply wjoe <invalid example.com> writes:
On Wednesday, 22 July 2020 at 15:26:23 UTC, Dukc wrote:
 On Wednesday, 22 July 2020 at 13:17:11 UTC, wjoe wrote:
 - Choosing a port which isn't in use right now isn't good 
 enough because a few minutes later there may be another 
 program using it, too, and for the same reason.
But doesn't the UDP header include the sender IP address? So together with the magic number, shouldn't it be good enough? I know it definitely is not going to hold against jamming or a man in the middle, but it isn't supposed to, at this stage. It's used only for simulations that have the criticality of a casual Tetris server. I do acknowledge that the needs may rise later on. And if so, I understand that I'm much better off switching the protocol than trying to hardening the UDP.
No, the UDP header includes the source and destination ports only. For transmission over the internet the Internet Protocol (IP) is used, which contains, among other things, the source and destination addresses. The anatomy looks like this: [ -------- IP - Datagram ------ ] [IP-Header][UDP-Header][UDP-Data] [ - UDP - Datagram - ] But keep in mind that the destination address can be a broadcast address, like e.g. 255.255.255.255, which you would use to announce your server to every PC in the network. If you send a UDP datagram to a single address, however, it will still be delivered to every program on that PC which receives UDP datagrams from that port. Also if you send UDP datagrams to multiple specific addresses, you need to send the same packet multiple times losing the major benefit of UDP - broadcast. And packets with a broadcast address sent over the internet are dropped, as that would affect every connected PC. If you are behind a router and send over the internet, your router will modify the IP-header, namely the sender address and replace that with your public address. When receiving packets, the IP header contains the destination address of your public IP (the router), which it will translate to the local address according to the port forwarding setup. That process is called network address translation (NAT) and is not only relevant for UDP.
Jul 22 2020
next sibling parent wjoe <invalid example.com> writes:
On Wednesday, 22 July 2020 at 16:14:24 UTC, wjoe wrote:
 When receiving packets, the IP header contains the destination 
 address of your public IP (the router), which it will translate 
 to the local address according to the port forwarding setup.
Pardon me, I meant to say according to the current routing table rules. Port Forwarding forwards all packets that match the defined criteria to the specified PC in the network. A port forwarding rule isn't required for NAT to work. Sender and receiver both need to send a packet to each other. This will cause the router to add a rule and expect an answer on that port from the destination address. When this packet arrives before the rule has been made it will be dropped (unless a port forwarding rule exists), so several packets may need to be sent for a successful punch-through.
Jul 22 2020
prev sibling parent reply Kagamin <spam here.lot> writes:
On Wednesday, 22 July 2020 at 16:14:24 UTC, wjoe wrote:
 If you send a UDP datagram to a single address, however, it 
 will still be delivered to every program on that PC which 
 receives UDP datagrams from that port.
Normally binding two sockets to the same port is not allowed.
Jul 23 2020
parent reply wjoe <invalid example.com> writes:
On Thursday, 23 July 2020 at 13:29:47 UTC, Kagamin wrote:
 On Wednesday, 22 July 2020 at 16:14:24 UTC, wjoe wrote:
 If you send a UDP datagram to a single address, however, it 
 will still be delivered to every program on that PC which 
 receives UDP datagrams from that port.
Normally binding two sockets to the same port is not allowed.
But it's possible when bound with the socket option SO_REUSEPORT (at least that's the name of the flag on linux since 3.9).
Jul 27 2020
parent reply Kagamin <spam here.lot> writes:
On Monday, 27 July 2020 at 09:41:44 UTC, wjoe wrote:
 But it's possible when bound with the socket option 
 SO_REUSEPORT (at least that's the name of the flag on linux 
 since 3.9).
The docs say it can't be used to hijack an address.
This option must be set on each socket (including the first 
socket) prior to calling bind(2) on the socket.
Jul 28 2020
parent wjoe <invalid example.com> writes:
On Tuesday, 28 July 2020 at 15:01:08 UTC, Kagamin wrote:
 On Monday, 27 July 2020 at 09:41:44 UTC, wjoe wrote:
 But it's possible when bound with the socket option 
 SO_REUSEPORT (at least that's the name of the flag on linux 
 since 3.9).
The docs say it can't be used to hijack an address.
This option must be set on each socket (including the first 
socket) prior to calling bind(2) on the socket.
Nowhere did I claim that you could hijack a bound port but that it's possible to reuse a port. Nothing prevents a UDP library from setting that option automatically or by default. Nothing prevents any program to bind to a port with that option set. Normal behavior doesn't matter - what matters is what the library you're using and other programs are doing. All of this doesn't change the fact that every program that has a socket bound to the same port on the same address at the same time will get the datagrams deliverd. One way to handle this scenario is to bind your socket with the reuse option unset. That would be first come first served. Problem not solved - you still need to consider the fact that another program or server on a different PC/address in the network can assume that their corresponding client is up and running and wants to receive on that very port. Due to the nature of UDP communication, the server needn't care if this assumption is true and send datagrams to it which you will receive instead.
Jul 28 2020
prev sibling parent Dukc <ajieskola gmail.com> writes:
Thank you everybody - Especially for the links to the blogs. This 
is just the kind of stuff I seek (didn't give a close look yet, 
though).

I think I'm going to try std.socket first, since it's in the 
standard library. If it feels like it could be easier, I'll 
consider Libasync.
Jul 19 2020