diff --git a/examples/coap-client.c b/examples/coap-client.c index 8f065986..b376c8d2 100644 --- a/examples/coap-client.c +++ b/examples/coap-client.c @@ -360,18 +360,19 @@ nack_handler(coap_session_t *session COAP_UNUSED, coap_bin_const_t token = coap_pdu_get_token(sent); if (coap_pdu_get_code(sent) != COAP_EMPTY_CODE && !track_check_token(&token)) { - coap_log_err("nack_handler: Unexpected token\n"); + coap_show_pdu(0, sent); + coap_log_err("nack_handler: %d: Unexpected token\n", reason); } } switch (reason) { case COAP_NACK_NOT_DELIVERABLE: case COAP_NACK_TLS_FAILED: + case COAP_NACK_TOO_MANY_RETRIES: coap_log_err("cannot send CoAP pdu\n"); if (!reconnect_secs) quit = 1; break; - case COAP_NACK_TOO_MANY_RETRIES: case COAP_NACK_WS_FAILED: case COAP_NACK_TLS_LAYER_FAILED: case COAP_NACK_WS_LAYER_FAILED: diff --git a/examples/coap-server.c b/examples/coap-server.c index 13922c83..7c1d647a 100644 --- a/examples/coap-server.c +++ b/examples/coap-server.c @@ -1099,12 +1099,12 @@ proxy_event_handler(coap_session_t *session COAP_UNUSED, return 0; } -static coap_response_t -reverse_response_handler(coap_session_t *rsp_session, - const coap_pdu_t *sent COAP_UNUSED, - const coap_pdu_t *received, - const coap_mid_t id COAP_UNUSED) { - return coap_proxy_forward_response(rsp_session, received, NULL); +static coap_pdu_t * +proxy_response_handler(coap_session_t *rsp_session COAP_UNUSED, + const coap_pdu_t *sent COAP_UNUSED, + coap_pdu_t *received, + coap_cache_key_t *cache_key COAP_UNUSED) { + return received; } static void @@ -1141,7 +1141,7 @@ init_resources(coap_context_t *ctx) { r = coap_resource_reverse_proxy_init(hnd_reverse_proxy_uri, 0); coap_add_resource(ctx, r); coap_register_event_handler(ctx, proxy_event_handler); - coap_register_proxy_response_handler(ctx, reverse_response_handler); + coap_register_proxy_response_handler(ctx, proxy_response_handler); coap_register_nack_handler(ctx, proxy_nack_handler); } else { #endif /* COAP_PROXY_SUPPORT */ @@ -1206,7 +1206,7 @@ init_resources(coap_context_t *ctx) { proxy_host_name_list, 0); coap_add_resource(ctx, r); coap_register_event_handler(ctx, proxy_event_handler); - coap_register_proxy_response_handler(ctx, reverse_response_handler); + coap_register_proxy_response_handler(ctx, proxy_response_handler); coap_register_nack_handler(ctx, proxy_nack_handler); } #endif /* COAP_PROXY_SUPPORT */ diff --git a/include/coap3/coap_net.h b/include/coap3/coap_net.h index 87cbb399..ba55a9a5 100644 --- a/include/coap3/coap_net.h +++ b/include/coap3/coap_net.h @@ -111,20 +111,6 @@ typedef void (*coap_pong_handler_t)(coap_session_t *session, void coap_register_response_handler(coap_context_t *context, coap_response_handler_t handler); -/** - * Registers a new message handler that is called whenever a response is - * received by the proxy logic. - * - * Note: If this is not defined, then the handler registered by - * coap_register_response_handler() will be used. - * - * @param context The context to register the handler for. - * @param handler The response handler to register. - */ -void coap_register_proxy_response_handler(coap_context_t *context, - coap_response_handler_t handler); - - /** * Registers a new message handler that is called whenever a confirmable * message (request or response) is dropped after all retries have been diff --git a/include/coap3/coap_net_internal.h b/include/coap3/coap_net_internal.h index 966c19d8..5ebdd5ff 100644 --- a/include/coap3/coap_net_internal.h +++ b/include/coap3/coap_net_internal.h @@ -105,8 +105,8 @@ struct coap_context_t { received */ #endif /* COAP_CLIENT_SUPPORT */ #if COAP_PROXY_SUPPORT - coap_response_handler_t proxy_response_handler; /**< Called when a reponse - to proxy logic received */ + coap_proxy_response_handler_t proxy_response_handler; /**< Called when a reponse + to proxy logic received */ #endif /* COAP_PROXY_SUPPORT */ coap_nack_handler_t nack_handler; /**< Called when a response issue has occurred */ @@ -993,8 +993,8 @@ coap_mid_t coap_send_ack_lkd(coap_session_t *session, const coap_pdu_t *request) */ coap_mid_t coap_send_rst_lkd(coap_session_t *session, const coap_pdu_t *request); -void coap_call_response_handler(coap_session_t *session, coap_pdu_t *sent, coap_pdu_t *rcvd, - void *body_free); +void coap_call_response_handler(coap_session_t *session, coap_pdu_t *sent, + coap_pdu_t *rcvd, void *body_free); /**@}*/ diff --git a/include/coap3/coap_proxy.h b/include/coap3/coap_proxy.h index a2a9b877..fe6f5de8 100644 --- a/include/coap3/coap_proxy.h +++ b/include/coap3/coap_proxy.h @@ -57,14 +57,49 @@ typedef struct coap_proxy_server_list_t { size_t next_entry; /**< Next server to use (% entry_count) */ coap_proxy_t type; /**< The proxy type */ int track_client_session; /**< If 1, track individual connections to upstream - server, else 0 for all clients to share the same - ongoing session */ + server, else 0 for all clients to be multiplexed + over the same upstream session */ unsigned int idle_timeout_secs; /**< Proxy upstream session idle timeout (0 is no timeout). Timeout is ignored if there are any active upstream Observe requests */ } coap_proxy_server_list_t; +/** + * Proxy response handler that is used as callback held in coap_context_t. + * + * @param session CoAP session. + * @param sent The PDU that was transmitted. + * @param received The respose PDU that was received, or returned from cache. + * @param cache_key Updated with the cache key pointer provided to + * coap_proxy_forward_request(). The caller should + * delete this cache key (unless the client request set up an + * Observe and there will be unsolicited responses). + * + * @return The PDU to be sent back to the client (usually @c received) or NULL + * if error. If NULL, this will cause sending a RST packet to the + * upstream server if the received PDU is a CON or NON. + * If the returned PDU is not @c received or @c NULL, then @c received + * must be freed off in the handler. + */ +typedef coap_pdu_t *(*coap_proxy_response_handler_t)(coap_session_t *session, + const coap_pdu_t *sent, + coap_pdu_t *received, + coap_cache_key_t *cache_key); + +/** + * Registers a new message handler that is called whenever a response is + * received by the proxy logic. + * + * Note: If this is not defined, then the handler registered by + * coap_register_response_handler() will be used. + * + * @param context The context to register the handler for. + * @param handler The response handler to register. + */ +void coap_register_proxy_response_handler(coap_context_t *context, + coap_proxy_response_handler_t handler); + /** * Verify that the CoAP Scheme is supported for an ongoing proxy connection. * diff --git a/include/coap3/coap_proxy_internal.h b/include/coap3/coap_proxy_internal.h index 60841122..2bde42b3 100644 --- a/include/coap3/coap_proxy_internal.h +++ b/include/coap3/coap_proxy_internal.h @@ -19,6 +19,7 @@ #include "coap_internal.h" +#if COAP_PROXY_SUPPORT /** * @ingroup internal_api * @defgroup Proxy Support @@ -26,25 +27,39 @@ * @{ */ +/* Client <--> Proxy-Server | Proxy-Client <--> Server */ + +typedef struct coap_proxy_cache_t { + UT_hash_handle hh; /**< Hash list for request Cache-Keys */ + coap_cache_key_t cache_req; /**< Cache-Key of the request */ + coap_pdu_t *req_pdu; /**< P-Client's request PDU */ + coap_pdu_t *rsp_pdu; /**< Latest response PDU seen by P-Client */ + coap_tick_t expire; /**< When this cache entry is to expire */ + uint64_t etag; /**< ETag value of response PDU */ + unsigned ref; /**< No of coap_proxy_req_t reference this object */ +} coap_proxy_cache_t; + typedef struct coap_proxy_req_t { - coap_pdu_t *pdu; - coap_resource_t *resource; - coap_session_t *incoming; - coap_bin_const_t *token_used; - coap_cache_key_t *cache_key; + coap_pdu_t *pdu; /**< Requesting PDU */ + coap_resource_t *resource; /**< P-Server resource */ + coap_session_t *incoming; /**< Incoming session from client */ + coap_bin_const_t *token_used; /**< Token used in forwarded request */ + coap_cache_key_t *cache_key; /**< Cache-Key passed into coap_proxy_forward_request() */ + coap_proxy_cache_t *proxy_cache; /**< Cache that this proxy request is using */ } coap_proxy_req_t; struct coap_proxy_list_t { - coap_session_t *ongoing; /**< Ongoing session */ - coap_session_t *incoming; /**< Incoming session (used if client tracking( */ + coap_session_t *ongoing; /**< Ongoing session */ + coap_session_t *incoming; /**< Incoming session (used if client tracking( */ coap_proxy_req_t *req_list; /**< Incoming list of request info */ - size_t req_count; /**< Count of incoming request info */ - coap_uri_t uri; /**< URI info for connection */ + size_t req_count; /**< Count of incoming request info */ + coap_proxy_cache_t *rsp_cache; /* Response cache list */ + coap_uri_t uri; /**< URI info for connection */ uint8_t *uri_host_keep; /**< memory for uri.host */ coap_tick_t idle_timeout_ticks; /**< Idle timeout (0 == no timeout). Timeout is ignored if there are any active upstream Observe requests */ - coap_tick_t last_used; /**< Last time entry was used */ + coap_tick_t last_used; /**< Last time entry was used */ }; /** @@ -167,7 +182,7 @@ coap_mid_t coap_proxy_local_write(coap_session_t *session, coap_pdu_t *pdu); * maps it back to the incoming request. * * @param ongoing The upstream proxy client session. - * @param received The received PDU from hte upstream server. + * @param received The received PDU from the upstream server. * @param proxy_entry Updated with the proxy server entry definition if not NULL. * * @return The proxy request information, or NULL on mapping failure. @@ -175,6 +190,39 @@ coap_mid_t coap_proxy_local_write(coap_session_t *session, coap_pdu_t *pdu); struct coap_proxy_req_t *coap_proxy_map_outgoing_request(coap_session_t *ongoing, const coap_pdu_t *received, coap_proxy_list_t **proxy_entry); + +/* + * coap_proxy_process_incoming() handles the Server response back to P-Client. + * + * @param session The upstream proxy client session. + * @param rcvd The received PDU from the upstream server. + * @param body_data The data to be freed off once all responses sent for rcvd, + * @param proxy_req The current proxy request object + * @param proxy_entry The current proxy entry object + * + * @return The proxy request information, or NULL on mapping failure. + */ +void coap_proxy_process_incoming(coap_session_t *session, + coap_pdu_t *rcvd, void *body_free, + coap_proxy_req_t *proxy_req, + coap_proxy_list_t *proxy_entry); /** @} */ +#define PROXY_CACHE_ADD(e, obj) \ + HASH_ADD(hh, (e), cache_req, sizeof((obj)->cache_req), (obj)) + +#define PROXY_CACHE_DELETE(e, obj) \ + HASH_DELETE(hh, (e), (obj)) + +#define PROXY_CACHE_ITER(e, el, rtmp) \ + HASH_ITER(hh, (e), el, rtmp) + +#define PROXY_CACHE_ITER_SAFE(e, el, rtmp) \ + for ((el) = (e); (el) && ((rtmp) = (el)->hh.next, 1); (el) = (rtmp)) + +#define PROXY_CACHE_FIND(e, k, res) { \ + HASH_FIND(hh, (e), (k), sizeof(*k), (res)); \ + } + +#endif /* COAP_PROXY_SUPPORT */ #endif /* COAP_PROXY_INTERNAL_H_ */ diff --git a/man/coap_persist.txt.in b/man/coap_persist.txt.in index 99bc7e31..373c067e 100644 --- a/man/coap_persist.txt.in +++ b/man/coap_persist.txt.in @@ -60,8 +60,8 @@ and maintaining OSCORE protection. There are callbacks provided to support doing this as an alternative persist storage in the coap-server application. -*NOTE:* The observe persist support is only available for UDP sessions that -use TCP/IP (i.e. not AF_UNIX). +*NOTE:* The observe persist support is only available for UDP (datagram) +sessions that use IPv4 or IPv6 (i.e. not AF_UNIX). When using the libcoap compiled in support, only two functions need to be called by the application. *coap_persist_startup*() defines the file names to diff --git a/man/coap_proxy.txt.in b/man/coap_proxy.txt.in index 43210813..a000a16e 100644 --- a/man/coap_proxy.txt.in +++ b/man/coap_proxy.txt.in @@ -37,7 +37,7 @@ coap_proxy_server_list_t *_server_list_);* coap_proxy_server_list_t *_server_list_);* *void coap_register_proxy_response_handler(coap_context_t *_context_, -coap_response_handler_t _handler_);* +coap_proxy_response_handler_t _handler_);* For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, @@ -49,8 +49,12 @@ or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with DESCRIPTION ----------- +Client <--> Proxy-Server | Proxy-Client <--> U-Server + To simplify CoAP proxy requirements, proxy forwarding functionality is -provided by libcoap for matching forwarded requests with returning responses. +provided by libcoap for matching forwarded requests with returning responses +by passing the appropriate information between Proxy-Server and Proxy-Client, +doing any necessary protocol translations. Two principal types of Proxy are supported. @@ -91,9 +95,9 @@ round-robin fashion. An existing client session will always get directed to the same upsteam server unless that upstream session has idle timed out. For the *forward-dynamic* proxy type, a dummy server needs to be defined if any -specific PKI/PSK or OSCORE is required for the ongoing session to the dynamically -determined upstream server. If client anonymous PKI only is required for -ongoing encrypted sessions, then this dummy server does not need to be defined. +specific PKI/PSK or OSCORE is required for creating the ongoing session to the +dynamically determined upstream server. If client anonymous PKI only is required +for ongoing encrypted sessions, then this dummy server does not need to be defined. For each upstream server, client sessions can all be multiplexed over a single upstream server session, or there can be the same number of upstream server @@ -109,6 +113,12 @@ The resourse handler to handle *forward* proxy requests is defined using The resource handler to handle *reverse* proxy requests is defined using *coap_resource_reverse_proxy_init*(3). +There is caching support limited to Observe subscriptions where multiple client +sessions are multiplexed across a single upstream server session. Here, if there +are multiple client Observe subscriptions to the same upstream server's resource, +then there is only one upstream Observe subscription and any unsolicited +responses are sent back to all the subscribing clients. + FUNCTIONS --------- @@ -144,8 +154,8 @@ typedef struct coap_proxy_server_list_t { size_t next_entry; /* Next server to use (% entry_count) */ coap_proxy_t type; /* The proxy type */ int track_client_session; /* If 1, track individual connections to upstream - server, else 0 for all clients to share the - same ongoing session */ + server, else 0 for all clients to be multiplexed + over the same upstream session */ unsigned int idle_timeout_secs; /* Proxy upstream session idle timeout (0 is no timeout). Timeout is ignored if there are any active upstream Observe @@ -157,10 +167,11 @@ The *coap_proxy_forward_request*() function is called from a request handler when the request needs to be forwarded to an upstream server with a possible change in protocol. _req_session_, _request_, _response_ and _resource_ are as provided to the application's request handler. _cache_key_ can be a cache_key -generated from the _request_ PDU or NULL. This _cache_key_ will get passed into -*coap_proxy_forward_response*() when handling the response. _server_list_ defines -the characteristics of zero or more of the upstream servers to connect to. The -definitions can cover the following +generated from the _request_ PDU or (usually) NULL. This _cache_key_ will get +passed into *coap_proxy_forward_response*() or the response handler set up +using *coap_register_proxy_response_handler*() when handling the response. +_server_list_ defines the characteristics of zero or more of the upstream +servers to connect to. The definitions can cover the following [source, c] ---- @@ -184,6 +195,13 @@ caller does not need to update this on error detection after calling *coap_proxy_forward_request*() will establish a new ongoing session to the upstream server as and when required. +*NOTE:* If *coap_register_proxy_response_handler*() has not been called to define +a handler, then _track_client_session_ is treated as having a value of 1. + +*NOTE:* If _request_ is replaced by a new PDU for onward forwarding, then this new +PDU must be deleted using *coap_delete_pdu*(3) after the call to +*coap_proxy_forward_request*(). _request_ should not be deleted. + *Function: coap_proxy_forward_response()* The *coap_proxy_forward_response*() function is used to forward on any response @@ -198,6 +216,10 @@ and there will be unsolicited responses). If _cache_key_ is not defined, but a _cache_key_ was passed into *coap_proxy_forward_request*() then it will get deleted. +*NOTE: *coap_proxy_forward_response*() should only be used if +*coap_register_proxy_response_handler*() has not been called, and the regular +response handler is being used (defined by *coap_register_response_handler*(3)). + *Function: coap_verify_proxy_scheme_supported()* The *coap_verify_proxy_scheme_supported*() function verifies that the @@ -216,7 +238,7 @@ chosen. defined by *coap_register_response_handler*(), not to the handler defined by *coap_register_proxy_response_handler*(). -*NOTE:* _server_list must exist for the duration of the created session as it +*NOTE:* _server_list_ must exist for the duration of the created session as it is used for every *coap_send*() or *coap_send_recv*(). To stop using a client session, the reference count must be decremented to 0 @@ -225,20 +247,60 @@ the client endpoint's _session_ and all its associated information. *Function: coap_register_proxy_response_handler()* +[source, c] +---- +/** + * Proxy response handler that is used as callback held in coap_context_t. + * + * @param session CoAP session. + * @param sent The PDU that was transmitted. + * @param received The respose PDU that was received, or returned from cache. + * @param cache_key Updated with the cache key pointer provided to + * coap_proxy_forward_request(). The caller should + * delete this cache key (unless the client request set up an + * Observe and there will be unsolicited responses). + * + * @return The PDU to be sent back to the client (usually @c received) or NULL + * if error. If NULL, this will cause sending a RST packet to the + * upstream server if the received PDU is a CON or NON. + * If the returned PDU is not @c received or @c NULL, then @c received + * must be freed off in the handler. + */ +typedef coap_pdu_t *(*coap_proxy_response_handler_t)(coap_session_t *session, + const coap_pdu_t *sent, + coap_pdu_t *received, + coap_cache_key_t *cache_key); +---- + The *coap_register_proxy_response_handler*() is a proxy client side function -that registers a upstream request's response callback _handler_ for traffic -associated with the _context_. The application can use this for handling any -proxy response packets, including sending a RST packet if this response was -unexpected. If _handler_ is NULL, then the handler is de-registered. +that registers an upstream request's response callback _handler_ for traffic +associated with the _context_. If _handler_ is NULL, then the handler is +de-registered. -It is expected that in _handler_, this will call coap_proxy_forward_response() -to forward the response back to the downstream requesting client. +The application can use this _handler_ for local processing any upstream +response packets, already updated ready for sending on back to the originating +client. -_handler_ function is defined in the same way as hte nandler for -*coap_register_response_handler*(3). +It is expected that the return from _handler_ would normally be +_received_ which causes the response packet to be sent to the client. +*coap_send*(3) or *coap_proxy_forward_response*() should not be used in +_handler_. + +If the return from _handler_ is NULL, then _received_ will not forwarded back +to the Client. This will also cause a RST packet to the upstream server if +the received PDU is a CON or NON. + +*NOTE:* If _received_ is to be updated by creating a new PDU, this new PDU can +be returned instead of _received_. However, _received_ must be not be +freed off using *coap_delete_pdu*(3) in _handler_ as the calling logic detects +a new PDU is being returned and does the *coap_delete_pdu*(3) itself. If *coap_register_proxy_response_handler*() is not called, or _handler_ is -defined as NULL, then *coap_register_response_handler*(3) will get called instead. +defined as NULL, then the _handler_ registered by +*coap_register_response_handler*(3) will get called instead. + +If *coap_register_proxy_response_handler*() is not called, or _handler_ is +defined as NULL, then caching support is disabled. RETURN VALUES ------------- @@ -283,7 +345,7 @@ static coap_proxy_server_list_t reverse_proxy = { .entry_count = sizeof(redirect_server)/sizeof(redirect_server[0]), .next_entry = 0, .type = COAP_PROXY_REVERSE_STRIP, - .track_client_session = 0, + .track_client_session = 0, /* Client sessions multiplexed over upstream session */ .idle_timeout_secs = 300 }; @@ -303,12 +365,12 @@ hnd_reverse_proxy_uri(coap_resource_t *resource, /* Leave response code as is */ } -static coap_response_t -proxy_response_handler(coap_session_t *rsp_session, +static coap_pdu_t * +proxy_response_handler(coap_session_t *rsp_session COAP_UNUSED, const coap_pdu_t *sent COAP_UNUSED, - const coap_pdu_t *received, - const coap_mid_t id COAP_UNUSED) { - return coap_proxy_forward_response(rsp_session, received, NULL); + coap_pdu_t *received, + coap_cache_key_t *cache_key COAP_UNUSED) { + return received; } static void @@ -330,6 +392,7 @@ init_resources(coap_context_t *ctx) { ---- #include +/* List of names / IP addresses that proxy server is known by */ static const char *proxy_host_name_list[2] = { "myservername", "1.2.3.5" /* my server IP */ @@ -359,12 +422,12 @@ hnd_forward_proxy_uri(coap_resource_t *resource, /* Leave response code as is */ } -static coap_response_t -proxy_response_handler(coap_session_t *rsp_session, +static coap_pdu_t * +proxy_response_handler(coap_session_t *rsp_session COAP_UNUSED, const coap_pdu_t *sent COAP_UNUSED, - const coap_pdu_t *received, - const coap_mid_t id COAP_UNUSED) { - return coap_proxy_forward_response(rsp_session, received, NULL); + coap_pdu_t *received, + coap_cache_key_t *cache_key COAP_UNUSED) { + return received; } static void @@ -388,6 +451,7 @@ init_resources(coap_context_t *ctx) { ---- #include +/* List of names / IP addresses that proxy server is known by */ static const char *proxy_host_name_list[2] = { "myservername", "1.2.3.5" /* my server IP */ @@ -433,12 +497,12 @@ hnd_onward_proxy_uri(coap_resource_t *resource, /* Leave response code as is */ } -static coap_response_t -proxy_response_handler(coap_session_t *rsp_session, +static coap_pdu_t * +proxy_response_handler(coap_session_t *rsp_session COAP_UNUSED, const coap_pdu_t *sent COAP_UNUSED, - const coap_pdu_t *received, - const coap_mid_t id COAP_UNUSED) { - return coap_proxy_forward_response(rsp_session, received, NULL); + coap_pdu_t *received, + coap_cache_key_t *cache_key COAP_UNUSED) { + return received; } static void diff --git a/src/coap_block.c b/src/coap_block.c index 5c817046..7e2b253e 100644 --- a/src/coap_block.c +++ b/src/coap_block.c @@ -1365,13 +1365,13 @@ coap_add_data_large_response_lkd(coap_resource_t *resource, #endif /* COAP_Q_BLOCK_SUPPORT */ } - coap_insert_option(response, COAP_OPTION_CONTENT_FORMAT, + coap_update_option(response, COAP_OPTION_CONTENT_FORMAT, coap_encode_var_safe(buf, sizeof(buf), media_type), buf); if (maxage >= 0) { - coap_insert_option(response, + coap_update_option(response, COAP_OPTION_MAXAGE, coap_encode_var_safe(buf, sizeof(buf), maxage), buf); } diff --git a/src/coap_net.c b/src/coap_net.c index d08af2d6..436ed36f 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -2288,13 +2288,13 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { } } - /* And finally delete the node */ if (node->pdu->type == COAP_MESSAGE_CON) { coap_handle_nack(node->session, node->pdu, COAP_NACK_TOO_MANY_RETRIES, node->id); } #if COAP_CLIENT_SUPPORT node->session->doing_send_recv = 0; #endif /* COAP_CLIENT_SUPPORT */ + /* And finally delete the node */ coap_delete_node_lkd(node); return COAP_INVALID_MID; } @@ -2403,6 +2403,10 @@ coap_read_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now) } } else if (bytes_read > 0) { session->last_rx_tx = now; +#if COAP_CLIENT_SUPPORT + if (session->session_failed) + session->session_failed = 0; +#endif /* COAP_CLIENT_SUPPORT */ /* coap_netif_dgrm_read() updates session->addr_info from packet->addr_info */ coap_handle_dgram_for_proto(ctx, session, packet); } else { @@ -4013,7 +4017,6 @@ fail_response: #endif /* COAP_SERVER_SUPPORT */ #if COAP_CLIENT_SUPPORT - /* Call application-specific response handler when available. */ void coap_call_response_handler(coap_session_t *session, @@ -4022,6 +4025,20 @@ coap_call_response_handler(coap_session_t *session, coap_context_t *context = session->context; coap_response_t ret; +#if COAP_PROXY_SUPPORT + if (context->proxy_response_handler) { + coap_proxy_list_t *proxy_entry; + coap_proxy_req_t *proxy_req = coap_proxy_map_outgoing_request(session, + rcvd, + &proxy_entry); + + if (proxy_req && proxy_req->incoming && !proxy_req->incoming->server_list) { + coap_proxy_process_incoming(session, rcvd, body_data, proxy_req, + proxy_entry); + return; + } + } +#endif /* COAP_PROXY_SUPPORT */ if (session->doing_send_recv && session->req_token && coap_binary_equal(session->req_token, &rcvd->actual_token)) { /* processing coap_send_recv() call */ @@ -4032,20 +4049,6 @@ coap_call_response_handler(coap_session_t *session, coap_send_ack_lkd(session, rcvd); session->last_con_handler_res = COAP_RESPONSE_OK; return; -#if COAP_PROXY_SUPPORT - } - coap_proxy_req_t *proxy_req = coap_proxy_map_outgoing_request(session, rcvd, NULL); - - if (context->proxy_response_handler && proxy_req && - proxy_req->incoming && !proxy_req->incoming->server_list) { - coap_lock_callback_ret_release(ret, context, - context->proxy_response_handler(session, - sent, - rcvd, - rcvd->mid), - /* context is being freed off */ - return); -#endif /* COAP_PROXY_SUPPORT */ } else if (context->response_handler) { coap_lock_callback_ret_release(ret, context, context->response_handler(session, @@ -5004,7 +5007,7 @@ coap_register_response_handler(coap_context_t *context, void coap_register_proxy_response_handler(coap_context_t *context, - coap_response_handler_t handler) { + coap_proxy_response_handler_t handler) { #if COAP_PROXY_SUPPORT context->proxy_response_handler = handler; #else /* ! COAP_PROXY_SUPPORT */ diff --git a/src/coap_netif.c b/src/coap_netif.c index eb6208ea..226cbba5 100644 --- a/src/coap_netif.c +++ b/src/coap_netif.c @@ -76,9 +76,9 @@ coap_netif_dgrm_read(coap_session_t *session, coap_packet_t *packet) { bytes_read = coap_socket_recv(&session->sock, packet); keep_errno = errno; if (bytes_read == -1) { - coap_log_debug("* %s: netif: failed to read %zd bytes (%s) state %d\n", + coap_log_debug("* %s: netif: failed to read %zd bytes (%s (%d)) state %d\n", coap_session_str(session), packet->length, - coap_socket_strerror(), session->state); + coap_socket_strerror(), keep_errno, session->state); errno = keep_errno; } else if (bytes_read > 0) { coap_ticks(&session->last_rx_tx); @@ -140,9 +140,9 @@ coap_netif_dgrm_write(coap_session_t *session, const uint8_t *data, bytes_written = coap_socket_send(sock, session, data, datalen); keep_errno = errno; if (bytes_written <= 0) { - coap_log_debug("* %s: netif: failed to send %zd bytes (%s) state %d\n", + coap_log_debug("* %s: netif: failed to send %zd bytes (%s (%d)) state %d\n", coap_session_str(session), datalen, - coap_socket_strerror(), session->state); + coap_socket_strerror(), errno, session->state); errno = keep_errno; } else { coap_ticks(&session->last_rx_tx); diff --git a/src/coap_openssl.c b/src/coap_openssl.c index 382f18c4..7d5e49d3 100644 --- a/src/coap_openssl.c +++ b/src/coap_openssl.c @@ -3594,7 +3594,10 @@ coap_dtls_send(coap_session_t *session, int r; SSL *ssl = (SSL *)session->tls; - assert(ssl != NULL); + if (ssl == NULL) { + session->dtls_event = COAP_EVENT_DTLS_CLOSED; + return -1; + } session->dtls_event = -1; ERR_clear_error(); diff --git a/src/coap_proxy.c b/src/coap_proxy.c index b8b2d60b..a82bd85a 100644 --- a/src/coap_proxy.c +++ b/src/coap_proxy.c @@ -35,17 +35,50 @@ coap_proxy_is_supported(void) { return 1; } +static void +coap_proxy_del_req(coap_proxy_list_t *proxy_entry, coap_proxy_req_t *proxy_req) { + size_t i; + + coap_delete_pdu_lkd(proxy_req->pdu); + coap_delete_bin_const(proxy_req->token_used); + coap_delete_cache_key(proxy_req->cache_key); + if (proxy_req->proxy_cache) { + assert(proxy_req->proxy_cache->ref); + proxy_req->proxy_cache->ref--; + if (proxy_req->proxy_cache->ref == 0) { + PROXY_CACHE_DELETE(proxy_entry->rsp_cache, proxy_req->proxy_cache); + coap_delete_pdu_lkd(proxy_req->proxy_cache->req_pdu); + coap_delete_pdu_lkd(proxy_req->proxy_cache->rsp_pdu); + coap_free_type(COAP_STRING, proxy_req->proxy_cache); + proxy_req->proxy_cache = NULL; + } + } + + for (i = 0; i < proxy_entry->req_count; i++) { + if (&proxy_entry->req_list[i] == proxy_req) { + if (proxy_entry->req_count > 1) { + memmove(&proxy_entry->req_list[i], &proxy_entry->req_list[i+1], + (proxy_entry->req_count-i-1) * sizeof(proxy_entry->req_list[0])); + } + proxy_entry->req_count--; + break; + } + } +} + static void coap_proxy_cleanup_entry(coap_proxy_list_t *proxy_entry, int send_failure) { size_t i; for (i = 0; i < proxy_entry->req_count; i++) { + coap_proxy_req_t *proxy_req = &proxy_entry->req_list[i]; + if (send_failure) { coap_pdu_t *response; coap_bin_const_t l_token; /* Need to send back a gateway failure */ - response = coap_pdu_init(proxy_entry->req_list[i].pdu->type, + response = coap_pdu_init(proxy_req->pdu->type, COAP_RESPONSE_CODE(502), coap_new_message_id_lkd(proxy_entry->incoming), coap_session_max_pdu_size_lkd(proxy_entry->incoming)); @@ -54,7 +87,7 @@ coap_proxy_cleanup_entry(coap_proxy_list_t *proxy_entry, int send_failure) { goto cleanup; } - l_token = coap_pdu_get_token(proxy_entry->req_list[i].pdu); + l_token = coap_pdu_get_token(proxy_req->pdu); if (!coap_add_token(response, l_token.length, l_token.s)) { coap_log_debug("Cannot add token to incoming proxy response PDU\n"); @@ -65,9 +98,7 @@ coap_proxy_cleanup_entry(coap_proxy_list_t *proxy_entry, int send_failure) { } } cleanup: - coap_delete_pdu_lkd(proxy_entry->req_list[i].pdu); - coap_delete_bin_const(proxy_entry->req_list[i].token_used); - coap_delete_cache_key(proxy_entry->req_list[i].cache_key); + coap_proxy_del_req(proxy_entry, proxy_req); } coap_free_type(COAP_STRING, proxy_entry->req_list); coap_free_type(COAP_STRING, proxy_entry->uri_host_keep); @@ -345,7 +376,7 @@ coap_proxy_get_session(coap_session_t *session, const coap_pdu_t *request, if (coap_string_equal(&proxy_list[i].uri.host, &server_use->uri.host) && proxy_list[i].uri.port == server_use->uri.port && proxy_list[i].uri.scheme == server_use->uri.scheme) { - if (!server_list->track_client_session) { + if (!server_list->track_client_session && session->context->proxy_response_handler) { coap_ticks(&proxy_list[i].last_used); return &proxy_list[i]; } else { @@ -404,38 +435,35 @@ coap_proxy_remove_association(coap_session_t *session, int send_failure) { size_t proxy_list_count = session->context->proxy_list_count; for (i = 0; i < proxy_list_count; i++) { + coap_proxy_list_t *proxy_entry = &proxy_list[i]; + /* Check for incoming match */ - for (j = 0; j < proxy_list[i].req_count; j++) { - if (proxy_list[i].req_list[j].incoming == session) { - coap_delete_pdu_lkd(proxy_list[i].req_list[j].pdu); - coap_delete_bin_const(proxy_list[i].req_list[j].token_used); - coap_delete_cache_key(proxy_list[i].req_list[j].cache_key); - if (proxy_list[i].req_count-j > 1) { - memmove(&proxy_list[i].req_list[j], &proxy_list[i].req_list[j+1], - (proxy_list[i].req_count-j-1) * sizeof(proxy_list[i].req_list[0])); - } - proxy_list[i].req_count--; + for (j = 0; j < proxy_entry->req_count; j++) { + coap_proxy_req_t *proxy_req = &proxy_entry->req_list[j]; + + if (proxy_req->incoming == session) { + coap_proxy_del_req(proxy_entry, proxy_req); break; } } - if (proxy_list[i].incoming == session) { + if (proxy_entry->incoming == session) { /* Only if there is a one-to-one tracking */ - coap_session_t *ongoing = proxy_list[i].ongoing; + coap_session_t *ongoing = proxy_entry->ongoing; - proxy_list[i].ongoing = NULL; + proxy_entry->ongoing = NULL; coap_session_release_lkd(ongoing); return 0; } /* Check for outgoing match */ - if (proxy_list[i].ongoing == session) { + if (proxy_entry->ongoing == session) { coap_session_t *ongoing; - coap_proxy_cleanup_entry(&proxy_list[i], send_failure); - ongoing = proxy_list[i].ongoing; + coap_proxy_cleanup_entry(proxy_entry, send_failure); + ongoing = proxy_entry->ongoing; coap_log_debug("* %s: proxy_entry %p released (rem count = %zd)\n", coap_session_str(ongoing), - (void *)&proxy_list[i], + (void *)proxy_entry, session->context->proxy_list_count - 1); if (proxy_list_count-i > 1) { memmove(&proxy_list[i], @@ -611,6 +639,112 @@ coap_proxy_release_body_data(coap_session_t *session COAP_UNUSED, coap_delete_binary(app_ptr); } +static coap_proxy_req_t * +coap_proxy_get_req(coap_proxy_list_t *proxy_entry, coap_session_t *session) { + size_t i; + + for (i = 0; i < proxy_entry->req_count; i++) { + if (proxy_entry->req_list[i].incoming == session) { + return &proxy_entry->req_list[i]; + } + } + return NULL; +} + +static void +coap_proxy_free_response_data(coap_session_t *session COAP_UNUSED, void *app_ptr) { + coap_delete_bin_const(app_ptr); +} + +static coap_response_t +coap_proxy_call_response_handler(coap_session_t *session, const coap_pdu_t *sent, + coap_pdu_t *rcvd, coap_bin_const_t *token, + coap_proxy_req_t *proxy_req, int replace_mid) { + coap_response_t ret = COAP_RESPONSE_FAIL; + coap_pdu_t *resp_pdu; + coap_pdu_t *fwd_pdu = NULL; + size_t size; + size_t offset; + size_t total; + const uint8_t *data; + coap_string_t *l_query = NULL; + + /* Correct the token */ + resp_pdu = coap_pdu_duplicate_lkd(rcvd, session, token->length, token->s, NULL); + if (!resp_pdu) + return COAP_RESPONSE_FAIL; + + if (replace_mid) + resp_pdu->mid = rcvd->mid; + if (coap_get_data_large(rcvd, &size, &data, &offset, &total)) { + uint16_t media_type = 0; + int maxage = -1; + uint64_t etag = 0; + coap_opt_t *option; + coap_opt_iterator_t opt_iter; + coap_bin_const_t *body; + + /* COAP_BLOCK_SINGLE_BODY is set, so single body should be given */ + assert(size == total); + + body = coap_new_bin_const(data, size); + if (!body) { + coap_log_debug("coap_proxy_call_response_handler: copy data error\n"); + goto failed; + } + option = coap_check_option(rcvd, COAP_OPTION_CONTENT_FORMAT, &opt_iter); + if (option) { + media_type = coap_decode_var_bytes(coap_opt_value(option), + coap_opt_length(option)); + } + option = coap_check_option(rcvd, COAP_OPTION_MAXAGE, &opt_iter); + if (option) { + maxage = coap_decode_var_bytes(coap_opt_value(option), + coap_opt_length(option)); + } + option = coap_check_option(rcvd, COAP_OPTION_ETAG, &opt_iter); + if (option) { + etag = coap_decode_var_bytes8(coap_opt_value(option), + coap_opt_length(option)); + } + if (sent) + l_query = coap_get_query(sent); + if (!coap_add_data_large_response_lkd(proxy_req->resource, session, sent, + resp_pdu, + l_query, + media_type, maxage, etag, body->length, + body->s, + coap_proxy_free_response_data, + body)) { + coap_log_debug("coap_proxy_call_response_handler: add data error\n"); + goto failed; + } + } + coap_lock_callback_ret_release(fwd_pdu, session->context, + session->context->proxy_response_handler(session, + sent, + resp_pdu, + proxy_req->cache_key), + /* context is being freed off */ + goto failed); + if (fwd_pdu) { + ret = COAP_RESPONSE_OK; + if (coap_send_lkd(session, fwd_pdu) == COAP_INVALID_MID) { + ret = COAP_RESPONSE_FAIL; + } + if (fwd_pdu != resp_pdu) { + /* Application created a new PDU */ + coap_delete_pdu_lkd(resp_pdu); + } + } else { +failed: + ret = COAP_RESPONSE_FAIL; + coap_delete_pdu_lkd(resp_pdu); + } + coap_delete_string(l_query); + return ret; +} + int COAP_API coap_proxy_forward_request(coap_session_t *session, const coap_pdu_t *request, @@ -631,6 +765,14 @@ coap_proxy_forward_request(coap_session_t *session, return ret; } +/* https://rfc-editor.org/rfc/rfc7641#section-3.6 */ +static const uint16_t coap_proxy_ignore_options[] = { COAP_OPTION_ETAG, + COAP_OPTION_RTAG, + COAP_OPTION_BLOCK2, + COAP_OPTION_Q_BLOCK2, + COAP_OPTION_OSCORE + }; + int coap_proxy_forward_request_lkd(coap_session_t *session, const coap_pdu_t *request, @@ -648,11 +790,15 @@ coap_proxy_forward_request_lkd(coap_session_t *session, coap_bin_const_t r_token = coap_pdu_get_token(request); uint8_t token[8]; size_t token_len; - coap_proxy_req_t *new_req_list; + coap_proxy_req_t *proxy_req = NULL; coap_optlist_t *optlist = NULL; coap_opt_t *option; coap_opt_iterator_t opt_iter; coap_uri_t uri; + coap_opt_t *obs_opt = coap_check_option(request, + COAP_OPTION_OBSERVE, + &opt_iter); + coap_proxy_cache_t *proxy_cache = NULL; /* Set up ongoing session (if not already done) */ proxy_entry = coap_proxy_get_ongoing_session(session, request, response, @@ -662,32 +808,108 @@ coap_proxy_forward_request_lkd(coap_session_t *session, return 0; } + /* Is this a observe cached request? */ + if (obs_opt && session->context->proxy_response_handler) { + coap_cache_key_t *cache_key_l; + coap_tick_t now; + + cache_key_l = coap_cache_derive_key_w_ignore(session, request, + COAP_CACHE_NOT_SESSION_BASED, + coap_proxy_ignore_options, + sizeof(coap_proxy_ignore_options)/sizeof(coap_proxy_ignore_options[0])); + if (!cache_key_l) { + response->code = COAP_RESPONSE_CODE(505); + return 0; + } + PROXY_CACHE_FIND(proxy_entry->rsp_cache, cache_key_l, proxy_cache); + coap_delete_cache_key(cache_key_l); + coap_ticks(&now); + if (proxy_cache && (proxy_cache->expire + COAP_TICKS_PER_SECOND) < now) { + /* Need to get an updated rsp_pdu */ + proxy_cache = NULL; + } + } + + if (proxy_cache) { + proxy_req = coap_proxy_get_req(proxy_entry, session); + if (proxy_req) { + if (obs_opt) { + int observe_action; + + observe_action = coap_decode_var_bytes(coap_opt_value(obs_opt), + coap_opt_length(obs_opt)); + + if (observe_action == COAP_OBSERVE_CANCEL) { + assert(proxy_cache->ref); + proxy_cache->ref--; + if (proxy_cache->ref > 0) { + goto return_cached_info; + } + proxy_cache = NULL; + if (proxy_req->proxy_cache->ref == 0) { + PROXY_CACHE_DELETE(proxy_entry->rsp_cache, proxy_req->proxy_cache); + coap_delete_pdu_lkd(proxy_req->proxy_cache->req_pdu); + coap_delete_pdu_lkd(proxy_req->proxy_cache->rsp_pdu); + coap_free_type(COAP_STRING, proxy_req->proxy_cache); + proxy_req->proxy_cache = NULL; + } + /* Last user of proxy_cache. Need to de-register upstream */ + } else if (observe_action == COAP_OBSERVE_ESTABLISH) { + /* Client must be re-registering */ + goto return_cached_info; + } + } else { + goto return_cached_info; + } + } + } + + if (!proxy_req) { + coap_proxy_req_t *new_req_list; + + new_req_list = coap_realloc_type(COAP_STRING, proxy_entry->req_list, + (proxy_entry->req_count + 1)*sizeof(coap_proxy_req_t)); + + if (new_req_list == NULL) { + goto failed; + } + proxy_entry->req_list = new_req_list; + proxy_req = &new_req_list[proxy_entry->req_count]; + memset(proxy_req, 0, sizeof(coap_proxy_req_t)); + + /* Get a new token for ongoing session */ + coap_session_new_token(proxy_entry->ongoing, &token_len, token); + proxy_req->token_used = coap_new_bin_const(token, token_len); + if (proxy_req->token_used == NULL) { + goto failed; + } + proxy_req->pdu = coap_const_pdu_reference_lkd(request); + proxy_req->resource = resource; + proxy_req->incoming = session; + proxy_req->cache_key = cache_key; + proxy_req->proxy_cache = proxy_cache; + proxy_entry->req_count++; + } else if (obs_opt) { + /* Need to reuse token */ + memcpy(token, proxy_req->token_used->s, proxy_req->token_used->length); + token_len = proxy_req->token_used->length; + } else { + /* Need to refresh used token */ + coap_session_new_token(proxy_entry->ongoing, &token_len, token); + coap_delete_bin_const(proxy_req->token_used); + proxy_req->token_used = coap_new_bin_const(token, token_len); + if (proxy_req->token_used == NULL) { + goto failed; + } + } + + if (proxy_cache) { + if (obs_opt) + proxy_cache->ref++; + goto return_cached_info; + } + /* Need to save the request pdu entry */ - new_req_list = coap_realloc_type(COAP_STRING, proxy_entry->req_list, - (proxy_entry->req_count + 1)*sizeof(coap_proxy_req_t)); - - if (new_req_list == NULL) { - goto failed; - } - proxy_entry->req_list = new_req_list; - /* Get a new token for ongoing session */ - coap_session_new_token(proxy_entry->ongoing, &token_len, token); - new_req_list[proxy_entry->req_count].token_used = coap_new_bin_const(token, token_len); - if (new_req_list[proxy_entry->req_count].token_used == NULL) { - goto failed; - } - new_req_list[proxy_entry->req_count].pdu = coap_pdu_duplicate_lkd(request, session, - r_token.length, r_token.s, NULL); - if (new_req_list[proxy_entry->req_count].pdu == NULL) { - coap_delete_bin_const(new_req_list[proxy_entry->req_count].token_used); - new_req_list[proxy_entry->req_count].token_used = NULL; - goto failed; - } - new_req_list[proxy_entry->req_count].resource = resource; - new_req_list[proxy_entry->req_count].incoming = session; - new_req_list[proxy_entry->req_count].cache_key = cache_key; - proxy_entry->req_count++; - switch (server_list->type) { case COAP_PROXY_REVERSE_STRIP: case COAP_PROXY_FORWARD_STATIC_STRIP: @@ -805,6 +1027,13 @@ failed: response->code = COAP_RESPONSE_CODE(500); coap_delete_pdu_lkd(pdu); return 0; + +return_cached_info: + coap_proxy_call_response_handler(session, request, proxy_cache->rsp_pdu, + &r_token, proxy_req, 1); + if (!obs_opt) + coap_proxy_del_req(proxy_entry, proxy_req); + return 1; } struct coap_proxy_req_t * @@ -969,20 +1198,113 @@ remove_match: option = coap_check_option(received, COAP_OPTION_OBSERVE, &opt_iter); /* Need to remove matching token entry (apart from an Observe response) */ if (option == NULL && proxy_entry->req_count) { - size_t j = proxy_req - proxy_entry->req_list; - coap_delete_pdu_lkd(proxy_entry->req_list[j].pdu); - coap_delete_bin_const(proxy_entry->req_list[j].token_used); /* Do not delete cache key here - caller's responsibility */ - proxy_entry->req_count--; - if (proxy_entry->req_count-j > 0) { - memmove(&proxy_entry->req_list[j], &proxy_entry->req_list[j+1], - (proxy_entry->req_count-j) * sizeof(proxy_entry->req_list[0])); - } + proxy_req->cache_key = NULL; + coap_proxy_del_req(proxy_entry, proxy_req); } coap_delete_binary(body_data); return COAP_RESPONSE_OK; } +void +coap_proxy_process_incoming(coap_session_t *session, + coap_pdu_t *rcvd, + void *body_data, coap_proxy_req_t *proxy_req, + coap_proxy_list_t *proxy_entry) { + coap_opt_t *obs_opt; + coap_opt_t *option; + coap_opt_iterator_t opt_iter; + coap_response_t ret = COAP_RESPONSE_FAIL; + coap_bin_const_t token; + + obs_opt = coap_check_option(rcvd, COAP_OPTION_OBSERVE, &opt_iter); + + /* See if we are doing proxy caching */ + if (obs_opt) { + coap_proxy_cache_t *proxy_cache; + coap_cache_key_t *cache_key_l; + coap_tick_t now; + uint64_t expire; + size_t i; + + /* Need to cache the response */ + if (proxy_req->proxy_cache) { + coap_delete_pdu_lkd(proxy_req->proxy_cache->rsp_pdu); + proxy_cache = proxy_req->proxy_cache; + } else { + proxy_cache = coap_malloc_type(COAP_STRING, sizeof(coap_proxy_cache_t)); + if (proxy_cache == NULL) { + goto cache_fail; + } + memset(proxy_cache, 0, sizeof(coap_proxy_cache_t)); + cache_key_l = coap_cache_derive_key_w_ignore(session, proxy_req->pdu, + COAP_CACHE_NOT_SESSION_BASED, + coap_proxy_ignore_options, + sizeof(coap_proxy_ignore_options)/sizeof(coap_proxy_ignore_options[0])); + if (!cache_key_l) { + coap_free_type(COAP_STRING, proxy_cache); + goto cache_fail; + } + memcpy(&proxy_cache->cache_req, cache_key_l, + sizeof(proxy_cache->cache_req)); + coap_delete_cache_key(cache_key_l); + + proxy_cache->req_pdu = coap_pdu_reference_lkd(proxy_req->pdu); + proxy_req->proxy_cache = proxy_cache; + + PROXY_CACHE_ADD(proxy_entry->rsp_cache, proxy_cache); + proxy_cache->ref++; + } + proxy_cache->rsp_pdu = coap_pdu_reference_lkd(rcvd); + option = coap_check_option(rcvd, COAP_OPTION_ETAG, &opt_iter); + if (option) { + proxy_cache->etag = coap_decode_var_bytes8(coap_opt_value(option), + coap_opt_length(option)); + } else { + proxy_cache->etag = 0; + } + coap_ticks(&now); + option = coap_check_option(rcvd, COAP_OPTION_MAXAGE, &opt_iter); + if (option) { + expire = coap_decode_var_bytes(coap_opt_value(option), + coap_opt_length(option)); + } else { + /* Default is 60 seconds */ + expire = 60; + } + proxy_cache->expire = now + expire * COAP_TICKS_PER_SECOND; + + /* Update all the cache listeners */ + for (i = 0; i < proxy_entry->req_count; i++) { + if (proxy_entry->req_list[i].proxy_cache == proxy_cache) { + proxy_req = &proxy_entry->req_list[i]; + token = coap_pdu_get_token(proxy_req->pdu); + if (coap_proxy_call_response_handler(proxy_req->incoming, proxy_req->pdu, + rcvd, &token, + proxy_req, 0) == COAP_RESPONSE_OK) { + /* At least one success */ + ret = COAP_RESPONSE_OK; + } + } + } + goto finish; + } +cache_fail: + token = coap_pdu_get_token(proxy_req->pdu); + ret = coap_proxy_call_response_handler(proxy_req->incoming, proxy_req->pdu, + rcvd, &token, proxy_req, 0); + +finish: + if (ret == COAP_RESPONSE_FAIL && rcvd->type != COAP_MESSAGE_ACK) { + coap_send_rst_lkd(session, rcvd); + session->last_con_handler_res = COAP_RESPONSE_FAIL; + } else { + coap_send_ack_lkd(session, rcvd); + session->last_con_handler_res = COAP_RESPONSE_OK; + } + coap_free_type(COAP_STRING, body_data); +} + /* */ coap_mid_t diff --git a/src/coap_session.c b/src/coap_session.c index 511a5e3e..541b050c 100644 --- a/src/coap_session.c +++ b/src/coap_session.c @@ -789,7 +789,7 @@ coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu, /* Check same mid is not getting re-used in violation of RFC7252 */ LL_FOREACH(session->delayqueue, q) { if (q->id == pdu->mid) { - coap_log_err("** %s: mid=0x%04x: already in-use - dropped\n", + coap_log_err("** %s: mid=0x%04x: already in-use - dropped\n", coap_session_str(session), pdu->mid); return COAP_INVALID_MID; } @@ -1170,6 +1170,8 @@ coap_session_failed(coap_session_t *session) { if (session->context->reconnect_time && session->state == COAP_SESSION_STATE_ESTABLISHED && session->type == COAP_SESSION_TYPE_CLIENT) { + if (session->sock.lfunc[COAP_LAYER_SESSION].l_close) + session->sock.lfunc[COAP_LAYER_SESSION].l_close(session); session->session_failed = 1; coap_ticks(&session->last_rx_tx); } diff --git a/src/coap_wolfssl.c b/src/coap_wolfssl.c index b6803351..054a1f0a 100644 --- a/src/coap_wolfssl.c +++ b/src/coap_wolfssl.c @@ -2019,6 +2019,7 @@ error: if (ssl) wolfSSL_free(ssl); coap_dtls_free_wolfssl_env(w_env); + session->tls = NULL; return NULL; } #endif /* COAP_SERVER_SUPPORT */ @@ -2699,6 +2700,7 @@ error: if (ssl) wolfSSL_free(ssl); coap_dtls_free_wolfssl_env(w_env); + session->tls = NULL; return NULL; } #endif /* COAP_SERVER_SUPPORT */ @@ -2720,6 +2722,7 @@ coap_tls_free_session(coap_session_t *session) { coap_handle_event_lkd(session->context, COAP_EVENT_DTLS_CLOSED, session); } coap_dtls_free_wolfssl_env(w_env); + session->tls = NULL; } /*