1COAP_IO(3)                      libcoap Manual                      COAP_IO(3)
2
3
4

NAME

6       coap_io, coap_io_process, coap_io_process_with_fds,
7       coap_context_get_coap_fd, coap_io_prepare_io, coap_io_do_io,
8       coap_io_prepare_epoll, coap_io_do_epoll, coap_io_pending, coap_can_exit
9       - Work with CoAP I/O to do the packet send and receives
10

SYNOPSIS

12       #include <coap3/coap.h>
13
14       int coap_io_process(coap_context_t *context, uint32_t timeout_ms);
15
16       int coap_io_process_with_fds(coap_context_t *context, uint32_t
17       timeout_ms, int nfds, fd_set *readfds, fd_set *writefds, fd_set
18       *exceptfds);
19
20       int coap_context_get_coap_fd(const coap_context_t *context);
21
22       unsigned int coap_io_prepare_io(coap_context_t *context, coap_socket_t
23       *sockets[], unsigned int max_sockets, unsigned int *num_sockets,
24       coap_tick_t now);
25
26       void coap_io_do_io(coap_context_t *context, coap_tick_t now);
27
28       unsigned int coap_io_prepare_epoll(coap_context_t *context, coap_tick_t
29       now);
30
31       void coap_io_do_epoll(coap_context_t *context, struct epoll_event
32       *events, size_t nevents);
33
34       int coap_io_pending(coap_context_t *context);
35
36       int coap_can_exit(coap_context_t *context);
37
38       For specific (D)TLS library support, link with -lcoap-3-notls,
39       -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls or
40       -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default
41       (D)TLS library support.
42

DESCRIPTION

44       After setting up all the contexts, resources, endpoints sessions etc.,
45       the underlying CoAP and (D)TLS need to send (and possible re-send)
46       created packets as well as receive packets for processing.
47
48       The coap_io_process() function is the primary function applications
49       should use. There are internal functions that coap_io_process() calls
50       which are available to use if absolutely necessary. These internal
51       functions and how to use them is different depending on whether libcoap
52       has been compiled to use epoll (Linux systems only) or not.
53
54       For epoll libcoap, coap_io_process() in simple terms calls
55       coap_io_prepare_epoll(), does an epoll_wait() and then calls
56       coap_io_do_epoll() if needed to make sure that all event based i/o has
57       been completed.
58
59       For non-epoll libcoap, coap_io_process() in simple terms calls
60       coap_io_prepare_io() to set up sockets[], sets up all of the select()
61       parameters based on the COAP_SOCKET_WANT* values in the sockets[], does
62       a select(), updates the sockets[] with COAP_SOCKET_CAN_* as appropriate
63       and then calls coap_io_do_io() to make sure that all current i/o has
64       been completed.
65

FUNCTIONS

67       Function: coap_io_process()
68
69       The coap_io_process() function will process any outstanding packets to
70       send for the specified context, process any available input packets and
71       then wait for processing any new input packets, or for when to
72       re-transmit a packet, for up to timeout_ms milli-seconds before
73       returning. There are 2 special case timeout_ms values.
74
75           #define COAP_IO_WAIT    0
76           #define COAP_IO_NO_WAIT ((uint32_t)-1)
77
78       If timeout_ms is set to COAP_IO_WAIT, then coap_io_process() will block
79       until the next internal action (e.g. packet retransmit) if any, or
80       block until the next packet is received whichever is the sooner and do
81       the necessary processing. If timeout_ms is set to COAP_IO_NO_WAIT, then
82       coap_io_process() will return immediately after processing without
83       waiting for any new input packets to arrive.
84
85       NOTE: coap_io_process() should not be called from within a callback
86       handler as defined using the coap_register_*_handler() as
87       coap_io_process() will likely recursively call the same handler.
88
89       There are two methods of how to call coap_io_process().
90
91        1. Have coap_io_process() called from within a while() loop. Under
92           idle conditions (no input traffic) coap_io_process() will then get
93           called every timeout_ms, but more frequently if there is input /
94           retransmission traffic.
95
96        2. Wait on the file descriptor returned by coap_context_get_coap_fd()
97           using select(), poll() or an event returned by epoll_wait(). If
98           read is available on the CoAP file descriptor, call
99           coap_io_process() with timeout_ms set to COAP_IO_NO_WAIT.
100
101           NOTE: This second method is only available for environments that
102           support epoll (mostly Linux) with libcoap compiled to use epoll
103           (the default) as libcoap will then be using epoll internally to
104           process all the file descriptors of the different sessions.
105
106       See EXAMPLES below.
107
108       Function: coap_io_prepare_epoll()
109
110       The coap_io_prepare_epoll() function for the specified context will
111       iterate through the endpoints and sessions to transmit any triggered
112       observer responses as well as handling any timed out packet
113       re-transmissions. Returned, based on now, is the number of milli-secs
114       needed to delay until the next time that coap_io_prepare_epoll() needs
115       to get called. After this call an epoll_wait() should done.
116
117       Function: coap_io_do_epoll()
118
119       The coap_io_do_epoll() function for the specified context will iterate
120       through the nevents of events returned by epoll_wait() and execute the
121       appropriate low level i/o function to send / receive / process the
122       packets. Where appropriate, structure information (endpoints, sessions
123       etc.) is updated with the value of now in the lower level functions.
124
125       Function: coap_io_prepare_io()
126
127       The coap_io_prepare_io() function for the specified context will
128       iterate through the endpoints and sessions to add all of sockets
129       waiting for network traffic (COAP_SOCKET_WANT_* is set) found to
130       sockets (limited by max_sockets) and updates num_sockets with the
131       number of sockets found. Furthermore, any triggered observer responses
132       are transmitted as well as handling any timed out packet
133       re-transmissions. Returned, based on now, is the number of milli-secs
134       needed to delay until the next time that coap_io_prepare_io() needs to
135       get called. After this call a select() should done on all the file
136       descriptors (COAP_WANT_READ for readfds etc.), and any that are
137       returned active should set the appropriate COAP_SOCKET_CAN_* in the
138       sockets.
139
140       Function: coap_io_do_io()
141
142       The coap_io_do_io() function for the specified context will iterate
143       through the endpoints and sessions to find all of sockets that have
144       COAP_SOCKET_CAN_* set and then execute the appropriate low level i/o
145       function to send / receive / process the packets. Where appropriate,
146       structure information (endpoints, sessions etc.) is updated with the
147       value of now in the lower level functions.
148
149       Function: coap_io_process_with_fds()
150
151       The coap_io_process_with_fds() function is the same as
152       coap_process_io() but supports additional select() style parameters
153       nfds, readfds, writefds and exceptfds. This provides the ability to add
154       in additional non libcoap FDs to test for in the internal select() call
155       which can then tested after the return from coap_io_process_with_fds().
156       readfds, writefds and exceptfds can either point to a defined and
157       pre-filled fd_set structure or NULL if not required. nfds needs to be
158       set to the maximum FD to test for in readfds, writefds or exceptfds if
159       any of them are set plus 1. If none of them are set, then nfds should
160       be set to 0.
161
162       NOTE: The additional parameters for coap_io_process_with_fds() are only
163       used if there is no epoll support in libcoap. If there is epoll
164       support, then coap_context_get_coap_fd() should be used and this
165       returned FD along with other non libcoap FDs can separately be
166       monitored using method 2 above.
167
168       Function: coap_context_get_coap_fd()
169
170       The coap_context_get_coap_fd() function obtains from the specified
171       context a single file descriptor that can be monitored by a select() or
172       as an event returned from a epoll_wait() call. This file descriptor
173       will get updated with information (read, write etc. available) whenever
174       any of the internal to libcoap file descriptors (sockets) change state.
175
176       Function: coap_io_pending()
177
178       The coap_io_pending() function checks to see if there are any
179       outstanding i/o requests / responses associated with context as well as
180       if Observe has been set up (client only) and large transfers are in
181       process.
182
183       Function: coap_can_exit()
184
185       The coap_can_exit() function checks to see if there are any outstanding
186       PDUs to transmit associated with context and returns 1 if there is
187       nothing outstanding else 0. This function does not check that all
188       requests transmitted have been responded to.
189

RETURN VALUES

191       coap_io_process() and coap_io_process_with_fds() return the time, in
192       milli-seconds, that was spent in the function. If -1 is returned, there
193       was an unexpected error.
194
195       coap_context_get_coap_fd() returns a non-negative number as the file
196       descriptor to monitor, or -1 if epoll is not configured in libcoap.
197
198       coap_io_prepare_io() and coap_io_prepare_epoll() return the number of
199       milli-seconds that need to be waited before the function should next be
200       called.
201
202       coap_io_pending() returns 1 if there is outstanding i/o else returns 0.
203
204       coap_can_exit() returns 1 if there is nothing outstanding to transmit
205       else returns 0.
206

EXAMPLES

208       Method One - use coap_io_process()
209
210           #include <coap3/coap.h>
211
212           int
213           main(int argc, char *argv[]) {
214
215             coap_context_t *ctx = NULL;
216             unsigned wait_ms;
217             /* Remove (void) definition if variable is used */
218             (void)argc;
219             (void)argv;
220
221             /* Initialize libcoap library */
222             coap_startup();
223
224             /* Create the libcoap context */
225             ctx = coap_new_context(NULL);
226             if (!ctx) {
227               exit(1);
228             }
229             /* See coap_block(3) */
230             coap_context_set_block_mode(ctx,
231                                         COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
232
233
234             /* Other Set up Code */
235
236             wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
237
238             while (1) {
239               int result = coap_io_process(ctx, wait_ms);
240               if (result < 0) {
241                 /* There is an internal issue */
242                 break;
243               }
244               /* Do any other housekeeping */
245             }
246             coap_free_context(ctx);
247             coap_cleanup();
248
249             /* Do any other cleanup */
250
251             exit(0);
252
253           }
254
255       Method One - coap_io_process_with_fds
256
257           #include <coap3/coap.h>
258
259           int
260           main(int argc, char *argv[]) {
261
262             coap_context_t *ctx = NULL;
263             unsigned wait_ms;
264             fd_set readfds;
265             int nfds = 0;
266             /* Remove (void) definition if variable is used */
267             (void)argc;
268             (void)argv;
269
270             /* Initialize libcoap library */
271             coap_startup();
272
273             /* Create the libcoap context */
274             ctx = coap_new_context(NULL);
275             if (!ctx) {
276               exit(1);
277             }
278             /* See coap_block(3) */
279             coap_context_set_block_mode(ctx,
280                                         COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
281
282
283             FD_ZERO(&readfds);
284             /* Set up readfds and nfds to handle other non libcoap FDs */
285
286             /* Other Set up Code */
287
288             wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
289
290             while (1) {
291               int result = coap_io_process_with_fds(ctx, wait_ms, nfds, &readfds, NULL, NULL);
292               if (result < 0) {
293                 /* There is an internal issue */
294                 break;
295               }
296               /* Check if set non libcoap FDs and process accordingly */
297
298               /* Do any other housekeeping */
299             }
300             coap_free_context(ctx);
301             coap_cleanup();
302
303             /* Do any other cleanup */
304
305             exit(0);
306
307           }
308
309       Method Two - select() based on monitorable file descriptor
310
311           #include <coap3/coap.h>
312
313           #include <errno.h>
314
315           int
316           main(int argc, char *argv[]) {
317
318             coap_context_t *ctx = NULL;
319             int coap_fd;
320             fd_set m_readfds;
321             int nfds;
322             /* Remove (void) definition if variable is used */
323             (void)argc;
324             (void)argv;
325
326             /* Initialize libcoap library */
327             coap_startup();
328
329             /* Create the libcoap context */
330             ctx = coap_new_context(NULL);
331             if (!ctx) {
332               exit(1);
333             }
334             /* See coap_block(3) */
335             coap_context_set_block_mode(ctx,
336                                         COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
337
338             coap_fd = coap_context_get_coap_fd(ctx);
339             if (coap_fd == -1) {
340               /* epoll is not supported */
341               exit(1);
342             }
343             FD_ZERO(&m_readfds);
344             FD_SET(coap_fd, &m_readfds);
345             nfds = coap_fd + 1;
346
347             /* Other Set up Code */
348
349             while (1) {
350               fd_set readfds = m_readfds;
351               int result;
352               /* Wait until any i/o takes place */
353               result = select (nfds, &readfds, NULL, NULL, NULL);
354               if (result == -1) {
355                 if (errno != EAGAIN) {
356                   coap_log_debug("select: %s (%d)\n", coap_socket_strerror(), errno);
357                   break;
358                 }
359               }
360               if (result > 0) {
361                 if (FD_ISSET(coap_fd, &readfds)) {
362                   result = coap_io_process(ctx, COAP_IO_NO_WAIT);
363                   if (result < 0) {
364                     /* There is an internal issue */
365                     break;
366                   }
367                 }
368               }
369               /* Do any other housekeeping */
370             }
371             coap_free_context(ctx);
372             coap_cleanup();
373
374             /* Do any other cleanup */
375
376             exit(0);
377
378           }
379
380       Method Two - epoll_wait() based on monitorable file descriptor
381
382           #include <coap3/coap.h>
383
384           #include <sys/epoll.h>
385
386           #include <errno.h>
387
388           #define MAX_EVENTS 10
389
390           int
391           main(int argc, char *argv[]) {
392
393             coap_context_t *ctx = NULL;
394             int coap_fd;
395             int epoll_fd;
396             struct epoll_event ev;
397             struct epoll_event events[MAX_EVENTS];
398             int nevents;
399             int i;
400             /* Remove (void) definition if variable is used */
401             (void)argc;
402             (void)argv;
403
404             /* Initialize libcoap library */
405             coap_startup();
406
407             /* Create the libcoap context */
408             ctx = coap_new_context(NULL);
409             if (!ctx) {
410               exit(1);
411             }
412             /* See coap_block(3) */
413             coap_context_set_block_mode(ctx,
414                                         COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
415
416             coap_fd = coap_context_get_coap_fd(ctx);
417             if (coap_fd == -1) {
418               exit(1);
419             }
420             epoll_fd = epoll_create1(0);
421             if (epoll_fd == -1) {
422               exit(2);
423             }
424             ev.events = EPOLLIN;
425             ev.data.fd = coap_fd;
426             if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, coap_fd, &ev) == -1) {
427               exit(3);
428             }
429
430             /* Other Set up Code */
431
432             while (1) {
433               int result;
434               /* Wait until any i/o takes place */
435               nevents = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
436               if (nevents == -1) {
437                 if (errno != EAGAIN) {
438                   coap_log_debug("epoll_wait: %s (%d)\n", coap_socket_strerror(), errno);
439                   break;
440                 }
441               }
442               for (i = 0; i < nevents; i++) {
443                 if (events[i].data.fd == coap_fd) {
444                   result = coap_io_process(ctx, COAP_IO_NO_WAIT);
445                   if (result < 0) {
446                     /* There is an internal issue */
447                     break;
448                   }
449                 }
450                 else {
451                   /* Process other events */
452                 }
453               }
454               /* Do any other housekeeping */
455             }
456
457             if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, coap_fd, &ev) == -1) {
458               coap_log_debug("epoll_ctl: %s (%d)\n", coap_socket_strerror(), errno);
459             }
460             coap_free_context(ctx);
461             coap_cleanup();
462
463             /* Do any other cleanup */
464
465             exit(0);
466
467           }
468

SEE ALSO

470       coap_block(3), coap_context(3) and coap_init(3)
471

FURTHER INFORMATION

473       See
474
475       "RFC7252: The Constrained Application Protocol (CoAP)"
476
477       for further information.
478

BUGS

480       Please report bugs on the mailing list for libcoap:
481       libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
482       https://github.com/obgm/libcoap/issues
483

AUTHORS

485       The libcoap project <libcoap-developers@lists.sourceforge.net>
486
487
488
489coap_io 4.3.4                     10/09/2023                        COAP_IO(3)
Impressum