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