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