Matched changes NetworkSocketAPI

Responded to feedback from mbed-client implementation
to introduce a full feature set that should support most
of the use cases for the API.
pull/2216/head^2
Christopher Haster 2016-04-06 08:50:56 -05:00
parent 9f668f1a8f
commit 4c7992cb24
17 changed files with 1000 additions and 348 deletions

View File

@ -109,33 +109,7 @@ static bool resolve(unsigned char *resp, char *ipaddress)
return false;
}
int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip)
{
if (isIP(host)) {
strcpy(ip, host);
return 0;
}
UDPSocket sock(iface);
int32_t err;
for (unsigned i = 0; i < DNS_COUNT; i++) {
err = sock.open(DNS_IPS[0], 53);
if (err < 0) {
return err;
}
err = dnsQuery(&sock, host, ip);
sock.close();
return err;
}
sock.close();
return NS_ERROR_DNS_FAILURE;
}
int32_t dnsQuery(UDPSocket *socket, const char *hostname, char *ipaddress)
static int32_t query(UDPSocket *socket, const SocketAddress &addr, const char *hostname, char *ipaddress)
{
int len = 0;
if (hostname == NULL) {
@ -184,7 +158,7 @@ int32_t dnsQuery(UDPSocket *socket, const char *hostname, char *ipaddress)
packet[c++] = 1;
if (socket->send(packet, packetlen) < 0) {
if (socket->sendto(addr, packet, packetlen) < 0) {
delete packet;
return false;
}
@ -194,21 +168,49 @@ int32_t dnsQuery(UDPSocket *socket, const char *hostname, char *ipaddress)
// Receive the answer from DNS
int response_length = 0;
response_length = socket->recv(packet, 1024);
response_length = socket->recvfrom(NULL, packet, 1024);
if (response_length > 0 ) {
if (!resolve(packet, ipaddress)) {
delete packet;
return NS_ERROR_DNS_FAILURE;
return NSAPI_ERROR_DNS_FAILURE;
}
// cleanup and return
delete packet;
return 0;
}
delete packet;
return NS_ERROR_DNS_FAILURE;
return NSAPI_ERROR_DNS_FAILURE;
}
int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip)
{
if (isIP(host)) {
strcpy(ip, host);
return 0;
}
UDPSocket sock(iface);
for (unsigned i = 0; i < DNS_COUNT; i++) {
return query(&sock, SocketAddress(DNS_IPS[0], 53), host, ip);
}
return NSAPI_ERROR_DNS_FAILURE;
}
int32_t dnsQuery(UDPSocket *socket, const char *host, char *ip)
{
if (isIP(host)) {
strcpy(ip, host);
return 0;
}
for (unsigned i = 0; i < DNS_COUNT; i++) {
return query(socket, SocketAddress(DNS_IPS[0], 53), host, ip);
}
return NSAPI_ERROR_DNS_FAILURE;
}

View File

@ -1,4 +1,4 @@
/* EthernetInterface Base Class
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -26,14 +26,14 @@ class EthernetInterface : public NetworkInterface
{
public:
/** Start the interface
* @return 0 on success
* @return 0 on success, negative on failure
*/
virtual int32_t connect() = 0;
virtual int connect() = 0;
/** Stop the interface
* @return 0 on success
* @return 0 on success, negative on failure
*/
virtual int32_t disconnect() = 0;
virtual int disconnect() = 0;
};
#endif

39
MeshInterface.h Normal file
View File

@ -0,0 +1,39 @@
/* 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 MESH_INTERFACE_H
#define MESH_INTERFACE_H
#include "NetworkInterface.h"
/** MeshInterface class
* Common interface that is shared between ethernet hardware
*/
class MeshInterface : public NetworkInterface
{
public:
/** Start the interface
* @return 0 on success, negative on failure
*/
virtual int connect() = 0;
/** Stop the interface
* @return 0 on success, negative on failure
*/
virtual int disconnect() = 0;
};
#endif

View File

@ -1,4 +1,4 @@
/* NetworkInterface Base Class
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -14,16 +14,10 @@
* limitations under the License.
*/
#include "NetworkInterface.h"
#include "DnsQuery.h"
#include "mbed.h"
bool NetworkInterface::isConnected()
int NetworkInterface::gethostbyname(const char *name, char *dest)
{
return getIPAddress() != 0;
}
int32_t NetworkInterface::getHostByName(const char *name, char *ip)
{
return dnsQuery(this, name, ip);
return dnsQuery(this, name, dest);
}

View File

@ -1,4 +1,4 @@
/* NetworkInterface Base Class
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -17,29 +17,37 @@
#ifndef NETWORK_INTERFACE_H
#define NETWORK_INTERFACE_H
#include "SocketInterface.h"
#include "stdint.h"
#include "mbed.h"
#include "SocketAddress.h"
/** Maximum storage needed for IP address and MAC addresses
*/
#define NS_IP_SIZE 16
#define NS_MAC_SIZE 18
/**
/** Enum of standardized error codes
* @enum ns_error_t
* @brief enum of standardized error codes
*/
enum ns_error_t {
NS_ERROR_WOULD_BLOCK = -3000, /*!< no data is not available but call is non-blocking */
NS_ERROR_TIMEOUT = -3001, /*!< operation took longer than allowed */
NS_ERROR_NO_CONNECTION = -3002, /*!< not connected to a network */
NS_ERROR_NO_SOCKET = -3003, /*!< socket not available for use */
NS_ERROR_NO_ADDRESS = -3004, /*!< IP address is not known */
NS_ERROR_NO_MEMORY = -3005, /*!< memory resource not available */
NS_ERROR_DNS_FAILURE = -3006, /*!< DNS failed to complete successfully */
NS_ERROR_DHCP_FAILURE = -3007, /*!< DHCP failed to complete successfully */
NS_ERROR_AUTH_FAILURE = -3008, /*!< connection to access point faield */
NS_ERROR_DEVICE_ERROR = -3009 /*!< failure interfacing with the network procesor */
enum nsapi_error_t {
NSAPI_ERROR_WOULD_BLOCK = -3001, /*!< no data is not available but call is non-blocking */
NSAPI_ERROR_UNSUPPORTED = -3002, /*!< unsupported configuration */
NSAPI_ERROR_NO_CONNECTION = -3003, /*!< not connected to a network */
NSAPI_ERROR_NO_SOCKET = -3004, /*!< socket not available for use */
NSAPI_ERROR_NO_ADDRESS = -3005, /*!< IP address is not known */
NSAPI_ERROR_NO_MEMORY = -3006, /*!< memory resource not available */
NSAPI_ERROR_DNS_FAILURE = -3007, /*!< DNS failed to complete successfully */
NSAPI_ERROR_DHCP_FAILURE = -3008, /*!< DHCP failed to complete successfully */
NSAPI_ERROR_AUTH_FAILURE = -3009, /*!< connection to access point faield */
NSAPI_ERROR_DEVICE_ERROR = -3010, /*!< failure interfacing with the network procesor */
};
/** Enum of available options
* @enum ns_opt_t
*/
enum ns_opt_t {
};
/** Enum of socket protocols
* @enum protocol_t
*/
enum nsapi_protocol_t {
NSAPI_TCP, /*!< Socket is of TCP type */
NSAPI_UDP, /*!< Socket is of UDP type */
};
/** NetworkInterface class
@ -51,42 +59,175 @@ class NetworkInterface
public:
virtual ~NetworkInterface() {};
/** Get the IP address
* @return IP address of the interface or 0 if not yet connected
/** Get the internally stored IP address
* @return IP address of the interface or null if not yet connected
*/
virtual const char *getIPAddress() = 0;
virtual const char *get_ip_address() = 0;
/** Get the current MAC address
* @return String MAC address of the interface
/** Get the internally stored MAC address
* @return MAC address of the interface
*/
virtual const char *getMACAddress() = 0;
virtual const char *get_mac_address() = 0;
/** Get the current status of the interface
* @return true if connected
* @return true if connected
*/
virtual bool isConnected();
virtual bool is_connected() {
return get_ip_address() != NULL;
}
/** Looks up the specified host's IP address
* @param name URL of host
* @param ip Buffer to hold IP address, must be at least SOCK_IP_SIZE
* @return 0 on success
* @param name Hostname to lookup
* @param dest Destination for IP address, must have space for SocketAddress::IP_SIZE
* @return 0 on success, negative on failure
*/
virtual int32_t getHostByName(const char *name, char *ip);
virtual int gethostbyname(const char *name, char *dest);
protected:
friend class Socket;
friend class UDPSocket;
friend class TCPSocket;
friend class TCPServer;
/** Internally create a socket
* @param proto The type of socket to open, NS_TCP or NS_UDP
* @return The allocated socket
/** Create a socket
* @param proto The type of socket to open, TCP or UDP
* @return The alocated socket or null on failure
*/
virtual SocketInterface *createSocket(ns_protocol_t proto) = 0;
virtual void *socket_create(nsapi_protocol_t proto) = 0;
/** Internally destroy a socket
* @param socket An allocated SocketInterface
* @returns 0 on success
/** Destroy a socket
* @param socket Previously allocated socket
*/
virtual void destroySocket(SocketInterface *socket) = 0;
virtual void socket_destroy(void *handle) = 0;
/** Set socket options
* @param handle Socket handle
* @param optname Option ID
* @param optval Option value
* @param optlen Length of the option value
* @return 0 on success, negative on failure
*/
virtual int socket_set_option(void *handle, int optname, const void *optval, unsigned int optlen) = 0;
/** Get socket options
* @param handle Socket handle
* @param optname Option ID
* @param optval Buffer pointer where to write the option value
* @param optlen Length of the option value
* @return 0 on success, negative on failure
*/
virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen) = 0;
/** Bind a server socket to a specific port
* @param handle Socket handle
* @param port The port to listen for incoming connections on
* @return 0 on success, negative on failure.
*/
virtual int socket_bind(void *handle, int port) = 0;
/** Start listening for incoming connections
* @param handle Socket handle
* @param backlog Number of pending connections that can be queued up at any
* one time [Default: 1]
* @return 0 on success, negative on failure
*/
virtual int socket_listen(void *handle, int backlog) = 0;
/** Connects this TCP socket to the server
* @param handle Socket handle
* @param address SocketAddress to connect to
* @return 0 on success, negative on failure
*/
virtual int socket_connect(void *handle, const SocketAddress &address) = 0;
/** Check if the socket is connected
* @param handle Socket handle
* @return true if connected, false otherwise
*/
virtual bool socket_is_connected(void *handle) = 0;
/** Accept a new connection.
* @param handle Socket handle
* @param socket A TCPSocket instance that will handle the incoming connection.
* @return 0 on success, negative on failure.
* @note This call is not-blocking, if this call would block, must
* immediately return NSAPI_ERROR_WOULD_WAIT
*/
virtual int socket_accept(void *handle, void **connection) = 0;
/** Send data to the remote host
* @param handle Socket handle
* @param data The buffer to send to the host
* @param size The length of the buffer to send
* @return Number of written bytes on success, negative on failure
* @note This call is not-blocking, if this call would block, must
* immediately return NSAPI_ERROR_WOULD_WAIT
*/
virtual int socket_send(void *handle, const void *data, unsigned size) = 0;
/** Receive data from the remote host
* @param handle Socket handle
* @param data The buffer in which to store the data received from the host
* @param size The maximum length of the buffer
* @return Number of received bytes on success, negative on failure
* @note This call is not-blocking, if this call would block, must
* immediately return NSAPI_ERROR_WOULD_WAIT
*/
virtual int socket_recv(void *handle, void *data, unsigned size) = 0;
/** Send a packet to a remote endpoint
* @param handle Socket handle
* @param address The remote SocketAddress
* @param data The packet to be sent
* @param size The length of the packet to be sent
* @return the number of written bytes on success, negative on failure
* @note This call is not-blocking, if this call would block, must
* immediately return NSAPI_ERROR_WOULD_WAIT
*/
virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size) = 0;
/** Receive a packet from a remote endpoint
* @param handle Socket handle
* @param address Destination for the remote SocketAddress or null
* @param buffer The buffer for storing the incoming packet data
* If a packet is too long to fit in the supplied buffer,
* excess bytes are discarded
* @param size The length of the buffer
* @return the number of received bytes on success, negative on failure
* @note This call is not-blocking, if this call would block, must
* immediately return NSAPI_ERROR_WOULD_WAIT
*/
virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size) = 0;
/** Close the socket
* @param handle Socket handle
* @param shutdown free the left-over data in message queues
*/
virtual int socket_close(void *handle, bool shutdown) = 0;
/** Register a callback on when a new connection is ready
* @param handle Socket handle
* @param callback Function to call when accept will succeed, may be called in
* interrupt context.
* @param id Argument to pass to callback
*/
virtual void socket_attach_accept(void *handle, void (*callback)(void *), void *id) = 0;
/** Register a callback on when send is ready
* @param handle Socket handle
* @param callback Function to call when accept will succeed, may be called in
* interrupt context.
* @param id Argument to pass to callback
*/
virtual void socket_attach_send(void *handle, void (*callback)(void *), void *id) = 0;
/** Register a callback on when recv is ready
* @param handle Socket handle
* @param callback Function to call when accept will succeed, may be called in
* interrupt context.
* @param id Argument to pass to callback
*/
virtual void socket_attach_recv(void *handle, void (*callback)(void *), void *id) = 0;
};
#endif

View File

@ -15,116 +15,68 @@
*/
#include "Socket.h"
#include <string.h>
Socket::Socket(NetworkInterface *iface, ns_protocol_t proto)
Socket::Socket(NetworkInterface *iface, nsapi_protocol_t proto)
: _iface(iface)
, _proto(proto)
, _socket(0)
, _blocking(true)
, _timeout(0)
{
memset(_ip_address, 0, NS_IP_SIZE);
_port = 0;
_socket = _iface->socket_create(proto);
}
Socket::~Socket()
{
if (_socket) {
close();
close(false);
}
}
int32_t Socket::open(const char *address, uint16_t port)
void Socket::set_blocking(bool blocking)
{
int32_t err;
err = close();
if (err) {
return err;
}
err = _iface->getHostByName(address, _ip_address);
_port = port;
if (err) {
return err;
}
_socket = _iface->createSocket(_proto);
if (!_socket) {
return NS_ERROR_NO_SOCKET;
}
err = _socket->open(_ip_address, _port);
if (err) {
_iface->destroySocket(_socket);
_socket = 0;
}
return err;
_blocking = blocking;
}
int32_t Socket::close()
void Socket::set_timeout(unsigned timeout)
{
_timeout = timeout;
}
int Socket::set_option(int optname, const void *optval, unsigned int optlen)
{
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
return _iface->socket_set_option(_socket, optname, optval, optlen);
}
int Socket::get_option(int optname, void *optval, unsigned int *optlen)
{
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
return _iface->socket_get_option(_socket, optname, optval, optlen);
}
int Socket::close(bool shutdown)
{
if (!_socket) {
return 0;
}
SocketInterface *socket = _socket;
_socket = 0;
int32_t err = socket->close();
int err = _iface->socket_close(_socket, shutdown);
if (!err) {
_iface->destroySocket(socket);
void *socket = _socket;
_socket = 0;
_iface->socket_destroy(socket);
}
return err;
}
int32_t Socket::send(const void *data, uint32_t size)
void Socket::thunk(void *p)
{
if (!_socket) {
return NS_ERROR_NO_CONNECTION;
}
return _socket->send(data, size);
FunctionPointer *fptr = (FunctionPointer *)p;
(*fptr)();
}
int32_t Socket::recv(void *data, uint32_t size, bool blocking)
{
while (true) {
if (!_socket) {
return NS_ERROR_NO_CONNECTION;
}
int32_t recv = _socket->recv(data, size);
if (recv != NS_ERROR_WOULD_BLOCK || !blocking) {
return recv;
}
}
}
const char *Socket::getIPAddress() const
{
if (_ip_address[0]) {
return _ip_address;
} else {
return 0;
}
}
uint16_t Socket::getPort() const
{
return _port;
}
bool Socket::isConnected()
{
if (!_socket) {
return false;
}
return _socket->isConnected();
}

View File

@ -17,69 +17,57 @@
#ifndef SOCKET_H
#define SOCKET_H
#include "SocketAddress.h"
#include "NetworkInterface.h"
/** Abstract socket class
* API for handling general sockets. Supports IP address operations
* and sending/recieving data.
*/
class Socket
{
class Socket {
public:
~Socket();
/** Open a connection to the underlying address
* @param address URL or IP address to connect to
* @param port Port to connect to
* @return 0 on success
/** Socket lifetime
*/
int32_t open(const char *address, uint16_t port);
/** Close an open connection
* @return 0 on success
virtual ~Socket();
/** Set blocking or non-blocking mode of the socket
* @param blocking true for blocking mode, false for non-blocking mode.
*/
int32_t close();
/** Send data over the socket
* @param data Buffer of data to send
* @param size Size of data to send
* @return Number of bytes sent or a negative value on failure
void set_blocking(bool blocking);
/** Set timeout on a socket operation if blocking behaviour is enabled
* @param timeout timeout in ms
*/
int32_t send(const void *data, uint32_t size);
void set_timeout(unsigned int timeout);
/** Recieve data over the socket
* @param data Buffer to store recieved data
* @param size Size of provided buffer
* @param blocking If true wait for data, otherwise return NS_ERROR_WOULD_BLOCK
* @return Number of bytes recieved or a negative value on failure
/* Set socket options
* @param optname Option ID
* @param optval Option value
* @param optlen Length of the option value
* @return 0 on success, negative on failure
*/
int32_t recv(void *data, uint32_t size, bool blocking = true);
/** Gets the IP address
* @return IP address to connect to
int set_option(int optname, const void *optval, unsigned optlen);
/* Get socket options
* @param optname Option ID
* @param optval Buffer pointer where to write the option value
* @param optlen Length of the option value
* @return 0 on success, negative on failure
*/
const char *getIPAddress() const;
/** Gets the port
* @return Port to connect to
int get_option(int optname, void *optval, unsigned *optlen);
/** Close the socket
* @param shutdown free the left-over data in message queues
*/
uint16_t getPort() const;
/** Returns status of socket
* @return true if connected
*/
bool isConnected();
int close(bool shutdown=true);
protected:
Socket(NetworkInterface *iface, ns_protocol_t proto);
Socket(NetworkInterface *iface, nsapi_protocol_t proto);
static void thunk(void *);
private:
NetworkInterface *_iface;
ns_protocol_t _proto;
SocketInterface *_socket;
char _ip_address[NS_IP_SIZE];
uint16_t _port;
void *_socket;
bool _blocking;
unsigned _timeout;
};
#endif

67
SocketAddress.cpp Normal file
View File

@ -0,0 +1,67 @@
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SocketAddress.h"
#include "NetworkInterface.h"
#include <string.h>
#include "mbed.h"
SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t port)
{
int err = iface->gethostbyname(host, _ip_address);
set_port(port);
if (err) {
_ip_address[0] = '\0';
_port = 0;
}
}
SocketAddress::SocketAddress(const char *addr, uint16_t port)
{
set_ip_address(addr);
set_port(port);
}
SocketAddress::SocketAddress(const SocketAddress &addr)
{
set_ip_address(addr.get_ip_address());
set_port(addr.get_port());
}
void SocketAddress::set_ip_address(const char *addr)
{
strncpy(_ip_address, addr, sizeof _ip_address);
_ip_address[sizeof _ip_address - 1] = '\0';
}
void SocketAddress::set_port(uint16_t port)
{
_port = port;
}
const char *SocketAddress::get_ip_address() const
{
if (!_ip_address[0]) {
return 0;
}
return _ip_address;
}
uint16_t SocketAddress::get_port() const
{
return _port;
}

83
SocketAddress.h Normal file
View File

@ -0,0 +1,83 @@
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOCKET_ADDRESS_H
#define SOCKET_ADDRESS_H
#include <stdint.h>
/** Maximum size of IP address
*/
#define NSAPI_IP_SIZE 16
/** Maximum size of MAC address
*/
#define NSAPI_MAC_SIZE 18
// Predeclared classes
class NetworkInterface;
/**
* A general socket address composed of the IP address and port
*/
class SocketAddress {
public:
/** SocketAddress construction using DNS resolution
* @param iface NetworkInterface to use for DNS resolution
* @param addr Null-terminated hostname that will be resolved
* @param port 16-bit port
* @note on failure, IP address and port will be set to null
*/
SocketAddress(NetworkInterface *iface, const char *addr, uint16_t port = 0);
/** SocketAddress construction
* @param addr Null-terminated IP address
* @param port 16-bit port
* @note on failure, IP address and port will be set to null
*/
SocketAddress(const char *addr = 0, uint16_t port = 0);
/** SocketAddress construction
* @param addr SocketAddress to copy
*/
SocketAddress(const SocketAddress &addr);
/** Set the IP address
* @param addr Null-terminated string representing the IP address
*/
void set_ip_address(const char *addr);
/** Set the port
* @param port 16-bit port
*/
void set_port(uint16_t port);
/** Get the IP address
* @return The string representation of the IP Address
*/
const char *get_ip_address() const;
/** Get the port
* @return The 16-bit port
*/
uint16_t get_port(void) const;
private:
char _ip_address[NSAPI_IP_SIZE];
uint16_t _port;
};
#endif

View File

@ -1,83 +0,0 @@
/* SocketInterface Base Class
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOCKET_INTERFACE_H
#define SOCKET_INTERFACE_H
#include "stdint.h"
/**
* @enum ns_protocol_t
* @brief enum of socket protocols
*/
enum ns_protocol_t {
NS_TCP, /*!< Socket is of TCP type */
NS_UDP, /*!< Socket is of UDP type */
};
/** SocketInterface class
* Common interface for implementation specific sockets created through
* network interfaces. This class is used internally by the
* TCPSocket and UDPSocket classes
*/
class SocketInterface
{
public:
virtual ~SocketInterface() {}
/** Open a connection to the underlying address
* @param ip IP address to connect to
* @param port Port to connect to
* @return 0 on success
*/
virtual int32_t open(const char *ip, uint16_t port) = 0;
/** Close an open connection
* @return 0 on success
*/
virtual int32_t close() = 0;
/** Send data
* @param data Buffer of data to send
* @param size Size of data to send
* @return Number of bytes received or a negative value on success
*/
virtual int32_t send(const void *data, uint32_t size) = 0;
/** Receive data
* @note
* This call should return immediately with a value of
* NS_ERROR_WOULD_BOCK if no data is available.
*
* @param data A buffer to store the data in
* @param size Size of buffer
* @return Number of bytes received or a negative value on failure
*/
virtual int32_t recv(void *data, uint32_t size) = 0;
/** Status of the socket
* @return True if connected
*/
virtual bool isConnected() {
// By default return true if socket was created successfully
return true;
}
};
#endif

87
TCPServer.cpp Normal file
View File

@ -0,0 +1,87 @@
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "TCPServer.h"
#include "Timer.h"
TCPServer::TCPServer(NetworkInterface *iface)
: Socket(iface, NSAPI_TCP)
{
}
int TCPServer::bind(uint16_t port)
{
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
return _iface->socket_bind(_socket, port);
}
int TCPServer::listen(int backlog)
{
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
return _iface->socket_listen(_socket, backlog);
}
int TCPServer::accept(TCPSocket *connection)
{
mbed::Timer timer;
timer.start();
void *socket = connection->_socket;
connection->_socket = 0;
_iface->socket_destroy(socket);
while (true) {
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
int err = _iface->socket_accept(_socket, &socket);
if (err > 0) {
connection->_socket = socket;
}
if (err != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
(_timeout && timer.read_ms() > _timeout)) {
return err;
}
}
}
void TCPServer::attach_accept(FunctionPointer callback)
{
_accept_cb = callback;
if (_socket && _accept_cb) {
return _iface->socket_attach_accept(_socket, Socket::thunk, &_accept_cb);
} else if (_socket) {
return _iface->socket_attach_accept(_socket, 0, 0);
}
}
TCPServer::~TCPServer()
{
if (_socket && _accept_cb) {
_iface->socket_attach_accept(_socket, 0, 0);
}
}

67
TCPServer.h Normal file
View File

@ -0,0 +1,67 @@
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include "Socket.h"
#include "TCPSocket.h"
#include "NetworkInterface.h"
/** TCP Server.
*/
class TCPServer : public Socket {
public:
/** TCP Server lifetime
*/
TCPServer(NetworkInterface *iface);
virtual ~TCPServer();
/** Bind a socket to a specific port
* @param port The port to listen for incoming connections on
* @return 0 on success, negative on failure
*/
int bind(uint16_t port);
/** Start listening for incoming connections
* @param backlog Number of pending connections that can be queued up at any
* one time [Default: 1]
* @return 0 on success, negative on failure
*/
int listen(int backlog=1);
/** Accept a new connection.
* @param socket A TCPSocket instance that will handle the incoming connection.
* @return 0 on success, negative on failure.
*/
int accept(TCPSocket *connection);
/** Register a callback on when a new connection is ready
* @param callback Function to call when accept will succeed, may be called in
* interrupt context.
*/
void attach_accept(FunctionPointer callback);
template <typename T, typename M>
void attach_accept(T *tptr, M mptr) {
attach_accept(FunctionPointer(tptr, mptr));
}
private:
FunctionPointer _accept_cb;
};
#endif

117
TCPSocket.cpp Normal file
View File

@ -0,0 +1,117 @@
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "TCPSocket.h"
#include "Timer.h"
TCPSocket::TCPSocket(NetworkInterface *iface)
: Socket(iface, NSAPI_TCP)
{
}
int TCPSocket::connect(const SocketAddress &addr)
{
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
return _iface->socket_connect(_socket, addr);
}
int TCPSocket::connect(const char *host, uint16_t port)
{
SocketAddress addr(_iface, host, port);
if (!addr.get_ip_address()) {
return NSAPI_ERROR_DNS_FAILURE;
}
return connect(addr);
}
bool TCPSocket::is_connected()
{
return _socket && _iface->socket_is_connected(_socket);
}
int TCPSocket::send(const void *data, unsigned size)
{
mbed::Timer timer;
timer.start();
while (true) {
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
int sent = _iface->socket_send(_socket, data, size);
if (sent != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
(_timeout && timer.read_ms() > _timeout)) {
return sent;
}
}
}
int TCPSocket::recv(void *data, unsigned size)
{
mbed::Timer timer;
timer.start();
while (true) {
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
int recv = _iface->socket_recv(_socket, data, size);
if (recv != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
(_timeout && timer.read_ms() > _timeout)) {
return recv;
}
}
}
void TCPSocket::attach_send(FunctionPointer callback)
{
_send_cb = callback;
if (_socket && _send_cb) {
return _iface->socket_attach_send(_socket, Socket::thunk, &_send_cb);
} else if (_socket) {
return _iface->socket_attach_send(_socket, 0, 0);
}
}
void TCPSocket::attach_recv(FunctionPointer callback)
{
_recv_cb = callback;
if (_socket && _recv_cb) {
return _iface->socket_attach_recv(_socket, Socket::thunk, &_recv_cb);
} else if (_socket) {
return _iface->socket_attach_recv(_socket, 0, 0);
}
}
TCPSocket::~TCPSocket()
{
if (_socket && _send_cb) {
_iface->socket_attach_send(_socket, 0, 0);
}
if (_socket && _recv_cb) {
_iface->socket_attach_recv(_socket, 0, 0);
}
}

View File

@ -1,4 +1,4 @@
/* TCPSocket
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -14,26 +14,81 @@
* limitations under the License.
*/
#ifndef TCP_SOCKET_H
#define TCP_SOCKET_H
#ifndef TCPSOCKET_H
#define TCPSOCKET_H
#include "Socket.h"
#include "NetworkInterface.h"
/** TCPSocket class
* API for handling TCP sockets. The implementation is determined
* by the interface passed during construction.
/** TCP socket connection
*/
class TCPSocket : public Socket
{
class TCPSocket : public Socket {
public:
/** Create a socket using the specified network interface
* No network operations are performed until the socket is actually used
* @param iface The network interface to use
* @param url Optional URL to connect to, copied internally
* @param port Optional port to connect to
/** TCP socket lifetime
*/
TCPSocket(NetworkInterface *iface)
: Socket(iface, NS_TCP) {}
TCPSocket(NetworkInterface *iface);
virtual ~TCPSocket();
/** Connects this TCP socket to the server
* @param host The host to connect to. It can either be an IP Address
* or a hostname that will be resolved with DNS
* @param port The host's port to connect to
* @return 0 on success, negative on failure
*/
int connect(const char *host, uint16_t port);
/** Connects this TCP socket to the server
* @param address SocketAddress to connect to
* @return 0 on success, negative on failure
*/
int connect(const SocketAddress &address);
/** Check if the socket is connected
* @return true if connected, false otherwise
*/
bool is_connected();
/** Send data to the remote host
* @param data The buffer to send to the host
* @param size The length of the buffer to send
* @return Number of written bytes on success, negative on failure
*/
int send(const void *data, unsigned size);
/** Receive data from the remote host
* @param data The buffer in which to store the data received from the host
* @param size The maximum length of the buffer
* @return Number of received bytes on success, negative on failure
*/
int recv(void *data, unsigned size);
/** Register a callback on when send is ready
* @param callback Function to call when send will succeed, may be called in
* interrupt context.
*/
void attach_send(FunctionPointer callback);
template <typename T, typename M>
void attach_send(T *tptr, M mptr) {
attach_send(FunctionPointer(tptr, mptr));
}
/** Register a callback on when recv is ready
* @param callback Function to call when recv will succeed, may be called in
* interrupt context.
*/
void attach_recv(FunctionPointer callback);
template <typename T, typename M>
void attach_recv(T *tptr, M mptr) {
attach_recv(FunctionPointer(tptr, mptr));
}
private:
friend class TCPServer;
FunctionPointer _send_cb;
FunctionPointer _recv_cb;
};
#endif

100
UDPSocket.cpp Normal file
View File

@ -0,0 +1,100 @@
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "UDPSocket.h"
#include "Timer.h"
UDPSocket::UDPSocket(NetworkInterface *iface)
: Socket(iface, NSAPI_UDP)
{
}
int UDPSocket::bind(uint16_t port)
{
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
return _iface->socket_bind(_socket, port);
}
int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size)
{
mbed::Timer timer;
timer.start();
while (true) {
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
int sent = _iface->socket_sendto(_socket, address, data, size);
if (sent != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
(_timeout && timer.read_ms() > _timeout)) {
return sent;
}
}
}
int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size)
{
mbed::Timer timer;
timer.start();
while (true) {
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
int recv = _iface->socket_recvfrom(_socket, address, buffer, size);
if (recv != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
(_timeout && timer.read_ms() > _timeout)) {
return recv;
}
}
}
void UDPSocket::attach_send(FunctionPointer callback)
{
_send_cb = callback;
if (_socket && _send_cb) {
return _iface->socket_attach_send(_socket, Socket::thunk, &_send_cb);
} else if (_socket) {
return _iface->socket_attach_send(_socket, 0, 0);
}
}
void UDPSocket::attach_recv(FunctionPointer callback)
{
_recv_cb = callback;
if (_socket && _recv_cb) {
return _iface->socket_attach_recv(_socket, Socket::thunk, &_recv_cb);
} else if (_socket) {
return _iface->socket_attach_recv(_socket, 0, 0);
}
}
UDPSocket::~UDPSocket()
{
if (_socket && _send_cb) {
_iface->socket_attach_send(_socket, 0, 0);
}
if (_socket && _recv_cb) {
_iface->socket_attach_recv(_socket, 0, 0);
}
}

View File

@ -1,4 +1,4 @@
/* UDPSocket
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -14,26 +14,70 @@
* limitations under the License.
*/
#ifndef UDP_SOCKET_H
#define UDP_SOCKET_H
#ifndef UDPSOCKET_H
#define UDPSOCKET_H
#include "Socket.h"
#include "NetworkInterface.h"
/** UDPSocket class
* API for handling UDP sockets. The implementation is determined
* by the interface passed during construction.
/** UDP Socket
*/
class UDPSocket : public Socket
{
class UDPSocket : public Socket {
public:
/** Create a socket using the specified network interface
* No network operations are performed until the socket is actually used
* @param iface The network interface to use
* @param ip Optional URL to connect to, copied internally
* @param port Optional port to connect to
/** UDPSocket lifetime
*/
UDPSocket(NetworkInterface *iface)
: Socket(iface, NS_UDP) {}
UDPSocket(NetworkInterface *iface);
virtual ~UDPSocket();
/** Bind a UDP Server Socket to a specific port
* @param port The port to listen for incoming connections on
* @return 0 on success, negative on failure.
*/
int bind(uint16_t port);
/** Send a packet to a remote endpoint
* @param address The remote SocketAddress
* @param data The packet to be sent
* @param size The length of the packet to be sent
* @return The number of written bytes on success, negative on failure
*/
int sendto(const SocketAddress &address, const void *data, unsigned size);
/** Receive a packet from a remote endpoint
* @param address Destination for the remote SocketAddress or null
* @param buffer The buffer for storing the incoming packet data
* If a packet is too long to fit in the supplied buffer,
* excess bytes are discarded
* @param size The length of the buffer
* @return The number of received bytes on success, negative on failure
*/
int recvfrom(SocketAddress *address, void *buffer, unsigned size);
/** Register a callback on when send is ready
* @param callback Function to call when send will succeed, may be called in
* interrupt context.
*/
void attach_send(FunctionPointer callback);
template <typename T, typename M>
void attach_send(T *tptr, M mptr) {
attach_send(FunctionPointer(tptr, mptr));
}
/** Register a callback on when recv is ready
* @param callback Function to call when recv will succeed, may be called in
* interrupt context.
*/
void attach_recv(FunctionPointer callback);
template <typename T, typename M>
void attach_recv(T *tptr, M mptr) {
attach_recv(FunctionPointer(tptr, mptr));
}
private:
FunctionPointer _send_cb;
FunctionPointer _recv_cb;
};
#endif

View File

@ -1,4 +1,4 @@
/* WiFiInterface Base Class
/* Socket
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,14 +21,13 @@
/** Enum for WiFi encryption types
*/
enum ns_security_t {
NS_SECURITY_NONE = 0, /*!< open access point */
NS_SECURITY_WEP, /*!< phrase conforms to WEP */
NS_SECURITY_WPA, /*!< phrase conforms to WPA */
NS_SECURITY_WPA2, /*!< phrase conforms to WPA2 */
enum nsapi_security_t {
NSAPI_SECURITY_NONE = 0, /*!< open access point */
NSAPI_SECURITY_WEP, /*!< phrase conforms to WEP */
NSAPI_SECURITY_WPA, /*!< phrase conforms to WPA */
NSAPI_SECURITY_WPA2, /*!< phrase conforms to WPA2 */
};
/** WiFiInterface class
* Common interface that is shared between WiFi devices
*/
@ -36,17 +35,17 @@ class WiFiInterface : public NetworkInterface
{
public:
/** Start the interface
* @param ssid Name of the network to connect to
* @param pass Security passphrase to connect to the network
* @param security Type of encryption to connect with
* @return 0 on success
* @param ssid Name of the network to connect to
* @param pass Security passphrase to connect to the network
* @param security Type of encryption for connection
* @return 0 on success, negative on failure
*/
virtual int32_t connect(const char *ssid, const char *pass, ns_security_t security = NS_SECURITY_NONE) = 0;
virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE) = 0;
/** Stop the interface
* @return 0 on success
* @return 0 on success, negative on failure
*/
virtual int32_t disconnect() = 0;
virtual int disconnect() = 0;
};
#endif