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 - Work with CoAP I/O to do the
9 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 For specific (D)TLS library support, link with -lcoap-3-notls,
35 -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls or
36 -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default
37 (D)TLS library support.
38
40 After setting up all the contexts, resources, endpoints sessions etc.,
41 the underlying CoAP and (D)TLS need to send (and possible re-send)
42 created packets as well as receive packets for processing.
43
44 The coap_io_process() function will process any outstanding packets to
45 send for the specified context, process any available input packets and
46 then wait for processing any new input packets, or for when to
47 re-transmit a packet, for up to timeout_ms milli-seconds before
48 returning. There are 2 special case timeout_ms values.
49
50 #define COAP_IO_WAIT 0
51 #define COAP_IO_NO_WAIT ((uint32_t)-1)
52
53 If timeout_ms is set to COAP_IO_WAIT, then coap_io_process() will block
54 until the next internal action (e.g. packet retransmit) if any, or
55 block until the next packet is received whichever is the sooner and do
56 the necessary processing. If timeout_ms is set to COAP_IO_NO_WAIT, then
57 coap_io_process() will return immediately after processing without
58 waiting for any new input packets to arrive.
59
60 There are two methods of how to call coap_io_process().
61
62 1. Have coap_io_process() called from within a while() loop. Under
63 idle conditions (no input traffic) coap_io_process() will then get
64 called every timeout_ms, but more frequently if there is input /
65 retransmission traffic.
66
67 2. Wait on the file descriptor returned by coap_context_get_coap_fd()
68 using select() or an event returned by epoll_wait(). If read is
69 available on the file descriptor, call coap_io_process() with
70 timeout_ms set to COAP_IO_NO_WAIT.
71
72 NOTE: This second method is only available for environments that
73 support epoll (mostly Linux) with libcoap compiled to use epoll
74 (the default) as libcoap will then be using epoll internally to
75 process all the file descriptors of the different sessions.
76
77 See EXAMPLES below.
78
79 The coap_io_process() function is the primary function applications
80 should use. There are internal functions that coap_io_process() calls
81 which are available to use if absolutely necessary. These internal
82 functions and how to use them is different depending on whether libcoap
83 has been compiled to use epoll (Linux systems only) or not.
84
85 For epoll libcoap, coap_io_process() in simple terms calls
86 coap_io_prepare_epoll(), does an epoll_wait() and then calls
87 coap_io_do_epoll() if needed to make sure that all event based i/o has
88 been completed.
89
90 For non-epoll libcoap, coap_io_process() in simple terms calls
91 coap_io_prepare_io() to set up sockets[], sets up all of the select()
92 parameters based on the COAP_SOCKET_WANT* values in the sockets[], does
93 a select(), updates the sockets[] with COAP_SOCKET_CAN_* as appropriate
94 and then calls coap_io_do_io() to make sure that all current i/o has
95 been completed.
96
97 The coap_io_prepare_epoll() function for the specified context will
98 iterate through the endpoints and sessions to transmit any triggered
99 observer responses as well as handling any timed out packet
100 re-transmissions. Returned, based on now, is the number of milli-secs
101 needed to delay until the next time that coap_io_prepare_epoll() needs
102 to get called. After this call an epoll_wait() should done.
103
104 The coap_io_do_epoll() function for the specified context will iterate
105 through the nevents of events returned by epoll_wait() and execute the
106 appropriate low level i/o function to send / receive / process the
107 packets. Where appropriate, structure information (endpoints, sessions
108 etc.) is updated with the value of now in the lower level functions.
109
110 The coap_io_prepare_io() function for the specified context will
111 iterate through the endpoints and sessions to add all of sockets
112 waiting for network traffic (COAP_SOCKET_WANT_* is set) found to
113 sockets (limited by max_sockets) and updates num_sockets with the
114 number of sockets found. Furthermore, any triggered observer responses
115 are transmitted as well as handling any timed out packet
116 re-transmissions. Returned, based on now, is the number of milli-secs
117 needed to delay until the next time that coap_io_prepare_io() needs to
118 get called. After this call a select() should done on all the file
119 descriptors (COAP_WANT_READ for readfds etc.), and any that are
120 returned active should set the appropriate COAP_SOCKET_CAN_* in the
121 sockets.
122
123 The coap_io_do_io() function for the specified context will iterate
124 through the endpoints and sessions to find all of sockets that have
125 COAP_SOCKET_CAN_* set and then execute the appropriate low level i/o
126 function to send / receive / process the packets. Where appropriate,
127 structure information (endpoints, sessions etc.) is updated with the
128 value of now in the lower level functions.
129
130 The coap_io_process_with_fds() function is the same as
131 coap_process_io() but supports additional select() style parameters
132 nfds, readfds, writefds and exceptfds. This provides the ability to add
133 in additional non libcoap FDs to test for in the internal select() call
134 which can then tested after the return from coap_io_process_with_fds().
135 readfds, writefds and exceptfds can either point to a defined and
136 pre-filled fd_set structure or NULL if not required. nfds needs to be
137 set to the maximum FD to test for in readfds, writefds or exceptfds if
138 any of them are set plus 1. If none of them are set, then nfds should
139 be set to 0.
140
141 Note
142 The additional parameters for coap_io_process_with_fds() are only
143 used if there is no epoll support in libcoap. If there is epoll
144 support, then coap_context_get_coap_fd() should be used and this
145 returned FD along with other non libcoap FDs can separately be
146 monitored using method 2 above.
147
148 The coap_context_get_coap_fd() function obtains from the specified
149 context a single file descriptor that can be monitored by a select() or
150 as an event returned from a epoll_wait() call. This file descriptor
151 will get updated with information (read, write etc. available) whenever
152 any of the internal to libcoap file descriptors (sockets) change state.
153
155 coap_io_process() and coap_io_process_with_fds() returns the time, in
156 milli-seconds, that was spent in the function. If -1 is returned, there
157 was an unexpected error.
158
159 coap_context_get_coap_fd() returns a non-negative number as the file
160 descriptor to monitor, or -1 if epoll is not configured in libcoap.
161
162 coap_io_prepare_io() and coap_io_prepare_epoll() returns the number of
163 milli-seconds that need to be waited before the function should next be
164 called.
165
167 Method One - use coap_io_process()
168
169 #include <coap3/coap.h>
170
171 int main(int argc, char *argv[]){
172
173 coap_context_t *ctx = NULL;
174 unsigned wait_ms;
175 /* Remove (void) definition if variable is used */
176 (void)argc;
177 (void)argv;
178
179 /* Create the libcoap context */
180 ctx = coap_new_context(NULL);
181 if (!ctx) {
182 exit(1);
183 }
184 /* See coap_block(3) */
185 coap_context_set_block_mode(ctx,
186 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
187
188
189 /* Other Set up Code */
190
191 wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
192
193 while (1) {
194 int result = coap_io_process(ctx, wait_ms);
195 if (result < 0) {
196 /* There is an internal issue */
197 break;
198 }
199 /* Do any other housekeeping */
200 }
201 coap_free_context(ctx);
202
203 /* Do any other cleanup */
204
205 exit(0);
206
207 }
208
209 Method One - coap_io_process_with_fds
210
211 #include <coap3/coap.h>
212
213 int main(int argc, char *argv[]){
214
215 coap_context_t *ctx = NULL;
216 unsigned wait_ms;
217 fd_set readfds;
218 int nfds = 0;
219 /* Remove (void) definition if variable is used */
220 (void)argc;
221 (void)argv;
222
223 /* Create the libcoap context */
224 ctx = coap_new_context(NULL);
225 if (!ctx) {
226 exit(1);
227 }
228 /* See coap_block(3) */
229 coap_context_set_block_mode(ctx,
230 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
231
232
233 FD_ZERO(&readfds);
234 /* Set up readfds and nfds to handle other non libcoap FDs */
235
236 /* Other Set up Code */
237
238 wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
239
240 while (1) {
241 int result = coap_io_process_with_fds(ctx, wait_ms, nfds, &readfds, NULL, NULL);
242 if (result < 0) {
243 /* There is an internal issue */
244 break;
245 }
246 /* Check if set non libcoap FDs and process accordingly */
247
248 /* Do any other housekeeping */
249 }
250 coap_free_context(ctx);
251
252 /* Do any other cleanup */
253
254 exit(0);
255
256 }
257
258 Method Two - select() based on monitorable file descriptor
259
260 #include <coap3/coap.h>
261
262 #include <errno.h>
263
264 int main(int argc, char *argv[]){
265
266 coap_context_t *ctx = NULL;
267 int coap_fd;
268 fd_set m_readfds;
269 int nfds;
270 /* Remove (void) definition if variable is used */
271 (void)argc;
272 (void)argv;
273
274 /* Create the libcoap context */
275 ctx = coap_new_context(NULL);
276 if (!ctx) {
277 exit(1);
278 }
279 /* See coap_block(3) */
280 coap_context_set_block_mode(ctx,
281 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
282
283 coap_fd = coap_context_get_coap_fd(ctx);
284 if (coap_fd == -1) {
285 /* epoll is not supported */
286 exit(1);
287 }
288 FD_ZERO(&m_readfds);
289 FD_SET(coap_fd, &m_readfds);
290 nfds = coap_fd + 1;
291
292 /* Other Set up Code */
293
294 while (1) {
295 fd_set readfds = m_readfds;
296 int result;
297 /* Wait until any i/o takes place */
298 result = select (nfds, &readfds, NULL, NULL, NULL);
299 if (result == -1) {
300 if (errno != EAGAIN) {
301 coap_log(LOG_DEBUG, "select: %s (%d)\n", coap_socket_strerror(), errno);
302 break;
303 }
304 }
305 if (result > 0) {
306 if (FD_ISSET(coap_fd, &readfds)) {
307 result = coap_io_process(ctx, COAP_IO_NO_WAIT);
308 if (result < 0) {
309 /* There is an internal issue */
310 break;
311 }
312 }
313 }
314 /* Do any other housekeeping */
315 }
316 coap_free_context(ctx);
317
318 /* Do any other cleanup */
319
320 exit(0);
321
322 }
323
324 Method Two - epoll_wait() based on monitorable file descriptor
325
326 #include <coap3/coap.h>
327
328 #include <sys/epoll.h>
329
330 #include <errno.h>
331
332 #define MAX_EVENTS 10
333
334 int main(int argc, char *argv[]){
335
336 coap_context_t *ctx = NULL;
337 int coap_fd;
338 int epoll_fd;
339 struct epoll_event ev;
340 struct epoll_event events[MAX_EVENTS];
341 int nevents;
342 int i;
343 /* Remove (void) definition if variable is used */
344 (void)argc;
345 (void)argv;
346
347 /* Create the libcoap context */
348 ctx = coap_new_context(NULL);
349 if (!ctx) {
350 exit(1);
351 }
352 /* See coap_block(3) */
353 coap_context_set_block_mode(ctx,
354 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
355
356 coap_fd = coap_context_get_coap_fd(ctx);
357 if (coap_fd == -1) {
358 exit(1);
359 }
360 epoll_fd = epoll_create1(0);
361 if (epoll_fd == -1) {
362 exit(2);
363 }
364 ev.events = EPOLLIN;
365 ev.data.fd = coap_fd;
366 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, coap_fd, &ev) == -1) {
367 exit(3);
368 }
369
370 /* Other Set up Code */
371
372 while (1) {
373 int result;
374 /* Wait until any i/o takes place */
375 nevents = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
376 if (nevents == -1) {
377 if (errno != EAGAIN) {
378 coap_log(LOG_DEBUG, "epoll_wait: %s (%d)\n", coap_socket_strerror(), errno);
379 break;
380 }
381 }
382 for (i = 0; i < nevents; i++) {
383 if (events[i].data.fd == coap_fd) {
384 result = coap_io_process(ctx, COAP_IO_NO_WAIT);
385 if (result < 0) {
386 /* There is an internal issue */
387 break;
388 }
389 }
390 else {
391 /* Process other events */
392 }
393 }
394 /* Do any other housekeeping */
395 }
396
397 if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, coap_fd, &ev) == -1) {
398 coap_log(LOG_DEBUG, "epoll_ctl: %s (%d)\n", coap_socket_strerror(), errno);
399 }
400 coap_free_context(ctx);
401
402 /* Do any other cleanup */
403
404 exit(0);
405
406 }
407
409 coap_block(3), coap_context(3)
410
412 See "RFC7252: The Constrained Application Protocol (CoAP)" for further
413 information.
414
416 Please report bugs on the mailing list for libcoap:
417 libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
418 https://github.com/obgm/libcoap/issues
419
421 The libcoap project <libcoap-developers@lists.sourceforge.net>
422
423
424
425coap_io 4.3.0 01/20/2022 COAP_IO(3)