mirror of
https://github.com/obgm/libcoap.git
synced 2026-11-12 11:40:39 +03:00
Rename coap_run_once() to coap_io_process()
coap_read(), coap_write() and coap_run_once() are confusing in their names and do not really describe what they do. For example, coap_read() does both reading and writing, coap_write() may do some writing, but primarily is used to determine what should be monitored and for how long to wait in the following select() or epoll_wait() calls. coap_run_once() implies that the code is only to be run once - again confusing. By renaming coap_read() to coap_io_do_io(), this better describes what this function does. By renaming coap_write() to coap_io_prepare_io() this better describes what this function does. By renaming coap_run_once() to coap_io_process(), this better describes what this function does. By renaming coap_io_do_events() to coap_io_do_epoll(), this better describes what this function does and is associated with. A wrapper function coap_io_prepare_epoll() has been created, using coap_io_prepare_io() with some preset values to simplify function usage. include/coap2/net.h: Update with the new function names, and deprecate the old functions. Also document the fact that coap_io_prepare_io(), coap_io_do_io(), coap_io_prepare_epoll(), and coap_io_do_epoll() are really internal functions. Create app_io module for Doxygen. libcoap-2.map: libcoap-2.sym: Expose the new functions to applications. examples/client.c: examples/coap-rd.c: examples/coap-server.c: examples/contiki/coap-observer.c: examples/contiki/server.c: examples/etsi_iot_01.c: man/coap_io.txt.in: man/coap_observe.txt.in: src/coap_io.c: src/coap_io_lwip.c: src/net.c: src/pdu.c: Update using the new function names. Setting the etimer has been moved out of coap_io_process() into coap_io_do_epoll(), making the logic easier for applications to use coap_io_do_epoll() should they need to. This also gets rid of a potential timing window where a pending etimer event gets missed. coap_io_do_epoll() now calls coap_io_prepare_epoll() if the etimer has triggered removing the need for applications using coap_io_do_epoll() to set up their own loops if etimer is triggered.
This commit is contained in:
1 parent
fca966385e
commit
9cf4f10b35
15 files changed
+384
-193
No files matched your search
+1
-1
@@ -1740,7 +1740,7 @@ main(int argc, char **argv) {
|
||||
|
||||
while (!quit && !(ready && !doing_getting_block && coap_can_exit(ctx)) ) {
|
||||
|
||||
result = coap_run_once( ctx, wait_ms == 0 ?
|
||||
result = coap_io_process( ctx, wait_ms == 0 ?
|
||||
obs_ms : obs_ms == 0 ?
|
||||
min(wait_ms, 1000) : min( wait_ms, obs_ms ) );
|
||||
|
||||
|
||||
+1
-1
@@ -859,7 +859,7 @@ main(int argc, char **argv) {
|
||||
#endif
|
||||
|
||||
while ( !quit ) {
|
||||
result = coap_run_once( ctx, COAP_RESOURCE_CHECK_TIME * 1000 );
|
||||
result = coap_io_process( ctx, COAP_RESOURCE_CHECK_TIME * 1000 );
|
||||
if ( result >= 0 ) {
|
||||
/* coap_check_resource_list( ctx ); */
|
||||
}
|
||||
|
||||
@@ -1453,13 +1453,13 @@ main(int argc, char **argv) {
|
||||
}
|
||||
if (result > 0) {
|
||||
if (FD_ISSET(coap_fd, &readfds)) {
|
||||
result = coap_run_once(ctx, COAP_RUN_NONBLOCK);
|
||||
result = coap_io_process(ctx, COAP_RUN_NONBLOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* epoll is not supported within libcoap */
|
||||
result = coap_run_once( ctx, wait_ms );
|
||||
result = coap_io_process(ctx, wait_ms);
|
||||
}
|
||||
if ( result < 0 ) {
|
||||
break;
|
||||
@@ -1470,7 +1470,7 @@ main(int argc, char **argv) {
|
||||
/*
|
||||
* result == 0, or result >= wait_ms
|
||||
* (wait_ms could have decremented to a small value, below
|
||||
* the granularity of the timer in coap_run_once() and hence
|
||||
* the granularity of the timer in coap_io_process() and hence
|
||||
* result == 0)
|
||||
*/
|
||||
time_t t_now = time(NULL);
|
||||
|
||||
@@ -176,7 +176,7 @@ PROCESS_THREAD(coap_server_process, ev, data)
|
||||
while(1) {
|
||||
PROCESS_YIELD();
|
||||
if(ev == tcpip_event) {
|
||||
coap_read(coap_context); /* read received data */
|
||||
coap_io_do_io(coap_context); /* read received data */
|
||||
coap_dispatch(coap_context); /* and dispatch PDUs from receivequeue */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ PROCESS_THREAD(coap_server_process, ev, data)
|
||||
PROCESS_YIELD();
|
||||
if(ev == tcpip_event) {
|
||||
/* There is something to read on the endpoint */
|
||||
coap_run_once(coap_context, COAP_RUN_BLOCK);
|
||||
coap_io_process(coap_context, COAP_RUN_BLOCK);
|
||||
} else if (ev == PROCESS_EVENT_TIMER && etimer_expired(&dirty_timer)) {
|
||||
coap_resource_notify_observers(time_resource, NULL);
|
||||
etimer_reset(&dirty_timer);
|
||||
|
||||
@@ -667,7 +667,7 @@ main(int argc, char **argv) {
|
||||
sigaction (SIGPIPE, &sa, NULL);
|
||||
|
||||
while ( !quit ) {
|
||||
result = coap_run_once( ctx, COAP_RESOURCE_CHECK_TIME * 1000 );
|
||||
result = coap_io_process( ctx, COAP_RESOURCE_CHECK_TIME * 1000 );
|
||||
if ( result >= 0 ) {
|
||||
/* coap_check_resource_list( ctx ); */
|
||||
}
|
||||
|
||||
+227
-120
@@ -541,126 +541,6 @@ coap_tid_t coap_send( coap_session_t *session, coap_pdu_t *pdu );
|
||||
*/
|
||||
coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node);
|
||||
|
||||
/**
|
||||
* For applications with their own message loop, send all pending retransmits and
|
||||
* return the list of sockets with events to wait for and the next timeout
|
||||
* The application should call coap_read, then coap_write again when any condition below is true:
|
||||
* - data is available on any of the sockets with the COAP_SOCKET_WANT_READ
|
||||
* - an incoming connection is pending in the listen queue and the COAP_SOCKET_WANT_ACCEPT flag is set
|
||||
* - at least some data can be written without blocking on any of the sockets with the COAP_SOCKET_WANT_WRITE flag set
|
||||
* - a connection event occured (success or failure) and the COAP_SOCKET_WANT_CONNECT flag is set
|
||||
* - the timeout has expired
|
||||
* Before calling coap_read or coap_write again, the application should position COAP_SOCKET_CAN_READ and COAP_SOCKET_CAN_WRITE flags as applicable.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param sockets array of socket descriptors, filled on output
|
||||
* @param max_sockets size of socket array.
|
||||
* @param num_sockets pointer to the number of valid entries in the socket arrays on output
|
||||
* @param now Current time.
|
||||
*
|
||||
* @return timeout as maxmimum number of milliseconds that the application should wait for network events or 0 if the application should wait forever.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
coap_write(coap_context_t *ctx,
|
||||
coap_socket_t *sockets[],
|
||||
unsigned int max_sockets,
|
||||
unsigned int *num_sockets,
|
||||
coap_tick_t now
|
||||
);
|
||||
|
||||
/**
|
||||
* For applications with their own message loop, reads all data from the network.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param now Current time
|
||||
*/
|
||||
void coap_read(coap_context_t *ctx, coap_tick_t now);
|
||||
|
||||
#define COAP_RUN_BLOCK 0
|
||||
#define COAP_RUN_NONBLOCK 1
|
||||
|
||||
/**
|
||||
* The main message processing loop.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param timeout_ms Minimum number of milliseconds to wait for new packets
|
||||
* before returning. If COAP_RUN_BLOCK, the call will block
|
||||
* until at least one new packet is received. If
|
||||
* COAP_RUN_NONBLOCK, the function will return immediately
|
||||
* following without waiting for any new input not already
|
||||
* available.
|
||||
*
|
||||
* @return Number of milliseconds spent in coap_run_once, or @c -1 if there
|
||||
* was an error
|
||||
*/
|
||||
int coap_run_once( coap_context_t *ctx, unsigned int timeout_ms );
|
||||
|
||||
/**
|
||||
* The main message processing loop with additional fds for internal select.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param timeout_ms Minimum number of milliseconds to wait for new packets
|
||||
* before returning. If COAP_RUN_BLOCK, the call will block
|
||||
* until at least one new packet is received. If
|
||||
* COAP_RUN_NONBLOCK, the function will return immediately
|
||||
* following without waiting for any new input not already
|
||||
* available.
|
||||
* @param nfds The maximum FD set in readfds, writefds or exceptfds
|
||||
* plus one,
|
||||
* @param readfds Read FDs to additionally check for in internal select()
|
||||
* or NULL if not required.
|
||||
* @param writefds Write FDs to additionally check for in internal select()
|
||||
* or NULL if not required.
|
||||
* @param exceptfds Except FDs to additionally check for in internal select()
|
||||
* or NULL if not required.
|
||||
*
|
||||
*
|
||||
* @return Number of milliseconds spent in coap_io_process_with_fds, or @c -1
|
||||
* if there was an error. If defined, readfds, writefds, exceptfds
|
||||
* are updated as returned by the internal select() call.
|
||||
*/
|
||||
int coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms,
|
||||
int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *exceptfds);
|
||||
|
||||
/**
|
||||
* Any now timed out delayed packet is transmitted, along with any packets
|
||||
* associated with requested observable response.
|
||||
*
|
||||
* In addition, it returns when the next expected I/O is expected to take place
|
||||
* (e.g. a packet retransmit).
|
||||
*
|
||||
* Note: If epoll support is compiled into libcoap, coap_io_prepare_epoll() must
|
||||
* be used instead of coap_write().
|
||||
*
|
||||
* Internal function.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param now Current time.
|
||||
*
|
||||
* @return timeout Maxmimum number of milliseconds that can be used by a
|
||||
* epoll_wait() to wait for network events or 0 if wait should be
|
||||
* forever.
|
||||
*/
|
||||
unsigned int
|
||||
coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now);
|
||||
|
||||
struct epoll_event;
|
||||
|
||||
/**
|
||||
* Process all the epoll events
|
||||
*
|
||||
* Internal function
|
||||
*
|
||||
* @param ctx The current CoAP context.
|
||||
* @param events The list of events returned from an epoll_wait() call.
|
||||
* @param nevents The number of events.
|
||||
*
|
||||
*/
|
||||
void coap_io_do_events(coap_context_t *ctx, struct epoll_event* events,
|
||||
size_t nevents);
|
||||
|
||||
/**
|
||||
* Parses and interprets a CoAP datagram with context @p ctx. This function
|
||||
* returns @c 0 if the datagram was handled, or a value less than zero on
|
||||
@@ -844,4 +724,231 @@ unsigned int coap_calc_timeout(coap_session_t *session, unsigned char r);
|
||||
int
|
||||
coap_join_mcast_group(coap_context_t *ctx, const char *groupname);
|
||||
|
||||
/**
|
||||
* @defgroup app_io Application I/O Handling
|
||||
* API functions for Application Input / Output
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define COAP_RUN_BLOCK 0
|
||||
#define COAP_RUN_NONBLOCK 1
|
||||
|
||||
/**
|
||||
* The main I/O processing function. All pending network I/O is completed,
|
||||
* and then optionally waits for the next input packet.
|
||||
*
|
||||
* This internally calls coap_io_prepare_io(), then select() for the appropriate
|
||||
* sockets, updates COAP_SOCKET_CAN_xxx where appropriate and then calls
|
||||
* coap_io_do_io() before returning with the time spent in the function.
|
||||
*
|
||||
* Alternatively, if libcoap is compiled with epoll support, this internally
|
||||
* calls coap_io_prepare_epoll(), then epoll_wait() for waiting for any file
|
||||
* descriptors that have (internally) been set up with epoll_ctl() and
|
||||
* finally coap_io_do_epoll() before returning with the time spent in the
|
||||
* function.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param timeout_ms Minimum number of milliseconds to wait for new packets
|
||||
* before returning. If COAP_RUN_BLOCK, the call will block
|
||||
* until at least one new packet is received. If
|
||||
* COAP_RUN_NONBLOCK, the function will return immediately
|
||||
* following without waiting for any new input not already
|
||||
* available.
|
||||
*
|
||||
* @return Number of milliseconds spent in function or @c -1 if there was
|
||||
* an error
|
||||
*/
|
||||
int coap_io_process(coap_context_t *ctx, unsigned int timeout_ms);
|
||||
|
||||
/**
|
||||
* @deprecated Use coap_io_process() instead.
|
||||
*
|
||||
* This function just calls coap_io_process().
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param timeout_ms Minimum number of milliseconds to wait for new packets
|
||||
* before returning. If COAP_RUN_BLOCK, the call will block
|
||||
* until at least one new packet is received. If
|
||||
* COAP_RUN_NONBLOCK, the function will return immediately
|
||||
* following without waiting for any new input not already
|
||||
* available.
|
||||
*
|
||||
* @return Number of milliseconds spent in function or @c -1 if there was
|
||||
* an error
|
||||
*/
|
||||
COAP_STATIC_INLINE COAP_DEPRECATED int
|
||||
coap_run_once(coap_context_t *ctx, unsigned int timeout_ms)
|
||||
{
|
||||
return coap_io_process(ctx, timeout_ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main message processing loop with additional fds for internal select.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param timeout_ms Minimum number of milliseconds to wait for new packets
|
||||
* before returning. If COAP_RUN_BLOCK, the call will block
|
||||
* until at least one new packet is received. If
|
||||
* COAP_RUN_NONBLOCK, the function will return immediately
|
||||
* after processing any existing input packets.
|
||||
* @param nfds The maximum FD set in readfds, writefds or exceptfds
|
||||
* plus one,
|
||||
* @param readfds Read FDs to additionally check for in internal select()
|
||||
* or NULL if not required.
|
||||
* @param writefds Write FDs to additionally check for in internal select()
|
||||
* or NULL if not required.
|
||||
* @param exceptfds Except FDs to additionally check for in internal select()
|
||||
* or NULL if not required.
|
||||
*
|
||||
*
|
||||
* @return Number of milliseconds spent in coap_io_process_with_fds, or @c -1
|
||||
* if there was an error. If defined, readfds, writefds, exceptfds
|
||||
* are updated as returned by the internal select() call.
|
||||
*/
|
||||
int coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms,
|
||||
int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *exceptfds);
|
||||
|
||||
/**
|
||||
* Iterates through all the coap_socket_t structures embedded in endpoints or
|
||||
* sessions associated with the @p ctx to determine which are wanting any
|
||||
* read, write, accept or connect I/O (COAP_SOCKET_WANT_xxx is set). If set,
|
||||
* the coap_socket_t is added to the @p sockets.
|
||||
*
|
||||
* Any now timed out delayed packet is transmitted, along with any packets
|
||||
* associated with requested observable response.
|
||||
*
|
||||
* In addition, it returns when the next expected I/O is expected to take place
|
||||
* (e.g. a packet retransmit).
|
||||
*
|
||||
* Prior to calling coap_io_do_io(), the @p sockets must be tested to see
|
||||
* if any of the COAP_SOCKET_WANT_xxx have the appropriate information and if
|
||||
* so, COAP_SOCKET_CAN_xxx is set. This typically will be done after using a
|
||||
* select() call.
|
||||
*
|
||||
* Note: If epoll support is compiled into libcoap, coap_io_prepare_epoll() must
|
||||
* be used instead of coap_io_prepare_io().
|
||||
*
|
||||
* Internal function.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param sockets Array of socket descriptors, filled on output
|
||||
* @param max_sockets Size of socket array.
|
||||
* @param num_sockets Pointer to the number of valid entries in the socket
|
||||
* arrays on output.
|
||||
* @param now Current time.
|
||||
*
|
||||
* @return timeout Maxmimum number of milliseconds that can be used by a
|
||||
* select() to wait for network events or 0 if wait should be
|
||||
* forever.
|
||||
*/
|
||||
unsigned int
|
||||
coap_io_prepare_io(coap_context_t *ctx,
|
||||
coap_socket_t *sockets[],
|
||||
unsigned int max_sockets,
|
||||
unsigned int *num_sockets,
|
||||
coap_tick_t now
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated Use coap_io_prepare_io() instead.
|
||||
*
|
||||
* This function just calls coap_io_prepare_io().
|
||||
*
|
||||
* Internal function.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param sockets Array of socket descriptors, filled on output
|
||||
* @param max_sockets Size of socket array.
|
||||
* @param num_sockets Pointer to the number of valid entries in the socket
|
||||
* arrays on output.
|
||||
* @param now Current time.
|
||||
*
|
||||
* @return timeout Maxmimum number of milliseconds that can be used by a
|
||||
* select() to wait for network events or 0 if wait should be
|
||||
* forever.
|
||||
*/
|
||||
COAP_STATIC_INLINE COAP_DEPRECATED unsigned int
|
||||
coap_write(coap_context_t *ctx,
|
||||
coap_socket_t *sockets[],
|
||||
unsigned int max_sockets,
|
||||
unsigned int *num_sockets,
|
||||
coap_tick_t now
|
||||
) {
|
||||
return coap_io_prepare_io(ctx, sockets, max_sockets, num_sockets, now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes any outstanding read, write, accept or connect I/O as indicated
|
||||
* in the coap_socket_t structures (COAP_SOCKET_CAN_xxx set) embedded in
|
||||
* endpoints or sessions associated with @p ctx.
|
||||
*
|
||||
* Note: If epoll support is compiled into libcoap, coap_io_do_epoll() must
|
||||
* be used instead of coap_io_do_io().
|
||||
*
|
||||
* Internal function.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param now Current time
|
||||
*/
|
||||
void coap_io_do_io(coap_context_t *ctx, coap_tick_t now);
|
||||
|
||||
/**
|
||||
* @deprecated Use coap_io_do_io() instead.
|
||||
*
|
||||
* This function just calls coap_io_do_io().
|
||||
*
|
||||
* Internal function.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param now Current time
|
||||
*/
|
||||
COAP_STATIC_INLINE COAP_DEPRECATED void
|
||||
coap_read(coap_context_t *ctx, coap_tick_t now
|
||||
) {
|
||||
coap_io_do_io(ctx, now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Any now timed out delayed packet is transmitted, along with any packets
|
||||
* associated with requested observable response.
|
||||
*
|
||||
* In addition, it returns when the next expected I/O is expected to take place
|
||||
* (e.g. a packet retransmit).
|
||||
*
|
||||
* Note: If epoll support is compiled into libcoap, coap_io_prepare_epoll() must
|
||||
* be used instead of coap_io_prepare_io().
|
||||
*
|
||||
* Internal function.
|
||||
*
|
||||
* @param ctx The CoAP context
|
||||
* @param now Current time.
|
||||
*
|
||||
* @return timeout Maxmimum number of milliseconds that can be used by a
|
||||
* epoll_wait() to wait for network events or 0 if wait should be
|
||||
* forever.
|
||||
*/
|
||||
unsigned int
|
||||
coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now);
|
||||
|
||||
struct epoll_event;
|
||||
|
||||
/**
|
||||
* Process all the epoll events
|
||||
*
|
||||
* Note: If epoll support is compiled into libcoap, coap_io_do_epoll() must
|
||||
* be used instead of coap_io_do_io().
|
||||
*
|
||||
* Internal function
|
||||
*
|
||||
* @param ctx The current CoAP context.
|
||||
* @param events The list of events returned from an epoll_wait() call.
|
||||
* @param nevents The number of events.
|
||||
*
|
||||
*/
|
||||
void coap_io_do_epoll(coap_context_t *ctx, struct epoll_event* events,
|
||||
size_t nevents);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif /* COAP_NET_H_ */
|
||||
+4
-3
@@ -79,7 +79,11 @@ global:
|
||||
coap_hash_impl;
|
||||
coap_insert_node;
|
||||
coap_insert_optlist;
|
||||
coap_io_do_epoll;
|
||||
coap_io_do_io;
|
||||
coap_io_prepare_epoll;
|
||||
coap_io_prepare_io;
|
||||
coap_io_process;
|
||||
coap_io_process_with_fds;
|
||||
coap_is_mcast;
|
||||
coap_join_mcast_group;
|
||||
@@ -137,7 +141,6 @@ global:
|
||||
coap_print_addr;
|
||||
coap_print_link;
|
||||
coap_print_wellknown;
|
||||
coap_read;
|
||||
coap_register_async;
|
||||
coap_register_event_handler;
|
||||
coap_register_handler;
|
||||
@@ -149,7 +152,6 @@ global:
|
||||
coap_resource_unknown_init;
|
||||
coap_response_phrase;
|
||||
coap_retransmit;
|
||||
coap_run_once;
|
||||
coap_send;
|
||||
coap_send_ack;
|
||||
coap_send_error;
|
||||
@@ -199,7 +201,6 @@ global:
|
||||
coap_touch_observer;
|
||||
coap_wait_ack;
|
||||
coap_wellknown_response;
|
||||
coap_write;
|
||||
coap_write_block_opt;
|
||||
local:
|
||||
*;
|
||||
|
||||
+4
-3
@@ -77,7 +77,11 @@ coap_handle_failed_notify
|
||||
coap_hash_impl
|
||||
coap_insert_node
|
||||
coap_insert_optlist
|
||||
coap_io_do_epoll
|
||||
coap_io_do_io
|
||||
coap_io_prepare_epoll
|
||||
coap_io_prepare_io
|
||||
coap_io_process
|
||||
coap_io_process_with_fds
|
||||
coap_is_mcast
|
||||
coap_join_mcast_group
|
||||
@@ -135,7 +139,6 @@ coap_pop_next
|
||||
coap_print_addr
|
||||
coap_print_link
|
||||
coap_print_wellknown
|
||||
coap_read
|
||||
coap_register_async
|
||||
coap_register_event_handler
|
||||
coap_register_handler
|
||||
@@ -147,7 +150,6 @@ coap_resource_set_dirty
|
||||
coap_resource_unknown_init
|
||||
coap_response_phrase
|
||||
coap_retransmit
|
||||
coap_run_once
|
||||
coap_send
|
||||
coap_send_ack
|
||||
coap_send_error
|
||||
@@ -197,5 +199,4 @@ coap_tls_is_supported
|
||||
coap_touch_observer
|
||||
coap_wait_ack
|
||||
coap_wellknown_response
|
||||
coap_write
|
||||
coap_write_block_opt
|
||||
+112
-32
@@ -10,14 +10,15 @@ coap_io(3)
|
||||
|
||||
NAME
|
||||
----
|
||||
coap_io, coap_run_once, coap_io_process_with_fds, coap_context_get_coap_fd
|
||||
coap_io, coap_io_process, coap_io_process_with_fds, coap_context_get_coap_fd,
|
||||
coap_io_prepare_io, coap_io_do_io, coap_io_prepare_epoll, coap_io_do_epoll
|
||||
- Work with CoAP I/O to do the packet send and receives
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*#include <coap@LIBCOAP_API_VERSION@/coap.h>*
|
||||
|
||||
*int coap_run_once(coap_context_t *_context_, unsigned int _timeout_ms_)*;
|
||||
*int coap_io_process(coap_context_t *_context_, unsigned int _timeout_ms_)*;
|
||||
|
||||
*int coap_io_process_with_fds(coap_context_t *_context_,
|
||||
unsigned int _timeout_ms_, int _nfds_, fd_set *_readfds_, fd_set *_writefds_,
|
||||
@@ -25,6 +26,18 @@ fd_set *_exceptfds_)*;
|
||||
|
||||
*int coap_context_get_coap_fd(coap_context_t *_context_)*;
|
||||
|
||||
*unsigned int coap_io_prepare_io(coap_context_t *_context_,
|
||||
coap_socket_t *_sockets[]_, unsigned int _max_sockets_,
|
||||
unsigned int *_num_sockets_, coap_tick_t _now_)*;
|
||||
|
||||
*void coap_io_do_io(coap_context_t *_context_, coap_tick_t _now_)*;
|
||||
|
||||
*unsigned int coap_io_prepare_epoll(coap_context_t *_context_,
|
||||
coap_tick_t _now_)*;
|
||||
|
||||
*int coap_io_do_epoll(coap_context_t *_context_, struct epoll_event *_events_,
|
||||
size_t _nevents_)*
|
||||
|
||||
Link with *-lcoap-@LIBCOAP_API_VERSION@*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*,
|
||||
*-lcoap-@LIBCOAP_API_VERSION@-openssl* or
|
||||
*-lcoap-@LIBCOAP_API_VERSION@-tinydtls* depending on your (D)TLS library
|
||||
@@ -36,39 +49,92 @@ After setting up all the contexts, resources, endpoints sessions etc., the
|
||||
underlying CoAP and (D)TLS need to send (and possible re-send) created packets
|
||||
as well as receive packets for processing.
|
||||
|
||||
The *coap_run_once*() function will process any outstanding packets to send
|
||||
for the specified _context_ and wait for processing any input packets for up to
|
||||
_timeout_ms_ milli-seconds before returning. Once any outstanding input packets
|
||||
have been processed, the function will return. There are 2 special case
|
||||
The *coap_io_process*() function will process any outstanding packets to send
|
||||
for the specified _context_, process any available input packets and then wait
|
||||
for processing any new input packets, or for when to re-transmit a packet, for
|
||||
up to _timeout_ms_ milli-seconds before returning. There are 2 special case
|
||||
_timeout_ms_ values.
|
||||
[source, c]
|
||||
----
|
||||
#define COAP_RUN_BLOCK 0
|
||||
#define COAP_RUN_NONBLOCK 1
|
||||
----
|
||||
If _timeout_ms_ is set to COAP_RUN_BLOCK, then *coap_run_once*() will wait
|
||||
indefinitely for the first new input packet to come in. If _timeout_ms_ is set
|
||||
to COAP_RUN_NONBLOCK, then there is no wait if there are no more input packets.
|
||||
If _timeout_ms_ is set to COAP_RUN_BLOCK, then *coap_io_process*() will wait
|
||||
indefinitely for the first new input packet to come in, or for when to
|
||||
re-transmit a packet. If _timeout_ms_ is set to COAP_RUN_NONBLOCK, then there
|
||||
is no wait if there is no more input or output to process.
|
||||
|
||||
There are two methods of how to call *coap_run_once*().
|
||||
There are two methods of how to call *coap_io_process*().
|
||||
|
||||
1. Have *coap_run_once*() called from within a while() loop. Under idle
|
||||
conditions (no input traffic) *coap_run_once*() will then get called every
|
||||
_timeout_ms_, but more frequently if there is input traffic.
|
||||
1. Have *coap_io_process*() called from within a while() loop. Under idle
|
||||
conditions (no input traffic) *coap_io_process*() will then get called every
|
||||
_timeout_ms_, but more frequently if there is input / retransmission traffic.
|
||||
|
||||
2. Wait on the file descriptor returned by *coap_context_get_coap_fd*()
|
||||
using select() or an event returned by epoll_wait(). If 'read' is available on
|
||||
the file descriptor, call *coap_run_once*() with _timeout_ms_ set to
|
||||
COAP_RUN_NONBLOCK. See EXAMPLES below.
|
||||
using *select*() or an event returned by epoll_wait(). If 'read' is available on
|
||||
the file descriptor, call *coap_io_process*() with _timeout_ms_ set to
|
||||
COAP_RUN_NONBLOCK. +
|
||||
*NOTE*: This second method is only available for environments that support epoll
|
||||
(mostly Linux) with libcoap compiled to use *epoll* (the default) as libcoap
|
||||
will then be using *epoll* internally to process all the file descriptors of
|
||||
the different sessions.
|
||||
|
||||
NOTE: This method is only available for environments that support epoll
|
||||
(mostly Linux) as libcoap will then be using epoll internally to process all
|
||||
the file descriptors of the different sessions.
|
||||
See EXAMPLES below.
|
||||
|
||||
The *coap_io_process_with_fds*() function is the same as *coap_run_once*()
|
||||
The *coap_io_process*() function is the primary function applications should
|
||||
use. There are internal functions that *coap_io_process*() calls which are
|
||||
available to use if absolutely necessary. These internal functions and how to
|
||||
use them is different depending on whether libcoap has been compiled to use
|
||||
*epoll* (Linux systems only) or not.
|
||||
|
||||
For *epoll* libcoap, *coap_io_process*() in simple terms calls
|
||||
*coap_io_prepare_epoll()*, does an *epoll_wait*() and then calls
|
||||
*coap_io_do_epoll*() if needed to make sure that all event based i/o has been
|
||||
completed.
|
||||
|
||||
For *non-epoll* libcoap, *coap_io_process*() in simple terms calls
|
||||
*coap_io_prepare_io*() to set up sockets[], sets up all of the *select*()
|
||||
parameters based on the COAP_SOCKET_WANT* values in the sockets[], does a
|
||||
*select*(), updates the sockets[] with COAP_SOCKET_CAN_* as appropriate and
|
||||
then calls *coap_io_do_io*() to make sure that all current i/o has been
|
||||
completed.
|
||||
|
||||
The *coap_io_prepare_epoll*() function for the specified _context_ will
|
||||
iterate through the endpoints and sessions to transmit any triggered observer
|
||||
responses as well as handling any timed out packet re-transmissions. Returned,
|
||||
based on _now_, is the number of milli-secs needed to delay until the next
|
||||
time that *coap_io_prepare_epoll*() needs to get called. After this call an
|
||||
*epoll_wait*() should done.
|
||||
|
||||
The *coap_io_do_epoll*() function for the specified _context_ will
|
||||
iterate through the _nevents_ of _events_ returned by *epoll_wait*() and
|
||||
execute the appropriate low level i/o function to send / receive / process the
|
||||
packets. Where appropriate, structure information (endpoints, sessions etc.)
|
||||
is updated with the value of _now_ in the lower level functions.
|
||||
|
||||
The *coap_io_prepare_io*() function for the specified _context_ will iterate
|
||||
through the endpoints and sessions to add all of sockets waiting for network
|
||||
traffic (COAP_SOCKET_WANT_* is set) found to _sockets_ (limited by
|
||||
_max_sockets_) and updates _num_sockets_ with the number of sockets found.
|
||||
Furthermore, any triggered observer responses are transmitted
|
||||
as well as handling any timed out packet re-transmissions. Returned, based on
|
||||
_now_, is the number of milli-secs needed to delay until the next time that
|
||||
*coap_io_prepare_io*() needs to get called. After this call a *select*() should
|
||||
done on all the file descriptors (COAP_WANT_READ for readfds etc.), and any
|
||||
that are returned active should set the appropriate COAP_SOCKET_CAN_* in the
|
||||
_sockets_.
|
||||
|
||||
The *coap_io_do_io*() function for the specified _context_ will
|
||||
iterate through the endpoints and sessions to find all of sockets that have
|
||||
COAP_SOCKET_CAN_* set and then execute the appropriate low level i/o function
|
||||
to send / receive / process the packets. Where appropriate, structure
|
||||
information (endpoints, sessions etc.) is updated with the value of _now_ in
|
||||
the lower level functions.
|
||||
|
||||
The *coap_io_process_with_fds*() function is the same as *coap_process_io*()
|
||||
but supports additional select() style parameters _nfds_, _readfds_,
|
||||
_writefds_ and _exceptfds_. This provides the ability to add in additional
|
||||
non libcoap FDs to test for in the internal select() call which can then
|
||||
non libcoap FDs to test for in the internal select() call which can then
|
||||
tested after the return from coap_io_process_with_fds(). _readfds_,
|
||||
_writefds_ and _exceptfds_ can either point to a defined and pre-filled fd_set
|
||||
structure or NULL if not required. _nfds_ needs to be set to the maximum FD to
|
||||
@@ -81,24 +147,26 @@ if there is no epoll support in libcoap. If there is epoll support, then
|
||||
other non libcoap FDs can separately be monitored using method 2 above.
|
||||
|
||||
The *coap_context_get_coap_fd*() function obtains from the specified
|
||||
_context_ a single file descriptor that can be monitored by a select() or
|
||||
as an event returned from a epoll_wait() call. This file descriptor will get
|
||||
_context_ a single file descriptor that can be monitored by a *select*() or
|
||||
as an event returned from a *epoll_wait*() call. This file descriptor will get
|
||||
updated with information (read, write etc. available) whenever any of the
|
||||
internal to libcoap file descriptors (sockets) change state.
|
||||
|
||||
RETURN VALUES
|
||||
-------------
|
||||
*coap_run_once*() and *coap_io_process_with_fds*() returns the time, in
|
||||
*coap_io_process*() and *coap_io_process_with_fds*() returns the time, in
|
||||
milli-seconds, that was spent in the function. If -1 is returned, there was
|
||||
an unexpected error.
|
||||
|
||||
*coap_context_get_coap_fd*() returns a non-negative number as the file
|
||||
descriptor to monitor, or -1 if epoll is not supported by the host
|
||||
environment.
|
||||
descriptor to monitor, or -1 if epoll is not configured in libcoap.
|
||||
|
||||
*coap_io_prepare_io*() and *coap_io_prepare_epoll*() returns the number of
|
||||
milli-seconds that need to be waited before the function should next be called.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
*Method One - coap_run_once*
|
||||
*Method One - use coap_io_process()*
|
||||
|
||||
[source, c]
|
||||
----
|
||||
@@ -109,6 +177,9 @@ int main(int argc, char *argv[]){
|
||||
coap_context_t *ctx = NULL;
|
||||
unsigned wait_ms;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
/* Create the libcoap context */
|
||||
ctx = coap_new_context(NULL);
|
||||
if (!ctx) {
|
||||
@@ -120,7 +191,7 @@ int main(int argc, char *argv[]){
|
||||
wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
|
||||
|
||||
while (1) {
|
||||
int result = coap_run_once(ctx, wait_ms);
|
||||
int result = coap_io_process(ctx, wait_ms);
|
||||
if (result < 0) {
|
||||
/* There is an internal issue */
|
||||
break;
|
||||
@@ -149,6 +220,9 @@ int main(int argc, char *argv[]){
|
||||
fd_set readfds;
|
||||
int nfds = 0;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
/* Create the libcoap context */
|
||||
ctx = coap_new_context(NULL);
|
||||
if (!ctx) {
|
||||
@@ -181,7 +255,7 @@ int main(int argc, char *argv[]){
|
||||
}
|
||||
----
|
||||
|
||||
*Method Two - select*
|
||||
*Method Two - select() based on monitorable file descriptor*
|
||||
|
||||
[source, c]
|
||||
----
|
||||
@@ -196,6 +270,9 @@ int main(int argc, char *argv[]){
|
||||
fd_set m_readfds;
|
||||
int nfds;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
/* Create the libcoap context */
|
||||
ctx = coap_new_context(NULL);
|
||||
if (!ctx) {
|
||||
@@ -224,7 +301,7 @@ int main(int argc, char *argv[]){
|
||||
}
|
||||
if (result > 0) {
|
||||
if (FD_ISSET(coap_fd, &readfds)) {
|
||||
result = coap_run_once(ctx, COAP_RUN_NONBLOCK);
|
||||
result = coap_io_process(ctx, COAP_RUN_NONBLOCK);
|
||||
if (result < 0) {
|
||||
/* There is an internal issue */
|
||||
break;
|
||||
@@ -242,7 +319,7 @@ int main(int argc, char *argv[]){
|
||||
}
|
||||
----
|
||||
|
||||
*Method Two - epoll*
|
||||
*Method Two - epoll_wait() based on monitorable file descriptor*
|
||||
|
||||
[source, c]
|
||||
----
|
||||
@@ -264,6 +341,9 @@ int main(int argc, char *argv[]){
|
||||
int nevents;
|
||||
int i;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
/* Create the libcoap context */
|
||||
ctx = coap_new_context(NULL);
|
||||
if (!ctx) {
|
||||
@@ -297,7 +377,7 @@ int main(int argc, char *argv[]){
|
||||
}
|
||||
for (i = 0; i < nevents; i++) {
|
||||
if (events[i].data.fd == coap_fd) {
|
||||
result = coap_run_once(ctx, COAP_RUN_NONBLOCK);
|
||||
result = coap_io_process(ctx, COAP_RUN_NONBLOCK);
|
||||
if (result < 0) {
|
||||
/* There is an internal issue */
|
||||
break;
|
||||
|
||||
@@ -70,7 +70,7 @@ appropriate GET handler within the server application is called to fill in the
|
||||
response packet with the appropriate information. This "fake GET request" is
|
||||
triggered by a call to *coap_resource_notify_observers*().
|
||||
|
||||
The call to *coap_run_once*() in the main server application i/o loop will do
|
||||
The call to *coap_io_process*() in the main server application i/o loop will do
|
||||
all the necessary processing of sending any outstanding "fake GET requests".
|
||||
|
||||
Whenever the server sends a copy of the state of the "observed" resource to
|
||||
@@ -286,7 +286,7 @@ int main(int argc, char *argv[]){
|
||||
wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
|
||||
|
||||
while (1) {
|
||||
int result = coap_run_once( ctx, wait_ms );
|
||||
int result = coap_io_process( ctx, wait_ms );
|
||||
if ( result < 0 ) {
|
||||
break;
|
||||
} else if ( result && (unsigned)result < wait_ms ) {
|
||||
@@ -296,7 +296,7 @@ int main(int argc, char *argv[]){
|
||||
/*
|
||||
* result == 0, or result >= wait_ms
|
||||
* (wait_ms could have decremented to a small value, below
|
||||
* the granularity of the timer in coap_run_once() and hence
|
||||
* the granularity of the timer in coap_io_process() and hence
|
||||
* result == 0)
|
||||
*/
|
||||
time_t t_now = time(NULL);
|
||||
|
||||
+17
-15
@@ -945,6 +945,8 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(WITH_CONTIKI)
|
||||
|
||||
unsigned int
|
||||
coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now) {
|
||||
#ifndef COAP_EPOLL_SUPPORT
|
||||
@@ -960,7 +962,7 @@ coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now) {
|
||||
unsigned int timeout;
|
||||
|
||||
/* Use the common logic */
|
||||
timeout = coap_write(ctx, sockets, max_sockets, &num_sockets, now);
|
||||
timeout = coap_io_prepare_io(ctx, sockets, max_sockets, &num_sockets, now);
|
||||
/* Save when the next expected I/O is to take place */
|
||||
ctx->next_timeout = timeout ? now + timeout : 0;
|
||||
if (ctx->eptimerfd != -1) {
|
||||
@@ -989,10 +991,8 @@ coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now) {
|
||||
#endif /* COAP_EPOLL_SUPPORT */
|
||||
}
|
||||
|
||||
#if !defined(WITH_CONTIKI)
|
||||
|
||||
unsigned int
|
||||
coap_write(coap_context_t *ctx,
|
||||
coap_io_prepare_io(coap_context_t *ctx,
|
||||
coap_socket_t *sockets[],
|
||||
unsigned int max_sockets,
|
||||
unsigned int *num_sockets,
|
||||
@@ -1174,7 +1174,7 @@ coap_write(coap_context_t *ctx,
|
||||
}
|
||||
|
||||
int
|
||||
coap_run_once(coap_context_t *ctx, unsigned timeout_ms) {
|
||||
coap_io_process(coap_context_t *ctx, unsigned timeout_ms) {
|
||||
return coap_io_process_with_fds(ctx, timeout_ms, 0, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -1212,7 +1212,9 @@ coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms,
|
||||
coap_ticks(&before);
|
||||
|
||||
#ifndef COAP_EPOLL_SUPPORT
|
||||
timeout = coap_write(ctx, sockets, (unsigned int)(sizeof(sockets) / sizeof(sockets[0])), &num_sockets, before);
|
||||
timeout = coap_io_prepare_io(ctx, sockets,
|
||||
(sizeof(sockets) / sizeof(sockets[0])),
|
||||
&num_sockets, before);
|
||||
if (timeout == 0 || timeout_ms < timeout)
|
||||
timeout = timeout_ms;
|
||||
|
||||
@@ -1293,7 +1295,7 @@ coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms,
|
||||
}
|
||||
|
||||
coap_ticks(&now);
|
||||
coap_read(ctx, now);
|
||||
coap_io_do_io(ctx, now);
|
||||
if (ereadfds) {
|
||||
*ereadfds = readfds;
|
||||
}
|
||||
@@ -1334,7 +1336,7 @@ coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms,
|
||||
break;
|
||||
}
|
||||
|
||||
coap_io_do_events(ctx, events, nfds);
|
||||
coap_io_do_epoll(ctx, events, nfds);
|
||||
|
||||
/*
|
||||
* reset to COAP_RUN_NONBLOCK (which causes etimeout to become 0)
|
||||
@@ -1357,23 +1359,23 @@ coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms,
|
||||
}
|
||||
|
||||
#else /* WITH_CONTIKI */
|
||||
int coap_run_once(coap_context_t *ctx, unsigned int timeout_ms) {
|
||||
int coap_io_process(coap_context_t *ctx, unsigned int timeout_ms) {
|
||||
coap_tick_t now;
|
||||
|
||||
coap_ticks(&now);
|
||||
/* There is something to read on the endpoint */
|
||||
ctx->endpoint->sock.flags |= COAP_SOCKET_CAN_READ;
|
||||
/* read in, and send off any responses */
|
||||
coap_read(ctx, now); /* read received data */
|
||||
coap_io_do_io(ctx, now); /* read received data */
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
coap_write(coap_context_t *ctx,
|
||||
coap_socket_t *sockets[],
|
||||
unsigned int max_sockets,
|
||||
unsigned int *num_sockets,
|
||||
coap_tick_t now)
|
||||
coap_io_prepare(coap_context_t *ctx,
|
||||
coap_socket_t *sockets[],
|
||||
unsigned int max_sockets,
|
||||
unsigned int *num_sockets,
|
||||
coap_tick_t now)
|
||||
{
|
||||
*num_sockets = 0;
|
||||
return 0;
|
||||
|
||||
+2
-2
@@ -48,9 +48,9 @@ struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet)
|
||||
*
|
||||
* The current implementation deals this to coap_dispatch immediately, but
|
||||
* other mechanisms (as storing the package in a queue and later fetching it
|
||||
* when coap_read is called) can be envisioned.
|
||||
* when coap_io_do_io is called) can be envisioned.
|
||||
*
|
||||
* It handles everything coap_read does on other implementations.
|
||||
* It handles everything coap_io_do_io does on other implementations.
|
||||
*/
|
||||
static void coap_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
|
||||
@@ -1125,7 +1125,7 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) {
|
||||
#ifdef WITH_LWIP
|
||||
/* WITH_LWIP, this is handled by coap_recv in a different way */
|
||||
void
|
||||
coap_read(coap_context_t *ctx, coap_tick_t now) {
|
||||
coap_io_do_io(coap_context_t *ctx, coap_tick_t now) {
|
||||
return;
|
||||
}
|
||||
#else /* WITH_LWIP */
|
||||
@@ -1419,12 +1419,12 @@ coap_accept_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint,
|
||||
}
|
||||
|
||||
void
|
||||
coap_read(coap_context_t *ctx, coap_tick_t now) {
|
||||
coap_io_do_io(coap_context_t *ctx, coap_tick_t now) {
|
||||
#ifdef COAP_EPOLL_SUPPORT
|
||||
(void)ctx;
|
||||
(void)now;
|
||||
coap_log(LOG_EMERG,
|
||||
"coap_read() requires libcoap not compiled for using epoll\n");
|
||||
"coap_io_do_io() requires libcoap not compiled for using epoll\n");
|
||||
#else /* ! COAP_EPOLL_SUPPORT */
|
||||
coap_endpoint_t *ep, *tmp;
|
||||
coap_session_t *s, *rtmp;
|
||||
@@ -1476,17 +1476,17 @@ coap_read(coap_context_t *ctx, coap_tick_t now) {
|
||||
}
|
||||
|
||||
/*
|
||||
* While this code in part replicates coap_read(), doing the functions
|
||||
* While this code in part replicates coap_io_do_io(), doing the functions
|
||||
* directly saves having to iterate through the endpoints / sessions.
|
||||
*/
|
||||
void
|
||||
coap_io_do_events(coap_context_t *ctx, struct epoll_event *events, size_t nevents) {
|
||||
coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events, size_t nevents) {
|
||||
#ifndef COAP_EPOLL_SUPPORT
|
||||
(void)ctx;
|
||||
(void)events;
|
||||
(void)nevents;
|
||||
coap_log(LOG_EMERG,
|
||||
"coap_io_do_events() requires libcoap compiled for using epoll\n");
|
||||
"coap_io_do_epoll() requires libcoap compiled for using epoll\n");
|
||||
#else /* COAP_EPOLL_SUPPORT */
|
||||
coap_tick_t now;
|
||||
size_t j;
|
||||
|
||||
@@ -57,7 +57,7 @@ coap_pdu_from_pbuf( struct pbuf *pbuf )
|
||||
if (pbuf == NULL) return NULL;
|
||||
|
||||
LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
|
||||
LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
|
||||
LWIP_ASSERT("coap_io_do_io needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
|
||||
|
||||
pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t) );
|
||||
if (!pdu) {
|
||||
|
||||
Reference in new issue
Block a user