mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #7192 from SeppoTakalo/socket-refactor
Create abstract Socket interfacepull/7113/merge
commit
24efa4c06e
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
/** @}*/
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue