1fbb2e0a3SchristosNetworking 2fbb2e0a3Schristos========== 3fbb2e0a3Schristos 4fbb2e0a3SchristosNetworking in libuv is not much different from directly using the BSD socket 5fbb2e0a3Schristosinterface, some things are easier, all are non-blocking, but the concepts stay 6fbb2e0a3Schristosthe same. In addition libuv offers utility functions to abstract the annoying, 7fbb2e0a3Schristosrepetitive and low-level tasks like setting up sockets using the BSD socket 8fbb2e0a3Schristosstructures, DNS lookup, and tweaking various socket parameters. 9fbb2e0a3Schristos 10fbb2e0a3SchristosThe ``uv_tcp_t`` and ``uv_udp_t`` structures are used for network I/O. 11fbb2e0a3Schristos 12fbb2e0a3Schristos.. NOTE:: 13fbb2e0a3Schristos 14fbb2e0a3Schristos The code samples in this chapter exist to show certain libuv APIs. They are 15fbb2e0a3Schristos not examples of good quality code. They leak memory and don't always close 16fbb2e0a3Schristos connections properly. 17fbb2e0a3Schristos 18fbb2e0a3SchristosTCP 19fbb2e0a3Schristos--- 20fbb2e0a3Schristos 21fbb2e0a3SchristosTCP is a connection oriented, stream protocol and is therefore based on the 22fbb2e0a3Schristoslibuv streams infrastructure. 23fbb2e0a3Schristos 24fbb2e0a3SchristosServer 25fbb2e0a3Schristos++++++ 26fbb2e0a3Schristos 27fbb2e0a3SchristosServer sockets proceed by: 28fbb2e0a3Schristos 29fbb2e0a3Schristos1. ``uv_tcp_init`` the TCP handle. 30fbb2e0a3Schristos2. ``uv_tcp_bind`` it. 31fbb2e0a3Schristos3. Call ``uv_listen`` on the handle to have a callback invoked whenever a new 32fbb2e0a3Schristos connection is established by a client. 33fbb2e0a3Schristos4. Use ``uv_accept`` to accept the connection. 34fbb2e0a3Schristos5. Use :ref:`stream operations <buffers-and-streams>` to communicate with the 35fbb2e0a3Schristos client. 36fbb2e0a3Schristos 37fbb2e0a3SchristosHere is a simple echo server 38fbb2e0a3Schristos 39fbb2e0a3Schristos.. rubric:: tcp-echo-server/main.c - The listen socket 40fbb2e0a3Schristos.. literalinclude:: ../../code/tcp-echo-server/main.c 41*b29f2fbfSchristos :language: c 42fbb2e0a3Schristos :linenos: 43fbb2e0a3Schristos :lines: 68- 44fbb2e0a3Schristos :emphasize-lines: 4-5,7-10 45fbb2e0a3Schristos 46fbb2e0a3SchristosYou can see the utility function ``uv_ip4_addr`` being used to convert from 47fbb2e0a3Schristosa human readable IP address, port pair to the sockaddr_in structure required by 48fbb2e0a3Schristosthe BSD socket APIs. The reverse can be obtained using ``uv_ip4_name``. 49fbb2e0a3Schristos 50fbb2e0a3Schristos.. NOTE:: 51fbb2e0a3Schristos 52fbb2e0a3Schristos There are ``uv_ip6_*`` analogues for the ip4 functions. 53fbb2e0a3Schristos 54fbb2e0a3SchristosMost of the setup functions are synchronous since they are CPU-bound. 55fbb2e0a3Schristos``uv_listen`` is where we return to libuv's callback style. The second 56fbb2e0a3Schristosarguments is the backlog queue -- the maximum length of queued connections. 57fbb2e0a3Schristos 58fbb2e0a3SchristosWhen a connection is initiated by clients, the callback is required to set up 59fbb2e0a3Schristosa handle for the client socket and associate the handle using ``uv_accept``. 60fbb2e0a3SchristosIn this case we also establish interest in reading from this stream. 61fbb2e0a3Schristos 62fbb2e0a3Schristos.. rubric:: tcp-echo-server/main.c - Accepting the client 63fbb2e0a3Schristos.. literalinclude:: ../../code/tcp-echo-server/main.c 64*b29f2fbfSchristos :language: c 65fbb2e0a3Schristos :linenos: 66fbb2e0a3Schristos :lines: 51-66 67fbb2e0a3Schristos :emphasize-lines: 9-10 68fbb2e0a3Schristos 69fbb2e0a3SchristosThe remaining set of functions is very similar to the streams example and can 70fbb2e0a3Schristosbe found in the code. Just remember to call ``uv_close`` when the socket isn't 71fbb2e0a3Schristosrequired. This can be done even in the ``uv_listen`` callback if you are not 72fbb2e0a3Schristosinterested in accepting the connection. 73fbb2e0a3Schristos 74fbb2e0a3SchristosClient 75fbb2e0a3Schristos++++++ 76fbb2e0a3Schristos 77fbb2e0a3SchristosWhere you do bind/listen/accept on the server, on the client side it's simply 78fbb2e0a3Schristosa matter of calling ``uv_tcp_connect``. The same ``uv_connect_cb`` style 79fbb2e0a3Schristoscallback of ``uv_listen`` is used by ``uv_tcp_connect``. Try:: 80fbb2e0a3Schristos 81fbb2e0a3Schristos uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); 82fbb2e0a3Schristos uv_tcp_init(loop, socket); 83fbb2e0a3Schristos 84fbb2e0a3Schristos uv_connect_t* connect = (uv_connect_t*)malloc(sizeof(uv_connect_t)); 85fbb2e0a3Schristos 86fbb2e0a3Schristos struct sockaddr_in dest; 87fbb2e0a3Schristos uv_ip4_addr("127.0.0.1", 80, &dest); 88fbb2e0a3Schristos 89fbb2e0a3Schristos uv_tcp_connect(connect, socket, (const struct sockaddr*)&dest, on_connect); 90fbb2e0a3Schristos 91fbb2e0a3Schristoswhere ``on_connect`` will be called after the connection is established. The 92fbb2e0a3Schristoscallback receives the ``uv_connect_t`` struct, which has a member ``.handle`` 93fbb2e0a3Schristospointing to the socket. 94fbb2e0a3Schristos 95fbb2e0a3SchristosUDP 96fbb2e0a3Schristos--- 97fbb2e0a3Schristos 98fbb2e0a3SchristosThe `User Datagram Protocol`_ offers connectionless, unreliable network 99fbb2e0a3Schristoscommunication. Hence libuv doesn't offer a stream. Instead libuv provides 100fbb2e0a3Schristosnon-blocking UDP support via the `uv_udp_t` handle (for receiving) and 101fbb2e0a3Schristos`uv_udp_send_t` request (for sending) and related functions. That said, the 102fbb2e0a3Schristosactual API for reading/writing is very similar to normal stream reads. To look 103fbb2e0a3Schristosat how UDP can be used, the example shows the first stage of obtaining an IP 104fbb2e0a3Schristosaddress from a `DHCP`_ server -- DHCP Discover. 105fbb2e0a3Schristos 106fbb2e0a3Schristos.. note:: 107fbb2e0a3Schristos 108fbb2e0a3Schristos You will have to run `udp-dhcp` as **root** since it uses well known port 109fbb2e0a3Schristos numbers below 1024. 110fbb2e0a3Schristos 111fbb2e0a3Schristos.. rubric:: udp-dhcp/main.c - Setup and send UDP packets 112fbb2e0a3Schristos.. literalinclude:: ../../code/udp-dhcp/main.c 113*b29f2fbfSchristos :language: c 114fbb2e0a3Schristos :linenos: 115fbb2e0a3Schristos :lines: 7-11,104- 116fbb2e0a3Schristos :emphasize-lines: 8,10-11,17-18,21 117fbb2e0a3Schristos 118fbb2e0a3Schristos.. note:: 119fbb2e0a3Schristos 120fbb2e0a3Schristos The IP address ``0.0.0.0`` is used to bind to all interfaces. The IP 121fbb2e0a3Schristos address ``255.255.255.255`` is a broadcast address meaning that packets 122fbb2e0a3Schristos will be sent to all interfaces on the subnet. port ``0`` means that the OS 123fbb2e0a3Schristos randomly assigns a port. 124fbb2e0a3Schristos 125fbb2e0a3SchristosFirst we setup the receiving socket to bind on all interfaces on port 68 (DHCP 126fbb2e0a3Schristosclient) and start a read on it. This will read back responses from any DHCP 127fbb2e0a3Schristosserver that replies. We use the UV_UDP_REUSEADDR flag to play nice with any 128fbb2e0a3Schristosother system DHCP clients that are running on this computer on the same port. 129fbb2e0a3SchristosThen we setup a similar send socket and use ``uv_udp_send`` to send 130fbb2e0a3Schristosa *broadcast message* on port 67 (DHCP server). 131fbb2e0a3Schristos 132fbb2e0a3SchristosIt is **necessary** to set the broadcast flag, otherwise you will get an 133fbb2e0a3Schristos``EACCES`` error [#]_. The exact message being sent is not relevant to this 134fbb2e0a3Schristosbook and you can study the code if you are interested. As usual the read and 135fbb2e0a3Schristoswrite callbacks will receive a status code of < 0 if something went wrong. 136fbb2e0a3Schristos 137fbb2e0a3SchristosSince UDP sockets are not connected to a particular peer, the read callback 138fbb2e0a3Schristosreceives an extra parameter about the sender of the packet. 139fbb2e0a3Schristos 140fbb2e0a3Schristos``nread`` may be zero if there is no more data to be read. If ``addr`` is NULL, 141fbb2e0a3Schristosit indicates there is nothing to read (the callback shouldn't do anything), if 142fbb2e0a3Schristosnot NULL, it indicates that an empty datagram was received from the host at 143fbb2e0a3Schristos``addr``. The ``flags`` parameter may be ``UV_UDP_PARTIAL`` if the buffer 144fbb2e0a3Schristosprovided by your allocator was not large enough to hold the data. *In this case 145fbb2e0a3Schristosthe OS will discard the data that could not fit* (That's UDP for you!). 146fbb2e0a3Schristos 147fbb2e0a3Schristos.. rubric:: udp-dhcp/main.c - Reading packets 148fbb2e0a3Schristos.. literalinclude:: ../../code/udp-dhcp/main.c 149*b29f2fbfSchristos :language: c 150fbb2e0a3Schristos :linenos: 151fbb2e0a3Schristos :lines: 17-40 152fbb2e0a3Schristos :emphasize-lines: 1,23 153fbb2e0a3Schristos 154fbb2e0a3SchristosUDP Options 155fbb2e0a3Schristos+++++++++++ 156fbb2e0a3Schristos 157fbb2e0a3SchristosTime-to-live 158fbb2e0a3Schristos~~~~~~~~~~~~ 159fbb2e0a3Schristos 160fbb2e0a3SchristosThe TTL of packets sent on the socket can be changed using ``uv_udp_set_ttl``. 161fbb2e0a3Schristos 162fbb2e0a3SchristosIPv6 stack only 163fbb2e0a3Schristos~~~~~~~~~~~~~~~ 164fbb2e0a3Schristos 165fbb2e0a3SchristosIPv6 sockets can be used for both IPv4 and IPv6 communication. If you want to 166fbb2e0a3Schristosrestrict the socket to IPv6 only, pass the ``UV_UDP_IPV6ONLY`` flag to 167fbb2e0a3Schristos``uv_udp_bind`` [#]_. 168fbb2e0a3Schristos 169fbb2e0a3SchristosMulticast 170fbb2e0a3Schristos~~~~~~~~~ 171fbb2e0a3Schristos 172fbb2e0a3SchristosA socket can (un)subscribe to a multicast group using: 173fbb2e0a3Schristos 174fbb2e0a3Schristos.. code::block:: c 175fbb2e0a3Schristos 176fbb2e0a3Schristos int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, uv_membership membership); 177fbb2e0a3Schristos 178fbb2e0a3Schristoswhere ``membership`` is ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``. 179fbb2e0a3Schristos 180fbb2e0a3SchristosThe concepts of multicasting are nicely explained in `this guide`_. 181fbb2e0a3Schristos 182fbb2e0a3Schristos.. _this guide: https://www.tldp.org/HOWTO/Multicast-HOWTO-2.html 183fbb2e0a3Schristos 184fbb2e0a3SchristosLocal loopback of multicast packets is enabled by default [#]_, use 185fbb2e0a3Schristos``uv_udp_set_multicast_loop`` to switch it off. 186fbb2e0a3Schristos 187fbb2e0a3SchristosThe packet time-to-live for multicast packets can be changed using 188fbb2e0a3Schristos``uv_udp_set_multicast_ttl``. 189fbb2e0a3Schristos 190fbb2e0a3SchristosQuerying DNS 191fbb2e0a3Schristos------------ 192fbb2e0a3Schristos 193fbb2e0a3Schristoslibuv provides asynchronous DNS resolution. For this it provides its own 194fbb2e0a3Schristos``getaddrinfo`` replacement [#]_. In the callback you can 195fbb2e0a3Schristosperform normal socket operations on the retrieved addresses. Let's connect to 196*b29f2fbfSchristosLibera.chat to see an example of DNS resolution. 197fbb2e0a3Schristos 198fbb2e0a3Schristos.. rubric:: dns/main.c 199fbb2e0a3Schristos.. literalinclude:: ../../code/dns/main.c 200*b29f2fbfSchristos :language: c 201fbb2e0a3Schristos :linenos: 202fbb2e0a3Schristos :lines: 61- 203fbb2e0a3Schristos :emphasize-lines: 12 204fbb2e0a3Schristos 205fbb2e0a3SchristosIf ``uv_getaddrinfo`` returns non-zero, something went wrong in the setup and 206fbb2e0a3Schristosyour callback won't be invoked at all. All arguments can be freed immediately 207fbb2e0a3Schristosafter ``uv_getaddrinfo`` returns. The `hostname`, `servname` and `hints` 208*b29f2fbfSchristosstructures are documented in `the getaddrinfo man page <getaddrinfo_>`_. The 209fbb2e0a3Schristoscallback can be ``NULL`` in which case the function will run synchronously. 210fbb2e0a3Schristos 211fbb2e0a3SchristosIn the resolver callback, you can pick any IP from the linked list of ``struct 212fbb2e0a3Schristosaddrinfo(s)``. This also demonstrates ``uv_tcp_connect``. It is necessary to 213fbb2e0a3Schristoscall ``uv_freeaddrinfo`` in the callback. 214fbb2e0a3Schristos 215fbb2e0a3Schristos.. rubric:: dns/main.c 216fbb2e0a3Schristos.. literalinclude:: ../../code/dns/main.c 217*b29f2fbfSchristos :language: c 218fbb2e0a3Schristos :linenos: 219fbb2e0a3Schristos :lines: 42-60 220fbb2e0a3Schristos :emphasize-lines: 8,16 221fbb2e0a3Schristos 222fbb2e0a3Schristoslibuv also provides the inverse `uv_getnameinfo`_. 223fbb2e0a3Schristos 224fbb2e0a3Schristos.. _uv_getnameinfo: http://docs.libuv.org/en/v1.x/dns.html#c.uv_getnameinfo 225fbb2e0a3Schristos 226fbb2e0a3SchristosNetwork interfaces 227fbb2e0a3Schristos------------------ 228fbb2e0a3Schristos 229fbb2e0a3SchristosInformation about the system's network interfaces can be obtained through libuv 230fbb2e0a3Schristosusing ``uv_interface_addresses``. This simple program just prints out all the 231fbb2e0a3Schristosinterface details so you get an idea of the fields that are available. This is 232fbb2e0a3Schristosuseful to allow your service to bind to IP addresses when it starts. 233fbb2e0a3Schristos 234fbb2e0a3Schristos.. rubric:: interfaces/main.c 235fbb2e0a3Schristos.. literalinclude:: ../../code/interfaces/main.c 236*b29f2fbfSchristos :language: c 237fbb2e0a3Schristos :linenos: 238fbb2e0a3Schristos :emphasize-lines: 9,17 239fbb2e0a3Schristos 240fbb2e0a3Schristos``is_internal`` is true for loopback interfaces. Note that if a physical 241fbb2e0a3Schristosinterface has multiple IPv4/IPv6 addresses, the name will be reported multiple 242fbb2e0a3Schristostimes, with each address being reported once. 243fbb2e0a3Schristos 244fbb2e0a3Schristos.. _c-ares: https://c-ares.haxx.se 245*b29f2fbfSchristos.. _getaddrinfo: https://man7.org/linux/man-pages/man3/getaddrinfo.3.html 246fbb2e0a3Schristos 247fbb2e0a3Schristos.. _User Datagram Protocol: https://en.wikipedia.org/wiki/User_Datagram_Protocol 248fbb2e0a3Schristos.. _DHCP: https://tools.ietf.org/html/rfc2131 249fbb2e0a3Schristos 250fbb2e0a3Schristos---- 251fbb2e0a3Schristos 252fbb2e0a3Schristos.. [#] https://beej.us/guide/bgnet/html/#broadcast-packetshello-world 253fbb2e0a3Schristos.. [#] on Windows only supported on Windows Vista and later. 254fbb2e0a3Schristos.. [#] https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html#ss6.1 255fbb2e0a3Schristos.. [#] libuv use the system ``getaddrinfo`` in the libuv threadpool. libuv 256fbb2e0a3Schristos v0.8.0 and earlier also included c-ares_ as an alternative, but this has been 257fbb2e0a3Schristos removed in v0.9.0. 258