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