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