NetworkSocketAPI


NetworkSocketAPI is a simple yet powerful network and socket interface

Porting Guide

New Device

The NetworkSocketAPI is designed to make porting new devices as easy as possible and only requires a handful of methods for a minimal implementation.

A new device must implement a NetworkStack with the naming convention of DeviceInterface where Device is a unique name that represents the device or network processor. The DeviceInterface should inherit one additional of the following unless it is an abstract device: The currently defined subclasses are:

/media/uploads/sam_grove/class_l_w_i_p_interface__inherit__graph.png

The DeviceStack implementation provides the following methods:

/** Get the local IP address
 *
 *  @return         Null-terminated representation of the local IP address
 *                  or null if not yet connected
 */
const char *get_ip_address();

/** Get the local MAC address
 *
 *  @return         Null-terminated representation of the local MAC address
 */
const char *get_mac_address();

/** 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
 */
int socket_open(void **handle, nsapi_protocol_t proto);

/** 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
 */
int socket_close(void *handle);

/** Bind a specific address to a socket
 *
 *  Binding a socket specifies the address and port on which to receive
 *  data. If the IP address is zeroed, only the port is bound.
 *
 *  @param handle   Socket handle
 *  @param address  Local address to bind
 *  @return         0 on success, negative error code on failure.
 */
int socket_bind(void *handle, const SocketAddress &address);

/** 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
 */
int socket_listen(void *handle, int backlog);

/** 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
 */
int socket_connect(void *handle, const SocketAddress &address);

/** 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 socket
 *  @param server   Socket handle to server to accept from
 *  @return         0 on success, negative error code on failure
 */
int socket_accept(void **handle, void *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 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
 */
int socket_send(void *handle, 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 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
 */
int socket_recv(void *handle, 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 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
 */
int socket_sendto(void *handle, 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.
 *
 *  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
 */
int socket_recvfrom(void *handle, SocketAddress *address, 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 handle   Socket handle
 *  @param callback Function to call on state change
 *  @param data     Argument to pass to callback
 */
void socket_attach(void *handle, void (*callback)(void *), void *data);



Sockets

As a part of implementing the NetworkStack interface, a new device must implement a series of socket_ functions. A void * is provided to pass socket-specific context between these functions. The socket functions are managed by the Socket classes and implementation functions are hidden from the user.



Errors

The convention for the NetworkSocketAPI is to have functions that may fail and return a signed integer. To indicate success, the function should return a non-negative integer which may also contain the size of a transaction. To indicate failure the function should return a negative integer which should be one of the following error codes from the nsapi_error_t enum:

/** Enum of standardized error codes 
 *
 *  Valid error codes have negative values and may
 *  be returned by any network operation.
 *
 *  @enum nsapi_error_t
 */
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 failed */
    NSAPI_ERROR_DEVICE_ERROR  = -3010,     /*!< failure interfacing with the network processor */
};



Testing

When adding new device support there is a test harness that can be used to verify implementations. The test program is very simple since it only needs to instantiate the new network interface and all further operations are performed against the managed classes.

Import program

00001 /* NetworkSocketAPI Example Program
00002  * Copyright (c) 2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "mbed.h"
00018 #include "ESP8266Interface.h"
00019 #include "NSAPITests.h"
00020 
00021 ESP8266Interface iface(D1, D0);
00022 
00023 int main()
00024 {
00025     int32_t result = iface.connect("ssid", "password");
00026 
00027     if (result) {
00028         printf("Interface failed to connect with code %d\r\n", result);
00029     } else {
00030         nsapi_tests("ESP8266Interface Tests", &iface, "0.0.0.0", 4000);
00031         iface.disconnect();
00032     }
00033     while(1);
00034 }


// replace 0.0.0.0 with the ip address of the host pc running the echo_server.py script
nsapi_tests("ESP8266Interface Tests", &iface, "0.0.0.0", 4000);


The test harness library is NSAPITests. It relies on a python echo server which is also part of that repo. Make sure to change the IP address in the interface test program to point at the computer that is running the script.

Import libraryNSAPITests

Tests for the NetworkSocketAPI



References

Import libraryESP8266Interface

Socket interface for ESP8266. Implements the NetworkSocketAPI


Import libraryLWIPInterface

Implementation of the NetworkSocketAPI for LWIP


All wikipages