xref: /netbsd-src/external/mit/libuv/dist/docs/src/guide/networking.rst (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
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