1COAP_IO(3) libcoap Manual COAP_IO(3)
2
3
4
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
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
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
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
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
423 coap_block(3) and coap_context(3)
424
426 See "RFC7252: The Constrained Application Protocol (CoAP)" for further
427 information.
428
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
435 The libcoap project <libcoap-developers@lists.sourceforge.net>
436
437
438
439coap_io 4.3.1 11/24/2022 COAP_IO(3)