From f0f7972a64d33153d7658f6f97f810be8b859887 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 05:12:10 -0500 Subject: [PATCH 01/33] Move to asynch lwip sockets based on armmbed/sal-stack-lwip Move the backend of LWIPInterface from the LWIP socket API to the asynch UDP/TCP APIs used in https://github.com/armmbed/sal-stack-lwip. Provides asynchronous functionality for the LWIPInterface. --- net/LWIPInterface/LWIPInterface.cpp | 419 +++++++++++++++++++++------- 1 file changed, 314 insertions(+), 105 deletions(-) diff --git a/net/LWIPInterface/LWIPInterface.cpp b/net/LWIPInterface/LWIPInterface.cpp index 18df1b3328..a39ff0666f 100644 --- a/net/LWIPInterface/LWIPInterface.cpp +++ b/net/LWIPInterface/LWIPInterface.cpp @@ -25,6 +25,15 @@ #include "lwip/netdb.h" #include "netif/etharp.h" #include "eth_arch.h" +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" +#include "lwip/timers.h" +#include "lwip/dns.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" + /* TCP/IP and Network Interface Initialisation */ static struct netif netif; @@ -36,19 +45,19 @@ static Semaphore tcpip_inited(0); static Semaphore netif_linked(0); static Semaphore netif_up(0); -static void tcpip_init_done(void *) +static void tcpip_init_irq(void *) { tcpip_inited.release(); } -static void netif_link_callback(struct netif *netif) +static void netif_link_irq(struct netif *netif) { if (netif_is_link_up(netif)) { netif_linked.release(); } } -static void netif_status_callback(struct netif *netif) +static void netif_status_irq(struct netif *netif) { if (netif_is_up(netif)) { strcpy(ip_addr, inet_ntoa(netif->ip_addr)); @@ -58,15 +67,15 @@ static void netif_status_callback(struct netif *netif) static void init_netif(ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw) { - tcpip_init(tcpip_init_done, NULL); + tcpip_init(tcpip_init_irq, NULL); tcpip_inited.wait(); memset((void*) &netif, 0, sizeof(netif)); netif_add(&netif, ipaddr, netmask, gw, NULL, eth_arch_enetif_init, tcpip_input); netif_set_default(&netif); - netif_set_link_callback (&netif, netif_link_callback); - netif_set_status_callback(&netif, netif_status_callback); + netif_set_link_callback (&netif, netif_link_irq); + netif_set_status_callback(&netif, netif_status_irq); } static void set_mac_address(void) @@ -82,6 +91,7 @@ static void set_mac_address(void) } +/* Interface implementation */ int LWIPInterface::connect() { // Set up network @@ -122,51 +132,101 @@ const char *LWIPInterface::get_mac_address() return mac_addr; } +struct lwip_socket { + nsapi_protocol_t proto; + union { + struct udp_pcb *udp; + struct tcp_pcb *tcp; + }; + + struct pbuf *rx_chain; + Semaphore *sem; + + void (*send_cb)(void *); void *send_data; + void (*recv_cb)(void *); void *recv_data; +}; + +static void udp_recv_irq( + void *arg, struct udp_pcb *upcb, struct pbuf *p, + struct ip_addr *addr, uint16_t port); + void *LWIPInterface::socket_create(nsapi_protocol_t proto) { - int type = (proto == NSAPI_UDP) ? SOCK_DGRAM : SOCK_STREAM; - int fd = lwip_socket(AF_INET, type, 0); - if (fd < 0) { + struct lwip_socket *s = new struct lwip_socket; + if (!s) { return 0; } - return (void *)(fd+1); + memset(s, 0, sizeof *s); + + switch (proto) { + case NSAPI_UDP: + s->proto = proto; + s->udp = udp_new(); + if (!s->udp) { + return 0; + } + + udp_recv(s->udp, udp_recv_irq, s); + return s; + + case NSAPI_TCP: + s->proto = proto; + s->tcp = tcp_new(); + if (!s->tcp) { + return 0; + } + + tcp_arg(s->tcp, s); + //tcp_err(s->tcp, tcp_error_irq); + return s; + } + + return 0; } void LWIPInterface::socket_destroy(void *handle) { - int fd = (int)handle-1; - lwip_close(fd); - + struct lwip_socket *s = (struct lwip_socket *)handle; + + if (s->rx_chain) { + pbuf_free(s->rx_chain); + s->rx_chain = 0; + } + + delete s; } int LWIPInterface::socket_set_option(void *handle, int optname, const void *optval, unsigned optlen) { - int fd = (int)handle-1; - return lwip_setsockopt(fd, SOL_SOCKET, optname, optval, (socklen_t)optlen); + return NSAPI_ERROR_UNSUPPORTED; } int LWIPInterface::socket_get_option(void *handle, int optname, void *optval, unsigned *optlen) { - int fd = (int)handle-1; - return lwip_getsockopt(fd, SOL_SOCKET, optname, optval, (socklen_t*)optlen); + return NSAPI_ERROR_UNSUPPORTED; } int LWIPInterface::socket_bind(void *handle, int port) { - int fd = (int)handle-1; - struct sockaddr_in sa; - memset(&sa, 0, sizeof sa); - - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = INADDR_ANY; - - if (lwip_bind(fd, (const struct sockaddr *)&sa, sizeof sa) < 0) { - return NSAPI_ERROR_DEVICE_ERROR; + struct lwip_socket *s = (struct lwip_socket *)handle; + ip_addr_t ip_addr = ip_addr_any; + + switch (s->proto) { + case NSAPI_UDP: + if (udp_bind(s->udp, &ip_addr, port)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + return 0; + + case NSAPI_TCP: + if (tcp_bind(s->tcp, &ip_addr, port)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + return 0; } - - return 0; + + return NSAPI_ERROR_DEVICE_ERROR; } int LWIPInterface::socket_listen(void *handle, int backlog) @@ -174,16 +234,34 @@ int LWIPInterface::socket_listen(void *handle, int backlog) return NSAPI_ERROR_UNSUPPORTED; } +static err_t tcp_sent_irq(void *arg, struct tcp_pcb *tpcb, uint16_t len); +static err_t tcp_recv_irq(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); + +static err_t tcp_connect_irq(void *handle, struct tcp_pcb *tpcb, err_t err) +{ + struct lwip_socket *s = (struct lwip_socket *)handle; + tcp_sent(tpcb, tcp_sent_irq); + tcp_recv(tpcb, tcp_recv_irq); + + s->sem->release(); + + return ERR_OK; +} + int LWIPInterface::socket_connect(void *handle, const SocketAddress &addr) { - int fd = (int)handle-1; - struct sockaddr_in sa; - memset(&sa, 0, sizeof sa); - inet_aton(addr.get_ip_address(), &sa.sin_addr); - sa.sin_family = AF_INET; - sa.sin_port = htons(addr.get_port()); + struct lwip_socket *s = (struct lwip_socket *)handle; - if (lwip_connect(fd, (const struct sockaddr *)&sa, sizeof sa) < 0) { + ip_addr_t ip_addr; + inet_aton(addr.get_ip_address(), &ip_addr); + + Semaphore connected(0); + s->sem = &connected; + + tcp_connect(s->tcp, &ip_addr, addr.get_port(), tcp_connect_irq); + + // Wait for connection + if (connected.wait(1500) < 0) { return NSAPI_ERROR_NO_CONNECTION; } @@ -200,105 +278,230 @@ int LWIPInterface::socket_accept(void *handle, void **connection) return NSAPI_ERROR_UNSUPPORTED; } -int LWIPInterface::socket_send(void *handle, const void *p, unsigned size) +static struct pbuf *pbuf_consume(struct pbuf *p, size_t consume, bool free_partial) { - int fd = (int)handle-1; - uint8_t *data = (uint8_t *)p; - unsigned written = 0; - - while (written < size) { - int ret = lwip_send(fd, data + written, size - written, 0); - - if (ret > 0) { - written += ret; - } else if (ret == 0) { - return NSAPI_ERROR_NO_CONNECTION; - } else { - return NSAPI_ERROR_DEVICE_ERROR; + do { + if (consume <= p->len) { + // advance the payload pointer by the number of bytes copied + p->payload = (char *)p->payload + consume; + // reduce the length by the number of bytes copied + p->len -= consume; + // break out of the loop + consume = 0; } - } - - return written; + if (p->len == 0 || consume > p->len || (consume == 0 && free_partial)) { + struct pbuf *q; + q = p->next; + // decrement the number of bytes copied by the length of the buffer + if(consume > p->len) + consume -= p->len; + // Free the current pbuf + // NOTE: This operation is interrupt safe, but not thread safe. + if (q != NULL) { + pbuf_ref(q); + } + pbuf_free(p); + p = q; + } + } while (consume); + return p; } -int LWIPInterface::socket_recv(void *handle, void *data, unsigned size) +static err_t tcp_sent_irq(void *handle, struct tcp_pcb *tpcb, uint16_t len) { - int fd = (int)handle-1; - int ret = lwip_recv(fd, data, size, MSG_DONTWAIT); + struct lwip_socket *s = (struct lwip_socket *)handle; + if (s->send_cb) { + s->send_cb(s->send_data); + } - if (ret > 0) { - return ret; - } else if (ret == 0) { - return NSAPI_ERROR_NO_CONNECTION; - } else if (ret == -1) { - return NSAPI_ERROR_WOULD_BLOCK; - } else { + return ERR_OK; +} + +int LWIPInterface::socket_send(void *handle, const void *buf, unsigned size) +{ + struct lwip_socket *s = (struct lwip_socket *)handle; + + if (tcp_write(s->tcp, buf, size, TCP_WRITE_FLAG_COPY)) { return NSAPI_ERROR_DEVICE_ERROR; } + + tcp_output(s->tcp); + + return size; } -int LWIPInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *p, unsigned size) +static err_t tcp_recv_irq(void *handle, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { - int fd = (int)handle-1; - uint8_t *data = (uint8_t *)p; - unsigned written = 0; + struct lwip_socket *s = (struct lwip_socket *)handle; - struct sockaddr_in sa; - memset(&sa, 0, sizeof sa); - inet_aton(addr.get_ip_address(), &sa.sin_addr); - sa.sin_family = AF_INET; - sa.sin_port = htons(addr.get_port()); - - while (written < size) { - int ret = lwip_sendto(fd, data + written, size - written, 0, - (const struct sockaddr *)&sa, sizeof sa); - - if (ret > 0) { - written += ret; - } else if (ret == 0) { - return NSAPI_ERROR_NO_CONNECTION; - } else { - return NSAPI_ERROR_DEVICE_ERROR; + // Check for disconnect + if (!p) { + // Zero pcb during disconnect, since disconnect will cause a free + switch (tpcb->state) { + case FIN_WAIT_1: + case FIN_WAIT_2: + case TIME_WAIT: + s->tcp = 0; + break; + default: + break; } + return ERR_OK; } - return written; + __disable_irq(); + if (!s->rx_chain) { + s->rx_chain = p; + } else { + pbuf_cat(s->rx_chain, p); + } + __enable_irq(); + + if (s->recv_cb) { + s->recv_cb(s->recv_data); + } + + return ERR_OK; } -int LWIPInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +int LWIPInterface::socket_recv(void *handle, void *buf, unsigned size) { - int fd = (int)handle-1; - struct sockaddr_in sa; - socklen_t sa_len = sizeof sa; + struct lwip_socket *s = (struct lwip_socket *)handle; - int ret = lwip_recvfrom(fd, data, size, MSG_DONTWAIT, - (struct sockaddr *)&sa, &sa_len); - - if (ret > 0 && addr) { - addr->set_ip_address(inet_ntoa(sa.sin_addr)); - addr->set_port(ntohs(sa.sin_port)); + // Disconnected + if (!s->tcp && !s->rx_chain) { + return NSAPI_ERROR_NO_CONNECTION; } - if (ret > 0) { - return ret; - } else if (ret == 0) { - return NSAPI_ERROR_NO_CONNECTION; - } else if (ret == -1) { + // Nothing ready + if (!s->rx_chain) { return NSAPI_ERROR_WOULD_BLOCK; - } else { + } + + // Copy out pbuf + struct pbuf *p = s->rx_chain; + int copied = pbuf_copy_partial(p, buf, size, 0); + s->rx_chain = pbuf_consume(p, copied, false); + + // Update TCP window + tcp_recved(s->tcp, copied); + return copied; +} + +int LWIPInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *buf, unsigned size) +{ + struct lwip_socket *s = (struct lwip_socket *)handle; + + struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); + if (pbuf_take(pb, buf, size)) { return NSAPI_ERROR_DEVICE_ERROR; } + + ip_addr_t id_addr; + inet_aton(addr.get_ip_address(), &id_addr); + + err_t err = udp_sendto(s->udp, pb, &id_addr, addr.get_port()); + pbuf_free(pb); + if (err) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + if (s->send_cb) { + s->send_cb(s->send_data); + } + + return size; +} + +static void udp_recv_irq( + void *handle, struct udp_pcb *upcb, struct pbuf *p, + struct ip_addr *addr, uint16_t port) +{ + struct lwip_socket *s = (struct lwip_socket *)handle; + + __disable_irq(); + if (!s->rx_chain) { + s->rx_chain = p; + } else { + // Attach p to buffer chain without changing the tot_len + // NOTE: This is not how pbufs are intended to work, but it is necessary to deal with + // a) fragmentation and b) packet queueing + struct pbuf *q = s->rx_chain; + while (q->next) { q = q->next; } + q->next = p; + } + __enable_irq(); + + if (s->recv_cb) { + s->recv_cb(s->recv_data); + } +} + +int LWIPInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *buf, unsigned size) +{ + struct lwip_socket *s = (struct lwip_socket *)handle; + + // Disconnected + if (!s->udp && !s->rx_chain) { + return NSAPI_ERROR_NO_CONNECTION; + } + + // Nothing ready + if (!s->rx_chain) { + return NSAPI_ERROR_WOULD_BLOCK; + } + + struct pbuf *p = s->rx_chain; + + if (addr) { + struct udp_hdr *udphdr; + struct ip_hdr *iphdr; + + // roll back the pbuf by udp_hdr to find the source port + pbuf_header(p, UDP_HLEN); + udphdr = (struct udp_hdr *)p->payload; + + // roll back the pbuf by ip_hdr to find the source IP + pbuf_header(p, IP_HLEN); + iphdr = (struct ip_hdr *)p->payload; + + // put the pbuf back where it was + pbuf_header(p, -UDP_HLEN - IP_HLEN); + + addr->set_ip_address(inet_ntoa(iphdr->src)); + addr->set_port(ntohs(udphdr->src)); + } + + // Copy out pbuf + size = size < p->tot_len ? size : p->tot_len; + int copied = pbuf_copy_partial(p, buf, size, 0); + s->rx_chain = pbuf_consume(p, p->tot_len, true); + + return copied; } int LWIPInterface::socket_close(void *handle, bool shutdown) { - int fd = (int)handle-1; - if (shutdown) { - lwip_shutdown(fd, SHUT_RDWR); + struct lwip_socket *s = (struct lwip_socket *)handle; + + switch (s->proto) { + case NSAPI_UDP: + udp_disconnect(s->udp); + return 0; + + case NSAPI_TCP: + if (shutdown) { + tcp_abort(s->tcp); + } + + if (tcp_close(s->tcp)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + return 0; } - lwip_close(fd); - return 0; + return NSAPI_ERROR_DEVICE_ERROR; } void LWIPInterface::socket_attach_accept(void *handle, void (*callback)(void *), void *id) @@ -307,9 +510,15 @@ void LWIPInterface::socket_attach_accept(void *handle, void (*callback)(void *), void LWIPInterface::socket_attach_send(void *handle, void (*callback)(void *), void *id) { + struct lwip_socket *s = (struct lwip_socket *)handle; + s->send_cb = callback; + s->send_data = id; } void LWIPInterface::socket_attach_recv(void *handle, void (*callback)(void *), void *id) { + struct lwip_socket *s = (struct lwip_socket *)handle; + s->recv_cb = callback; + s->recv_data = id; } From 106e459a6401ad947b61197ab3b80cae6a5cebcc Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 06:32:02 -0500 Subject: [PATCH 02/33] Adopt mbed style doxygen comments per @0xc0170 --- net/NetworkSocketAPI/NetworkInterface.h | 208 ++++++++++++------------ net/NetworkSocketAPI/Socket.h | 36 ++-- net/NetworkSocketAPI/SocketAddress.h | 30 ++-- net/NetworkSocketAPI/TCPServer.h | 28 ++-- net/NetworkSocketAPI/TCPSocket.h | 55 +++---- net/NetworkSocketAPI/UDPSocket.h | 49 +++--- net/NetworkSocketAPI/WiFiInterface.h | 16 +- 7 files changed, 209 insertions(+), 213 deletions(-) diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index 654e3a5e55..28ad41e28e 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -20,9 +20,8 @@ #include "mbed.h" #include "SocketAddress.h" -/** +/** Enum of standardized error codes * @enum ns_error_t - * @brief enum of standardized error codes */ enum nsapi_error_t { NSAPI_ERROR_WOULD_BLOCK = -3001, /*!< no data is not available but call is non-blocking */ @@ -37,16 +36,15 @@ enum nsapi_error_t { NSAPI_ERROR_DEVICE_ERROR = -3010, /*!< failure interfacing with the network procesor */ }; -/** +/** Enum of available options * @enum ns_opt_t - * @brief enum of available options */ enum ns_opt_t { }; /** Enum of socket protocols -/enum protocol_t -*/ + * @enum protocol_t + */ enum nsapi_protocol_t { NSAPI_TCP, /*!< Socket is of TCP type */ NSAPI_UDP, /*!< Socket is of UDP type */ @@ -62,27 +60,27 @@ public: virtual ~NetworkInterface() {}; /** Get the internally stored IP address - /return IP address of the interface or null if not yet connected - */ + * @return IP address of the interface or null if not yet connected + */ virtual const char *get_ip_address() = 0; /** Get the internally stored MAC address - /return MAC address of the interface - */ + * @return MAC address of the interface + */ virtual const char *get_mac_address() = 0; /** Get the current status of the interface - /return true if connected - */ + * @return true if connected + */ virtual bool is_connected() { return get_ip_address() != NULL; } /** Looks up the specified host's IP address - /param name Hostname to lookup - /param dest Destination for IP address, must have space for SocketAddress::IP_SIZE - /return 0 on success, negative on failure - */ + * @param name Hostname to lookup + * @param dest Destination for IP address, must have space for SocketAddress::IP_SIZE + * @return 0 on success, negative on failure + */ virtual int gethostbyname(const char *name, char *dest); protected: @@ -92,143 +90,143 @@ protected: friend class TCPServer; /** Create a socket - /param proto The type of socket to open, TCP or UDP - /return The alocated socket or null on failure - */ + * @param proto The type of socket to open, TCP or UDP + * @return The alocated socket or null on failure + */ virtual void *socket_create(nsapi_protocol_t proto) = 0; /** Destroy a socket - /param socket Previously allocated socket - */ + * @param socket Previously allocated socket + */ virtual void socket_destroy(void *handle) = 0; /** Set socket options - \param handle Socket handle - \param optname Option ID - \param optval Option value - \param optlen Length of the option value - \return 0 on success, negative on failure - */ + * @param handle Socket handle + * @param optname Option ID + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative on failure + */ virtual int socket_set_option(void *handle, int optname, const void *optval, unsigned int optlen) = 0; /** Get socket options - \param handle Socket handle - \param optname Option ID - \param optval Buffer pointer where to write the option value - \param optlen Length of the option value - \return 0 on success, negative on failure - */ + * @param handle Socket handle + * @param optname Option ID + * @param optval Buffer pointer where to write the option value + * @param optlen Length of the option value + * @return 0 on success, negative on failure + */ virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen) = 0; /** Bind a server socket to a specific port - \param handle Socket handle - \param port The port to listen for incoming connections on - \return 0 on success, negative on failure. - */ + * @param handle Socket handle + * @param port The port to listen for incoming connections on + * @return 0 on success, negative on failure. + */ virtual int socket_bind(void *handle, int port) = 0; /** Start listening for incoming connections - \param handle Socket handle - \param backlog Number of pending connections that can be queued up at any - one time [Default: 1] - \return 0 on success, negative on failure - */ + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return 0 on success, negative on failure + */ virtual int socket_listen(void *handle, int backlog) = 0; /** Connects this TCP socket to the server - \param handle Socket handle - \param address SocketAddress to connect to - \return 0 on success, negative on failure - */ + * @param handle Socket handle + * @param address SocketAddress to connect to + * @return 0 on success, negative on failure + */ virtual int socket_connect(void *handle, const SocketAddress &address) = 0; /** Check if the socket is connected - \param handle Socket handle - \return true if connected, false otherwise - */ + * @param handle Socket handle + * @return true if connected, false otherwise + */ virtual bool socket_is_connected(void *handle) = 0; /** Accept a new connection. - \param handle Socket handle - \param socket A TCPSocket instance that will handle the incoming connection. - \return 0 on success, negative on failure. - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param socket A TCPSocket instance that will handle the incoming connection. + * @return 0 on success, negative on failure. + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_accept(void *handle, void **connection) = 0; /** Send data to the remote host - \param handle Socket handle - \param data The buffer to send to the host - \param size The length of the buffer to send - \return Number of written bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param data The buffer to send to the host + * @param size The length of the buffer to send + * @return Number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_send(void *handle, const void *data, unsigned size) = 0; /** Receive data from the remote host - \param handle Socket handle - \param data The buffer in which to store the data received from the host - \param size The maximum length of the buffer - \return Number of received bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param data The buffer in which to store the data received from the host + * @param size The maximum length of the buffer + * @return Number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_recv(void *handle, void *data, unsigned size) = 0; /** Send a packet to a remote endpoint - \param handle Socket handle - \param address The remote SocketAddress - \param data The packet to be sent - \param size The length of the packet to be sent - \return the number of written bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param address The remote SocketAddress + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return the number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size) = 0; /** Receive a packet from a remote endpoint - \param handle Socket handle - \param address Destination for the remote SocketAddress or null - \param buffer The buffer for storing the incoming packet data - If a packet is too long to fit in the supplied buffer, - excess bytes are discarded - \param size The length of the buffer - \return the number of received bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param address Destination for the remote SocketAddress or null + * @param buffer The buffer for storing the incoming packet data + * If a packet is too long to fit in the supplied buffer, + * excess bytes are discarded + * @param size The length of the buffer + * @return the number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size) = 0; /** Close the socket - \param handle Socket handle - \param shutdown free the left-over data in message queues - */ + * @param handle Socket handle + * @param shutdown free the left-over data in message queues + */ virtual int socket_close(void *handle, bool shutdown) = 0; /** Register a callback on when a new connection is ready - \param handle Socket handle - \param callback Function to call when accept will succeed, may be called in - interrupt context. - \param id Argument to pass to callback - */ + * @param handle Socket handle + * @param callback Function to call when accept will succeed, may be called in + * interrupt context. + * @param id Argument to pass to callback + */ virtual void socket_attach_accept(void *handle, void (*callback)(void *), void *id) = 0; /** Register a callback on when send is ready - \param handle Socket handle - \param callback Function to call when accept will succeed, may be called in - interrupt context. - \param id Argument to pass to callback - */ + * @param handle Socket handle + * @param callback Function to call when accept will succeed, may be called in + * interrupt context. + * @param id Argument to pass to callback + */ virtual void socket_attach_send(void *handle, void (*callback)(void *), void *id) = 0; /** Register a callback on when recv is ready - \param handle Socket handle - \param callback Function to call when accept will succeed, may be called in - interrupt context. - \param id Argument to pass to callback - */ + * @param handle Socket handle + * @param callback Function to call when accept will succeed, may be called in + * interrupt context. + * @param id Argument to pass to callback + */ virtual void socket_attach_recv(void *handle, void (*callback)(void *), void *id) = 0; }; diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index 6fb8d6127f..cb359e7040 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -29,34 +29,34 @@ public: virtual ~Socket(); /** Set blocking or non-blocking mode of the socket - \param blocking true for blocking mode, false for non-blocking mode. - */ + * @param blocking true for blocking mode, false for non-blocking mode. + */ void set_blocking(bool blocking); /** Set timeout on a socket operation if blocking behaviour is enabled - \param timeout timeout in ms - */ + * @param timeout timeout in ms + */ void set_timeout(unsigned int timeout); - /** Set socket options - \param optname Option ID - \param optval Option value - \param optlen Length of the option value - \return 0 on success, negative on failure - */ + /* Set socket options + * @param optname Option ID + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative on failure + */ int set_option(int optname, const void *optval, unsigned optlen); - /** Get socket options - \param optname Option ID - \param optval Buffer pointer where to write the option value - \param optlen Length of the option value - \return 0 on success, negative on failure - */ + /* Get socket options + * @param optname Option ID + * @param optval Buffer pointer where to write the option value + * @param optlen Length of the option value + * @return 0 on success, negative on failure + */ int get_option(int optname, void *optval, unsigned *optlen); /** Close the socket - \param shutdown free the left-over data in message queues - */ + * @param shutdown free the left-over data in message queues + */ int close(bool shutdown=true); protected: diff --git a/net/NetworkSocketAPI/SocketAddress.h b/net/NetworkSocketAPI/SocketAddress.h index e6fedc2496..44e55bc9d1 100644 --- a/net/NetworkSocketAPI/SocketAddress.h +++ b/net/NetworkSocketAPI/SocketAddress.h @@ -36,42 +36,42 @@ class NetworkInterface; class SocketAddress { public: /** SocketAddress construction using DNS resolution - /param iface NetworkInterface to use for DNS resolution - /param addr Null-terminated hostname that will be resolved - /param port 16-bit port - /note on failure, IP address and port will be set to null - */ + * @param iface NetworkInterface to use for DNS resolution + * @param addr Null-terminated hostname that will be resolved + * @param port 16-bit port + * @note on failure, IP address and port will be set to null + */ SocketAddress(NetworkInterface *iface, const char *addr, uint16_t port = 0); /** SocketAddress construction - /param addr Null-terminated IP address - /param port 16-bit port - /note on failure, IP address and port will be set to null - */ + * @param addr Null-terminated IP address + * @param port 16-bit port + * @note on failure, IP address and port will be set to null + */ SocketAddress(const char *addr = 0, uint16_t port = 0); /** SocketAddress construction - /param addr SocketAddress to copy - */ + * @param addr SocketAddress to copy + */ SocketAddress(const SocketAddress &addr); /** Set the IP address - \param addr Null-terminated string representing the IP address + * @param addr Null-terminated string representing the IP address */ void set_ip_address(const char *addr); /** Set the port - \param port 16-bit port + * @param port 16-bit port */ void set_port(uint16_t port); /** Get the IP address - \return The string representation of the IP Address + * @return The string representation of the IP Address */ const char *get_ip_address() const; /** Get the port - \return The 16-bit port + * @return The 16-bit port */ uint16_t get_port(void) const; diff --git a/net/NetworkSocketAPI/TCPServer.h b/net/NetworkSocketAPI/TCPServer.h index 697104c66f..0072ec3f1c 100644 --- a/net/NetworkSocketAPI/TCPServer.h +++ b/net/NetworkSocketAPI/TCPServer.h @@ -26,33 +26,33 @@ class TCPServer : public Socket { public: /** TCP Server lifetime - */ + */ TCPServer(NetworkInterface *iface); virtual ~TCPServer(); /** Bind a socket to a specific port - \param port The port to listen for incoming connections on - \return 0 on success, negative on failure - */ + * @param port The port to listen for incoming connections on + * @return 0 on success, negative on failure + */ int bind(uint16_t port); /** Start listening for incoming connections - \param backlog Number of pending connections that can be queued up at any - one time [Default: 1] - \return 0 on success, negative on failure - */ + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return 0 on success, negative on failure + */ int listen(int backlog=1); /** Accept a new connection. - \param socket A TCPSocket instance that will handle the incoming connection. - \return 0 on success, negative on failure. - */ + * @param socket A TCPSocket instance that will handle the incoming connection. + * @return 0 on success, negative on failure. + */ int accept(TCPSocket *connection); /** Register a callback on when a new connection is ready - \param callback Function to call when accept will succeed, may be called in - interrupt context. - */ + * @param callback Function to call when accept will succeed, may be called in + * interrupt context. + */ void attach_accept(FunctionPointer callback); template diff --git a/net/NetworkSocketAPI/TCPSocket.h b/net/NetworkSocketAPI/TCPSocket.h index 36693c387f..b4f7917424 100644 --- a/net/NetworkSocketAPI/TCPSocket.h +++ b/net/NetworkSocketAPI/TCPSocket.h @@ -20,53 +20,52 @@ #include "Socket.h" #include "NetworkInterface.h" -/** -TCP socket connection -*/ +/** TCP socket connection + */ class TCPSocket : public Socket { public: /** TCP socket lifetime - */ + */ TCPSocket(NetworkInterface *iface); virtual ~TCPSocket(); /** Connects this TCP socket to the server - \param host The host to connect to. It can either be an IP Address - or a hostname that will be resolved with DNS - \param port The host's port to connect to - \return 0 on success, negative on failure - */ + * @param host The host to connect to. It can either be an IP Address + * or a hostname that will be resolved with DNS + * @param port The host's port to connect to + * @return 0 on success, negative on failure + */ int connect(const char *host, uint16_t port); /** Connects this TCP socket to the server - \param address SocketAddress to connect to - \return 0 on success, negative on failure - */ + * @param address SocketAddress to connect to + * @return 0 on success, negative on failure + */ int connect(const SocketAddress &address); /** Check if the socket is connected - \return true if connected, false otherwise - */ + * @return true if connected, false otherwise + */ bool is_connected(); /** Send data to the remote host - \param data The buffer to send to the host - \param size The length of the buffer to send - \return Number of written bytes on success, negative on failure - */ + * @param data The buffer to send to the host + * @param size The length of the buffer to send + * @return Number of written bytes on success, negative on failure + */ int send(const void *data, unsigned size); /** Receive data from the remote host - \param data The buffer in which to store the data received from the host - \param size The maximum length of the buffer - \return Number of received bytes on success, negative on failure - */ + * @param data The buffer in which to store the data received from the host + * @param size The maximum length of the buffer + * @return Number of received bytes on success, negative on failure + */ int recv(void *data, unsigned size); /** Register a callback on when send is ready - \param callback Function to call when send will succeed, may be called in - interrupt context. - */ + * @param callback Function to call when send will succeed, may be called in + * interrupt context. + */ void attach_send(FunctionPointer callback); template @@ -75,9 +74,9 @@ public: } /** Register a callback on when recv is ready - \param callback Function to call when recv will succeed, may be called in - interrupt context. - */ + * @param callback Function to call when recv will succeed, may be called in + * interrupt context. + */ void attach_recv(FunctionPointer callback); template diff --git a/net/NetworkSocketAPI/UDPSocket.h b/net/NetworkSocketAPI/UDPSocket.h index 9d1ab06112..1614f8f920 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -20,44 +20,43 @@ #include "Socket.h" #include "NetworkInterface.h" -/** -UDP Socket -*/ +/** UDP Socket + */ class UDPSocket : public Socket { public: /** UDPSocket lifetime - */ + */ UDPSocket(NetworkInterface *iface); virtual ~UDPSocket(); /** Bind a UDP Server Socket to a specific port - \param port The port to listen for incoming connections on - \return 0 on success, negative on failure. - */ + * @param port The port to listen for incoming connections on + * @return 0 on success, negative on failure. + */ int bind(uint16_t port); /** Send a packet to a remote endpoint - \param address The remote SocketAddress - \param data The packet to be sent - \param size The length of the packet to be sent - \return the number of written bytes on success, negative on failure - */ + * @param address The remote SocketAddress + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return The number of written bytes on success, negative on failure + */ int sendto(const SocketAddress &address, const void *data, unsigned size); /** Receive a packet from a remote endpoint - \param address Destination for the remote SocketAddress or null - \param buffer The buffer for storing the incoming packet data - If a packet is too long to fit in the supplied buffer, - excess bytes are discarded - \param size The length of the buffer - \return the number of received bytes on success, negative on failure - */ + * @param address Destination for the remote SocketAddress or null + * @param buffer The buffer for storing the incoming packet data + * If a packet is too long to fit in the supplied buffer, + * excess bytes are discarded + * @param size The length of the buffer + * @return The number of received bytes on success, negative on failure + */ int recvfrom(SocketAddress *address, void *buffer, unsigned size); /** Register a callback on when send is ready - \param callback Function to call when send will succeed, may be called in - interrupt context. - */ + * @param callback Function to call when send will succeed, may be called in + * interrupt context. + */ void attach_send(FunctionPointer callback); template @@ -66,9 +65,9 @@ public: } /** Register a callback on when recv is ready - \param callback Function to call when recv will succeed, may be called in - interrupt context. - */ + * @param callback Function to call when recv will succeed, may be called in + * interrupt context. + */ void attach_recv(FunctionPointer callback); template diff --git a/net/NetworkSocketAPI/WiFiInterface.h b/net/NetworkSocketAPI/WiFiInterface.h index 541a6a8fa8..21fa397a66 100644 --- a/net/NetworkSocketAPI/WiFiInterface.h +++ b/net/NetworkSocketAPI/WiFiInterface.h @@ -20,7 +20,7 @@ #include "NetworkInterface.h" /** Enum for WiFi encryption types -*/ + */ enum nsapi_security_t { NSAPI_SECURITY_NONE = 0, /*!< open access point */ NSAPI_SECURITY_WEP, /*!< phrase conforms to WEP */ @@ -35,16 +35,16 @@ class WiFiInterface : public NetworkInterface { public: /** Start the interface - /param ssid Name of the network to connect to - /param pass Security passphrase to connect to the network - /param security Type of encryption for connection - /return 0 on success, negative on failure - */ + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection + * @return 0 on success, negative on failure + */ virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE) = 0; /** Stop the interface - /return 0 on success, negative on failure - */ + * @return 0 on success, negative on failure + */ virtual int disconnect() = 0; }; From 71efccb1e8e5475865e265f87fa01b1ba6177e67 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 07:08:27 -0500 Subject: [PATCH 03/33] Add open call as alternative to passing NetworkInterface at construction Pros - Allows memory to be statically allocated - Avoids issues with Thread creation before entering main - Matches existing APIs such as FunctionPointer and Ticker Cons - Does not enforce passing a NetworkInterface --- net/NetworkSocketAPI/Socket.cpp | 44 +++++++++++++++++------------- net/NetworkSocketAPI/Socket.h | 8 +++++- net/NetworkSocketAPI/TCPServer.cpp | 20 ++++++++++---- net/NetworkSocketAPI/TCPServer.h | 6 ++++ net/NetworkSocketAPI/TCPSocket.cpp | 13 +++++++-- net/NetworkSocketAPI/TCPSocket.h | 6 ++++ net/NetworkSocketAPI/UDPSocket.cpp | 13 +++++++-- net/NetworkSocketAPI/UDPSocket.h | 6 ++++ 8 files changed, 87 insertions(+), 29 deletions(-) diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index 7f90895ede..e52ba47793 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -16,12 +16,12 @@ #include "Socket.h" -Socket::Socket(NetworkInterface *iface, nsapi_protocol_t proto) - : _iface(iface) +Socket::Socket() + : _iface(0) + , _socket(0) , _blocking(true) , _timeout(0) { - _socket = _iface->socket_create(proto); } Socket::~Socket() @@ -31,6 +31,28 @@ Socket::~Socket() } } +int Socket::open(NetworkInterface *iface, nsapi_protocol_t proto) +{ + _iface = iface; + _socket = _iface->socket_create(proto); +} + +int Socket::close(bool shutdown) +{ + if (!_socket) { + return 0; + } + + int err = _iface->socket_close(_socket, shutdown); + if (!err) { + void *socket = _socket; + _socket = 0; + _iface->socket_destroy(socket); + } + + return err; +} + void Socket::set_blocking(bool blocking) { _blocking = blocking; @@ -59,22 +81,6 @@ int Socket::get_option(int optname, void *optval, unsigned int *optlen) return _iface->socket_get_option(_socket, optname, optval, optlen); } -int Socket::close(bool shutdown) -{ - if (!_socket) { - return 0; - } - - int err = _iface->socket_close(_socket, shutdown); - if (!err) { - void *socket = _socket; - _socket = 0; - _iface->socket_destroy(socket); - } - - return err; -} - void Socket::thunk(void *p) { FunctionPointer *fptr = (FunctionPointer *)p; diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index cb359e7040..ebae4440e0 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -27,6 +27,11 @@ public: /** Socket lifetime */ virtual ~Socket(); + + /** Open the socket + * @param iface Interface to open socket on + */ + virtual int open(NetworkInterface *iface) = 0; /** Set blocking or non-blocking mode of the socket * @param blocking true for blocking mode, false for non-blocking mode. @@ -60,7 +65,8 @@ public: int close(bool shutdown=true); protected: - Socket(NetworkInterface *iface, nsapi_protocol_t proto); + Socket(); + int open(NetworkInterface *iface, nsapi_protocol_t proto); static void thunk(void *); diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index aa3623caa0..c3e9dd6c18 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -17,11 +17,20 @@ #include "TCPServer.h" #include "Timer.h" -TCPServer::TCPServer(NetworkInterface *iface) - : Socket(iface, NSAPI_TCP) +TCPServer::TCPServer() { } +TCPServer::TCPServer(NetworkInterface *iface) +{ + open(iface); +} + +int TCPServer::open(NetworkInterface *iface) +{ + return Socket::open(iface, NSAPI_TCP); +} + int TCPServer::bind(uint16_t port) { if (!_socket) { @@ -45,15 +54,16 @@ int TCPServer::accept(TCPSocket *connection) mbed::Timer timer; timer.start(); - void *socket = connection->_socket; - connection->_socket = 0; - _iface->socket_destroy(socket); + if (connection->_socket) { + connection->close(); + } while (true) { if (!_socket) { return NSAPI_ERROR_NO_SOCKET; } + void *socket; int err = _iface->socket_accept(_socket, &socket); if (err > 0) { diff --git a/net/NetworkSocketAPI/TCPServer.h b/net/NetworkSocketAPI/TCPServer.h index 0072ec3f1c..8d52c06bd1 100644 --- a/net/NetworkSocketAPI/TCPServer.h +++ b/net/NetworkSocketAPI/TCPServer.h @@ -27,8 +27,14 @@ class TCPServer : public Socket { public: /** TCP Server lifetime */ + TCPServer(); TCPServer(NetworkInterface *iface); virtual ~TCPServer(); + + /** Open the socket + * @param iface Interface to open socket on + */ + virtual int open(NetworkInterface *iface); /** Bind a socket to a specific port * @param port The port to listen for incoming connections on diff --git a/net/NetworkSocketAPI/TCPSocket.cpp b/net/NetworkSocketAPI/TCPSocket.cpp index 13bd8b6c0a..84a86c1ff7 100644 --- a/net/NetworkSocketAPI/TCPSocket.cpp +++ b/net/NetworkSocketAPI/TCPSocket.cpp @@ -17,11 +17,20 @@ #include "TCPSocket.h" #include "Timer.h" -TCPSocket::TCPSocket(NetworkInterface *iface) - : Socket(iface, NSAPI_TCP) +TCPSocket::TCPSocket() { } +TCPSocket::TCPSocket(NetworkInterface *iface) +{ + open(iface); +} + +int TCPSocket::open(NetworkInterface *iface) +{ + return Socket::open(iface, NSAPI_TCP); +} + int TCPSocket::connect(const SocketAddress &addr) { if (!_socket) { diff --git a/net/NetworkSocketAPI/TCPSocket.h b/net/NetworkSocketAPI/TCPSocket.h index b4f7917424..31085919eb 100644 --- a/net/NetworkSocketAPI/TCPSocket.h +++ b/net/NetworkSocketAPI/TCPSocket.h @@ -26,8 +26,14 @@ class TCPSocket : public Socket { public: /** TCP socket lifetime */ + TCPSocket(); TCPSocket(NetworkInterface *iface); virtual ~TCPSocket(); + + /** Open the socket + * @param iface Interface to open socket on + */ + virtual int open(NetworkInterface *iface); /** Connects this TCP socket to the server * @param host The host to connect to. It can either be an IP Address diff --git a/net/NetworkSocketAPI/UDPSocket.cpp b/net/NetworkSocketAPI/UDPSocket.cpp index 90ed74ad39..3025cd93c4 100644 --- a/net/NetworkSocketAPI/UDPSocket.cpp +++ b/net/NetworkSocketAPI/UDPSocket.cpp @@ -17,11 +17,20 @@ #include "UDPSocket.h" #include "Timer.h" -UDPSocket::UDPSocket(NetworkInterface *iface) - : Socket(iface, NSAPI_UDP) +UDPSocket::UDPSocket() { } +UDPSocket::UDPSocket(NetworkInterface *iface) +{ + open(iface); +} + +int UDPSocket::open(NetworkInterface *iface) +{ + return Socket::open(iface, NSAPI_UDP); +} + int UDPSocket::bind(uint16_t port) { if (!_socket) { diff --git a/net/NetworkSocketAPI/UDPSocket.h b/net/NetworkSocketAPI/UDPSocket.h index 1614f8f920..8564713c53 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -26,8 +26,14 @@ class UDPSocket : public Socket { public: /** UDPSocket lifetime */ + UDPSocket(); UDPSocket(NetworkInterface *iface); virtual ~UDPSocket(); + + /** Open the socket + * @param iface Interface to open socket on + */ + virtual int open(NetworkInterface *iface); /** Bind a UDP Server Socket to a specific port * @param port The port to listen for incoming connections on From c3eec0322ba124debb84e54f20c9e4ab617c138c Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 07:13:14 -0500 Subject: [PATCH 04/33] Remove shutdown parameter from close call Pros - Simplifies interface - Easier base implementation Cons - May need shutdown functionality, in this case shutdown can be added as another function in the future --- net/ESP8266Interface/ESP8266Interface.cpp | 2 +- net/ESP8266Interface/ESP8266Interface.h | 3 +-- net/LWIPInterface/LWIPInterface.cpp | 6 +----- net/LWIPInterface/LWIPInterface.h | 3 +-- net/NetworkSocketAPI/NetworkInterface.h | 3 +-- net/NetworkSocketAPI/Socket.cpp | 6 +++--- net/NetworkSocketAPI/Socket.h | 3 +-- 7 files changed, 9 insertions(+), 17 deletions(-) diff --git a/net/ESP8266Interface/ESP8266Interface.cpp b/net/ESP8266Interface/ESP8266Interface.cpp index f675d7618e..b91f29c35c 100644 --- a/net/ESP8266Interface/ESP8266Interface.cpp +++ b/net/ESP8266Interface/ESP8266Interface.cpp @@ -207,7 +207,7 @@ int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *d return socket_recv(socket, data, size); } -int ESP8266Interface::socket_close(void *handle, bool shutdown) +int ESP8266Interface::socket_close(void *handle) { struct esp8266_socket *socket = (struct esp8266_socket *)handle; _esp.setTimeout(ESP8266_MISC_TIMEOUT); diff --git a/net/ESP8266Interface/ESP8266Interface.h b/net/ESP8266Interface/ESP8266Interface.h index 88ce4dcf17..ee5c3a8c9e 100644 --- a/net/ESP8266Interface/ESP8266Interface.h +++ b/net/ESP8266Interface/ESP8266Interface.h @@ -174,9 +174,8 @@ protected: /** Close the socket \param handle Socket handle - \param shutdown free the left-over data in message queues */ - virtual int socket_close(void *handle, bool shutdown); + virtual int socket_close(void *handle); /** Register a callback on when a new connection is ready \param handle Socket handle diff --git a/net/LWIPInterface/LWIPInterface.cpp b/net/LWIPInterface/LWIPInterface.cpp index a39ff0666f..c954059d24 100644 --- a/net/LWIPInterface/LWIPInterface.cpp +++ b/net/LWIPInterface/LWIPInterface.cpp @@ -480,7 +480,7 @@ int LWIPInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *buf, return copied; } -int LWIPInterface::socket_close(void *handle, bool shutdown) +int LWIPInterface::socket_close(void *handle) { struct lwip_socket *s = (struct lwip_socket *)handle; @@ -490,10 +490,6 @@ int LWIPInterface::socket_close(void *handle, bool shutdown) return 0; case NSAPI_TCP: - if (shutdown) { - tcp_abort(s->tcp); - } - if (tcp_close(s->tcp)) { return NSAPI_ERROR_DEVICE_ERROR; } diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index 055b7edda2..cf0fb45daf 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -161,9 +161,8 @@ protected: /** Close the socket \param handle Socket handle - \param shutdown free the left-over data in message queues */ - virtual int socket_close(void *handle, bool shutdown); + virtual int socket_close(void *handle); /** Register a callback on when a new connection is ready \param handle Socket handle diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index 28ad41e28e..26cd98cbac 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -201,9 +201,8 @@ protected: /** Close the socket * @param handle Socket handle - * @param shutdown free the left-over data in message queues */ - virtual int socket_close(void *handle, bool shutdown) = 0; + virtual int socket_close(void *handle) = 0; /** Register a callback on when a new connection is ready * @param handle Socket handle diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index e52ba47793..53d66a635b 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -27,7 +27,7 @@ Socket::Socket() Socket::~Socket() { if (_socket) { - close(false); + close(); } } @@ -37,13 +37,13 @@ int Socket::open(NetworkInterface *iface, nsapi_protocol_t proto) _socket = _iface->socket_create(proto); } -int Socket::close(bool shutdown) +int Socket::close() { if (!_socket) { return 0; } - int err = _iface->socket_close(_socket, shutdown); + int err = _iface->socket_close(_socket); if (!err) { void *socket = _socket; _socket = 0; diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index ebae4440e0..376e73a41c 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -60,9 +60,8 @@ public: int get_option(int optname, void *optval, unsigned *optlen); /** Close the socket - * @param shutdown free the left-over data in message queues */ - int close(bool shutdown=true); + int close(); protected: Socket(); From c33d246fa6f70e2f1f25f51550128561cef9de9e Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 11:36:13 -0500 Subject: [PATCH 05/33] Move to single state-change interrupt Pros - Easier to implement - More similar to SIGIO in BDS sockets Cons - Less information, but this information had a high risk of being faulty/spurious --- net/ESP8266Interface/ESP8266Interface.cpp | 10 +----- net/ESP8266Interface/ESP8266Interface.h | 30 +++++------------- net/LWIPInterface/LWIPInterface.cpp | 38 ++++++++--------------- net/LWIPInterface/LWIPInterface.h | 30 +++++------------- net/NetworkSocketAPI/NetworkInterface.h | 26 +++------------- net/NetworkSocketAPI/Socket.cpp | 14 +++++++-- net/NetworkSocketAPI/Socket.h | 14 +++++++++ net/NetworkSocketAPI/TCPServer.cpp | 19 ------------ net/NetworkSocketAPI/TCPServer.h | 14 --------- net/NetworkSocketAPI/TCPSocket.cpp | 34 -------------------- net/NetworkSocketAPI/TCPSocket.h | 26 ---------------- net/NetworkSocketAPI/UDPSocket.cpp | 32 ------------------- net/NetworkSocketAPI/UDPSocket.h | 27 ---------------- 13 files changed, 58 insertions(+), 256 deletions(-) diff --git a/net/ESP8266Interface/ESP8266Interface.cpp b/net/ESP8266Interface/ESP8266Interface.cpp index b91f29c35c..14ddc48421 100644 --- a/net/ESP8266Interface/ESP8266Interface.cpp +++ b/net/ESP8266Interface/ESP8266Interface.cpp @@ -219,14 +219,6 @@ int ESP8266Interface::socket_close(void *handle) return 0; } -void ESP8266Interface::socket_attach_accept(void *handle, void (*callback)(void *), void *id) -{ -} - -void ESP8266Interface::socket_attach_send(void *handle, void (*callback)(void *), void *id) -{ -} - -void ESP8266Interface::socket_attach_recv(void *handle, void (*callback)(void *), void *id) +void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), void *data) { } diff --git a/net/ESP8266Interface/ESP8266Interface.h b/net/ESP8266Interface/ESP8266Interface.h index ee5c3a8c9e..0613daa12d 100644 --- a/net/ESP8266Interface/ESP8266Interface.h +++ b/net/ESP8266Interface/ESP8266Interface.h @@ -177,29 +177,13 @@ protected: */ virtual int socket_close(void *handle); - /** Register a callback on when a new connection is ready - \param handle Socket handle - \param callback Function to call when accept will succeed, may be called in - interrupt context. - \param id Argument to pass to callback - */ - virtual void socket_attach_accept(void *handle, void (*callback)(void *), void *id); - - /** Register a callback on when send is ready - \param handle Socket handle - \param callback Function to call when accept will succeed, may be called in - interrupt context. - \param id Argument to pass to callback - */ - virtual void socket_attach_send(void *handle, void (*callback)(void *), void *id); - - /** Register a callback on when recv is ready - \param handle Socket handle - \param callback Function to call when accept will succeed, may be called in - interrupt context. - \param id Argument to pass to callback - */ - virtual void socket_attach_recv(void *handle, void (*callback)(void *), void *id); + /** Register a callback on state change of the socket + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + * @note Callback may be called in an interrupt context. + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); private: ESP8266 _esp; diff --git a/net/LWIPInterface/LWIPInterface.cpp b/net/LWIPInterface/LWIPInterface.cpp index c954059d24..b960aa2ac2 100644 --- a/net/LWIPInterface/LWIPInterface.cpp +++ b/net/LWIPInterface/LWIPInterface.cpp @@ -142,8 +142,8 @@ struct lwip_socket { struct pbuf *rx_chain; Semaphore *sem; - void (*send_cb)(void *); void *send_data; - void (*recv_cb)(void *); void *recv_data; + void (*callback)(void *); + void *data; }; static void udp_recv_irq( @@ -310,8 +310,8 @@ static struct pbuf *pbuf_consume(struct pbuf *p, size_t consume, bool free_parti static err_t tcp_sent_irq(void *handle, struct tcp_pcb *tpcb, uint16_t len) { struct lwip_socket *s = (struct lwip_socket *)handle; - if (s->send_cb) { - s->send_cb(s->send_data); + if (s->callback) { + s->callback(s->data); } return ERR_OK; @@ -357,8 +357,8 @@ static err_t tcp_recv_irq(void *handle, struct tcp_pcb *tpcb, struct pbuf *p, er } __enable_irq(); - if (s->recv_cb) { - s->recv_cb(s->recv_data); + if (s->callback) { + s->callback(s->data); } return ERR_OK; @@ -406,8 +406,8 @@ int LWIPInterface::socket_sendto(void *handle, const SocketAddress &addr, const return NSAPI_ERROR_DEVICE_ERROR; } - if (s->send_cb) { - s->send_cb(s->send_data); + if (s->callback) { + s->callback(s->data); } return size; @@ -432,8 +432,8 @@ static void udp_recv_irq( } __enable_irq(); - if (s->recv_cb) { - s->recv_cb(s->recv_data); + if (s->callback) { + s->callback(s->data); } } @@ -500,21 +500,9 @@ int LWIPInterface::socket_close(void *handle) return NSAPI_ERROR_DEVICE_ERROR; } -void LWIPInterface::socket_attach_accept(void *handle, void (*callback)(void *), void *id) -{ -} - -void LWIPInterface::socket_attach_send(void *handle, void (*callback)(void *), void *id) +void LWIPInterface::socket_attach(void *handle, void (*callback)(void *), void *data) { struct lwip_socket *s = (struct lwip_socket *)handle; - s->send_cb = callback; - s->send_data = id; + s->callback = callback; + s->data = data; } - -void LWIPInterface::socket_attach_recv(void *handle, void (*callback)(void *), void *id) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - s->recv_cb = callback; - s->recv_data = id; -} - diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index cf0fb45daf..19b769dfd6 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -164,29 +164,13 @@ protected: */ virtual int socket_close(void *handle); - /** Register a callback on when a new connection is ready - \param handle Socket handle - \param callback Function to call when accept will succeed, may be called in - interrupt context. - \param id Argument to pass to callback - */ - virtual void socket_attach_accept(void *handle, void (*callback)(void *), void *id); - - /** Register a callback on when send is ready - \param handle Socket handle - \param callback Function to call when accept will succeed, may be called in - interrupt context. - \param id Argument to pass to callback - */ - virtual void socket_attach_send(void *handle, void (*callback)(void *), void *id); - - /** Register a callback on when recv is ready - \param handle Socket handle - \param callback Function to call when accept will succeed, may be called in - interrupt context. - \param id Argument to pass to callback - */ - virtual void socket_attach_recv(void *handle, void (*callback)(void *), void *id); + /** Register a callback on state change of the socket + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + * @note Callback may be called in an interrupt context. + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); }; #endif diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index 26cd98cbac..a3cbbb889b 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -204,29 +204,13 @@ protected: */ virtual int socket_close(void *handle) = 0; - /** Register a callback on when a new connection is ready + /** Register a callback on state change of the socket * @param handle Socket handle - * @param callback Function to call when accept will succeed, may be called in - * interrupt context. - * @param id Argument to pass to callback + * @param callback Function to call on state change + * @param data Argument to pass to callback + * @note Callback may be called in an interrupt context. */ - virtual void socket_attach_accept(void *handle, void (*callback)(void *), void *id) = 0; - - /** Register a callback on when send is ready - * @param handle Socket handle - * @param callback Function to call when accept will succeed, may be called in - * interrupt context. - * @param id Argument to pass to callback - */ - virtual void socket_attach_send(void *handle, void (*callback)(void *), void *id) = 0; - - /** Register a callback on when recv is ready - * @param handle Socket handle - * @param callback Function to call when accept will succeed, may be called in - * interrupt context. - * @param id Argument to pass to callback - */ - virtual void socket_attach_recv(void *handle, void (*callback)(void *), void *id) = 0; + virtual void socket_attach(void *handle, void (*callback)(void *), void *data) = 0; }; #endif diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index 53d66a635b..a26d9984f9 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -35,6 +35,7 @@ int Socket::open(NetworkInterface *iface, nsapi_protocol_t proto) { _iface = iface; _socket = _iface->socket_create(proto); + _iface->socket_attach(_socket, &Socket::thunk, this); } int Socket::close() @@ -81,8 +82,15 @@ int Socket::get_option(int optname, void *optval, unsigned int *optlen) return _iface->socket_get_option(_socket, optname, optval, optlen); } -void Socket::thunk(void *p) +void Socket::thunk(void *data) { - FunctionPointer *fptr = (FunctionPointer *)p; - (*fptr)(); + Socket *self = (Socket *)data; + if (self->_callback) { + self->_callback(); + } +} + +void Socket::attach(FunctionPointer callback) +{ + _callback = callback; } diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index 376e73a41c..e8b96dd8c5 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -63,6 +63,19 @@ public: */ int close(); + /** Register a callback on state change of the socket + * @param callback Function to call on state change + * @note Callback may be called in an interrupt context. + * The callback should not perform long operations + * such as recv or send calls. + */ + void attach(FunctionPointer callback); + + template + void attach(T *tptr, M mptr) { + attach(FunctionPointer(tptr, mptr)); + } + protected: Socket(); int open(NetworkInterface *iface, nsapi_protocol_t proto); @@ -73,6 +86,7 @@ protected: void *_socket; bool _blocking; unsigned _timeout; + FunctionPointer _callback; }; #endif diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index c3e9dd6c18..1430adfa4c 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -76,22 +76,3 @@ int TCPServer::accept(TCPSocket *connection) } } } - - -void TCPServer::attach_accept(FunctionPointer callback) -{ - _accept_cb = callback; - - if (_socket && _accept_cb) { - return _iface->socket_attach_accept(_socket, Socket::thunk, &_accept_cb); - } else if (_socket) { - return _iface->socket_attach_accept(_socket, 0, 0); - } -} - -TCPServer::~TCPServer() -{ - if (_socket && _accept_cb) { - _iface->socket_attach_accept(_socket, 0, 0); - } -} diff --git a/net/NetworkSocketAPI/TCPServer.h b/net/NetworkSocketAPI/TCPServer.h index 8d52c06bd1..84fbe82c97 100644 --- a/net/NetworkSocketAPI/TCPServer.h +++ b/net/NetworkSocketAPI/TCPServer.h @@ -54,20 +54,6 @@ public: * @return 0 on success, negative on failure. */ int accept(TCPSocket *connection); - - /** Register a callback on when a new connection is ready - * @param callback Function to call when accept will succeed, may be called in - * interrupt context. - */ - void attach_accept(FunctionPointer callback); - - template - void attach_accept(T *tptr, M mptr) { - attach_accept(FunctionPointer(tptr, mptr)); - } - -private: - FunctionPointer _accept_cb; }; #endif diff --git a/net/NetworkSocketAPI/TCPSocket.cpp b/net/NetworkSocketAPI/TCPSocket.cpp index 84a86c1ff7..6c19ddc2e1 100644 --- a/net/NetworkSocketAPI/TCPSocket.cpp +++ b/net/NetworkSocketAPI/TCPSocket.cpp @@ -90,37 +90,3 @@ int TCPSocket::recv(void *data, unsigned size) } } } - - -void TCPSocket::attach_send(FunctionPointer callback) -{ - _send_cb = callback; - - if (_socket && _send_cb) { - return _iface->socket_attach_send(_socket, Socket::thunk, &_send_cb); - } else if (_socket) { - return _iface->socket_attach_send(_socket, 0, 0); - } -} - -void TCPSocket::attach_recv(FunctionPointer callback) -{ - _recv_cb = callback; - - if (_socket && _recv_cb) { - return _iface->socket_attach_recv(_socket, Socket::thunk, &_recv_cb); - } else if (_socket) { - return _iface->socket_attach_recv(_socket, 0, 0); - } -} - -TCPSocket::~TCPSocket() -{ - if (_socket && _send_cb) { - _iface->socket_attach_send(_socket, 0, 0); - } - - if (_socket && _recv_cb) { - _iface->socket_attach_recv(_socket, 0, 0); - } -} diff --git a/net/NetworkSocketAPI/TCPSocket.h b/net/NetworkSocketAPI/TCPSocket.h index 31085919eb..c5a7e97c20 100644 --- a/net/NetworkSocketAPI/TCPSocket.h +++ b/net/NetworkSocketAPI/TCPSocket.h @@ -28,7 +28,6 @@ public: */ TCPSocket(); TCPSocket(NetworkInterface *iface); - virtual ~TCPSocket(); /** Open the socket * @param iface Interface to open socket on @@ -68,33 +67,8 @@ public: */ int recv(void *data, unsigned size); - /** Register a callback on when send is ready - * @param callback Function to call when send will succeed, may be called in - * interrupt context. - */ - void attach_send(FunctionPointer callback); - - template - void attach_send(T *tptr, M mptr) { - attach_send(FunctionPointer(tptr, mptr)); - } - - /** Register a callback on when recv is ready - * @param callback Function to call when recv will succeed, may be called in - * interrupt context. - */ - void attach_recv(FunctionPointer callback); - - template - void attach_recv(T *tptr, M mptr) { - attach_recv(FunctionPointer(tptr, mptr)); - } - private: friend class TCPServer; - - FunctionPointer _send_cb; - FunctionPointer _recv_cb; }; #endif diff --git a/net/NetworkSocketAPI/UDPSocket.cpp b/net/NetworkSocketAPI/UDPSocket.cpp index 3025cd93c4..5970d61def 100644 --- a/net/NetworkSocketAPI/UDPSocket.cpp +++ b/net/NetworkSocketAPI/UDPSocket.cpp @@ -75,35 +75,3 @@ int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size) } } } - - -void UDPSocket::attach_send(FunctionPointer callback) -{ - _send_cb = callback; - if (_socket && _send_cb) { - return _iface->socket_attach_send(_socket, Socket::thunk, &_send_cb); - } else if (_socket) { - return _iface->socket_attach_send(_socket, 0, 0); - } -} - -void UDPSocket::attach_recv(FunctionPointer callback) -{ - _recv_cb = callback; - if (_socket && _recv_cb) { - return _iface->socket_attach_recv(_socket, Socket::thunk, &_recv_cb); - } else if (_socket) { - return _iface->socket_attach_recv(_socket, 0, 0); - } -} - -UDPSocket::~UDPSocket() -{ - if (_socket && _send_cb) { - _iface->socket_attach_send(_socket, 0, 0); - } - - if (_socket && _recv_cb) { - _iface->socket_attach_recv(_socket, 0, 0); - } -} diff --git a/net/NetworkSocketAPI/UDPSocket.h b/net/NetworkSocketAPI/UDPSocket.h index 8564713c53..e40d231287 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -28,7 +28,6 @@ public: */ UDPSocket(); UDPSocket(NetworkInterface *iface); - virtual ~UDPSocket(); /** Open the socket * @param iface Interface to open socket on @@ -58,32 +57,6 @@ public: * @return The number of received bytes on success, negative on failure */ int recvfrom(SocketAddress *address, void *buffer, unsigned size); - - /** Register a callback on when send is ready - * @param callback Function to call when send will succeed, may be called in - * interrupt context. - */ - void attach_send(FunctionPointer callback); - - template - void attach_send(T *tptr, M mptr) { - attach_send(FunctionPointer(tptr, mptr)); - } - - /** Register a callback on when recv is ready - * @param callback Function to call when recv will succeed, may be called in - * interrupt context. - */ - void attach_recv(FunctionPointer callback); - - template - void attach_recv(T *tptr, M mptr) { - attach_recv(FunctionPointer(tptr, mptr)); - } - -private: - FunctionPointer _send_cb; - FunctionPointer _recv_cb; }; #endif From 455f023949d8e7d0a1d48398849ba358e434089e Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 14:37:55 -0500 Subject: [PATCH 06/33] Renamed NetworkInterface create/destroy methods to match Socket methods - socket_create -> socket_open - socket_destroy -> socket_close --- net/ESP8266Interface/ESP8266Interface.cpp | 33 +++++++------- net/ESP8266Interface/ESP8266Interface.h | 41 +++++++++-------- net/LWIPInterface/LWIPInterface.cpp | 54 +++++++++++------------ net/LWIPInterface/LWIPInterface.h | 41 +++++++++-------- net/NetworkSocketAPI/NetworkInterface.h | 31 +++++++------ net/NetworkSocketAPI/Socket.cpp | 22 +++++---- net/NetworkSocketAPI/TCPServer.cpp | 5 +-- 7 files changed, 110 insertions(+), 117 deletions(-) diff --git a/net/ESP8266Interface/ESP8266Interface.cpp b/net/ESP8266Interface/ESP8266Interface.cpp index 14ddc48421..4beee7ad53 100644 --- a/net/ESP8266Interface/ESP8266Interface.cpp +++ b/net/ESP8266Interface/ESP8266Interface.cpp @@ -84,7 +84,7 @@ struct esp8266_socket { bool connected; }; -void *ESP8266Interface::socket_create(nsapi_protocol_t proto) +int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto) { // Look for an unused socket int id = -1; @@ -98,25 +98,34 @@ void *ESP8266Interface::socket_create(nsapi_protocol_t proto) } if (id == -1) { - return 0; + return NSAPI_ERROR_NO_SOCKET; } struct esp8266_socket *socket = new struct esp8266_socket; if (!socket) { - return 0; + return NSAPI_ERROR_NO_SOCKET; } socket->id = id; socket->proto = proto; socket->connected = false; - return socket; + *handle = socket; + return 0; } -void ESP8266Interface::socket_destroy(void *handle) +int ESP8266Interface::socket_close(void *handle) { struct esp8266_socket *socket = (struct esp8266_socket *)handle; + int err = 0; + _esp.setTimeout(ESP8266_MISC_TIMEOUT); + + if (!_esp.close(socket->id)) { + err = NSAPI_ERROR_DEVICE_ERROR; + } + _ids[socket->id] = false; delete socket; + return err; } int ESP8266Interface::socket_set_option(void *handle, int optname, const void *optval, unsigned optlen) @@ -158,7 +167,7 @@ bool ESP8266Interface::socket_is_connected(void *handle) return true; } -int ESP8266Interface::socket_accept(void *handle, void **connection) +int ESP8266Interface::socket_accept(void **handle, void *server) { return NSAPI_ERROR_UNSUPPORTED; } @@ -207,18 +216,6 @@ int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *d return socket_recv(socket, data, size); } -int ESP8266Interface::socket_close(void *handle) -{ - struct esp8266_socket *socket = (struct esp8266_socket *)handle; - _esp.setTimeout(ESP8266_MISC_TIMEOUT); - - if (!_esp.close(socket->id)) { - return NSAPI_ERROR_DEVICE_ERROR; - } - - return 0; -} - void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), void *data) { } diff --git a/net/ESP8266Interface/ESP8266Interface.h b/net/ESP8266Interface/ESP8266Interface.h index 0613daa12d..21829a4d02 100644 --- a/net/ESP8266Interface/ESP8266Interface.h +++ b/net/ESP8266Interface/ESP8266Interface.h @@ -62,16 +62,20 @@ public: virtual const char *get_mac_address(); protected: - /** Create a socket - /param proto The type of socket to open, TCP or UDP - /return The alocated socket or null on failure - */ - virtual void *socket_create(nsapi_protocol_t proto); + /** Open a socket + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure + */ + virtual int socket_open(void **handle, nsapi_protocol_t proto); - /** Destroy a socket - /param socket Previously allocated socket - */ - virtual void socket_destroy(void *handle); + /** Close the socket + * @param handle Socket handle + * @return 0 on success, negative on failure + * @note On failure, any memory associated with the socket must still + * be cleaned up + */ + virtual int socket_close(void *handle); /** Set socket options \param handle Socket handle @@ -120,13 +124,13 @@ protected: virtual bool socket_is_connected(void *handle); /** Accept a new connection. - \param handle Socket handle - \param socket A TCPSocket instance that will handle the incoming connection. - \return 0 on success, negative on failure. - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ - virtual int socket_accept(void *handle, void **connection); + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return 0 on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_accept(void **handle, void *server); /** Send data to the remote host \param handle Socket handle @@ -172,11 +176,6 @@ protected: */ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); - /** Close the socket - \param handle Socket handle - */ - virtual int socket_close(void *handle); - /** Register a callback on state change of the socket * @param handle Socket handle * @param callback Function to call on state change diff --git a/net/LWIPInterface/LWIPInterface.cpp b/net/LWIPInterface/LWIPInterface.cpp index b960aa2ac2..2cc0c0873a 100644 --- a/net/LWIPInterface/LWIPInterface.cpp +++ b/net/LWIPInterface/LWIPInterface.cpp @@ -150,11 +150,11 @@ static void udp_recv_irq( void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, uint16_t port); -void *LWIPInterface::socket_create(nsapi_protocol_t proto) +int LWIPInterface::socket_open(void **handle, nsapi_protocol_t proto) { struct lwip_socket *s = new struct lwip_socket; if (!s) { - return 0; + return NSAPI_ERROR_NO_SOCKET; } memset(s, 0, sizeof *s); @@ -164,30 +164,43 @@ void *LWIPInterface::socket_create(nsapi_protocol_t proto) s->proto = proto; s->udp = udp_new(); if (!s->udp) { - return 0; + return NSAPI_ERROR_NO_SOCKET; } udp_recv(s->udp, udp_recv_irq, s); - return s; + *handle = s; case NSAPI_TCP: s->proto = proto; s->tcp = tcp_new(); if (!s->tcp) { - return 0; + return NSAPI_ERROR_NO_SOCKET; } tcp_arg(s->tcp, s); //tcp_err(s->tcp, tcp_error_irq); - return s; + *handle = s; } - return 0; + return NSAPI_ERROR_DEVICE_ERROR; } -void LWIPInterface::socket_destroy(void *handle) +int LWIPInterface::socket_close(void *handle) { struct lwip_socket *s = (struct lwip_socket *)handle; + int err = 0; + + switch (s->proto) { + case NSAPI_UDP: + udp_disconnect(s->udp); + break; + + case NSAPI_TCP: + if (tcp_close(s->tcp)) { + err = NSAPI_ERROR_DEVICE_ERROR; + } + break; + } if (s->rx_chain) { pbuf_free(s->rx_chain); @@ -195,8 +208,11 @@ void LWIPInterface::socket_destroy(void *handle) } delete s; + + return err; } + int LWIPInterface::socket_set_option(void *handle, int optname, const void *optval, unsigned optlen) { return NSAPI_ERROR_UNSUPPORTED; @@ -273,7 +289,7 @@ bool LWIPInterface::socket_is_connected(void *handle) return true; } -int LWIPInterface::socket_accept(void *handle, void **connection) +int LWIPInterface::socket_accept(void **handle, void *server) { return NSAPI_ERROR_UNSUPPORTED; } @@ -480,26 +496,6 @@ int LWIPInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *buf, return copied; } -int LWIPInterface::socket_close(void *handle) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - - switch (s->proto) { - case NSAPI_UDP: - udp_disconnect(s->udp); - return 0; - - case NSAPI_TCP: - if (tcp_close(s->tcp)) { - return NSAPI_ERROR_DEVICE_ERROR; - } - - return 0; - } - - return NSAPI_ERROR_DEVICE_ERROR; -} - void LWIPInterface::socket_attach(void *handle, void (*callback)(void *), void *data) { struct lwip_socket *s = (struct lwip_socket *)handle; diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index 19b769dfd6..1cdaafdc78 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -49,16 +49,20 @@ public: virtual const char *get_mac_address(); protected: - /** Create a socket - /param proto The type of socket to open, TCP or UDP - /return The alocated socket or null on failure - */ - virtual void *socket_create(nsapi_protocol_t proto); + /** Open a socket + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure + */ + virtual int socket_open(void **handle, nsapi_protocol_t proto); - /** Destroy a socket - /param socket Previously allocated socket - */ - virtual void socket_destroy(void *handle); + /** Close the socket + * @param handle Socket handle + * @return 0 on success, negative on failure + * @note On failure, any memory associated with the socket must still + * be cleaned up + */ + virtual int socket_close(void *handle); /** Set socket options \param handle Socket handle @@ -107,13 +111,13 @@ protected: virtual bool socket_is_connected(void *handle); /** Accept a new connection. - \param handle Socket handle - \param socket A TCPSocket instance that will handle the incoming connection. - \return 0 on success, negative on failure. - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ - virtual int socket_accept(void *handle, void **connection); + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return 0 on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_accept(void **handle, void *server); /** Send data to the remote host \param handle Socket handle @@ -159,11 +163,6 @@ protected: */ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); - /** Close the socket - \param handle Socket handle - */ - virtual int socket_close(void *handle); - /** Register a callback on state change of the socket * @param handle Socket handle * @param callback Function to call on state change diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index a3cbbb889b..45123053a2 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -89,16 +89,20 @@ protected: friend class TCPSocket; friend class TCPServer; - /** Create a socket - * @param proto The type of socket to open, TCP or UDP - * @return The alocated socket or null on failure + /** Open a socket + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure */ - virtual void *socket_create(nsapi_protocol_t proto) = 0; + virtual int socket_open(void **handle, nsapi_protocol_t proto) = 0; - /** Destroy a socket - * @param socket Previously allocated socket + /** Close the socket + * @param handle Socket handle + * @return 0 on success, negative on failure + * @note On failure, any memory associated with the socket must still + * be cleaned up */ - virtual void socket_destroy(void *handle) = 0; + virtual int socket_close(void *handle) = 0; /** Set socket options * @param handle Socket handle @@ -147,13 +151,13 @@ protected: virtual bool socket_is_connected(void *handle) = 0; /** Accept a new connection. - * @param handle Socket handle - * @param socket A TCPSocket instance that will handle the incoming connection. - * @return 0 on success, negative on failure. + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return 0 on success, negative on failure * @note This call is not-blocking, if this call would block, must * immediately return NSAPI_ERROR_WOULD_WAIT */ - virtual int socket_accept(void *handle, void **connection) = 0; + virtual int socket_accept(void **handle, void *server) = 0; /** Send data to the remote host * @param handle Socket handle @@ -199,11 +203,6 @@ protected: */ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size) = 0; - /** Close the socket - * @param handle Socket handle - */ - virtual int socket_close(void *handle) = 0; - /** Register a callback on state change of the socket * @param handle Socket handle * @param callback Function to call on state change diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index a26d9984f9..1b3858aa91 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -34,8 +34,17 @@ Socket::~Socket() int Socket::open(NetworkInterface *iface, nsapi_protocol_t proto) { _iface = iface; - _socket = _iface->socket_create(proto); + + void *socket; + int err = _iface->socket_open(&socket, proto); + if (err) { + return err; + } + + _socket = socket; _iface->socket_attach(_socket, &Socket::thunk, this); + + return 0; } int Socket::close() @@ -44,14 +53,9 @@ int Socket::close() return 0; } - int err = _iface->socket_close(_socket); - if (!err) { - void *socket = _socket; - _socket = 0; - _iface->socket_destroy(socket); - } - - return err; + void *socket = _socket; + _socket = 0; + return _iface->socket_close(socket); } void Socket::set_blocking(bool blocking) diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index 1430adfa4c..ccfd65056b 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -64,9 +64,8 @@ int TCPServer::accept(TCPSocket *connection) } void *socket; - int err = _iface->socket_accept(_socket, &socket); - - if (err > 0) { + int err = _iface->socket_accept(&socket, _socket); + if (!err) { connection->_socket = socket; } From 62bb777c1f2d1ed808ad8fbdc57a6d232da11953 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 16:49:18 -0500 Subject: [PATCH 07/33] Added support for storing bytes directly in SocketAddress Bytes are stored by default, however enough space is allocated in a SocketAddress to generate the string representation if necessary. Currently there is no support for shortened addresses --- net/NetworkSocketAPI/NetworkInterface.h | 10 ++ net/NetworkSocketAPI/SocketAddress.cpp | 172 ++++++++++++++++++++++-- net/NetworkSocketAPI/SocketAddress.h | 96 ++++++++++--- 3 files changed, 245 insertions(+), 33 deletions(-) diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index 45123053a2..76fac217e5 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -20,6 +20,7 @@ #include "mbed.h" #include "SocketAddress.h" + /** Enum of standardized error codes * @enum ns_error_t */ @@ -50,6 +51,15 @@ enum nsapi_protocol_t { NSAPI_UDP, /*!< Socket is of UDP type */ }; +/** Maximum size of MAC address representation + */ +#define NSAPI_MAC_SIZE 18 + +/** Maximum number of bytes for MAC address + */ +#define NSAPI_MAC_BYTES 6 + + /** NetworkInterface class * Common interface that is shared between all hardware that * can connect to a network over IP. diff --git a/net/NetworkSocketAPI/SocketAddress.cpp b/net/NetworkSocketAPI/SocketAddress.cpp index f57fd8253f..af65723ff4 100644 --- a/net/NetworkSocketAPI/SocketAddress.cpp +++ b/net/NetworkSocketAPI/SocketAddress.cpp @@ -19,14 +19,95 @@ #include #include "mbed.h" +static bool address_is_ipv4(const char *addr) +{ + int i = 0; + + // Check each digit for [0-9.] + for (; addr[i]; i++) { + if (!(addr[i] >= '0' && addr[i] <= '9') && addr[i] != '.') { + return false; + } + } + + // Ending with '.' garuntees host + if (i > 0 && addr[i-1] == '.') { + return false; + } + + return true; +} + +static bool address_is_ipv6(const char *addr) +{ + // Check each digit for [0-9a-fA-F:] + for (int i = 0; addr[i]; i++) { + if (!(addr[i] >= '0' && addr[i] <= '9') && + !(addr[i] >= 'a' && addr[i] <= 'f') && + !(addr[i] >= 'A' && addr[i] <= 'F') && + addr[i] != ':') { + return false; + } + } + + return true; +} + +static void address_to_ipv4(uint8_t *bytes, const char *addr) +{ + sscanf(addr, "%hhd.%hhd.%hhd.%hhd", &bytes[0], &bytes[1], &bytes[2], &bytes[3]); +} + +static void address_to_ipv6(uint8_t *bytes, const char *addr) +{ + // TODO support short form (::1, 2001::ffee:100a) + // Use a more intellegent algorithm + uint16_t shorts[NSAPI_IPv6_BYTES/2]; + sscanf(addr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", + &shorts[0], &shorts[1], &shorts[2], &shorts[3], + &shorts[4], &shorts[5], &shorts[6], &shorts[7]); + + for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) { + bytes[2*i+0] = (uint8_t)(shorts[i] >> 8); + bytes[2*i+1] = (uint8_t)(shorts[i] >> 0); + } +} + +static void ipv4_to_address(char *addr, const uint8_t *bytes) +{ + sprintf(addr, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); +} + +static void ipv6_to_address(char *addr, const uint8_t *bytes) +{ + for (int i = 0; i < NSAPI_IPv6_BYTES; i+=2) { + sprintf(&addr[5*i], "%02x%02x", bytes[i], bytes[i+1]); + addr[5*i+4] = ':'; + } + addr[NSAPI_IPv6_BYTES-1] = '\0'; +} + SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t port) { - int err = iface->gethostbyname(host, _ip_address); - set_port(port); - - if (err) { - _ip_address[0] = '\0'; - _port = 0; + // Check for valid IP addresses + if (host && address_is_ipv4(host)) { + _ip_version = NSAPI_IPv4; + address_to_ipv4(_ip_bytes, host); + } else if (host && address_is_ipv6(host)) { + _ip_version = NSAPI_IPv6; + address_to_ipv4(_ip_bytes, host); + } else { + // DNS lookup + char addr[NSAPI_IP_SIZE]; + int err = iface->gethostbyname(host, addr); + if (!err) { + set_ip_address(addr); + set_port(port); + } else { + _ip_version = NSAPI_IPv4; + memset(_ip_bytes, 0, NSAPI_IPv4_BYTES); + set_port(0); + } } } @@ -36,16 +117,48 @@ SocketAddress::SocketAddress(const char *addr, uint16_t port) set_port(port); } +SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port) +{ + set_ip_bytes(bytes, version); + set_port(port); +} + SocketAddress::SocketAddress(const SocketAddress &addr) { - set_ip_address(addr.get_ip_address()); + set_ip_bytes(addr.get_ip_bytes(), addr.get_ip_version()); set_port(addr.get_port()); } void SocketAddress::set_ip_address(const char *addr) { - strncpy(_ip_address, addr, sizeof _ip_address); - _ip_address[sizeof _ip_address - 1] = '\0'; + _ip_address[0] = '\0'; + + if (addr && address_is_ipv4(addr)) { + _ip_version = NSAPI_IPv4; + address_to_ipv4(_ip_bytes, addr); + } else if (addr && address_is_ipv6(addr)) { + _ip_version = NSAPI_IPv6; + address_to_ipv4(_ip_bytes, addr); + } else { + _ip_version = NSAPI_IPv4; + memset(_ip_bytes, 0, NSAPI_IPv4_BYTES); + } +} + +void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version) +{ + _ip_address[0] = '\0'; + + if (_ip_version == NSAPI_IPv4) { + _ip_version = NSAPI_IPv4; + memcpy(_ip_bytes, bytes, NSAPI_IPv4_BYTES); + } else if (_ip_version == NSAPI_IPv6) { + _ip_version = NSAPI_IPv6; + memcpy(_ip_bytes, bytes, NSAPI_IPv6_BYTES); + } else { + _ip_version = NSAPI_IPv4; + memset(_ip_bytes, 0, NSAPI_IPv4_BYTES); + } } void SocketAddress::set_port(uint16_t port) @@ -55,13 +168,48 @@ void SocketAddress::set_port(uint16_t port) const char *SocketAddress::get_ip_address() const { - if (!_ip_address[0]) { - return 0; + char *ip_address = (char *)_ip_address; + + if (!ip_address[0]) { + if (_ip_version == NSAPI_IPv4) { + ipv4_to_address(ip_address, _ip_bytes); + } else if (_ip_version == NSAPI_IPv4) { + ipv6_to_address(ip_address, _ip_bytes); + } } - return _ip_address; + + return ip_address; +} + +const void *SocketAddress::get_ip_bytes() const +{ + return _ip_bytes; +} + +nsapi_version_t SocketAddress::get_ip_version() const +{ + return _ip_version; } uint16_t SocketAddress::get_port() const { return _port; } + +SocketAddress::operator bool() const +{ + int count = 0; + if (_ip_version == NSAPI_IPv4) { + count = NSAPI_IPv4_BYTES; + } else if (_ip_version == NSAPI_IPv6) { + count = NSAPI_IPv6_BYTES; + } + + for (int i = 0; i < count; i++) { + if (_ip_bytes[i]) { + return true; + } + } + + return false; +} diff --git a/net/NetworkSocketAPI/SocketAddress.h b/net/NetworkSocketAPI/SocketAddress.h index 44e55bc9d1..1f93177b5e 100644 --- a/net/NetworkSocketAPI/SocketAddress.h +++ b/net/NetworkSocketAPI/SocketAddress.h @@ -19,64 +19,118 @@ #include -/** Maximum size of IP address -*/ -#define NSAPI_IP_SIZE 16 -/** Maximum size of MAC address -*/ -#define NSAPI_MAC_SIZE 18 +/** Maximum size of IP address representation + */ +#define NSAPI_IP_SIZE NSAPI_IPv6_SIZE + +/** Maximum number of bytes for IP address + */ +#define NSAPI_IP_BYTES NSAPI_IPv6_BYTES + +/** Enum of address families + * @enum nsapi_family_t + */ +enum nsapi_version_t { + NSAPI_IPv4, /*!< Address is IPv4 */ + NSAPI_IPv6, /*!< Address is IPv6 */ +}; + +/** Size of IPv4 representation + */ +#define NSAPI_IPv4_SIZE 16 + +/** Number of bytes in IPv4 address + */ +#define NSAPI_IPv4_BYTES 4 + +/** Size of IPv6 representation + */ +#define NSAPI_IPv6_SIZE 40 + +/** Number of bytes in IPv6 address + */ +#define NSAPI_IPv6_BYTES 16 // Predeclared classes class NetworkInterface; -/** - * A general socket address composed of the IP address and port + +/** A general address class composed of the IP address and optional port */ class SocketAddress { public: /** SocketAddress construction using DNS resolution - * @param iface NetworkInterface to use for DNS resolution - * @param addr Null-terminated hostname that will be resolved - * @param port 16-bit port - * @note on failure, IP address and port will be set to null + * @param iface NetworkInterface to use for DNS resolution + * @param addr Null-terminated hostname that will be resolved + * @param port Optional 16-bit port + * @note on failure, IP address and port will be set to zero */ SocketAddress(NetworkInterface *iface, const char *addr, uint16_t port = 0); /** SocketAddress construction - * @param addr Null-terminated IP address - * @param port 16-bit port - * @note on failure, IP address and port will be set to null + * @param addr Null-terminated IP address + * @param port Optional 16-bit port */ SocketAddress(const char *addr = 0, uint16_t port = 0); /** SocketAddress construction - * @param addr SocketAddress to copy + * @param bytes Bytes to assign to address in big-endian order + * @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6 + * @param port Optional 16-bit port + */ + SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port = 0); + + /** SocketAddress construction + * @param addr SocketAddress to copy */ SocketAddress(const SocketAddress &addr); /** Set the IP address - * @param addr Null-terminated string representing the IP address + * @param addr Null-terminated string representing the IP address */ void set_ip_address(const char *addr); + /** Set the IP address bytes directly + * @param bytes Bytes to assign to address in big-endian order + * @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6 + */ + void set_ip_bytes(const void *bytes, nsapi_version_t version); + /** Set the port - * @param port 16-bit port + * @param port 16-bit port */ void set_port(uint16_t port); /** Get the IP address - * @return The string representation of the IP Address + * @return The string representation of the IP Address */ const char *get_ip_address() const; + + /** Get the IP address bytes directly + * @return IP address bytes + */ + const void *get_ip_bytes() const; + + /** Get the type of the IP address + * @return IP address version, NSAPI_IPv4 or NSAPI_IPv6 + */ + nsapi_version_t get_ip_version() const; /** Get the port - * @return The 16-bit port + * @return The 16-bit port */ - uint16_t get_port(void) const; + uint16_t get_port() const; + + /** Determine if address is all zeros + * @return True if address is not zero address + */ + operator bool() const; private: char _ip_address[NSAPI_IP_SIZE]; + uint8_t _ip_bytes[NSAPI_IP_BYTES]; + nsapi_version_t _ip_version; uint16_t _port; }; From d488f02f5e93cefd4af1f3d78cf7460b82ca50a9 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 16:55:34 -0500 Subject: [PATCH 08/33] Move to SocketAddress in gethostbyname --- net/NetworkSocketAPI/NetworkInterface.cpp | 11 +++++++++-- net/NetworkSocketAPI/NetworkInterface.h | 4 ++-- net/NetworkSocketAPI/SocketAddress.cpp | 4 +--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/net/NetworkSocketAPI/NetworkInterface.cpp b/net/NetworkSocketAPI/NetworkInterface.cpp index 455d3ddf3b..39ccdd69ff 100644 --- a/net/NetworkSocketAPI/NetworkInterface.cpp +++ b/net/NetworkSocketAPI/NetworkInterface.cpp @@ -17,7 +17,14 @@ #include "DnsQuery.h" #include "mbed.h" -int NetworkInterface::gethostbyname(const char *name, char *dest) +int NetworkInterface::gethostbyname(SocketAddress *address, const char *name) { - return dnsQuery(this, name, dest); + char buffer[NSAPI_IP_SIZE]; + int err = dnsQuery(this, name, buffer); + if (err) { + return err; + } + + address->set_ip_address(buffer); + return 0; } diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index 76fac217e5..da002f6d7e 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -87,11 +87,11 @@ public: } /** Looks up the specified host's IP address + * @param address Destination for the host SocketAddress * @param name Hostname to lookup - * @param dest Destination for IP address, must have space for SocketAddress::IP_SIZE * @return 0 on success, negative on failure */ - virtual int gethostbyname(const char *name, char *dest); + virtual int gethostbyname(SocketAddress *address, const char *name); protected: friend class Socket; diff --git a/net/NetworkSocketAPI/SocketAddress.cpp b/net/NetworkSocketAPI/SocketAddress.cpp index af65723ff4..e8251a7c1b 100644 --- a/net/NetworkSocketAPI/SocketAddress.cpp +++ b/net/NetworkSocketAPI/SocketAddress.cpp @@ -98,10 +98,8 @@ SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t address_to_ipv4(_ip_bytes, host); } else { // DNS lookup - char addr[NSAPI_IP_SIZE]; - int err = iface->gethostbyname(host, addr); + int err = iface->gethostbyname(this, host); if (!err) { - set_ip_address(addr); set_port(port); } else { _ip_version = NSAPI_IPv4; From 141b245dfc4a95b706f6516e20227ee908c1d680 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 17:25:05 -0500 Subject: [PATCH 09/33] Added better support for SocketAddress/string addresses/ports --- net/ESP8266Interface/ESP8266Interface.cpp | 2 +- net/ESP8266Interface/ESP8266Interface.h | 10 +++++----- net/LWIPInterface/LWIPInterface.cpp | 8 ++++---- net/LWIPInterface/LWIPInterface.h | 10 +++++----- net/NetworkSocketAPI/NetworkInterface.h | 10 +++++----- net/NetworkSocketAPI/TCPServer.cpp | 16 +++++++++++++-- net/NetworkSocketAPI/TCPServer.h | 19 +++++++++++++++--- net/NetworkSocketAPI/TCPSocket.cpp | 2 +- net/NetworkSocketAPI/UDPSocket.cpp | 24 ++++++++++++++++++++++- net/NetworkSocketAPI/UDPSocket.h | 23 ++++++++++++++++++++++ 10 files changed, 97 insertions(+), 27 deletions(-) diff --git a/net/ESP8266Interface/ESP8266Interface.cpp b/net/ESP8266Interface/ESP8266Interface.cpp index 4beee7ad53..60a1d17f75 100644 --- a/net/ESP8266Interface/ESP8266Interface.cpp +++ b/net/ESP8266Interface/ESP8266Interface.cpp @@ -138,7 +138,7 @@ int ESP8266Interface::socket_get_option(void *handle, int optname, void *optval, return NSAPI_ERROR_UNSUPPORTED; } -int ESP8266Interface::socket_bind(void *handle, int port) +int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address) { return NSAPI_ERROR_UNSUPPORTED; } diff --git a/net/ESP8266Interface/ESP8266Interface.h b/net/ESP8266Interface/ESP8266Interface.h index 21829a4d02..41d89687d5 100644 --- a/net/ESP8266Interface/ESP8266Interface.h +++ b/net/ESP8266Interface/ESP8266Interface.h @@ -96,11 +96,11 @@ protected: virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen); /** Bind a server socket to a specific port - \param handle Socket handle - \param port The port to listen for incoming connections on - \return 0 on success, negative on failure. - */ - virtual int socket_bind(void *handle, int port); + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + virtual int socket_bind(void *handle, const SocketAddress &address); /** Start listening for incoming connections \param handle Socket handle diff --git a/net/LWIPInterface/LWIPInterface.cpp b/net/LWIPInterface/LWIPInterface.cpp index 2cc0c0873a..5e05daee46 100644 --- a/net/LWIPInterface/LWIPInterface.cpp +++ b/net/LWIPInterface/LWIPInterface.cpp @@ -223,20 +223,20 @@ int LWIPInterface::socket_get_option(void *handle, int optname, void *optval, un return NSAPI_ERROR_UNSUPPORTED; } -int LWIPInterface::socket_bind(void *handle, int port) +int LWIPInterface::socket_bind(void *handle, const SocketAddress &address) { struct lwip_socket *s = (struct lwip_socket *)handle; - ip_addr_t ip_addr = ip_addr_any; + ip_addr_t ip_addr = ip_addr_any; // TODO use address switch (s->proto) { case NSAPI_UDP: - if (udp_bind(s->udp, &ip_addr, port)) { + if (udp_bind(s->udp, &ip_addr, address.get_port())) { return NSAPI_ERROR_DEVICE_ERROR; } return 0; case NSAPI_TCP: - if (tcp_bind(s->tcp, &ip_addr, port)) { + if (tcp_bind(s->tcp, &ip_addr, address.get_port())) { return NSAPI_ERROR_DEVICE_ERROR; } return 0; diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index 1cdaafdc78..f2386c5d9d 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -83,11 +83,11 @@ protected: virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen); /** Bind a server socket to a specific port - \param handle Socket handle - \param port The port to listen for incoming connections on - \return 0 on success, negative on failure. - */ - virtual int socket_bind(void *handle, int port); + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + virtual int socket_bind(void *handle, const SocketAddress &address); /** Start listening for incoming connections \param handle Socket handle diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index da002f6d7e..4f1c2cd139 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -22,7 +22,7 @@ /** Enum of standardized error codes - * @enum ns_error_t + * @enum nsapi_error_t */ enum nsapi_error_t { NSAPI_ERROR_WOULD_BLOCK = -3001, /*!< no data is not available but call is non-blocking */ @@ -38,9 +38,9 @@ enum nsapi_error_t { }; /** Enum of available options - * @enum ns_opt_t + * @enum nsapi_opt_t */ -enum ns_opt_t { +enum nsapi_opt_t { }; /** Enum of socket protocols @@ -134,10 +134,10 @@ protected: /** Bind a server socket to a specific port * @param handle Socket handle - * @param port The port to listen for incoming connections on + * @param address Local address to listen for incoming connections on * @return 0 on success, negative on failure. */ - virtual int socket_bind(void *handle, int port) = 0; + virtual int socket_bind(void *handle, const SocketAddress &address) = 0; /** Start listening for incoming connections * @param handle Socket handle diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index ccfd65056b..b2b7e57a6a 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -32,12 +32,24 @@ int TCPServer::open(NetworkInterface *iface) } int TCPServer::bind(uint16_t port) +{ + SocketAddress addr(0, port); + return bind(addr); +} + +int TCPServer::bind(const char *address, uint16_t port) +{ + SocketAddress addr(address, port); + return bind(addr); +} + +int TCPServer::bind(const SocketAddress &address) { if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; + return NSAPI_ERROR_NO_SOCKET; } - return _iface->socket_bind(_socket, port); + return _iface->socket_bind(_socket, address); } int TCPServer::listen(int backlog) diff --git a/net/NetworkSocketAPI/TCPServer.h b/net/NetworkSocketAPI/TCPServer.h index 84fbe82c97..17b2a48c7b 100644 --- a/net/NetworkSocketAPI/TCPServer.h +++ b/net/NetworkSocketAPI/TCPServer.h @@ -36,11 +36,24 @@ public: */ virtual int open(NetworkInterface *iface); - /** Bind a socket to a specific port - * @param port The port to listen for incoming connections on - * @return 0 on success, negative on failure + /** Bind a TCP Server to a specific port + * @param port The port to listen for incoming connections on + * @return 0 on success, negative on failure. */ int bind(uint16_t port); + + /** Bind a TCP Server to a local address + * @param address The null-terminated address to listen for incoming connections on + * @param port The port to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + int bind(const char *address, uint16_t port); + + /** Bind a TCP Server to a local address + * @param address The SocketAddress to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + int bind(const SocketAddress &address); /** Start listening for incoming connections * @param backlog Number of pending connections that can be queued up at any diff --git a/net/NetworkSocketAPI/TCPSocket.cpp b/net/NetworkSocketAPI/TCPSocket.cpp index 6c19ddc2e1..a5225ce56c 100644 --- a/net/NetworkSocketAPI/TCPSocket.cpp +++ b/net/NetworkSocketAPI/TCPSocket.cpp @@ -43,7 +43,7 @@ int TCPSocket::connect(const SocketAddress &addr) int TCPSocket::connect(const char *host, uint16_t port) { SocketAddress addr(_iface, host, port); - if (!addr.get_ip_address()) { + if (!addr) { return NSAPI_ERROR_DNS_FAILURE; } diff --git a/net/NetworkSocketAPI/UDPSocket.cpp b/net/NetworkSocketAPI/UDPSocket.cpp index 5970d61def..6e210946e9 100644 --- a/net/NetworkSocketAPI/UDPSocket.cpp +++ b/net/NetworkSocketAPI/UDPSocket.cpp @@ -32,12 +32,34 @@ int UDPSocket::open(NetworkInterface *iface) } int UDPSocket::bind(uint16_t port) +{ + SocketAddress addr(0, port); + return bind(addr); +} + +int UDPSocket::bind(const char *address, uint16_t port) +{ + SocketAddress addr(address, port); + return bind(addr); +} + +int UDPSocket::bind(const SocketAddress &address) { if (!_socket) { return NSAPI_ERROR_NO_SOCKET; } - return _iface->socket_bind(_socket, port); + return _iface->socket_bind(_socket, address); +} + +int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigned size) +{ + SocketAddress addr(_iface, host, port); + if (!addr) { + return NSAPI_ERROR_DNS_FAILURE; + } + + return sendto(addr, data, size); } int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size) diff --git a/net/NetworkSocketAPI/UDPSocket.h b/net/NetworkSocketAPI/UDPSocket.h index e40d231287..f17ad6c8a3 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -40,6 +40,29 @@ public: */ int bind(uint16_t port); + /** Bind a UDP Server Socket to a local address + * @param address The null-terminated address to listen for incoming connections on + * @param port The port to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + int bind(const char *address, uint16_t port); + + /** Bind a UDP Server Socket to a local address + * @param address The SocketAddress to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + int bind(const SocketAddress &address); + + /** Send a packet to a remote endpoint + * @param host The host to connect to. It can either be an IP Address + * or a hostname that will be resolved with DNS + * @param port The remote port + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return The number of written bytes on success, negative on failure + */ + int sendto(const char *host, uint16_t port, const void *data, unsigned size); + /** Send a packet to a remote endpoint * @param address The remote SocketAddress * @param data The packet to be sent From fa451312455a49e1f2ca9549cfd097c446190bc2 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Mon, 18 Apr 2016 21:26:39 -0500 Subject: [PATCH 10/33] Fix ipv6 addr in SocketAddress Correctly set and return the ipv6 address. --- net/NetworkSocketAPI/SocketAddress.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/NetworkSocketAPI/SocketAddress.cpp b/net/NetworkSocketAPI/SocketAddress.cpp index e8251a7c1b..a30daaf585 100644 --- a/net/NetworkSocketAPI/SocketAddress.cpp +++ b/net/NetworkSocketAPI/SocketAddress.cpp @@ -80,11 +80,20 @@ static void ipv4_to_address(char *addr, const uint8_t *bytes) static void ipv6_to_address(char *addr, const uint8_t *bytes) { + int pos = 0; for (int i = 0; i < NSAPI_IPv6_BYTES; i+=2) { - sprintf(&addr[5*i], "%02x%02x", bytes[i], bytes[i+1]); - addr[5*i+4] = ':'; + int ret = sprintf(&addr[pos], "%02x%02x", bytes[i], bytes[i+1]); + if (ret < 0) { + memset(addr, 0, NSAPI_IPv6_SIZE + 1); + return; + } + pos += ret; + + addr[pos++] = ':'; } - addr[NSAPI_IPv6_BYTES-1] = '\0'; + pos -= 1; // Overwrite last ':' + addr[pos++] = '\0'; + MBED_ASSERT(NSAPI_IPv6_SIZE == pos); } SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t port) @@ -136,7 +145,7 @@ void SocketAddress::set_ip_address(const char *addr) address_to_ipv4(_ip_bytes, addr); } else if (addr && address_is_ipv6(addr)) { _ip_version = NSAPI_IPv6; - address_to_ipv4(_ip_bytes, addr); + address_to_ipv6(_ip_bytes, addr); } else { _ip_version = NSAPI_IPv4; memset(_ip_bytes, 0, NSAPI_IPv4_BYTES); @@ -171,7 +180,7 @@ const char *SocketAddress::get_ip_address() const if (!ip_address[0]) { if (_ip_version == NSAPI_IPv4) { ipv4_to_address(ip_address, _ip_bytes); - } else if (_ip_version == NSAPI_IPv4) { + } else if (_ip_version == NSAPI_IPv6) { ipv6_to_address(ip_address, _ip_bytes); } } From c4506dc1c0d146e6617cb6ad6bf77e25b1c32522 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 17:57:17 -0500 Subject: [PATCH 11/33] Move bind to Socket Bind can operate on any IP socket and is not specific to a protocol --- net/NetworkSocketAPI/Socket.cpp | 21 +++++++++++++++++++++ net/NetworkSocketAPI/Socket.h | 19 +++++++++++++++++++ net/NetworkSocketAPI/TCPServer.cpp | 21 --------------------- net/NetworkSocketAPI/TCPServer.h | 19 ------------------- net/NetworkSocketAPI/UDPSocket.cpp | 21 --------------------- net/NetworkSocketAPI/UDPSocket.h | 19 ------------------- 6 files changed, 40 insertions(+), 80 deletions(-) diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index 1b3858aa91..0d6e652993 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -58,6 +58,27 @@ int Socket::close() return _iface->socket_close(socket); } +int Socket::bind(uint16_t port) +{ + SocketAddress addr(0, port); + return bind(addr); +} + +int Socket::bind(const char *address, uint16_t port) +{ + SocketAddress addr(address, port); + return bind(addr); +} + +int Socket::bind(const SocketAddress &address) +{ + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + return _iface->socket_bind(_socket, address); +} + void Socket::set_blocking(bool blocking) { _blocking = blocking; diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index e8b96dd8c5..68353f1b12 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -33,6 +33,25 @@ public: */ virtual int open(NetworkInterface *iface) = 0; + /** Bind a socket to a specific port + * @param port The port to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + int bind(uint16_t port); + + /** Bind a socket to a specific port + * @param address The null-terminated address to listen for incoming connections on + * @param port The port to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + int bind(const char *address, uint16_t port); + + /** Bind a socket to a specific port + * @param address The SocketAddress to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + int bind(const SocketAddress &address); + /** Set blocking or non-blocking mode of the socket * @param blocking true for blocking mode, false for non-blocking mode. */ diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index b2b7e57a6a..6c513f4be0 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -31,27 +31,6 @@ int TCPServer::open(NetworkInterface *iface) return Socket::open(iface, NSAPI_TCP); } -int TCPServer::bind(uint16_t port) -{ - SocketAddress addr(0, port); - return bind(addr); -} - -int TCPServer::bind(const char *address, uint16_t port) -{ - SocketAddress addr(address, port); - return bind(addr); -} - -int TCPServer::bind(const SocketAddress &address) -{ - if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; - } - - return _iface->socket_bind(_socket, address); -} - int TCPServer::listen(int backlog) { if (!_socket) { diff --git a/net/NetworkSocketAPI/TCPServer.h b/net/NetworkSocketAPI/TCPServer.h index 17b2a48c7b..59fbbac5fb 100644 --- a/net/NetworkSocketAPI/TCPServer.h +++ b/net/NetworkSocketAPI/TCPServer.h @@ -36,25 +36,6 @@ public: */ virtual int open(NetworkInterface *iface); - /** Bind a TCP Server to a specific port - * @param port The port to listen for incoming connections on - * @return 0 on success, negative on failure. - */ - int bind(uint16_t port); - - /** Bind a TCP Server to a local address - * @param address The null-terminated address to listen for incoming connections on - * @param port The port to listen for incoming connections on - * @return 0 on success, negative on failure. - */ - int bind(const char *address, uint16_t port); - - /** Bind a TCP Server to a local address - * @param address The SocketAddress to listen for incoming connections on - * @return 0 on success, negative on failure. - */ - int bind(const SocketAddress &address); - /** Start listening for incoming connections * @param backlog Number of pending connections that can be queued up at any * one time [Default: 1] diff --git a/net/NetworkSocketAPI/UDPSocket.cpp b/net/NetworkSocketAPI/UDPSocket.cpp index 6e210946e9..9177de60c8 100644 --- a/net/NetworkSocketAPI/UDPSocket.cpp +++ b/net/NetworkSocketAPI/UDPSocket.cpp @@ -31,27 +31,6 @@ int UDPSocket::open(NetworkInterface *iface) return Socket::open(iface, NSAPI_UDP); } -int UDPSocket::bind(uint16_t port) -{ - SocketAddress addr(0, port); - return bind(addr); -} - -int UDPSocket::bind(const char *address, uint16_t port) -{ - SocketAddress addr(address, port); - return bind(addr); -} - -int UDPSocket::bind(const SocketAddress &address) -{ - if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; - } - - return _iface->socket_bind(_socket, address); -} - int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigned size) { SocketAddress addr(_iface, host, port); diff --git a/net/NetworkSocketAPI/UDPSocket.h b/net/NetworkSocketAPI/UDPSocket.h index f17ad6c8a3..4fecb7cf18 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -33,25 +33,6 @@ public: * @param iface Interface to open socket on */ virtual int open(NetworkInterface *iface); - - /** Bind a UDP Server Socket to a specific port - * @param port The port to listen for incoming connections on - * @return 0 on success, negative on failure. - */ - int bind(uint16_t port); - - /** Bind a UDP Server Socket to a local address - * @param address The null-terminated address to listen for incoming connections on - * @param port The port to listen for incoming connections on - * @return 0 on success, negative on failure. - */ - int bind(const char *address, uint16_t port); - - /** Bind a UDP Server Socket to a local address - * @param address The SocketAddress to listen for incoming connections on - * @return 0 on success, negative on failure. - */ - int bind(const SocketAddress &address); /** Send a packet to a remote endpoint * @param host The host to connect to. It can either be an IP Address From 525c7b361cc51218d2810eb57b2c628d2e62612c Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 18:47:41 -0500 Subject: [PATCH 12/33] Revised stack specific configurations Adds the following functions for direct configuration of interface - (set|get)stackopt - (set|get)sockopt --- net/ESP8266Interface/ESP8266Interface.cpp | 10 ---- net/ESP8266Interface/ESP8266Interface.h | 18 ------- net/LWIPInterface/LWIPInterface.cpp | 10 ---- net/LWIPInterface/LWIPInterface.h | 18 ------- net/NetworkSocketAPI/NetworkInterface.cpp | 20 ++++++++ net/NetworkSocketAPI/NetworkInterface.h | 62 ++++++++++++++--------- net/NetworkSocketAPI/Socket.cpp | 9 ++-- net/NetworkSocketAPI/Socket.h | 26 +++++----- 8 files changed, 77 insertions(+), 96 deletions(-) diff --git a/net/ESP8266Interface/ESP8266Interface.cpp b/net/ESP8266Interface/ESP8266Interface.cpp index 60a1d17f75..cf29646337 100644 --- a/net/ESP8266Interface/ESP8266Interface.cpp +++ b/net/ESP8266Interface/ESP8266Interface.cpp @@ -128,16 +128,6 @@ int ESP8266Interface::socket_close(void *handle) return err; } -int ESP8266Interface::socket_set_option(void *handle, int optname, const void *optval, unsigned optlen) -{ - return NSAPI_ERROR_UNSUPPORTED; -} - -int ESP8266Interface::socket_get_option(void *handle, int optname, void *optval, unsigned *optlen) -{ - return NSAPI_ERROR_UNSUPPORTED; -} - int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address) { return NSAPI_ERROR_UNSUPPORTED; diff --git a/net/ESP8266Interface/ESP8266Interface.h b/net/ESP8266Interface/ESP8266Interface.h index 41d89687d5..6d3d76caa4 100644 --- a/net/ESP8266Interface/ESP8266Interface.h +++ b/net/ESP8266Interface/ESP8266Interface.h @@ -77,24 +77,6 @@ protected: */ virtual int socket_close(void *handle); - /** Set socket options - \param handle Socket handle - \param optname Option ID - \param optval Option value - \param optlen Length of the option value - \return 0 on success, negative on failure - */ - virtual int socket_set_option(void *handle, int optname, const void *optval, unsigned int optlen); - - /** Get socket options - \param handle Socket handle - \param optname Option ID - \param optval Buffer pointer where to write the option value - \param optlen Length of the option value - \return 0 on success, negative on failure - */ - virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen); - /** Bind a server socket to a specific port * @param handle Socket handle * @param address Local address to listen for incoming connections on diff --git a/net/LWIPInterface/LWIPInterface.cpp b/net/LWIPInterface/LWIPInterface.cpp index 5e05daee46..2fd9c82a68 100644 --- a/net/LWIPInterface/LWIPInterface.cpp +++ b/net/LWIPInterface/LWIPInterface.cpp @@ -213,16 +213,6 @@ int LWIPInterface::socket_close(void *handle) } -int LWIPInterface::socket_set_option(void *handle, int optname, const void *optval, unsigned optlen) -{ - return NSAPI_ERROR_UNSUPPORTED; -} - -int LWIPInterface::socket_get_option(void *handle, int optname, void *optval, unsigned *optlen) -{ - return NSAPI_ERROR_UNSUPPORTED; -} - int LWIPInterface::socket_bind(void *handle, const SocketAddress &address) { struct lwip_socket *s = (struct lwip_socket *)handle; diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index f2386c5d9d..962d484c4f 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -64,24 +64,6 @@ protected: */ virtual int socket_close(void *handle); - /** Set socket options - \param handle Socket handle - \param optname Option ID - \param optval Option value - \param optlen Length of the option value - \return 0 on success, negative on failure - */ - virtual int socket_set_option(void *handle, int optname, const void *optval, unsigned int optlen); - - /** Get socket options - \param handle Socket handle - \param optname Option ID - \param optval Buffer pointer where to write the option value - \param optlen Length of the option value - \return 0 on success, negative on failure - */ - virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen); - /** Bind a server socket to a specific port * @param handle Socket handle * @param address Local address to listen for incoming connections on diff --git a/net/NetworkSocketAPI/NetworkInterface.cpp b/net/NetworkSocketAPI/NetworkInterface.cpp index 39ccdd69ff..a39fdc7c43 100644 --- a/net/NetworkSocketAPI/NetworkInterface.cpp +++ b/net/NetworkSocketAPI/NetworkInterface.cpp @@ -28,3 +28,23 @@ int NetworkInterface::gethostbyname(SocketAddress *address, const char *name) address->set_ip_address(buffer); return 0; } + +int NetworkInterface::setstackopt(int level, int optname, const void *optval, unsigned optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int NetworkInterface::getstackopt(int level, int optname, void *optval, unsigned *optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int NetworkInterface::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int NetworkInterface::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index 4f1c2cd139..162fbe0861 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -36,12 +36,6 @@ enum nsapi_error_t { NSAPI_ERROR_AUTH_FAILURE = -3009, /*!< connection to access point faield */ NSAPI_ERROR_DEVICE_ERROR = -3010, /*!< failure interfacing with the network procesor */ }; - -/** Enum of available options - * @enum nsapi_opt_t - */ -enum nsapi_opt_t { -}; /** Enum of socket protocols * @enum protocol_t @@ -93,6 +87,24 @@ public: */ virtual int gethostbyname(SocketAddress *address, const char *name); + /* Set stack options + * @param level Option level + * @param optname Option identifier + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative on failure + */ + virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen); + + /* Get stack options + * @param level Option level + * @param optname Option identifier + * @param optval Buffer where to write option value + * @param optlen Length of the option value + * @return 0 on success, negative on failure + */ + virtual int getstackopt(int level, int optname, void *optval, unsigned *optlen); + protected: friend class Socket; friend class UDPSocket; @@ -114,24 +126,6 @@ protected: */ virtual int socket_close(void *handle) = 0; - /** Set socket options - * @param handle Socket handle - * @param optname Option ID - * @param optval Option value - * @param optlen Length of the option value - * @return 0 on success, negative on failure - */ - virtual int socket_set_option(void *handle, int optname, const void *optval, unsigned int optlen) = 0; - - /** Get socket options - * @param handle Socket handle - * @param optname Option ID - * @param optval Buffer pointer where to write the option value - * @param optlen Length of the option value - * @return 0 on success, negative on failure - */ - virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen) = 0; - /** Bind a server socket to a specific port * @param handle Socket handle * @param address Local address to listen for incoming connections on @@ -220,6 +214,26 @@ protected: * @note Callback may be called in an interrupt context. */ virtual void socket_attach(void *handle, void (*callback)(void *), void *data) = 0; + + /* Set socket options + * @param handle Socket handle + * @param level Option level + * @param optname Option identifier + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative on failure + */ + virtual int setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen); + + /* Get socket options + * @param handle Socket handle + * @param level Option level + * @param optname Option identifier + * @param optval Buffer where to write option value + * @param optlen Length of the option value + * @return 0 on success, negative on failure + */ + virtual int getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen); }; #endif diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index 0d6e652993..e291f7e1a5 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -89,22 +89,23 @@ void Socket::set_timeout(unsigned timeout) _timeout = timeout; } -int Socket::set_option(int optname, const void *optval, unsigned int optlen) +int Socket::setsockopt(int level, int optname, const void *optval, unsigned optlen) { if (!_socket) { return NSAPI_ERROR_NO_SOCKET; } - return _iface->socket_set_option(_socket, optname, optval, optlen); + return _iface->setsockopt(_socket, level, optname, optval, optlen); } -int Socket::get_option(int optname, void *optval, unsigned int *optlen) +int Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen) { if (!_socket) { return NSAPI_ERROR_NO_SOCKET; } - return _iface->socket_get_option(_socket, optname, optval, optlen); + return _iface->getsockopt(_socket, level, optname, optval, optlen); + } void Socket::thunk(void *data) diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index 68353f1b12..59e8f9558f 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -33,6 +33,10 @@ public: */ virtual int open(NetworkInterface *iface) = 0; + /** Close the socket + */ + int close(); + /** Bind a socket to a specific port * @param port The port to listen for incoming connections on * @return 0 on success, negative on failure. @@ -63,24 +67,22 @@ public: void set_timeout(unsigned int timeout); /* Set socket options - * @param optname Option ID + * @param level Option level + * @param optname Option identifier * @param optval Option value * @param optlen Length of the option value * @return 0 on success, negative on failure - */ - int set_option(int optname, const void *optval, unsigned optlen); - + */ + int setsockopt(int level, int optname, const void *optval, unsigned optlen); + /* Get socket options - * @param optname Option ID - * @param optval Buffer pointer where to write the option value + * @param level Option level + * @param optname Option identifier + * @param optval Buffer where to write option value * @param optlen Length of the option value * @return 0 on success, negative on failure - */ - int get_option(int optname, void *optval, unsigned *optlen); - - /** Close the socket - */ - int close(); + */ + int getsockopt(int level, int optname, void *optval, unsigned *optlen); /** Register a callback on state change of the socket * @param callback Function to call on state change From e762b04f64fe885a94696a21c7a87daa4c395841 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 13 Mar 2016 19:30:30 -0500 Subject: [PATCH 13/33] Added support for shortened form ipv6 addresses supported: 1.2.3.4 1:2:3:4:5:6:7:8 1:2::7:8 :: currently not supported: 1:2:3:4:5:6:1.2.3.4 --- net/NetworkSocketAPI/SocketAddress.cpp | 96 +++++++++++++++++--------- 1 file changed, 63 insertions(+), 33 deletions(-) diff --git a/net/NetworkSocketAPI/SocketAddress.cpp b/net/NetworkSocketAPI/SocketAddress.cpp index a30daaf585..f8446ea349 100644 --- a/net/NetworkSocketAPI/SocketAddress.cpp +++ b/net/NetworkSocketAPI/SocketAddress.cpp @@ -19,7 +19,8 @@ #include #include "mbed.h" -static bool address_is_ipv4(const char *addr) + +static bool ipv4_is_valid(const char *addr) { int i = 0; @@ -38,7 +39,7 @@ static bool address_is_ipv4(const char *addr) return true; } -static bool address_is_ipv6(const char *addr) +static bool ipv6_is_valid(const char *addr) { // Check each digit for [0-9a-fA-F:] for (int i = 0; addr[i]; i++) { @@ -53,20 +54,57 @@ static bool address_is_ipv6(const char *addr) return true; } -static void address_to_ipv4(uint8_t *bytes, const char *addr) +static void ipv4_from_address(uint8_t *bytes, const char *addr) { - sscanf(addr, "%hhd.%hhd.%hhd.%hhd", &bytes[0], &bytes[1], &bytes[2], &bytes[3]); + sscanf(addr, "%hhu.%hhu.%hhu.%hhu", &bytes[0], &bytes[1], &bytes[2], &bytes[3]); } -static void address_to_ipv6(uint8_t *bytes, const char *addr) -{ - // TODO support short form (::1, 2001::ffee:100a) - // Use a more intellegent algorithm - uint16_t shorts[NSAPI_IPv6_BYTES/2]; - sscanf(addr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", - &shorts[0], &shorts[1], &shorts[2], &shorts[3], - &shorts[4], &shorts[5], &shorts[6], &shorts[7]); +static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) { + int count = 0; + int i = 0; + for (; count < NSAPI_IPv6_BYTES/2; count++) { + int scanned = sscanf(&chunk[i], "%hx", &shorts[count]); + if (scanned < 1) { + return count; + } + + for (; chunk[i] != ':'; i++) { + if (!chunk[i]) { + return count+1; + } + } + + i++; + } + + return count; +} + +static void ipv6_from_address(uint8_t *bytes, const char *addr) +{ + // Start with zeroed address + uint16_t shorts[NSAPI_IPv6_BYTES/2]; + memset(shorts, 0, sizeof shorts); + + int suffix = 0; + + // Find double colons and scan suffix + for (int i = 0; addr[i]; i++) { + if (addr[i] == ':' && addr[i+1] == ':') { + suffix = ipv6_scan_chunk(shorts, &addr[i+2]); + break; + } + } + + // Move suffix to end + memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0], + suffix*sizeof(uint16_t)); + + // Scan prefix + ipv6_scan_chunk(shorts, &addr[0]); + + // Flip bytes for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) { bytes[2*i+0] = (uint8_t)(shorts[i] >> 8); bytes[2*i+1] = (uint8_t)(shorts[i] >> 0); @@ -80,31 +118,23 @@ static void ipv4_to_address(char *addr, const uint8_t *bytes) static void ipv6_to_address(char *addr, const uint8_t *bytes) { - int pos = 0; - for (int i = 0; i < NSAPI_IPv6_BYTES; i+=2) { - int ret = sprintf(&addr[pos], "%02x%02x", bytes[i], bytes[i+1]); - if (ret < 0) { - memset(addr, 0, NSAPI_IPv6_SIZE + 1); - return; - } - pos += ret; - - addr[pos++] = ':'; + for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) { + sprintf(&addr[5*i], "%02x%02x", bytes[2*i], bytes[2*i+1]); + addr[5*i+4] = ':'; } - pos -= 1; // Overwrite last ':' - addr[pos++] = '\0'; - MBED_ASSERT(NSAPI_IPv6_SIZE == pos); + addr[NSAPI_IPv6_SIZE-1] = '\0'; } + SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t port) { // Check for valid IP addresses - if (host && address_is_ipv4(host)) { + if (host && ipv4_is_valid(host)) { _ip_version = NSAPI_IPv4; - address_to_ipv4(_ip_bytes, host); - } else if (host && address_is_ipv6(host)) { + ipv4_from_address(_ip_bytes, host); + } else if (host && ipv6_is_valid(host)) { _ip_version = NSAPI_IPv6; - address_to_ipv4(_ip_bytes, host); + ipv4_from_address(_ip_bytes, host); } else { // DNS lookup int err = iface->gethostbyname(this, host); @@ -140,12 +170,12 @@ void SocketAddress::set_ip_address(const char *addr) { _ip_address[0] = '\0'; - if (addr && address_is_ipv4(addr)) { + if (addr && ipv4_is_valid(addr)) { _ip_version = NSAPI_IPv4; - address_to_ipv4(_ip_bytes, addr); - } else if (addr && address_is_ipv6(addr)) { + ipv4_from_address(_ip_bytes, addr); + } else if (addr && ipv6_is_valid(addr)) { _ip_version = NSAPI_IPv6; - address_to_ipv6(_ip_bytes, addr); + ipv6_from_address(_ip_bytes, addr); } else { _ip_version = NSAPI_IPv4; memset(_ip_bytes, 0, NSAPI_IPv4_BYTES); From 59549cb4df4e9ab49d5b5a13882b11314cced323 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Apr 2016 13:22:30 -0500 Subject: [PATCH 14/33] Standardized comment style --- net/ESP8266Interface/ESP8266Interface.h | 144 ++++++++++++------------ net/LWIPInterface/LWIPInterface.h | 128 ++++++++++----------- 2 files changed, 136 insertions(+), 136 deletions(-) diff --git a/net/ESP8266Interface/ESP8266Interface.h b/net/ESP8266Interface/ESP8266Interface.h index 6d3d76caa4..04efed53e0 100644 --- a/net/ESP8266Interface/ESP8266Interface.h +++ b/net/ESP8266Interface/ESP8266Interface.h @@ -29,139 +29,139 @@ class ESP8266Interface : public WiFiInterface { public: /** ESP8266Interface lifetime - /param tx TX pin - /param rx RX pin - /param debug Enable debugging - */ + * @param tx TX pin + * @param rx RX pin + * @param debug Enable debugging + */ ESP8266Interface(PinName tx, PinName rx, bool debug = false); /** Start the interface - /param ssid Name of the network to connect to - /param pass Security passphrase to connect to the network - /param security Type of encryption for connection - /return 0 on success, negative on failure - */ + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection + * @return 0 on success, negative on failure + */ virtual int connect( const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE); /** Stop the interface - * @return 0 on success, negative on failure + * @return 0 on success, negative on failure */ virtual int disconnect(); /** Get the internally stored IP address - /return IP address of the interface or null if not yet connected - */ + * @return IP address of the interface or null if not yet connected + */ virtual const char *get_ip_address(); /** Get the internally stored MAC address - /return MAC address of the interface - */ + * @return MAC address of the interface + */ virtual const char *get_mac_address(); protected: /** Open a socket - * @param handle Handle in which to store new socket - * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP - * @return 0 on success, negative on failure + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure */ virtual int socket_open(void **handle, nsapi_protocol_t proto); /** Close the socket - * @param handle Socket handle - * @return 0 on success, negative on failure + * @param handle Socket handle + * @return 0 on success, negative on failure * @note On failure, any memory associated with the socket must still * be cleaned up */ virtual int socket_close(void *handle); /** Bind a server socket to a specific port - * @param handle Socket handle - * @param address Local address to listen for incoming connections on - * @return 0 on success, negative on failure. + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return 0 on success, negative on failure. */ virtual int socket_bind(void *handle, const SocketAddress &address); /** Start listening for incoming connections - \param handle Socket handle - \param backlog Number of pending connections that can be queued up at any - one time [Default: 1] - \return 0 on success, negative on failure - */ + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return 0 on success, negative on failure + */ virtual int socket_listen(void *handle, int backlog); /** Connects this TCP socket to the server - \param handle Socket handle - \param address SocketAddress to connect to - \return 0 on success, negative on failure - */ + * @param handle Socket handle + * @param address SocketAddress to connect to + * @return 0 on success, negative on failure + */ virtual int socket_connect(void *handle, const SocketAddress &address); /** Check if the socket is connected - \param handle Socket handle - \return true if connected, false otherwise - */ + * @param handle Socket handle + * @return true if connected, false otherwise + */ virtual bool socket_is_connected(void *handle); /** Accept a new connection. - * @param handle Handle in which to store new socket - * @param server Socket handle to server to accept from - * @return 0 on success, negative on failure + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return 0 on success, negative on failure * @note This call is not-blocking, if this call would block, must * immediately return NSAPI_ERROR_WOULD_WAIT */ virtual int socket_accept(void **handle, void *server); /** Send data to the remote host - \param handle Socket handle - \param data The buffer to send to the host - \param size The length of the buffer to send - \return Number of written bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param data The buffer to send to the host + * @param size The length of the buffer to send + * @return Number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_send(void *handle, const void *data, unsigned size); /** Receive data from the remote host - \param handle Socket handle - \param data The buffer in which to store the data received from the host - \param size The maximum length of the buffer - \return Number of received bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param data The buffer in which to store the data received from the host + * @param size The maximum length of the buffer + * @return Number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_recv(void *handle, void *data, unsigned size); /** Send a packet to a remote endpoint - \param handle Socket handle - \param address The remote SocketAddress - \param data The packet to be sent - \param size The length of the packet to be sent - \return the number of written bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param address The remote SocketAddress + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return the number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size); /** Receive a packet from a remote endpoint - \param handle Socket handle - \param address Destination for the remote SocketAddress or null - \param buffer The buffer for storing the incoming packet data - If a packet is too long to fit in the supplied buffer, - excess bytes are discarded - \param size The length of the buffer - \return the number of received bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param address Destination for the remote SocketAddress or null + * @param buffer The buffer for storing the incoming packet data + * If a packet is too long to fit in the supplied buffer, + * excess bytes are discarded + * @param size The length of the buffer + * @return the number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); /** Register a callback on state change of the socket - * @param handle Socket handle - * @param callback Function to call on state change - * @param data Argument to pass to callback + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback * @note Callback may be called in an interrupt context. */ virtual void socket_attach(void *handle, void (*callback)(void *), void *data); diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index 962d484c4f..4b0331c1db 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -29,126 +29,126 @@ class LWIPInterface : public EthernetInterface { public: /** Start the interface - * @return 0 on success, negative on failure + * @return 0 on success, negative on failure */ virtual int connect(); /** Stop the interface - * @return 0 on success, negative on failure + * @return 0 on success, negative on failure */ virtual int disconnect(); /** Get the internally stored IP address - /return IP address of the interface or null if not yet connected - */ + * @return IP address of the interface or null if not yet connected + */ virtual const char *get_ip_address(); /** Get the internally stored MAC address - /return MAC address of the interface - */ + * @return MAC address of the interface + */ virtual const char *get_mac_address(); protected: /** Open a socket - * @param handle Handle in which to store new socket - * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP - * @return 0 on success, negative on failure + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure */ virtual int socket_open(void **handle, nsapi_protocol_t proto); /** Close the socket - * @param handle Socket handle - * @return 0 on success, negative on failure + * @param handle Socket handle + * @return 0 on success, negative on failure * @note On failure, any memory associated with the socket must still * be cleaned up */ virtual int socket_close(void *handle); /** Bind a server socket to a specific port - * @param handle Socket handle - * @param address Local address to listen for incoming connections on - * @return 0 on success, negative on failure. + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return 0 on success, negative on failure. */ virtual int socket_bind(void *handle, const SocketAddress &address); /** Start listening for incoming connections - \param handle Socket handle - \param backlog Number of pending connections that can be queued up at any - one time [Default: 1] - \return 0 on success, negative on failure - */ + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return 0 on success, negative on failure + */ virtual int socket_listen(void *handle, int backlog); /** Connects this TCP socket to the server - \param handle Socket handle - \param address SocketAddress to connect to - \return 0 on success, negative on failure - */ + * @param handle Socket handle + * @param address SocketAddress to connect to + * @return 0 on success, negative on failure + */ virtual int socket_connect(void *handle, const SocketAddress &address); /** Check if the socket is connected - \param handle Socket handle - \return true if connected, false otherwise - */ + * @param handle Socket handle + * @return true if connected, false otherwise + */ virtual bool socket_is_connected(void *handle); /** Accept a new connection. - * @param handle Handle in which to store new socket - * @param server Socket handle to server to accept from - * @return 0 on success, negative on failure + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return 0 on success, negative on failure * @note This call is not-blocking, if this call would block, must * immediately return NSAPI_ERROR_WOULD_WAIT */ virtual int socket_accept(void **handle, void *server); /** Send data to the remote host - \param handle Socket handle - \param data The buffer to send to the host - \param size The length of the buffer to send - \return Number of written bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param data The buffer to send to the host + * @param size The length of the buffer to send + * @return Number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_send(void *handle, const void *data, unsigned size); /** Receive data from the remote host - \param handle Socket handle - \param data The buffer in which to store the data received from the host - \param size The maximum length of the buffer - \return Number of received bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param data The buffer in which to store the data received from the host + * @param size The maximum length of the buffer + * @return Number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_recv(void *handle, void *data, unsigned size); /** Send a packet to a remote endpoint - \param handle Socket handle - \param address The remote SocketAddress - \param data The packet to be sent - \param size The length of the packet to be sent - \return the number of written bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param address The remote SocketAddress + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return the number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size); /** Receive a packet from a remote endpoint - \param handle Socket handle - \param address Destination for the remote SocketAddress or null - \param buffer The buffer for storing the incoming packet data - If a packet is too long to fit in the supplied buffer, - excess bytes are discarded - \param size The length of the buffer - \return the number of received bytes on success, negative on failure - \note This call is not-blocking, if this call would block, must - immediately return NSAPI_ERROR_WOULD_WAIT - */ + * @param handle Socket handle + * @param address Destination for the remote SocketAddress or null + * @param buffer The buffer for storing the incoming packet data + * If a packet is too long to fit in the supplied buffer, + * excess bytes are discarded + * @param size The length of the buffer + * @return the number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); /** Register a callback on state change of the socket - * @param handle Socket handle - * @param callback Function to call on state change - * @param data Argument to pass to callback + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback * @note Callback may be called in an interrupt context. */ virtual void socket_attach(void *handle, void (*callback)(void *), void *data); From 50a914347812f2526377e92c1913007b51730dba Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Apr 2016 15:47:36 -0500 Subject: [PATCH 15/33] Revisited documentation for NetworkInterface specific methods --- net/NetworkSocketAPI/NetworkInterface.h | 262 ++++++++++++++++-------- 1 file changed, 173 insertions(+), 89 deletions(-) diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index 162fbe0861..63e1800732 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -21,7 +21,11 @@ #include "SocketAddress.h" -/** Enum of standardized error codes +/** Enum of standardized error codes + * + * Valid error codes have negative values and may + * be returned by any network operation. + * * @enum nsapi_error_t */ enum nsapi_error_t { @@ -38,6 +42,10 @@ enum nsapi_error_t { }; /** Enum of socket protocols + * + * The socket protocol specifies a particular protocol to + * be used with a newly created socket. + * * @enum protocol_t */ enum nsapi_protocol_t { @@ -55,8 +63,11 @@ enum nsapi_protocol_t { /** NetworkInterface class - * Common interface that is shared between all hardware that - * can connect to a network over IP. + * + * Common interface that is shared between hardware that + * can connect to a network over IP. By implementing the + * NetworkInterface, a network stack can be used as a target + * for instantiating network sockets. */ class NetworkInterface { @@ -64,44 +75,54 @@ public: virtual ~NetworkInterface() {}; /** Get the internally stored IP address + * * @return IP address of the interface or null if not yet connected */ virtual const char *get_ip_address() = 0; /** Get the internally stored MAC address + * * @return MAC address of the interface */ virtual const char *get_mac_address() = 0; - /** Get the current status of the interface - * @return true if connected - */ - virtual bool is_connected() { - return get_ip_address() != NULL; - } - - /** Looks up the specified host's IP address + /** Translates a host name to an IP address + * + * The host name may be either a domain name or an IP address. + * If no stack-specific DNS resolution is provided, the host name + * will be resolve using a UDP socket on the stack. + * * @param address Destination for the host SocketAddress - * @param name Hostname to lookup - * @return 0 on success, negative on failure + * @param host Host name to lookup + * @return 0 on success, negative error code on failure */ - virtual int gethostbyname(SocketAddress *address, const char *name); + virtual int gethostbyname(SocketAddress *address, const char *host); - /* Set stack options - * @param level Option level - * @param optname Option identifier + /* Set stack-specific stack options + * + * The setstackopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the stack is unmodified. + * + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier * @param optval Option value * @param optlen Length of the option value - * @return 0 on success, negative on failure + * @return 0 on success, negative error code on failure */ virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen); - /* Get stack options - * @param level Option level - * @param optname Option identifier - * @param optval Buffer where to write option value + /* Get stack-specific stack options + * + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Destination for option value * @param optlen Length of the option value - * @return 0 on success, negative on failure + * @return 0 on success, negative error code on failure */ virtual int getstackopt(int level, int optname, void *optval, unsigned *optlen); @@ -111,127 +132,190 @@ protected: friend class TCPSocket; friend class TCPServer; - /** Open a socket - * @param handle Handle in which to store new socket - * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP - * @return 0 on success, negative on failure + /** Opens a socket + * + * Creates a socket for communication and stores it in the specified + * handle. The handle must be passed to following calls on the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * @param handle Destination for the handle to a newly created socket + * @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative error code on failure */ virtual int socket_open(void **handle, nsapi_protocol_t proto) = 0; /** Close the socket + * + * Closes any open connection and deallocates any memory associated with + * the socket. + * * @param handle Socket handle - * @return 0 on success, negative on failure - * @note On failure, any memory associated with the socket must still - * be cleaned up + * @return 0 on success, negative error code on failure */ virtual int socket_close(void *handle) = 0; - /** Bind a server socket to a specific port + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to recieve + * data. If the IP address is zeroed, only the port is bound. + * * @param handle Socket handle - * @param address Local address to listen for incoming connections on - * @return 0 on success, negative on failure. + * @param address Local address to bind + * @return 0 on success, negative error code on failure. */ virtual int socket_bind(void *handle, const SocketAddress &address) = 0; - /** Start listening for incoming connections + /** Listen for connections on a TCP socket + * + * Marks the socket as a passive socket that can be used to accept + * incoming connections. + * * @param handle Socket handle - * @param backlog Number of pending connections that can be queued up at any - * one time [Default: 1] - * @return 0 on success, negative on failure + * @param backlog Number of pending connections that can be queued + * simultaneously, defaults to 1 + * @return 0 on success, negative error code on failure */ virtual int socket_listen(void *handle, int backlog) = 0; - /** Connects this TCP socket to the server + /** Connects TCP socket to a remote host + * + * Initiates a connection to a remote server specified by the + * indicated address. + * * @param handle Socket handle - * @param address SocketAddress to connect to - * @return 0 on success, negative on failure + * @param address The SocketAddress of the remote host + * @return 0 on success, negative error code on failure */ virtual int socket_connect(void *handle, const SocketAddress &address) = 0; - - /** Check if the socket is connected - * @param handle Socket handle - * @return true if connected, false otherwise - */ - virtual bool socket_is_connected(void *handle) = 0; - /** Accept a new connection. - * @param handle Handle in which to store new socket + /** Accepts a connection on a TCP socket + * + * The server socket must be bound and set to listen for connections. + * On a new connection, creates a socket stores it in the specified + * handle. The handle must be passed to following calls on the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * This call is non-blocking. If accept would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Destination for a handle to the newly created sockey * @param server Socket handle to server to accept from - * @return 0 on success, negative on failure - * @note This call is not-blocking, if this call would block, must - * immediately return NSAPI_ERROR_WOULD_WAIT + * @return 0 on success, negative error code on failure */ virtual int socket_accept(void **handle, void *server) = 0; - /** Send data to the remote host + /** Send data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes sent from the buffer. + * + * This call is non-blocking. If send would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * * @param handle Socket handle - * @param data The buffer to send to the host - * @param size The length of the buffer to send - * @return Number of written bytes on success, negative on failure - * @note This call is not-blocking, if this call would block, must - * immediately return NSAPI_ERROR_WOULD_WAIT + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure */ virtual int socket_send(void *handle, const void *data, unsigned size) = 0; - /** Receive data from the remote host + /** Receive data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes received into the buffer. + * + * This call is non-blocking. If recv would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * * @param handle Socket handle - * @param data The buffer in which to store the data received from the host - * @param size The maximum length of the buffer - * @return Number of received bytes on success, negative on failure - * @note This call is not-blocking, if this call would block, must - * immediately return NSAPI_ERROR_WOULD_WAIT + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure */ virtual int socket_recv(void *handle, void *data, unsigned size) = 0; - /** Send a packet to a remote endpoint + /** Send a packet over a UDP socket + * + * Sends data to the specified address. Returns the number of bytes + * sent from the buffer. + * + * This call is non-blocking. If sendto would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * * @param handle Socket handle - * @param address The remote SocketAddress - * @param data The packet to be sent - * @param size The length of the packet to be sent - * @return the number of written bytes on success, negative on failure - * @note This call is not-blocking, if this call would block, must - * immediately return NSAPI_ERROR_WOULD_WAIT + * @param address The SocketAddress of the remote host + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure */ virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size) = 0; - /** Receive a packet from a remote endpoint + /** Receive a packet over a UDP socket + * + * Receives data and stores the source address in address if address + * is not NULL. Returns the number of bytes received into the buffer. + * + * This call is non-blocking. If recvfrom would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * * @param handle Socket handle - * @param address Destination for the remote SocketAddress or null - * @param buffer The buffer for storing the incoming packet data - * If a packet is too long to fit in the supplied buffer, - * excess bytes are discarded - * @param size The length of the buffer - * @return the number of received bytes on success, negative on failure - * @note This call is not-blocking, if this call would block, must - * immediately return NSAPI_ERROR_WOULD_WAIT + * @param address Destination for the source address or NULL + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure */ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size) = 0; /** Register a callback on state change of the socket + * + * The specified callback will be called on state changes such as when + * the socket can recv/send/accept successfully and on when an error + * occurs. The callback may also be called spuriously without reason. + * + * The callback may be called in an interrupt context and should not + * perform expensive operations such as recv/send calls. + * * @param handle Socket handle * @param callback Function to call on state change * @param data Argument to pass to callback - * @note Callback may be called in an interrupt context. */ virtual void socket_attach(void *handle, void (*callback)(void *), void *data) = 0; - /* Set socket options + /* Set stack-specific socked options + * + * The setsockopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. + * * @param handle Socket handle - * @param level Option level - * @param optname Option identifier + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier * @param optval Option value * @param optlen Length of the option value - * @return 0 on success, negative on failure + * @return 0 on success, negative error code on failure */ virtual int setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen); - /* Get socket options + /* Get stack-specific socket options + * + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * * @param handle Socket handle - * @param level Option level - * @param optname Option identifier - * @param optval Buffer where to write option value + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Destination for option value * @param optlen Length of the option value - * @return 0 on success, negative on failure + * @return 0 on success, negative error code on failure */ virtual int getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen); }; From eab6d775ac2560f479b4822075c3fa748dcdaba2 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Apr 2016 15:47:54 -0500 Subject: [PATCH 16/33] Removed is_connected function - Not supported by TCP/UDP protocols - Uncommon and less useful with proper error handling --- net/NetworkSocketAPI/TCPSocket.cpp | 5 ----- net/NetworkSocketAPI/TCPSocket.h | 5 ----- 2 files changed, 10 deletions(-) diff --git a/net/NetworkSocketAPI/TCPSocket.cpp b/net/NetworkSocketAPI/TCPSocket.cpp index a5225ce56c..a837f29fe2 100644 --- a/net/NetworkSocketAPI/TCPSocket.cpp +++ b/net/NetworkSocketAPI/TCPSocket.cpp @@ -50,11 +50,6 @@ int TCPSocket::connect(const char *host, uint16_t port) return connect(addr); } -bool TCPSocket::is_connected() -{ - return _socket && _iface->socket_is_connected(_socket); -} - int TCPSocket::send(const void *data, unsigned size) { mbed::Timer timer; diff --git a/net/NetworkSocketAPI/TCPSocket.h b/net/NetworkSocketAPI/TCPSocket.h index c5a7e97c20..c6714feea9 100644 --- a/net/NetworkSocketAPI/TCPSocket.h +++ b/net/NetworkSocketAPI/TCPSocket.h @@ -48,11 +48,6 @@ public: */ int connect(const SocketAddress &address); - /** Check if the socket is connected - * @return true if connected, false otherwise - */ - bool is_connected(); - /** Send data to the remote host * @param data The buffer to send to the host * @param size The length of the buffer to send From d43f8706d3e68a9ade87ebd71f17ab2197826f31 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Apr 2016 16:52:06 -0500 Subject: [PATCH 17/33] Revisited documentation for Socket API --- net/NetworkSocketAPI/NetworkInterface.h | 19 ++-- net/NetworkSocketAPI/Socket.h | 117 ++++++++++++++++++------ net/NetworkSocketAPI/TCPServer.h | 54 ++++++++--- net/NetworkSocketAPI/TCPSocket.h | 79 ++++++++++++---- net/NetworkSocketAPI/UDPSocket.h | 87 +++++++++++++----- 5 files changed, 261 insertions(+), 95 deletions(-) diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index 63e1800732..f15a2c16cb 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -1,4 +1,4 @@ -/* Socket +/* NetworkInterface * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -134,8 +134,8 @@ protected: /** Opens a socket * - * Creates a socket for communication and stores it in the specified - * handle. The handle must be passed to following calls on the socket. + * Creates a network socket and stores it in the specified handle. + * The handle must be passed to following calls on the socket. * * A stack may have a finite number of sockets, in this case * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. @@ -148,8 +148,8 @@ protected: /** Close the socket * - * Closes any open connection and deallocates any memory associated with - * the socket. + * Closes any open connection and deallocates any memory associated + * with the socket. * * @param handle Socket handle * @return 0 on success, negative error code on failure @@ -174,7 +174,7 @@ protected: * * @param handle Socket handle * @param backlog Number of pending connections that can be queued - * simultaneously, defaults to 1 + * simultaneously * @return 0 on success, negative error code on failure */ virtual int socket_listen(void *handle, int backlog) = 0; @@ -193,8 +193,9 @@ protected: /** Accepts a connection on a TCP socket * * The server socket must be bound and set to listen for connections. - * On a new connection, creates a socket stores it in the specified - * handle. The handle must be passed to following calls on the socket. + * On a new connection, creates a network socket and stores it in the + * specified handle. The handle must be passed to following calls on + * the socket. * * A stack may have a finite number of sockets, in this case * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. @@ -289,7 +290,7 @@ protected: */ virtual void socket_attach(void *handle, void (*callback)(void *), void *data) = 0; - /* Set stack-specific socked options + /* Set stack-specific socket options * * The setsockopt allow an application to pass stack-specific hints * to the underlying stack. For unsupported options, diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index 59e8f9558f..612360e927 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -24,74 +24,135 @@ */ class Socket { public: - /** Socket lifetime + /** Destroy a socket + * + * Closes socket if the socket is still open */ virtual ~Socket(); - /** Open the socket - * @param iface Interface to open socket on + /** Opens a socket + * + * Creates a network socket on the specified network stack. + * Not needed if stack is passed to the socket's constructor. + * + * @param iface Network stack as target for socket + * @return 0 on success, negative error code on failure */ virtual int open(NetworkInterface *iface) = 0; /** Close the socket + * + * Closes any open connection and deallocates any memory associated + * with the socket. Called from destructor if socket is not closed. + * + * @return 0 on success, negative error code on failure */ int close(); - /** Bind a socket to a specific port - * @param port The port to listen for incoming connections on - * @return 0 on success, negative on failure. + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to recieve + * data. + * + * @param port Local port to bind + * @return 0 on success, negative error code on failure. */ int bind(uint16_t port); - /** Bind a socket to a specific port - * @param address The null-terminated address to listen for incoming connections on - * @param port The port to listen for incoming connections on - * @return 0 on success, negative on failure. + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to recieve + * data. If the IP address is zeroed, only the port is bound. + * + * @param address Null-terminated local address to bind + * @param port Local port to bind + * @return 0 on success, negative error code on failure. */ int bind(const char *address, uint16_t port); - /** Bind a socket to a specific port - * @param address The SocketAddress to listen for incoming connections on - * @return 0 on success, negative on failure. + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to recieve + * data. If the IP address is zeroed, only the port is bound. + * + * @param address Local address to bind + * @return 0 on success, negative error code on failure. */ int bind(const SocketAddress &address); /** Set blocking or non-blocking mode of the socket - * @param blocking true for blocking mode, false for non-blocking mode. + * + * Initially all sockets are in blocking mode. In non-blocking mode + * blocking operations such as send/recv/accept return + * NSAPI_ERROR_WOULD_BLOCK if they can not continue. + * + * @param blocking True for blocking mode, false for non-blocking mode. */ void set_blocking(bool blocking); - /** Set timeout on a socket operation if blocking behaviour is enabled - * @param timeout timeout in ms + /** Set timeout on blocking socket operations + * + * Initially all sockets have unbounded timeouts. NSAPI_ERROR_WOULD_BLOCK + * is returned if a blocking operation takes longer than the specified + * timeout. A timeout of 0 removes a timeout from the socket. + * + * @param timeout Timeout in milliseconds */ void set_timeout(unsigned int timeout); - /* Set socket options - * @param level Option level - * @param optname Option identifier + /* Set stack-specific socket options + * + * The setsockopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. + * + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier * @param optval Option value * @param optlen Length of the option value - * @return 0 on success, negative on failure + * @return 0 on success, negative error code on failure */ int setsockopt(int level, int optname, const void *optval, unsigned optlen); - /* Get socket options - * @param level Option level - * @param optname Option identifier - * @param optval Buffer where to write option value + /* Get stack-specific socket options + * + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Destination for option value * @param optlen Length of the option value - * @return 0 on success, negative on failure + * @return 0 on success, negative error code on failure */ int getsockopt(int level, int optname, void *optval, unsigned *optlen); /** Register a callback on state change of the socket + * + * The specified callback will be called on state changes such as when + * the socket can recv/send/accept successfully and on when an error + * occurs. The callback may also be called spuriously without reason. + * + * The callback may be called in an interrupt context and should not + * perform expensive operations such as recv/send calls. + * * @param callback Function to call on state change - * @note Callback may be called in an interrupt context. - * The callback should not perform long operations - * such as recv or send calls. */ void attach(FunctionPointer callback); + /** Register a callback on state change of the socket + * + * The specified callback will be called on state changes such as when + * the socket can recv/send/accept successfully and on when an error + * occurs. The callback may also be called spuriously without reason. + * + * The callback may be called in an interrupt context and should not + * perform expensive operations such as recv/send calls. + * + * @param tptr Pointer to object to call method on + * @param mptr Method to call on state change + */ template void attach(T *tptr, M mptr) { attach(FunctionPointer(tptr, mptr)); diff --git a/net/NetworkSocketAPI/TCPServer.h b/net/NetworkSocketAPI/TCPServer.h index 59fbbac5fb..ec2e488316 100644 --- a/net/NetworkSocketAPI/TCPServer.h +++ b/net/NetworkSocketAPI/TCPServer.h @@ -21,31 +21,57 @@ #include "TCPSocket.h" #include "NetworkInterface.h" -/** TCP Server. +/** TCP socket server */ class TCPServer : public Socket { public: - /** TCP Server lifetime + /** Create an uninitialized socket + * + * Must call open to initialize the socket on a network stack. */ TCPServer(); - TCPServer(NetworkInterface *iface); - virtual ~TCPServer(); - /** Open the socket - * @param iface Interface to open socket on + /** Create a socket on a network stack + * + * Creates and opens a socket on the specified network stack. + * + * @param iface Network stack as target for socket + */ + TCPServer(NetworkInterface *iface); + + /** Opens a socket + * + * Creates a network socket on the specified network stack. + * Not needed if stack is passed to the socket's constructor. + * + * @param iface Network stack as target for socket + * @return 0 on success, negative error code on failure */ virtual int open(NetworkInterface *iface); - /** Start listening for incoming connections - * @param backlog Number of pending connections that can be queued up at any - * one time [Default: 1] - * @return 0 on success, negative on failure + /** Listen for connections on a TCP socket + * + * Marks the socket as a passive socket that can be used to accept + * incoming connections. + * + * @param backlog Number of pending connections that can be queued + * simultaneously, defaults to 1 + * @return 0 on success, negative error code on failure */ - int listen(int backlog=1); + int listen(int backlog = 1); - /** Accept a new connection. - * @param socket A TCPSocket instance that will handle the incoming connection. - * @return 0 on success, negative on failure. + /** Accepts a connection on a TCP socket + * + * The server socket must be bound and set to listen for connections. + * On a new connection, creates a network socket using the specified + * socket instance. + * + * By default, accept blocks until data is sent. If socket is set to + * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned + * immediately. + * + * @param socket TCPSocket instance that will handle the incoming connection. + * @return 0 on success, negative error code on failure */ int accept(TCPSocket *connection); }; diff --git a/net/NetworkSocketAPI/TCPSocket.h b/net/NetworkSocketAPI/TCPSocket.h index c6714feea9..f2501e22ee 100644 --- a/net/NetworkSocketAPI/TCPSocket.h +++ b/net/NetworkSocketAPI/TCPSocket.h @@ -24,41 +24,80 @@ */ class TCPSocket : public Socket { public: - /** TCP socket lifetime + /** Create an uninitialized socket + * + * Must call open to initialize the socket on a network stack. */ TCPSocket(); + + /** Create a socket on a network stack + * + * Creates and opens a socket on the specified network stack. + * + * @param iface Network stack as target for socket + */ TCPSocket(NetworkInterface *iface); - /** Open the socket - * @param iface Interface to open socket on + /** Opens a socket + * + * Creates a network socket on the specified network stack. + * Not needed if stack is passed to the socket's constructor. + * + * @param iface Network stack as target for socket + * @return 0 on success, negative error code on failure */ virtual int open(NetworkInterface *iface); - - /** Connects this TCP socket to the server - * @param host The host to connect to. It can either be an IP Address - * or a hostname that will be resolved with DNS - * @param port The host's port to connect to - * @return 0 on success, negative on failure + + /** Connects TCP socket to a remote host + * + * Initiates a connection to a remote server specified by either + * a domain name or an IP address and a port. + * + * @param host Host name of the remote host + * @param port Port of the remote host + * @return 0 on success, negative error code on failure */ int connect(const char *host, uint16_t port); - /** Connects this TCP socket to the server - * @param address SocketAddress to connect to - * @return 0 on success, negative on failure + /** Connects TCP socket to a remote host + * + * Initiates a connection to a remote server specified by the + * indicated address. + * + * @param address The SocketAddress of the remote host + * @return 0 on success, negative error code on failure */ int connect(const SocketAddress &address); - /** Send data to the remote host - * @param data The buffer to send to the host - * @param size The length of the buffer to send - * @return Number of written bytes on success, negative on failure + /** Send data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes sent from the buffer. + * + * By default, send blocks until data is sent. If socket is set to + * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned + * immediately. + * + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure */ int send(const void *data, unsigned size); - /** Receive data from the remote host - * @param data The buffer in which to store the data received from the host - * @param size The maximum length of the buffer - * @return Number of received bytes on success, negative on failure + /** Receive data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes received into the buffer. + * + * By default, recv blocks until data is sent. If socket is set to + * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned + * immediately. + * + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure */ int recv(void *data, unsigned size); diff --git a/net/NetworkSocketAPI/UDPSocket.h b/net/NetworkSocketAPI/UDPSocket.h index 4fecb7cf18..23c91c92f5 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -20,47 +20,86 @@ #include "Socket.h" #include "NetworkInterface.h" -/** UDP Socket +/** UDP socket */ class UDPSocket : public Socket { public: - /** UDPSocket lifetime + /** Create an uninitialized socket + * + * Must call open to initialize the socket on a network stack. */ UDPSocket(); + + /** Create a socket on a network stack + * + * Creates and opens a socket on the specified network stack. + * + * @param iface Network stack as target for socket + */ UDPSocket(NetworkInterface *iface); - /** Open the socket - * @param iface Interface to open socket on + /** Opens a socket + * + * Creates a network socket on the specified network stack. + * Not needed if stack is passed to the socket's constructor. + * + * @param iface Network stack as target for socket + * @return 0 on success, negative error code on failure */ virtual int open(NetworkInterface *iface); - /** Send a packet to a remote endpoint - * @param host The host to connect to. It can either be an IP Address - * or a hostname that will be resolved with DNS - * @param port The remote port - * @param data The packet to be sent - * @param size The length of the packet to be sent - * @return The number of written bytes on success, negative on failure + /** Send a packet over a UDP socket + * + * Sends data to the specified address specified by either a domain name + * or an IP address and port. Returns the number of bytes sent from the + * buffer. + * + * By default, sendto blocks until data is sent. If socket is set to + * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned + * immediately. + * + * @param host Host name of the remote host + * @param port Port of the remote host + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure */ int sendto(const char *host, uint16_t port, const void *data, unsigned size); - /** Send a packet to a remote endpoint - * @param address The remote SocketAddress - * @param data The packet to be sent - * @param size The length of the packet to be sent - * @return The number of written bytes on success, negative on failure + /** Send a packet over a UDP socket + * + * Sends data to the specified address. Returns the number of bytes + * sent from the buffer. + * + * By default, sendto blocks until data is sent. If socket is set to + * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned + * immediately. + * + * @param address The SocketAddress of the remote host + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure */ int sendto(const SocketAddress &address, const void *data, unsigned size); - /** Receive a packet from a remote endpoint - * @param address Destination for the remote SocketAddress or null - * @param buffer The buffer for storing the incoming packet data - * If a packet is too long to fit in the supplied buffer, - * excess bytes are discarded - * @param size The length of the buffer - * @return The number of received bytes on success, negative on failure + /** Receive a packet over a UDP socket + * + * Receives data and stores the source address in address if address + * is not NULL. Returns the number of bytes received into the buffer. + * + * By default, recvfrom blocks until data is sent. If socket is set to + * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned + * immediately. + * + * @param address Destination for the source address or NULL + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure */ - int recvfrom(SocketAddress *address, void *buffer, unsigned size); + int recvfrom(SocketAddress *address, void *data, unsigned size); }; #endif From 55f7d29fc347d95b5ef2fd13130b88055fbb3c4f Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Apr 2016 17:51:51 -0500 Subject: [PATCH 18/33] Revised documentation for Interface classes --- net/NetworkSocketAPI/CellularInterface.h | 45 ++++++++++++++++ net/NetworkSocketAPI/EthernetInterface.h | 11 ++-- net/NetworkSocketAPI/MeshInterface.h | 7 ++- net/NetworkSocketAPI/NetworkInterface.h | 21 ++++---- net/NetworkSocketAPI/SocketAddress.h | 69 +++++++++++++++--------- net/NetworkSocketAPI/TCPServer.h | 2 +- net/NetworkSocketAPI/TCPSocket.h | 4 +- net/NetworkSocketAPI/UDPSocket.h | 4 +- net/NetworkSocketAPI/WiFiInterface.h | 19 +++++-- 9 files changed, 134 insertions(+), 48 deletions(-) create mode 100644 net/NetworkSocketAPI/CellularInterface.h diff --git a/net/NetworkSocketAPI/CellularInterface.h b/net/NetworkSocketAPI/CellularInterface.h new file mode 100644 index 0000000000..a65ac62012 --- /dev/null +++ b/net/NetworkSocketAPI/CellularInterface.h @@ -0,0 +1,45 @@ +/* CellularInterface + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CELLULAR_INTERFACE_H +#define CELLULAR_INTERFACE_H + +#include "NetworkInterface.h" + +/** CellularInterface class + * + * Common interface that is shared between ethernet hardware + */ +class CellularInterface : public NetworkInterface +{ +public: + /** Start the interface + * + * @param apn Optional name of the network to connect to + * @param username Optional username for your APN + * @param password Optional password for your APN + * @return 0 on success, negative error code on failure + */ + virtual int connect(const char *apn = 0, const char *username = 0, const char *password = 0) = 0; + + /** Stop the interface + * + * @return 0 on success, negative error code on failure + */ + virtual int disconnect() = 0; +}; + +#endif diff --git a/net/NetworkSocketAPI/EthernetInterface.h b/net/NetworkSocketAPI/EthernetInterface.h index a48846f650..8fce3082d0 100644 --- a/net/NetworkSocketAPI/EthernetInterface.h +++ b/net/NetworkSocketAPI/EthernetInterface.h @@ -1,4 +1,4 @@ -/* Socket +/* EthernetInterface * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,18 +20,21 @@ #include "NetworkInterface.h" /** EthernetInterface class - * Common interface that is shared between ethernet hardware + * + * Common interface that is shared between ethernet hardware. */ class EthernetInterface : public NetworkInterface { public: /** Start the interface - * @return 0 on success, negative on failure + * + * @return 0 on success, negative error code on failure */ virtual int connect() = 0; /** Stop the interface - * @return 0 on success, negative on failure + * + * @return 0 on success, negative error code on failure */ virtual int disconnect() = 0; }; diff --git a/net/NetworkSocketAPI/MeshInterface.h b/net/NetworkSocketAPI/MeshInterface.h index 884708a623..0b1f598a00 100644 --- a/net/NetworkSocketAPI/MeshInterface.h +++ b/net/NetworkSocketAPI/MeshInterface.h @@ -1,4 +1,4 @@ -/* Socket +/* MeshInterface * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,17 +20,20 @@ #include "NetworkInterface.h" /** MeshInterface class - * Common interface that is shared between ethernet hardware + * + * Common interface that is shared between mesh hardware */ class MeshInterface : public NetworkInterface { public: /** Start the interface + * * @return 0 on success, negative on failure */ virtual int connect() = 0; /** Stop the interface + * * @return 0 on success, negative on failure */ virtual int disconnect() = 0; diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index f15a2c16cb..1f35571d6e 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -46,7 +46,7 @@ enum nsapi_error_t { * The socket protocol specifies a particular protocol to * be used with a newly created socket. * - * @enum protocol_t + * @enum nsapi_protocol_t */ enum nsapi_protocol_t { NSAPI_TCP, /*!< Socket is of TCP type */ @@ -74,26 +74,29 @@ class NetworkInterface public: virtual ~NetworkInterface() {}; - /** Get the internally stored IP address + /** Get the local IP address * - * @return IP address of the interface or null if not yet connected + * @return Null-terminated representation of the local IP address + * or null if not yet connected */ virtual const char *get_ip_address() = 0; - /** Get the internally stored MAC address + /** Get the local MAC address * - * @return MAC address of the interface + * @return Null-terminated representation of the local MAC address */ virtual const char *get_mac_address() = 0; - /** Translates a host name to an IP address + /** Translates a hostname to an IP address * - * The host name may be either a domain name or an IP address. - * If no stack-specific DNS resolution is provided, the host name + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname * will be resolve using a UDP socket on the stack. * * @param address Destination for the host SocketAddress - * @param host Host name to lookup + * @param host Hostname to resolve * @return 0 on success, negative error code on failure */ virtual int gethostbyname(SocketAddress *address, const char *host); diff --git a/net/NetworkSocketAPI/SocketAddress.h b/net/NetworkSocketAPI/SocketAddress.h index 1f93177b5e..4e68053265 100644 --- a/net/NetworkSocketAPI/SocketAddress.h +++ b/net/NetworkSocketAPI/SocketAddress.h @@ -1,4 +1,4 @@ -/* Socket +/* SocketAddress * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,8 +28,11 @@ */ #define NSAPI_IP_BYTES NSAPI_IPv6_BYTES -/** Enum of address families - * @enum nsapi_family_t +/** Enum of IP address versions + * + * The IP version specifies the type of an IP address. + * + * @enum nsapi_version_t */ enum nsapi_version_t { NSAPI_IPv4, /*!< Address is IPv4 */ @@ -56,74 +59,92 @@ enum nsapi_version_t { class NetworkInterface; -/** A general address class composed of the IP address and optional port +/** SocketAddress class + * + * Representation of an IP address and port pair. */ class SocketAddress { public: - /** SocketAddress construction using DNS resolution - * @param iface NetworkInterface to use for DNS resolution - * @param addr Null-terminated hostname that will be resolved + /** Create a SocketAddress from a hostname and port + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * On failure, the IP address and port will be set to zero + * + * @param iface Network stack to use for DNS resolution + * @param host Hostname to resolve * @param port Optional 16-bit port - * @note on failure, IP address and port will be set to zero */ - SocketAddress(NetworkInterface *iface, const char *addr, uint16_t port = 0); + SocketAddress(NetworkInterface *iface, const char *host, uint16_t port = 0); - /** SocketAddress construction - * @param addr Null-terminated IP address + /** Create a SocketAddress from an IP address and port + * + * @param host Null-terminated representation of the IP address * @param port Optional 16-bit port */ SocketAddress(const char *addr = 0, uint16_t port = 0); - /** SocketAddress construction - * @param bytes Bytes to assign to address in big-endian order + /** Create a SocketAddress from a raw IP address and port + * + * @param bytes Raw IP address in big-endian order * @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6 * @param port Optional 16-bit port */ SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port = 0); - /** SocketAddress construction - * @param addr SocketAddress to copy + /** Create a SocketAddress from another SocketAddress + * + * @param address SocketAddress to copy */ SocketAddress(const SocketAddress &addr); /** Set the IP address - * @param addr Null-terminated string representing the IP address + * + * @param addr Null-terminated represention of the IP address */ void set_ip_address(const char *addr); - /** Set the IP address bytes directly - * @param bytes Bytes to assign to address in big-endian order + /** Set the raw IP address + * + * @param bytes Raw IP address in big-endian order * @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6 */ void set_ip_bytes(const void *bytes, nsapi_version_t version); /** Set the port + * * @param port 16-bit port */ void set_port(uint16_t port); /** Get the IP address - * @return The string representation of the IP Address + * + * @return Null-terminated representation of the IP Address */ const char *get_ip_address() const; - /** Get the IP address bytes directly - * @return IP address bytes + /** Get the raw IP address + * + * @return Raw IP address in big-endian order */ const void *get_ip_bytes() const; - /** Get the type of the IP address + /** Get the IP address version + * * @return IP address version, NSAPI_IPv4 or NSAPI_IPv6 */ nsapi_version_t get_ip_version() const; /** Get the port + * * @return The 16-bit port */ uint16_t get_port() const; - /** Determine if address is all zeros - * @return True if address is not zero address + /** Test if address is zero + * + * @return True if address is not zero */ operator bool() const; diff --git a/net/NetworkSocketAPI/TCPServer.h b/net/NetworkSocketAPI/TCPServer.h index ec2e488316..619056369c 100644 --- a/net/NetworkSocketAPI/TCPServer.h +++ b/net/NetworkSocketAPI/TCPServer.h @@ -1,4 +1,4 @@ -/* Socket +/* TCPServer * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/net/NetworkSocketAPI/TCPSocket.h b/net/NetworkSocketAPI/TCPSocket.h index f2501e22ee..834b064015 100644 --- a/net/NetworkSocketAPI/TCPSocket.h +++ b/net/NetworkSocketAPI/TCPSocket.h @@ -1,4 +1,4 @@ -/* Socket +/* TCPSocket * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -53,7 +53,7 @@ public: * Initiates a connection to a remote server specified by either * a domain name or an IP address and a port. * - * @param host Host name of the remote host + * @param host Hostname of the remote host * @param port Port of the remote host * @return 0 on success, negative error code on failure */ diff --git a/net/NetworkSocketAPI/UDPSocket.h b/net/NetworkSocketAPI/UDPSocket.h index 23c91c92f5..74f8c4a340 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -1,4 +1,4 @@ -/* Socket +/* UDPSocket * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -58,7 +58,7 @@ public: * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned * immediately. * - * @param host Host name of the remote host + * @param host Hostname of the remote host * @param port Port of the remote host * @param data Buffer of data to send to the host * @param size Size of the buffer in bytes diff --git a/net/NetworkSocketAPI/WiFiInterface.h b/net/NetworkSocketAPI/WiFiInterface.h index 21fa397a66..1a9e267e0b 100644 --- a/net/NetworkSocketAPI/WiFiInterface.h +++ b/net/NetworkSocketAPI/WiFiInterface.h @@ -1,4 +1,4 @@ -/* Socket +/* WiFiInterface * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,12 @@ #include "NetworkInterface.h" -/** Enum for WiFi encryption types +/** Enum of WiFi encryption types + * + * The security type specifies a particular security to use when + * connected to a WiFi network + * + * @enum nsapi_protocol_t */ enum nsapi_security_t { NSAPI_SECURITY_NONE = 0, /*!< open access point */ @@ -29,21 +34,27 @@ enum nsapi_security_t { }; /** WiFiInterface class + * * Common interface that is shared between WiFi devices */ class WiFiInterface : public NetworkInterface { public: /** Start the interface + * + * Attempts to connect to a WiFi network. If passphrase is invalid, + * NSAPI_ERROR_AUTH_ERROR is returned. + * * @param ssid Name of the network to connect to * @param pass Security passphrase to connect to the network * @param security Type of encryption for connection - * @return 0 on success, negative on failure + * @return 0 on success, negative error code on failure */ virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE) = 0; /** Stop the interface - * @return 0 on success, negative on failure + * + * @return 0 on success, negative error code on failure */ virtual int disconnect() = 0; }; From 16929af278523f636be6c7d42b1020164fc42e53 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Apr 2016 18:07:43 -0500 Subject: [PATCH 19/33] Rename Interface -> Stack NetworkInterface -> NetworkStack EthernetInterface -> EthernetStack WiFiInterface -> WiFiStack CellularInterface -> CellularStack MeshInterface -> MeshStack --- net/ESP8266Interface/ESP8266Interface.h | 6 +++--- net/LWIPInterface/LWIPInterface.h | 6 +++--- net/LWIPInterface/eth_arch.h | 2 +- .../{CellularInterface.h => CellularStack.h} | 8 ++++---- net/NetworkSocketAPI/DnsQuery/DnsQuery.cpp | 2 +- net/NetworkSocketAPI/DnsQuery/DnsQuery.h | 4 ++-- .../{EthernetInterface.h => EthernetStack.h} | 8 ++++---- net/NetworkSocketAPI/{MeshInterface.h => MeshStack.h} | 8 ++++---- .../{NetworkInterface.cpp => NetworkStack.cpp} | 10 +++++----- .../{NetworkInterface.h => NetworkStack.h} | 10 +++++----- net/NetworkSocketAPI/Socket.cpp | 2 +- net/NetworkSocketAPI/Socket.h | 8 ++++---- net/NetworkSocketAPI/SocketAddress.cpp | 4 ++-- net/NetworkSocketAPI/SocketAddress.h | 4 ++-- net/NetworkSocketAPI/TCPServer.cpp | 4 ++-- net/NetworkSocketAPI/TCPServer.h | 6 +++--- net/NetworkSocketAPI/TCPSocket.cpp | 4 ++-- net/NetworkSocketAPI/TCPSocket.h | 6 +++--- net/NetworkSocketAPI/UDPSocket.cpp | 4 ++-- net/NetworkSocketAPI/UDPSocket.h | 6 +++--- net/NetworkSocketAPI/{WiFiInterface.h => WiFiStack.h} | 8 ++++---- 21 files changed, 60 insertions(+), 60 deletions(-) rename net/NetworkSocketAPI/{CellularInterface.h => CellularStack.h} (90%) rename net/NetworkSocketAPI/{EthernetInterface.h => EthernetStack.h} (88%) rename net/NetworkSocketAPI/{MeshInterface.h => MeshStack.h} (89%) rename net/NetworkSocketAPI/{NetworkInterface.cpp => NetworkStack.cpp} (67%) rename net/NetworkSocketAPI/{NetworkInterface.h => NetworkStack.h} (98%) rename net/NetworkSocketAPI/{WiFiInterface.h => WiFiStack.h} (94%) diff --git a/net/ESP8266Interface/ESP8266Interface.h b/net/ESP8266Interface/ESP8266Interface.h index 04efed53e0..e6d64fae8b 100644 --- a/net/ESP8266Interface/ESP8266Interface.h +++ b/net/ESP8266Interface/ESP8266Interface.h @@ -17,15 +17,15 @@ #ifndef ESP8266_INTERFACE_H #define ESP8266_INTERFACE_H -#include "WiFiInterface.h" +#include "WiFiStack.h" #include "ESP8266.h" #define ESP8266_SOCKET_COUNT 5 /** ESP8266Interface class - * Implementation of the NetworkInterface for the ESP8266 + * Implementation of the NetworkStack for the ESP8266 */ -class ESP8266Interface : public WiFiInterface +class ESP8266Interface : public WiFiStack { public: /** ESP8266Interface lifetime diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index 4b0331c1db..5bb3a59221 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -17,15 +17,15 @@ #ifndef LWIP_INTERFACE_H #define LWIP_INTERFACE_H -#include "EthernetInterface.h" +#include "EthernetStack.h" #include "rtos.h" #include "lwip/netif.h" /** LWIPInterface class - * Implementation of the NetworkInterface for LWIP + * Implementation of the NetworkStack for LWIP */ -class LWIPInterface : public EthernetInterface +class LWIPInterface : public EthernetStack { public: /** Start the interface diff --git a/net/LWIPInterface/eth_arch.h b/net/LWIPInterface/eth_arch.h index 1ff54b1d38..850d65e4ef 100644 --- a/net/LWIPInterface/eth_arch.h +++ b/net/LWIPInterface/eth_arch.h @@ -1,4 +1,4 @@ -/* EthernetInterface.h */ +/* EthernetStack.h */ /* Copyright (C) 2012 mbed.org, MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software diff --git a/net/NetworkSocketAPI/CellularInterface.h b/net/NetworkSocketAPI/CellularStack.h similarity index 90% rename from net/NetworkSocketAPI/CellularInterface.h rename to net/NetworkSocketAPI/CellularStack.h index a65ac62012..da96cafedb 100644 --- a/net/NetworkSocketAPI/CellularInterface.h +++ b/net/NetworkSocketAPI/CellularStack.h @@ -1,4 +1,4 @@ -/* CellularInterface +/* CellularStack * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,13 +17,13 @@ #ifndef CELLULAR_INTERFACE_H #define CELLULAR_INTERFACE_H -#include "NetworkInterface.h" +#include "NetworkStack.h" -/** CellularInterface class +/** CellularStack class * * Common interface that is shared between ethernet hardware */ -class CellularInterface : public NetworkInterface +class CellularStack : public NetworkStack { public: /** Start the interface diff --git a/net/NetworkSocketAPI/DnsQuery/DnsQuery.cpp b/net/NetworkSocketAPI/DnsQuery/DnsQuery.cpp index e940e34694..2c209f529e 100644 --- a/net/NetworkSocketAPI/DnsQuery/DnsQuery.cpp +++ b/net/NetworkSocketAPI/DnsQuery/DnsQuery.cpp @@ -185,7 +185,7 @@ static int32_t query(UDPSocket *socket, const SocketAddress &addr, const char *h return NSAPI_ERROR_DNS_FAILURE; } -int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip) +int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip) { if (isIP(host)) { strcpy(ip, host); diff --git a/net/NetworkSocketAPI/DnsQuery/DnsQuery.h b/net/NetworkSocketAPI/DnsQuery/DnsQuery.h index 6e1e6265b7..3c5dfa7d70 100644 --- a/net/NetworkSocketAPI/DnsQuery/DnsQuery.h +++ b/net/NetworkSocketAPI/DnsQuery/DnsQuery.h @@ -18,7 +18,7 @@ #ifndef __DNSQUERY_H__ #define __DNSQUERY_H__ -#include "NetworkInterface.h" +#include "NetworkStack.h" #include "UDPSocket.h" @@ -34,7 +34,7 @@ * @returns 0 on succes, NS_DNS_FAILURE if host is not found, * or a negative value for other errors. */ -int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip); +int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip); int32_t dnsQuery(UDPSocket *sock, const char *host, char *ip); diff --git a/net/NetworkSocketAPI/EthernetInterface.h b/net/NetworkSocketAPI/EthernetStack.h similarity index 88% rename from net/NetworkSocketAPI/EthernetInterface.h rename to net/NetworkSocketAPI/EthernetStack.h index 8fce3082d0..061648af14 100644 --- a/net/NetworkSocketAPI/EthernetInterface.h +++ b/net/NetworkSocketAPI/EthernetStack.h @@ -1,4 +1,4 @@ -/* EthernetInterface +/* EthernetStack * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,13 +17,13 @@ #ifndef ETHERNET_INTERFACE_H #define ETHERNET_INTERFACE_H -#include "NetworkInterface.h" +#include "NetworkStack.h" -/** EthernetInterface class +/** EthernetStack class * * Common interface that is shared between ethernet hardware. */ -class EthernetInterface : public NetworkInterface +class EthernetStack : public NetworkStack { public: /** Start the interface diff --git a/net/NetworkSocketAPI/MeshInterface.h b/net/NetworkSocketAPI/MeshStack.h similarity index 89% rename from net/NetworkSocketAPI/MeshInterface.h rename to net/NetworkSocketAPI/MeshStack.h index 0b1f598a00..cdb4360700 100644 --- a/net/NetworkSocketAPI/MeshInterface.h +++ b/net/NetworkSocketAPI/MeshStack.h @@ -1,4 +1,4 @@ -/* MeshInterface +/* MeshStack * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,13 +17,13 @@ #ifndef MESH_INTERFACE_H #define MESH_INTERFACE_H -#include "NetworkInterface.h" +#include "NetworkStack.h" -/** MeshInterface class +/** MeshStack class * * Common interface that is shared between mesh hardware */ -class MeshInterface : public NetworkInterface +class MeshStack : public NetworkStack { public: /** Start the interface diff --git a/net/NetworkSocketAPI/NetworkInterface.cpp b/net/NetworkSocketAPI/NetworkStack.cpp similarity index 67% rename from net/NetworkSocketAPI/NetworkInterface.cpp rename to net/NetworkSocketAPI/NetworkStack.cpp index a39fdc7c43..1b70dd6551 100644 --- a/net/NetworkSocketAPI/NetworkInterface.cpp +++ b/net/NetworkSocketAPI/NetworkStack.cpp @@ -17,7 +17,7 @@ #include "DnsQuery.h" #include "mbed.h" -int NetworkInterface::gethostbyname(SocketAddress *address, const char *name) +int NetworkStack::gethostbyname(SocketAddress *address, const char *name) { char buffer[NSAPI_IP_SIZE]; int err = dnsQuery(this, name, buffer); @@ -29,22 +29,22 @@ int NetworkInterface::gethostbyname(SocketAddress *address, const char *name) return 0; } -int NetworkInterface::setstackopt(int level, int optname, const void *optval, unsigned optlen) +int NetworkStack::setstackopt(int level, int optname, const void *optval, unsigned optlen) { return NSAPI_ERROR_UNSUPPORTED; } -int NetworkInterface::getstackopt(int level, int optname, void *optval, unsigned *optlen) +int NetworkStack::getstackopt(int level, int optname, void *optval, unsigned *optlen) { return NSAPI_ERROR_UNSUPPORTED; } -int NetworkInterface::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen) +int NetworkStack::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen) { return NSAPI_ERROR_UNSUPPORTED; } -int NetworkInterface::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen) +int NetworkStack::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen) { return NSAPI_ERROR_UNSUPPORTED; } diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkStack.h similarity index 98% rename from net/NetworkSocketAPI/NetworkInterface.h rename to net/NetworkSocketAPI/NetworkStack.h index 1f35571d6e..37306e6c19 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkStack.h @@ -1,4 +1,4 @@ -/* NetworkInterface +/* NetworkStack * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -62,17 +62,17 @@ enum nsapi_protocol_t { #define NSAPI_MAC_BYTES 6 -/** NetworkInterface class +/** NetworkStack class * * Common interface that is shared between hardware that * can connect to a network over IP. By implementing the - * NetworkInterface, a network stack can be used as a target + * NetworkStack, a network stack can be used as a target * for instantiating network sockets. */ -class NetworkInterface +class NetworkStack { public: - virtual ~NetworkInterface() {}; + virtual ~NetworkStack() {}; /** Get the local IP address * diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index e291f7e1a5..aa8a47023c 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -31,7 +31,7 @@ Socket::~Socket() } } -int Socket::open(NetworkInterface *iface, nsapi_protocol_t proto) +int Socket::open(NetworkStack *iface, nsapi_protocol_t proto) { _iface = iface; diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index 612360e927..ab093e39d3 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -18,7 +18,7 @@ #define SOCKET_H #include "SocketAddress.h" -#include "NetworkInterface.h" +#include "NetworkStack.h" /** Abstract socket class */ @@ -38,7 +38,7 @@ public: * @param iface Network stack as target for socket * @return 0 on success, negative error code on failure */ - virtual int open(NetworkInterface *iface) = 0; + virtual int open(NetworkStack *iface) = 0; /** Close the socket * @@ -160,11 +160,11 @@ public: protected: Socket(); - int open(NetworkInterface *iface, nsapi_protocol_t proto); + int open(NetworkStack *iface, nsapi_protocol_t proto); static void thunk(void *); - NetworkInterface *_iface; + NetworkStack *_iface; void *_socket; bool _blocking; unsigned _timeout; diff --git a/net/NetworkSocketAPI/SocketAddress.cpp b/net/NetworkSocketAPI/SocketAddress.cpp index f8446ea349..f238c883d8 100644 --- a/net/NetworkSocketAPI/SocketAddress.cpp +++ b/net/NetworkSocketAPI/SocketAddress.cpp @@ -15,7 +15,7 @@ */ #include "SocketAddress.h" -#include "NetworkInterface.h" +#include "NetworkStack.h" #include #include "mbed.h" @@ -126,7 +126,7 @@ static void ipv6_to_address(char *addr, const uint8_t *bytes) } -SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t port) +SocketAddress::SocketAddress(NetworkStack *iface, const char *host, uint16_t port) { // Check for valid IP addresses if (host && ipv4_is_valid(host)) { diff --git a/net/NetworkSocketAPI/SocketAddress.h b/net/NetworkSocketAPI/SocketAddress.h index 4e68053265..5d71e2678e 100644 --- a/net/NetworkSocketAPI/SocketAddress.h +++ b/net/NetworkSocketAPI/SocketAddress.h @@ -56,7 +56,7 @@ enum nsapi_version_t { #define NSAPI_IPv6_BYTES 16 // Predeclared classes -class NetworkInterface; +class NetworkStack; /** SocketAddress class @@ -76,7 +76,7 @@ public: * @param host Hostname to resolve * @param port Optional 16-bit port */ - SocketAddress(NetworkInterface *iface, const char *host, uint16_t port = 0); + SocketAddress(NetworkStack *iface, const char *host, uint16_t port = 0); /** Create a SocketAddress from an IP address and port * diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index 6c513f4be0..83a85d66b4 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -21,12 +21,12 @@ TCPServer::TCPServer() { } -TCPServer::TCPServer(NetworkInterface *iface) +TCPServer::TCPServer(NetworkStack *iface) { open(iface); } -int TCPServer::open(NetworkInterface *iface) +int TCPServer::open(NetworkStack *iface) { return Socket::open(iface, NSAPI_TCP); } diff --git a/net/NetworkSocketAPI/TCPServer.h b/net/NetworkSocketAPI/TCPServer.h index 619056369c..0bb7d15a01 100644 --- a/net/NetworkSocketAPI/TCPServer.h +++ b/net/NetworkSocketAPI/TCPServer.h @@ -19,7 +19,7 @@ #include "Socket.h" #include "TCPSocket.h" -#include "NetworkInterface.h" +#include "NetworkStack.h" /** TCP socket server */ @@ -37,7 +37,7 @@ public: * * @param iface Network stack as target for socket */ - TCPServer(NetworkInterface *iface); + TCPServer(NetworkStack *iface); /** Opens a socket * @@ -47,7 +47,7 @@ public: * @param iface Network stack as target for socket * @return 0 on success, negative error code on failure */ - virtual int open(NetworkInterface *iface); + virtual int open(NetworkStack *iface); /** Listen for connections on a TCP socket * diff --git a/net/NetworkSocketAPI/TCPSocket.cpp b/net/NetworkSocketAPI/TCPSocket.cpp index a837f29fe2..b59715594c 100644 --- a/net/NetworkSocketAPI/TCPSocket.cpp +++ b/net/NetworkSocketAPI/TCPSocket.cpp @@ -21,12 +21,12 @@ TCPSocket::TCPSocket() { } -TCPSocket::TCPSocket(NetworkInterface *iface) +TCPSocket::TCPSocket(NetworkStack *iface) { open(iface); } -int TCPSocket::open(NetworkInterface *iface) +int TCPSocket::open(NetworkStack *iface) { return Socket::open(iface, NSAPI_TCP); } diff --git a/net/NetworkSocketAPI/TCPSocket.h b/net/NetworkSocketAPI/TCPSocket.h index 834b064015..2a37f776fb 100644 --- a/net/NetworkSocketAPI/TCPSocket.h +++ b/net/NetworkSocketAPI/TCPSocket.h @@ -18,7 +18,7 @@ #define TCPSOCKET_H #include "Socket.h" -#include "NetworkInterface.h" +#include "NetworkStack.h" /** TCP socket connection */ @@ -36,7 +36,7 @@ public: * * @param iface Network stack as target for socket */ - TCPSocket(NetworkInterface *iface); + TCPSocket(NetworkStack *iface); /** Opens a socket * @@ -46,7 +46,7 @@ public: * @param iface Network stack as target for socket * @return 0 on success, negative error code on failure */ - virtual int open(NetworkInterface *iface); + virtual int open(NetworkStack *iface); /** Connects TCP socket to a remote host * diff --git a/net/NetworkSocketAPI/UDPSocket.cpp b/net/NetworkSocketAPI/UDPSocket.cpp index 9177de60c8..85569c7a58 100644 --- a/net/NetworkSocketAPI/UDPSocket.cpp +++ b/net/NetworkSocketAPI/UDPSocket.cpp @@ -21,12 +21,12 @@ UDPSocket::UDPSocket() { } -UDPSocket::UDPSocket(NetworkInterface *iface) +UDPSocket::UDPSocket(NetworkStack *iface) { open(iface); } -int UDPSocket::open(NetworkInterface *iface) +int UDPSocket::open(NetworkStack *iface) { return Socket::open(iface, NSAPI_UDP); } diff --git a/net/NetworkSocketAPI/UDPSocket.h b/net/NetworkSocketAPI/UDPSocket.h index 74f8c4a340..b2a8454d9f 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -18,7 +18,7 @@ #define UDPSOCKET_H #include "Socket.h" -#include "NetworkInterface.h" +#include "NetworkStack.h" /** UDP socket */ @@ -36,7 +36,7 @@ public: * * @param iface Network stack as target for socket */ - UDPSocket(NetworkInterface *iface); + UDPSocket(NetworkStack *iface); /** Opens a socket * @@ -46,7 +46,7 @@ public: * @param iface Network stack as target for socket * @return 0 on success, negative error code on failure */ - virtual int open(NetworkInterface *iface); + virtual int open(NetworkStack *iface); /** Send a packet over a UDP socket * diff --git a/net/NetworkSocketAPI/WiFiInterface.h b/net/NetworkSocketAPI/WiFiStack.h similarity index 94% rename from net/NetworkSocketAPI/WiFiInterface.h rename to net/NetworkSocketAPI/WiFiStack.h index 1a9e267e0b..f5a2ef632b 100644 --- a/net/NetworkSocketAPI/WiFiInterface.h +++ b/net/NetworkSocketAPI/WiFiStack.h @@ -1,4 +1,4 @@ -/* WiFiInterface +/* WiFiStack * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ #ifndef WIFI_INTERFACE_H #define WIFI_INTERFACE_H -#include "NetworkInterface.h" +#include "NetworkStack.h" /** Enum of WiFi encryption types * @@ -33,11 +33,11 @@ enum nsapi_security_t { NSAPI_SECURITY_WPA2, /*!< phrase conforms to WPA2 */ }; -/** WiFiInterface class +/** WiFiStack class * * Common interface that is shared between WiFi devices */ -class WiFiInterface : public NetworkInterface +class WiFiStack : public NetworkStack { public: /** Start the interface From f4526e5b733ac8d856ae42a3483ca926fa58d0b9 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 19 Apr 2016 20:43:18 -0500 Subject: [PATCH 20/33] Fix race condition in socket close --- net/NetworkSocketAPI/Socket.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index aa8a47023c..f2eeb14f1e 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -53,7 +53,9 @@ int Socket::close() return 0; } - void *socket = _socket; + _iface->socket_attach(_socket, 0, 0); + + void *volatile socket = _socket; _socket = 0; return _iface->socket_close(socket); } From 57de57efc57023102b175883f8cdae755ba29a51 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Wed, 20 Apr 2016 11:31:58 -0500 Subject: [PATCH 21/33] Update libraries to match the latest NSAPI Update the library references for mbed-client-classic and sal-iface-6lowpan-morpheus-private. --- net/mbed-client-classic.lib | 2 +- net/sal-iface-6lowpan-morpheus-private.lib | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mbed-client-classic.lib b/net/mbed-client-classic.lib index d016f7d813..4e6ea87e68 100644 --- a/net/mbed-client-classic.lib +++ b/net/mbed-client-classic.lib @@ -1 +1 @@ -https://github.com/ARMmbed/mbed-client-classic.git/#0cf03c143a2a +https://github.com/ARMmbed/mbed-client-classic.git/#31381dfcd9d6 diff --git a/net/sal-iface-6lowpan-morpheus-private.lib b/net/sal-iface-6lowpan-morpheus-private.lib index 36e7ef81d8..df6a7af1ac 100644 --- a/net/sal-iface-6lowpan-morpheus-private.lib +++ b/net/sal-iface-6lowpan-morpheus-private.lib @@ -1 +1 @@ -https://github.com/ARMmbed/sal-iface-6lowpan-morpheus-private-mirror.git/#2b4852e22679 +https://github.com/ARMmbed/sal-iface-6lowpan-morpheus-private-mirror.git/#baeb2fcf3ce4 From 893dfec7e6a96d3349ad8180dc780dbf19497216 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Apr 2016 03:22:31 -0500 Subject: [PATCH 22/33] Added workaround for bug in newlib sscanf https://bugs.launchpad.net/gcc-arm-embedded/+bug/1399224 --- net/NetworkSocketAPI/SocketAddress.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/net/NetworkSocketAPI/SocketAddress.cpp b/net/NetworkSocketAPI/SocketAddress.cpp index f238c883d8..933f851731 100644 --- a/net/NetworkSocketAPI/SocketAddress.cpp +++ b/net/NetworkSocketAPI/SocketAddress.cpp @@ -56,7 +56,23 @@ static bool ipv6_is_valid(const char *addr) static void ipv4_from_address(uint8_t *bytes, const char *addr) { - sscanf(addr, "%hhu.%hhu.%hhu.%hhu", &bytes[0], &bytes[1], &bytes[2], &bytes[3]); + int count = 0; + int i = 0; + + for (; count < NSAPI_IPv4_BYTES; count++) { + int scanned = sscanf(&addr[i], "%hhu", &bytes[count]); + if (scanned < 1) { + return; + } + + for (; addr[i] != '.'; i++) { + if (!addr[i]) { + return; + } + } + + i++; + } } static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) { From 49ba2be3a7935628000a84ae33bc3f4a0240ade2 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Apr 2016 03:23:58 -0500 Subject: [PATCH 23/33] Add standardized stack options --- net/NetworkSocketAPI/NetworkStack.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/net/NetworkSocketAPI/NetworkStack.h b/net/NetworkSocketAPI/NetworkStack.h index 37306e6c19..6ce6995bbc 100644 --- a/net/NetworkSocketAPI/NetworkStack.h +++ b/net/NetworkSocketAPI/NetworkStack.h @@ -53,6 +53,30 @@ enum nsapi_protocol_t { NSAPI_UDP, /*!< Socket is of UDP type */ }; +/* Enum of standardized stack option levels + * + * @enum nsapi_level_t + */ +enum nsapi_level_t { + NSAPI_STACK, /*!< Stack option level */ + NSAPI_SOCKET, /*!< Socket option level */ +}; + +/* Enum of standardized stack options + * + * These options may not be supported on all stacks, in which + * case NSAPI_ERROR_UNSUPPORTED may be returned from setsockopt. + * + * @enum nsapi_option_t + */ +enum nsapi_option_t { + NSAPI_REUSEADDR, /*!< Allow bind to reuse local addresses */ + NSAPI_KEEPALIVE, /*!< Enables sending of keepalive messages */ + NSAPI_LINGER, /*!< Keeps close from returning until queues empty */ + NSAPI_SNDBUF, /*!< Sets send buffer size */ + NSAPI_RCVBUF, /*!< Sets recv buffer size */ +}; + /** Maximum size of MAC address representation */ #define NSAPI_MAC_SIZE 18 From d17fa4faad75864b13646e88c8724d9cbe8be8e7 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Apr 2016 14:39:13 -0500 Subject: [PATCH 24/33] Separate Stack/Interface concept into two distinct classes --- net/ESP8266Interface/ESP8266Interface.h | 4 ++-- net/LWIPInterface/LWIPInterface.h | 4 ++-- .../{CellularStack.h => CellularInterface.h} | 12 +++++++++--- .../{EthernetStack.h => EthernetInterface.h} | 12 +++++++++--- .../{MeshStack.h => MeshInterface.h} | 12 +++++++++--- net/NetworkSocketAPI/NetworkStack.h | 14 -------------- net/NetworkSocketAPI/Socket.cpp | 4 ++-- net/NetworkSocketAPI/SocketAddress.h | 8 ++++++++ .../{WiFiStack.h => WiFiInterface.h} | 12 +++++++++--- 9 files changed, 50 insertions(+), 32 deletions(-) rename net/NetworkSocketAPI/{CellularStack.h => CellularInterface.h} (84%) rename net/NetworkSocketAPI/{EthernetStack.h => EthernetInterface.h} (80%) rename net/NetworkSocketAPI/{MeshStack.h => MeshInterface.h} (81%) rename net/NetworkSocketAPI/{WiFiStack.h => WiFiInterface.h} (88%) diff --git a/net/ESP8266Interface/ESP8266Interface.h b/net/ESP8266Interface/ESP8266Interface.h index e6d64fae8b..a71609f6eb 100644 --- a/net/ESP8266Interface/ESP8266Interface.h +++ b/net/ESP8266Interface/ESP8266Interface.h @@ -17,7 +17,7 @@ #ifndef ESP8266_INTERFACE_H #define ESP8266_INTERFACE_H -#include "WiFiStack.h" +#include "WiFiInterface.h" #include "ESP8266.h" #define ESP8266_SOCKET_COUNT 5 @@ -25,7 +25,7 @@ /** ESP8266Interface class * Implementation of the NetworkStack for the ESP8266 */ -class ESP8266Interface : public WiFiStack +class ESP8266Interface : public NetworkStack, public WiFiInterface { public: /** ESP8266Interface lifetime diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index 5bb3a59221..41fdf0069f 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -17,7 +17,7 @@ #ifndef LWIP_INTERFACE_H #define LWIP_INTERFACE_H -#include "EthernetStack.h" +#include "EthernetInterface.h" #include "rtos.h" #include "lwip/netif.h" @@ -25,7 +25,7 @@ /** LWIPInterface class * Implementation of the NetworkStack for LWIP */ -class LWIPInterface : public EthernetStack +class LWIPInterface : public NetworkStack, public EthernetInterface { public: /** Start the interface diff --git a/net/NetworkSocketAPI/CellularStack.h b/net/NetworkSocketAPI/CellularInterface.h similarity index 84% rename from net/NetworkSocketAPI/CellularStack.h rename to net/NetworkSocketAPI/CellularInterface.h index da96cafedb..0f9c28b840 100644 --- a/net/NetworkSocketAPI/CellularStack.h +++ b/net/NetworkSocketAPI/CellularInterface.h @@ -1,4 +1,4 @@ -/* CellularStack +/* CellularInterface * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,11 +19,11 @@ #include "NetworkStack.h" -/** CellularStack class +/** CellularInterface class * * Common interface that is shared between ethernet hardware */ -class CellularStack : public NetworkStack +class CellularInterface { public: /** Start the interface @@ -40,6 +40,12 @@ public: * @return 0 on success, negative error code on failure */ virtual int disconnect() = 0; + + /** Get the local MAC address + * + * @return Null-terminated representation of the local MAC address + */ + virtual const char *get_mac_address() = 0; }; #endif diff --git a/net/NetworkSocketAPI/EthernetStack.h b/net/NetworkSocketAPI/EthernetInterface.h similarity index 80% rename from net/NetworkSocketAPI/EthernetStack.h rename to net/NetworkSocketAPI/EthernetInterface.h index 061648af14..c0214c688b 100644 --- a/net/NetworkSocketAPI/EthernetStack.h +++ b/net/NetworkSocketAPI/EthernetInterface.h @@ -1,4 +1,4 @@ -/* EthernetStack +/* EthernetInterface * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,11 +19,11 @@ #include "NetworkStack.h" -/** EthernetStack class +/** EthernetInterface class * * Common interface that is shared between ethernet hardware. */ -class EthernetStack : public NetworkStack +class EthernetInterface { public: /** Start the interface @@ -37,6 +37,12 @@ public: * @return 0 on success, negative error code on failure */ virtual int disconnect() = 0; + + /** Get the local MAC address + * + * @return Null-terminated representation of the local MAC address + */ + virtual const char *get_mac_address() = 0; }; #endif diff --git a/net/NetworkSocketAPI/MeshStack.h b/net/NetworkSocketAPI/MeshInterface.h similarity index 81% rename from net/NetworkSocketAPI/MeshStack.h rename to net/NetworkSocketAPI/MeshInterface.h index cdb4360700..811b3f7352 100644 --- a/net/NetworkSocketAPI/MeshStack.h +++ b/net/NetworkSocketAPI/MeshInterface.h @@ -1,4 +1,4 @@ -/* MeshStack +/* MeshInterface * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,11 +19,11 @@ #include "NetworkStack.h" -/** MeshStack class +/** MeshInterface class * * Common interface that is shared between mesh hardware */ -class MeshStack : public NetworkStack +class MeshInterface { public: /** Start the interface @@ -37,6 +37,12 @@ public: * @return 0 on success, negative on failure */ virtual int disconnect() = 0; + + /** Get the local MAC address + * + * @return Null-terminated representation of the local MAC address + */ + virtual const char *get_mac_address() = 0; }; #endif diff --git a/net/NetworkSocketAPI/NetworkStack.h b/net/NetworkSocketAPI/NetworkStack.h index 6ce6995bbc..f82bd24e1d 100644 --- a/net/NetworkSocketAPI/NetworkStack.h +++ b/net/NetworkSocketAPI/NetworkStack.h @@ -77,14 +77,6 @@ enum nsapi_option_t { NSAPI_RCVBUF, /*!< Sets recv buffer size */ }; -/** Maximum size of MAC address representation - */ -#define NSAPI_MAC_SIZE 18 - -/** Maximum number of bytes for MAC address - */ -#define NSAPI_MAC_BYTES 6 - /** NetworkStack class * @@ -105,12 +97,6 @@ public: */ virtual const char *get_ip_address() = 0; - /** Get the local MAC address - * - * @return Null-terminated representation of the local MAC address - */ - virtual const char *get_mac_address() = 0; - /** Translates a hostname to an IP address * * The hostname may be either a domain name or an IP address. If the diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index f2eeb14f1e..943187d364 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -52,9 +52,9 @@ int Socket::close() if (!_socket) { return 0; } - + _iface->socket_attach(_socket, 0, 0); - + void *volatile socket = _socket; _socket = 0; return _iface->socket_close(socket); diff --git a/net/NetworkSocketAPI/SocketAddress.h b/net/NetworkSocketAPI/SocketAddress.h index 5d71e2678e..64f2991e0b 100644 --- a/net/NetworkSocketAPI/SocketAddress.h +++ b/net/NetworkSocketAPI/SocketAddress.h @@ -28,6 +28,14 @@ */ #define NSAPI_IP_BYTES NSAPI_IPv6_BYTES +/** Maximum size of MAC address representation + */ +#define NSAPI_MAC_SIZE 18 + +/** Maximum number of bytes for MAC address + */ +#define NSAPI_MAC_BYTES 6 + /** Enum of IP address versions * * The IP version specifies the type of an IP address. diff --git a/net/NetworkSocketAPI/WiFiStack.h b/net/NetworkSocketAPI/WiFiInterface.h similarity index 88% rename from net/NetworkSocketAPI/WiFiStack.h rename to net/NetworkSocketAPI/WiFiInterface.h index f5a2ef632b..09f5340d32 100644 --- a/net/NetworkSocketAPI/WiFiStack.h +++ b/net/NetworkSocketAPI/WiFiInterface.h @@ -1,4 +1,4 @@ -/* WiFiStack +/* WiFiInterface * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,11 +33,11 @@ enum nsapi_security_t { NSAPI_SECURITY_WPA2, /*!< phrase conforms to WPA2 */ }; -/** WiFiStack class +/** WiFiInterface class * * Common interface that is shared between WiFi devices */ -class WiFiStack : public NetworkStack +class WiFiInterface { public: /** Start the interface @@ -57,6 +57,12 @@ public: * @return 0 on success, negative error code on failure */ virtual int disconnect() = 0; + + /** Get the local MAC address + * + * @return Null-terminated representation of the local MAC address + */ + virtual const char *get_mac_address() = 0; }; #endif From 5475dd0404e4583b089254ae95696872319fa788 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Apr 2016 19:10:13 -0500 Subject: [PATCH 25/33] Consolidate set_timeout/set_blocking behaviour - Avoids ambiguity when both are used - Matches Python behaviour --- net/NetworkSocketAPI/Socket.cpp | 7 +++---- net/NetworkSocketAPI/Socket.h | 15 ++++++++++----- net/NetworkSocketAPI/TCPServer.cpp | 5 +++-- net/NetworkSocketAPI/TCPSocket.cpp | 10 ++++++---- net/NetworkSocketAPI/UDPSocket.cpp | 10 ++++++---- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index 943187d364..d21f984e7e 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -19,8 +19,7 @@ Socket::Socket() : _iface(0) , _socket(0) - , _blocking(true) - , _timeout(0) + , _timeout(-1) { } @@ -83,10 +82,10 @@ int Socket::bind(const SocketAddress &address) void Socket::set_blocking(bool blocking) { - _blocking = blocking; + set_timeout(blocking ? -1 : 0); } -void Socket::set_timeout(unsigned timeout) +void Socket::set_timeout(int timeout) { _timeout = timeout; } diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index ab093e39d3..195da38204 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -86,7 +86,10 @@ public: * blocking operations such as send/recv/accept return * NSAPI_ERROR_WOULD_BLOCK if they can not continue. * - * @param blocking True for blocking mode, false for non-blocking mode. + * set_blocking(false) is equivalent to set_timeout(-1) + * set_blocking(true) is equivalent to set_timeout(0) + * + * @param blocking true for blocking mode, false for non-blocking mode. */ void set_blocking(bool blocking); @@ -94,11 +97,14 @@ public: * * Initially all sockets have unbounded timeouts. NSAPI_ERROR_WOULD_BLOCK * is returned if a blocking operation takes longer than the specified - * timeout. A timeout of 0 removes a timeout from the socket. + * timeout. A timeout of -1 removes the timeout from the socket. + * + * set_timeout(-1) is equivalent to set_blocking(false) + * set_timeout(0) is equivalent to set_blocking(true) * * @param timeout Timeout in milliseconds */ - void set_timeout(unsigned int timeout); + void set_timeout(int timeout); /* Set stack-specific socket options * @@ -166,8 +172,7 @@ protected: NetworkStack *_iface; void *_socket; - bool _blocking; - unsigned _timeout; + int _timeout; FunctionPointer _callback; }; diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index 83a85d66b4..7a65e954da 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -60,8 +60,9 @@ int TCPServer::accept(TCPSocket *connection) connection->_socket = socket; } - if (err != NSAPI_ERROR_WOULD_BLOCK || !_blocking || - (_timeout && timer.read_ms() > _timeout)) { + if (err != NSAPI_ERROR_WOULD_BLOCK + || _timeout < 0 + || timer.read_ms() > _timeout) { return err; } } diff --git a/net/NetworkSocketAPI/TCPSocket.cpp b/net/NetworkSocketAPI/TCPSocket.cpp index b59715594c..926473dacc 100644 --- a/net/NetworkSocketAPI/TCPSocket.cpp +++ b/net/NetworkSocketAPI/TCPSocket.cpp @@ -61,8 +61,9 @@ int TCPSocket::send(const void *data, unsigned size) } int sent = _iface->socket_send(_socket, data, size); - if (sent != NSAPI_ERROR_WOULD_BLOCK || !_blocking || - (_timeout && timer.read_ms() > _timeout)) { + if (sent != NSAPI_ERROR_WOULD_BLOCK + || _timeout < 0 + || timer.read_ms() > _timeout) { return sent; } } @@ -79,8 +80,9 @@ int TCPSocket::recv(void *data, unsigned size) } int recv = _iface->socket_recv(_socket, data, size); - if (recv != NSAPI_ERROR_WOULD_BLOCK || !_blocking || - (_timeout && timer.read_ms() > _timeout)) { + if (recv != NSAPI_ERROR_WOULD_BLOCK + || _timeout < 0 + || timer.read_ms() > _timeout) { return recv; } } diff --git a/net/NetworkSocketAPI/UDPSocket.cpp b/net/NetworkSocketAPI/UDPSocket.cpp index 85569c7a58..a8148fb38f 100644 --- a/net/NetworkSocketAPI/UDPSocket.cpp +++ b/net/NetworkSocketAPI/UDPSocket.cpp @@ -52,8 +52,9 @@ int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned s } int sent = _iface->socket_sendto(_socket, address, data, size); - if (sent != NSAPI_ERROR_WOULD_BLOCK || !_blocking || - (_timeout && timer.read_ms() > _timeout)) { + if (sent != NSAPI_ERROR_WOULD_BLOCK + || _timeout < 0 + || timer.read_ms() > _timeout) { return sent; } } @@ -70,8 +71,9 @@ int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size) } int recv = _iface->socket_recvfrom(_socket, address, buffer, size); - if (recv != NSAPI_ERROR_WOULD_BLOCK || !_blocking || - (_timeout && timer.read_ms() > _timeout)) { + if (recv != NSAPI_ERROR_WOULD_BLOCK + || _timeout < 0 + || timer.read_ms() > _timeout) { return recv; } } From bcab0fcef5045926e97d8c355b3885032c6bbc5a Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 20 Apr 2016 19:30:16 -0500 Subject: [PATCH 26/33] Added WFI to save power in temporary polling implementation --- net/NetworkSocketAPI/Socket.cpp | 4 ++++ net/NetworkSocketAPI/Socket.h | 1 + net/NetworkSocketAPI/TCPServer.cpp | 9 +++++++-- net/NetworkSocketAPI/TCPSocket.cpp | 18 ++++++++++++++---- net/NetworkSocketAPI/UDPSocket.cpp | 18 ++++++++++++++---- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index d21f984e7e..3b853e19ec 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -109,6 +109,10 @@ int Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen) } +void Socket::wakeup() +{ +} + void Socket::thunk(void *data) { Socket *self = (Socket *)data; diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index 195da38204..64e7325214 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -169,6 +169,7 @@ protected: int open(NetworkStack *iface, nsapi_protocol_t proto); static void thunk(void *); + static void wakeup(); NetworkStack *_iface; void *_socket; diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index 7a65e954da..e31a6328be 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -44,6 +44,10 @@ int TCPServer::accept(TCPSocket *connection) { mbed::Timer timer; timer.start(); + mbed::Timeout timeout; + if (_timeout >= 0) { + timeout.attach_us(&Socket::wakeup, _timeout * 1000); + } if (connection->_socket) { connection->close(); @@ -61,9 +65,10 @@ int TCPServer::accept(TCPSocket *connection) } if (err != NSAPI_ERROR_WOULD_BLOCK - || _timeout < 0 - || timer.read_ms() > _timeout) { + || (_timeout >= 0 && timer.read_ms() >= _timeout)) { return err; } + + __WFI(); } } diff --git a/net/NetworkSocketAPI/TCPSocket.cpp b/net/NetworkSocketAPI/TCPSocket.cpp index 926473dacc..4ec5ce6ab1 100644 --- a/net/NetworkSocketAPI/TCPSocket.cpp +++ b/net/NetworkSocketAPI/TCPSocket.cpp @@ -54,6 +54,10 @@ int TCPSocket::send(const void *data, unsigned size) { mbed::Timer timer; timer.start(); + mbed::Timeout timeout; + if (_timeout >= 0) { + timeout.attach_us(&Socket::wakeup, _timeout * 1000); + } while (true) { if (!_socket) { @@ -62,10 +66,11 @@ int TCPSocket::send(const void *data, unsigned size) int sent = _iface->socket_send(_socket, data, size); if (sent != NSAPI_ERROR_WOULD_BLOCK - || _timeout < 0 - || timer.read_ms() > _timeout) { + || (_timeout >= 0 && timer.read_ms() >= _timeout)) { return sent; } + + __WFI(); } } @@ -73,6 +78,10 @@ int TCPSocket::recv(void *data, unsigned size) { mbed::Timer timer; timer.start(); + mbed::Timeout timeout; + if (_timeout >= 0) { + timeout.attach_us(&Socket::wakeup, _timeout * 1000); + } while (true) { if (!_socket) { @@ -81,9 +90,10 @@ int TCPSocket::recv(void *data, unsigned size) int recv = _iface->socket_recv(_socket, data, size); if (recv != NSAPI_ERROR_WOULD_BLOCK - || _timeout < 0 - || timer.read_ms() > _timeout) { + || (_timeout >= 0 && timer.read_ms() >= _timeout)) { return recv; } + + __WFI(); } } diff --git a/net/NetworkSocketAPI/UDPSocket.cpp b/net/NetworkSocketAPI/UDPSocket.cpp index a8148fb38f..9494323fbd 100644 --- a/net/NetworkSocketAPI/UDPSocket.cpp +++ b/net/NetworkSocketAPI/UDPSocket.cpp @@ -45,6 +45,10 @@ int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned s { mbed::Timer timer; timer.start(); + mbed::Timeout timeout; + if (_timeout >= 0) { + timeout.attach_us(&Socket::wakeup, _timeout * 1000); + } while (true) { if (!_socket) { @@ -53,10 +57,11 @@ int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned s int sent = _iface->socket_sendto(_socket, address, data, size); if (sent != NSAPI_ERROR_WOULD_BLOCK - || _timeout < 0 - || timer.read_ms() > _timeout) { + || (_timeout >= 0 && timer.read_ms() >= _timeout)) { return sent; } + + __WFI(); } } @@ -64,6 +69,10 @@ int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size) { mbed::Timer timer; timer.start(); + mbed::Timeout timeout; + if (_timeout >= 0) { + timeout.attach_us(&Socket::wakeup, _timeout * 1000); + } while (true) { if (!_socket) { @@ -72,9 +81,10 @@ int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size) int recv = _iface->socket_recvfrom(_socket, address, buffer, size); if (recv != NSAPI_ERROR_WOULD_BLOCK - || _timeout < 0 - || timer.read_ms() > _timeout) { + || (_timeout >= 0 && timer.read_ms() >= _timeout)) { return recv; } + + __WFI(); } } From 8304124a63f333ef1272e077ff531f3a5fe96b35 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 10 May 2016 12:45:12 -0500 Subject: [PATCH 27/33] Add NSAPI_ERROR_PARAMETER per @c1728p9 --- net/NetworkSocketAPI/NetworkStack.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/net/NetworkSocketAPI/NetworkStack.h b/net/NetworkSocketAPI/NetworkStack.h index f82bd24e1d..30dea56b26 100644 --- a/net/NetworkSocketAPI/NetworkStack.h +++ b/net/NetworkSocketAPI/NetworkStack.h @@ -30,15 +30,16 @@ */ enum nsapi_error_t { NSAPI_ERROR_WOULD_BLOCK = -3001, /*!< no data is not available but call is non-blocking */ - NSAPI_ERROR_UNSUPPORTED = -3002, /*!< unsupported configuration */ - NSAPI_ERROR_NO_CONNECTION = -3003, /*!< not connected to a network */ - NSAPI_ERROR_NO_SOCKET = -3004, /*!< socket not available for use */ - NSAPI_ERROR_NO_ADDRESS = -3005, /*!< IP address is not known */ - NSAPI_ERROR_NO_MEMORY = -3006, /*!< memory resource not available */ - NSAPI_ERROR_DNS_FAILURE = -3007, /*!< DNS failed to complete successfully */ - NSAPI_ERROR_DHCP_FAILURE = -3008, /*!< DHCP failed to complete successfully */ - NSAPI_ERROR_AUTH_FAILURE = -3009, /*!< connection to access point faield */ - NSAPI_ERROR_DEVICE_ERROR = -3010, /*!< failure interfacing with the network procesor */ + NSAPI_ERROR_UNSUPPORTED = -3002, /*!< unsupported functionality */ + NSAPI_ERROR_PARAMETER = -3003, /*!< invalid configuration */ + NSAPI_ERROR_NO_CONNECTION = -3004, /*!< not connected to a network */ + NSAPI_ERROR_NO_SOCKET = -3005, /*!< socket not available for use */ + NSAPI_ERROR_NO_ADDRESS = -3006, /*!< IP address is not known */ + NSAPI_ERROR_NO_MEMORY = -3007, /*!< memory resource not available */ + NSAPI_ERROR_DNS_FAILURE = -3008, /*!< DNS failed to complete successfully */ + NSAPI_ERROR_DHCP_FAILURE = -3009, /*!< DHCP failed to complete successfully */ + NSAPI_ERROR_AUTH_FAILURE = -3010, /*!< connection to access point faield */ + NSAPI_ERROR_DEVICE_ERROR = -3011, /*!< failure interfacing with the network procesor */ }; /** Enum of socket protocols From 7d9b5e6f761c4ffd6b76a21617ea0062342a0bfe Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 10 May 2016 12:46:26 -0500 Subject: [PATCH 28/33] Small bug fixes mirrored from: https://developer.mbed.org/teams/NetworkSocketAPI/code/NetworkSocketAPI/ - Fix bug with SocketAddress init per @c1728p9 - Fix issue with not passing interface through accept call - Fix port issue in SocketAddress constructor --- net/NetworkSocketAPI/SocketAddress.cpp | 11 +++++++++-- net/NetworkSocketAPI/TCPServer.cpp | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/net/NetworkSocketAPI/SocketAddress.cpp b/net/NetworkSocketAPI/SocketAddress.cpp index 933f851731..1496aef21d 100644 --- a/net/NetworkSocketAPI/SocketAddress.cpp +++ b/net/NetworkSocketAPI/SocketAddress.cpp @@ -144,13 +144,17 @@ static void ipv6_to_address(char *addr, const uint8_t *bytes) SocketAddress::SocketAddress(NetworkStack *iface, const char *host, uint16_t port) { + memset(&_ip_address, 0, sizeof _ip_address); + // Check for valid IP addresses if (host && ipv4_is_valid(host)) { _ip_version = NSAPI_IPv4; ipv4_from_address(_ip_bytes, host); + set_port(port); } else if (host && ipv6_is_valid(host)) { _ip_version = NSAPI_IPv6; ipv4_from_address(_ip_bytes, host); + set_port(port); } else { // DNS lookup int err = iface->gethostbyname(this, host); @@ -166,18 +170,21 @@ SocketAddress::SocketAddress(NetworkStack *iface, const char *host, uint16_t por SocketAddress::SocketAddress(const char *addr, uint16_t port) { + memset(&_ip_address, 0, sizeof _ip_address); set_ip_address(addr); set_port(port); } SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port) { + memset(&_ip_address, 0, sizeof _ip_address); set_ip_bytes(bytes, version); set_port(port); } SocketAddress::SocketAddress(const SocketAddress &addr) { + memset(&_ip_address, 0, sizeof _ip_address); set_ip_bytes(addr.get_ip_bytes(), addr.get_ip_version()); set_port(addr.get_port()); } @@ -202,10 +209,10 @@ void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version) { _ip_address[0] = '\0'; - if (_ip_version == NSAPI_IPv4) { + if (version == NSAPI_IPv4) { _ip_version = NSAPI_IPv4; memcpy(_ip_bytes, bytes, NSAPI_IPv4_BYTES); - } else if (_ip_version == NSAPI_IPv6) { + } else if (version == NSAPI_IPv6) { _ip_version = NSAPI_IPv6; memcpy(_ip_bytes, bytes, NSAPI_IPv6_BYTES); } else { diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index e31a6328be..84c47a09ae 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -61,6 +61,7 @@ int TCPServer::accept(TCPSocket *connection) void *socket; int err = _iface->socket_accept(&socket, _socket); if (!err) { + connection->_iface = _iface; connection->_socket = socket; } From 4684173778cf07835266e3da37494391912c338d Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 10 May 2016 14:32:24 -0500 Subject: [PATCH 29/33] Match changes to NSAPI in ESP8266Interface mirrored from: https://developer.mbed.org/teams/components/code/ESP8266Interface/ --- net/ESP8266Interface/ESP8266Interface.cpp | 5 ---- net/ESP8266Interface/ESP8266Interface.h | 29 ++++++++++------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/net/ESP8266Interface/ESP8266Interface.cpp b/net/ESP8266Interface/ESP8266Interface.cpp index cf29646337..82b717b40e 100644 --- a/net/ESP8266Interface/ESP8266Interface.cpp +++ b/net/ESP8266Interface/ESP8266Interface.cpp @@ -152,11 +152,6 @@ int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr) return 0; } -bool ESP8266Interface::socket_is_connected(void *handle) -{ - return true; -} - int ESP8266Interface::socket_accept(void **handle, void *server) { return NSAPI_ERROR_UNSUPPORTED; diff --git a/net/ESP8266Interface/ESP8266Interface.h b/net/ESP8266Interface/ESP8266Interface.h index a71609f6eb..ce26e5ea82 100644 --- a/net/ESP8266Interface/ESP8266Interface.h +++ b/net/ESP8266Interface/ESP8266Interface.h @@ -29,17 +29,21 @@ class ESP8266Interface : public NetworkStack, public WiFiInterface { public: /** ESP8266Interface lifetime - * @param tx TX pin - * @param rx RX pin - * @param debug Enable debugging + * @param tx TX pin + * @param rx RX pin + * @param debug Enable debugging */ ESP8266Interface(PinName tx, PinName rx, bool debug = false); /** Start the interface - * @param ssid Name of the network to connect to - * @param pass Security passphrase to connect to the network - * @param security Type of encryption for connection - * @return 0 on success, negative on failure + * + * Attempts to connect to a WiFi network. If passphrase is invalid, + * NSAPI_ERROR_AUTH_ERROR is returned. + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection + * @return 0 on success, negative error code on failure */ virtual int connect( const char *ssid, @@ -98,12 +102,6 @@ protected: * @return 0 on success, negative on failure */ virtual int socket_connect(void *handle, const SocketAddress &address); - - /** Check if the socket is connected - * @param handle Socket handle - * @return true if connected, false otherwise - */ - virtual bool socket_is_connected(void *handle); /** Accept a new connection. * @param handle Handle in which to store new socket @@ -139,7 +137,7 @@ protected: * @param address The remote SocketAddress * @param data The packet to be sent * @param size The length of the packet to be sent - * @return the number of written bytes on success, negative on failure + * @return The number of written bytes on success, negative on failure * @note This call is not-blocking, if this call would block, must * immediately return NSAPI_ERROR_WOULD_WAIT */ @@ -152,7 +150,7 @@ protected: * If a packet is too long to fit in the supplied buffer, * excess bytes are discarded * @param size The length of the buffer - * @return the number of received bytes on success, negative on failure + * @return The number of received bytes on success, negative on failure * @note This call is not-blocking, if this call would block, must * immediately return NSAPI_ERROR_WOULD_WAIT */ @@ -172,4 +170,3 @@ private: }; #endif - From 9e415df1961d2846b91481d3f4e037292881a76a Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 10 May 2016 14:36:08 -0500 Subject: [PATCH 30/33] Match changes to NSAPI in LWIPInterface mirrored from: https://developer.mbed.org/teams/NetworkSocketAPI/code/LWIPInterface/ --- net/LWIPInterface/LWIPInterface.cpp | 8 +++----- net/LWIPInterface/LWIPInterface.h | 6 ------ net/LWIPInterface/eth_arch.h | 2 +- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/net/LWIPInterface/LWIPInterface.cpp b/net/LWIPInterface/LWIPInterface.cpp index 2fd9c82a68..c37a52463a 100644 --- a/net/LWIPInterface/LWIPInterface.cpp +++ b/net/LWIPInterface/LWIPInterface.cpp @@ -169,6 +169,7 @@ int LWIPInterface::socket_open(void **handle, nsapi_protocol_t proto) udp_recv(s->udp, udp_recv_irq, s); *handle = s; + return 0; case NSAPI_TCP: s->proto = proto; @@ -180,6 +181,7 @@ int LWIPInterface::socket_open(void **handle, nsapi_protocol_t proto) tcp_arg(s->tcp, s); //tcp_err(s->tcp, tcp_error_irq); *handle = s; + return 0; } return NSAPI_ERROR_DEVICE_ERROR; @@ -193,6 +195,7 @@ int LWIPInterface::socket_close(void *handle) switch (s->proto) { case NSAPI_UDP: udp_disconnect(s->udp); + udp_remove(s->udp); break; case NSAPI_TCP: @@ -273,11 +276,6 @@ int LWIPInterface::socket_connect(void *handle, const SocketAddress &addr) return 0; } - -bool LWIPInterface::socket_is_connected(void *handle) -{ - return true; -} int LWIPInterface::socket_accept(void **handle, void *server) { diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index 41fdf0069f..139ab45548 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -85,12 +85,6 @@ protected: * @return 0 on success, negative on failure */ virtual int socket_connect(void *handle, const SocketAddress &address); - - /** Check if the socket is connected - * @param handle Socket handle - * @return true if connected, false otherwise - */ - virtual bool socket_is_connected(void *handle); /** Accept a new connection. * @param handle Handle in which to store new socket diff --git a/net/LWIPInterface/eth_arch.h b/net/LWIPInterface/eth_arch.h index 850d65e4ef..1ff54b1d38 100644 --- a/net/LWIPInterface/eth_arch.h +++ b/net/LWIPInterface/eth_arch.h @@ -1,4 +1,4 @@ -/* EthernetStack.h */ +/* EthernetInterface.h */ /* Copyright (C) 2012 mbed.org, MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software From 83f65c0d3af7cbef775e5d8d19b8ecefe6cf9c3e Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 10 May 2016 14:37:36 -0500 Subject: [PATCH 31/33] Add rudimentary support for server side mirrored from: https://developer.mbed.org/teams/NetworkSocketAPI/code/LWIPInterface/ --- net/LWIPInterface/LWIPInterface.cpp | 65 ++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/net/LWIPInterface/LWIPInterface.cpp b/net/LWIPInterface/LWIPInterface.cpp index c37a52463a..9f13b5ccd5 100644 --- a/net/LWIPInterface/LWIPInterface.cpp +++ b/net/LWIPInterface/LWIPInterface.cpp @@ -139,6 +139,7 @@ struct lwip_socket { struct tcp_pcb *tcp; }; + struct tcp_pcb *npcb; struct pbuf *rx_chain; Semaphore *sem; @@ -238,9 +239,25 @@ int LWIPInterface::socket_bind(void *handle, const SocketAddress &address) return NSAPI_ERROR_DEVICE_ERROR; } +static err_t tcp_accept_irq(void *arg, struct tcp_pcb *tpcb, err_t err); + int LWIPInterface::socket_listen(void *handle, int backlog) { - return NSAPI_ERROR_UNSUPPORTED; + struct lwip_socket *s = (struct lwip_socket *)handle; + + if (s->tcp->state != LISTEN) { + struct tcp_pcb *server = tcp_listen(s->tcp); + if (!server) { + return NSAPI_ERROR_NO_SOCKET; + } + + s->tcp = server; + s->npcb = 0; + } + + tcp_arg(s->tcp, s); + tcp_accept(s->tcp, tcp_accept_irq); + return 0; } static err_t tcp_sent_irq(void *arg, struct tcp_pcb *tpcb, uint16_t len); @@ -277,9 +294,53 @@ int LWIPInterface::socket_connect(void *handle, const SocketAddress &addr) return 0; } +static err_t tcp_refuse_irq(void *handle, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) +{ + return ERR_WOULDBLOCK; +} + +static err_t tcp_accept_irq(void *handle, struct tcp_pcb *npcb, err_t err) +{ + struct lwip_socket *s = (struct lwip_socket *)handle; + if (s->npcb) { + tcp_abort(npcb); + return ERR_ABRT; + } + + tcp_recv(npcb, tcp_refuse_irq); + s->npcb = npcb; + + if (s->callback) { + s->callback(s->data); + } + + return ERR_OK; +} + int LWIPInterface::socket_accept(void **handle, void *server) { - return NSAPI_ERROR_UNSUPPORTED; + struct lwip_socket *s = (struct lwip_socket *)server; + if (!s->npcb) { + return NSAPI_ERROR_WOULD_BLOCK; + } + + struct lwip_socket *ns = new struct lwip_socket; + if (!ns) { + return NSAPI_ERROR_NO_SOCKET; + } + + memset(ns, 0, sizeof *ns); + + ns->tcp = s->npcb; + s->npcb = 0; + + tcp_accepted(ns->tcp); + tcp_arg(ns->tcp, ns); + //tcp_err(ns->tcp, tcp_error_irq); + tcp_sent(ns->tcp, tcp_sent_irq); + tcp_recv(ns->tcp, tcp_recv_irq); + *handle = ns; + return 0; } static struct pbuf *pbuf_consume(struct pbuf *p, size_t consume, bool free_partial) From c8fc4dff6d9b29477981d6b242407e0c893c2e39 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Sun, 8 May 2016 19:03:55 -0500 Subject: [PATCH 32/33] Update Nanostack related libs Update library files related to Nanostack to bring in Network Socket API support. --- net/atmel-rf-driver.lib | 2 +- net/mbed-client-classic.lib | 2 +- net/mbed-mesh-api.lib | 2 +- net/nanostack-hal-mbed-cmsis-rtos.lib | 2 +- .../NanostackInterface.cpp | 899 ++++++++++++++++++ net/nanostack-interface/NanostackInterface.h | 250 +++++ net/nanostack-libservice.lib | 2 +- net/sal-iface-6lowpan-morpheus-private.lib | 1 - net/sal-stack-nanostack-eventloop.lib | 2 +- net/sal-stack-nanostack-private.lib | 2 +- 10 files changed, 1156 insertions(+), 8 deletions(-) create mode 100644 net/nanostack-interface/NanostackInterface.cpp create mode 100644 net/nanostack-interface/NanostackInterface.h delete mode 100644 net/sal-iface-6lowpan-morpheus-private.lib diff --git a/net/atmel-rf-driver.lib b/net/atmel-rf-driver.lib index 368d967a37..409b903ec1 100644 --- a/net/atmel-rf-driver.lib +++ b/net/atmel-rf-driver.lib @@ -1 +1 @@ -https://github.com/ARMmbed/atmel-rf-driver-mirror.git/#f4c48e5e98f6 +https://github.com/ARMmbed/atmel-rf-driver-mirror/#473759f1a37c1863cb2adfcb2a87ac3f1da144ed diff --git a/net/mbed-client-classic.lib b/net/mbed-client-classic.lib index 4e6ea87e68..de43c820ee 100644 --- a/net/mbed-client-classic.lib +++ b/net/mbed-client-classic.lib @@ -1 +1 @@ -https://github.com/ARMmbed/mbed-client-classic.git/#31381dfcd9d6 +https://github.com/ARMmbed/mbed-client-classic/#3120f1a11ca18fc0fedcccfb5042e62d4faeda0a diff --git a/net/mbed-mesh-api.lib b/net/mbed-mesh-api.lib index f45138d229..15ba5f511d 100644 --- a/net/mbed-mesh-api.lib +++ b/net/mbed-mesh-api.lib @@ -1 +1 @@ -https://github.com/ARMmbed/mbed-mesh-api-mirror.git/#f7a198bb1e66 +https://github.com/ARMmbed/mbed-mesh-api-mirror/#7312d7621c5c6b89f7c0476a2b103a9f1ea71c3c diff --git a/net/nanostack-hal-mbed-cmsis-rtos.lib b/net/nanostack-hal-mbed-cmsis-rtos.lib index e8134cd07c..4a54aad23e 100644 --- a/net/nanostack-hal-mbed-cmsis-rtos.lib +++ b/net/nanostack-hal-mbed-cmsis-rtos.lib @@ -1 +1 @@ -https://github.com/ARMmbed/nanostack-hal-mbed-cmsis-rtos.git/#ab64e255deb9 +https://github.com/ARMmbed/nanostack-hal-mbed-cmsis-rtos/#1d27e2613bf7a454f553e2363c115a1635fa9002 diff --git a/net/nanostack-interface/NanostackInterface.cpp b/net/nanostack-interface/NanostackInterface.cpp new file mode 100644 index 0000000000..4b40acc4dc --- /dev/null +++ b/net/nanostack-interface/NanostackInterface.cpp @@ -0,0 +1,899 @@ +/* Nanostack implementation of NetworkSocketAPI + * Copyright (c) 2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed.h" +#include "rtos.h" +#include "NanostackInterface.h" + +#include "ns_address.h" +#include "nsdynmemLIB.h" +#include "eventOS_scheduler.h" + +#include "mbed-mesh-api/MeshInterfaceFactory.h" + +#include "socket_api.h" +#include "driverRFPhy.h" +#include "net_interface.h" +#include "ip6string.h" +// Uncomment to enable trace +//#define HAVE_DEBUG +#include "ns_trace.h" +#define TRACE_GROUP "nsif" + +#define NS_INTERFACE_SOCKETS_MAX 16 //same as NanoStack SOCKET_MAX +#define NANOSTACK_SOCKET_UDP 17 // same as nanostack SOCKET_UDP +#define NANOSTACK_SOCKET_TCP 6 // same as nanostack SOCKET_TCP + +#define MALLOC ns_dyn_mem_alloc +#define FREE ns_dyn_mem_free + +#define nanostack_lock() eventOS_scheduler_mutex_wait() +#define nanostack_unlock() eventOS_scheduler_mutex_release() +#define nanostack_assert_locked() //MBED_ASSERT(eventOS_scheduler_mutex_is_owner()) + +enum socket_mode_t { + SOCKET_MODE_UNOPENED, // No socket ID + SOCKET_MODE_OPENED, // Socket ID but no assigned use yet + SOCKET_MODE_CONNECTING, // Socket is connecting but not open yet + SOCKET_MODE_DATAGRAM, // Socket is bound to a port and listening for datagrams + SOCKET_MODE_STREAM, // Socket has an open stream + SOCKET_MODE_CLOSED, // Socket is closed and resources are freed +}; + +class NanostackBuffer { +public: + NanostackBuffer *next; /*type = ADDRESS_IPV6; + ns_addr->identifier = s_addr->get_port(); + const char *str = s_addr->get_ip_address(); + stoip6(str, strlen(str), ns_addr->address); +} + +static void convert_ns_addr_to_mbed(SocketAddress *s_addr, const ns_address_t *ns_addr) +{ + char str[40]; + ip6tos(ns_addr->address, str); + s_addr->set_port(ns_addr->identifier); + s_addr->set_ip_address(str); +} + +void* NanostackSocket::operator new(std::size_t sz) { + return MALLOC(sz); +} +void NanostackSocket::operator delete(void* ptr) { + FREE(ptr); +} + +NanostackSocket::NanostackSocket(int8_t protocol) +{ + nanostack_assert_locked(); + + callback = NULL; + callback_data = NULL; + socket_id = -1; + rxBufChain = NULL; + proto = protocol; + addr_valid = false; + memset(&ns_address, 0, sizeof(ns_address)); + mode = SOCKET_MODE_UNOPENED; +} + +NanostackSocket::~NanostackSocket() +{ + nanostack_assert_locked(); + + if (mode != SOCKET_MODE_CLOSED) { + close(); + } + if (socket_id >= 0) { + int ret = socket_free(socket_id); + MBED_ASSERT(0 == ret); + MBED_ASSERT(socket_tbl[socket_id] == this); + socket_id = -1; + data_free_all(); + } + +} + +bool NanostackSocket::open(void) +{ + nanostack_assert_locked(); + MBED_ASSERT(SOCKET_MODE_UNOPENED == mode); + + int temp_socket = socket_open(proto, 0, socket_callback); + + if (temp_socket < 0) { + tr_error("NanostackSocket::open() failed"); + return false; + } + if (temp_socket >= NS_INTERFACE_SOCKETS_MAX) { + MBED_ASSERT(false); + return false; + } + if (socket_tbl[temp_socket] != NULL) { + MBED_ASSERT(false); + return false; + } + socket_id = temp_socket; + socket_tbl[socket_id] = this; + mode = SOCKET_MODE_OPENED; + return true; + +} + +void NanostackSocket::close() +{ + nanostack_assert_locked(); + MBED_ASSERT(mode != SOCKET_MODE_CLOSED); + + if (socket_id >= 0) { + int ret = socket_close(socket_id, (addr_valid ? &ns_address : NULL)); + MBED_ASSERT(0 == ret); + } else { + MBED_ASSERT(SOCKET_MODE_UNOPENED == mode); + } + + data_free_all(); + + mode = SOCKET_MODE_CLOSED; + signal_event(); +} + +bool NanostackSocket::is_bound() +{ + return SOCKET_MODE_DATAGRAM == mode; +} + +void NanostackSocket::set_bound() +{ + nanostack_assert_locked(); + MBED_ASSERT(SOCKET_MODE_OPENED == mode); + if (SOCKET_UDP == proto) { + mode = SOCKET_MODE_DATAGRAM; + } +} + +bool NanostackSocket::is_connecting() +{ + return SOCKET_MODE_CONNECTING == mode; +} + +void NanostackSocket::set_connecting(ns_address_t *addr) +{ + nanostack_assert_locked(); + MBED_ASSERT(SOCKET_MODE_OPENED == mode); + + memcpy(&ns_address, addr, sizeof(ns_address_t)); + mode = SOCKET_MODE_CONNECTING; +} + +void NanostackSocket::set_connected() +{ + nanostack_assert_locked(); + MBED_ASSERT(SOCKET_MODE_CONNECTING == mode); + + mode = SOCKET_MODE_STREAM; +} + +void NanostackSocket::signal_event() +{ + nanostack_assert_locked(); + + if (callback != NULL) { + callback(callback_data); + } +} + +void NanostackSocket::socket_callback(void *cb) { + nanostack_assert_locked(); + + socket_callback_t *sock_cb = (socket_callback_t *) cb; + NanostackSocket *socket = socket_tbl[sock_cb->socket_id]; + MBED_ASSERT(socket != NULL); + + tr_debug("socket_callback() sock=%d, event=%d, interface=%d, data len=%d", + sock_cb->socket_id, sock_cb->event_type, sock_cb->interface_id, sock_cb->d_len); + + switch (sock_cb->event_type) { + case SOCKET_DATA: + tr_debug("SOCKET_DATA, sock=%d, bytes=%d", sock_cb->socket_id, sock_cb->d_len); + socket->event_data(sock_cb); + break; + case SOCKET_BIND_DONE: + tr_debug("SOCKET_BIND_DONE"); + socket->event_bind_done(sock_cb); + break; + case SOCKET_BIND_FAIL: // Not used in NS + tr_debug("SOCKET_BIND_FAIL"); + break; + case SOCKET_BIND_AUTH_FAIL: // Not used in NS + tr_debug("SOCKET_BIND_AUTH_FAIL"); + break; + case SOCKET_SERVER_CONNECT_TO_CLIENT: // Not used in NS + tr_debug("SOCKET_SERVER_CONNECT_TO_CLIENT"); + break; + case SOCKET_TX_FAIL: + tr_debug("SOCKET_TX_FAIL"); + break; + case SOCKET_CONNECT_CLOSED: + tr_debug("SOCKET_CONNECT_CLOSED"); + socket->event_connnect_closed(sock_cb); + break; + case SOCKET_CONNECT_FAIL_CLOSED: // Not used in NS + tr_debug("SOCKET_CONNECT_FAIL_CLOSED"); + break; + case SOCKET_NO_ROUTE: + tr_debug("SOCKET_NO_ROUTE"); + break; + case SOCKET_TX_DONE: + tr_debug("SOCKET_TX_DONE, %d bytes sent", sock_cb->d_len); + socket->event_tx_done(sock_cb); + break; + default: + // SOCKET_NO_RAM, error case for SOCKET_TX_DONE + break; + } +} + + +bool NanostackSocket::data_available() +{ + nanostack_assert_locked(); + MBED_ASSERT((SOCKET_MODE_DATAGRAM == mode) || + (SOCKET_MODE_CONNECTING == mode) || + (SOCKET_MODE_STREAM == mode)); + + return (NULL == rxBufChain) ? false : true; +} + +size_t NanostackSocket::data_copy_and_free(void *dest, size_t len, + SocketAddress *address, bool stream) +{ + nanostack_assert_locked(); + MBED_ASSERT((SOCKET_MODE_DATAGRAM == mode) || + (mode == SOCKET_MODE_STREAM)); + + NanostackBuffer *data_buf = rxBufChain; + if (NULL == data_buf) { + // No data + return 0; + } + + if (address) { + convert_ns_addr_to_mbed(address, &data_buf->ns_address); + } + + size_t copy_size = (len > data_buf->length) ? data_buf->length : len; + memcpy(dest, data_buf->payload, copy_size); + + if (stream && (copy_size < data_buf->length)) { + // Update the size in the buffer + size_t new_buf_size = data_buf->length - copy_size; + memmove(data_buf->payload, data_buf->payload + copy_size, new_buf_size); + data_buf->length = new_buf_size; + } else { + // Entire packet used so free it + rxBufChain = data_buf->next; + FREE(data_buf); + } + + return copy_size; +} + +void NanostackSocket::data_free_all(void) +{ + nanostack_assert_locked(); + // No mode requirement + + NanostackBuffer *buffer = rxBufChain; + while (buffer != NULL) { + NanostackBuffer *next_buffer = buffer->next; + FREE(buffer); + buffer = next_buffer; + } +} + +void NanostackSocket::data_attach(NanostackBuffer *data_buf) +{ + nanostack_assert_locked(); + MBED_ASSERT((SOCKET_MODE_DATAGRAM == mode) || + (SOCKET_MODE_STREAM == mode)); + + // Add to linked list + tr_debug("data_attach socket=%p", this); + if (NULL == rxBufChain) { + rxBufChain = data_buf; + } else { + NanostackBuffer *buf_tmp = rxBufChain; + while (NULL != buf_tmp->next) { + buf_tmp = buf_tmp->next; + } + buf_tmp->next = data_buf; + } + signal_event(); +} + +void NanostackSocket::event_data(socket_callback_t *sock_cb) +{ + nanostack_assert_locked(); + MBED_ASSERT((SOCKET_MODE_DATAGRAM == mode) || + (SOCKET_MODE_STREAM == mode)); + + // Allocate buffer + NanostackBuffer *recv_buff = (NanostackBuffer *) MALLOC( + sizeof(NanostackBuffer) + sock_cb->d_len); + if (NULL == recv_buff) { + tr_error("alloc failed!"); + return; + } + recv_buff->next = NULL; + + // Write data to buffer + int16_t length = socket_read(sock_cb->socket_id, + &recv_buff->ns_address, recv_buff->payload, + sock_cb->d_len); + if (length < 0) { + tr_error("socket_read failed!"); + FREE(recv_buff); + return; + } + recv_buff->length = length; + + data_attach(recv_buff); +} + +void NanostackSocket::event_tx_done(socket_callback_t *sock_cb) +{ + nanostack_assert_locked(); + MBED_ASSERT((SOCKET_MODE_STREAM == mode) || + (SOCKET_MODE_DATAGRAM == mode)); + + signal_event(); +} + +void NanostackSocket::event_bind_done(socket_callback_t *sock_cb) +{ + nanostack_assert_locked(); + MBED_ASSERT(SOCKET_MODE_CONNECTING == mode); + + set_connected(); + signal_event(); +} + +void NanostackSocket::event_connnect_closed(socket_callback_t *sock_cb) +{ + nanostack_assert_locked(); + + // Only TCP sockets can be closed by the remote end + MBED_ASSERT((SOCKET_MODE_STREAM == mode) || + (SOCKET_MODE_CONNECTING == mode)); + close(); +} + +void NanostackInterface::mesh_network_handler(mesh_connection_status_t status) +{ + nanostack_lock(); + + if (status == MESH_CONNECTED) { + connect_semaphore.release(); + } + + nanostack_unlock(); +} + +int NanostackInterface::register_rf() +{ + nanostack_lock(); + + rf_device_id = rf_device_register(); + if (rf_device_id < 0) { + nanostack_unlock(); + return -1; + } + // Read mac address after registering the device. + rf_read_mac_address(eui64); + sprintf(mac_addr_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", eui64[0], eui64[1], eui64[2], eui64[3], eui64[4], eui64[5], eui64[6], eui64[7]); + + nanostack_unlock(); + + return 0; +} + +int NanostackInterface::actual_connect() +{ + nanostack_lock(); + + mesh_error_t status = get_mesh_api()->connect(); + if (status != MESH_ERROR_NONE) { + nanostack_unlock(); + return map_mesh_error(status); + } + + // Release mutex before blocking + nanostack_unlock(); + + int32_t count = connect_semaphore.wait(30000); + if (count <= 0) { + return NSAPI_ERROR_DHCP_FAILURE; // sort of... + } + return 0; +} + +int NanostackInterface::disconnect() +{ + nanostack_lock(); + + mesh_error_t status = get_mesh_api()->disconnect(); + + nanostack_unlock(); + + return map_mesh_error(status); +} + +int ThreadInterface::connect() +{ + nanostack_lock(); + + mesh_api = MeshInterfaceFactory::createInterface(MESH_TYPE_THREAD); + if (!mesh_api) { + nanostack_unlock(); + return NSAPI_ERROR_NO_MEMORY; + } + if (register_rf() < 0) { + nanostack_unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + mesh_error_t status = ((MeshThread *)mesh_api)->init(rf_device_id, AbstractMesh::mesh_network_handler_t(static_cast(this), &ThreadInterface::mesh_network_handler), eui64, NULL); + if (status != MESH_ERROR_NONE) { + nanostack_unlock(); + return map_mesh_error(status); + } + int ret = this->actual_connect(); + + nanostack_unlock(); + + return ret; +} + +int LoWPANNDInterface::connect() +{ + nanostack_lock(); + + mesh_api = MeshInterfaceFactory::createInterface(MESH_TYPE_6LOWPAN_ND); + if (!mesh_api) { + nanostack_unlock(); + return NSAPI_ERROR_NO_MEMORY; + } + if (register_rf() < 0) { + nanostack_unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + mesh_error_t status = ((Mesh6LoWPAN_ND *)mesh_api)->init(rf_device_id, AbstractMesh::mesh_network_handler_t(static_cast(this), &LoWPANNDInterface::mesh_network_handler)); + if (status != MESH_ERROR_NONE) { + nanostack_unlock(); + return map_mesh_error(status); + } + int ret = this->actual_connect(); + + nanostack_unlock(); + + return ret; +} + +int NanostackInterface::socket_open(void **handle, nsapi_protocol_t protocol) +{ + // Validate parameters + if (NULL == handle) { + MBED_ASSERT(false); + return NSAPI_ERROR_NO_SOCKET; + } + int8_t ns_proto; + if (NSAPI_UDP == protocol) { + ns_proto = SOCKET_UDP; + } else if (NSAPI_TCP == protocol) { + ns_proto = SOCKET_TCP; + } else { + MBED_ASSERT(false); + return NSAPI_ERROR_UNSUPPORTED; + } + *handle = (void*)NULL; + + nanostack_lock(); + + NanostackSocket * socket = new NanostackSocket(ns_proto); + if (NULL == socket) { + nanostack_unlock(); + tr_debug("socket_open() ret=%i", NSAPI_ERROR_NO_MEMORY); + return NSAPI_ERROR_NO_MEMORY; + } + if (!socket->open()) { + delete socket; + nanostack_unlock(); + tr_debug("socket_open() ret=%i", NSAPI_ERROR_DEVICE_ERROR); + return NSAPI_ERROR_DEVICE_ERROR; + } + *handle = (void*)socket; + + nanostack_unlock(); + + tr_debug("socket_open() socket=%p, sock_id=%d, ret=0", socket, socket->socket_id); + + return 0; +} + +int NanostackInterface::socket_close(void *handle) +{ + // Validate parameters + NanostackSocket * socket = static_cast(handle); + if (NULL == handle) { + MBED_ASSERT(false); + return NSAPI_ERROR_NO_SOCKET; + } + tr_debug("socket_close(socket=%p) sock_id=%d", socket, socket->socket_id); + + nanostack_lock(); + + delete socket; + + nanostack_unlock(); + + return 0; + +} + +int NanostackInterface::socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned int size) +{ + // Validate parameters + NanostackSocket * socket = static_cast(handle); + if (NULL == handle) { + MBED_ASSERT(false); + return NSAPI_ERROR_NO_SOCKET; + } + + nanostack_lock(); + + int ret; + if (socket->closed()) { + ret = NSAPI_ERROR_NO_CONNECTION; + } else if (NANOSTACK_SOCKET_TCP == socket->proto) { + tr_error("socket_sendto() not supported with SOCKET_STREAM!"); + ret = NSAPI_ERROR_UNSUPPORTED; + } else { + ns_address_t ns_address; + convert_mbed_addr_to_ns(&ns_address, &address); + if (!socket->is_bound()) { + socket->set_bound(); + } + int8_t send_to_status = ::socket_sendto(socket->socket_id, &ns_address, + (uint8_t *)data, size); + /* + * \return 0 on success. + * \return -1 invalid socket id. + * \return -2 Socket memory allocation fail. + * \return -3 TCP state not established. + * \return -4 Socket tx process busy. + * \return -5 TLS authentication not ready. + * \return -6 Packet too short. + * */ + if (-4 == send_to_status) { + ret = NSAPI_ERROR_WOULD_BLOCK; + } else if (0 != send_to_status) { + tr_error("socket_sendto: error=%d", send_to_status); + ret = NSAPI_ERROR_DEVICE_ERROR; + } else { + ret = size; + } + } + + nanostack_unlock(); + + tr_debug("socket_sendto(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret); + + return ret; +} + +int NanostackInterface::socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size) +{ + // Validate parameters + NanostackSocket * socket = static_cast(handle); + if (NULL == handle) { + MBED_ASSERT(false); + return NSAPI_ERROR_NO_SOCKET; + } + if (NULL == buffer) { + MBED_ASSERT(false); + return NSAPI_ERROR_PARAMETER; + } + if (0 == size) { + MBED_ASSERT(false); + return NSAPI_ERROR_PARAMETER; + } + + nanostack_lock(); + + int ret; + if (socket->closed()) { + ret = NSAPI_ERROR_NO_CONNECTION; + } else if (NANOSTACK_SOCKET_TCP == socket->proto) { + tr_error("recv_from() not supported with SOCKET_STREAM!"); + ret = NSAPI_ERROR_UNSUPPORTED; + } else if (!socket->data_available()) { + ret = NSAPI_ERROR_WOULD_BLOCK; + } else { + ret = socket->data_copy_and_free(buffer, size, address, false); + } + + nanostack_unlock(); + + tr_debug("socket_recvfrom(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret); + + return ret; +} + +int NanostackInterface::socket_bind(void *handle, const SocketAddress &address) +{ + // Validate parameters + NanostackSocket * socket = static_cast(handle); + if (NULL == handle) { + MBED_ASSERT(false); + return NSAPI_ERROR_NO_SOCKET; + } + + + nanostack_lock(); + + ns_address_t ns_address; + ns_address.type = ADDRESS_IPV6; + memset(ns_address.address, 0, sizeof ns_address.address); + ns_address.identifier = address.get_port(); + int ret = NSAPI_ERROR_DEVICE_ERROR; + if (0 == ::socket_bind(socket->socket_id, &ns_address)) { + socket->set_bound(); + ret = 0; + } + + nanostack_unlock(); + + tr_debug("socket_bind(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret); + + return ret; +} + +const char *NanostackInterface::get_ip_address() +{ + nanostack_lock(); + + const char *ret = NULL; + if (mesh_api && mesh_api->getOwnIpAddress(ip_addr_str, sizeof ip_addr_str)) { + ret = ip_addr_str; + } + + nanostack_unlock(); + + return ret; +} + +const char *NanostackInterface::get_mac_address() +{ + return mac_addr_str; +} + +int NanostackInterface::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int NanostackInterface::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int NanostackInterface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int NanostackInterface::socket_connect(void *handle, const SocketAddress &addr) +{ + // Validate parameters + NanostackSocket * socket = static_cast(handle); + if (NULL == handle) { + MBED_ASSERT(false); + return NSAPI_ERROR_NO_SOCKET; + } + + nanostack_lock(); + + int ret; + ns_address_t ns_addr; + int random_port = socket->is_bound() ? 0 : 1; + convert_mbed_addr_to_ns(&ns_addr, &addr); + if (0 == ::socket_connect(socket->socket_id, &ns_addr, random_port)) { + socket->set_connecting(&ns_addr); + ret = 0; + } else { + ret = NSAPI_ERROR_DEVICE_ERROR; + } + + nanostack_unlock(); + + tr_debug("socket_connect(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret); + + return ret; +} + +int NanostackInterface::socket_accept(void **handle, void *server) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int NanostackInterface::socket_send(void *handle, const void *p, unsigned size) +{ + // Validate parameters + NanostackSocket * socket = static_cast(handle); + if (NULL == handle) { + MBED_ASSERT(false); + return NSAPI_ERROR_NO_SOCKET; + } + + nanostack_lock(); + + int ret; + if (socket->closed()) { + ret = NSAPI_ERROR_NO_CONNECTION; + } else if (socket->is_connecting()) { + ret = NSAPI_ERROR_WOULD_BLOCK; + } else { + ret = ::socket_sendto(socket->socket_id, &socket->ns_address, (uint8_t*)p, size); + /* + * \return 0 on success. + * \return -1 invalid socket id. + * \return -2 Socket memory allocation fail. + * \return -3 TCP state not established. + * \return -4 Socket tx process busy. + * \return -5 TLS authentication not ready. + * \return -6 Packet too short. + * */ + if (-4 == ret) { + ret = NSAPI_ERROR_WOULD_BLOCK; + } else if (ret != 0) { + tr_warning("socket_sendto ret %i, socket_id %i", ret, socket->socket_id); + ret = NSAPI_ERROR_DEVICE_ERROR; + } else { + ret = size; + } + } + + nanostack_unlock(); + + tr_debug("socket_send(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret); + + return ret; +} + +int NanostackInterface::socket_recv(void *handle, void *data, unsigned size) +{ + // Validate parameters + NanostackSocket * socket = static_cast(handle); + if (NULL == handle) { + MBED_ASSERT(false); + return NSAPI_ERROR_NO_SOCKET; + } + + nanostack_lock(); + + int ret; + if (socket->closed()) { + ret = NSAPI_ERROR_NO_CONNECTION; + } else if (socket->data_available()) { + ret = socket->data_copy_and_free(data, size, NULL, true); + } else { + ret = NSAPI_ERROR_WOULD_BLOCK; + } + + nanostack_unlock(); + + tr_debug("socket_recv(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret); + + return ret; +} + +void NanostackInterface::socket_attach(void *handle, void (*callback)(void *), void *id) +{ + // Validate parameters + NanostackSocket * socket = static_cast(handle); + if (NULL == handle) { + MBED_ASSERT(false); + return; + } + + nanostack_lock(); + + socket->callback = callback; + socket->callback_data = id; + + nanostack_unlock(); + + tr_debug("socket_attach(socket=%p) sock_id=%d", socket, socket->socket_id); +} diff --git a/net/nanostack-interface/NanostackInterface.h b/net/nanostack-interface/NanostackInterface.h new file mode 100644 index 0000000000..7d747cf63d --- /dev/null +++ b/net/nanostack-interface/NanostackInterface.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + */ + +#ifndef NANOSTACK_INTERFACE_H_ +#define NANOSTACK_INTERFACE_H_ + +#include "NetworkStack.h" +#include "MeshInterface.h" + +#include "mbed-mesh-api/Mesh6LoWPAN_ND.h" +#include "mbed-mesh-api/MeshThread.h" + +class NanostackInterface : public MeshInterface, public NetworkStack { +public: + int disconnect(); + + /** Get the internally stored IP address + /return IP address of the interface or null if not yet connected + */ + const char *get_ip_address(); + + /** Get the internally stored MAC address + /return MAC address of the interface + */ + const char *get_mac_address(); + +protected: + + /** Opens a socket + * + * Creates a network socket and stores it in the specified handle. + * The handle must be passed to following calls on the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * @param handle Destination for the handle to a newly created socket + * @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative error code on failure + */ + virtual int socket_open(void **handle, nsapi_protocol_t proto); + + /** Close the socket + * + * Closes any open connection and deallocates any memory associated + * with the socket. + * + * @param handle Socket handle + * @return 0 on success, negative error code on failure + */ + virtual int socket_close(void *handle); + + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to recieve + * data. If the IP address is zeroed, only the port is bound. + * + * @param handle Socket handle + * @param address Local address to bind + * @return 0 on success, negative error code on failure. + */ + virtual int socket_bind(void *handle, const SocketAddress &address); + + /** Listen for connections on a TCP socket + * + * Marks the socket as a passive socket that can be used to accept + * incoming connections. + * + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued + * simultaneously + * @return 0 on success, negative error code on failure + */ + virtual int socket_listen(void *handle, int backlog); + + /** Connects TCP socket to a remote host + * + * Initiates a connection to a remote server specified by the + * indicated address. + * + * @param handle Socket handle + * @param address The SocketAddress of the remote host + * @return 0 on success, negative error code on failure + */ + virtual int socket_connect(void *handle, const SocketAddress &address); + + /** Accepts a connection on a TCP socket + * + * The server socket must be bound and set to listen for connections. + * On a new connection, creates a network socket and stores it in the + * specified handle. The handle must be passed to following calls on + * the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * This call is non-blocking. If accept would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Destination for a handle to the newly created sockey + * @param server Socket handle to server to accept from + * @return 0 on success, negative error code on failure + */ + virtual int socket_accept(void **handle, void *server); + + /** Send data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes sent from the buffer. + * + * This call is non-blocking. If send would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure + */ + virtual int socket_send(void *handle, const void *data, unsigned size); + + /** Receive data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes received into the buffer. + * + * This call is non-blocking. If recv would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure + */ + virtual int socket_recv(void *handle, void *data, unsigned size); + + /** Send a packet over a UDP socket + * + * Sends data to the specified address. Returns the number of bytes + * sent from the buffer. + * + * This call is non-blocking. If sendto would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param address The SocketAddress of the remote host + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure + */ + virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size); + + /** Receive a packet over a UDP socket + * + * Receives data and stores the source address in address if address + * is not NULL. Returns the number of bytes received into the buffer. + * + * This call is non-blocking. If recvfrom would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param address Destination for the source address or NULL + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure + */ + virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); + + /** Register a callback on state change of the socket + * + * The specified callback will be called on state changes such as when + * the socket can recv/send/accept successfully and on when an error + * occurs. The callback may also be called spuriously without reason. + * + * The callback may be called in an interrupt context and should not + * perform expensive operations such as recv/send calls. + * + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); + + /* Set stack-specific socket options + * + * The setsockopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. + * + * @param handle Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual int setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen); + + /* Get stack-specific socket options + * + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * + * @param handle Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Destination for option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual int getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen); + +protected: + int register_rf(); + int actual_connect(); + + virtual AbstractMesh *get_mesh_api() const = 0; + void mesh_network_handler(mesh_connection_status_t status); + AbstractMesh *mesh_api; + int8_t rf_device_id; + uint8_t eui64[8]; + char ip_addr_str[40]; + char mac_addr_str[24]; +}; + +class LoWPANNDInterface : public NanostackInterface { +public: + int connect(); +protected: + Mesh6LoWPAN_ND *get_mesh_api() const { return static_cast(mesh_api); } +private: + +}; + +class ThreadInterface : public NanostackInterface { +public: + int connect(); +protected: + MeshThread *get_mesh_api() const { return static_cast(mesh_api); } +private: + +}; + + +#endif /* NANOSTACK_INTERFACE_H_ */ diff --git a/net/nanostack-libservice.lib b/net/nanostack-libservice.lib index 98b4a94a0a..dacd2c665f 100644 --- a/net/nanostack-libservice.lib +++ b/net/nanostack-libservice.lib @@ -1 +1 @@ -https://github.com/ARMmbed/nanostack-libservice-mirror.git/#e3f7da74a143 +https://github.com/ARMmbed/nanostack-libservice-mirror/#5490767fc3f8b9f204be20f88456f63a84810d06 diff --git a/net/sal-iface-6lowpan-morpheus-private.lib b/net/sal-iface-6lowpan-morpheus-private.lib deleted file mode 100644 index df6a7af1ac..0000000000 --- a/net/sal-iface-6lowpan-morpheus-private.lib +++ /dev/null @@ -1 +0,0 @@ -https://github.com/ARMmbed/sal-iface-6lowpan-morpheus-private-mirror.git/#baeb2fcf3ce4 diff --git a/net/sal-stack-nanostack-eventloop.lib b/net/sal-stack-nanostack-eventloop.lib index b6736e0045..84b804682d 100644 --- a/net/sal-stack-nanostack-eventloop.lib +++ b/net/sal-stack-nanostack-eventloop.lib @@ -1 +1 @@ -https://github.com/ARMmbed/sal-stack-nanostack-eventloop-mirror.git/#627b9769e352 +https://github.com/ARMmbed/sal-stack-nanostack-eventloop-mirror/#dcbeaf4babf7d74d252e905fd15d1d63bbaaf9c2 diff --git a/net/sal-stack-nanostack-private.lib b/net/sal-stack-nanostack-private.lib index 0e000b3b3c..1f920f848b 100644 --- a/net/sal-stack-nanostack-private.lib +++ b/net/sal-stack-nanostack-private.lib @@ -1 +1 @@ -https://github.com/ARMmbed/sal-stack-nanostack-private-mirror.git/#1374c77b03fb +https://github.com/ARMmbed/sal-stack-nanostack-private-mirror/#c83ddc4f776847d62ae3aa53d591157adc910b59 From b15e2c293ec8a0d4f814a7f86e34c0e4c570e03b Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Tue, 3 May 2016 15:29:54 -0500 Subject: [PATCH 33/33] Add synchronization to the network socket API Add mutexes to protect the network socket API. Also use semaphores to wait for read/write events. Also fix a typo in the comments for timeout. --- net/NetworkSocketAPI/Socket.cpp | 100 +++++++++++++++++------- net/NetworkSocketAPI/Socket.h | 13 ++-- net/NetworkSocketAPI/TCPServer.cpp | 72 +++++++++++------ net/NetworkSocketAPI/TCPServer.h | 4 + net/NetworkSocketAPI/TCPSocket.cpp | 121 +++++++++++++++++++++-------- net/NetworkSocketAPI/TCPSocket.h | 8 +- net/NetworkSocketAPI/UDPSocket.cpp | 108 ++++++++++++++++++------- net/NetworkSocketAPI/UDPSocket.h | 7 ++ 8 files changed, 315 insertions(+), 118 deletions(-) diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index 3b853e19ec..fd32a30cb8 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -19,109 +19,153 @@ Socket::Socket() : _iface(0) , _socket(0) - , _timeout(-1) + , _timeout(osWaitForever) { } Socket::~Socket() { - if (_socket) { - close(); - } + // Underlying close is thread safe + close(); } int Socket::open(NetworkStack *iface, nsapi_protocol_t proto) { + _lock.lock(); + + if (_iface != NULL) { + _lock.unlock(); + return NSAPI_ERROR_PARAMETER; + } _iface = iface; void *socket; int err = _iface->socket_open(&socket, proto); if (err) { + _lock.unlock(); return err; } _socket = socket; _iface->socket_attach(_socket, &Socket::thunk, this); + _lock.unlock(); + return 0; } int Socket::close() { - if (!_socket) { - return 0; + _lock.lock(); + + int ret = 0; + if (_socket) { + _iface->socket_attach(_socket, 0, 0); + + void * socket = _socket; + _socket = 0; + ret = _iface->socket_close(socket); } - - _iface->socket_attach(_socket, 0, 0); - - void *volatile socket = _socket; - _socket = 0; - return _iface->socket_close(socket); + + // Wakeup anything in a blocking operation + // on this socket + socket_event(); + + _lock.unlock(); + return ret; } int Socket::bind(uint16_t port) { + // Underlying bind is thread safe SocketAddress addr(0, port); return bind(addr); } int Socket::bind(const char *address, uint16_t port) { + // Underlying bind is thread safe SocketAddress addr(address, port); return bind(addr); } int Socket::bind(const SocketAddress &address) { - if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; + _lock.lock(); + + int ret = NSAPI_ERROR_NO_SOCKET; + if (_socket) { + ret = _iface->socket_bind(_socket, address); } - return _iface->socket_bind(_socket, address); + _lock.unlock(); + return ret; } void Socket::set_blocking(bool blocking) { + // Socket::set_timeout is thread safe set_timeout(blocking ? -1 : 0); } void Socket::set_timeout(int timeout) { - _timeout = timeout; + _lock.lock(); + + if (timeout >= 0) { + _timeout = (uint32_t)timeout; + } else { + _timeout = osWaitForever; + } + + _lock.unlock(); } int Socket::setsockopt(int level, int optname, const void *optval, unsigned optlen) { - if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; + _lock.lock(); + + int ret = NSAPI_ERROR_NO_SOCKET; + if (_socket) { + ret = _iface->setsockopt(_socket, level, optname, optval, optlen); } - return _iface->setsockopt(_socket, level, optname, optval, optlen); + _lock.unlock(); + return ret; } int Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen) { - if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; + _lock.lock(); + + int ret = NSAPI_ERROR_NO_SOCKET; + if (_socket) { + ret = _iface->getsockopt(_socket, level, optname, optval, optlen); } - return _iface->getsockopt(_socket, level, optname, optval, optlen); + _lock.unlock(); + return ret; } -void Socket::wakeup() +void Socket::attach(FunctionPointer callback) { + _lock.lock(); + + _callback = callback; + + _lock.unlock(); } void Socket::thunk(void *data) { Socket *self = (Socket *)data; - if (self->_callback) { - self->_callback(); - } + self->socket_event(); } -void Socket::attach(FunctionPointer callback) +void Socket::socket_event(void) { - _callback = callback; + if (_callback) { + _callback(); + } } diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index 64e7325214..bee2d11a74 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -19,6 +19,7 @@ #include "SocketAddress.h" #include "NetworkStack.h" +#include "Mutex.h" /** Abstract socket class */ @@ -97,10 +98,11 @@ public: * * Initially all sockets have unbounded timeouts. NSAPI_ERROR_WOULD_BLOCK * is returned if a blocking operation takes longer than the specified - * timeout. A timeout of -1 removes the timeout from the socket. + * timeout. A timeout of 0 removes the timeout from the socket. A negative + * value give the socket an unbounded timeout. * - * set_timeout(-1) is equivalent to set_blocking(false) - * set_timeout(0) is equivalent to set_blocking(true) + * set_timeout(0) is equivalent to set_blocking(false) + * set_timeout(-1) is equivalent to set_blocking(true) * * @param timeout Timeout in milliseconds */ @@ -169,12 +171,13 @@ protected: int open(NetworkStack *iface, nsapi_protocol_t proto); static void thunk(void *); - static void wakeup(); + virtual void socket_event(void); NetworkStack *_iface; void *_socket; - int _timeout; + uint32_t _timeout; FunctionPointer _callback; + rtos::Mutex _lock; }; #endif diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp index 84c47a09ae..4d4c9f5390 100644 --- a/net/NetworkSocketAPI/TCPServer.cpp +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -17,11 +17,11 @@ #include "TCPServer.h" #include "Timer.h" -TCPServer::TCPServer() +TCPServer::TCPServer(): _accept_sem(0) { } -TCPServer::TCPServer(NetworkStack *iface) +TCPServer::TCPServer(NetworkStack *iface): _accept_sem(0) { open(iface); } @@ -33,43 +33,69 @@ int TCPServer::open(NetworkStack *iface) int TCPServer::listen(int backlog) { - if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; + _lock.lock(); + + int ret = NSAPI_ERROR_NO_SOCKET; + if (_socket) { + ret = _iface->socket_listen(_socket, backlog); } - return _iface->socket_listen(_socket, backlog); + _lock.unlock(); + return ret; } int TCPServer::accept(TCPSocket *connection) { - mbed::Timer timer; - timer.start(); - mbed::Timeout timeout; - if (_timeout >= 0) { - timeout.attach_us(&Socket::wakeup, _timeout * 1000); - } - - if (connection->_socket) { - connection->close(); - } + _lock.lock(); + int ret = NSAPI_ERROR_NO_SOCKET; while (true) { if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; + ret = NSAPI_ERROR_NO_SOCKET; + break; } void *socket; - int err = _iface->socket_accept(&socket, _socket); - if (!err) { + ret = _iface->socket_accept(&socket, _socket); + if (0 == ret) { + connection->_lock.lock(); + + if (connection->_socket) { + connection->close(); + } + connection->_iface = _iface; connection->_socket = socket; + _iface->socket_attach(socket, &Socket::thunk, connection); + + connection->_lock.unlock(); + break; } - if (err != NSAPI_ERROR_WOULD_BLOCK - || (_timeout >= 0 && timer.read_ms() >= _timeout)) { - return err; - } + if (NSAPI_ERROR_WOULD_BLOCK == ret) { + int32_t count; - __WFI(); + _lock.unlock(); + count = _accept_sem.wait(_timeout); + _lock.lock(); + + if (count < 1) { + ret = NSAPI_ERROR_WOULD_BLOCK; + break; + } + } } + + _lock.unlock(); + return ret; +} + +void TCPServer::socket_event() +{ + int32_t status = _accept_sem.wait(0); + if (status <= 1) { + _accept_sem.release(); + } + + Socket::socket_event(); } diff --git a/net/NetworkSocketAPI/TCPServer.h b/net/NetworkSocketAPI/TCPServer.h index 0bb7d15a01..9155f78e67 100644 --- a/net/NetworkSocketAPI/TCPServer.h +++ b/net/NetworkSocketAPI/TCPServer.h @@ -20,6 +20,7 @@ #include "Socket.h" #include "TCPSocket.h" #include "NetworkStack.h" +#include "Semaphore.h" /** TCP socket server */ @@ -74,6 +75,9 @@ public: * @return 0 on success, negative error code on failure */ int accept(TCPSocket *connection); +protected: + virtual void socket_event(void); + rtos::Semaphore _accept_sem; }; #endif diff --git a/net/NetworkSocketAPI/TCPSocket.cpp b/net/NetworkSocketAPI/TCPSocket.cpp index 4ec5ce6ab1..14c0b61736 100644 --- a/net/NetworkSocketAPI/TCPSocket.cpp +++ b/net/NetworkSocketAPI/TCPSocket.cpp @@ -17,83 +17,140 @@ #include "TCPSocket.h" #include "Timer.h" -TCPSocket::TCPSocket() +TCPSocket::TCPSocket(): _read_sem(0), _write_sem(0) { } -TCPSocket::TCPSocket(NetworkStack *iface) +TCPSocket::TCPSocket(NetworkStack *iface): _read_sem(0), _write_sem(0) { + // TCPSocket::open is thread safe open(iface); } int TCPSocket::open(NetworkStack *iface) { + // Socket::open is thread safe return Socket::open(iface, NSAPI_TCP); } int TCPSocket::connect(const SocketAddress &addr) { - if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; + _lock.lock(); + + int ret = NSAPI_ERROR_NO_SOCKET; + if (_socket) { + ret = _iface->socket_connect(_socket, addr); } - return _iface->socket_connect(_socket, addr); + _lock.unlock(); + return ret; } int TCPSocket::connect(const char *host, uint16_t port) { + _lock.lock(); + SocketAddress addr(_iface, host, port); - if (!addr) { - return NSAPI_ERROR_DNS_FAILURE; + int ret = NSAPI_ERROR_DNS_FAILURE; + if (addr) { + ret = connect(addr); } - return connect(addr); + _lock.unlock(); + return ret; } int TCPSocket::send(const void *data, unsigned size) { - mbed::Timer timer; - timer.start(); - mbed::Timeout timeout; - if (_timeout >= 0) { - timeout.attach_us(&Socket::wakeup, _timeout * 1000); + if (osOK != _write_lock.lock(_timeout)) { + return NSAPI_ERROR_WOULD_BLOCK; } + _lock.lock(); + int ret; while (true) { if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; + ret = NSAPI_ERROR_NO_SOCKET; + break; } int sent = _iface->socket_send(_socket, data, size); - if (sent != NSAPI_ERROR_WOULD_BLOCK - || (_timeout >= 0 && timer.read_ms() >= _timeout)) { - return sent; - } + if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != sent)) { + ret = sent; + break; + } else { + int32_t count; - __WFI(); + // Release lock before blocking so other threads + // accessing this object aren't blocked + _lock.unlock(); + count = _write_sem.wait(_timeout); + _lock.lock(); + + if (count < 1) { + // Semaphore wait timed out so break out and return + ret = NSAPI_ERROR_WOULD_BLOCK; + break; + } + } } + + _lock.unlock(); + _write_lock.unlock(); + return ret; } int TCPSocket::recv(void *data, unsigned size) { - mbed::Timer timer; - timer.start(); - mbed::Timeout timeout; - if (_timeout >= 0) { - timeout.attach_us(&Socket::wakeup, _timeout * 1000); + if (osOK != _read_lock.lock(_timeout)) { + return NSAPI_ERROR_WOULD_BLOCK; } + _lock.lock(); + int ret; while (true) { if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; - } - - int recv = _iface->socket_recv(_socket, data, size); - if (recv != NSAPI_ERROR_WOULD_BLOCK - || (_timeout >= 0 && timer.read_ms() >= _timeout)) { - return recv; + ret = NSAPI_ERROR_NO_SOCKET; + break; } - __WFI(); + int recv = _iface->socket_recv(_socket, data, size); + if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) { + ret = recv; + break; + } else { + int32_t count; + + // Release lock before blocking so other threads + // accessing this object aren't blocked + _lock.unlock(); + count = _read_sem.wait(_timeout); + _lock.lock(); + + if (count < 1) { + // Semaphore wait timed out so break out and return + ret = NSAPI_ERROR_WOULD_BLOCK; + break; + } + } } + + _lock.unlock(); + _read_lock.unlock(); + return ret; +} + +void TCPSocket::socket_event() +{ + int32_t count; + count = _write_sem.wait(0); + if (count <= 1) { + _write_sem.release(); + } + count = _read_sem.wait(0); + if (count <= 1) { + _read_sem.release(); + } + + Socket::socket_event(); } diff --git a/net/NetworkSocketAPI/TCPSocket.h b/net/NetworkSocketAPI/TCPSocket.h index 2a37f776fb..5341174344 100644 --- a/net/NetworkSocketAPI/TCPSocket.h +++ b/net/NetworkSocketAPI/TCPSocket.h @@ -19,6 +19,7 @@ #include "Socket.h" #include "NetworkStack.h" +#include "Semaphore.h" /** TCP socket connection */ @@ -101,7 +102,12 @@ public: */ int recv(void *data, unsigned size); -private: +protected: + virtual void socket_event(void); + rtos::Mutex _read_lock; + rtos::Semaphore _read_sem; + rtos::Mutex _write_lock; + rtos::Semaphore _write_sem; friend class TCPServer; }; diff --git a/net/NetworkSocketAPI/UDPSocket.cpp b/net/NetworkSocketAPI/UDPSocket.cpp index 9494323fbd..dbff20fbf0 100644 --- a/net/NetworkSocketAPI/UDPSocket.cpp +++ b/net/NetworkSocketAPI/UDPSocket.cpp @@ -17,11 +17,11 @@ #include "UDPSocket.h" #include "Timer.h" -UDPSocket::UDPSocket() +UDPSocket::UDPSocket(): _read_sem(0), _write_sem(0) { } -UDPSocket::UDPSocket(NetworkStack *iface) +UDPSocket::UDPSocket(NetworkStack *iface): _read_sem(0), _write_sem(0) { open(iface); } @@ -38,53 +38,103 @@ int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigne return NSAPI_ERROR_DNS_FAILURE; } - return sendto(addr, data, size); + // sendto is thread safe + int ret = sendto(addr, data, size); + + return ret; } int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size) { - mbed::Timer timer; - timer.start(); - mbed::Timeout timeout; - if (_timeout >= 0) { - timeout.attach_us(&Socket::wakeup, _timeout * 1000); + if (osOK != _write_lock.lock(_timeout)) { + return NSAPI_ERROR_WOULD_BLOCK; } + _lock.lock(); + int ret; while (true) { if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; - } - - int sent = _iface->socket_sendto(_socket, address, data, size); - if (sent != NSAPI_ERROR_WOULD_BLOCK - || (_timeout >= 0 && timer.read_ms() >= _timeout)) { - return sent; + ret = NSAPI_ERROR_NO_SOCKET; + break; } - __WFI(); + int sent = _iface->socket_sendto(_socket, address, data, size); + if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != sent)) { + ret = sent; + break; + } else { + int32_t count; + + // Release lock before blocking so other threads + // accessing this object aren't blocked + _lock.unlock(); + count = _write_sem.wait(_timeout); + _lock.lock(); + + if (count < 1) { + // Semaphore wait timed out so break out and return + ret = NSAPI_ERROR_WOULD_BLOCK; + break; + } + } } + + _lock.unlock(); + _write_lock.unlock(); + return ret; } int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size) { - mbed::Timer timer; - timer.start(); - mbed::Timeout timeout; - if (_timeout >= 0) { - timeout.attach_us(&Socket::wakeup, _timeout * 1000); + if (osOK != _read_lock.lock(_timeout)) { + return NSAPI_ERROR_WOULD_BLOCK; } + _lock.lock(); + int ret; while (true) { if (!_socket) { - return NSAPI_ERROR_NO_SOCKET; - } - - int recv = _iface->socket_recvfrom(_socket, address, buffer, size); - if (recv != NSAPI_ERROR_WOULD_BLOCK - || (_timeout >= 0 && timer.read_ms() >= _timeout)) { - return recv; + ret = NSAPI_ERROR_NO_SOCKET; + break; } - __WFI(); + int recv = _iface->socket_recvfrom(_socket, address, buffer, size); + if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) { + ret = recv; + break; + } else { + int32_t count; + + // Release lock before blocking so other threads + // accessing this object aren't blocked + _lock.unlock(); + count = _read_sem.wait(_timeout); + _lock.lock(); + + if (count < 1) { + // Semaphore wait timed out so break out and return + ret = NSAPI_ERROR_WOULD_BLOCK; + break; + } + } } + + _lock.unlock(); + _read_lock.unlock(); + return ret; +} + +void UDPSocket::socket_event() +{ + int32_t count; + count = _write_sem.wait(0); + if (count <= 1) { + _write_sem.release(); + } + count = _read_sem.wait(0); + if (count <= 1) { + _read_sem.release(); + } + + Socket::socket_event(); } diff --git a/net/NetworkSocketAPI/UDPSocket.h b/net/NetworkSocketAPI/UDPSocket.h index b2a8454d9f..d5152d6348 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -19,6 +19,7 @@ #include "Socket.h" #include "NetworkStack.h" +#include "Semaphore.h" /** UDP socket */ @@ -100,6 +101,12 @@ public: * code on failure */ int recvfrom(SocketAddress *address, void *data, unsigned size); +protected: + virtual void socket_event(void); + rtos::Mutex _read_lock; + rtos::Semaphore _read_sem; + rtos::Mutex _write_lock; + rtos::Semaphore _write_sem; }; #endif