Merge pull request #2216 from geky/nsapi

Introduce the network-socket API to mbed
pull/2229/head
Sam Grove 2016-07-22 14:56:24 -05:00 committed by GitHub
commit 9ab05ae7c5
21 changed files with 3135 additions and 0 deletions

View File

@ -0,0 +1,53 @@
/* CellularInterface
* 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 CELLULAR_INTERFACE_H
#define CELLULAR_INTERFACE_H
#include "network-socket/NetworkInterface.h"
/** CellularInterface class
*
* Common interface that is shared between ethernet hardware
*/
class CellularInterface : public NetworkInterface
{
public:
/** Start the interface
*
* @param apn Optional name of the network to connect to
* @param username Optional username for your APN
* @param password Optional password for your APN
* @return 0 on success, negative error code on failure
*/
virtual int connect(const char *apn = 0, const char *username = 0, const char *password = 0) = 0;
/** Stop the interface
*
* @return 0 on success, negative error code on failure
*/
virtual int disconnect() = 0;
/** Get the local MAC address
*
* @return Null-terminated representation of the local MAC address
*/
virtual const char *get_mac_address() = 0;
};
#endif

View File

@ -0,0 +1,216 @@
/* Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "DnsQuery.h"
#include <stdio.h>
#include <string.h>
#define DNS_COUNT (sizeof DNS_IPS / sizeof DNS_IPS[0])
const char *DNS_IPS[] = {
"8.8.8.8",
"209.244.0.3",
"84.200.69.80",
"8.26.56.26",
"208.67.222.222"
};
static bool isIP(const char *host)
{
int i;
for (i = 0; host[i]; i++) {
if (!(host[i] >= '0' && host[i] <= '9') && host[i] != '.') {
return false;
}
}
// Ending with '.' garuntees host
if (i > 0 && host[i-1] == '.') {
return false;
}
return true;
}
static bool parseRR(uint8_t *resp, int &c, char *adr)
{
int n = 0;
while((n=resp[c++]) != 0) {
if ((n & 0xc0) != 0) {
// This is a link
c++;
break;
} else {
// skip this segment, not interested in string domain names
c+= n;
}
}
int TYPE = (((int)resp[c])<<8) + resp[c+1];
int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
c+= 10;
if ((CLASS == 1) && (TYPE == 1)) {
sprintf(adr,"%d.%d.%d.%d", resp[c], resp[c+1], resp[c+2], resp[c+3]);
c+= RDLENGTH;
return true;
}
c+= RDLENGTH;
return false;
}
static bool resolve(unsigned char *resp, char *ipaddress)
{
int ID = (((int)resp[0]) <<8) + resp[1];
int QR = resp[2] >>7;
int Opcode = (resp[2]>>3) & 0x0F;
int RCODE = (resp[3] & 0x0F);
int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
return false;
}
int c = 12;
int d;
// Skip domain question
while( (d=resp[c++]) != 0) {
c+=d;
}
c+= 4; // skip QTYPE and QCLASS
// Here comes the resource record
for (int ans = 0 ; ans < ANCOUNT; ans++) {
if (parseRR(resp, c, ipaddress)) {
return true;
}
}
return false;
}
static int32_t query(UDPSocket *socket, const SocketAddress &addr, const char *hostname, char *ipaddress)
{
int len = 0;
if (hostname == NULL) {
return false;
}
len = strlen(hostname);
if ((len > 128) || (len == 0)) {
return false;
}
int packetlen = /* size of HEADER structure */ 12 + /* size of QUESTION Structure */5 + len + 1;
uint8_t *packet = new uint8_t[packetlen]; /* this is the UDP packet to send to the DNS */
if (packet == NULL) {
return false;
}
// Fill the header
memset(packet, 0, packetlen);
packet[1] = 1; // ID = 1
packet[5] = 1; // QDCOUNT = 1 (contains one question)
packet[2] = 1; // recursion requested
int c = 13; // point to NAME element in question section or request
int cnt = 12; // points to the counter of
packet[cnt] = 0;
for (int i = 0 ; i < len ; i++) {
if (hostname[i] != '.') {
// Copy the character and increment the character counter
packet[cnt]++;
packet[c++] = hostname[i];
} else {
// Finished with this part, so go to the next
cnt = c++;
packet[cnt] = 0;
}
}
// Terminate this domain name with a zero entry
packet[c++] = 0;
// Set QTYPE
packet[c++] = 0;
packet[c++] = 1;
// Set QCLASS
packet[c++] = 0;
packet[c++] = 1;
if (socket->sendto(addr, packet, packetlen) < 0) {
delete packet;
return false;
}
delete packet;
packet = new uint8_t [1024];
// Receive the answer from DNS
int response_length = 0;
response_length = socket->recvfrom(NULL, packet, 1024);
if (response_length > 0 ) {
if (!resolve(packet, ipaddress)) {
delete packet;
return NSAPI_ERROR_DNS_FAILURE;
}
// cleanup and return
delete packet;
return 0;
}
delete packet;
return NSAPI_ERROR_DNS_FAILURE;
}
int32_t dnsQuery(NetworkStack *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

@ -0,0 +1,41 @@
/*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __DNSQUERY_H__
#define __DNSQUERY_H__
#include "NetworkStack.h"
#include "UDPSocket.h"
/** Function dnsQuery implements the functionality to query a domain name
* server for an IP-Address of a given hostname.
* @param iface : Network interface to use for DNS resolution.
* @param sock : Previously opened socket to use for DNS resolution.
* @param hostname : The hostname of interest as a string.
* Format must be without http:// or www. IE google.com, mbed.org, etc.
* If a standard IP Address is passed, it will be copied into ip unmodified.
* @param ipaddress : A reference to a IPADDRESS_t object which will receive
* the resolved IP Address of the host in question.
* @returns 0 on succes, NS_DNS_FAILURE if host is not found,
* or a negative value for other errors.
*/
int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip);
int32_t dnsQuery(UDPSocket *sock, const char *host, char *ip);
#endif // __DNSQUERY_H__

View File

@ -0,0 +1,50 @@
/* EthInterface
* 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 ETH_INTERFACE_H
#define ETH_INTERFACE_H
#include "network-socket/NetworkInterface.h"
/** EthInterface class
*
* Common interface that is shared between ethernet hardware.
*/
class EthInterface : public NetworkInterface
{
public:
/** Start the interface
*
* @return 0 on success, negative error code on failure
*/
virtual int connect() = 0;
/** Stop the interface
*
* @return 0 on success, negative error code on failure
*/
virtual int disconnect() = 0;
/** Get the local MAC address
*
* @return Null-terminated representation of the local MAC address
*/
virtual const char *get_mac_address() = 0;
};
#endif

View File

@ -0,0 +1,50 @@
/* MeshInterface
* 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 "network-socket/NetworkInterface.h"
/** MeshInterface class
*
* Common interface that is shared between mesh 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;
/** Get the local MAC address
*
* @return Null-terminated representation of the local MAC address
*/
virtual const char *get_mac_address() = 0;
};
#endif

View File

@ -0,0 +1,56 @@
/* NetworkStack
* 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 NETWORK_INTERFACE_H
#define NETWORK_INTERFACE_H
// Predeclared class
class NetworkStack;
/** NetworkInterface class
*
* Common interface that is shared between network devices
*/
class NetworkInterface {
public:
virtual ~NetworkInterface() {};
/** Get the local IP address
*
* @return Null-terminated representation of the local IP address
* or null if not yet connected
*/
virtual const char *get_ip_address() = 0;
protected:
friend class Socket;
friend class UDPSocket;
friend class TCPSocket;
friend class TCPServer;
friend class SocketAddress;
template <typename IF>
friend NetworkStack *nsapi_create_stack(IF *iface);
/** Provide access to the NetworkStack object
*
* @return The underlying NetworkStack object
*/
virtual NetworkStack *get_stack() = 0;
};
#endif

View File

@ -0,0 +1,257 @@
/* 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 "NetworkStack.h"
#include "DnsQuery.h"
#include "mbed.h"
#include "stddef.h"
#include <new>
// Default NetworkStack operations
int NetworkStack::gethostbyname(SocketAddress *address, const char *name)
{
char buffer[NSAPI_IP_SIZE];
int err = dnsQuery(this, name, buffer);
if (err) {
return err;
}
address->set_ip_address(buffer);
return 0;
}
int NetworkStack::setstackopt(int level, int optname, const void *optval, unsigned optlen)
{
return NSAPI_ERROR_UNSUPPORTED;
}
int NetworkStack::getstackopt(int level, int optname, void *optval, unsigned *optlen)
{
return NSAPI_ERROR_UNSUPPORTED;
}
int NetworkStack::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen)
{
return NSAPI_ERROR_UNSUPPORTED;
}
int NetworkStack::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen)
{
return NSAPI_ERROR_UNSUPPORTED;
}
// NetworkStackWrapper class for encapsulating the raw nsapi_stack structure
class NetworkStackWrapper : public NetworkStack
{
private:
inline nsapi_stack_t *_stack()
{
return reinterpret_cast<nsapi_stack_t *>(
reinterpret_cast<uint8_t *>(this)
- offsetof(nsapi_stack_t, _stack_buffer));
}
inline const nsapi_stack_api_t *_stack_api()
{
return _stack()->stack_api;
}
public:
virtual const char *get_ip_address()
{
if (!_stack_api()->get_ip_address) {
return 0;
}
static uint8_t buffer[sizeof(SocketAddress)];
SocketAddress *address = new (buffer) SocketAddress(_stack_api()->get_ip_address(_stack()));
return address->get_ip_address();
}
virtual int gethostbyname(SocketAddress *address, const char *name)
{
if (!_stack_api()->gethostbyname) {
return NetworkStack::gethostbyname(address, name);
}
nsapi_addr_t addr = {NSAPI_IPv4, 0};
int err = _stack_api()->gethostbyname(_stack(), &addr, name);
address->set_addr(addr);
return err;
}
virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen)
{
if (!_stack_api()->setstackopt) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->setstackopt(_stack(), level, optname, optval, optlen);
}
virtual int getstackopt(int level, int optname, void *optval, unsigned *optlen)
{
if (!_stack_api()->getstackopt) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->getstackopt(_stack(), level, optname, optval, optlen);
}
protected:
virtual int socket_open(nsapi_socket_t *socket, nsapi_protocol_t proto)
{
if (!_stack_api()->socket_open) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->socket_open(_stack(), socket, proto);
}
virtual int socket_close(nsapi_socket_t socket)
{
if (!_stack_api()->socket_close) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->socket_close(_stack(), socket);
}
virtual int socket_bind(nsapi_socket_t socket, const SocketAddress &address)
{
if (!_stack_api()->socket_bind) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->socket_bind(_stack(), socket, address.get_addr(), address.get_port());
}
virtual int socket_listen(nsapi_socket_t socket, int backlog)
{
if (!_stack_api()->socket_listen) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->socket_listen(_stack(), socket, backlog);
}
virtual int socket_connect(nsapi_socket_t socket, const SocketAddress &address)
{
if (!_stack_api()->socket_connect) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->socket_connect(_stack(), socket, address.get_addr(), address.get_port());
}
virtual int socket_accept(nsapi_socket_t *socket, nsapi_socket_t server)
{
if (!_stack_api()->socket_accept) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->socket_accept(_stack(), socket, server);
}
virtual int socket_send(nsapi_socket_t socket, const void *data, unsigned size)
{
if (!_stack_api()->socket_send) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->socket_send(_stack(), socket, data, size);
}
virtual int socket_recv(nsapi_socket_t socket, void *data, unsigned size)
{
if (!_stack_api()->socket_recv) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->socket_recv(_stack(), socket, data, size);
}
virtual int socket_sendto(nsapi_socket_t socket, const SocketAddress &address, const void *data, unsigned size)
{
if (!_stack_api()->socket_sendto) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->socket_sendto(_stack(), socket, address.get_addr(), address.get_port(), data, size);
}
virtual int socket_recvfrom(nsapi_socket_t socket, SocketAddress *address, void *data, unsigned size)
{
if (!_stack_api()->socket_recvfrom) {
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_addr_t addr = {NSAPI_IPv4, 0};
uint16_t port = 0;
int err = _stack_api()->socket_recvfrom(_stack(), socket, &addr, &port, data, size);
if (address) {
address->set_addr(addr);
address->set_port(port);
}
return err;
}
virtual void socket_attach(nsapi_socket_t socket, void (*callback)(void *), void *data)
{
if (!_stack_api()->socket_attach) {
return;
}
return _stack_api()->socket_attach(_stack(), socket, callback, data);
}
virtual int setsockopt(nsapi_socket_t socket, int level, int optname, const void *optval, unsigned optlen)
{
if (!_stack_api()->setsockopt) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->setsockopt(_stack(), socket, level, optname, optval, optlen);
}
virtual int getsockopt(nsapi_socket_t socket, int level, int optname, void *optval, unsigned *optlen)
{
if (!_stack_api()->getsockopt) {
return NSAPI_ERROR_UNSUPPORTED;
}
return _stack_api()->getsockopt(_stack(), socket, level, optname, optval, optlen);
}
};
// Conversion function for network stacks
NetworkStack *nsapi_create_stack(nsapi_stack_t *stack)
{
MBED_ASSERT(sizeof stack->_stack_buffer >= sizeof(NetworkStackWrapper));
return new (stack->_stack_buffer) NetworkStackWrapper;
}
NetworkStack *nsapi_create_stack(NetworkStack *stack)
{
return stack;
}

View File

@ -0,0 +1,300 @@
/* NetworkStack
* 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 NETWORK_STACK_H
#define NETWORK_STACK_H
#include "nsapi_types.h"
#include "network-socket/SocketAddress.h"
#include "network-socket/NetworkInterface.h"
/** NetworkStack class
*
* Common interface that is shared between hardware that
* can connect to a network over IP. By implementing the
* NetworkStack, a network stack can be used as a target
* for instantiating network sockets.
*/
class NetworkStack
{
public:
virtual ~NetworkStack() {};
/** Get the local IP address
*
* @return Null-terminated representation of the local IP address
* or null if not yet connected
*/
virtual const char *get_ip_address() = 0;
/** Translates a hostname to an IP address
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* If no stack-specific DNS resolution is provided, the hostname
* will be resolve using a UDP socket on the stack.
*
* @param address Destination for the host SocketAddress
* @param host Hostname to resolve
* @return 0 on success, negative error code on failure
*/
virtual int gethostbyname(SocketAddress *address, const char *host);
/* Set stack-specific stack options
*
* The setstackopt allow an application to pass stack-specific hints
* to the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and the stack is unmodified.
*
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen);
/* Get stack-specific stack options
*
* The getstackopt allow an application to retrieve stack-specific hints
* from the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
*
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Destination for option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
virtual int getstackopt(int level, int optname, void *optval, unsigned *optlen);
protected:
friend class Socket;
friend class UDPSocket;
friend class TCPSocket;
friend class TCPServer;
/** Opens a socket
*
* Creates a network socket and stores it in the specified handle.
* The handle must be passed to following calls on the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* @param handle Destination for the handle to a newly created socket
* @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP
* @return 0 on success, negative error code on failure
*/
virtual int socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto) = 0;
/** Close the socket
*
* Closes any open connection and deallocates any memory associated
* with the socket.
*
* @param handle Socket handle
* @return 0 on success, negative error code on failure
*/
virtual int socket_close(nsapi_socket_t handle) = 0;
/** Bind a specific address to a socket
*
* Binding a socket specifies the address and port on which to recieve
* data. If the IP address is zeroed, only the port is bound.
*
* @param handle Socket handle
* @param address Local address to bind
* @return 0 on success, negative error code on failure.
*/
virtual int socket_bind(nsapi_socket_t handle, const SocketAddress &address) = 0;
/** Listen for connections on a TCP socket
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param handle Socket handle
* @param backlog Number of pending connections that can be queued
* simultaneously
* @return 0 on success, negative error code on failure
*/
virtual int socket_listen(nsapi_socket_t handle, int backlog) = 0;
/** Connects TCP socket to a remote host
*
* Initiates a connection to a remote server specified by the
* indicated address.
*
* @param handle Socket handle
* @param address The SocketAddress of the remote host
* @return 0 on success, negative error code on failure
*/
virtual int socket_connect(nsapi_socket_t handle, const SocketAddress &address) = 0;
/** Accepts a connection on a TCP socket
*
* The server socket must be bound and set to listen for connections.
* On a new connection, creates a network socket and stores it in the
* specified handle. The handle must be passed to following calls on
* the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* This call is non-blocking. If accept would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Destination for a handle to the newly created sockey
* @param server Socket handle to server to accept from
* @return 0 on success, negative error code on failure
*/
virtual int socket_accept(nsapi_socket_t *handle, nsapi_socket_t server) = 0;
/** Send data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes sent from the buffer.
*
* This call is non-blocking. If send would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @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 int socket_send(nsapi_socket_t handle, const void *data, unsigned size) = 0;
/** Receive data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes received into the buffer.
*
* This call is non-blocking. If recv would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @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 int socket_recv(nsapi_socket_t handle, void *data, unsigned size) = 0;
/** Send a packet over a UDP socket
*
* Sends data to the specified address. Returns the number of bytes
* sent from the buffer.
*
* This call is non-blocking. If sendto would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param address The SocketAddress of the remote host
* @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 int socket_sendto(nsapi_socket_t handle, const SocketAddress &address, const void *data, unsigned size) = 0;
/** Receive a packet over a UDP socket
*
* Receives data and stores the source address in address if address
* is not NULL. Returns the number of bytes received into the buffer.
*
* This call is non-blocking. If recvfrom would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param address Destination for the source address or NULL
* @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 int socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, void *buffer, unsigned size) = 0;
/** 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.
*
* @param handle Socket handle
* @param callback Function to call on state change
* @param data Argument to pass to callback
*/
virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data) = 0;
/* Set stack-specific socket options
*
* The setsockopt allow an application to pass stack-specific hints
* to the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
*
* @param handle Socket handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
virtual int setsockopt(nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen);
/* Get stack-specific socket options
*
* The getstackopt allow an application to retrieve stack-specific hints
* from the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
*
* @param handle Socket handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Destination for option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
virtual int getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen);
};
/** Convert a raw nsapi_stack_t object into a C++ NetworkStack object
*
* @param stack Reference to an object that can be converted to a stack
* - A raw nsapi_stack_t object
* - A reference to a network stack
* - A reference to a network interface
* @return Reference to the underlying network stack
*/
NetworkStack *nsapi_create_stack(nsapi_stack_t *stack);
NetworkStack *nsapi_create_stack(NetworkStack *stack);
template <typename IF>
NetworkStack *nsapi_create_stack(IF *iface)
{
return nsapi_create_stack(static_cast<NetworkInterface *>(iface)->get_stack());
}
#endif

View File

@ -0,0 +1,157 @@
/* 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 "Socket.h"
Socket::Socket()
: _stack(0)
, _socket(0)
, _timeout(osWaitForever)
{
}
int Socket::open(NetworkStack *stack)
{
_lock.lock();
if (_stack != NULL || stack == NULL) {
_lock.unlock();
return NSAPI_ERROR_PARAMETER;
}
_stack = stack;
nsapi_socket_t socket;
int err = _stack->socket_open(&socket, get_proto());
if (err) {
_lock.unlock();
return err;
}
_socket = socket;
_event.attach(this, &Socket::event);
_stack->socket_attach(_socket, Callback<void()>::thunk, &_event);
_lock.unlock();
return 0;
}
int Socket::close()
{
_lock.lock();
int ret = 0;
if (_socket) {
_stack->socket_attach(_socket, 0, 0);
nsapi_socket_t socket = _socket;
_socket = 0;
ret = _stack->socket_close(socket);
}
// Wakeup anything in a blocking operation
// on this socket
event();
_lock.unlock();
return ret;
}
int Socket::bind(uint16_t port)
{
// Underlying bind is thread safe
SocketAddress addr(0, port);
return bind(addr);
}
int Socket::bind(const char *address, uint16_t port)
{
// Underlying bind is thread safe
SocketAddress addr(address, port);
return bind(addr);
}
int Socket::bind(const SocketAddress &address)
{
_lock.lock();
int ret;
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
} else {
ret = _stack->socket_bind(_socket, address);
}
_lock.unlock();
return ret;
}
void Socket::set_blocking(bool blocking)
{
// Socket::set_timeout is thread safe
set_timeout(blocking ? -1 : 0);
}
void Socket::set_timeout(int timeout)
{
_lock.lock();
if (timeout >= 0) {
_timeout = (uint32_t)timeout;
} else {
_timeout = osWaitForever;
}
_lock.unlock();
}
int Socket::setsockopt(int level, int optname, const void *optval, unsigned optlen)
{
_lock.lock();
int ret;
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
} else {
ret = _stack->setsockopt(_socket, level, optname, optval, optlen);
}
_lock.unlock();
return ret;
}
int Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen)
{
_lock.lock();
int ret;
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
} else {
ret = _stack->getsockopt(_socket, level, optname, optval, optlen);
}
_lock.unlock();
return ret;
}
void Socket::attach(Callback<void()> callback)
{
_lock.lock();
_callback = callback;
_lock.unlock();
}

View File

@ -0,0 +1,195 @@
/* 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_H
#define SOCKET_H
#include "network-socket/SocketAddress.h"
#include "network-socket/NetworkStack.h"
#include "rtos/Mutex.h"
#include "Callback.h"
#ifndef NSAPI_NO_INCLUDE_MBED
#include "mbed.h" // needed for backwards compatability
#endif
/** Abstract socket class
*/
class Socket {
public:
/** 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
*/
int open(NetworkStack *stack);
template <typename S>
int 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
*/
int close();
/** Bind a specific address to a socket
*
* Binding a socket specifies the address and port on which to recieve
* data.
*
* @param port Local port to bind
* @return 0 on success, negative error code on failure.
*/
int bind(uint16_t port);
/** Bind a specific address to a socket
*
* Binding a socket specifies the address and port on which to recieve
* 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.
*/
int 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 recieve
* 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.
*/
int 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.
*/
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
*/
void set_timeout(int timeout);
/* Set stack-specific socket options
*
* The setsockopt allow an application to pass stack-specific hints
* to the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
*
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
int setsockopt(int level, int optname, const void *optval, unsigned optlen);
/* Get stack-specific socket options
*
* The getstackopt allow an application to retrieve stack-specific hints
* from the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
*
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Destination for option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
int 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.
*
* @param func Function to call on state change
*/
void attach(mbed::Callback<void()> func);
/** 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.
*
* @param obj Pointer to object to call method on
* @param method Method to call on state change
*/
template <typename T, typename M>
void attach(T *obj, M method) {
attach(mbed::Callback<void()>(obj, method));
}
protected:
Socket();
virtual nsapi_protocol_t get_proto() = 0;
virtual void event() = 0;
NetworkStack *_stack;
nsapi_socket_t _socket;
uint32_t _timeout;
mbed::Callback<void()> _event;
mbed::Callback<void()> _callback;
rtos::Mutex _lock;
};
#endif

View File

@ -0,0 +1,282 @@
/* 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 "NetworkStack.h"
#include <string.h>
#include "mbed.h"
static bool ipv4_is_valid(const char *addr)
{
int i = 0;
// Check each digit for [0-9.]
for (; addr[i]; i++) {
if (!(addr[i] >= '0' && addr[i] <= '9') && addr[i] != '.') {
return false;
}
}
// Ending with '.' garuntees host
if (i > 0 && addr[i-1] == '.') {
return false;
}
return true;
}
static bool ipv6_is_valid(const char *addr)
{
// Check each digit for [0-9a-fA-F:]
for (int i = 0; addr[i]; i++) {
if (!(addr[i] >= '0' && addr[i] <= '9') &&
!(addr[i] >= 'a' && addr[i] <= 'f') &&
!(addr[i] >= 'A' && addr[i] <= 'F') &&
addr[i] != ':') {
return false;
}
}
return true;
}
static void ipv4_from_address(uint8_t *bytes, const char *addr)
{
int count = 0;
int i = 0;
for (; count < NSAPI_IPv4_BYTES; count++) {
int scanned = sscanf(&addr[i], "%hhu", &bytes[count]);
if (scanned < 1) {
return;
}
for (; addr[i] != '.'; i++) {
if (!addr[i]) {
return;
}
}
i++;
}
}
static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) {
int count = 0;
int i = 0;
for (; count < NSAPI_IPv6_BYTES/2; count++) {
int scanned = sscanf(&chunk[i], "%hx", &shorts[count]);
if (scanned < 1) {
return count;
}
for (; chunk[i] != ':'; i++) {
if (!chunk[i]) {
return count+1;
}
}
i++;
}
return count;
}
static void ipv6_from_address(uint8_t *bytes, const char *addr)
{
// Start with zeroed address
uint16_t shorts[NSAPI_IPv6_BYTES/2];
memset(shorts, 0, sizeof shorts);
int suffix = 0;
// Find double colons and scan suffix
for (int i = 0; addr[i]; i++) {
if (addr[i] == ':' && addr[i+1] == ':') {
suffix = ipv6_scan_chunk(shorts, &addr[i+2]);
break;
}
}
// Move suffix to end
memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0],
suffix*sizeof(uint16_t));
// Scan prefix
ipv6_scan_chunk(shorts, &addr[0]);
// Flip bytes
for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
bytes[2*i+0] = (uint8_t)(shorts[i] >> 8);
bytes[2*i+1] = (uint8_t)(shorts[i] >> 0);
}
}
static void ipv4_to_address(char *addr, const uint8_t *bytes)
{
sprintf(addr, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
}
static void ipv6_to_address(char *addr, const uint8_t *bytes)
{
for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
sprintf(&addr[5*i], "%02x%02x", bytes[2*i], bytes[2*i+1]);
addr[5*i+4] = ':';
}
addr[NSAPI_IPv6_SIZE-1] = '\0';
}
SocketAddress::SocketAddress(nsapi_addr_t addr, uint16_t port)
{
_ip_address[0] = '\0';
set_addr(addr);
set_port(port);
}
SocketAddress::SocketAddress(const char *addr, uint16_t port)
{
_ip_address[0] = '\0';
set_ip_address(addr);
set_port(port);
}
SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port)
{
_ip_address[0] = '\0';
set_ip_bytes(bytes, version);
set_port(port);
}
SocketAddress::SocketAddress(const SocketAddress &addr)
{
_ip_address[0] = '\0';
set_addr(addr.get_addr());
set_port(addr.get_port());
}
void SocketAddress::set_ip_address(const char *addr)
{
_ip_address[0] = '\0';
if (addr && ipv4_is_valid(addr)) {
_addr.version = NSAPI_IPv4;
ipv4_from_address(_addr.bytes, addr);
} else if (addr && ipv6_is_valid(addr)) {
_addr.version = NSAPI_IPv6;
ipv6_from_address(_addr.bytes, addr);
} else {
_addr = (nsapi_addr_t){};
}
}
void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version)
{
nsapi_addr_t addr;
addr.version = version;
memcpy(addr.bytes, bytes, NSAPI_IP_BYTES);
set_addr(addr);
}
void SocketAddress::set_addr(nsapi_addr_t addr)
{
_ip_address[0] = '\0';
_addr = addr;
}
void SocketAddress::set_port(uint16_t port)
{
_port = port;
}
const char *SocketAddress::get_ip_address() const
{
char *ip_address = (char *)_ip_address;
if (!ip_address[0]) {
if (_addr.version == NSAPI_IPv4) {
ipv4_to_address(ip_address, _addr.bytes);
} else if (_addr.version == NSAPI_IPv6) {
ipv6_to_address(ip_address, _addr.bytes);
}
}
return ip_address;
}
const void *SocketAddress::get_ip_bytes() const
{
return _addr.bytes;
}
nsapi_version_t SocketAddress::get_ip_version() const
{
return _addr.version;
}
nsapi_addr_t SocketAddress::get_addr() const
{
return _addr;
}
uint16_t SocketAddress::get_port() const
{
return _port;
}
SocketAddress::operator bool() const
{
int count = 0;
if (_addr.version == NSAPI_IPv4) {
count = NSAPI_IPv4_BYTES;
} else if (_addr.version == NSAPI_IPv6) {
count = NSAPI_IPv6_BYTES;
}
for (int i = 0; i < count; i++) {
if (_addr.bytes[i]) {
return true;
}
}
return false;
}
void SocketAddress::_SocketAddress(NetworkStack *iface, const char *host, uint16_t port)
{
_ip_address[0] = '\0';
// Check for valid IP addresses
if (host && ipv4_is_valid(host)) {
_addr.version = NSAPI_IPv4;
ipv4_from_address(_addr.bytes, host);
_port = port;
} else if (host && ipv6_is_valid(host)) {
_addr.version = NSAPI_IPv6;
ipv6_from_address(_addr.bytes, host);
_port = port;
} else {
// DNS lookup
int err = iface->gethostbyname(this, host);
if (err) {
_addr = (nsapi_addr_t){};
_port = 0;
}
}
}

View File

@ -0,0 +1,149 @@
/* SocketAddress
* 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 "nsapi_types.h"
#include "toolchain.h"
// Predeclared classes
class NetworkStack;
class NetworkInterface;
/** SocketAddress class
*
* Representation of an IP address and port pair.
*/
class SocketAddress {
public:
/** Create a SocketAddress from a hostname and port
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* On failure, the IP address and port will be set to zero
*
* @param stack Network stack to use for DNS resolution
* @param host Hostname to resolve
* @param port Optional 16-bit port
*/
template <typename S>
SocketAddress(S *stack, const char *host, uint16_t port = 0)
{
_SocketAddress(nsapi_create_stack(stack), host, port);
}
/** Create a SocketAddress from a raw IP address and port
*
* @param addr Raw IP address
* @param port Optional 16-bit port
*/
SocketAddress(nsapi_addr_t addr = (nsapi_addr_t){}, uint16_t port = 0);
/** Create a SocketAddress from an IP address and port
*
* @param host Null-terminated representation of the IP address
* @param port Optional 16-bit port
*/
SocketAddress(const char *addr, uint16_t port = 0);
/** Create a SocketAddress from raw IP bytes, IP version, and port
*
* @param bytes Raw IP address in big-endian order
* @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6
* @param port Optional 16-bit port
*/
SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port = 0);
/** Create a SocketAddress from another SocketAddress
*
* @param address SocketAddress to copy
*/
SocketAddress(const SocketAddress &addr);
/** Set the IP address
*
* @param addr Null-terminated represention of the IP address
*/
void set_ip_address(const char *addr);
/** Set the raw IP bytes and IP version
*
* @param bytes Raw IP address in big-endian order
* @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6
*/
void set_ip_bytes(const void *bytes, nsapi_version_t version);
/** Set the raw IP address
*
* @param addr Raw IP address
*/
void set_addr(nsapi_addr_t addr);
/** Set the port
*
* @param port 16-bit port
*/
void set_port(uint16_t port);
/** Get the IP address
*
* @return Null-terminated representation of the IP Address
*/
const char *get_ip_address() const;
/* Get the raw IP bytes
*
* @return Raw IP address in big-endian order
*/
const void *get_ip_bytes() const;
/** Get the IP address version
*
* @return IP address version, NSAPI_IPv4 or NSAPI_IPv6
*/
nsapi_version_t get_ip_version() const;
/** Get the raw IP address
*
* @return Raw IP address
*/
nsapi_addr_t get_addr() const;
/** Get the port
*
* @return The 16-bit port
*/
uint16_t get_port() const;
/** Test if address is zero
*
* @return True if address is not zero
*/
operator bool() const;
private:
void _SocketAddress(NetworkStack *iface, const char *host, uint16_t port);
char _ip_address[NSAPI_IP_SIZE];
nsapi_addr_t _addr;
uint16_t _port;
};
#endif

View File

@ -0,0 +1,110 @@
/* 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()
: _pending(0), _accept_sem(0)
{
}
TCPServer::~TCPServer()
{
close();
}
nsapi_protocol_t TCPServer::get_proto()
{
return NSAPI_TCP;
}
int TCPServer::listen(int backlog)
{
_lock.lock();
int ret;
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
} else {
ret = _stack->socket_listen(_socket, backlog);
}
_lock.unlock();
return ret;
}
int TCPServer::accept(TCPSocket *connection)
{
_lock.lock();
int ret;
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
break;
}
_pending = 0;
void *socket;
ret = _stack->socket_accept(&socket, _socket);
if (0 == ret) {
connection->_lock.lock();
if (connection->_socket) {
connection->close();
}
connection->_stack = _stack;
connection->_socket = socket;
connection->_event = Callback<void()>(connection, &TCPSocket::event);
_stack->socket_attach(socket, &Callback<void()>::thunk, &connection->_event);
connection->_lock.unlock();
break;
}
if (NSAPI_ERROR_WOULD_BLOCK == ret) {
int32_t count;
_lock.unlock();
count = _accept_sem.wait(_timeout);
_lock.lock();
if (count < 1) {
ret = NSAPI_ERROR_WOULD_BLOCK;
break;
}
}
}
_lock.unlock();
return ret;
}
void TCPServer::event()
{
int32_t acount = _accept_sem.wait(0);
if (acount <= 1) {
_accept_sem.release();
}
_pending += 1;
if (_callback && _pending == 1) {
_callback();
}
}

View File

@ -0,0 +1,94 @@
/* TCPServer
* 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 "network-socket/Socket.h"
#include "network-socket/TCPSocket.h"
#include "network-socket/NetworkStack.h"
#include "network-socket/NetworkInterface.h"
#include "rtos/Semaphore.h"
/** TCP socket server
*/
class TCPServer : public Socket {
public:
/** Create an uninitialized socket
*
* Must call open to initialize the socket on a network stack.
*/
TCPServer();
/** Create a socket on a network interface
*
* Creates and opens a socket on the network stack of the given
* network interface.
*
* @param stack Network stack as target for socket
*/
TCPServer(NetworkStack *stack);
template <typename IF>
TCPServer(IF *iface)
: _pending(0), _accept_sem(0)
{
open(iface->get_stack());
}
/** Destroy a socket
*
* Closes socket if the socket is still open
*/
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
*/
int listen(int backlog = 1);
/** Accepts a connection on a TCP socket
*
* The server socket must be bound and set to listen for connections.
* On a new connection, creates a network socket using the specified
* socket instance.
*
* By default, accept blocks until data is sent. If socket is set to
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
* immediately.
*
* @param socket TCPSocket instance that will handle the incoming connection.
* @return 0 on success, negative error code on failure
*/
int accept(TCPSocket *connection);
protected:
virtual nsapi_protocol_t get_proto();
virtual void event();
volatile unsigned _pending;
rtos::Semaphore _accept_sem;
};
#endif

View File

@ -0,0 +1,166 @@
/* 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"
#include "mbed_assert.h"
TCPSocket::TCPSocket()
: _pending(0), _read_sem(0), _write_sem(0),
_read_in_progress(false), _write_in_progress(false)
{
}
TCPSocket::~TCPSocket()
{
close();
}
nsapi_protocol_t TCPSocket::get_proto()
{
return NSAPI_TCP;
}
int TCPSocket::connect(const SocketAddress &address)
{
_lock.lock();
int ret;
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
} else {
ret = _stack->socket_connect(_socket, address);
}
_lock.unlock();
return ret;
}
int TCPSocket::connect(const char *host, uint16_t port)
{
SocketAddress address(_stack, host, port);
if (!address) {
return NSAPI_ERROR_DNS_FAILURE;
}
// connect is thread safe
return connect(address);
}
int TCPSocket::send(const void *data, unsigned size)
{
_lock.lock();
int ret;
// 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;
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
break;
}
_pending = 0;
int sent = _stack->socket_send(_socket, data, size);
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != sent)) {
ret = sent;
break;
} else {
int32_t count;
// Release lock before blocking so other threads
// accessing this object aren't blocked
_lock.unlock();
count = _write_sem.wait(_timeout);
_lock.lock();
if (count < 1) {
// Semaphore wait timed out so break out and return
ret = NSAPI_ERROR_WOULD_BLOCK;
break;
}
}
}
_write_in_progress = false;
_lock.unlock();
return ret;
}
int TCPSocket::recv(void *data, unsigned size)
{
_lock.lock();
int ret;
// 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;
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
break;
}
_pending = 0;
int recv = _stack->socket_recv(_socket, data, size);
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) {
ret = recv;
break;
} else {
int32_t count;
// Release lock before blocking so other threads
// accessing this object aren't blocked
_lock.unlock();
count = _read_sem.wait(_timeout);
_lock.lock();
if (count < 1) {
// Semaphore wait timed out so break out and return
ret = NSAPI_ERROR_WOULD_BLOCK;
break;
}
}
}
_read_in_progress = false;
_lock.unlock();
return ret;
}
void TCPSocket::event()
{
int32_t wcount = _write_sem.wait(0);
if (wcount <= 1) {
_write_sem.release();
}
int32_t rcount = _read_sem.wait(0);
if (rcount <= 1) {
_read_sem.release();
}
_pending += 1;
if (_callback && _pending == 1) {
_callback();
}
}

View File

@ -0,0 +1,124 @@
/* TCPSocket
* 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 TCPSOCKET_H
#define TCPSOCKET_H
#include "network-socket/Socket.h"
#include "network-socket/NetworkStack.h"
#include "network-socket/NetworkInterface.h"
#include "rtos/Semaphore.h"
/** TCP socket connection
*/
class TCPSocket : public Socket {
public:
/** Create an uninitialized socket
*
* Must call open to initialize the socket on a network stack.
*/
TCPSocket();
/** Create a socket on a network interface
*
* Creates and opens a socket on the network stack of the given
* network interface.
*
* @param stack Network stack as target for socket
*/
template <typename S>
TCPSocket(S *stack)
: _pending(0), _read_sem(0), _write_sem(0),
_read_in_progress(false), _write_in_progress(false)
{
open(stack);
}
/** Destroy a socket
*
* Closes socket if the socket is still open
*/
virtual ~TCPSocket();
/** Connects TCP socket to a remote host
*
* Initiates a connection to a remote server specified by either
* a domain name or an IP address and a port.
*
* @param host Hostname of the remote host
* @param port Port of the remote host
* @return 0 on success, negative error code on failure
*/
int connect(const char *host, uint16_t port);
/** Connects TCP socket to a remote host
*
* Initiates a connection to a remote server specified by the
* indicated address.
*
* @param address The SocketAddress of the remote host
* @return 0 on success, negative error code on failure
*/
int connect(const SocketAddress &address);
/** Send data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes sent from the buffer.
*
* By default, send blocks until data is sent. If socket is set to
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
* immediately.
*
* @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
*/
int send(const void *data, unsigned size);
/** Receive data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes received into the buffer.
*
* By default, recv blocks until data is sent. If socket is set to
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
* immediately.
*
* @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
*/
int recv(void *data, unsigned size);
protected:
friend class TCPServer;
virtual nsapi_protocol_t get_proto();
virtual void event();
volatile unsigned _pending;
rtos::Semaphore _read_sem;
rtos::Semaphore _write_sem;
bool _read_in_progress;
bool _write_in_progress;
};
#endif

View File

@ -0,0 +1,151 @@
/* 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"
#include "mbed_assert.h"
UDPSocket::UDPSocket()
: _pending(0), _read_sem(0), _write_sem(0),
_read_in_progress(false), _write_in_progress(false)
{
}
UDPSocket::~UDPSocket()
{
close();
}
nsapi_protocol_t UDPSocket::get_proto()
{
return NSAPI_UDP;
}
int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigned size)
{
SocketAddress address(_stack, host, port);
if (!address) {
return NSAPI_ERROR_DNS_FAILURE;
}
// sendto is thread safe
return sendto(address, data, size);
}
int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size)
{
_lock.lock();
int ret;
// 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;
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
break;
}
_pending = 0;
int sent = _stack->socket_sendto(_socket, address, data, size);
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != sent)) {
ret = sent;
break;
} else {
int32_t count;
// Release lock before blocking so other threads
// accessing this object aren't blocked
_lock.unlock();
count = _write_sem.wait(_timeout);
_lock.lock();
if (count < 1) {
// Semaphore wait timed out so break out and return
ret = NSAPI_ERROR_WOULD_BLOCK;
break;
}
}
}
_write_in_progress = false;
_lock.unlock();
return ret;
}
int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size)
{
_lock.lock();
int ret;
// 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;
while (true) {
if (!_socket) {
ret = NSAPI_ERROR_NO_SOCKET;
break;
}
_pending = 0;
int recv = _stack->socket_recvfrom(_socket, address, buffer, size);
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) {
ret = recv;
break;
} else {
int32_t count;
// Release lock before blocking so other threads
// accessing this object aren't blocked
_lock.unlock();
count = _read_sem.wait(_timeout);
_lock.lock();
if (count < 1) {
// Semaphore wait timed out so break out and return
ret = NSAPI_ERROR_WOULD_BLOCK;
break;
}
}
}
_read_in_progress = false;
_lock.unlock();
return ret;
}
void UDPSocket::event()
{
int32_t wcount = _write_sem.wait(0);
if (wcount <= 1) {
_write_sem.release();
}
int32_t rcount = _read_sem.wait(0);
if (rcount <= 1) {
_read_sem.release();
}
_pending += 1;
if (_callback && _pending == 1) {
_callback();
}
}

View File

@ -0,0 +1,122 @@
/* UDPSocket
* 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 UDPSOCKET_H
#define UDPSOCKET_H
#include "network-socket/Socket.h"
#include "network-socket/NetworkStack.h"
#include "network-socket/NetworkInterface.h"
#include "rtos/Semaphore.h"
/** UDP socket
*/
class UDPSocket : public Socket {
public:
/** Create an uninitialized socket
*
* Must call open to initialize the socket on a network stack.
*/
UDPSocket();
/** Create a socket on a network interface
*
* Creates and opens a socket on the network stack of the given
* network interface.
*
* @param stack Network stack as target for socket
*/
template <typename S>
UDPSocket(S *stack)
: _pending(0), _read_sem(0), _write_sem(0),
_read_in_progress(false), _write_in_progress(false)
{
open(stack);
}
/** Destroy a socket
*
* Closes socket if the socket is still open
*/
virtual ~UDPSocket();
/** Send a packet over a UDP socket
*
* Sends data to the specified address specified by either a domain name
* or an IP address and port. Returns the number of bytes sent from the
* buffer.
*
* 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 host Hostname of the remote host
* @param port Port of the remote host
* @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
*/
int sendto(const char *host, uint16_t port, const void *data, unsigned size);
/** Send a packet over a UDP socket
*
* Sends data to the specified address. Returns the number of bytes
* sent from the buffer.
*
* 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 The SocketAddress of the remote host
* @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
*/
int sendto(const SocketAddress &address, const void *data, unsigned size);
/** Receive a packet over a UDP socket
*
* Receives data and stores the source address in address if address
* is not NULL. Returns the number of bytes received into the buffer.
*
* By default, recvfrom blocks until data is sent. If socket is set to
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
* immediately.
*
* @param address Destination for the source address or NULL
* @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
*/
int recvfrom(SocketAddress *address, void *data, unsigned size);
protected:
virtual nsapi_protocol_t get_proto();
virtual void event();
volatile unsigned _pending;
rtos::Semaphore _read_sem;
rtos::Semaphore _write_sem;
bool _read_in_progress;
bool _write_in_progress;
};
#endif

View File

@ -0,0 +1,70 @@
/* WiFiInterface
* 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 WIFI_INTERFACE_H
#define WIFI_INTERFACE_H
#include "network-socket/NetworkInterface.h"
/** Enum of WiFi encryption types
*
* The security type specifies a particular security to use when
* connected to a WiFi network
*
* @enum nsapi_protocol_t
*/
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
*/
class WiFiInterface: public NetworkInterface
{
public:
/** Start the interface
*
* Attempts to connect to a WiFi network. If passphrase is invalid,
* NSAPI_ERROR_AUTH_ERROR is returned.
*
* @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 error code on failure
*/
virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE) = 0;
/** Stop the interface
*
* @return 0 on success, negative error code on failure
*/
virtual int disconnect() = 0;
/** Get the local MAC address
*
* @return Null-terminated representation of the local MAC address
*/
virtual const char *get_mac_address() = 0;
};
#endif

View File

@ -0,0 +1,47 @@
/* nsapi.h - The network socket API
* 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 NSAPI_H
#define NSAPI_H
// entry point for nsapi types
#include "nsapi_types.h"
// disable bug-compatible mbed inclusion
#define NSAPI_NO_INCLUDE_MBED
#ifdef __cplusplus
// entry point for C++ api
#include "network-socket/SocketAddress.h"
#include "network-socket/NetworkStack.h"
#include "network-socket/NetworkInterface.h"
#include "network-socket/EthInterface.h"
#include "network-socket/WiFiInterface.h"
#include "network-socket/CellularInterface.h"
#include "network-socket/MeshInterface.h"
#include "network-socket/Socket.h"
#include "network-socket/UDPSocket.h"
#include "network-socket/TCPSocket.h"
#include "network-socket/TCPServer.h"
#endif
#endif

View File

@ -0,0 +1,445 @@
/* nsapi.h - The network socket API
* 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 NSAPI_TYPES_H
#define NSAPI_TYPES_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Enum of standardized error codes
*
* Valid error codes have negative values and may
* be returned by any network operation.
*
* @enum nsapi_error_t
*/
typedef enum nsapi_error {
NSAPI_ERROR_WOULD_BLOCK = -3001, /*!< no data is not available but call is non-blocking */
NSAPI_ERROR_UNSUPPORTED = -3002, /*!< unsupported functionality */
NSAPI_ERROR_PARAMETER = -3003, /*!< invalid configuration */
NSAPI_ERROR_NO_CONNECTION = -3004, /*!< not connected to a network */
NSAPI_ERROR_NO_SOCKET = -3005, /*!< socket not available for use */
NSAPI_ERROR_NO_ADDRESS = -3006, /*!< IP address is not known */
NSAPI_ERROR_NO_MEMORY = -3007, /*!< memory resource not available */
NSAPI_ERROR_DNS_FAILURE = -3008, /*!< DNS failed to complete successfully */
NSAPI_ERROR_DHCP_FAILURE = -3009, /*!< DHCP failed to complete successfully */
NSAPI_ERROR_AUTH_FAILURE = -3010, /*!< connection to access point faield */
NSAPI_ERROR_DEVICE_ERROR = -3011, /*!< failure interfacing with the network procesor */
} nsapi_error_t;
/** Maximum size of IP address representation
*/
#define NSAPI_IP_SIZE NSAPI_IPv6_SIZE
/** Maximum number of bytes for IP address
*/
#define NSAPI_IP_BYTES NSAPI_IPv6_BYTES
/** Maximum size of MAC address representation
*/
#define NSAPI_MAC_SIZE 18
/** Maximum number of bytes for MAC address
*/
#define NSAPI_MAC_BYTES 6
/** Size of IPv4 representation
*/
#define NSAPI_IPv4_SIZE 16
/** Number of bytes in IPv4 address
*/
#define NSAPI_IPv4_BYTES 4
/** Size of IPv6 representation
*/
#define NSAPI_IPv6_SIZE 40
/** Number of bytes in IPv6 address
*/
#define NSAPI_IPv6_BYTES 16
/** Enum of IP address versions
*
* The IP version specifies the type of an IP address.
*
* @enum nsapi_version_t
*/
typedef enum nsapi_version {
NSAPI_IPv4, /*!< Address is IPv4 */
NSAPI_IPv6, /*!< Address is IPv6 */
} nsapi_version_t;
/** IP address structure for passing IP addresses by value
*/
typedef struct nsapi_addr {
/** IP version
* NSAPI_IPv4 or NSAPI_IPv6
*/
nsapi_version_t version;
/** IP address
* The raw bytes of the IP address stored in big-endian format
*/
uint8_t bytes[NSAPI_IP_BYTES];
} nsapi_addr_t;
/** Opaque handle for network sockets
*/
typedef void *nsapi_socket_t;
/** Enum of socket protocols
*
* The socket protocol specifies a particular protocol to
* be used with a newly created socket.
*
* @enum nsapi_protocol_t
*/
typedef enum nsapi_protocol {
NSAPI_TCP, /*!< Socket is of TCP type */
NSAPI_UDP, /*!< Socket is of UDP type */
} nsapi_protocol_t;
/* Enum of standardized stack option levels
*
* @enum nsapi_level_t
*/
typedef enum nsapi_level {
NSAPI_STACK, /*!< Stack option level */
NSAPI_SOCKET, /*!< Socket option level */
} nsapi_level_t;
/* Enum of standardized stack options
*
* These options may not be supported on all stacks, in which
* case NSAPI_ERROR_UNSUPPORTED may be returned from setsockopt.
*
* @enum nsapi_option_t
*/
typedef enum nsapi_option {
NSAPI_REUSEADDR, /*!< Allow bind to reuse local addresses */
NSAPI_KEEPALIVE, /*!< Enables sending of keepalive messages */
NSAPI_KEEPIDLE, /*!< Sets timeout value to initiate keepalive */
NSAPI_KEEPINTVL, /*!< Sets timeout value for keepalive */
NSAPI_LINGER, /*!< Keeps close from returning until queues empty */
NSAPI_SNDBUF, /*!< Sets send buffer size */
NSAPI_RCVBUF, /*!< Sets recv buffer size */
} nsapi_option_t;
/** nsapi_stack structure
*
* Stack structure representing a specific instance of a stack.
*/
typedef struct nsapi_stack {
/** Network stack operation table
*
* Provides access to the underlying api of the stack. This is not
* flattened into the nsapi_stack to allow allocation in read-only
* memory.
*/
const struct nsapi_stack_api *stack_api;
/** Opaque handle for network stacks
*/
void *stack;
// Internal nsapi buffer
unsigned _stack_buffer[16];
} nsapi_stack_t;
/** nsapi_stack_api structure
*
* Common api structure for network stack operations. A network stack
* can provide a nsapi_stack_api structure filled out with the
* appropriate implementation.
*
* Unsupported operations can be left as null pointers.
*/
typedef struct nsapi_stack_api
{
/** Get the local IP address
*
* @param stack Stack handle
* @return Local IP Address or null address if not connected
*/
nsapi_addr_t (*get_ip_address)(nsapi_stack_t *stack);
/** Translates a hostname to an IP address
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* If no stack-specific DNS resolution is provided, the hostname
* will be resolve using a UDP socket on the stack.
*
* @param stack Stack handle
* @param addr Destination for the host IP address
* @param host Hostname to resolve
* @return 0 on success, negative error code on failure
*/
int (*gethostbyname)(nsapi_stack_t *stack, nsapi_addr_t *addr, const char *host);
/* Set stack-specific stack options
*
* The setstackopt allow an application to pass stack-specific hints
* to the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and the stack is unmodified.
*
* @param stack Stack handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
int (*setstackopt)(nsapi_stack_t *stack, int level, int optname, const void *optval, unsigned optlen);
/* Get stack-specific stack options
*
* The getstackopt allow an application to retrieve stack-specific hints
* from the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
*
* @param stack Stack handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Destination for option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
int (*getstackopt)(nsapi_stack_t *stack, int level, int optname, void *optval, unsigned *optlen);
/** Opens a socket
*
* Creates a network socket and stores it in the specified handle.
* The handle must be passed to following calls on the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* @param stack Stack context
* @param socket Destination for the handle to a newly created socket
* @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP
* @return 0 on success, negative error code on failure
*/
int (*socket_open)(nsapi_stack_t *stack, nsapi_socket_t *socket, nsapi_protocol_t proto);
/** Close the socket
*
* Closes any open connection and deallocates any memory associated
* with the socket.
*
* @param stack Stack handle
* @param socket Socket handle
* @return 0 on success, negative error code on failure
*/
int (*socket_close)(nsapi_stack_t *stack, nsapi_socket_t socket);
/** Bind a specific address to a socket
*
* Binding a socket specifies the address and port on which to recieve
* data. If the IP address is zeroed, only the port is bound.
*
* @param stack Stack handle
* @param socket Socket handle
* @param addr Local address to bind, may be null
* @param port Local port to bind
* @return 0 on success, negative error code on failure.
*/
int (*socket_bind)(nsapi_stack_t *stack, nsapi_socket_t socket, nsapi_addr_t addr, uint16_t port);
/** Listen for connections on a TCP socket
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param stack Stack handle
* @param socket Socket handle
* @param backlog Number of pending connections that can be queued
* simultaneously
* @return 0 on success, negative error code on failure
*/
int (*socket_listen)(nsapi_stack_t *stack, nsapi_socket_t socket, int backlog);
/** Connects TCP socket to a remote host
*
* Initiates a connection to a remote server specified by the
* indicated address.
*
* @param stack Stack handle
* @param socket Socket handle
* @param addr The address of the remote host
* @param port The port of the remote host
* @return 0 on success, negative error code on failure
*/
int (*socket_connect)(nsapi_stack_t *stack, nsapi_socket_t socket, nsapi_addr_t addr, uint16_t port);
/** Accepts a connection on a TCP socket
*
* The server socket must be bound and set to listen for connections.
* On a new connection, creates a network socket and stores it in the
* specified handle. The handle must be passed to following calls on
* the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* This call is non-blocking. If accept would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param stack Stack handle
* @param socket Destination for a handle to the newly created sockey
* @param server Socket handle to server to accept from
* @return 0 on success, negative error code on failure
*/
int (*socket_accept)(nsapi_stack_t *stack, nsapi_socket_t *socket, nsapi_socket_t server);
/** Send data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes sent from the buffer.
*
* This call is non-blocking. If send would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param stack Stack handle
* @param socket Socket handle
* @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
*/
int (*socket_send)(nsapi_stack_t *stack, nsapi_socket_t socket, const void *data, unsigned size);
/** Receive data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes received into the buffer.
*
* This call is non-blocking. If recv would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param stack Stack handle
* @param socket Socket handle
* @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
*/
int (*socket_recv)(nsapi_stack_t *stack, nsapi_socket_t socket, void *data, unsigned size);
/** Send a packet over a UDP socket
*
* Sends data to the specified address. Returns the number of bytes
* sent from the buffer.
*
* This call is non-blocking. If sendto would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param stack Stack handle
* @param socket Socket handle
* @param addr The address of the remote host
* @param port The port of the remote host
* @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
*/
int (*socket_sendto)(nsapi_stack_t *stack, nsapi_socket_t socket, nsapi_addr_t addr, uint16_t port, const void *data, unsigned size);
/** Receive a packet over a UDP socket
*
* Receives data and stores the source address in address if address
* is not NULL. Returns the number of bytes received into the buffer.
*
* This call is non-blocking. If recvfrom would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param stack Stack handle
* @param socket Socket handle
* @param addr Destination for the address of the remote host
* @param port Destination for the port of the remote host
* @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
*/
int (*socket_recvfrom)(nsapi_stack_t *stack, nsapi_socket_t socket, nsapi_addr_t *addr, uint16_t *port, void *buffer, unsigned size);
/** 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.
*
* @param stack Stack handle
* @param socket Socket handle
* @param callback Function to call on state change
* @param data Argument to pass to callback
*/
void (*socket_attach)(nsapi_stack_t *stack, nsapi_socket_t socket, void (*callback)(void *), void *data);
/* Set stack-specific socket options
*
* The setsockopt allow an application to pass stack-specific hints
* to the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
*
* @param stack Stack handle
* @param socket Socket handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
int (*setsockopt)(nsapi_stack_t *stack, nsapi_socket_t socket, int level, int optname, const void *optval, unsigned optlen);
/* Get stack-specific socket options
*
* The getstackopt allow an application to retrieve stack-specific hints
* from the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
*
* @param stack Stack handle
* @param socket Socket handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Destination for option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
int (*getsockopt)(nsapi_stack_t *stack, nsapi_socket_t socket, int level, int optname, void *optval, unsigned *optlen);
} nsapi_stack_api_t;
#ifdef __cplusplus
}
#endif
#endif