Merge pull request #7192 from SeppoTakalo/socket-refactor

Create abstract Socket interface
pull/7113/merge
Cruz Monrreal 2018-06-25 10:18:51 -05:00 committed by GitHub
commit 24efa4c06e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 811 additions and 291 deletions

View File

@ -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()
: _stack(0)
, _socket(0)
, _timeout(osWaitForever)
using namespace mbed;
InternetSocket::InternetSocket()
: _stack(0), _socket(0), _timeout(osWaitForever),
_readers(0), _writers(0), _factory_allocated(false),
_pending(0)
{
}
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<void()>::thunk, &_event);
_lock.unlock();
return NSAPI_ERROR_OK;
}
nsapi_error_t Socket::close()
nsapi_error_t InternetSocket::close()
{
_lock.lock();
@ -66,11 +68,23 @@ nsapi_error_t Socket::close()
// on this socket
event();
// Wait until all readers and writers are gone
while (_readers || _writers) {
_lock.unlock();
_event_flag.wait_any(FINISHED_FLAG, osWaitForever);
_lock.lock();
}
_lock.unlock();
// When allocated by accept() call, will self desctruct on close();
if (_factory_allocated) {
delete this;
}
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 +95,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 +135,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 +154,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 +169,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;
@ -170,15 +184,24 @@ nsapi_error_t Socket::getsockopt(int level, int optname, void *optval, unsigned
return ret;
}
void InternetSocket::event()
{
_event_flag.set(READ_FLAG|WRITE_FLAG);
void Socket::sigio(Callback<void()> callback)
_pending += 1;
if (_callback && _pending == 1) {
_callback();
}
}
void InternetSocket::sigio(Callback<void()> callback)
{
_lock.lock();
_callback = callback;
_lock.unlock();
}
void Socket::attach(Callback<void()> callback)
void InternetSocket::attach(Callback<void()> callback)
{
sigio(callback);
}

View File

@ -0,0 +1,245 @@
/** \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 "rtos/EventFlags.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 <typename S>
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<void()> 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<void()> 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 <typename T, typename M>
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();
int modify_multicast_group(const SocketAddress &address, nsapi_socket_option_t socketopt);
NetworkStack *_stack;
nsapi_socket_t _socket;
uint32_t _timeout;
mbed::Callback<void()> _event;
mbed::Callback<void()> _callback;
rtos::EventFlags _event_flag;
rtos::Mutex _lock;
SocketAddress _remote_peer;
uint8_t _readers;
uint8_t _writers;
volatile unsigned _pending;
bool _factory_allocated;
// Event flags
static const int READ_FLAG = 0x1u;
static const int WRITE_FLAG = 0x2u;
static const int FINISHED_FLAG = 0x3u;
};
#endif // INTERNETSOCKET_H
/** @}*/

View File

@ -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;

View File

@ -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;

View File

@ -21,93 +21,135 @@
#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 <typename S>
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 address.
*
* @param address Multicast group IP address
* @return Negative error code on failure
* Attempt to make connection on connection-mode protocol or set or reset
* the peer address on connectionless protocol.
*
* Also connectionless protocols use the connected address to filter
* incoming packets for recv() and recvfrom() calls.
*
* To reset the peer address, zero initialised(default constructor) SocketAddress
* object have to be in the address parameter.
*
* @param address The SocketAddress of the remote peer
* @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.
* If socket is connected, only packets coming from connected peer address
* are accepted.
*
* @note recv() is allowed write to data buffer even if error occurs.
*
* 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 socket is connected, only packets coming from connected peer address
* are accepted.
*
* @note recvfrom() is allowed write to address and data buffers even if error occurs.
*
* By default, recvfrom blocks until a datagram is received. If socket is set to
* non-blocking or times out with no data, 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 +160,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 +174,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 +192,67 @@ public:
*
* @param func Function to call on state change
*/
void sigio(mbed::Callback<void()> func);
virtual void sigio(mbed::Callback<void()> 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<void()> 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 <typename T, typename M>
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);
/* 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;
NetworkStack *_stack;
nsapi_socket_t _socket;
uint32_t _timeout;
mbed::Callback<void()> _event;
mbed::Callback<void()> _callback;
rtos::Mutex _lock;
/** Accepts a connection on a socket.
*
* The server socket must be bound and set to listen for connections.
* On a new connection, returns connected network socket which user is expected to call close()
* and that deallocates the resources. Referencing a returned pointer after a close()
* call is not allowed and leads to undefined behaviour.
*
* By default, accept blocks until incomming connection occurs. If socket is set to
* non-blocking or times out, error is set to NSAPI_ERROR_WOULD_BLOCK.
*
* @param error pointer to storage of the error value or NULL
* @return pointer to a socket
*/
virtual Socket *accept(nsapi_error_t *error = NULL) = 0;
/** Listen for incoming connections.
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param backlog Number of pending connections that can be queued
* simultaneously, defaults to 1
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t listen(int backlog = 1) = 0;
};

View File

@ -18,8 +18,9 @@
#include "NetworkInterface.h"
#include "NetworkStack.h"
#include <string.h>
#include <stdio.h>
#include "ip6string.h"
#include "mbed.h"
static bool ipv4_is_valid(const char *addr)
@ -105,35 +106,36 @@ static void ipv6_to_address(char *addr, const uint8_t *bytes)
SocketAddress::SocketAddress(nsapi_addr_t addr, uint16_t port)
{
_ip_address[0] = '\0';
_ip_address = NULL;
set_addr(addr);
set_port(port);
}
SocketAddress::SocketAddress(const char *addr, uint16_t port)
{
_ip_address[0] = '\0';
_ip_address = NULL;
set_ip_address(addr);
set_port(port);
}
SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port)
{
_ip_address[0] = '\0';
_ip_address = NULL;
set_ip_bytes(bytes, version);
set_port(port);
}
SocketAddress::SocketAddress(const SocketAddress &addr)
{
_ip_address[0] = '\0';
_ip_address = NULL;
set_addr(addr.get_addr());
set_port(addr.get_port());
}
bool SocketAddress::set_ip_address(const char *addr)
{
_ip_address[0] = '\0';
delete[] _ip_address;
_ip_address = NULL;
if (addr && ipv4_is_valid(addr)) {
_addr.version = NSAPI_IPv4;
@ -165,7 +167,8 @@ void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version)
void SocketAddress::set_addr(nsapi_addr_t addr)
{
_ip_address[0] = '\0';
delete[] _ip_address;
_ip_address = NULL;
_addr = addr;
}
@ -180,7 +183,8 @@ const char *SocketAddress::get_ip_address() const
return NULL;
}
if (!_ip_address[0]) {
if (!_ip_address) {
_ip_address = new char[NSAPI_IP_SIZE];
if (_addr.version == NSAPI_IPv4) {
ipv4_to_address(_ip_address, _addr.bytes);
} else if (_addr.version == NSAPI_IPv6) {
@ -234,6 +238,15 @@ SocketAddress::operator bool() const
}
}
SocketAddress &SocketAddress::operator=(const SocketAddress &addr)
{
delete[] _ip_address;
_ip_address = NULL;
set_addr(addr.get_addr());
set_port(addr.get_port());
return *this;
}
bool operator==(const SocketAddress &a, const SocketAddress &b)
{
if (!a && !b) {
@ -256,7 +269,7 @@ bool operator!=(const SocketAddress &a, const SocketAddress &b)
void SocketAddress::_SocketAddress(NetworkStack *iface, const char *host, uint16_t port)
{
_ip_address[0] = '\0';
_ip_address = NULL;
// gethostbyname must check for literals, so can call it directly
int err = iface->gethostbyname(host, this);
@ -266,3 +279,8 @@ void SocketAddress::_SocketAddress(NetworkStack *iface, const char *host, uint16
_port = 0;
}
}
SocketAddress::~SocketAddress()
{
delete[] _ip_address;
}

View File

@ -28,7 +28,7 @@ class NetworkInterface;
/** SocketAddress class
*
* Representation of an IP address and port pair.
* Representation of an IP address and port pair.
* @addtogroup netsocket
*/
class SocketAddress {
@ -83,7 +83,10 @@ public:
* @param addr SocketAddress to copy
*/
SocketAddress(const SocketAddress &addr);
/** Destructor */
~SocketAddress();
/** Set the IP address
*
* @param addr Null-terminated represention of the IP address
@ -110,8 +113,11 @@ public:
* @param port 16-bit port
*/
void set_port(uint16_t port);
/** Get the IP address
/** Get the human-readable IP address
*
* Allocates memory for a string and converts binary address to
* human-readable format. String is freed in the destructor.
*
* @return Null-terminated representation of the IP Address
*/
@ -134,7 +140,7 @@ public:
* @return Raw IP address
*/
nsapi_addr_t get_addr() const;
/** Get the port
*
* @return The 16-bit port
@ -147,6 +153,12 @@ public:
*/
operator bool() const;
/** Copy address from another SocketAddress
*
* @param addr SocketAddress to copy
*/
SocketAddress &operator=(const SocketAddress &addr);
/** Compare two addresses for equality
*
* @return True if both addresses are equal
@ -162,7 +174,7 @@ public:
private:
void _SocketAddress(NetworkStack *iface, const char *host, uint16_t port);
mutable char _ip_address[NSAPI_IP_SIZE];
mutable char *_ip_address;
nsapi_addr_t _addr;
uint16_t _port;
};

View File

@ -18,7 +18,6 @@
#include "mbed.h"
TCPServer::TCPServer()
: _pending(0), _accept_sem(0)
{
}
@ -27,36 +26,15 @@ TCPServer::~TCPServer()
close();
}
nsapi_protocol_t TCPServer::get_proto()
{
return NSAPI_TCP;
}
nsapi_error_t TCPServer::listen(int backlog)
{
_lock.lock();
nsapi_error_t ret;
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
} else {
ret = _stack->socket_listen(_socket, backlog);
}
_lock.unlock();
return ret;
}
nsapi_error_t TCPServer::accept(TCPSocket *connection, SocketAddress *address)
{
_lock.lock();
nsapi_error_t ret;
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
break;
}
}
_pending = 0;
void *socket;
@ -76,19 +54,19 @@ nsapi_error_t TCPServer::accept(TCPSocket *connection, SocketAddress *address)
connection->_lock.unlock();
break;
} else if (NSAPI_ERROR_WOULD_BLOCK != ret) {
} else if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {
break;
} else {
int32_t count;
uint32_t flag;
// Release lock before blocking so other threads
// accessing this object aren't blocked
_lock.unlock();
count = _accept_sem.wait(_timeout);
flag = _event_flag.wait_any(READ_FLAG, _timeout);
_lock.lock();
if (count < 1) {
// Semaphore wait timed out so break out and return
if (flag & osFlagsError) {
// Timeout break
ret = NSAPI_ERROR_WOULD_BLOCK;
break;
}
@ -98,16 +76,3 @@ nsapi_error_t TCPServer::accept(TCPSocket *connection, SocketAddress *address)
_lock.unlock();
return ret;
}
void TCPServer::event()
{
int32_t acount = _accept_sem.wait(0);
if (acount <= 1) {
_accept_sem.release();
}
_pending += 1;
if (_callback && _pending == 1) {
_callback();
}
}

View File

@ -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,12 +28,14 @@
/** TCP socket server
* @addtogroup netsocket
*/
class TCPServer : public Socket {
class TCPServer : public TCPSocket {
public:
/** Create an uninitialized socket
*
* Must call open to initialize the socket on a network stack.
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"TCPServer is deprecated, use TCPSocket")
TCPServer();
/** Create a socket on a network interface
@ -44,8 +46,9 @@ public:
* @param stack Network stack as target for socket
*/
template <typename S>
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"TCPServer is deprecated, use TCPSocket")
TCPServer(S *stack)
: _pending(0), _accept_sem(0)
{
open(stack);
}
@ -56,17 +59,6 @@ public:
*/
virtual ~TCPServer();
/** Listen for connections on a TCP socket
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param backlog Number of pending connections that can be queued
* simultaneously, defaults to 1
* @return 0 on success, negative error code on failure
*/
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.
@ -81,15 +73,9 @@ public:
* @param address Destination for the remote address or NULL
* @return 0 on success, negative error code on failure
*/
MBED_DEPRECATED_SINCE("mbed-os-5.10",
"TCPServer::accept() is deprecated, use Socket *Socket::accept() instead")
nsapi_error_t accept(TCPSocket *connection, SocketAddress *address = NULL);
protected:
virtual nsapi_protocol_t get_proto();
virtual void event();
volatile unsigned _pending;
rtos::Semaphore _accept_sem;
};
#endif

View File

@ -18,12 +18,7 @@
#include "Timer.h"
#include "mbed_assert.h"
#define READ_FLAG 0x1u
#define WRITE_FLAG 0x2u
TCPSocket::TCPSocket()
: _pending(0), _event_flag(),
_read_in_progress(false), _write_in_progress(false)
{
}
@ -45,8 +40,8 @@ nsapi_error_t TCPSocket::connect(const SocketAddress &address)
// If this assert is hit then there are two threads
// performing a send at the same time which is undefined
// behavior
MBED_ASSERT(!_write_in_progress);
_write_in_progress = true;
MBED_ASSERT(_writers == 0);
_writers++;
bool blocking_connect_in_progress = false;
@ -77,13 +72,20 @@ nsapi_error_t TCPSocket::connect(const SocketAddress &address)
}
}
_write_in_progress = false;
_writers--;
if (!_socket) {
_event_flag.set(FINISHED_FLAG);
}
/* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */
if (ret == NSAPI_ERROR_IS_CONNECTED && blocking_connect_in_progress) {
ret = NSAPI_ERROR_OK;
}
if (ret == NSAPI_ERROR_OK || ret == NSAPI_ERROR_IN_PROGRESS) {
_remote_peer = address;
}
_lock.unlock();
return ret;
}
@ -112,8 +114,8 @@ nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size)
// If this assert is hit then there are two threads
// performing a send at the same time which is undefined
// behavior
MBED_ASSERT(!_write_in_progress);
_write_in_progress = true;
MBED_ASSERT(_writers == 0);
_writers++;
// Unlike recv, we should write the whole thing if blocking. POSIX only
// allows partial as a side-effect of signal handling; it normally tries to
@ -152,7 +154,11 @@ nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size)
}
}
_write_in_progress = false;
_writers--;
if (!_socket) {
_event_flag.set(FINISHED_FLAG);
}
_lock.unlock();
if (ret <= 0 && ret != NSAPI_ERROR_WOULD_BLOCK) {
return ret;
@ -163,6 +169,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();
@ -171,8 +183,8 @@ nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size)
// If this assert is hit then there are two threads
// performing a recv at the same time which is undefined
// behavior
MBED_ASSERT(!_read_in_progress);
_read_in_progress = true;
MBED_ASSERT(_readers == 0);
_readers++;
while (true) {
if (!_socket) {
@ -201,17 +213,95 @@ nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size)
}
}
_read_in_progress = false;
_readers--;
if (!_socket) {
_event_flag.set(FINISHED_FLAG);
}
_lock.unlock();
return ret;
}
void TCPSocket::event()
nsapi_size_or_error_t TCPSocket::recvfrom(SocketAddress *address, void *data, nsapi_size_t size)
{
_event_flag.set(READ_FLAG|WRITE_FLAG);
_pending += 1;
if (_callback && _pending == 1) {
_callback();
if (address) {
*address = _remote_peer;
}
return recv(data, size);
}
nsapi_error_t TCPSocket::listen(int backlog)
{
_lock.lock();
nsapi_error_t ret;
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
} else {
ret = _stack->socket_listen(_socket, backlog);
}
_lock.unlock();
return ret;
}
TCPSocket *TCPSocket::accept(nsapi_error_t *error)
{
_lock.lock();
TCPSocket *connection = NULL;
nsapi_error_t ret;
_readers++;
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
break;
}
_pending = 0;
void *socket;
SocketAddress address;
ret = _stack->socket_accept(_socket, &socket, &address);
if (0 == ret) {
TCPSocket *connection = new TCPSocket();
connection->_lock.lock();
connection->_factory_allocated = true; // Destroy automatically on close()
connection->_remote_peer = address;
connection->_stack = _stack;
connection->_socket = socket;
connection->_event = mbed::Callback<void()>(connection, &TCPSocket::event);
_stack->socket_attach(socket, &mbed::Callback<void()>::thunk, &connection->_event);
connection->_lock.unlock();
break;
} else if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {
break;
} else {
uint32_t flag;
// Release lock before blocking so other threads
// accessing this object aren't blocked
_lock.unlock();
flag = _event_flag.wait_any(READ_FLAG, _timeout);
_lock.lock();
if (flag & osFlagsError) {
// Timeout break
ret = NSAPI_ERROR_WOULD_BLOCK;
break;
}
}
}
_readers--;
if (!_socket) {
_event_flag.set(FINISHED_FLAG);
}
_lock.unlock();
if (error) {
*error = ret;
}
return connection;
}

View File

@ -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
*
@ -45,8 +45,6 @@ public:
*/
template <typename S>
TCPSocket(S *stack)
: _pending(0), _event_flag(0),
_read_in_progress(false), _write_in_progress(false)
{
open(stack);
}
@ -60,7 +58,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 +79,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 +95,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,18 +113,72 @@ 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);
/** 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.
*
* By default, recvfrom blocks until a data 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);
/** Accepts a connection on a socket.
*
* The server socket must be bound and set to listen for connections.
* On a new connection, returns connected network socket which user is expected to call close()
* and that deallocates the resources. Referencing a returned pointer after a close()
* call is not allowed and leads to undefined behaviour.
*
* By default, accept blocks until incomming connection occurs. If socket is set to
* non-blocking or times out, error is set to NSAPI_ERROR_WOULD_BLOCK.
*
* @param error pointer to storage of the error value or NULL
* @return pointer to a socket
*/
virtual TCPSocket *accept(nsapi_error_t *error = NULL);
/** Listen for incoming connections.
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param backlog Number of pending connections that can be queued
* simultaneously, defaults to 1
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t listen(int backlog = 1);
protected:
friend class TCPServer;
virtual nsapi_protocol_t get_proto();
virtual void event();
volatile unsigned _pending;
rtos::EventFlags _event_flag;
bool _read_in_progress;
bool _write_in_progress;
};

View File

@ -18,12 +18,7 @@
#include "Timer.h"
#include "mbed_assert.h"
#define TCP_EVENT "UDP_Events"
#define READ_FLAG 0x1u
#define WRITE_FLAG 0x2u
UDPSocket::UDPSocket()
: _pending(0), _event_flag()
{
}
@ -37,6 +32,11 @@ nsapi_protocol_t UDPSocket::get_proto()
return NSAPI_UDP;
}
nsapi_error_t UDPSocket::connect(const SocketAddress &address)
{
_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)
{
@ -57,6 +57,8 @@ nsapi_size_or_error_t UDPSocket::sendto(const SocketAddress &address, const void
_lock.lock();
nsapi_size_or_error_t ret;
_writers++;
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
@ -85,14 +87,32 @@ nsapi_size_or_error_t UDPSocket::sendto(const SocketAddress &address, const void
}
}
_writers--;
if (!_socket || !_writers) {
_event_flag.set(FINISHED_FLAG);
}
_lock.unlock();
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();
nsapi_size_or_error_t ret;
SocketAddress ignored;
if (!address) {
address = &ignored;
}
_readers++;
while (true) {
if (!_socket) {
@ -102,6 +122,13 @@ nsapi_size_or_error_t UDPSocket::recvfrom(SocketAddress *address, void *buffer,
_pending = 0;
nsapi_size_or_error_t recv = _stack->socket_recvfrom(_socket, address, buffer, size);
// Filter incomming packets using connected peer address
if (recv >= 0 && _remote_peer && _remote_peer == *address) {
continue;
}
// Non-blocking sockets always return. Blocking only returns when success or errors other than WOULD_BLOCK
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) {
ret = recv;
break;
@ -122,16 +149,29 @@ nsapi_size_or_error_t UDPSocket::recvfrom(SocketAddress *address, void *buffer,
}
}
_readers--;
if (!_socket || !_readers) {
_event_flag.set(FINISHED_FLAG);
}
_lock.unlock();
return ret;
}
void UDPSocket::event()
nsapi_size_or_error_t UDPSocket::recv(void *buffer, nsapi_size_t size)
{
_event_flag.set(READ_FLAG|WRITE_FLAG);
_pending += 1;
if (_callback && _pending == 1) {
_callback();
}
return recvfrom(NULL, buffer, size);
}
Socket *UDPSocket::accept(nsapi_error_t *error)
{
if (error) {
*error = NSAPI_ERROR_UNSUPPORTED;
}
return NULL;
}
nsapi_error_t UDPSocket::listen(int)
{
return NSAPI_ERROR_UNSUPPORTED;
}

View File

@ -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
*
@ -45,7 +45,6 @@ public:
*/
template <typename S>
UDPSocket(S *stack)
: _pending(0), _event_flag(0)
{
open(stack);
}
@ -73,7 +72,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 +90,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
@ -100,6 +99,11 @@ public:
* 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.
*
* If socket is connected, only packets coming from connected peer address
* are accepted.
*
* @note recvfrom() is allowed write to address and data buffers even if error occurs.
*
* 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.
@ -110,15 +114,72 @@ 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 and filtering
* for incomming packets. To reset the address, zero initialised
* SocketAddress must be in the address parameter.
*
* @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).
*
* If socket is connected, only packets coming from connected peer address
* are accepted.
*
* @note recv() is allowed write to data buffer even if error occurs.
*
* 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);
/** Not implemented for UDP
*
* @param error unused
* @return NSAPI_ERROR_UNSUPPORTED
*/
virtual Socket *accept(nsapi_error_t *error = NULL);
/** Not implemented for UDP
*
* @param backlog unused
* @return NSAPI_ERROR_UNSUPPORTED
*/
virtual nsapi_error_t listen(int backlog = 1);
protected:
virtual nsapi_protocol_t get_proto();
virtual void event();
volatile unsigned _pending;
rtos::EventFlags _event_flag;
};