• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// -*- mode:doc; -*-
2// vim: set syntax=asciidoc tw=0
3
4coap_io(3)
5==========
6:doctype: manpage
7:man source:   coap_io
8:man version:  @PACKAGE_VERSION@
9:man manual:   libcoap Manual
10
11NAME
12----
13coap_io,
14coap_io_process,
15coap_io_process_with_fds,
16coap_context_get_coap_fd,
17coap_io_prepare_io,
18coap_io_do_io,
19coap_io_prepare_epoll,
20coap_io_do_epoll,
21coap_io_pending,
22coap_can_exit
23- Work with CoAP I/O to do the packet send and receives
24
25SYNOPSIS
26--------
27*#include <coap@LIBCOAP_API_VERSION@/coap.h>*
28
29*int coap_io_process(coap_context_t *_context_, uint32_t _timeout_ms_)*;
30
31*int coap_io_process_with_fds(coap_context_t *_context_,
32uint32_t _timeout_ms_, int _nfds_, fd_set *_readfds_, fd_set *_writefds_,
33fd_set *_exceptfds_)*;
34
35*int coap_context_get_coap_fd(const coap_context_t *_context_)*;
36
37*unsigned int coap_io_prepare_io(coap_context_t *_context_,
38coap_socket_t *_sockets_[], unsigned int _max_sockets_,
39unsigned int *_num_sockets_, coap_tick_t _now_)*;
40
41*void coap_io_do_io(coap_context_t *_context_, coap_tick_t _now_)*;
42
43*unsigned int coap_io_prepare_epoll(coap_context_t *_context_,
44coap_tick_t _now_)*;
45
46*void coap_io_do_epoll(coap_context_t *_context_, struct epoll_event *_events_,
47size_t _nevents_)*;
48
49*int coap_io_pending(coap_context_t *_context_)*;
50
51*int coap_can_exit(coap_context_t *_context_)*;
52
53For specific (D)TLS library support, link with
54*-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*,
55*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls*
56or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*.   Otherwise, link with
57*-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support.
58
59DESCRIPTION
60-----------
61After setting up all the contexts, resources, endpoints sessions etc., the
62underlying CoAP and (D)TLS need to send (and possible re-send) created packets
63as well as receive packets for processing.
64
65The *coap_io_process*() function is the primary function applications should
66use. There are internal functions that *coap_io_process*() calls which are
67available to use if absolutely necessary.  These internal functions and how to
68use them is different depending on whether libcoap has been compiled to use
69*epoll* (Linux systems only) or not.
70
71For *epoll* libcoap, *coap_io_process*() in simple terms calls
72*coap_io_prepare_epoll*(), does an *epoll_wait*() and then calls
73*coap_io_do_epoll*() if needed to make sure that all event based i/o has been
74completed.
75
76For *non-epoll* libcoap, *coap_io_process*() in simple terms calls
77*coap_io_prepare_io*() to set up sockets[], sets up all of the *select*()
78parameters based on the COAP_SOCKET_WANT* values in the sockets[], does a
79*select*(), updates the sockets[] with COAP_SOCKET_CAN_* as appropriate and
80then calls *coap_io_do_io*() to make sure that all current i/o has been
81completed.
82
83FUNCTIONS
84---------
85
86*Function: coap_io_process()*
87
88The *coap_io_process*() function will process any outstanding packets to send
89for the specified _context_, process any available input packets and then wait
90for processing any new input packets, or for when to re-transmit a packet, for
91up to _timeout_ms_ milli-seconds before returning. There are 2 special case
92_timeout_ms_ values.
93[source, c]
94----
95#define COAP_IO_WAIT    0
96#define COAP_IO_NO_WAIT ((uint32_t)-1)
97----
98If _timeout_ms_ is set to COAP_IO_WAIT, then *coap_io_process*() will block
99until the next internal action (e.g. packet retransmit) if any, or block until
100the next packet is received whichever is the sooner and do the necessary
101processing. If _timeout_ms_ is set to COAP_IO_NO_WAIT, then *coap_io_process*()
102will return immediately after processing without waiting for any new input
103packets to arrive.
104
105*NOTE:* *coap_io_process*() should not be called from within a callback
106handler as defined using the coap_register_*_handler() as *coap_io_process*()
107will likely recursively call the same handler.
108
109There are two methods of how to call *coap_io_process*().
110
1111. Have *coap_io_process*() called from within a while() loop.  Under idle
112conditions (no input traffic) *coap_io_process*() will then get called every
113_timeout_ms_, but more frequently if there is input / retransmission traffic.
114
1152. Wait on the file descriptor returned by *coap_context_get_coap_fd*()
116using *select*(), *poll*() or an event returned by epoll_wait(). If 'read' is
117available on the CoAP file descriptor, call *coap_io_process*() with
118_timeout_ms_ set to COAP_IO_NO_WAIT. +
119*NOTE*: This second method is only available for environments that support epoll
120(mostly Linux) with libcoap compiled to use *epoll* (the default) as libcoap
121will then be using *epoll* internally to process all the file descriptors of
122the different sessions.
123
124See EXAMPLES below.
125
126*Function: coap_io_prepare_epoll()*
127
128The *coap_io_prepare_epoll*() function for the specified _context_ will
129iterate through the endpoints and sessions to transmit any triggered observer
130responses as well as handling any timed out packet re-transmissions.  Returned,
131based on _now_, is the number of milli-secs needed to delay until the next
132time that *coap_io_prepare_epoll*() needs to get called.  After this call an
133*epoll_wait*() should done.
134
135*Function: coap_io_do_epoll()*
136
137The *coap_io_do_epoll*() function for the specified _context_ will
138iterate through the _nevents_ of _events_ returned by *epoll_wait*() and
139execute the appropriate low level i/o function to send / receive / process the
140packets. Where appropriate, structure information (endpoints, sessions etc.)
141is updated with the value of _now_ in the lower level functions.
142
143*Function: coap_io_prepare_io()*
144
145The *coap_io_prepare_io*() function for the specified _context_ will iterate
146through the endpoints and sessions to add all of sockets waiting for network
147traffic (COAP_SOCKET_WANT_* is set) found to _sockets_ (limited by
148_max_sockets_) and updates _num_sockets_ with the number of sockets found.
149Furthermore, any triggered observer responses are transmitted
150as well as handling any timed out packet re-transmissions.  Returned, based on
151_now_, is the number of milli-secs needed to delay until the next time that
152*coap_io_prepare_io*() needs to get called.  After this call a *select*() should
153done on all the file descriptors (COAP_WANT_READ for readfds etc.), and any
154that are returned active should set the appropriate COAP_SOCKET_CAN_* in the
155_sockets_.
156
157*Function: coap_io_do_io()*
158
159The *coap_io_do_io*() function for the specified _context_ will
160iterate through the endpoints and sessions to find all of sockets that have
161COAP_SOCKET_CAN_* set and then execute the appropriate low level i/o function
162to send / receive / process the packets. Where appropriate, structure
163information (endpoints, sessions etc.) is updated with the value of _now_ in
164the lower level functions.
165
166*Function: coap_io_process_with_fds()*
167
168The *coap_io_process_with_fds*() function is the same as *coap_process_io*()
169but supports additional select() style parameters _nfds_, _readfds_,
170_writefds_ and _exceptfds_. This provides the ability to add in additional
171non libcoap FDs to test for in the internal select() call which can then
172tested after the return from coap_io_process_with_fds(). _readfds_,
173_writefds_ and _exceptfds_ can either point to a defined and pre-filled fd_set
174structure or NULL if not required. _nfds_ needs to be set to the maximum FD to
175test for in _readfds_, _writefds_ or _exceptfds_ if any of them are set plus 1.
176If none of them are set, then _nfds_ should be set to 0.
177
178*NOTE:* The additional parameters for *coap_io_process_with_fds*() are only used
179if there is no epoll support in libcoap. If there is epoll support, then
180*coap_context_get_coap_fd*() should be used and this returned FD along with
181other non libcoap FDs can separately be monitored using method 2 above.
182
183*Function: coap_context_get_coap_fd()*
184
185The *coap_context_get_coap_fd*() function obtains from the specified
186_context_ a single file descriptor that can be monitored by a *select*() or
187as an event returned from a *epoll_wait*() call.  This file descriptor will get
188updated with information (read, write etc. available) whenever any of the
189internal to libcoap file descriptors (sockets) change state.
190
191*Function: coap_io_pending()*
192
193The *coap_io_pending*() function checks to see if there are any outstanding
194i/o requests / responses associated with _context_ as well as if Observe has
195been set up (client only) and large transfers are in process.
196
197*Function: coap_can_exit()*
198
199The *coap_can_exit*() function checks to see if there are any outstanding
200PDUs to transmit associated with _context_ and returns 1 if there is nothing
201outstanding else 0. This function does not check that all requests transmitted
202have been responded to.
203
204RETURN VALUES
205-------------
206*coap_io_process*() and *coap_io_process_with_fds*() return the time, in
207milli-seconds, that was spent in the function. If -1 is returned, there was
208an unexpected error.
209
210*coap_context_get_coap_fd*() returns a non-negative number as the file
211descriptor to monitor, or -1 if epoll is not configured in libcoap.
212
213*coap_io_prepare_io*() and *coap_io_prepare_epoll*() return the number of
214milli-seconds that need to be waited before the function should next be called.
215
216*coap_io_pending*() returns 1 if there is outstanding i/o else returns 0.
217
218*coap_can_exit*() returns 1 if there is nothing outstanding to transmit else
219returns 0.
220
221EXAMPLES
222--------
223*Method One - use coap_io_process()*
224
225[source, c]
226----
227#include <coap@LIBCOAP_API_VERSION@/coap.h>
228
229int
230main(int argc, char *argv[]) {
231
232  coap_context_t *ctx = NULL;
233  unsigned wait_ms;
234  /* Remove (void) definition if variable is used */
235  (void)argc;
236  (void)argv;
237
238  /* Initialize libcoap library */
239  coap_startup();
240
241  /* Create the libcoap context */
242  ctx = coap_new_context(NULL);
243  if (!ctx) {
244    exit(1);
245  }
246  /* See coap_block(3) */
247  coap_context_set_block_mode(ctx,
248                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
249
250
251  /* Other Set up Code */
252
253  wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
254
255  while (1) {
256    int result = coap_io_process(ctx, wait_ms);
257    if (result < 0) {
258      /* There is an internal issue */
259      break;
260    }
261    /* Do any other housekeeping */
262  }
263  coap_free_context(ctx);
264  coap_cleanup();
265
266  /* Do any other cleanup */
267
268  exit(0);
269
270}
271----
272
273*Method One - coap_io_process_with_fds*
274
275[source, c]
276----
277#include <coap@LIBCOAP_API_VERSION@/coap.h>
278
279int
280main(int argc, char *argv[]) {
281
282  coap_context_t *ctx = NULL;
283  unsigned wait_ms;
284  fd_set readfds;
285  int nfds = 0;
286  /* Remove (void) definition if variable is used */
287  (void)argc;
288  (void)argv;
289
290  /* Initialize libcoap library */
291  coap_startup();
292
293  /* Create the libcoap context */
294  ctx = coap_new_context(NULL);
295  if (!ctx) {
296    exit(1);
297  }
298  /* See coap_block(3) */
299  coap_context_set_block_mode(ctx,
300                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
301
302
303  FD_ZERO(&readfds);
304  /* Set up readfds and nfds to handle other non libcoap FDs */
305
306  /* Other Set up Code */
307
308  wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
309
310  while (1) {
311    int result = coap_io_process_with_fds(ctx, wait_ms, nfds, &readfds, NULL, NULL);
312    if (result < 0) {
313      /* There is an internal issue */
314      break;
315    }
316    /* Check if set non libcoap FDs and process accordingly */
317
318    /* Do any other housekeeping */
319  }
320  coap_free_context(ctx);
321  coap_cleanup();
322
323  /* Do any other cleanup */
324
325  exit(0);
326
327}
328----
329
330*Method Two - select() based on monitorable file descriptor*
331
332[source, c]
333----
334#include <coap@LIBCOAP_API_VERSION@/coap.h>
335
336#include <errno.h>
337
338int
339main(int argc, char *argv[]) {
340
341  coap_context_t *ctx = NULL;
342  int coap_fd;
343  fd_set m_readfds;
344  int nfds;
345  /* Remove (void) definition if variable is used */
346  (void)argc;
347  (void)argv;
348
349  /* Initialize libcoap library */
350  coap_startup();
351
352  /* Create the libcoap context */
353  ctx = coap_new_context(NULL);
354  if (!ctx) {
355    exit(1);
356  }
357  /* See coap_block(3) */
358  coap_context_set_block_mode(ctx,
359                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
360
361  coap_fd = coap_context_get_coap_fd(ctx);
362  if (coap_fd == -1) {
363    /* epoll is not supported */
364    exit(1);
365  }
366  FD_ZERO(&m_readfds);
367  FD_SET(coap_fd, &m_readfds);
368  nfds = coap_fd + 1;
369
370  /* Other Set up Code */
371
372  while (1) {
373    fd_set readfds = m_readfds;
374    int result;
375    /* Wait until any i/o takes place */
376    result = select (nfds, &readfds, NULL, NULL, NULL);
377    if (result == -1) {
378      if (errno != EAGAIN) {
379        coap_log_debug("select: %s (%d)\n", coap_socket_strerror(), errno);
380        break;
381      }
382    }
383    if (result > 0) {
384      if (FD_ISSET(coap_fd, &readfds)) {
385        result = coap_io_process(ctx, COAP_IO_NO_WAIT);
386        if (result < 0) {
387          /* There is an internal issue */
388          break;
389        }
390      }
391    }
392    /* Do any other housekeeping */
393  }
394  coap_free_context(ctx);
395  coap_cleanup();
396
397  /* Do any other cleanup */
398
399  exit(0);
400
401}
402----
403
404*Method Two - epoll_wait() based on monitorable file descriptor*
405
406[source, c]
407----
408#include <coap@LIBCOAP_API_VERSION@/coap.h>
409
410#include <sys/epoll.h>
411
412#include <errno.h>
413
414#define MAX_EVENTS 10
415
416int
417main(int argc, char *argv[]) {
418
419  coap_context_t *ctx = NULL;
420  int coap_fd;
421  int epoll_fd;
422  struct epoll_event ev;
423  struct epoll_event events[MAX_EVENTS];
424  int nevents;
425  int i;
426  /* Remove (void) definition if variable is used */
427  (void)argc;
428  (void)argv;
429
430  /* Initialize libcoap library */
431  coap_startup();
432
433  /* Create the libcoap context */
434  ctx = coap_new_context(NULL);
435  if (!ctx) {
436    exit(1);
437  }
438  /* See coap_block(3) */
439  coap_context_set_block_mode(ctx,
440                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
441
442  coap_fd = coap_context_get_coap_fd(ctx);
443  if (coap_fd == -1) {
444    exit(1);
445  }
446  epoll_fd = epoll_create1(0);
447  if (epoll_fd == -1) {
448    exit(2);
449  }
450  ev.events = EPOLLIN;
451  ev.data.fd = coap_fd;
452  if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, coap_fd, &ev) == -1) {
453    exit(3);
454  }
455
456  /* Other Set up Code */
457
458  while (1) {
459    int result;
460    /* Wait until any i/o takes place */
461    nevents = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
462    if (nevents == -1) {
463      if (errno != EAGAIN) {
464        coap_log_debug("epoll_wait: %s (%d)\n", coap_socket_strerror(), errno);
465        break;
466      }
467    }
468    for (i = 0; i < nevents; i++) {
469      if (events[i].data.fd == coap_fd) {
470        result = coap_io_process(ctx, COAP_IO_NO_WAIT);
471        if (result < 0) {
472          /* There is an internal issue */
473          break;
474        }
475      }
476      else {
477        /* Process other events */
478      }
479    }
480    /* Do any other housekeeping */
481  }
482
483  if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, coap_fd, &ev) == -1) {
484    coap_log_debug("epoll_ctl: %s (%d)\n", coap_socket_strerror(), errno);
485  }
486  coap_free_context(ctx);
487  coap_cleanup();
488
489  /* Do any other cleanup */
490
491  exit(0);
492
493}
494----
495
496SEE ALSO
497--------
498*coap_block*(3), *coap_context*(3) and *coap_init*(3)
499
500FURTHER INFORMATION
501-------------------
502See
503
504"https://rfc-editor.org/rfc/rfc7252[RFC7252: The Constrained Application Protocol (CoAP)]"
505
506for further information.
507
508BUGS
509----
510Please report bugs on the mailing list for libcoap:
511libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
512https://github.com/obgm/libcoap/issues
513
514AUTHORS
515-------
516The libcoap project <libcoap-developers@lists.sourceforge.net>
517