diff --git a/net/LWIPInterface/LWIPInterface.cpp b/net/LWIPInterface/LWIPInterface.cpp index b2d4ad6247..18df1b3328 100644 --- a/net/LWIPInterface/LWIPInterface.cpp +++ b/net/LWIPInterface/LWIPInterface.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ +#include "mbed.h" #include "LWIPInterface.h" -#include "mbed.h" #include "lwip/inet.h" #include "lwip/netif.h" #include "lwip/dhcp.h" @@ -26,15 +26,11 @@ #include "netif/etharp.h" #include "eth_arch.h" - -#define LWIP_TIMEOUT 15000 - - /* TCP/IP and Network Interface Initialisation */ static struct netif netif; -static char ip_addr[NS_IP_SIZE] = "\0"; -static char mac_addr[NS_MAC_SIZE] = "\0"; +static char ip_addr[NSAPI_IP_SIZE] = "\0"; +static char mac_addr[NSAPI_MAC_SIZE] = "\0"; static Semaphore tcpip_inited(0); static Semaphore netif_linked(0); @@ -86,8 +82,7 @@ static void set_mac_address(void) } -// LWIPInterface implementation -int32_t LWIPInterface::connect() +int LWIPInterface::connect() { // Set up network set_mac_address(); @@ -100,14 +95,14 @@ int32_t LWIPInterface::connect() // Wait for an IP Address // -1: error, 0: timeout - if (netif_up.wait(LWIP_TIMEOUT) < 0) { - return NS_ERROR_TIMEOUT; + if (netif_up.wait(1500) < 0) { + return NSAPI_ERROR_DHCP_FAILURE; } return 0; } -int32_t LWIPInterface::disconnect() +int LWIPInterface::disconnect() { dhcp_release(&netif); dhcp_stop(&netif); @@ -117,90 +112,204 @@ int32_t LWIPInterface::disconnect() return 0; } -const char *LWIPInterface::getIPAddress() +const char *LWIPInterface::get_ip_address() { return ip_addr; } -const char *LWIPInterface::getMACAddress() +const char *LWIPInterface::get_mac_address() { return mac_addr; } -SocketInterface *LWIPInterface::createSocket(ns_protocol_t proto) +void *LWIPInterface::socket_create(nsapi_protocol_t proto) { - int type = (proto == NS_UDP) ? SOCK_DGRAM : SOCK_STREAM; + int type = (proto == NSAPI_UDP) ? SOCK_DGRAM : SOCK_STREAM; int fd = lwip_socket(AF_INET, type, 0); if (fd < 0) { return 0; } - return new LWIPSocket(fd); + return (void *)(fd+1); } -void LWIPInterface::destroySocket(SocketInterface *siface) +void LWIPInterface::socket_destroy(void *handle) { - LWIPSocket *socket = (LWIPSocket *)siface; - lwip_close(socket->fd); - - delete socket; + int fd = (int)handle-1; + lwip_close(fd); + } - -// TCP SocketInterface implementation -int32_t LWIPInterface::LWIPSocket::open(const char *ip, uint16_t port) +int LWIPInterface::socket_set_option(void *handle, int optname, const void *optval, unsigned optlen) { - struct sockaddr_in host; - memset(&host, 0, sizeof host); - inet_aton(ip, &host.sin_addr); - host.sin_family = AF_INET; - host.sin_port = htons(port); + int fd = (int)handle-1; + return lwip_setsockopt(fd, SOL_SOCKET, optname, optval, (socklen_t)optlen); +} - if (lwip_connect(fd, (const struct sockaddr *)&host, sizeof host) < 0) { - return NS_ERROR_NO_CONNECTION; +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); +} + +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; + } + + return 0; +} + +int LWIPInterface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +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()); + + if (lwip_connect(fd, (const struct sockaddr *)&sa, sizeof sa) < 0) { + return NSAPI_ERROR_NO_CONNECTION; } return 0; } - -int32_t LWIPInterface::LWIPSocket::close() + +bool LWIPInterface::socket_is_connected(void *handle) { - return 0; + return true; } -int32_t LWIPInterface::LWIPSocket::send(const void *voiddata, uint32_t size) +int LWIPInterface::socket_accept(void *handle, void **connection) { - uint8_t *data = (uint8_t *)voiddata; - uint32_t writtenLen = 0; + return NSAPI_ERROR_UNSUPPORTED; +} - while (writtenLen < size) { - int ret = lwip_send(fd, data + writtenLen, size - writtenLen, 0); +int LWIPInterface::socket_send(void *handle, const void *p, unsigned size) +{ + 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) { - writtenLen += ret; + written += ret; } else if (ret == 0) { - return NS_ERROR_NO_CONNECTION; + return NSAPI_ERROR_NO_CONNECTION; } else { - return NS_ERROR_DEVICE_ERROR; + return NSAPI_ERROR_DEVICE_ERROR; } } - return writtenLen; + return written; } -int32_t LWIPInterface::LWIPSocket::recv(void *data, uint32_t size) +int LWIPInterface::socket_recv(void *handle, void *data, unsigned size) { + int fd = (int)handle-1; int ret = lwip_recv(fd, data, size, MSG_DONTWAIT); if (ret > 0) { return ret; } else if (ret == 0) { - return NS_ERROR_NO_CONNECTION; + return NSAPI_ERROR_NO_CONNECTION; } else if (ret == -1) { - return NS_ERROR_WOULD_BLOCK; + return NSAPI_ERROR_WOULD_BLOCK; } else { - return NS_ERROR_DEVICE_ERROR; + return NSAPI_ERROR_DEVICE_ERROR; } } +int LWIPInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *p, unsigned size) +{ + int fd = (int)handle-1; + uint8_t *data = (uint8_t *)p; + unsigned written = 0; + + 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; + } + } + + return written; +} + +int LWIPInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + int fd = (int)handle-1; + struct sockaddr_in sa; + socklen_t sa_len = sizeof sa; + + 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)); + } + + 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 NSAPI_ERROR_DEVICE_ERROR; + } +} + +int LWIPInterface::socket_close(void *handle, bool shutdown) +{ + int fd = (int)handle-1; + if (shutdown) { + lwip_shutdown(fd, SHUT_RDWR); + } + + lwip_close(fd); + return 0; +} + +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_recv(void *handle, void (*callback)(void *), void *id) +{ +} diff --git a/net/LWIPInterface/LWIPInterface.h b/net/LWIPInterface/LWIPInterface.h index 4d5b467a5e..055b7edda2 100644 --- a/net/LWIPInterface/LWIPInterface.h +++ b/net/LWIPInterface/LWIPInterface.h @@ -28,36 +28,166 @@ class LWIPInterface : public EthernetInterface { public: + /** Start the interface + * @return 0 on success, negative on failure + */ + virtual int connect(); - // Implementation of EthernetInterface - virtual int32_t connect(); - virtual int32_t disconnect(); + /** Stop the interface + * @return 0 on success, negative on failure + */ + virtual int disconnect(); - // Implementation of NetworkInterface - virtual const char *getIPAddress(); - virtual const char *getMACAddress(); + /** Get the internally stored IP address + /return IP address of the interface or null if not yet connected + */ + virtual const char *get_ip_address(); - virtual SocketInterface *createSocket(ns_protocol_t proto); - virtual void destroySocket(SocketInterface *socket); + /** Get the internally stored MAC address + /return MAC address of the interface + */ + virtual const char *get_mac_address(); -private: +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); - // Implementation of the TCP SocketInterface for LWIP - class LWIPSocket : public SocketInterface - { - public: + /** Destroy a socket + /param socket Previously allocated socket + */ + virtual void socket_destroy(void *handle); - LWIPSocket(int fd) : fd(fd) {} - int fd; + /** 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); - // Implementation of SocketInterface - virtual int32_t open(const char *ip, uint16_t port); - virtual int32_t close(); + /** 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); - virtual int32_t send(const void *data, uint32_t size); - virtual int32_t recv(void *data, uint32_t size); - }; + /** 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); + + /** 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 + */ + 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 + */ + 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 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); + + /** 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 + */ + 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 + */ + 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 + */ + 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 + */ + virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); + + /** 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); + + /** 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); }; - #endif diff --git a/net/LWIPInterface/lwip/COPYING b/net/LWIPInterface/lwip/COPYING deleted file mode 100644 index e23898b5e8..0000000000 --- a/net/LWIPInterface/lwip/COPYING +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2001, 2002 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - - diff --git a/net/NetworkSocketAPI/DnsQuery/DnsQuery.cpp b/net/NetworkSocketAPI/DnsQuery/DnsQuery.cpp index 8cf6ca367e..e940e34694 100644 --- a/net/NetworkSocketAPI/DnsQuery/DnsQuery.cpp +++ b/net/NetworkSocketAPI/DnsQuery/DnsQuery.cpp @@ -109,33 +109,7 @@ static bool resolve(unsigned char *resp, char *ipaddress) return false; } - -int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip) -{ - if (isIP(host)) { - strcpy(ip, host); - return 0; - } - - UDPSocket sock(iface); - int32_t err; - - for (unsigned i = 0; i < DNS_COUNT; i++) { - err = sock.open(DNS_IPS[0], 53); - if (err < 0) { - return err; - } - - err = dnsQuery(&sock, host, ip); - sock.close(); - return err; - } - - sock.close(); - return NS_ERROR_DNS_FAILURE; -} - -int32_t dnsQuery(UDPSocket *socket, const char *hostname, char *ipaddress) +static int32_t query(UDPSocket *socket, const SocketAddress &addr, const char *hostname, char *ipaddress) { int len = 0; if (hostname == NULL) { @@ -184,7 +158,7 @@ int32_t dnsQuery(UDPSocket *socket, const char *hostname, char *ipaddress) packet[c++] = 1; - if (socket->send(packet, packetlen) < 0) { + if (socket->sendto(addr, packet, packetlen) < 0) { delete packet; return false; } @@ -194,21 +168,49 @@ int32_t dnsQuery(UDPSocket *socket, const char *hostname, char *ipaddress) // Receive the answer from DNS int response_length = 0; - response_length = socket->recv(packet, 1024); + response_length = socket->recvfrom(NULL, packet, 1024); if (response_length > 0 ) { if (!resolve(packet, ipaddress)) { delete packet; - return NS_ERROR_DNS_FAILURE; + return NSAPI_ERROR_DNS_FAILURE; } - + // cleanup and return delete packet; return 0; } delete packet; - return NS_ERROR_DNS_FAILURE; + return NSAPI_ERROR_DNS_FAILURE; } +int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip) +{ + if (isIP(host)) { + strcpy(ip, host); + return 0; + } + UDPSocket sock(iface); + + for (unsigned i = 0; i < DNS_COUNT; i++) { + return query(&sock, SocketAddress(DNS_IPS[0], 53), host, ip); + } + + return NSAPI_ERROR_DNS_FAILURE; +} + +int32_t dnsQuery(UDPSocket *socket, const char *host, char *ip) +{ + if (isIP(host)) { + strcpy(ip, host); + return 0; + } + + for (unsigned i = 0; i < DNS_COUNT; i++) { + return query(socket, SocketAddress(DNS_IPS[0], 53), host, ip); + } + + return NSAPI_ERROR_DNS_FAILURE; +} diff --git a/net/NetworkSocketAPI/EthernetInterface.h b/net/NetworkSocketAPI/EthernetInterface.h index 9caf067294..a48846f650 100644 --- a/net/NetworkSocketAPI/EthernetInterface.h +++ b/net/NetworkSocketAPI/EthernetInterface.h @@ -1,4 +1,4 @@ -/* EthernetInterface Base Class +/* Socket * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,14 +26,14 @@ class EthernetInterface : public NetworkInterface { public: /** Start the interface - * @return 0 on success + * @return 0 on success, negative on failure */ - virtual int32_t connect() = 0; + virtual int connect() = 0; /** Stop the interface - * @return 0 on success + * @return 0 on success, negative on failure */ - virtual int32_t disconnect() = 0; + virtual int disconnect() = 0; }; #endif diff --git a/net/NetworkSocketAPI/NetworkInterface.cpp b/net/NetworkSocketAPI/NetworkInterface.cpp index b5e53140de..455d3ddf3b 100644 --- a/net/NetworkSocketAPI/NetworkInterface.cpp +++ b/net/NetworkSocketAPI/NetworkInterface.cpp @@ -1,4 +1,4 @@ -/* NetworkInterface Base Class +/* Socket * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,16 +14,10 @@ * limitations under the License. */ -#include "NetworkInterface.h" #include "DnsQuery.h" +#include "mbed.h" - -bool NetworkInterface::isConnected() +int NetworkInterface::gethostbyname(const char *name, char *dest) { - return getIPAddress() != 0; -} - -int32_t NetworkInterface::getHostByName(const char *name, char *ip) -{ - return dnsQuery(this, name, ip); + return dnsQuery(this, name, dest); } diff --git a/net/NetworkSocketAPI/NetworkInterface.h b/net/NetworkSocketAPI/NetworkInterface.h index d63750e576..bb167ad688 100644 --- a/net/NetworkSocketAPI/NetworkInterface.h +++ b/net/NetworkSocketAPI/NetworkInterface.h @@ -1,4 +1,4 @@ -/* NetworkInterface Base Class +/* Socket * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,29 +17,42 @@ #ifndef NETWORK_INTERFACE_H #define NETWORK_INTERFACE_H -#include "SocketInterface.h" -#include "stdint.h" - -/** Maximum storage needed for IP address and MAC addresses - */ -#define NS_IP_SIZE 16 -#define NS_MAC_SIZE 18 +#ifndef MBED_OPERATORS +#define MBED_OPERATORS +#endif +#include "FunctionPointer.h" +#include "SocketAddress.h" /** * @enum ns_error_t * @brief enum of standardized error codes */ -enum ns_error_t { - NS_ERROR_WOULD_BLOCK = -3000, /*!< no data is not available but call is non-blocking */ - NS_ERROR_TIMEOUT = -3001, /*!< operation took longer than allowed */ - NS_ERROR_NO_CONNECTION = -3002, /*!< not connected to a network */ - NS_ERROR_NO_SOCKET = -3003, /*!< socket not available for use */ - NS_ERROR_NO_ADDRESS = -3004, /*!< IP address is not known */ - NS_ERROR_NO_MEMORY = -3005, /*!< memory resource not available */ - NS_ERROR_DNS_FAILURE = -3006, /*!< DNS failed to complete successfully */ - NS_ERROR_DHCP_FAILURE = -3007, /*!< DHCP failed to complete successfully */ - NS_ERROR_AUTH_FAILURE = -3008, /*!< connection to access point faield */ - NS_ERROR_DEVICE_ERROR = -3009 /*!< failure interfacing with the network procesor */ +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 */ +}; + +/** + * @enum ns_opt_t + * @brief enum of available options + */ +enum ns_opt_t { +}; + +/** Enum of socket protocols +/enum protocol_t +*/ +enum nsapi_protocol_t { + NSAPI_TCP, /*!< Socket is of TCP type */ + NSAPI_UDP, /*!< Socket is of UDP type */ }; /** NetworkInterface class @@ -51,42 +64,175 @@ class NetworkInterface public: virtual ~NetworkInterface() {}; - /** Get the IP address - * @return IP address of the interface or 0 if not yet connected - */ - virtual const char *getIPAddress() = 0; + /** 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 current MAC address - * @return String MAC address of the interface - */ - virtual const char *getMACAddress() = 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 isConnected(); + /return true if connected + */ + virtual bool is_connected() { + return get_ip_address() != NULL; + } /** Looks up the specified host's IP address - * @param name URL of host - * @param ip Buffer to hold IP address, must be at least SOCK_IP_SIZE - * @return 0 on success - */ - virtual int32_t getHostByName(const char *name, char *ip); + /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: friend class Socket; + friend class UDPSocket; + friend class TCPSocket; + friend class TCPServer; - /** Internally create a socket - * @param proto The type of socket to open, NS_TCP or NS_UDP - * @return The allocated socket - */ - virtual SocketInterface *createSocket(ns_protocol_t proto) = 0; + /** 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) = 0; - /** Internally destroy a socket - * @param socket An allocated SocketInterface - * @returns 0 on success - */ - virtual void destroySocket(SocketInterface *socket) = 0; + /** Destroy a 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 + */ + 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 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 + */ + 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 + */ + 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 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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; }; #endif diff --git a/net/NetworkSocketAPI/Socket.cpp b/net/NetworkSocketAPI/Socket.cpp index 92618b7fbb..88ce3ee685 100644 --- a/net/NetworkSocketAPI/Socket.cpp +++ b/net/NetworkSocketAPI/Socket.cpp @@ -15,116 +15,68 @@ */ #include "Socket.h" -#include -Socket::Socket(NetworkInterface *iface, ns_protocol_t proto) +Socket::Socket(NetworkInterface *iface, nsapi_protocol_t proto) : _iface(iface) - , _proto(proto) - , _socket(0) + , _blocking(true) + , _timeout(0) { - memset(_ip_address, 0, NS_IP_SIZE); - _port = 0; + _socket = _iface->socket_create(proto); } Socket::~Socket() { if (_socket) { - close(); + close(false); } } - -int32_t Socket::open(const char *address, uint16_t port) +void Socket::set_blocking(bool blocking) { - int32_t err; - - err = close(); - if (err) { - return err; - } - - err = _iface->getHostByName(address, _ip_address); - _port = port; - if (err) { - return err; - } - - _socket = _iface->createSocket(_proto); - if (!_socket) { - return NS_ERROR_NO_SOCKET; - } - - err = _socket->open(_ip_address, _port); - - if (err) { - _iface->destroySocket(_socket); - _socket = 0; - } - - return err; + _blocking = blocking; } -int32_t Socket::close() +void Socket::set_timeout(unsigned timeout) +{ + _timeout = timeout; +} + +int Socket::set_option(int optname, const void *optval, unsigned int optlen) +{ + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + return _iface->socket_set_option(_socket, optname, optval, optlen); +} + +int Socket::get_option(int optname, void *optval, unsigned int *optlen) +{ + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + return _iface->socket_get_option(_socket, optname, optval, optlen); +} + +int Socket::close(bool shutdown) { if (!_socket) { return 0; } - - SocketInterface *socket = _socket; - _socket = 0; - int32_t err = socket->close(); + int err = _iface->socket_close(_socket, shutdown); if (!err) { - _iface->destroySocket(socket); + void *socket = _socket; + _socket = 0; + _iface->socket_destroy(socket); } return err; } -int32_t Socket::send(const void *data, uint32_t size) +void Socket::thunk(void *p) { - if (!_socket) { - return NS_ERROR_NO_CONNECTION; - } - return _socket->send(data, size); + mbed::FuncPtr *fptr = (mbed::FuncPtr *)p; + (*fptr)(); } - -int32_t Socket::recv(void *data, uint32_t size, bool blocking) -{ - while (true) { - if (!_socket) { - return NS_ERROR_NO_CONNECTION; - } - - int32_t recv = _socket->recv(data, size); - - if (recv != NS_ERROR_WOULD_BLOCK || !blocking) { - return recv; - } - } -} - - -const char *Socket::getIPAddress() const -{ - if (_ip_address[0]) { - return _ip_address; - } else { - return 0; - } -} - -uint16_t Socket::getPort() const -{ - return _port; -} - -bool Socket::isConnected() -{ - if (!_socket) { - return false; - } - - return _socket->isConnected(); -} - diff --git a/net/NetworkSocketAPI/Socket.h b/net/NetworkSocketAPI/Socket.h index f02fc29246..6fb8d6127f 100644 --- a/net/NetworkSocketAPI/Socket.h +++ b/net/NetworkSocketAPI/Socket.h @@ -17,69 +17,57 @@ #ifndef SOCKET_H #define SOCKET_H +#include "SocketAddress.h" #include "NetworkInterface.h" /** Abstract socket class - * API for handling general sockets. Supports IP address operations - * and sending/recieving data. */ -class Socket -{ +class Socket { public: - ~Socket(); - - /** Open a connection to the underlying address - * @param address URL or IP address to connect to - * @param port Port to connect to - * @return 0 on success + /** Socket lifetime */ - int32_t open(const char *address, uint16_t port); + virtual ~Socket(); + + /** Set blocking or non-blocking mode of the socket + \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 + */ + void set_timeout(unsigned int timeout); - /** Close an open connection - * @return 0 on success - */ - int32_t close(); - - /** Send data over the socket - * @param data Buffer of data to send - * @param size Size of data to send - * @return Number of bytes sent or a negative value on failure - */ - int32_t send(const void *data, uint32_t size); - - /** Recieve data over the socket - * @param data Buffer to store recieved data - * @param size Size of provided buffer - * @param blocking If true wait for data, otherwise return NS_ERROR_WOULD_BLOCK - * @return Number of bytes recieved or a negative value on failure - */ - int32_t recv(void *data, uint32_t size, bool blocking = true); - - /** Gets the IP address - * @return IP address to connect to - */ - const char *getIPAddress() const; - - /** Gets the port - * @return Port to connect to - */ - uint16_t getPort() const; - - /** Returns status of socket - * @return true if connected - */ - bool isConnected(); + /** 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 + */ + 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); protected: - Socket(NetworkInterface *iface, ns_protocol_t proto); + Socket(NetworkInterface *iface, nsapi_protocol_t proto); + + static void thunk(void *); -private: NetworkInterface *_iface; - ns_protocol_t _proto; - SocketInterface *_socket; - - char _ip_address[NS_IP_SIZE]; - uint16_t _port; + void *_socket; + bool _blocking; + unsigned _timeout; }; #endif diff --git a/net/NetworkSocketAPI/SocketAddress.cpp b/net/NetworkSocketAPI/SocketAddress.cpp new file mode 100644 index 0000000000..f57fd8253f --- /dev/null +++ b/net/NetworkSocketAPI/SocketAddress.cpp @@ -0,0 +1,67 @@ +/* Socket + * 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. + */ + +#include "SocketAddress.h" +#include "NetworkInterface.h" +#include +#include "mbed.h" + +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; + } +} + +SocketAddress::SocketAddress(const char *addr, uint16_t port) +{ + set_ip_address(addr); + set_port(port); +} + +SocketAddress::SocketAddress(const SocketAddress &addr) +{ + set_ip_address(addr.get_ip_address()); + 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'; +} + +void SocketAddress::set_port(uint16_t port) +{ + _port = port; +} + +const char *SocketAddress::get_ip_address() const +{ + if (!_ip_address[0]) { + return 0; + } + return _ip_address; +} + +uint16_t SocketAddress::get_port() const +{ + return _port; +} diff --git a/net/NetworkSocketAPI/SocketAddress.h b/net/NetworkSocketAPI/SocketAddress.h new file mode 100644 index 0000000000..e6fedc2496 --- /dev/null +++ b/net/NetworkSocketAPI/SocketAddress.h @@ -0,0 +1,83 @@ +/* Socket + * 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 SOCKET_ADDRESS_H +#define SOCKET_ADDRESS_H + +#include + +/** Maximum size of IP address +*/ +#define NSAPI_IP_SIZE 16 + +/** Maximum size of MAC address +*/ +#define NSAPI_MAC_SIZE 18 + +// Predeclared classes +class NetworkInterface; + +/** + * A general socket address composed of the IP address and 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 + */ + 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 + */ + SocketAddress(const char *addr = 0, 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 + */ + void set_ip_address(const char *addr); + + /** 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 + */ + const char *get_ip_address() const; + + /** Get the port + \return The 16-bit port + */ + uint16_t get_port(void) const; + +private: + char _ip_address[NSAPI_IP_SIZE]; + uint16_t _port; +}; + +#endif diff --git a/net/NetworkSocketAPI/SocketInterface.h b/net/NetworkSocketAPI/SocketInterface.h deleted file mode 100644 index 3ca975bc20..0000000000 --- a/net/NetworkSocketAPI/SocketInterface.h +++ /dev/null @@ -1,83 +0,0 @@ -/* SocketInterface Base Class - * 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 SOCKET_INTERFACE_H -#define SOCKET_INTERFACE_H - -#include "stdint.h" - - -/** - * @enum ns_protocol_t - * @brief enum of socket protocols - */ -enum ns_protocol_t { - NS_TCP, /*!< Socket is of TCP type */ - NS_UDP, /*!< Socket is of UDP type */ -}; - - -/** SocketInterface class - * Common interface for implementation specific sockets created through - * network interfaces. This class is used internally by the - * TCPSocket and UDPSocket classes - */ -class SocketInterface -{ -public: - - virtual ~SocketInterface() {} - - /** Open a connection to the underlying address - * @param ip IP address to connect to - * @param port Port to connect to - * @return 0 on success - */ - virtual int32_t open(const char *ip, uint16_t port) = 0; - - /** Close an open connection - * @return 0 on success - */ - virtual int32_t close() = 0; - - /** Send data - * @param data Buffer of data to send - * @param size Size of data to send - * @return Number of bytes received or a negative value on success - */ - virtual int32_t send(const void *data, uint32_t size) = 0; - - /** Receive data - * @note - * This call should return immediately with a value of - * NS_ERROR_WOULD_BOCK if no data is available. - * - * @param data A buffer to store the data in - * @param size Size of buffer - * @return Number of bytes received or a negative value on failure - */ - virtual int32_t recv(void *data, uint32_t size) = 0; - - /** Status of the socket - * @return True if connected - */ - virtual bool isConnected() { - // By default return true if socket was created successfully - return true; - } -}; - -#endif diff --git a/net/NetworkSocketAPI/TCPServer.cpp b/net/NetworkSocketAPI/TCPServer.cpp new file mode 100644 index 0000000000..535c69f2ff --- /dev/null +++ b/net/NetworkSocketAPI/TCPServer.cpp @@ -0,0 +1,87 @@ +/* Socket + * 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. + */ + +#include "TCPServer.h" +#include "Timer.h" + +TCPServer::TCPServer(NetworkInterface *iface) + : Socket(iface, NSAPI_TCP) +{ +} + +int TCPServer::bind(uint16_t port) +{ + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + return _iface->socket_bind(_socket, port); +} + +int TCPServer::listen(int backlog) +{ + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + return _iface->socket_listen(_socket, backlog); +} + +int TCPServer::accept(TCPSocket *connection) +{ + mbed::Timer timer; + timer.start(); + + void *socket = connection->_socket; + connection->_socket = 0; + _iface->socket_destroy(socket); + + while (true) { + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + int err = _iface->socket_accept(_socket, &socket); + + if (err > 0) { + connection->_socket = socket; + } + + if (err != NSAPI_ERROR_WOULD_BLOCK || !_blocking || + (_timeout && timer.read_ms() > _timeout)) { + return err; + } + } +} + + +void TCPServer::attach_accept(mbed::FuncPtr 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 new file mode 100644 index 0000000000..c8baa1203f --- /dev/null +++ b/net/NetworkSocketAPI/TCPServer.h @@ -0,0 +1,67 @@ +/* Socket + * 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 TCPSERVER_H +#define TCPSERVER_H + +#include "Socket.h" +#include "TCPSocket.h" +#include "NetworkInterface.h" + +/** TCP Server. + */ +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 + */ + 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 + */ + 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. + */ + 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(mbed::FuncPtr callback); + + template + void attach_accept(T *tptr, M mptr) { + attach_accept(mbed::FuncPtr(tptr, mptr)); + } + +private: + mbed::FuncPtr _accept_cb; +}; + +#endif diff --git a/net/NetworkSocketAPI/TCPSocket.cpp b/net/NetworkSocketAPI/TCPSocket.cpp new file mode 100644 index 0000000000..4f917d1d0e --- /dev/null +++ b/net/NetworkSocketAPI/TCPSocket.cpp @@ -0,0 +1,117 @@ +/* Socket + * 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. + */ + +#include "TCPSocket.h" +#include "Timer.h" + +TCPSocket::TCPSocket(NetworkInterface *iface) + : Socket(iface, NSAPI_TCP) +{ +} + +int TCPSocket::connect(const SocketAddress &addr) +{ + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + return _iface->socket_connect(_socket, addr); +} + +int TCPSocket::connect(const char *host, uint16_t port) +{ + SocketAddress addr(_iface, host, port); + if (!addr.get_ip_address()) { + return NSAPI_ERROR_DNS_FAILURE; + } + + 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; + timer.start(); + + while (true) { + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + int sent = _iface->socket_send(_socket, data, size); + if (sent != NSAPI_ERROR_WOULD_BLOCK || !_blocking || + (_timeout && timer.read_ms() > _timeout)) { + return sent; + } + } +} + +int TCPSocket::recv(void *data, unsigned size) +{ + mbed::Timer timer; + timer.start(); + + while (true) { + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + int recv = _iface->socket_recv(_socket, data, size); + if (recv != NSAPI_ERROR_WOULD_BLOCK || !_blocking || + (_timeout && timer.read_ms() > _timeout)) { + return recv; + } + } +} + + +void TCPSocket::attach_send(mbed::FuncPtr 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(mbed::FuncPtr 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 31674e2171..c7845d9140 100644 --- a/net/NetworkSocketAPI/TCPSocket.h +++ b/net/NetworkSocketAPI/TCPSocket.h @@ -1,4 +1,4 @@ -/* TCPSocket +/* Socket * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,26 +14,82 @@ * limitations under the License. */ -#ifndef TCP_SOCKET_H -#define TCP_SOCKET_H +#ifndef TCPSOCKET_H +#define TCPSOCKET_H #include "Socket.h" +#include "NetworkInterface.h" -/** TCPSocket class - * API for handling TCP sockets. The implementation is determined - * by the interface passed during construction. - */ -class TCPSocket : public Socket -{ +/** +TCP socket connection +*/ +class TCPSocket : public Socket { public: - /** Create a socket using the specified network interface - * No network operations are performed until the socket is actually used - * @param iface The network interface to use - * @param url Optional URL to connect to, copied internally - * @param port Optional port to connect to - */ - TCPSocket(NetworkInterface *iface) - : Socket(iface, NS_TCP) {} + /** 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 + */ + 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 + */ + 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 + \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 + */ + 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(mbed::FuncPtr callback); + + template + void attach_send(T *tptr, M mptr) { + attach_send(mbed::FuncPtr(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(mbed::FuncPtr callback); + + template + void attach_recv(T *tptr, M mptr) { + attach_recv(mbed::FuncPtr(tptr, mptr)); + } + +private: + friend class TCPServer; + + mbed::FuncPtr _send_cb; + mbed::FuncPtr _recv_cb; }; #endif diff --git a/net/NetworkSocketAPI/UDPSocket.cpp b/net/NetworkSocketAPI/UDPSocket.cpp new file mode 100644 index 0000000000..5ab756cc9e --- /dev/null +++ b/net/NetworkSocketAPI/UDPSocket.cpp @@ -0,0 +1,100 @@ +/* Socket + * 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. + */ + +#include "UDPSocket.h" +#include "Timer.h" + +UDPSocket::UDPSocket(NetworkInterface *iface) + : Socket(iface, NSAPI_UDP) +{ +} + +int UDPSocket::bind(uint16_t port) +{ + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + return _iface->socket_bind(_socket, port); +} + +int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size) +{ + mbed::Timer timer; + timer.start(); + + while (true) { + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + int sent = _iface->socket_sendto(_socket, address, data, size); + if (sent != NSAPI_ERROR_WOULD_BLOCK || !_blocking || + (_timeout && timer.read_ms() > _timeout)) { + return sent; + } + } +} + +int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size) +{ + mbed::Timer timer; + timer.start(); + + while (true) { + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + int recv = _iface->socket_recvfrom(_socket, address, buffer, size); + if (recv != NSAPI_ERROR_WOULD_BLOCK || !_blocking || + (_timeout && timer.read_ms() > _timeout)) { + return recv; + } + } +} + + +void UDPSocket::attach_send(mbed::FuncPtr 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(mbed::FuncPtr 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 faa4787d3e..a216142242 100644 --- a/net/NetworkSocketAPI/UDPSocket.h +++ b/net/NetworkSocketAPI/UDPSocket.h @@ -1,4 +1,4 @@ -/* UDPSocket +/* Socket * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,26 +14,71 @@ * limitations under the License. */ -#ifndef UDP_SOCKET_H -#define UDP_SOCKET_H +#ifndef UDPSOCKET_H +#define UDPSOCKET_H #include "Socket.h" +#include "NetworkInterface.h" -/** UDPSocket class - * API for handling UDP sockets. The implementation is determined - * by the interface passed during construction. - */ -class UDPSocket : public Socket -{ +/** +UDP Socket +*/ +class UDPSocket : public Socket { public: - /** Create a socket using the specified network interface - * No network operations are performed until the socket is actually used - * @param iface The network interface to use - * @param ip Optional URL to connect to, copied internally - * @param port Optional port to connect to - */ - UDPSocket(NetworkInterface *iface) - : Socket(iface, NS_UDP) {} + /** 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. + */ + 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 + */ + 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 + */ + 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(mbed::FuncPtr callback); + + template + void attach_send(T *tptr, M mptr) { + attach_send(mbed::FuncPtr(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(mbed::FuncPtr callback); + + template + void attach_recv(T *tptr, M mptr) { + attach_recv(mbed::FuncPtr(tptr, mptr)); + } + +private: + mbed::FuncPtr _send_cb; + mbed::FuncPtr _recv_cb; }; #endif diff --git a/net/NetworkSocketAPI/WiFiInterface.h b/net/NetworkSocketAPI/WiFiInterface.h index e91ef5a212..541a6a8fa8 100644 --- a/net/NetworkSocketAPI/WiFiInterface.h +++ b/net/NetworkSocketAPI/WiFiInterface.h @@ -1,4 +1,4 @@ -/* WiFiInterface Base Class +/* Socket * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,15 +20,14 @@ #include "NetworkInterface.h" /** Enum for WiFi encryption types - */ -enum ns_security_t { - NS_SECURITY_NONE = 0, /*!< open access point */ - NS_SECURITY_WEP, /*!< phrase conforms to WEP */ - NS_SECURITY_WPA, /*!< phrase conforms to WPA */ - NS_SECURITY_WPA2, /*!< phrase conforms to WPA2 */ +*/ +enum nsapi_security_t { + NSAPI_SECURITY_NONE = 0, /*!< open access point */ + NSAPI_SECURITY_WEP, /*!< phrase conforms to WEP */ + NSAPI_SECURITY_WPA, /*!< phrase conforms to WPA */ + NSAPI_SECURITY_WPA2, /*!< phrase conforms to WPA2 */ }; - /** WiFiInterface class * Common interface that is shared between WiFi devices */ @@ -36,17 +35,17 @@ 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 to connect with - * @return 0 on success - */ - virtual int32_t connect(const char *ssid, const char *pass, ns_security_t security = NS_SECURITY_NONE) = 0; + /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 - */ - virtual int32_t disconnect() = 0; + /return 0 on success, negative on failure + */ + virtual int disconnect() = 0; }; #endif