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