From cdbe43c0d52c4f4f9e68687d23adffe824f3f1a4 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 17 May 2018 21:36:15 +0100 Subject: [PATCH] Refactor Sockets by moving functions up into common base. * Move IP Socket stuff to InternetSocket class which is inherited by TCP/UDP * Implement sendto() and recvfrom() on TCP socket * Implement connect() call on UDP * Implement send() and recv() calls on UDP socket --- .../{Socket.cpp => InternetSocket.cpp} | 42 +-- features/netsocket/InternetSocket.h | 232 +++++++++++++++++ features/netsocket/NetworkInterface.h | 6 +- features/netsocket/NetworkStack.h | 2 +- features/netsocket/Socket.h | 244 +++++++++--------- features/netsocket/SocketAddress.cpp | 3 +- features/netsocket/TCPServer.cpp | 27 +- features/netsocket/TCPServer.h | 42 ++- features/netsocket/TCPSocket.cpp | 18 ++ features/netsocket/TCPSocket.h | 35 ++- features/netsocket/UDPSocket.cpp | 20 ++ features/netsocket/UDPSocket.h | 49 +++- 12 files changed, 550 insertions(+), 170 deletions(-) rename features/netsocket/{Socket.cpp => InternetSocket.cpp} (72%) create mode 100644 features/netsocket/InternetSocket.h diff --git a/features/netsocket/Socket.cpp b/features/netsocket/InternetSocket.cpp similarity index 72% rename from features/netsocket/Socket.cpp rename to features/netsocket/InternetSocket.cpp index 7317648b65..5179f8a26f 100644 --- a/features/netsocket/Socket.cpp +++ b/features/netsocket/InternetSocket.cpp @@ -1,4 +1,4 @@ -/* Socket +/* InternetSocket * Copyright (c) 2015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,17 +14,19 @@ * limitations under the License. */ -#include "Socket.h" -#include "mbed.h" +#include "InternetSocket.h" +#include "platform/Callback.h" -Socket::Socket() +using namespace mbed; + +InternetSocket::InternetSocket() : _stack(0) , _socket(0) , _timeout(osWaitForever) { } -nsapi_error_t Socket::open(NetworkStack *stack) +nsapi_error_t InternetSocket::open(NetworkStack *stack) { _lock.lock(); @@ -42,14 +44,14 @@ nsapi_error_t Socket::open(NetworkStack *stack) } _socket = socket; - _event = callback(this, &Socket::event); + _event = callback(this, &InternetSocket::event); _stack->socket_attach(_socket, Callback::thunk, &_event); _lock.unlock(); return NSAPI_ERROR_OK; } -nsapi_error_t Socket::close() +nsapi_error_t InternetSocket::close() { _lock.lock(); @@ -70,7 +72,7 @@ nsapi_error_t Socket::close() return ret; } -int Socket::modify_multicast_group(const SocketAddress &address, nsapi_socket_option_t socketopt) +int InternetSocket::modify_multicast_group(const SocketAddress &address, nsapi_socket_option_t socketopt) { nsapi_ip_mreq_t mreq; @@ -81,32 +83,32 @@ int Socket::modify_multicast_group(const SocketAddress &address, nsapi_socket_op return this->setsockopt(NSAPI_SOCKET, socketopt, &mreq, sizeof(mreq)); } -int Socket::join_multicast_group(const SocketAddress &address) +int InternetSocket::join_multicast_group(const SocketAddress &address) { return modify_multicast_group(address, NSAPI_ADD_MEMBERSHIP); } -int Socket::leave_multicast_group(const SocketAddress &address) +int InternetSocket::leave_multicast_group(const SocketAddress &address) { return modify_multicast_group(address, NSAPI_DROP_MEMBERSHIP); } -nsapi_error_t Socket::bind(uint16_t port) +nsapi_error_t InternetSocket::bind(uint16_t port) { // Underlying bind is thread safe SocketAddress addr(0, port); return bind(addr); } -nsapi_error_t Socket::bind(const char *address, uint16_t port) +nsapi_error_t InternetSocket::bind(const char *address, uint16_t port) { // Underlying bind is thread safe SocketAddress addr(address, port); return bind(addr); } -nsapi_error_t Socket::bind(const SocketAddress &address) +nsapi_error_t InternetSocket::bind(const SocketAddress &address) { _lock.lock(); nsapi_error_t ret; @@ -121,13 +123,13 @@ nsapi_error_t Socket::bind(const SocketAddress &address) return ret; } -void Socket::set_blocking(bool blocking) +void InternetSocket::set_blocking(bool blocking) { - // Socket::set_timeout is thread safe + // InternetSocket::set_timeout is thread safe set_timeout(blocking ? -1 : 0); } -void Socket::set_timeout(int timeout) +void InternetSocket::set_timeout(int timeout) { _lock.lock(); @@ -140,7 +142,7 @@ void Socket::set_timeout(int timeout) _lock.unlock(); } -nsapi_error_t Socket::setsockopt(int level, int optname, const void *optval, unsigned optlen) +nsapi_error_t InternetSocket::setsockopt(int level, int optname, const void *optval, unsigned optlen) { _lock.lock(); nsapi_error_t ret; @@ -155,7 +157,7 @@ nsapi_error_t Socket::setsockopt(int level, int optname, const void *optval, uns return ret; } -nsapi_error_t Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen) +nsapi_error_t InternetSocket::getsockopt(int level, int optname, void *optval, unsigned *optlen) { _lock.lock(); nsapi_error_t ret; @@ -171,14 +173,14 @@ nsapi_error_t Socket::getsockopt(int level, int optname, void *optval, unsigned } -void Socket::sigio(Callback callback) +void InternetSocket::sigio(Callback callback) { _lock.lock(); _callback = callback; _lock.unlock(); } -void Socket::attach(Callback callback) +void InternetSocket::attach(Callback callback) { sigio(callback); } diff --git a/features/netsocket/InternetSocket.h b/features/netsocket/InternetSocket.h new file mode 100644 index 0000000000..ec1a81cc56 --- /dev/null +++ b/features/netsocket/InternetSocket.h @@ -0,0 +1,232 @@ + +/** \addtogroup netsocket */ +/** @{*/ +/* 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 INTERNETSOCKET_H +#define INTERNETSOCKET_H + +#include "netsocket/Socket.h" +#include "netsocket/NetworkStack.h" +#include "rtos/Mutex.h" +#include "Callback.h" +#include "mbed_toolchain.h" + +/** Socket implementation that uses IP network stack. + * Not to be directly used by applications. Cannot be directly instantiated. + */ +class InternetSocket : public Socket { +public: + /** Destroy a socket + * + * Closes socket if the socket is still open + */ + virtual ~InternetSocket() {} + + /** Opens a socket + * + * Creates a network socket on the network stack of the given + * network interface. Not needed if stack is passed to the + * socket's constructor. + * + * @param stack Network stack as target for socket + * @return 0 on success, negative error code on failure + */ + nsapi_error_t open(NetworkStack *stack); + + template + nsapi_error_t open(S *stack) { + return open(nsapi_create_stack(stack)); + } + + /** 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 + */ + virtual nsapi_error_t close(); + + /** Subscribes to an IP multicast group + * + * @param address Multicast group IP address + * @return Negative error code on failure + */ + int join_multicast_group(const SocketAddress &address); + + /** Leave an IP multicast group + * + * @param address Multicast group IP address + * @return Negative error code on failure + */ + int leave_multicast_group(const SocketAddress &address); + + + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to receive + * data. + * + * @param port Local port to bind + * @return 0 on success, negative error code on failure. + */ + nsapi_error_t bind(uint16_t port); + + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to receive + * 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. + */ + nsapi_error_t bind(const char *address, uint16_t port); + + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to receive + * 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. + */ + virtual nsapi_error_t bind(const SocketAddress &address); + + /** Set blocking or non-blocking mode of the socket + * + * 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. + * + * 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. + */ + virtual void set_blocking(bool blocking); + + /** 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 the timeout from the socket. A negative + * value give the socket an unbounded timeout. + * + * set_timeout(0) is equivalent to set_blocking(false) + * set_timeout(-1) is equivalent to set_blocking(true) + * + * @param timeout Timeout in milliseconds + */ + virtual void set_timeout(int timeout); + + /* Set socket options + * + * setsockopt allows an application to pass stack-specific options + * to the underlying stack using stack-specific level and option names, + * or to request generic options using levels from nsapi_socket_level_t. + * + * For unsupported options, NSAPI_ERROR_UNSUPPORTED is returned + * and the socket is unmodified. + * + * @param level Stack-specific protocol level or nsapi_socket_level_t + * @param optname Level-specific option name + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen); + + /* Get socket options + * + * getsockopt allows an application to retrieve stack-specific options + * from the underlying stack using stack-specific level and option names, + * or to request generic options using levels from nsapi_socket_level_t. + * + * For unsupported options, NSAPI_ERROR_UNSUPPORTED is returned + * and the socket is unmodified. + * + * @param level Stack-specific protocol level or nsapi_socket_level_t + * @param optname Level-specific option name + * @param optval Destination for option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t 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. + * + * Note! This is not intended as a replacement for a poll or attach-like + * asynchronous api, but rather as a building block for constructing + * such functionality. The exact timing of when the registered function + * is called is not guaranteed and susceptible to change. + * + * @param func Function to call on state change + */ + virtual void sigio(mbed::Callback func); + + /** Register a callback on state change of the socket + * + * @see Socket::sigio + * @deprecated + * The behaviour of Socket::attach differs from other attach functions in + * mbed OS and has been known to cause confusion. Replaced by Socket::sigio. + */ + MBED_DEPRECATED_SINCE("mbed-os-5.4", + "The behaviour of Socket::attach differs from other attach functions in " + "mbed OS and has been known to cause confusion. Replaced by Socket::sigio.") + void attach(mbed::Callback func); + + /** Register a callback on state change of the socket + * + * @see Socket::sigio + * @deprecated + * The attach function does not support cv-qualifiers. Replaced by + * attach(callback(obj, method)). + */ + template + MBED_DEPRECATED_SINCE("mbed-os-5.1", + "The attach function does not support cv-qualifiers. Replaced by " + "attach(callback(obj, method)).") + void attach(T *obj, M method) { + attach(mbed::callback(obj, method)); + } + +protected: + InternetSocket(); + virtual nsapi_protocol_t get_proto() = 0; + virtual void event() = 0; + int modify_multicast_group(const SocketAddress &address, nsapi_socket_option_t socketopt); + + NetworkStack *_stack; + nsapi_socket_t _socket; + uint32_t _timeout; + mbed::Callback _event; + mbed::Callback _callback; + rtos::Mutex _lock; + SocketAddress _remote_peer; +}; + +#endif // INTERNETSOCKET_H diff --git a/features/netsocket/NetworkInterface.h b/features/netsocket/NetworkInterface.h index e164288bb0..5c9afd57da 100644 --- a/features/netsocket/NetworkInterface.h +++ b/features/netsocket/NetworkInterface.h @@ -84,7 +84,7 @@ public: * Provided MAC address is intended for info or debug purposes and * may not be provided if the underlying network interface does not * provide a MAC address - * + * * @return Null-terminated representation of the local MAC address * or null if no MAC address is available */ @@ -99,7 +99,7 @@ public: /** Get the local network mask * - * @return Null-terminated representation of the local network mask + * @return Null-terminated representation of the local network mask * or null if no network mask has been received */ virtual const char *get_netmask(); @@ -270,7 +270,7 @@ public: } protected: - friend class Socket; + friend class InternetSocket; friend class UDPSocket; friend class TCPSocket; friend class TCPServer; diff --git a/features/netsocket/NetworkStack.h b/features/netsocket/NetworkStack.h index 6e8fcb7f0e..96acf96626 100644 --- a/features/netsocket/NetworkStack.h +++ b/features/netsocket/NetworkStack.h @@ -165,7 +165,7 @@ public: virtual OnboardNetworkStack *onboardNetworkStack() { return 0; } protected: - friend class Socket; + friend class InternetSocket; friend class UDPSocket; friend class TCPSocket; friend class TCPServer; diff --git a/features/netsocket/Socket.h b/features/netsocket/Socket.h index 8c74a9e60c..05bbe3ffc6 100644 --- a/features/netsocket/Socket.h +++ b/features/netsocket/Socket.h @@ -21,93 +21,121 @@ #define SOCKET_H #include "netsocket/SocketAddress.h" -#include "netsocket/NetworkStack.h" -#include "rtos/Mutex.h" #include "Callback.h" -#include "mbed_toolchain.h" - /** Abstract socket class */ class Socket { public: - /** Destroy a socket + /** Destroy a socket. * * Closes socket if the socket is still open */ virtual ~Socket() {} - /** Opens a socket - * - * Creates a network socket on the network stack of the given - * network interface. Not needed if stack is passed to the - * socket's constructor. - * - * @param stack Network stack as target for socket - * @return 0 on success, negative error code on failure - */ - nsapi_error_t open(NetworkStack *stack); - - template - nsapi_error_t open(S *stack) { - return open(nsapi_create_stack(stack)); - } - - /** Close the socket + /** 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 */ - nsapi_error_t close(); - - /** Subscribes to an IP multicast group - * - * @param address Multicast group IP address - * @return Negative error code on failure - */ - int join_multicast_group(const SocketAddress &address); + virtual nsapi_error_t close() = 0; - /** Leave an IP multicast group + /** Connects socket to a remote host. * - * @param address Multicast group IP address - * @return Negative error code on failure + * Initiates a connection to a remote server specified by the + * indicated address. In case of connectionless protocol, set + * the remote address for next send() call. + * + * @param address The SocketAddress of the remote host + * @return 0 on success, negative error code on failure */ - int leave_multicast_group(const SocketAddress &address); + virtual nsapi_error_t connect(const SocketAddress &address) = 0; - /** Bind a specific address to a socket + /** Send data on a socket * - * Binding a socket specifies the address and port on which to receive - * data. + * The socket must be connected to a remote host before send() call. + * Returns the number of bytes sent from the buffer. + * In case of connectionless socket, send data to pre-specified remote. * - * @param port Local port to bind - * @return 0 on success, negative error code on failure. + * By default, send blocks until all data is sent. If socket is set to + * non-blocking or times out, a partial amount can be written. + * NSAPI_ERROR_WOULD_BLOCK is returned if no data was written. + * + * @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. */ - nsapi_error_t bind(uint16_t port); + virtual nsapi_size_or_error_t send(const void *data, nsapi_size_t size) = 0; - /** Bind a specific address to a socket + /** Receive data from a socket. * - * Binding a socket specifies the address and port on which to receive - * data. If the IP address is zeroed, only the port is bound. + * Receive data from connected socket or in case of connectionless socket + * this is equivalent of calling recvfrom(NULL, data, size). * - * @param address Null-terminated local address to bind - * @param port Local port to bind - * @return 0 on success, negative error code on failure. + * By default, recv blocks until some data is received. If socket is set to + * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK can be returned to + * indicate no data. + * + * @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. If no data is available to be received + * and the peer has performed an orderly shutdown, + * recv() returns 0. */ - nsapi_error_t bind(const char *address, uint16_t port); + virtual nsapi_size_or_error_t recv(void *data, nsapi_size_t size) = 0; - /** Bind a specific address to a socket + /** Send a message on a socket. * - * Binding a socket specifies the address and port on which to receive - * data. If the IP address is zeroed, only the port is bound. + * The sendto() function shall send a message through a connection-mode or connectionless-mode socket. + * If the socket is connectionless-mode, the message shall be sent to the address specified. + * If the socket is connection-mode, address shall be ignored. + * + * 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 Remote address + * @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 nsapi_size_or_error_t sendto(const SocketAddress &address, + const void *data, nsapi_size_t size) = 0; + + /** Receive a data from a socket + * + * Receives a data and stores the source address in address if address + * is not NULL. Returns the number of bytes written into the buffer. If the + * datagram is larger than the buffer, the excess data is silently discarded. + * + * By default, recvfrom blocks until a datagram is received. If socket is set to + * non-blocking or times out with no datagram, NSAPI_ERROR_WOULD_BLOCK + * is returned. + * + * @param address Destination for the source address or NULL + * @param data Destination buffer for datagram 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 nsapi_size_or_error_t recvfrom(SocketAddress *address, + void *data, nsapi_size_t size) = 0; + + /** Bind a specific address to a socket. + * + * Binding assigns a local address to a socket. * * @param address Local address to bind * @return 0 on success, negative error code on failure. */ - nsapi_error_t bind(const SocketAddress &address); - - /** Set blocking or non-blocking mode of the socket + virtual nsapi_error_t bind(const SocketAddress &address) = 0; + + /** Set blocking or non-blocking mode of the socket. * * Initially all sockets are in blocking mode. In non-blocking mode * blocking operations such as send/recv/accept return @@ -118,9 +146,9 @@ public: * * @param blocking true for blocking mode, false for non-blocking mode. */ - void set_blocking(bool blocking); - - /** Set timeout on blocking socket operations + virtual void set_blocking(bool blocking) = 0; + + /** 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 @@ -132,43 +160,9 @@ public: * * @param timeout Timeout in milliseconds */ - void set_timeout(int timeout); + virtual void set_timeout(int timeout) = 0; - /* Set socket options - * - * setsockopt allows an application to pass stack-specific options - * to the underlying stack using stack-specific level and option names, - * or to request generic options using levels from nsapi_socket_level_t. - * - * For unsupported options, NSAPI_ERROR_UNSUPPORTED is returned - * and the socket is unmodified. - * - * @param level Stack-specific protocol level or nsapi_socket_level_t - * @param optname Level-specific option name - * @param optval Option value - * @param optlen Length of the option value - * @return 0 on success, negative error code on failure - */ - nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen); - - /* Get socket options - * - * getsockopt allows an application to retrieve stack-specific options - * from the underlying stack using stack-specific level and option names, - * or to request generic options using levels from nsapi_socket_level_t. - * - * For unsupported options, NSAPI_ERROR_UNSUPPORTED is returned - * and the socket is unmodified. - * - * @param level Stack-specific protocol level or nsapi_socket_level_t - * @param optname Level-specific option name - * @param optval Destination for option value - * @param optlen Length of the option value - * @return 0 on success, negative error code on failure - */ - nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen); - - /** Register a callback on state change of the socket + /** 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 @@ -184,47 +178,41 @@ public: * * @param func Function to call on state change */ - void sigio(mbed::Callback func); + virtual void sigio(mbed::Callback func) = 0; - /** Register a callback on state change of the socket + /* Set socket options. * - * @see Socket::sigio - * @deprecated - * The behaviour of Socket::attach differs from other attach functions in - * mbed OS and has been known to cause confusion. Replaced by Socket::sigio. - */ - MBED_DEPRECATED_SINCE("mbed-os-5.4", - "The behaviour of Socket::attach differs from other attach functions in " - "mbed OS and has been known to cause confusion. Replaced by Socket::sigio.") - void attach(mbed::Callback func); - - /** Register a callback on state change of the socket + * setsockopt() allows an application to pass stack-specific options + * to the underlying stack using stack-specific level and option names, + * or to request generic options using levels from nsapi_socket_level_t. * - * @see Socket::sigio - * @deprecated - * The attach function does not support cv-qualifiers. Replaced by - * attach(callback(obj, method)). + * For unsupported options, NSAPI_ERROR_UNSUPPORTED is returned + * and the socket is unmodified. + * + * @param level Stack-specific protocol level or nsapi_socket_level_t + * @param optname Level-specific option name + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure */ - template - MBED_DEPRECATED_SINCE("mbed-os-5.1", - "The attach function does not support cv-qualifiers. Replaced by " - "attach(callback(obj, method)).") - void attach(T *obj, M method) { - attach(mbed::callback(obj, method)); - } + virtual nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen) = 0; -protected: - Socket(); - virtual nsapi_protocol_t get_proto() = 0; - virtual void event() = 0; - int modify_multicast_group(const SocketAddress &address, nsapi_socket_option_t socketopt); - - NetworkStack *_stack; - nsapi_socket_t _socket; - uint32_t _timeout; - mbed::Callback _event; - mbed::Callback _callback; - rtos::Mutex _lock; + /* Get socket options. + * + * getsockopt() allows an application to retrieve stack-specific options + * from the underlying stack using stack-specific level and option names, + * or to request generic options using levels from nsapi_socket_level_t. + * + * For unsupported options, NSAPI_ERROR_UNSUPPORTED is returned + * and the socket is unmodified. + * + * @param level Stack-specific protocol level or nsapi_socket_level_t + * @param optname Level-specific option name + * @param optval Destination for option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen) = 0; }; diff --git a/features/netsocket/SocketAddress.cpp b/features/netsocket/SocketAddress.cpp index 953eb66194..c30572beea 100644 --- a/features/netsocket/SocketAddress.cpp +++ b/features/netsocket/SocketAddress.cpp @@ -18,8 +18,9 @@ #include "NetworkInterface.h" #include "NetworkStack.h" #include +#include #include "ip6string.h" -#include "mbed.h" + static bool ipv4_is_valid(const char *addr) diff --git a/features/netsocket/TCPServer.cpp b/features/netsocket/TCPServer.cpp index 85f3249341..ee9e5cf7aa 100644 --- a/features/netsocket/TCPServer.cpp +++ b/features/netsocket/TCPServer.cpp @@ -56,7 +56,7 @@ nsapi_error_t TCPServer::accept(TCPSocket *connection, SocketAddress *address) if (!_socket) { ret = NSAPI_ERROR_NO_SOCKET; break; - } + } _pending = 0; void *socket; @@ -111,3 +111,28 @@ void TCPServer::event() _callback(); } } + +nsapi_error_t TCPServer::connect(const SocketAddress) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_size_or_error_t TCPServer::send(const void *, nsapi_size_t) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_size_or_error_t TCPServer::recv(void *, nsapi_size_t) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_size_or_error_t TCPServer::sendto(const SocketAddress&, const void *, nsapi_size_t) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_size_or_error_t TCPServer::recvfrom(SocketAddress*, void *, nsapi_size_t) +{ + return NSAPI_ERROR_UNSUPPORTED; +} diff --git a/features/netsocket/TCPServer.h b/features/netsocket/TCPServer.h index af9a4e66e3..04962bb59c 100644 --- a/features/netsocket/TCPServer.h +++ b/features/netsocket/TCPServer.h @@ -18,7 +18,7 @@ #ifndef TCPSERVER_H #define TCPSERVER_H -#include "netsocket/Socket.h" +#include "netsocket/InternetSocket.h" #include "netsocket/TCPSocket.h" #include "netsocket/NetworkStack.h" #include "netsocket/NetworkInterface.h" @@ -28,7 +28,7 @@ /** TCP socket server * @addtogroup netsocket */ -class TCPServer : public Socket { +class TCPServer : public InternetSocket { public: /** Create an uninitialized socket * @@ -66,7 +66,7 @@ public: * @return 0 on success, negative error code on failure */ nsapi_error_t listen(int backlog = 1); - + /** Accepts a connection on a TCP socket * * The server socket must be bound and set to listen for connections. @@ -83,6 +83,42 @@ public: */ nsapi_error_t accept(TCPSocket *connection, SocketAddress *address = NULL); + /** Not supported on TCPServer. + * @param address unused + * @return NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_error_t connect(const SocketAddress &address); + + /** Not supported on TCPServer. + * @param data unused + * @param size unused + * @return NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_size_or_error_t send(const void *data, nsapi_size_t size); + + /** Not supported on TCPServer. + * @param data unused + * @param size unused + * @return NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_size_or_error_t recv(void *data, nsapi_size_t size); + + /** Not supported on TCPServer. + * @param address unused + * @param data unused + * @param size unused + * @return NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_size_or_error_t sendto(const SocketAddress& address, const void *data, nsapi_size_t size); + + /** Not supported on TCPServer. + * @param address unused + * @param data unused + * @param size unused + * @return NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_size_or_error_t recvfrom(SocketAddress* address, void *data, nsapi_size_t size); + protected: virtual nsapi_protocol_t get_proto(); virtual void event(); diff --git a/features/netsocket/TCPSocket.cpp b/features/netsocket/TCPSocket.cpp index 7897f8acca..0328d4a8a9 100644 --- a/features/netsocket/TCPSocket.cpp +++ b/features/netsocket/TCPSocket.cpp @@ -84,6 +84,10 @@ nsapi_error_t TCPSocket::connect(const SocketAddress &address) ret = NSAPI_ERROR_OK; } + if (ret == NSAPI_ERROR_OK || ret == NSAPI_ERROR_IN_PROGRESS) { + _remote_peer = address; + } + _lock.unlock(); return ret; } @@ -163,6 +167,12 @@ nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size) } } +nsapi_size_or_error_t TCPSocket::sendto(const SocketAddress &address, const void *data, nsapi_size_t size) +{ + (void)address; + return send(data, size); +} + nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size) { _lock.lock(); @@ -206,6 +216,14 @@ nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size) return ret; } +nsapi_size_or_error_t TCPSocket::recvfrom(SocketAddress *address, void *data, nsapi_size_t size) +{ + if (address) { + *address = _remote_peer; + } + return recv(data, size); +} + void TCPSocket::event() { _event_flag.set(READ_FLAG|WRITE_FLAG); diff --git a/features/netsocket/TCPSocket.h b/features/netsocket/TCPSocket.h index 39c547d7af..e433b7fbc2 100644 --- a/features/netsocket/TCPSocket.h +++ b/features/netsocket/TCPSocket.h @@ -20,7 +20,7 @@ #ifndef TCPSOCKET_H #define TCPSOCKET_H -#include "netsocket/Socket.h" +#include "netsocket/InternetSocket.h" #include "netsocket/NetworkStack.h" #include "netsocket/NetworkInterface.h" #include "rtos/EventFlags.h" @@ -28,7 +28,7 @@ /** TCP socket connection */ -class TCPSocket : public Socket { +class TCPSocket : public InternetSocket { public: /** Create an uninitialized socket * @@ -60,7 +60,7 @@ public: /** Override multicast functions to return error for TCP * */ - int join_multicast_group(const SocketAddress &address) { return NSAPI_ERROR_UNSUPPORTED; } + virtual int join_multicast_group(const SocketAddress &address) { return NSAPI_ERROR_UNSUPPORTED; } /** Connects TCP socket to a remote host * @@ -81,8 +81,8 @@ public: * @param address The SocketAddress of the remote host * @return 0 on success, negative error code on failure */ - nsapi_error_t connect(const SocketAddress &address); - + virtual nsapi_error_t connect(const SocketAddress &address); + /** Send data over a TCP socket * * The socket must be connected to a remote host. Returns the number of @@ -97,8 +97,8 @@ public: * @return Number of sent bytes on success, negative error * code on failure */ - nsapi_size_or_error_t send(const void *data, nsapi_size_t size); - + virtual nsapi_size_or_error_t send(const void *data, nsapi_size_t size); + /** Receive data over a TCP socket * * The socket must be connected to a remote host. Returns the number of @@ -115,7 +115,26 @@ public: * and the peer has performed an orderly shutdown, * recv() returns 0. */ - nsapi_size_or_error_t recv(void *data, nsapi_size_t size); + virtual nsapi_size_or_error_t recv(void *data, nsapi_size_t size); + + /** Send data on a socket. + * + * TCP socket is connection oriented protocol, so address is ignored. + * + * 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 Remote address + * @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 nsapi_size_or_error_t sendto(const SocketAddress &address, + const void *data, nsapi_size_t size); + virtual nsapi_size_or_error_t recvfrom(SocketAddress *address, + void *data, nsapi_size_t size); protected: friend class TCPServer; diff --git a/features/netsocket/UDPSocket.cpp b/features/netsocket/UDPSocket.cpp index cb6fbd67ce..1dab92b56c 100644 --- a/features/netsocket/UDPSocket.cpp +++ b/features/netsocket/UDPSocket.cpp @@ -37,6 +37,13 @@ nsapi_protocol_t UDPSocket::get_proto() return NSAPI_UDP; } +nsapi_error_t UDPSocket::connect(const SocketAddress &address) +{ + if (!address) + return NSAPI_ERROR_PARAMETER; + _remote_peer = address; + return NSAPI_ERROR_OK; +} nsapi_size_or_error_t UDPSocket::sendto(const char *host, uint16_t port, const void *data, nsapi_size_t size) { @@ -89,6 +96,13 @@ nsapi_size_or_error_t UDPSocket::sendto(const SocketAddress &address, const void return ret; } +nsapi_size_or_error_t UDPSocket::send(const void *data, nsapi_size_t size) +{ + if (!_remote_peer) + return NSAPI_ERROR_NO_ADDRESS; + return sendto(_remote_peer, data, size); +} + nsapi_size_or_error_t UDPSocket::recvfrom(SocketAddress *address, void *buffer, nsapi_size_t size) { _lock.lock(); @@ -126,6 +140,12 @@ nsapi_size_or_error_t UDPSocket::recvfrom(SocketAddress *address, void *buffer, return ret; } +nsapi_size_or_error_t UDPSocket::recv(void *buffer, nsapi_size_t size) +{ + SocketAddress ignored; // Dangerous, I'm spending ~50 bytes from stack for address space that I'll ignore. + return recvfrom(&ignored, buffer, size); +} + void UDPSocket::event() { _event_flag.set(READ_FLAG|WRITE_FLAG); diff --git a/features/netsocket/UDPSocket.h b/features/netsocket/UDPSocket.h index a4570fa80e..fe219412c4 100644 --- a/features/netsocket/UDPSocket.h +++ b/features/netsocket/UDPSocket.h @@ -20,7 +20,7 @@ #ifndef UDPSOCKET_H #define UDPSOCKET_H -#include "netsocket/Socket.h" +#include "netsocket/InternetSocket.h" #include "netsocket/NetworkStack.h" #include "netsocket/NetworkInterface.h" #include "rtos/EventFlags.h" @@ -28,7 +28,7 @@ /** UDP socket */ -class UDPSocket : public Socket { +class UDPSocket : public InternetSocket { public: /** Create an uninitialized socket * @@ -73,7 +73,7 @@ public: * @return Number of sent bytes on success, negative error * code on failure */ - nsapi_size_or_error_t sendto(const char *host, uint16_t port, + virtual nsapi_size_or_error_t sendto(const char *host, uint16_t port, const void *data, nsapi_size_t size); /** Send a packet over a UDP socket @@ -91,7 +91,7 @@ public: * @return Number of sent bytes on success, negative error * code on failure */ - nsapi_size_or_error_t sendto(const SocketAddress &address, + virtual nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size); /** Receive a datagram over a UDP socket @@ -110,9 +110,48 @@ public: * @return Number of received bytes on success, negative error * code on failure */ - nsapi_size_or_error_t recvfrom(SocketAddress *address, + virtual nsapi_size_or_error_t recvfrom(SocketAddress *address, void *data, nsapi_size_t size); + /** Set remote peer address + * + * Set the remote address for next send() call. + * + * @param address The SocketAddress of the remote host + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t connect(const SocketAddress &address); + + /** Send a datagram to pre-specified remote. + * + * The socket must be connected to a remote host before send() call. + * Returns the number of bytes sent from the buffer. + * + * By default, send blocks until all data is sent. If socket is set to + * non-blocking or times out, a partial amount can be written. + * NSAPI_ERROR_WOULD_BLOCK is returned if no data was written. + * + * @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 nsapi_size_or_error_t send(const void *data, nsapi_size_t size); + + /** Receive data from a socket. + * + * This is equivalent of calling recvfrom(NULL, data, size). + * + * By default, recv blocks until some data is received. If socket is set to + * non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK can be returned to + * indicate no data. + * + * @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 nsapi_size_or_error_t recv(void *data, nsapi_size_t size); protected: virtual nsapi_protocol_t get_proto(); virtual void event();