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_can_exit - Work with
9       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_can_exit(coap_context_t *context);
35
36       For specific (D)TLS library support, link with -lcoap-3-notls,
37       -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls or
38       -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default
39       (D)TLS library support.
40

DESCRIPTION

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

RETURN VALUES

166       coap_io_process() and coap_io_process_with_fds() returns the time, in
167       milli-seconds, that was spent in the function. If -1 is returned, there
168       was an unexpected error.
169
170       coap_context_get_coap_fd() returns a non-negative number as the file
171       descriptor to monitor, or -1 if epoll is not configured in libcoap.
172
173       coap_io_prepare_io() and coap_io_prepare_epoll() returns the number of
174       milli-seconds that need to be waited before the function should next be
175       called.
176
177       coap_can_exit() returns 1 if there is nothing outstanding to transmit
178       else returns 0.
179

EXAMPLES

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

SEE ALSO

423       coap_block(3) and coap_context(3)
424

FURTHER INFORMATION

426       See "RFC7252: The Constrained Application Protocol (CoAP)" for further
427       information.
428

BUGS

430       Please report bugs on the mailing list for libcoap:
431       libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
432       https://github.com/obgm/libcoap/issues
433

AUTHORS

435       The libcoap project <libcoap-developers@lists.sourceforge.net>
436
437
438
439coap_io 4.3.1                     01/19/2023                        COAP_IO(3)
Impressum