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