diff --git a/examples/lwip/client-coap.c b/examples/lwip/client-coap.c index 632443e0..6887e097 100644 --- a/examples/lwip/client-coap.c +++ b/examples/lwip/client-coap.c @@ -76,7 +76,7 @@ nack_handler(coap_session_t *session COAP_UNUSED, static int resolve_address(const char *host, const char *service, coap_address_t *dst, - int scheme_hint_bits) { + coap_proto_t *proto, int scheme_hint_bits) { coap_addr_info_t *addr_info; coap_str_const_t str_host; @@ -92,6 +92,7 @@ resolve_address(const char *host, const char *service, coap_address_t *dst, if (addr_info) { ret = 1; *dst = addr_info->addr; + *proto = addr_info->proto; } coap_free_address_info(addr_info); @@ -118,6 +119,7 @@ client_coap_init(coap_lwip_input_wait_handler_t input_wait, void *input_arg, const char *use_psk = "secretPSK"; const char *use_id = "abc"; coap_pdu_type_t pdu_type = COAP_MESSAGE_CON; + coap_proto_t proto; /* Initialize libcoap library */ coap_startup(); @@ -155,17 +157,12 @@ client_coap_init(coap_lwip_input_wait_handler_t input_wait, void *input_arg, /* Parse the URI */ len = coap_split_uri((const unsigned char *)use_uri, strlen(use_uri), &uri); LWIP_ASSERT("Failed to parse uri", len == 0); - LWIP_ASSERT("Unsupported URI type", uri.scheme == COAP_URI_SCHEME_COAP || - uri.scheme == COAP_URI_SCHEME_COAPS); - if (uri.scheme == COAP_URI_SCHEME_COAPS) { - LWIP_ASSERT("DTLS not supported", coap_dtls_is_supported()); - } snprintf(portbuf, sizeof(portbuf), "%d", uri.port); snprintf((char *)buf, sizeof(buf), "%*.*s", (int)uri.host.length, (int)uri.host.length, (const char *)uri.host.s); /* resolve destination address where server should be sent */ - len = resolve_address((const char *)buf, portbuf, &dst, 1 << uri.scheme); + len = resolve_address((const char *)buf, portbuf, &dst, &proto, 1 << uri.scheme); LWIP_ASSERT("Failed to resolve address", len > 0); main_coap_context = coap_new_context(NULL); @@ -174,10 +171,8 @@ client_coap_init(coap_lwip_input_wait_handler_t input_wait, void *input_arg, coap_context_set_block_mode(main_coap_context, COAP_BLOCK_USE_LIBCOAP); coap_lwip_set_input_wait_handler(main_coap_context, input_wait, input_arg); - if (uri.scheme == COAP_URI_SCHEME_COAP) { - session = coap_new_client_session(main_coap_context, NULL, &dst, - COAP_PROTO_UDP); - } else { + if (proto == COAP_PROTO_DTLS || proto == COAP_PROTO_TLS || + proto == COAP_PROTO_WSS) { static coap_dtls_cpsk_t dtls_psk; static char client_sni[256]; @@ -197,6 +192,9 @@ client_coap_init(coap_lwip_input_wait_handler_t input_wait, void *input_arg, session = coap_new_client_session_psk2(main_coap_context, NULL, &dst, COAP_PROTO_DTLS, &dtls_psk); + } else { + session = coap_new_client_session(main_coap_context, NULL, &dst, + proto); } LWIP_ASSERT("Failed to create session", session != NULL); diff --git a/examples/lwip/config/coap_config.h b/examples/lwip/config/coap_config.h index ec86c76c..69bf2f0a 100644 --- a/examples/lwip/config/coap_config.h +++ b/examples/lwip/config/coap_config.h @@ -33,7 +33,11 @@ #ifndef COAP_DISABLE_TCP /* Define to 1 to build without TCP support. */ +#if LWIP_TCP +#define COAP_DISABLE_TCP 0 +#else /* ! LWIP_TCP */ #define COAP_DISABLE_TCP 1 +#endif /* ! LWIP_TCP */ #endif #ifndef COAP_ASYNC_SUPPORT @@ -56,11 +60,21 @@ #define COAP_Q_BLOCK_SUPPORT 0 #endif +#ifndef PACKAGE_NAME #define PACKAGE_NAME "libcoap" -#define PACKAGE_VERSION "4.3.4" -#define PACKAGE_STRING "libcoap 4.3.4" +#endif /* PACKAGE_NAME */ +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "4.3.4" +#endif /* PACKAGE_VERSION */ + +#ifndef PACKAGE_STRING +#define PACKAGE_STRING "libcoap 4.3.4" +#endif /* PACKAGE_STRING */ + +#ifndef assert #define assert(x) LWIP_ASSERT("CoAP assert failed", x) +#endif /* assert */ /* it's just provided by libc. i hope we don't get too many of those, as * actually we'd need autotools again to find out what environment we're diff --git a/examples/lwip/config/coap_config.h.in b/examples/lwip/config/coap_config.h.in index 80899659..4549fcb4 100644 --- a/examples/lwip/config/coap_config.h.in +++ b/examples/lwip/config/coap_config.h.in @@ -33,7 +33,11 @@ #ifndef COAP_DISABLE_TCP /* Define to 1 to build without TCP support. */ +#if LWIP_TCP +#define COAP_DISABLE_TCP 0 +#else /* ! LWIP_TCP */ #define COAP_DISABLE_TCP 1 +#endif /* ! LWIP_TCP */ #endif #ifndef COAP_ASYNC_SUPPORT @@ -56,11 +60,21 @@ #define COAP_Q_BLOCK_SUPPORT 0 #endif +#ifndef PACKAGE_NAME #define PACKAGE_NAME "@PACKAGE_NAME@" -#define PACKAGE_VERSION "@PACKAGE_VERSION@" -#define PACKAGE_STRING "@PACKAGE_STRING@" +#endif /* PACKAGE_NAME */ +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "@PACKAGE_VERSION@" +#endif /* PACKAGE_VERSION */ + +#ifndef PACKAGE_STRING +#define PACKAGE_STRING "@PACKAGE_STRING@" +#endif /* PACKAGE_STRING */ + +#ifndef assert #define assert(x) LWIP_ASSERT("CoAP assert failed", x) +#endif /* assert */ /* it's just provided by libc. i hope we don't get too many of those, as * actually we'd need autotools again to find out what environment we're diff --git a/examples/lwip/config/lwipopts.h b/examples/lwip/config/lwipopts.h index 4543c7eb..929c40dc 100644 --- a/examples/lwip/config/lwipopts.h +++ b/examples/lwip/config/lwipopts.h @@ -23,6 +23,9 @@ #define LWIP_IPV6_MLD 0 #define LWIP_ICMP6 (LWIP_IPV6==1) +/* Set to 1 if TCP support is required */ +#define LWIP_TCP 0 + #ifndef LWIP_RAND #define LWIP_RAND() ((u32_t)rand()) #endif @@ -36,6 +39,8 @@ #define UNLOCK_TCPIP_CORE() #endif +#define MEMP_NUM_SYS_TIMEOUT 10 + #define MEMP_USE_CUSTOM_POOLS 1 #define MEM_SIZE (4 * 1024) /* Support a 1500 MTU packet */ diff --git a/examples/lwip/config/lwippools.h b/examples/lwip/config/lwippools.h index 6a8409ed..eef70b75 100644 --- a/examples/lwip/config/lwippools.h +++ b/examples/lwip/config/lwippools.h @@ -43,11 +43,19 @@ typedef struct l_coap_tiny_context_t { #endif #ifndef MEMP_NUM_COAPENDPOINT +#if COAP_DISABLE_TCP #ifdef COAP_WITH_LIBTINYDTLS #define MEMP_NUM_COAPENDPOINT 2 #else /* ! COAP_WITH_LIBTINYDTLS */ #define MEMP_NUM_COAPENDPOINT 1 #endif /* ! COAP_WITH_LIBTINYDTLS */ +#else /* ! COAP_DISABLE_TCP */ +#ifdef COAP_WITH_LIBTINYDTLS +#define MEMP_NUM_COAPENDPOINT 4 +#else /* ! COAP_WITH_LIBTINYDTLS */ +#define MEMP_NUM_COAPENDPOINT 2 +#endif /* ! COAP_WITH_LIBTINYDTLS */ +#endif /* ! COAP_DISABLE_TCP */ #endif /* 1 is sufficient as this is very short-lived */ @@ -92,7 +100,11 @@ typedef struct l_coap_tiny_context_t { #endif #ifndef MEMP_LEN_COAPSTRING +#ifdef COAP_WITH_LIBTINYDTLS +#define MEMP_LEN_COAPSTRING 120 +#else /* COAP_WITH_TINYDTLS */ #define MEMP_LEN_COAPSTRING 40 +#endif /* COAP_WITH_TINYDTLS */ #endif #ifndef MEMP_NUM_COAPCACHE_KEYS diff --git a/include/coap3/coap_io_internal.h b/include/coap3/coap_io_internal.h index a9506d27..5d686bd7 100644 --- a/include/coap3/coap_io_internal.h +++ b/include/coap3/coap_io_internal.h @@ -33,7 +33,12 @@ struct uip_udp_conn; struct coap_socket_t { #if defined(WITH_LWIP) - struct udp_pcb *pcb; + struct pbuf *p; + struct udp_pcb *udp_pcb; +#if ! COAP_DISABLE_TCP + struct tcp_pcb *tcp_pcb; +#endif /* ! COAP_DISABLE_TCP */ + #elif defined(WITH_CONTIKI) struct uip_udp_conn *udp_conn; coap_context_t *context; diff --git a/include/coap3/coap_mem.h b/include/coap3/coap_mem.h index ad6a464a..bdc22f61 100644 --- a/include/coap3/coap_mem.h +++ b/include/coap3/coap_mem.h @@ -143,13 +143,26 @@ coap_free(void *object) { COAP_STATIC_INLINE void coap_memory_init(void) {} +#if MEMP_STATS +COAP_STATIC_INLINE void * +coap_malloc_error(uint16_t *err) { + (*err)++; + return NULL; +} +#endif /* MEMP_STATS */ /* It would be nice to check that size equals the size given at the memp * declaration, but i currently don't see a standard way to check that without * sourcing the custom memp pools and becoming dependent of its syntax */ +#if MEMP_STATS +#define coap_malloc_type(type, asize) \ + (((asize) <= memp_pools[MEMP_ ## type]->size) ? \ + memp_malloc(MEMP_ ## type) : coap_malloc_error(&memp_pools[MEMP_ ## type]->stats->err)) +#else /* ! MEMP_STATS */ #define coap_malloc_type(type, asize) \ (((asize) <= memp_pools[MEMP_ ## type]->size) ? \ memp_malloc(MEMP_ ## type) : NULL) +#endif /* ! MEMP_STATS */ #define coap_free_type(type, p) memp_free(MEMP_ ## type, p) /* As these are fixed size, return value if already defined */ diff --git a/include/coap3/coap_netif_internal.h b/include/coap3/coap_netif_internal.h index 1196e73e..71c44513 100644 --- a/include/coap3/coap_netif_internal.h +++ b/include/coap3/coap_netif_internal.h @@ -128,10 +128,12 @@ int coap_netif_strm_listen(coap_endpoint_t *endpoint, * * @param endpoint Endpoint to to do the accept on. * @param session Session to to do the accept update on. + * @param extra Available for use by any underlying network stack. * * @return @c 1 OK, 0 on failure. */ -int coap_netif_strm_accept(coap_endpoint_t *endpoint, coap_session_t *session); +int coap_netif_strm_accept(coap_endpoint_t *endpoint, coap_session_t *session, + void *extra); /** * Layer function interface for Netif stream connect (tcp). diff --git a/include/coap3/coap_session_internal.h b/include/coap3/coap_session_internal.h index b0a6710e..b3698bd3 100644 --- a/include/coap3/coap_session_internal.h +++ b/include/coap3/coap_session_internal.h @@ -309,14 +309,14 @@ int coap_session_refresh_psk_identity(coap_session_t *session, * Creates a new server session for the specified endpoint. * @param ctx The CoAP context. * @param ep An endpoint where an incoming connection request is pending. + * @param extra Available for use by any underlying network stack. * * @return A new CoAP session or NULL if failed. Call coap_session_release to * add to unused queue. */ -coap_session_t *coap_new_server_session( - coap_context_t *ctx, - coap_endpoint_t *ep -); +coap_session_t *coap_new_server_session(coap_context_t *ctx, + coap_endpoint_t *ep, + void *extra); #endif /* COAP_SERVER_SUPPORT */ /** @@ -384,6 +384,10 @@ coap_session_t *coap_session_new_dtls_session(coap_session_t *session, void coap_session_free(coap_session_t *session); void coap_session_mfree(coap_session_t *session); +void coap_read_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now); + +void coap_connect_session(coap_session_t *session, coap_tick_t now); + #define COAP_SESSION_REF(s) ((s)->ref /* RFC7252 */ diff --git a/include/coap3/coap_tcp_internal.h b/include/coap3/coap_tcp_internal.h index e14a927a..f57d14b6 100644 --- a/include/coap3/coap_tcp_internal.h +++ b/include/coap3/coap_tcp_internal.h @@ -93,13 +93,15 @@ int coap_socket_bind_tcp(coap_socket_t *sock, * session information * @param local_addr Filled in with the local address * @param remote_addr Filled in with the remote address + * @param extra Available for use by any underlying network stack. * * @return @c 1 if succesful, @c 0 if failure of some sort */ int coap_socket_accept_tcp(coap_socket_t *server, coap_socket_t *new_client, coap_address_t *local_addr, - coap_address_t *remote_addr); + coap_address_t *remote_addr, + void *extra); #endif /* !COAP_DISABLE_TCP */ diff --git a/src/coap_io_lwip.c b/src/coap_io_lwip.c index 636daa39..6e4de8a6 100644 --- a/src/coap_io_lwip.c +++ b/src/coap_io_lwip.c @@ -202,7 +202,7 @@ coap_free_packet(coap_packet_t *packet) { coap_free_type(COAP_PACKET, packet); } -/** Callback from lwIP when a package was received for a server. +/** Callback from lwIP when a UDP packet was received for a server. * * The current implementation deals this to coap_dispatch immediately, but * other mechanisms (as storing the package in a queue and later fetching it @@ -211,8 +211,8 @@ coap_free_packet(coap_packet_t *packet) { * It handles everything coap_io_do_io does on other implementations. */ static void -coap_recvs(void *arg, struct udp_pcb *upcb, struct pbuf *p, - const ip_addr_t *addr, u16_t port) { +coap_udp_recvs(void *arg, struct udp_pcb *upcb, struct pbuf *p, + const ip_addr_t *addr, u16_t port) { coap_endpoint_t *ep = (coap_endpoint_t *)arg; coap_pdu_t *pdu = NULL; coap_session_t *session = NULL; @@ -304,7 +304,7 @@ coap_socket_send_pdu(coap_socket_t *sock, coap_session_t *session, pbuf = pbuf_clone(PBUF_TRANSPORT, PBUF_RAM, pdu->pbuf); if (pbuf == NULL) return -1; - err = udp_sendto(sock->pcb, pbuf, &session->addr_info.remote.addr, + err = udp_sendto(sock->udp_pcb, pbuf, &session->addr_info.remote.addr, session->addr_info.remote.port); pbuf_free(pbuf); if (err < 0) @@ -332,7 +332,7 @@ coap_socket_send(coap_socket_t *sock, const coap_session_t *session, LOCK_TCPIP_CORE(); - err = udp_sendto(sock->pcb, pbuf, &session->addr_info.remote.addr, + err = udp_sendto(sock->udp_pcb, pbuf, &session->addr_info.remote.addr, session->addr_info.remote.port); UNLOCK_TCPIP_CORE(); @@ -352,19 +352,19 @@ coap_socket_bind_udp(coap_socket_t *sock, int err; coap_address_t l_listen = *listen_addr; - sock->pcb = udp_new_ip_type(IPADDR_TYPE_ANY); - if (sock->pcb == NULL) + sock->udp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + if (sock->udp_pcb == NULL) return 0; #if LWIP_IPV6 && LWIP_IPV4 if (l_listen.addr.type == IPADDR_TYPE_V6) l_listen.addr.type = IPADDR_TYPE_ANY; #endif /* LWIP_IPV6 && LWIP_IPV4 */ - udp_recv(sock->pcb, coap_recvs, (void *)sock->endpoint); - err = udp_bind(sock->pcb, &l_listen.addr, l_listen.port); + udp_recv(sock->udp_pcb, coap_udp_recvs, (void *)sock->endpoint); + err = udp_bind(sock->udp_pcb, &l_listen.addr, l_listen.port); if (err) { - udp_remove(sock->pcb); - sock->pcb = NULL; + udp_remove(sock->udp_pcb); + sock->udp_pcb = NULL; } *bound_addr = l_listen; return err ? 0 : 1; @@ -413,9 +413,9 @@ coap_socket_connect_udp(coap_socket_t *sock, pcb->local_ip.type = pcb->remote_ip.type; #endif /* LWIP_IPV6 && LWIP_IPV4 */ - sock->pcb = pcb; + sock->udp_pcb = pcb; - udp_recv(sock->pcb, coap_recvc, (void *)sock->session); + udp_recv(sock->udp_pcb, coap_recvc, (void *)sock->session); UNLOCK_TCPIP_CORE(); @@ -431,6 +431,77 @@ err_unlock: #endif /* ! COAP_CLIENT_SUPPORT */ #if ! COAP_DISABLE_TCP + +#include + +static void +do_tcp_err(void *arg, err_t err) { + coap_session_t *session = (coap_session_t *)arg; + + (void)err; + + coap_handle_event(session->context, COAP_EVENT_TCP_FAILED, session); + /* + * as per tcp_err() documentation, the corresponding pcb is already freed + * when this callback is called. So, stop a double free when + * coap_session_disconnected() eventually coap_socket_close() is called. + */ + session->sock.tcp_pcb = NULL; + coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); +} + +/** Callback from lwIP when a TCP packet is received. + * + * The current implementation invokes coap_read_session() to do the bulk of the + * work. + */ +static err_t +coap_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { + coap_session_t *session = (coap_session_t *)arg; + coap_socket_t *sock = &session->sock; + coap_tick_t now; + + (void)tpcb; + if (p == NULL) { + /* remote host closed connection */ + tcp_arg(sock->tcp_pcb, NULL); + tcp_recv(sock->tcp_pcb, NULL); + tcp_close(sock->tcp_pcb); + sock->tcp_pcb = NULL; + coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); + return ERR_OK; + } else if (err != ERR_OK) { + /* cleanup, for unknown reason */ + if (p != NULL) { + pbuf_free(p); + } + return err; + } + + sock->p = p; + coap_ticks(&now); + coap_read_session(session->context, session, now); + return ERR_OK; +} + +#if COAP_CLIENT_SUPPORT + +static err_t +do_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) { + coap_session_t *session = (coap_session_t *)arg; + coap_tick_t now; + + if (err) + return err; + session->sock.flags |= COAP_SOCKET_CONNECTED; + session->addr_info.local.addr = tpcb->local_ip; + session->addr_info.local.port = tpcb->local_port; + tcp_recv(tpcb, coap_tcp_recv); + coap_ticks(&now); + coap_connect_session(session, now); + return ERR_OK; +} + int coap_socket_connect_tcp1(coap_socket_t *sock, const coap_address_t *local_if, @@ -438,13 +509,45 @@ coap_socket_connect_tcp1(coap_socket_t *sock, int default_port, coap_address_t *local_addr, coap_address_t *remote_addr) { - (void)sock; - (void)local_if; - (void)server; - (void)default_port; + coap_address_t connect_addr; + err_t err; + (void)local_addr; (void)remote_addr; - return 0; + + sock->flags &= ~(COAP_SOCKET_WANT_CONNECT | COAP_SOCKET_CONNECTED); + + sock->tcp_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); + if (sock->tcp_pcb == NULL) + return 0; + + tcp_arg(sock->tcp_pcb, sock->session); + tcp_recv(sock->tcp_pcb, coap_tcp_recv); + tcp_err(sock->tcp_pcb, do_tcp_err); + if (local_if) { + coap_address_t l_local_if = *local_if; +#if LWIP_IPV6 && LWIP_IPV4 + if (l_local_if.addr.type == IPADDR_TYPE_V6) + l_local_if.addr.type = IPADDR_TYPE_ANY; +#endif /* LWIP_IPV6 && LWIP_IPV4 */ + err = tcp_bind(sock->tcp_pcb, &l_local_if.addr, l_local_if.port); + if (err != ERR_OK) { + tcp_arg(sock->tcp_pcb, NULL); + tcp_recv(sock->tcp_pcb, NULL); + tcp_close(sock->tcp_pcb); + sock->tcp_pcb = NULL; + return 0; + } + } + coap_address_copy(&connect_addr, server); + if (connect_addr.port == 0) + connect_addr.port = htons(default_port); + + err = tcp_connect(sock->tcp_pcb, &connect_addr.addr, connect_addr.port, + do_tcp_connected); + if (err == ERR_OK) + sock->flags |= COAP_SOCKET_WANT_CONNECT | COAP_SOCKET_CONNECTED; + return err ? 0 : 1; } int @@ -454,55 +557,174 @@ coap_socket_connect_tcp2(coap_socket_t *sock, (void)sock; (void)local_addr; (void)remote_addr; - return 0; + + sock->flags &= ~(COAP_SOCKET_WANT_CONNECT | COAP_SOCKET_CAN_CONNECT); + return 1; +} +#endif /* COAP_CLIENT_SUPPORT */ + +#if COAP_SERVER_SUPPORT + +static err_t +do_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { + coap_endpoint_t *endpoint = arg; + coap_session_t *session; + coap_tick_t now; + err_t ret_err = ERR_OK; + + if ((err != ERR_OK) || (newpcb == NULL)) { + return ERR_VAL; + } + coap_ticks(&now); + + session = coap_new_server_session(endpoint->context, endpoint, newpcb); + + if (session) { + session->sock.tcp_pcb = newpcb; + session->last_rx_tx = now; + tcp_arg(newpcb, session); + tcp_setprio(newpcb, TCP_PRIO_MIN); + tcp_recv(newpcb, coap_tcp_recv); + tcp_err(newpcb, do_tcp_err); + } else { + ret_err = ERR_MEM; + } + return ret_err; } int coap_socket_bind_tcp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr) { - (void)sock; - (void)listen_addr; - (void)bound_addr; - return 0; + int err; + coap_address_t l_listen = *listen_addr; + struct tcp_pcb *tcp_pcb; + + sock->tcp_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); + if (sock->tcp_pcb == NULL) + return 0; + +#if LWIP_IPV6 && LWIP_IPV4 + if (l_listen.addr.type == IPADDR_TYPE_V6) + l_listen.addr.type = IPADDR_TYPE_ANY; +#endif /* LWIP_IPV6 && LWIP_IPV4 */ + tcp_arg(sock->tcp_pcb, sock->endpoint); + err = tcp_bind(sock->tcp_pcb, &l_listen.addr, l_listen.port); + if (err != ERR_OK) { + tcp_arg(sock->tcp_pcb, NULL); + tcp_recv(sock->tcp_pcb, NULL); + tcp_close(sock->tcp_pcb); + sock->tcp_pcb = NULL; + return 0; + } else { + tcp_pcb = tcp_listen(sock->tcp_pcb); + if (tcp_pcb) { + sock->tcp_pcb = tcp_pcb; + tcp_accept(sock->tcp_pcb, do_tcp_accept); + } else { + tcp_arg(sock->tcp_pcb, NULL); + tcp_recv(sock->tcp_pcb, NULL); + tcp_close(sock->tcp_pcb); + sock->tcp_pcb = NULL; + return 0; + } + } + *bound_addr = l_listen; + return err ? 0 : 1; } int coap_socket_accept_tcp(coap_socket_t *server, coap_socket_t *new_client, coap_address_t *local_addr, - coap_address_t *remote_addr) { + coap_address_t *remote_addr, + void *extra) { + struct tcp_pcb *tcp_pcb = (struct tcp_pcb *)extra; + (void)server; - (void)new_client; - (void)local_addr; - (void)remote_addr; + + new_client->tcp_pcb = tcp_pcb; + local_addr->addr = tcp_pcb->local_ip; + local_addr->port = tcp_pcb->local_port; + remote_addr->addr = tcp_pcb->remote_ip; + remote_addr->port = tcp_pcb->remote_port; + return 1; +} +#endif /* COAP_SERVER_SUPPORT */ + +/* + * strm + * return +ve Number of bytes written. + * -1 Error error in errno). + */ +ssize_t +coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) { + struct pbuf *pbuf; + int err; + + pbuf = pbuf_alloc(PBUF_TRANSPORT, data_len, PBUF_RAM); + if (pbuf == NULL) + return -1; + memcpy(pbuf->payload, data, data_len); + + LOCK_TCPIP_CORE(); + + err = tcp_write(sock->tcp_pcb, pbuf->payload, pbuf->len, 1); + + UNLOCK_TCPIP_CORE(); + + pbuf_free(pbuf); + if (err < 0) + return -1; + return data_len; +} + +/* + * strm + * return >=0 Number of bytes read. + * -1 Error error in errno). + */ +ssize_t +coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) { + if (sock->p) { + if (data_len < sock->p->len) { + uint8_t *ptr = (uint8_t *)sock->p->payload; + + /* Handle partial read of data request */ + memcpy(data, sock->p->payload, data_len); + sock->p->payload = &ptr[data_len]; + sock->p->len -= data_len; + return data_len; + } else { + data_len = sock->p->len; + memcpy(data, sock->p->payload, sock->p->len); + pbuf_free(sock->p); + sock->p = NULL; + return data_len; + } + } return 0; } #endif /* !COAP_DISABLE_TCP */ -ssize_t -coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) { - (void)sock; - (void)data; - (void)data_len; - return -1; -} - -ssize_t -coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) { - (void)sock; - (void)data; - (void)data_len; - return -1; -} - void coap_socket_close(coap_socket_t *sock) { - if (sock->pcb) { + if (sock->udp_pcb) { LOCK_TCPIP_CORE(); - udp_remove(sock->pcb); + udp_remove(sock->udp_pcb); UNLOCK_TCPIP_CORE(); + sock->udp_pcb = NULL; } - sock->pcb = NULL; +#if ! COAP_DISABLE_TCP + if (sock->tcp_pcb) { + tcp_arg(sock->tcp_pcb, NULL); +#if COAP_SERVER_SUPPORT + if (!sock->endpoint) +#endif /* COAP_SERVER_SUPPORT */ + tcp_recv(sock->tcp_pcb, NULL); + tcp_close(sock->tcp_pcb); + sock->tcp_pcb = NULL; + } +#endif /* !COAP_DISABLE_TCP */ return; } diff --git a/src/coap_net.c b/src/coap_net.c index 17de6105..b97be8db 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -1761,7 +1761,7 @@ coap_handle_dgram_for_proto(coap_context_t *ctx, coap_session_t *session, coap_p } #if COAP_CLIENT_SUPPORT -static void +void coap_connect_session(coap_session_t *session, coap_tick_t now) { #if COAP_DISABLE_TCP (void)now; @@ -1808,7 +1808,7 @@ coap_write_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now } } -static void +void coap_read_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now) { #if COAP_CONSTRAINED_STACK /* payload and packet protected by mutex m_read_session */ @@ -2061,8 +2061,8 @@ coap_write_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint, coap_tick_t #if !COAP_DISABLE_TCP static int coap_accept_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint, - coap_tick_t now) { - coap_session_t *session = coap_new_server_session(ctx, endpoint); + coap_tick_t now, void *extra) { + coap_session_t *session = coap_new_server_session(ctx, endpoint, extra); if (session) session->last_rx_tx = now; return session != NULL; @@ -2088,7 +2088,7 @@ coap_io_do_io(coap_context_t *ctx, coap_tick_t now) { coap_write_endpoint(ctx, ep, now); #if !COAP_DISABLE_TCP if ((ep->sock.flags & COAP_SOCKET_CAN_ACCEPT) != 0) - coap_accept_endpoint(ctx, ep, now); + coap_accept_endpoint(ctx, ep, now, NULL); #endif /* !COAP_DISABLE_TCP */ SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) { /* Make sure the session object is not deleted in one of the callbacks */ @@ -2168,7 +2168,7 @@ coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events, size_t nevents if ((sock->flags & COAP_SOCKET_WANT_ACCEPT) && (events[j].events & EPOLLIN)) { sock->flags |= COAP_SOCKET_CAN_ACCEPT; - coap_accept_endpoint(endpoint->context, endpoint, now); + coap_accept_endpoint(endpoint->context, endpoint, now, NULL); } #endif /* !COAP_DISABLE_TCP */ diff --git a/src/coap_netif.c b/src/coap_netif.c index 2df5f66e..13442aa6 100644 --- a/src/coap_netif.c +++ b/src/coap_netif.c @@ -167,10 +167,10 @@ coap_netif_strm_listen(coap_endpoint_t *endpoint, } int -coap_netif_strm_accept(coap_endpoint_t *endpoint, coap_session_t *session) { +coap_netif_strm_accept(coap_endpoint_t *endpoint, coap_session_t *session, void *extra) { if (!coap_socket_accept_tcp(&endpoint->sock, &session->sock, &session->addr_info.local, - &session->addr_info.remote)) { + &session->addr_info.remote, extra)) { return 0; } session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_CONNECTED | diff --git a/src/coap_session.c b/src/coap_session.c index 682729ca..2d5a0cd7 100644 --- a/src/coap_session.c +++ b/src/coap_session.c @@ -492,7 +492,8 @@ coap_session_mfree(coap_session_t *session) { if (session->partial_pdu) coap_delete_pdu(session->partial_pdu); - session->sock.lfunc[COAP_LAYER_SESSION].l_close(session); + if (session->sock.lfunc[COAP_LAYER_SESSION].l_close) + session->sock.lfunc[COAP_LAYER_SESSION].l_close(session); if (session->psk_identity) coap_delete_bin_const(session->psk_identity); if (session->psk_key) @@ -1529,7 +1530,7 @@ coap_new_client_session_pki(coap_context_t *ctx, #if COAP_SERVER_SUPPORT #if !COAP_DISABLE_TCP coap_session_t * -coap_new_server_session(coap_context_t *ctx, coap_endpoint_t *ep) { +coap_new_server_session(coap_context_t *ctx, coap_endpoint_t *ep, void *extra) { coap_session_t *session; session = coap_make_session(ep->proto, COAP_SESSION_TYPE_SERVER, NULL, NULL, NULL, 0, ctx, ep); @@ -1537,7 +1538,7 @@ coap_new_server_session(coap_context_t *ctx, coap_endpoint_t *ep) { goto error; memcpy(session->sock.lfunc, ep->sock.lfunc, sizeof(session->sock.lfunc)); - if (!coap_netif_strm_accept(ep, session)) + if (!coap_netif_strm_accept(ep, session, extra)) goto error; coap_make_addr_hash(&session->addr_hash, session->proto, &session->addr_info); diff --git a/src/coap_tcp.c b/src/coap_tcp.c index 124a927a..f84f84a5 100644 --- a/src/coap_tcp.c +++ b/src/coap_tcp.c @@ -38,7 +38,7 @@ coap_tcp_is_supported(void) { return !COAP_DISABLE_TCP; } -#if !COAP_DISABLE_TCP +#if !COAP_DISABLE_TCP && !defined(WITH_LWIP) int coap_socket_connect_tcp1(coap_socket_t *sock, const coap_address_t *local_if, @@ -176,12 +176,12 @@ coap_socket_connect_tcp2(coap_socket_t *sock, if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, OPTVAL_GT(&error), &optlen) == COAP_SOCKET_ERROR) { - coap_log_warn("coap_socket_finish_connect_tcp: getsockopt: %s\n", + coap_log_warn("coap_socket_connect_tcp2: getsockopt: %s\n", coap_socket_strerror()); } if (error) { - coap_log_warn("coap_socket_finish_connect_tcp: connect failed: %s\n", + coap_log_warn("coap_socket_connect_tcp2: connect failed: %s\n", coap_socket_format_errno(error)); coap_socket_close(sock); return 0; @@ -299,7 +299,8 @@ int coap_socket_accept_tcp(coap_socket_t *server, coap_socket_t *new_client, coap_address_t *local_addr, - coap_address_t *remote_addr) { + coap_address_t *remote_addr, + void *extra) { #ifndef RIOT_VERSION #ifdef _WIN32 u_long u_on = 1; @@ -307,6 +308,7 @@ coap_socket_accept_tcp(coap_socket_t *server, int on = 1; #endif #endif /* RIOT_VERSION */ + (void)extra; server->flags &= ~COAP_SOCKET_CAN_ACCEPT;