mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #88 from geky/nsapi-changes
Update Network Socket API
commit
b7cdc204fd
|
@ -84,7 +84,7 @@ struct esp8266_socket {
|
|||
bool connected;
|
||||
};
|
||||
|
||||
void *ESP8266Interface::socket_create(nsapi_protocol_t proto)
|
||||
int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto)
|
||||
{
|
||||
// Look for an unused socket
|
||||
int id = -1;
|
||||
|
@ -98,38 +98,37 @@ void *ESP8266Interface::socket_create(nsapi_protocol_t proto)
|
|||
}
|
||||
|
||||
if (id == -1) {
|
||||
return 0;
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
struct esp8266_socket *socket = new struct esp8266_socket;
|
||||
if (!socket) {
|
||||
return 0;
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
socket->id = id;
|
||||
socket->proto = proto;
|
||||
socket->connected = false;
|
||||
return socket;
|
||||
*handle = socket;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ESP8266Interface::socket_destroy(void *handle)
|
||||
int ESP8266Interface::socket_close(void *handle)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
int err = 0;
|
||||
_esp.setTimeout(ESP8266_MISC_TIMEOUT);
|
||||
|
||||
if (!_esp.close(socket->id)) {
|
||||
err = NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
_ids[socket->id] = false;
|
||||
delete socket;
|
||||
return err;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_set_option(void *handle, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_get_option(void *handle, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_bind(void *handle, int port)
|
||||
int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
@ -153,12 +152,7 @@ int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool ESP8266Interface::socket_is_connected(void *handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_accept(void *handle, void **connection)
|
||||
int ESP8266Interface::socket_accept(void **handle, void *server)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
@ -207,26 +201,6 @@ int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *d
|
|||
return socket_recv(socket, data, size);
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_close(void *handle, bool shutdown)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
_esp.setTimeout(ESP8266_MISC_TIMEOUT);
|
||||
|
||||
if (!_esp.close(socket->id)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ESP8266Interface::socket_attach_accept(void *handle, void (*callback)(void *), void *id)
|
||||
{
|
||||
}
|
||||
|
||||
void ESP8266Interface::socket_attach_send(void *handle, void (*callback)(void *), void *id)
|
||||
{
|
||||
}
|
||||
|
||||
void ESP8266Interface::socket_attach_recv(void *handle, void (*callback)(void *), void *id)
|
||||
void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), void *data)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -23,184 +23,146 @@
|
|||
#define ESP8266_SOCKET_COUNT 5
|
||||
|
||||
/** ESP8266Interface class
|
||||
* Implementation of the NetworkInterface for the ESP8266
|
||||
* Implementation of the NetworkStack for the ESP8266
|
||||
*/
|
||||
class ESP8266Interface : public WiFiInterface
|
||||
class ESP8266Interface : public NetworkStack, public WiFiInterface
|
||||
{
|
||||
public:
|
||||
/** ESP8266Interface lifetime
|
||||
/param tx TX pin
|
||||
/param rx RX pin
|
||||
/param debug Enable debugging
|
||||
*/
|
||||
* @param tx TX pin
|
||||
* @param rx RX pin
|
||||
* @param debug Enable debugging
|
||||
*/
|
||||
ESP8266Interface(PinName tx, PinName rx, bool debug = false);
|
||||
|
||||
/** Start the interface
|
||||
/param ssid Name of the network to connect to
|
||||
/param pass Security passphrase to connect to the network
|
||||
/param security Type of encryption for connection
|
||||
/return 0 on success, negative on failure
|
||||
*/
|
||||
*
|
||||
* 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);
|
||||
|
||||
/** Stop the interface
|
||||
* @return 0 on success, negative on failure
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int disconnect();
|
||||
|
||||
/** Get the internally stored IP address
|
||||
/return IP address of the interface or null if not yet connected
|
||||
*/
|
||||
* @return IP address of the interface or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address();
|
||||
|
||||
/** Get the internally stored MAC address
|
||||
/return MAC address of the interface
|
||||
*/
|
||||
* @return MAC address of the interface
|
||||
*/
|
||||
virtual const char *get_mac_address();
|
||||
|
||||
protected:
|
||||
/** Create a socket
|
||||
/param proto The type of socket to open, TCP or UDP
|
||||
/return The alocated socket or null on failure
|
||||
*/
|
||||
virtual void *socket_create(nsapi_protocol_t proto);
|
||||
/** Open a socket
|
||||
* @param handle Handle in which to store new socket
|
||||
* @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_open(void **handle, nsapi_protocol_t proto);
|
||||
|
||||
/** Destroy a socket
|
||||
/param socket Previously allocated socket
|
||||
*/
|
||||
virtual void socket_destroy(void *handle);
|
||||
|
||||
/** Set socket options
|
||||
\param handle Socket handle
|
||||
\param optname Option ID
|
||||
\param optval Option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_set_option(void *handle, int optname, const void *optval, unsigned int optlen);
|
||||
|
||||
/** Get socket options
|
||||
\param handle Socket handle
|
||||
\param optname Option ID
|
||||
\param optval Buffer pointer where to write the option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen);
|
||||
/** Close the socket
|
||||
* @param handle Socket handle
|
||||
* @return 0 on success, negative on failure
|
||||
* @note On failure, any memory associated with the socket must still
|
||||
* be cleaned up
|
||||
*/
|
||||
virtual int socket_close(void *handle);
|
||||
|
||||
/** Bind a server socket to a specific port
|
||||
\param handle Socket handle
|
||||
\param port The port to listen for incoming connections on
|
||||
\return 0 on success, negative on failure.
|
||||
*/
|
||||
virtual int socket_bind(void *handle, int port);
|
||||
* @param handle Socket handle
|
||||
* @param address Local address to listen for incoming connections on
|
||||
* @return 0 on success, negative on failure.
|
||||
*/
|
||||
virtual int socket_bind(void *handle, const SocketAddress &address);
|
||||
|
||||
/** Start listening for incoming connections
|
||||
\param handle Socket handle
|
||||
\param backlog Number of pending connections that can be queued up at any
|
||||
one time [Default: 1]
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param backlog Number of pending connections that can be queued up at any
|
||||
* one time [Default: 1]
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_listen(void *handle, int backlog);
|
||||
|
||||
/** Connects this TCP socket to the server
|
||||
\param handle Socket handle
|
||||
\param address SocketAddress to connect to
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param address SocketAddress to connect to
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_connect(void *handle, const SocketAddress &address);
|
||||
|
||||
/** Check if the socket is connected
|
||||
\param handle Socket handle
|
||||
\return true if connected, false otherwise
|
||||
*/
|
||||
virtual bool socket_is_connected(void *handle);
|
||||
|
||||
/** Accept a new connection.
|
||||
\param handle Socket handle
|
||||
\param socket A TCPSocket instance that will handle the incoming connection.
|
||||
\return 0 on success, negative on failure.
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_accept(void *handle, void **connection);
|
||||
* @param handle Handle in which to store new socket
|
||||
* @param server Socket handle to server to accept from
|
||||
* @return 0 on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_accept(void **handle, void *server);
|
||||
|
||||
/** Send data to the remote host
|
||||
\param handle Socket handle
|
||||
\param data The buffer to send to the host
|
||||
\param size The length of the buffer to send
|
||||
\return Number of written bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param data The buffer to send to the host
|
||||
* @param size The length of the buffer to send
|
||||
* @return Number of written bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_send(void *handle, const void *data, unsigned size);
|
||||
|
||||
/** Receive data from the remote host
|
||||
\param handle Socket handle
|
||||
\param data The buffer in which to store the data received from the host
|
||||
\param size The maximum length of the buffer
|
||||
\return Number of received bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param data The buffer in which to store the data received from the host
|
||||
* @param size The maximum length of the buffer
|
||||
* @return Number of received bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recv(void *handle, void *data, unsigned size);
|
||||
|
||||
/** Send a packet to a remote endpoint
|
||||
\param handle Socket handle
|
||||
\param address The remote SocketAddress
|
||||
\param data The packet to be sent
|
||||
\param size The length of the packet to be sent
|
||||
\return the number of written bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param address The remote SocketAddress
|
||||
* @param data The packet to be sent
|
||||
* @param size The length of the packet to be sent
|
||||
* @return The number of written bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size);
|
||||
|
||||
/** Receive a packet from a remote endpoint
|
||||
\param handle Socket handle
|
||||
\param address Destination for the remote SocketAddress or null
|
||||
\param buffer The buffer for storing the incoming packet data
|
||||
If a packet is too long to fit in the supplied buffer,
|
||||
excess bytes are discarded
|
||||
\param size The length of the buffer
|
||||
\return the number of received bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param address Destination for the remote SocketAddress or null
|
||||
* @param buffer The buffer for storing the incoming packet data
|
||||
* If a packet is too long to fit in the supplied buffer,
|
||||
* excess bytes are discarded
|
||||
* @param size The length of the buffer
|
||||
* @return The number of received bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size);
|
||||
|
||||
/** Close the socket
|
||||
\param handle Socket handle
|
||||
\param shutdown free the left-over data in message queues
|
||||
*/
|
||||
virtual int socket_close(void *handle, bool shutdown);
|
||||
|
||||
/** Register a callback on when a new connection is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_accept(void *handle, void (*callback)(void *), void *id);
|
||||
|
||||
/** Register a callback on when send is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_send(void *handle, void (*callback)(void *), void *id);
|
||||
|
||||
/** Register a callback on when recv is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_recv(void *handle, void (*callback)(void *), void *id);
|
||||
/** Register a callback on state change of the socket
|
||||
* @param handle Socket handle
|
||||
* @param callback Function to call on state change
|
||||
* @param data Argument to pass to callback
|
||||
* @note Callback may be called in an interrupt context.
|
||||
*/
|
||||
virtual void socket_attach(void *handle, void (*callback)(void *), void *data);
|
||||
|
||||
private:
|
||||
ESP8266 _esp;
|
||||
|
@ -208,4 +170,3 @@ private:
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -25,6 +25,15 @@
|
|||
#include "lwip/netdb.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "eth_arch.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/timers.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
|
||||
/* TCP/IP and Network Interface Initialisation */
|
||||
static struct netif netif;
|
||||
|
@ -36,19 +45,19 @@ static Semaphore tcpip_inited(0);
|
|||
static Semaphore netif_linked(0);
|
||||
static Semaphore netif_up(0);
|
||||
|
||||
static void tcpip_init_done(void *)
|
||||
static void tcpip_init_irq(void *)
|
||||
{
|
||||
tcpip_inited.release();
|
||||
}
|
||||
|
||||
static void netif_link_callback(struct netif *netif)
|
||||
static void netif_link_irq(struct netif *netif)
|
||||
{
|
||||
if (netif_is_link_up(netif)) {
|
||||
netif_linked.release();
|
||||
}
|
||||
}
|
||||
|
||||
static void netif_status_callback(struct netif *netif)
|
||||
static void netif_status_irq(struct netif *netif)
|
||||
{
|
||||
if (netif_is_up(netif)) {
|
||||
strcpy(ip_addr, inet_ntoa(netif->ip_addr));
|
||||
|
@ -58,15 +67,15 @@ static void netif_status_callback(struct netif *netif)
|
|||
|
||||
static void init_netif(ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw)
|
||||
{
|
||||
tcpip_init(tcpip_init_done, NULL);
|
||||
tcpip_init(tcpip_init_irq, NULL);
|
||||
tcpip_inited.wait();
|
||||
|
||||
memset((void*) &netif, 0, sizeof(netif));
|
||||
netif_add(&netif, ipaddr, netmask, gw, NULL, eth_arch_enetif_init, tcpip_input);
|
||||
netif_set_default(&netif);
|
||||
|
||||
netif_set_link_callback (&netif, netif_link_callback);
|
||||
netif_set_status_callback(&netif, netif_status_callback);
|
||||
netif_set_link_callback (&netif, netif_link_irq);
|
||||
netif_set_status_callback(&netif, netif_status_irq);
|
||||
}
|
||||
|
||||
static void set_mac_address(void)
|
||||
|
@ -82,6 +91,7 @@ static void set_mac_address(void)
|
|||
}
|
||||
|
||||
|
||||
/* Interface implementation */
|
||||
int LWIPInterface::connect()
|
||||
{
|
||||
// Set up network
|
||||
|
@ -122,194 +132,422 @@ const char *LWIPInterface::get_mac_address()
|
|||
return mac_addr;
|
||||
}
|
||||
|
||||
void *LWIPInterface::socket_create(nsapi_protocol_t proto)
|
||||
struct lwip_socket {
|
||||
nsapi_protocol_t proto;
|
||||
union {
|
||||
struct udp_pcb *udp;
|
||||
struct tcp_pcb *tcp;
|
||||
};
|
||||
|
||||
struct tcp_pcb *npcb;
|
||||
struct pbuf *rx_chain;
|
||||
Semaphore *sem;
|
||||
|
||||
void (*callback)(void *);
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void udp_recv_irq(
|
||||
void *arg, struct udp_pcb *upcb, struct pbuf *p,
|
||||
struct ip_addr *addr, uint16_t port);
|
||||
|
||||
int LWIPInterface::socket_open(void **handle, nsapi_protocol_t proto)
|
||||
{
|
||||
int type = (proto == NSAPI_UDP) ? SOCK_DGRAM : SOCK_STREAM;
|
||||
int fd = lwip_socket(AF_INET, type, 0);
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
struct lwip_socket *s = new struct lwip_socket;
|
||||
if (!s) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
return (void *)(fd+1);
|
||||
}
|
||||
memset(s, 0, sizeof *s);
|
||||
|
||||
void LWIPInterface::socket_destroy(void *handle)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
lwip_close(fd);
|
||||
|
||||
}
|
||||
switch (proto) {
|
||||
case NSAPI_UDP:
|
||||
s->proto = proto;
|
||||
s->udp = udp_new();
|
||||
if (!s->udp) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_set_option(void *handle, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
return lwip_setsockopt(fd, SOL_SOCKET, optname, optval, (socklen_t)optlen);
|
||||
}
|
||||
udp_recv(s->udp, udp_recv_irq, s);
|
||||
*handle = s;
|
||||
return 0;
|
||||
|
||||
int LWIPInterface::socket_get_option(void *handle, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
return lwip_getsockopt(fd, SOL_SOCKET, optname, optval, (socklen_t*)optlen);
|
||||
}
|
||||
case NSAPI_TCP:
|
||||
s->proto = proto;
|
||||
s->tcp = tcp_new();
|
||||
if (!s->tcp) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_bind(void *handle, int port)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
struct sockaddr_in sa;
|
||||
memset(&sa, 0, sizeof sa);
|
||||
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(port);
|
||||
sa.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (lwip_bind(fd, (const struct sockaddr *)&sa, sizeof sa) < 0) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
tcp_arg(s->tcp, s);
|
||||
//tcp_err(s->tcp, tcp_error_irq);
|
||||
*handle = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_close(void *handle)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
int err = 0;
|
||||
|
||||
switch (s->proto) {
|
||||
case NSAPI_UDP:
|
||||
udp_disconnect(s->udp);
|
||||
udp_remove(s->udp);
|
||||
break;
|
||||
|
||||
case NSAPI_TCP:
|
||||
if (tcp_close(s->tcp)) {
|
||||
err = NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->rx_chain) {
|
||||
pbuf_free(s->rx_chain);
|
||||
s->rx_chain = 0;
|
||||
}
|
||||
|
||||
delete s;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int LWIPInterface::socket_bind(void *handle, const SocketAddress &address)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
ip_addr_t ip_addr = ip_addr_any; // TODO use address
|
||||
|
||||
switch (s->proto) {
|
||||
case NSAPI_UDP:
|
||||
if (udp_bind(s->udp, &ip_addr, address.get_port())) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case NSAPI_TCP:
|
||||
if (tcp_bind(s->tcp, &ip_addr, address.get_port())) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
static err_t tcp_accept_irq(void *arg, struct tcp_pcb *tpcb, err_t err);
|
||||
|
||||
int LWIPInterface::socket_listen(void *handle, int backlog)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
|
||||
if (s->tcp->state != LISTEN) {
|
||||
struct tcp_pcb *server = tcp_listen(s->tcp);
|
||||
if (!server) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
s->tcp = server;
|
||||
s->npcb = 0;
|
||||
}
|
||||
|
||||
tcp_arg(s->tcp, s);
|
||||
tcp_accept(s->tcp, tcp_accept_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static err_t tcp_sent_irq(void *arg, struct tcp_pcb *tpcb, uint16_t len);
|
||||
static err_t tcp_recv_irq(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
|
||||
|
||||
static err_t tcp_connect_irq(void *handle, struct tcp_pcb *tpcb, err_t err)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
tcp_sent(tpcb, tcp_sent_irq);
|
||||
tcp_recv(tpcb, tcp_recv_irq);
|
||||
|
||||
s->sem->release();
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_connect(void *handle, const SocketAddress &addr)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
struct sockaddr_in sa;
|
||||
memset(&sa, 0, sizeof sa);
|
||||
inet_aton(addr.get_ip_address(), &sa.sin_addr);
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(addr.get_port());
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
|
||||
if (lwip_connect(fd, (const struct sockaddr *)&sa, sizeof sa) < 0) {
|
||||
ip_addr_t ip_addr;
|
||||
inet_aton(addr.get_ip_address(), &ip_addr);
|
||||
|
||||
Semaphore connected(0);
|
||||
s->sem = &connected;
|
||||
|
||||
tcp_connect(s->tcp, &ip_addr, addr.get_port(), tcp_connect_irq);
|
||||
|
||||
// Wait for connection
|
||||
if (connected.wait(1500) < 0) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool LWIPInterface::socket_is_connected(void *handle)
|
||||
|
||||
static err_t tcp_refuse_irq(void *handle, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
{
|
||||
return true;
|
||||
return ERR_WOULDBLOCK;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_accept(void *handle, void **connection)
|
||||
static err_t tcp_accept_irq(void *handle, struct tcp_pcb *npcb, err_t err)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_send(void *handle, const void *p, unsigned size)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
uint8_t *data = (uint8_t *)p;
|
||||
unsigned written = 0;
|
||||
|
||||
while (written < size) {
|
||||
int ret = lwip_send(fd, data + written, size - written, 0);
|
||||
|
||||
if (ret > 0) {
|
||||
written += ret;
|
||||
} else if (ret == 0) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
} else {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
if (s->npcb) {
|
||||
tcp_abort(npcb);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
|
||||
return written;
|
||||
tcp_recv(npcb, tcp_refuse_irq);
|
||||
s->npcb = npcb;
|
||||
|
||||
if (s->callback) {
|
||||
s->callback(s->data);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_recv(void *handle, void *data, unsigned size)
|
||||
int LWIPInterface::socket_accept(void **handle, void *server)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
int ret = lwip_recv(fd, data, size, MSG_DONTWAIT);
|
||||
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
} else if (ret == 0) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
} else if (ret == -1) {
|
||||
struct lwip_socket *s = (struct lwip_socket *)server;
|
||||
if (!s->npcb) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
} else {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *p, unsigned size)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
uint8_t *data = (uint8_t *)p;
|
||||
unsigned written = 0;
|
||||
|
||||
struct sockaddr_in sa;
|
||||
memset(&sa, 0, sizeof sa);
|
||||
inet_aton(addr.get_ip_address(), &sa.sin_addr);
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(addr.get_port());
|
||||
|
||||
while (written < size) {
|
||||
int ret = lwip_sendto(fd, data + written, size - written, 0,
|
||||
(const struct sockaddr *)&sa, sizeof sa);
|
||||
|
||||
if (ret > 0) {
|
||||
written += ret;
|
||||
} else if (ret == 0) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
} else {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
struct sockaddr_in sa;
|
||||
socklen_t sa_len = sizeof sa;
|
||||
|
||||
int ret = lwip_recvfrom(fd, data, size, MSG_DONTWAIT,
|
||||
(struct sockaddr *)&sa, &sa_len);
|
||||
|
||||
if (ret > 0 && addr) {
|
||||
addr->set_ip_address(inet_ntoa(sa.sin_addr));
|
||||
addr->set_port(ntohs(sa.sin_port));
|
||||
struct lwip_socket *ns = new struct lwip_socket;
|
||||
if (!ns) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
} else if (ret == 0) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
} else if (ret == -1) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
} else {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
memset(ns, 0, sizeof *ns);
|
||||
|
||||
int LWIPInterface::socket_close(void *handle, bool shutdown)
|
||||
{
|
||||
int fd = (int)handle-1;
|
||||
if (shutdown) {
|
||||
lwip_shutdown(fd, SHUT_RDWR);
|
||||
}
|
||||
ns->tcp = s->npcb;
|
||||
s->npcb = 0;
|
||||
|
||||
lwip_close(fd);
|
||||
tcp_accepted(ns->tcp);
|
||||
tcp_arg(ns->tcp, ns);
|
||||
//tcp_err(ns->tcp, tcp_error_irq);
|
||||
tcp_sent(ns->tcp, tcp_sent_irq);
|
||||
tcp_recv(ns->tcp, tcp_recv_irq);
|
||||
*handle = ns;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LWIPInterface::socket_attach_accept(void *handle, void (*callback)(void *), void *id)
|
||||
static struct pbuf *pbuf_consume(struct pbuf *p, size_t consume, bool free_partial)
|
||||
{
|
||||
do {
|
||||
if (consume <= p->len) {
|
||||
// advance the payload pointer by the number of bytes copied
|
||||
p->payload = (char *)p->payload + consume;
|
||||
// reduce the length by the number of bytes copied
|
||||
p->len -= consume;
|
||||
// break out of the loop
|
||||
consume = 0;
|
||||
}
|
||||
if (p->len == 0 || consume > p->len || (consume == 0 && free_partial)) {
|
||||
struct pbuf *q;
|
||||
q = p->next;
|
||||
// decrement the number of bytes copied by the length of the buffer
|
||||
if(consume > p->len)
|
||||
consume -= p->len;
|
||||
// Free the current pbuf
|
||||
// NOTE: This operation is interrupt safe, but not thread safe.
|
||||
if (q != NULL) {
|
||||
pbuf_ref(q);
|
||||
}
|
||||
pbuf_free(p);
|
||||
p = q;
|
||||
}
|
||||
} while (consume);
|
||||
return p;
|
||||
}
|
||||
|
||||
void LWIPInterface::socket_attach_send(void *handle, void (*callback)(void *), void *id)
|
||||
static err_t tcp_sent_irq(void *handle, struct tcp_pcb *tpcb, uint16_t len)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
if (s->callback) {
|
||||
s->callback(s->data);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void LWIPInterface::socket_attach_recv(void *handle, void (*callback)(void *), void *id)
|
||||
int LWIPInterface::socket_send(void *handle, const void *buf, unsigned size)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
|
||||
if (tcp_write(s->tcp, buf, size, TCP_WRITE_FLAG_COPY)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
tcp_output(s->tcp);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static err_t tcp_recv_irq(void *handle, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
|
||||
// Check for disconnect
|
||||
if (!p) {
|
||||
// Zero pcb during disconnect, since disconnect will cause a free
|
||||
switch (tpcb->state) {
|
||||
case FIN_WAIT_1:
|
||||
case FIN_WAIT_2:
|
||||
case TIME_WAIT:
|
||||
s->tcp = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
__disable_irq();
|
||||
if (!s->rx_chain) {
|
||||
s->rx_chain = p;
|
||||
} else {
|
||||
pbuf_cat(s->rx_chain, p);
|
||||
}
|
||||
__enable_irq();
|
||||
|
||||
if (s->callback) {
|
||||
s->callback(s->data);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_recv(void *handle, void *buf, unsigned size)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
|
||||
// Disconnected
|
||||
if (!s->tcp && !s->rx_chain) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
}
|
||||
|
||||
// Nothing ready
|
||||
if (!s->rx_chain) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
// Copy out pbuf
|
||||
struct pbuf *p = s->rx_chain;
|
||||
int copied = pbuf_copy_partial(p, buf, size, 0);
|
||||
s->rx_chain = pbuf_consume(p, copied, false);
|
||||
|
||||
// Update TCP window
|
||||
tcp_recved(s->tcp, copied);
|
||||
return copied;
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *buf, unsigned size)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
|
||||
struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
|
||||
if (pbuf_take(pb, buf, size)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
ip_addr_t id_addr;
|
||||
inet_aton(addr.get_ip_address(), &id_addr);
|
||||
|
||||
err_t err = udp_sendto(s->udp, pb, &id_addr, addr.get_port());
|
||||
pbuf_free(pb);
|
||||
if (err) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (s->callback) {
|
||||
s->callback(s->data);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void udp_recv_irq(
|
||||
void *handle, struct udp_pcb *upcb, struct pbuf *p,
|
||||
struct ip_addr *addr, uint16_t port)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
|
||||
__disable_irq();
|
||||
if (!s->rx_chain) {
|
||||
s->rx_chain = p;
|
||||
} else {
|
||||
// Attach p to buffer chain without changing the tot_len
|
||||
// NOTE: This is not how pbufs are intended to work, but it is necessary to deal with
|
||||
// a) fragmentation and b) packet queueing
|
||||
struct pbuf *q = s->rx_chain;
|
||||
while (q->next) { q = q->next; }
|
||||
q->next = p;
|
||||
}
|
||||
__enable_irq();
|
||||
|
||||
if (s->callback) {
|
||||
s->callback(s->data);
|
||||
}
|
||||
}
|
||||
|
||||
int LWIPInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *buf, unsigned size)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
|
||||
// Disconnected
|
||||
if (!s->udp && !s->rx_chain) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
}
|
||||
|
||||
// Nothing ready
|
||||
if (!s->rx_chain) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
struct pbuf *p = s->rx_chain;
|
||||
|
||||
if (addr) {
|
||||
struct udp_hdr *udphdr;
|
||||
struct ip_hdr *iphdr;
|
||||
|
||||
// roll back the pbuf by udp_hdr to find the source port
|
||||
pbuf_header(p, UDP_HLEN);
|
||||
udphdr = (struct udp_hdr *)p->payload;
|
||||
|
||||
// roll back the pbuf by ip_hdr to find the source IP
|
||||
pbuf_header(p, IP_HLEN);
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
|
||||
// put the pbuf back where it was
|
||||
pbuf_header(p, -UDP_HLEN - IP_HLEN);
|
||||
|
||||
addr->set_ip_address(inet_ntoa(iphdr->src));
|
||||
addr->set_port(ntohs(udphdr->src));
|
||||
}
|
||||
|
||||
// Copy out pbuf
|
||||
size = size < p->tot_len ? size : p->tot_len;
|
||||
int copied = pbuf_copy_partial(p, buf, size, 0);
|
||||
s->rx_chain = pbuf_consume(p, p->tot_len, true);
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
void LWIPInterface::socket_attach(void *handle, void (*callback)(void *), void *data)
|
||||
{
|
||||
struct lwip_socket *s = (struct lwip_socket *)handle;
|
||||
s->callback = callback;
|
||||
s->data = data;
|
||||
}
|
||||
|
|
|
@ -23,171 +23,129 @@
|
|||
|
||||
|
||||
/** LWIPInterface class
|
||||
* Implementation of the NetworkInterface for LWIP
|
||||
* Implementation of the NetworkStack for LWIP
|
||||
*/
|
||||
class LWIPInterface : public EthernetInterface
|
||||
class LWIPInterface : public NetworkStack, public EthernetInterface
|
||||
{
|
||||
public:
|
||||
/** Start the interface
|
||||
* @return 0 on success, negative on failure
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int connect();
|
||||
|
||||
/** Stop the interface
|
||||
* @return 0 on success, negative on failure
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int disconnect();
|
||||
|
||||
/** Get the internally stored IP address
|
||||
/return IP address of the interface or null if not yet connected
|
||||
*/
|
||||
* @return IP address of the interface or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address();
|
||||
|
||||
/** Get the internally stored MAC address
|
||||
/return MAC address of the interface
|
||||
*/
|
||||
* @return MAC address of the interface
|
||||
*/
|
||||
virtual const char *get_mac_address();
|
||||
|
||||
protected:
|
||||
/** Create a socket
|
||||
/param proto The type of socket to open, TCP or UDP
|
||||
/return The alocated socket or null on failure
|
||||
*/
|
||||
virtual void *socket_create(nsapi_protocol_t proto);
|
||||
/** Open a socket
|
||||
* @param handle Handle in which to store new socket
|
||||
* @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_open(void **handle, nsapi_protocol_t proto);
|
||||
|
||||
/** Destroy a socket
|
||||
/param socket Previously allocated socket
|
||||
*/
|
||||
virtual void socket_destroy(void *handle);
|
||||
|
||||
/** Set socket options
|
||||
\param handle Socket handle
|
||||
\param optname Option ID
|
||||
\param optval Option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_set_option(void *handle, int optname, const void *optval, unsigned int optlen);
|
||||
|
||||
/** Get socket options
|
||||
\param handle Socket handle
|
||||
\param optname Option ID
|
||||
\param optval Buffer pointer where to write the option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen);
|
||||
/** Close the socket
|
||||
* @param handle Socket handle
|
||||
* @return 0 on success, negative on failure
|
||||
* @note On failure, any memory associated with the socket must still
|
||||
* be cleaned up
|
||||
*/
|
||||
virtual int socket_close(void *handle);
|
||||
|
||||
/** Bind a server socket to a specific port
|
||||
\param handle Socket handle
|
||||
\param port The port to listen for incoming connections on
|
||||
\return 0 on success, negative on failure.
|
||||
*/
|
||||
virtual int socket_bind(void *handle, int port);
|
||||
* @param handle Socket handle
|
||||
* @param address Local address to listen for incoming connections on
|
||||
* @return 0 on success, negative on failure.
|
||||
*/
|
||||
virtual int socket_bind(void *handle, const SocketAddress &address);
|
||||
|
||||
/** Start listening for incoming connections
|
||||
\param handle Socket handle
|
||||
\param backlog Number of pending connections that can be queued up at any
|
||||
one time [Default: 1]
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param backlog Number of pending connections that can be queued up at any
|
||||
* one time [Default: 1]
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_listen(void *handle, int backlog);
|
||||
|
||||
/** Connects this TCP socket to the server
|
||||
\param handle Socket handle
|
||||
\param address SocketAddress to connect to
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param address SocketAddress to connect to
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_connect(void *handle, const SocketAddress &address);
|
||||
|
||||
/** Check if the socket is connected
|
||||
\param handle Socket handle
|
||||
\return true if connected, false otherwise
|
||||
*/
|
||||
virtual bool socket_is_connected(void *handle);
|
||||
|
||||
/** Accept a new connection.
|
||||
\param handle Socket handle
|
||||
\param socket A TCPSocket instance that will handle the incoming connection.
|
||||
\return 0 on success, negative on failure.
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_accept(void *handle, void **connection);
|
||||
* @param handle Handle in which to store new socket
|
||||
* @param server Socket handle to server to accept from
|
||||
* @return 0 on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_accept(void **handle, void *server);
|
||||
|
||||
/** Send data to the remote host
|
||||
\param handle Socket handle
|
||||
\param data The buffer to send to the host
|
||||
\param size The length of the buffer to send
|
||||
\return Number of written bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param data The buffer to send to the host
|
||||
* @param size The length of the buffer to send
|
||||
* @return Number of written bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_send(void *handle, const void *data, unsigned size);
|
||||
|
||||
/** Receive data from the remote host
|
||||
\param handle Socket handle
|
||||
\param data The buffer in which to store the data received from the host
|
||||
\param size The maximum length of the buffer
|
||||
\return Number of received bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param data The buffer in which to store the data received from the host
|
||||
* @param size The maximum length of the buffer
|
||||
* @return Number of received bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recv(void *handle, void *data, unsigned size);
|
||||
|
||||
/** Send a packet to a remote endpoint
|
||||
\param handle Socket handle
|
||||
\param address The remote SocketAddress
|
||||
\param data The packet to be sent
|
||||
\param size The length of the packet to be sent
|
||||
\return the number of written bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param address The remote SocketAddress
|
||||
* @param data The packet to be sent
|
||||
* @param size The length of the packet to be sent
|
||||
* @return the number of written bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size);
|
||||
|
||||
/** Receive a packet from a remote endpoint
|
||||
\param handle Socket handle
|
||||
\param address Destination for the remote SocketAddress or null
|
||||
\param buffer The buffer for storing the incoming packet data
|
||||
If a packet is too long to fit in the supplied buffer,
|
||||
excess bytes are discarded
|
||||
\param size The length of the buffer
|
||||
\return the number of received bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
* @param handle Socket handle
|
||||
* @param address Destination for the remote SocketAddress or null
|
||||
* @param buffer The buffer for storing the incoming packet data
|
||||
* If a packet is too long to fit in the supplied buffer,
|
||||
* excess bytes are discarded
|
||||
* @param size The length of the buffer
|
||||
* @return the number of received bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size);
|
||||
|
||||
/** Close the socket
|
||||
\param handle Socket handle
|
||||
\param shutdown free the left-over data in message queues
|
||||
*/
|
||||
virtual int socket_close(void *handle, bool shutdown);
|
||||
|
||||
/** Register a callback on when a new connection is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_accept(void *handle, void (*callback)(void *), void *id);
|
||||
|
||||
/** Register a callback on when send is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_send(void *handle, void (*callback)(void *), void *id);
|
||||
|
||||
/** Register a callback on when recv is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_recv(void *handle, void (*callback)(void *), void *id);
|
||||
/** Register a callback on state change of the socket
|
||||
* @param handle Socket handle
|
||||
* @param callback Function to call on state change
|
||||
* @param data Argument to pass to callback
|
||||
* @note Callback may be called in an interrupt context.
|
||||
*/
|
||||
virtual void socket_attach(void *handle, void (*callback)(void *), void *data);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/* 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 "NetworkStack.h"
|
||||
|
||||
/** CellularInterface class
|
||||
*
|
||||
* Common interface that is shared between ethernet hardware
|
||||
*/
|
||||
class CellularInterface
|
||||
{
|
||||
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
|
|
@ -185,7 +185,7 @@ static int32_t query(UDPSocket *socket, const SocketAddress &addr, const char *h
|
|||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
||||
int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip)
|
||||
int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip)
|
||||
{
|
||||
if (isIP(host)) {
|
||||
strcpy(ip, host);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#ifndef __DNSQUERY_H__
|
||||
#define __DNSQUERY_H__
|
||||
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
#include "UDPSocket.h"
|
||||
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
* @returns 0 on succes, NS_DNS_FAILURE if host is not found,
|
||||
* or a negative value for other errors.
|
||||
*/
|
||||
int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip);
|
||||
int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip);
|
||||
int32_t dnsQuery(UDPSocket *sock, const char *host, char *ip);
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Socket
|
||||
/* EthernetInterface
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -17,23 +17,32 @@
|
|||
#ifndef ETHERNET_INTERFACE_H
|
||||
#define ETHERNET_INTERFACE_H
|
||||
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
|
||||
/** EthernetInterface class
|
||||
* Common interface that is shared between ethernet hardware
|
||||
*
|
||||
* Common interface that is shared between ethernet hardware.
|
||||
*/
|
||||
class EthernetInterface : public NetworkInterface
|
||||
class EthernetInterface
|
||||
{
|
||||
public:
|
||||
/** Start the interface
|
||||
* @return 0 on success, negative on failure
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int connect() = 0;
|
||||
|
||||
/** Stop the interface
|
||||
* @return 0 on success, negative on failure
|
||||
*
|
||||
* @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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Socket
|
||||
/* MeshInterface
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -17,23 +17,32 @@
|
|||
#ifndef MESH_INTERFACE_H
|
||||
#define MESH_INTERFACE_H
|
||||
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
|
||||
/** MeshInterface class
|
||||
* Common interface that is shared between ethernet hardware
|
||||
*
|
||||
* Common interface that is shared between mesh hardware
|
||||
*/
|
||||
class MeshInterface : public NetworkInterface
|
||||
class MeshInterface
|
||||
{
|
||||
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
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/* 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 "DnsQuery.h"
|
||||
#include "mbed.h"
|
||||
|
||||
int NetworkInterface::gethostbyname(const char *name, char *dest)
|
||||
{
|
||||
return dnsQuery(this, name, dest);
|
||||
}
|
|
@ -1,235 +0,0 @@
|
|||
/* 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 NETWORK_INTERFACE_H
|
||||
#define NETWORK_INTERFACE_H
|
||||
|
||||
#include "mbed.h"
|
||||
#include "SocketAddress.h"
|
||||
|
||||
/**
|
||||
* @enum ns_error_t
|
||||
* @brief enum of standardized error codes
|
||||
*/
|
||||
enum nsapi_error_t {
|
||||
NSAPI_ERROR_WOULD_BLOCK = -3001, /*!< no data is not available but call is non-blocking */
|
||||
NSAPI_ERROR_UNSUPPORTED = -3002, /*!< unsupported configuration */
|
||||
NSAPI_ERROR_NO_CONNECTION = -3003, /*!< not connected to a network */
|
||||
NSAPI_ERROR_NO_SOCKET = -3004, /*!< socket not available for use */
|
||||
NSAPI_ERROR_NO_ADDRESS = -3005, /*!< IP address is not known */
|
||||
NSAPI_ERROR_NO_MEMORY = -3006, /*!< memory resource not available */
|
||||
NSAPI_ERROR_DNS_FAILURE = -3007, /*!< DNS failed to complete successfully */
|
||||
NSAPI_ERROR_DHCP_FAILURE = -3008, /*!< DHCP failed to complete successfully */
|
||||
NSAPI_ERROR_AUTH_FAILURE = -3009, /*!< connection to access point faield */
|
||||
NSAPI_ERROR_DEVICE_ERROR = -3010, /*!< failure interfacing with the network procesor */
|
||||
};
|
||||
|
||||
/**
|
||||
* @enum ns_opt_t
|
||||
* @brief enum of available options
|
||||
*/
|
||||
enum ns_opt_t {
|
||||
};
|
||||
|
||||
/** Enum of socket protocols
|
||||
/enum protocol_t
|
||||
*/
|
||||
enum nsapi_protocol_t {
|
||||
NSAPI_TCP, /*!< Socket is of TCP type */
|
||||
NSAPI_UDP, /*!< Socket is of UDP type */
|
||||
};
|
||||
|
||||
/** NetworkInterface class
|
||||
* Common interface that is shared between all hardware that
|
||||
* can connect to a network over IP.
|
||||
*/
|
||||
class NetworkInterface
|
||||
{
|
||||
public:
|
||||
virtual ~NetworkInterface() {};
|
||||
|
||||
/** Get the internally stored IP address
|
||||
/return IP address of the interface or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address() = 0;
|
||||
|
||||
/** Get the internally stored MAC address
|
||||
/return MAC address of the interface
|
||||
*/
|
||||
virtual const char *get_mac_address() = 0;
|
||||
|
||||
/** Get the current status of the interface
|
||||
/return true if connected
|
||||
*/
|
||||
virtual bool is_connected() {
|
||||
return get_ip_address() != NULL;
|
||||
}
|
||||
|
||||
/** Looks up the specified host's IP address
|
||||
/param name Hostname to lookup
|
||||
/param dest Destination for IP address, must have space for SocketAddress::IP_SIZE
|
||||
/return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int gethostbyname(const char *name, char *dest);
|
||||
|
||||
protected:
|
||||
friend class Socket;
|
||||
friend class UDPSocket;
|
||||
friend class TCPSocket;
|
||||
friend class TCPServer;
|
||||
|
||||
/** Create a socket
|
||||
/param proto The type of socket to open, TCP or UDP
|
||||
/return The alocated socket or null on failure
|
||||
*/
|
||||
virtual void *socket_create(nsapi_protocol_t proto) = 0;
|
||||
|
||||
/** Destroy a socket
|
||||
/param socket Previously allocated socket
|
||||
*/
|
||||
virtual void socket_destroy(void *handle) = 0;
|
||||
|
||||
/** Set socket options
|
||||
\param handle Socket handle
|
||||
\param optname Option ID
|
||||
\param optval Option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_set_option(void *handle, int optname, const void *optval, unsigned int optlen) = 0;
|
||||
|
||||
/** Get socket options
|
||||
\param handle Socket handle
|
||||
\param optname Option ID
|
||||
\param optval Buffer pointer where to write the option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_get_option(void *handle, int optname, void *optval, unsigned int *optlen) = 0;
|
||||
|
||||
/** Bind a server socket to a specific port
|
||||
\param handle Socket handle
|
||||
\param port The port to listen for incoming connections on
|
||||
\return 0 on success, negative on failure.
|
||||
*/
|
||||
virtual int socket_bind(void *handle, int port) = 0;
|
||||
|
||||
/** Start listening for incoming connections
|
||||
\param handle Socket handle
|
||||
\param backlog Number of pending connections that can be queued up at any
|
||||
one time [Default: 1]
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_listen(void *handle, int backlog) = 0;
|
||||
|
||||
/** Connects this TCP socket to the server
|
||||
\param handle Socket handle
|
||||
\param address SocketAddress to connect to
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_connect(void *handle, const SocketAddress &address) = 0;
|
||||
|
||||
/** Check if the socket is connected
|
||||
\param handle Socket handle
|
||||
\return true if connected, false otherwise
|
||||
*/
|
||||
virtual bool socket_is_connected(void *handle) = 0;
|
||||
|
||||
/** Accept a new connection.
|
||||
\param handle Socket handle
|
||||
\param socket A TCPSocket instance that will handle the incoming connection.
|
||||
\return 0 on success, negative on failure.
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_accept(void *handle, void **connection) = 0;
|
||||
|
||||
/** Send data to the remote host
|
||||
\param handle Socket handle
|
||||
\param data The buffer to send to the host
|
||||
\param size The length of the buffer to send
|
||||
\return Number of written bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_send(void *handle, const void *data, unsigned size) = 0;
|
||||
|
||||
/** Receive data from the remote host
|
||||
\param handle Socket handle
|
||||
\param data The buffer in which to store the data received from the host
|
||||
\param size The maximum length of the buffer
|
||||
\return Number of received bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recv(void *handle, void *data, unsigned size) = 0;
|
||||
|
||||
/** Send a packet to a remote endpoint
|
||||
\param handle Socket handle
|
||||
\param address The remote SocketAddress
|
||||
\param data The packet to be sent
|
||||
\param size The length of the packet to be sent
|
||||
\return the number of written bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size) = 0;
|
||||
|
||||
/** Receive a packet from a remote endpoint
|
||||
\param handle Socket handle
|
||||
\param address Destination for the remote SocketAddress or null
|
||||
\param buffer The buffer for storing the incoming packet data
|
||||
If a packet is too long to fit in the supplied buffer,
|
||||
excess bytes are discarded
|
||||
\param size The length of the buffer
|
||||
\return the number of received bytes on success, negative on failure
|
||||
\note This call is not-blocking, if this call would block, must
|
||||
immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size) = 0;
|
||||
|
||||
/** Close the socket
|
||||
\param handle Socket handle
|
||||
\param shutdown free the left-over data in message queues
|
||||
*/
|
||||
virtual int socket_close(void *handle, bool shutdown) = 0;
|
||||
|
||||
/** Register a callback on when a new connection is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_accept(void *handle, void (*callback)(void *), void *id) = 0;
|
||||
|
||||
/** Register a callback on when send is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_send(void *handle, void (*callback)(void *), void *id) = 0;
|
||||
|
||||
/** Register a callback on when recv is ready
|
||||
\param handle Socket handle
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
\param id Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach_recv(void *handle, void (*callback)(void *), void *id) = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
/* 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 "DnsQuery.h"
|
||||
#include "mbed.h"
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,338 @@
|
|||
/* 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
|
||||
|
||||
#include "mbed.h"
|
||||
#include "SocketAddress.h"
|
||||
|
||||
|
||||
/** 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 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 */
|
||||
};
|
||||
|
||||
/** Enum of socket protocols
|
||||
*
|
||||
* The socket protocol specifies a particular protocol to
|
||||
* be used with a newly created socket.
|
||||
*
|
||||
* @enum nsapi_protocol_t
|
||||
*/
|
||||
enum nsapi_protocol_t {
|
||||
NSAPI_TCP, /*!< Socket is of TCP type */
|
||||
NSAPI_UDP, /*!< Socket is of UDP type */
|
||||
};
|
||||
|
||||
/* Enum of standardized stack option levels
|
||||
*
|
||||
* @enum nsapi_level_t
|
||||
*/
|
||||
enum nsapi_level_t {
|
||||
NSAPI_STACK, /*!< Stack option level */
|
||||
NSAPI_SOCKET, /*!< Socket option level */
|
||||
};
|
||||
|
||||
/* 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
|
||||
*/
|
||||
enum nsapi_option_t {
|
||||
NSAPI_REUSEADDR, /*!< Allow bind to reuse local addresses */
|
||||
NSAPI_KEEPALIVE, /*!< Enables sending of keepalive messages */
|
||||
NSAPI_LINGER, /*!< Keeps close from returning until queues empty */
|
||||
NSAPI_SNDBUF, /*!< Sets send buffer size */
|
||||
NSAPI_RCVBUF, /*!< Sets recv buffer size */
|
||||
};
|
||||
|
||||
|
||||
/** 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(void **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(void *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(void *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(void *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(void *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(void **handle, void *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(void *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(void *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(void *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(void *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(void *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(void *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(void *handle, int level, int optname, void *optval, unsigned *optlen);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -16,67 +16,156 @@
|
|||
|
||||
#include "Socket.h"
|
||||
|
||||
Socket::Socket(NetworkInterface *iface, nsapi_protocol_t proto)
|
||||
: _iface(iface)
|
||||
, _blocking(true)
|
||||
, _timeout(0)
|
||||
Socket::Socket()
|
||||
: _iface(0)
|
||||
, _socket(0)
|
||||
, _timeout(osWaitForever)
|
||||
{
|
||||
_socket = _iface->socket_create(proto);
|
||||
}
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
if (_socket) {
|
||||
close(false);
|
||||
// Underlying close is thread safe
|
||||
close();
|
||||
}
|
||||
|
||||
int Socket::open(NetworkStack *iface, nsapi_protocol_t proto)
|
||||
{
|
||||
_lock.lock();
|
||||
|
||||
if (_iface != NULL) {
|
||||
_lock.unlock();
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
_iface = iface;
|
||||
|
||||
void *socket;
|
||||
int err = _iface->socket_open(&socket, proto);
|
||||
if (err) {
|
||||
_lock.unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
_socket = socket;
|
||||
_iface->socket_attach(_socket, &Socket::thunk, this);
|
||||
|
||||
_lock.unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Socket::close()
|
||||
{
|
||||
_lock.lock();
|
||||
|
||||
int ret = 0;
|
||||
if (_socket) {
|
||||
_iface->socket_attach(_socket, 0, 0);
|
||||
|
||||
void * socket = _socket;
|
||||
_socket = 0;
|
||||
ret = _iface->socket_close(socket);
|
||||
}
|
||||
|
||||
// Wakeup anything in a blocking operation
|
||||
// on this socket
|
||||
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 = NSAPI_ERROR_NO_SOCKET;
|
||||
if (_socket) {
|
||||
ret = _iface->socket_bind(_socket, address);
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Socket::set_blocking(bool blocking)
|
||||
{
|
||||
_blocking = blocking;
|
||||
// Socket::set_timeout is thread safe
|
||||
set_timeout(blocking ? -1 : 0);
|
||||
}
|
||||
|
||||
void Socket::set_timeout(unsigned timeout)
|
||||
void Socket::set_timeout(int timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
_lock.lock();
|
||||
|
||||
int Socket::set_option(int optname, const void *optval, unsigned int optlen)
|
||||
{
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
if (timeout >= 0) {
|
||||
_timeout = (uint32_t)timeout;
|
||||
} else {
|
||||
_timeout = osWaitForever;
|
||||
}
|
||||
|
||||
return _iface->socket_set_option(_socket, optname, optval, optlen);
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
int Socket::get_option(int optname, void *optval, unsigned int *optlen)
|
||||
int Socket::setsockopt(int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
_lock.lock();
|
||||
|
||||
int ret = NSAPI_ERROR_NO_SOCKET;
|
||||
if (_socket) {
|
||||
ret = _iface->setsockopt(_socket, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
return _iface->socket_get_option(_socket, optname, optval, optlen);
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Socket::close(bool shutdown)
|
||||
int Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
if (!_socket) {
|
||||
return 0;
|
||||
_lock.lock();
|
||||
|
||||
int ret = NSAPI_ERROR_NO_SOCKET;
|
||||
if (_socket) {
|
||||
ret = _iface->getsockopt(_socket, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int err = _iface->socket_close(_socket, shutdown);
|
||||
if (!err) {
|
||||
void *socket = _socket;
|
||||
_socket = 0;
|
||||
_iface->socket_destroy(socket);
|
||||
}
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void Socket::thunk(void *p)
|
||||
void Socket::attach(FunctionPointer callback)
|
||||
{
|
||||
FunctionPointer *fptr = (FunctionPointer *)p;
|
||||
(*fptr)();
|
||||
_lock.lock();
|
||||
|
||||
_callback = callback;
|
||||
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
void Socket::thunk(void *data)
|
||||
{
|
||||
Socket *self = (Socket *)data;
|
||||
self->socket_event();
|
||||
}
|
||||
|
||||
void Socket::socket_event(void)
|
||||
{
|
||||
if (_callback) {
|
||||
_callback();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,56 +18,166 @@
|
|||
#define SOCKET_H
|
||||
|
||||
#include "SocketAddress.h"
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
#include "Mutex.h"
|
||||
|
||||
/** Abstract socket class
|
||||
*/
|
||||
class Socket {
|
||||
public:
|
||||
/** Socket lifetime
|
||||
/** Destroy a socket
|
||||
*
|
||||
* Closes socket if the socket is still open
|
||||
*/
|
||||
virtual ~Socket();
|
||||
|
||||
/** Set blocking or non-blocking mode of the socket
|
||||
\param blocking true for blocking mode, false for non-blocking mode.
|
||||
*/
|
||||
void set_blocking(bool blocking);
|
||||
|
||||
/** Set timeout on a socket operation if blocking behaviour is enabled
|
||||
\param timeout timeout in ms
|
||||
*/
|
||||
void set_timeout(unsigned int timeout);
|
||||
|
||||
/** Set socket options
|
||||
\param optname Option ID
|
||||
\param optval Option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
int set_option(int optname, const void *optval, unsigned optlen);
|
||||
|
||||
/** Get socket options
|
||||
\param optname Option ID
|
||||
\param optval Buffer pointer where to write the option value
|
||||
\param optlen Length of the option value
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
int get_option(int optname, void *optval, unsigned *optlen);
|
||||
/** Opens a socket
|
||||
*
|
||||
* Creates a network socket on the specified network stack.
|
||||
* Not needed if stack is passed to the socket's constructor.
|
||||
*
|
||||
* @param iface Network stack as target for socket
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int open(NetworkStack *iface) = 0;
|
||||
|
||||
/** Close the socket
|
||||
\param shutdown free the left-over data in message queues
|
||||
*/
|
||||
int close(bool shutdown=true);
|
||||
*
|
||||
* 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 callback Function to call on state change
|
||||
*/
|
||||
void attach(FunctionPointer callback);
|
||||
|
||||
/** 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 tptr Pointer to object to call method on
|
||||
* @param mptr Method to call on state change
|
||||
*/
|
||||
template <typename T, typename M>
|
||||
void attach(T *tptr, M mptr) {
|
||||
attach(FunctionPointer(tptr, mptr));
|
||||
}
|
||||
|
||||
protected:
|
||||
Socket(NetworkInterface *iface, nsapi_protocol_t proto);
|
||||
Socket();
|
||||
int open(NetworkStack *iface, nsapi_protocol_t proto);
|
||||
|
||||
static void thunk(void *);
|
||||
virtual void socket_event(void);
|
||||
|
||||
NetworkInterface *_iface;
|
||||
NetworkStack *_iface;
|
||||
void *_socket;
|
||||
bool _blocking;
|
||||
unsigned _timeout;
|
||||
uint32_t _timeout;
|
||||
FunctionPointer _callback;
|
||||
rtos::Mutex _lock;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,37 +15,210 @@
|
|||
*/
|
||||
|
||||
#include "SocketAddress.h"
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
#include <string.h>
|
||||
#include "mbed.h"
|
||||
|
||||
SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t port)
|
||||
{
|
||||
int err = iface->gethostbyname(host, _ip_address);
|
||||
set_port(port);
|
||||
|
||||
if (err) {
|
||||
_ip_address[0] = '\0';
|
||||
_port = 0;
|
||||
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(NetworkStack *iface, const char *host, uint16_t port)
|
||||
{
|
||||
memset(&_ip_address, 0, sizeof _ip_address);
|
||||
|
||||
// Check for valid IP addresses
|
||||
if (host && ipv4_is_valid(host)) {
|
||||
_ip_version = NSAPI_IPv4;
|
||||
ipv4_from_address(_ip_bytes, host);
|
||||
set_port(port);
|
||||
} else if (host && ipv6_is_valid(host)) {
|
||||
_ip_version = NSAPI_IPv6;
|
||||
ipv4_from_address(_ip_bytes, host);
|
||||
set_port(port);
|
||||
} else {
|
||||
// DNS lookup
|
||||
int err = iface->gethostbyname(this, host);
|
||||
if (!err) {
|
||||
set_port(port);
|
||||
} else {
|
||||
_ip_version = NSAPI_IPv4;
|
||||
memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
|
||||
set_port(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SocketAddress::SocketAddress(const char *addr, uint16_t port)
|
||||
{
|
||||
memset(&_ip_address, 0, sizeof _ip_address);
|
||||
set_ip_address(addr);
|
||||
set_port(port);
|
||||
}
|
||||
|
||||
SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port)
|
||||
{
|
||||
memset(&_ip_address, 0, sizeof _ip_address);
|
||||
set_ip_bytes(bytes, version);
|
||||
set_port(port);
|
||||
}
|
||||
|
||||
SocketAddress::SocketAddress(const SocketAddress &addr)
|
||||
{
|
||||
set_ip_address(addr.get_ip_address());
|
||||
memset(&_ip_address, 0, sizeof _ip_address);
|
||||
set_ip_bytes(addr.get_ip_bytes(), addr.get_ip_version());
|
||||
set_port(addr.get_port());
|
||||
}
|
||||
|
||||
void SocketAddress::set_ip_address(const char *addr)
|
||||
{
|
||||
strncpy(_ip_address, addr, sizeof _ip_address);
|
||||
_ip_address[sizeof _ip_address - 1] = '\0';
|
||||
_ip_address[0] = '\0';
|
||||
|
||||
if (addr && ipv4_is_valid(addr)) {
|
||||
_ip_version = NSAPI_IPv4;
|
||||
ipv4_from_address(_ip_bytes, addr);
|
||||
} else if (addr && ipv6_is_valid(addr)) {
|
||||
_ip_version = NSAPI_IPv6;
|
||||
ipv6_from_address(_ip_bytes, addr);
|
||||
} else {
|
||||
_ip_version = NSAPI_IPv4;
|
||||
memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version)
|
||||
{
|
||||
_ip_address[0] = '\0';
|
||||
|
||||
if (version == NSAPI_IPv4) {
|
||||
_ip_version = NSAPI_IPv4;
|
||||
memcpy(_ip_bytes, bytes, NSAPI_IPv4_BYTES);
|
||||
} else if (version == NSAPI_IPv6) {
|
||||
_ip_version = NSAPI_IPv6;
|
||||
memcpy(_ip_bytes, bytes, NSAPI_IPv6_BYTES);
|
||||
} else {
|
||||
_ip_version = NSAPI_IPv4;
|
||||
memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketAddress::set_port(uint16_t port)
|
||||
|
@ -55,13 +228,48 @@ void SocketAddress::set_port(uint16_t port)
|
|||
|
||||
const char *SocketAddress::get_ip_address() const
|
||||
{
|
||||
if (!_ip_address[0]) {
|
||||
return 0;
|
||||
char *ip_address = (char *)_ip_address;
|
||||
|
||||
if (!ip_address[0]) {
|
||||
if (_ip_version == NSAPI_IPv4) {
|
||||
ipv4_to_address(ip_address, _ip_bytes);
|
||||
} else if (_ip_version == NSAPI_IPv6) {
|
||||
ipv6_to_address(ip_address, _ip_bytes);
|
||||
}
|
||||
}
|
||||
return _ip_address;
|
||||
|
||||
return ip_address;
|
||||
}
|
||||
|
||||
const void *SocketAddress::get_ip_bytes() const
|
||||
{
|
||||
return _ip_bytes;
|
||||
}
|
||||
|
||||
nsapi_version_t SocketAddress::get_ip_version() const
|
||||
{
|
||||
return _ip_version;
|
||||
}
|
||||
|
||||
uint16_t SocketAddress::get_port() const
|
||||
{
|
||||
return _port;
|
||||
}
|
||||
|
||||
SocketAddress::operator bool() const
|
||||
{
|
||||
int count = 0;
|
||||
if (_ip_version == NSAPI_IPv4) {
|
||||
count = NSAPI_IPv4_BYTES;
|
||||
} else if (_ip_version == NSAPI_IPv6) {
|
||||
count = NSAPI_IPv6_BYTES;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (_ip_bytes[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Socket
|
||||
/* SocketAddress
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -19,64 +19,147 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Maximum size of IP address
|
||||
*/
|
||||
#define NSAPI_IP_SIZE 16
|
||||
|
||||
/** Maximum size of MAC address
|
||||
*/
|
||||
/** 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
|
||||
|
||||
// Predeclared classes
|
||||
class NetworkInterface;
|
||||
/** Maximum number of bytes for MAC address
|
||||
*/
|
||||
#define NSAPI_MAC_BYTES 6
|
||||
|
||||
/**
|
||||
* A general socket address composed of the IP address and port
|
||||
/** Enum of IP address versions
|
||||
*
|
||||
* The IP version specifies the type of an IP address.
|
||||
*
|
||||
* @enum nsapi_version_t
|
||||
*/
|
||||
enum nsapi_version_t {
|
||||
NSAPI_IPv4, /*!< Address is IPv4 */
|
||||
NSAPI_IPv6, /*!< Address is IPv6 */
|
||||
};
|
||||
|
||||
/** 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
|
||||
|
||||
// Predeclared classes
|
||||
class NetworkStack;
|
||||
|
||||
|
||||
/** SocketAddress class
|
||||
*
|
||||
* Representation of an IP address and port pair.
|
||||
*/
|
||||
class SocketAddress {
|
||||
public:
|
||||
/** SocketAddress construction using DNS resolution
|
||||
/param iface NetworkInterface to use for DNS resolution
|
||||
/param addr Null-terminated hostname that will be resolved
|
||||
/param port 16-bit port
|
||||
/note on failure, IP address and port will be set to null
|
||||
*/
|
||||
SocketAddress(NetworkInterface *iface, const char *addr, uint16_t port = 0);
|
||||
/** 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 iface Network stack to use for DNS resolution
|
||||
* @param host Hostname to resolve
|
||||
* @param port Optional 16-bit port
|
||||
*/
|
||||
SocketAddress(NetworkStack *iface, const char *host, uint16_t port = 0);
|
||||
|
||||
/** SocketAddress construction
|
||||
/param addr Null-terminated IP address
|
||||
/param port 16-bit port
|
||||
/note on failure, IP address and port will be set to null
|
||||
*/
|
||||
/** 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 = 0, uint16_t port = 0);
|
||||
|
||||
/** SocketAddress construction
|
||||
/param addr SocketAddress to copy
|
||||
*/
|
||||
/** Create a SocketAddress from a raw IP address 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 string representing the IP address
|
||||
*
|
||||
* @param addr Null-terminated represention of the IP address
|
||||
*/
|
||||
void set_ip_address(const char *addr);
|
||||
|
||||
/** Set the raw IP address
|
||||
*
|
||||
* @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 port
|
||||
\param port 16-bit port
|
||||
*
|
||||
* @param port 16-bit port
|
||||
*/
|
||||
void set_port(uint16_t port);
|
||||
|
||||
/** Get the IP address
|
||||
\return The string representation of the IP Address
|
||||
*
|
||||
* @return Null-terminated representation of the IP Address
|
||||
*/
|
||||
const char *get_ip_address() const;
|
||||
|
||||
/** Get the raw IP address
|
||||
*
|
||||
* @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 port
|
||||
\return The 16-bit port
|
||||
*
|
||||
* @return The 16-bit port
|
||||
*/
|
||||
uint16_t get_port(void) const;
|
||||
uint16_t get_port() const;
|
||||
|
||||
/** Test if address is zero
|
||||
*
|
||||
* @return True if address is not zero
|
||||
*/
|
||||
operator bool() const;
|
||||
|
||||
private:
|
||||
char _ip_address[NSAPI_IP_SIZE];
|
||||
uint8_t _ip_bytes[NSAPI_IP_BYTES];
|
||||
nsapi_version_t _ip_version;
|
||||
uint16_t _port;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,71 +17,85 @@
|
|||
#include "TCPServer.h"
|
||||
#include "Timer.h"
|
||||
|
||||
TCPServer::TCPServer(NetworkInterface *iface)
|
||||
: Socket(iface, NSAPI_TCP)
|
||||
TCPServer::TCPServer(): _accept_sem(0)
|
||||
{
|
||||
}
|
||||
|
||||
int TCPServer::bind(uint16_t port)
|
||||
TCPServer::TCPServer(NetworkStack *iface): _accept_sem(0)
|
||||
{
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
open(iface);
|
||||
}
|
||||
|
||||
return _iface->socket_bind(_socket, port);
|
||||
int TCPServer::open(NetworkStack *iface)
|
||||
{
|
||||
return Socket::open(iface, NSAPI_TCP);
|
||||
}
|
||||
|
||||
int TCPServer::listen(int backlog)
|
||||
{
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
_lock.lock();
|
||||
|
||||
int ret = NSAPI_ERROR_NO_SOCKET;
|
||||
if (_socket) {
|
||||
ret = _iface->socket_listen(_socket, backlog);
|
||||
}
|
||||
|
||||
return _iface->socket_listen(_socket, backlog);
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TCPServer::accept(TCPSocket *connection)
|
||||
{
|
||||
mbed::Timer timer;
|
||||
timer.start();
|
||||
|
||||
void *socket = connection->_socket;
|
||||
connection->_socket = 0;
|
||||
_iface->socket_destroy(socket);
|
||||
_lock.lock();
|
||||
|
||||
int ret = NSAPI_ERROR_NO_SOCKET;
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
int err = _iface->socket_accept(_socket, &socket);
|
||||
void *socket;
|
||||
ret = _iface->socket_accept(&socket, _socket);
|
||||
if (0 == ret) {
|
||||
connection->_lock.lock();
|
||||
|
||||
if (err > 0) {
|
||||
if (connection->_socket) {
|
||||
connection->close();
|
||||
}
|
||||
|
||||
connection->_iface = _iface;
|
||||
connection->_socket = socket;
|
||||
_iface->socket_attach(socket, &Socket::thunk, connection);
|
||||
|
||||
connection->_lock.unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
if (err != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
|
||||
(_timeout && timer.read_ms() > _timeout)) {
|
||||
return err;
|
||||
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::attach_accept(FunctionPointer callback)
|
||||
void TCPServer::socket_event()
|
||||
{
|
||||
_accept_cb = callback;
|
||||
|
||||
if (_socket && _accept_cb) {
|
||||
return _iface->socket_attach_accept(_socket, Socket::thunk, &_accept_cb);
|
||||
} else if (_socket) {
|
||||
return _iface->socket_attach_accept(_socket, 0, 0);
|
||||
int32_t status = _accept_sem.wait(0);
|
||||
if (status <= 1) {
|
||||
_accept_sem.release();
|
||||
}
|
||||
}
|
||||
|
||||
TCPServer::~TCPServer()
|
||||
{
|
||||
if (_socket && _accept_cb) {
|
||||
_iface->socket_attach_accept(_socket, 0, 0);
|
||||
}
|
||||
Socket::socket_event();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Socket
|
||||
/* TCPServer
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -19,49 +19,65 @@
|
|||
|
||||
#include "Socket.h"
|
||||
#include "TCPSocket.h"
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
#include "Semaphore.h"
|
||||
|
||||
/** TCP Server.
|
||||
/** TCP socket server
|
||||
*/
|
||||
class TCPServer : public Socket {
|
||||
public:
|
||||
/** TCP Server lifetime
|
||||
*/
|
||||
TCPServer(NetworkInterface *iface);
|
||||
virtual ~TCPServer();
|
||||
/** Create an uninitialized socket
|
||||
*
|
||||
* Must call open to initialize the socket on a network stack.
|
||||
*/
|
||||
TCPServer();
|
||||
|
||||
/** Create a socket on a network stack
|
||||
*
|
||||
* Creates and opens a socket on the specified network stack.
|
||||
*
|
||||
* @param iface Network stack as target for socket
|
||||
*/
|
||||
TCPServer(NetworkStack *iface);
|
||||
|
||||
/** Opens a socket
|
||||
*
|
||||
* Creates a network socket on the specified network stack.
|
||||
* Not needed if stack is passed to the socket's constructor.
|
||||
*
|
||||
* @param iface Network stack as target for socket
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int open(NetworkStack *iface);
|
||||
|
||||
/** Bind a socket to a specific port
|
||||
\param port The port to listen for incoming connections on
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
int bind(uint16_t port);
|
||||
/** 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);
|
||||
|
||||
/** Start listening for incoming connections
|
||||
\param backlog Number of pending connections that can be queued up at any
|
||||
one time [Default: 1]
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
int listen(int backlog=1);
|
||||
|
||||
/** Accept a new connection.
|
||||
\param socket A TCPSocket instance that will handle the incoming connection.
|
||||
\return 0 on success, negative on failure.
|
||||
*/
|
||||
/** 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);
|
||||
|
||||
/** Register a callback on when a new connection is ready
|
||||
\param callback Function to call when accept will succeed, may be called in
|
||||
interrupt context.
|
||||
*/
|
||||
void attach_accept(FunctionPointer callback);
|
||||
|
||||
template <typename T, typename M>
|
||||
void attach_accept(T *tptr, M mptr) {
|
||||
attach_accept(FunctionPointer(tptr, mptr));
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionPointer _accept_cb;
|
||||
protected:
|
||||
virtual void socket_event(void);
|
||||
rtos::Semaphore _accept_sem;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,101 +17,140 @@
|
|||
#include "TCPSocket.h"
|
||||
#include "Timer.h"
|
||||
|
||||
TCPSocket::TCPSocket(NetworkInterface *iface)
|
||||
: Socket(iface, NSAPI_TCP)
|
||||
TCPSocket::TCPSocket(): _read_sem(0), _write_sem(0)
|
||||
{
|
||||
}
|
||||
|
||||
TCPSocket::TCPSocket(NetworkStack *iface): _read_sem(0), _write_sem(0)
|
||||
{
|
||||
// TCPSocket::open is thread safe
|
||||
open(iface);
|
||||
}
|
||||
|
||||
int TCPSocket::open(NetworkStack *iface)
|
||||
{
|
||||
// Socket::open is thread safe
|
||||
return Socket::open(iface, NSAPI_TCP);
|
||||
}
|
||||
|
||||
int TCPSocket::connect(const SocketAddress &addr)
|
||||
{
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
_lock.lock();
|
||||
|
||||
int ret = NSAPI_ERROR_NO_SOCKET;
|
||||
if (_socket) {
|
||||
ret = _iface->socket_connect(_socket, addr);
|
||||
}
|
||||
|
||||
return _iface->socket_connect(_socket, addr);
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TCPSocket::connect(const char *host, uint16_t port)
|
||||
{
|
||||
_lock.lock();
|
||||
|
||||
SocketAddress addr(_iface, host, port);
|
||||
if (!addr.get_ip_address()) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
int ret = NSAPI_ERROR_DNS_FAILURE;
|
||||
if (addr) {
|
||||
ret = connect(addr);
|
||||
}
|
||||
|
||||
return connect(addr);
|
||||
}
|
||||
|
||||
bool TCPSocket::is_connected()
|
||||
{
|
||||
return _socket && _iface->socket_is_connected(_socket);
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TCPSocket::send(const void *data, unsigned size)
|
||||
{
|
||||
mbed::Timer timer;
|
||||
timer.start();
|
||||
if (osOK != _write_lock.lock(_timeout)) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
_lock.lock();
|
||||
|
||||
int ret;
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
int sent = _iface->socket_send(_socket, data, size);
|
||||
if (sent != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
|
||||
(_timeout && timer.read_ms() > _timeout)) {
|
||||
return sent;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
_write_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TCPSocket::recv(void *data, unsigned size)
|
||||
{
|
||||
mbed::Timer timer;
|
||||
timer.start();
|
||||
if (osOK != _read_lock.lock(_timeout)) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
_lock.lock();
|
||||
|
||||
int ret;
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int recv = _iface->socket_recv(_socket, data, size);
|
||||
if (recv != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
|
||||
(_timeout && timer.read_ms() > _timeout)) {
|
||||
return recv;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
_read_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void TCPSocket::attach_send(FunctionPointer callback)
|
||||
void TCPSocket::socket_event()
|
||||
{
|
||||
_send_cb = callback;
|
||||
|
||||
if (_socket && _send_cb) {
|
||||
return _iface->socket_attach_send(_socket, Socket::thunk, &_send_cb);
|
||||
} else if (_socket) {
|
||||
return _iface->socket_attach_send(_socket, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void TCPSocket::attach_recv(FunctionPointer callback)
|
||||
{
|
||||
_recv_cb = callback;
|
||||
|
||||
if (_socket && _recv_cb) {
|
||||
return _iface->socket_attach_recv(_socket, Socket::thunk, &_recv_cb);
|
||||
} else if (_socket) {
|
||||
return _iface->socket_attach_recv(_socket, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TCPSocket::~TCPSocket()
|
||||
{
|
||||
if (_socket && _send_cb) {
|
||||
_iface->socket_attach_send(_socket, 0, 0);
|
||||
}
|
||||
|
||||
if (_socket && _recv_cb) {
|
||||
_iface->socket_attach_recv(_socket, 0, 0);
|
||||
int32_t count;
|
||||
count = _write_sem.wait(0);
|
||||
if (count <= 1) {
|
||||
_write_sem.release();
|
||||
}
|
||||
count = _read_sem.wait(0);
|
||||
if (count <= 1) {
|
||||
_read_sem.release();
|
||||
}
|
||||
|
||||
Socket::socket_event();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Socket
|
||||
/* TCPSocket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -18,78 +18,97 @@
|
|||
#define TCPSOCKET_H
|
||||
|
||||
#include "Socket.h"
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
#include "Semaphore.h"
|
||||
|
||||
/**
|
||||
TCP socket connection
|
||||
*/
|
||||
/** TCP socket connection
|
||||
*/
|
||||
class TCPSocket : public Socket {
|
||||
public:
|
||||
/** TCP socket lifetime
|
||||
*/
|
||||
TCPSocket(NetworkInterface *iface);
|
||||
virtual ~TCPSocket();
|
||||
|
||||
/** Connects this TCP socket to the server
|
||||
\param host The host to connect to. It can either be an IP Address
|
||||
or a hostname that will be resolved with DNS
|
||||
\param port The host's port to connect to
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
/** Create an uninitialized socket
|
||||
*
|
||||
* Must call open to initialize the socket on a network stack.
|
||||
*/
|
||||
TCPSocket();
|
||||
|
||||
/** Create a socket on a network stack
|
||||
*
|
||||
* Creates and opens a socket on the specified network stack.
|
||||
*
|
||||
* @param iface Network stack as target for socket
|
||||
*/
|
||||
TCPSocket(NetworkStack *iface);
|
||||
|
||||
/** Opens a socket
|
||||
*
|
||||
* Creates a network socket on the specified network stack.
|
||||
* Not needed if stack is passed to the socket's constructor.
|
||||
*
|
||||
* @param iface Network stack as target for socket
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int open(NetworkStack *iface);
|
||||
|
||||
/** 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 this TCP socket to the server
|
||||
\param address SocketAddress to connect to
|
||||
\return 0 on success, negative on failure
|
||||
*/
|
||||
/** 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);
|
||||
|
||||
/** Check if the socket is connected
|
||||
\return true if connected, false otherwise
|
||||
*/
|
||||
bool is_connected();
|
||||
|
||||
/** Send data to the remote host
|
||||
\param data The buffer to send to the host
|
||||
\param size The length of the buffer to send
|
||||
\return Number of written bytes on success, negative on failure
|
||||
*/
|
||||
/** 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 from the remote host
|
||||
\param data The buffer in which to store the data received from the host
|
||||
\param size The maximum length of the buffer
|
||||
\return Number of received bytes on success, negative on failure
|
||||
*/
|
||||
/** 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);
|
||||
|
||||
/** Register a callback on when send is ready
|
||||
\param callback Function to call when send will succeed, may be called in
|
||||
interrupt context.
|
||||
*/
|
||||
void attach_send(FunctionPointer callback);
|
||||
|
||||
template <typename T, typename M>
|
||||
void attach_send(T *tptr, M mptr) {
|
||||
attach_send(FunctionPointer(tptr, mptr));
|
||||
}
|
||||
|
||||
/** Register a callback on when recv is ready
|
||||
\param callback Function to call when recv will succeed, may be called in
|
||||
interrupt context.
|
||||
*/
|
||||
void attach_recv(FunctionPointer callback);
|
||||
|
||||
template <typename T, typename M>
|
||||
void attach_recv(T *tptr, M mptr) {
|
||||
attach_recv(FunctionPointer(tptr, mptr));
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
virtual void socket_event(void);
|
||||
rtos::Mutex _read_lock;
|
||||
rtos::Semaphore _read_sem;
|
||||
rtos::Mutex _write_lock;
|
||||
rtos::Semaphore _write_sem;
|
||||
friend class TCPServer;
|
||||
|
||||
FunctionPointer _send_cb;
|
||||
FunctionPointer _recv_cb;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,84 +17,124 @@
|
|||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
|
||||
UDPSocket::UDPSocket(NetworkInterface *iface)
|
||||
: Socket(iface, NSAPI_UDP)
|
||||
UDPSocket::UDPSocket(): _read_sem(0), _write_sem(0)
|
||||
{
|
||||
}
|
||||
|
||||
int UDPSocket::bind(uint16_t port)
|
||||
UDPSocket::UDPSocket(NetworkStack *iface): _read_sem(0), _write_sem(0)
|
||||
{
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
open(iface);
|
||||
}
|
||||
|
||||
int UDPSocket::open(NetworkStack *iface)
|
||||
{
|
||||
return Socket::open(iface, NSAPI_UDP);
|
||||
}
|
||||
|
||||
int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigned size)
|
||||
{
|
||||
SocketAddress addr(_iface, host, port);
|
||||
if (!addr) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
||||
return _iface->socket_bind(_socket, port);
|
||||
// sendto is thread safe
|
||||
int ret = sendto(addr, data, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size)
|
||||
{
|
||||
mbed::Timer timer;
|
||||
timer.start();
|
||||
if (osOK != _write_lock.lock(_timeout)) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
_lock.lock();
|
||||
|
||||
int ret;
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int sent = _iface->socket_sendto(_socket, address, data, size);
|
||||
if (sent != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
|
||||
(_timeout && timer.read_ms() > _timeout)) {
|
||||
return sent;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
_write_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size)
|
||||
{
|
||||
mbed::Timer timer;
|
||||
timer.start();
|
||||
if (osOK != _read_lock.lock(_timeout)) {
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
_lock.lock();
|
||||
|
||||
int ret;
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int recv = _iface->socket_recvfrom(_socket, address, buffer, size);
|
||||
if (recv != NSAPI_ERROR_WOULD_BLOCK || !_blocking ||
|
||||
(_timeout && timer.read_ms() > _timeout)) {
|
||||
return recv;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
_read_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void UDPSocket::attach_send(FunctionPointer callback)
|
||||
void UDPSocket::socket_event()
|
||||
{
|
||||
_send_cb = callback;
|
||||
if (_socket && _send_cb) {
|
||||
return _iface->socket_attach_send(_socket, Socket::thunk, &_send_cb);
|
||||
} else if (_socket) {
|
||||
return _iface->socket_attach_send(_socket, 0, 0);
|
||||
int32_t count;
|
||||
count = _write_sem.wait(0);
|
||||
if (count <= 1) {
|
||||
_write_sem.release();
|
||||
}
|
||||
}
|
||||
|
||||
void UDPSocket::attach_recv(FunctionPointer callback)
|
||||
{
|
||||
_recv_cb = callback;
|
||||
if (_socket && _recv_cb) {
|
||||
return _iface->socket_attach_recv(_socket, Socket::thunk, &_recv_cb);
|
||||
} else if (_socket) {
|
||||
return _iface->socket_attach_recv(_socket, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
UDPSocket::~UDPSocket()
|
||||
{
|
||||
if (_socket && _send_cb) {
|
||||
_iface->socket_attach_send(_socket, 0, 0);
|
||||
count = _read_sem.wait(0);
|
||||
if (count <= 1) {
|
||||
_read_sem.release();
|
||||
}
|
||||
|
||||
if (_socket && _recv_cb) {
|
||||
_iface->socket_attach_recv(_socket, 0, 0);
|
||||
}
|
||||
Socket::socket_event();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Socket
|
||||
/* UDPSocket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -18,67 +18,95 @@
|
|||
#define UDPSOCKET_H
|
||||
|
||||
#include "Socket.h"
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
#include "Semaphore.h"
|
||||
|
||||
/**
|
||||
UDP Socket
|
||||
*/
|
||||
/** UDP socket
|
||||
*/
|
||||
class UDPSocket : public Socket {
|
||||
public:
|
||||
/** UDPSocket lifetime
|
||||
*/
|
||||
UDPSocket(NetworkInterface *iface);
|
||||
virtual ~UDPSocket();
|
||||
|
||||
/** Bind a UDP Server Socket to a specific port
|
||||
\param port The port to listen for incoming connections on
|
||||
\return 0 on success, negative on failure.
|
||||
*/
|
||||
int bind(uint16_t port);
|
||||
/** Create an uninitialized socket
|
||||
*
|
||||
* Must call open to initialize the socket on a network stack.
|
||||
*/
|
||||
UDPSocket();
|
||||
|
||||
/** Send a packet to a remote endpoint
|
||||
\param address The remote SocketAddress
|
||||
\param data The packet to be sent
|
||||
\param size The length of the packet to be sent
|
||||
\return the number of written bytes on success, negative on failure
|
||||
*/
|
||||
/** Create a socket on a network stack
|
||||
*
|
||||
* Creates and opens a socket on the specified network stack.
|
||||
*
|
||||
* @param iface Network stack as target for socket
|
||||
*/
|
||||
UDPSocket(NetworkStack *iface);
|
||||
|
||||
/** Opens a socket
|
||||
*
|
||||
* Creates a network socket on the specified network stack.
|
||||
* Not needed if stack is passed to the socket's constructor.
|
||||
*
|
||||
* @param iface Network stack as target for socket
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int open(NetworkStack *iface);
|
||||
|
||||
/** 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 from a remote endpoint
|
||||
\param address Destination for the remote SocketAddress or null
|
||||
\param buffer The buffer for storing the incoming packet data
|
||||
If a packet is too long to fit in the supplied buffer,
|
||||
excess bytes are discarded
|
||||
\param size The length of the buffer
|
||||
\return the number of received bytes on success, negative on failure
|
||||
*/
|
||||
int recvfrom(SocketAddress *address, void *buffer, unsigned size);
|
||||
|
||||
/** Register a callback on when send is ready
|
||||
\param callback Function to call when send will succeed, may be called in
|
||||
interrupt context.
|
||||
*/
|
||||
void attach_send(FunctionPointer callback);
|
||||
|
||||
template <typename T, typename M>
|
||||
void attach_send(T *tptr, M mptr) {
|
||||
attach_send(FunctionPointer(tptr, mptr));
|
||||
}
|
||||
|
||||
/** Register a callback on when recv is ready
|
||||
\param callback Function to call when recv will succeed, may be called in
|
||||
interrupt context.
|
||||
*/
|
||||
void attach_recv(FunctionPointer callback);
|
||||
|
||||
template <typename T, typename M>
|
||||
void attach_recv(T *tptr, M mptr) {
|
||||
attach_recv(FunctionPointer(tptr, mptr));
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionPointer _send_cb;
|
||||
FunctionPointer _recv_cb;
|
||||
/** 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 void socket_event(void);
|
||||
rtos::Mutex _read_lock;
|
||||
rtos::Semaphore _read_sem;
|
||||
rtos::Mutex _write_lock;
|
||||
rtos::Semaphore _write_sem;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Socket
|
||||
/* WiFiInterface
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -17,10 +17,15 @@
|
|||
#ifndef WIFI_INTERFACE_H
|
||||
#define WIFI_INTERFACE_H
|
||||
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
|
||||
/** Enum for WiFi encryption types
|
||||
*/
|
||||
/** 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 */
|
||||
|
@ -29,23 +34,35 @@ enum nsapi_security_t {
|
|||
};
|
||||
|
||||
/** WiFiInterface class
|
||||
*
|
||||
* Common interface that is shared between WiFi devices
|
||||
*/
|
||||
class WiFiInterface : public NetworkInterface
|
||||
class WiFiInterface
|
||||
{
|
||||
public:
|
||||
/** Start the interface
|
||||
/param ssid Name of the network to connect to
|
||||
/param pass Security passphrase to connect to the network
|
||||
/param security Type of encryption for connection
|
||||
/return 0 on success, negative on failure
|
||||
*/
|
||||
*
|
||||
* 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 on failure
|
||||
*/
|
||||
*
|
||||
* @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
|
||||
|
|
|
@ -1 +1 @@
|
|||
https://github.com/ARMmbed/atmel-rf-driver-mirror.git/#f4c48e5e98f6
|
||||
https://github.com/ARMmbed/atmel-rf-driver-mirror/#473759f1a37c1863cb2adfcb2a87ac3f1da144ed
|
||||
|
|
|
@ -1 +1 @@
|
|||
https://github.com/ARMmbed/mbed-client-classic.git/#0cf03c143a2a
|
||||
https://github.com/ARMmbed/mbed-client-classic/#3120f1a11ca18fc0fedcccfb5042e62d4faeda0a
|
||||
|
|
|
@ -1 +1 @@
|
|||
https://github.com/ARMmbed/mbed-mesh-api-mirror.git/#f7a198bb1e66
|
||||
https://github.com/ARMmbed/mbed-mesh-api-mirror/#7312d7621c5c6b89f7c0476a2b103a9f1ea71c3c
|
||||
|
|
|
@ -1 +1 @@
|
|||
https://github.com/ARMmbed/nanostack-hal-mbed-cmsis-rtos.git/#ab64e255deb9
|
||||
https://github.com/ARMmbed/nanostack-hal-mbed-cmsis-rtos/#1d27e2613bf7a454f553e2363c115a1635fa9002
|
||||
|
|
|
@ -0,0 +1,899 @@
|
|||
/* Nanostack implementation of NetworkSocketAPI
|
||||
* Copyright (c) 2016 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 "mbed.h"
|
||||
#include "rtos.h"
|
||||
#include "NanostackInterface.h"
|
||||
|
||||
#include "ns_address.h"
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "eventOS_scheduler.h"
|
||||
|
||||
#include "mbed-mesh-api/MeshInterfaceFactory.h"
|
||||
|
||||
#include "socket_api.h"
|
||||
#include "driverRFPhy.h"
|
||||
#include "net_interface.h"
|
||||
#include "ip6string.h"
|
||||
// Uncomment to enable trace
|
||||
//#define HAVE_DEBUG
|
||||
#include "ns_trace.h"
|
||||
#define TRACE_GROUP "nsif"
|
||||
|
||||
#define NS_INTERFACE_SOCKETS_MAX 16 //same as NanoStack SOCKET_MAX
|
||||
#define NANOSTACK_SOCKET_UDP 17 // same as nanostack SOCKET_UDP
|
||||
#define NANOSTACK_SOCKET_TCP 6 // same as nanostack SOCKET_TCP
|
||||
|
||||
#define MALLOC ns_dyn_mem_alloc
|
||||
#define FREE ns_dyn_mem_free
|
||||
|
||||
#define nanostack_lock() eventOS_scheduler_mutex_wait()
|
||||
#define nanostack_unlock() eventOS_scheduler_mutex_release()
|
||||
#define nanostack_assert_locked() //MBED_ASSERT(eventOS_scheduler_mutex_is_owner())
|
||||
|
||||
enum socket_mode_t {
|
||||
SOCKET_MODE_UNOPENED, // No socket ID
|
||||
SOCKET_MODE_OPENED, // Socket ID but no assigned use yet
|
||||
SOCKET_MODE_CONNECTING, // Socket is connecting but not open yet
|
||||
SOCKET_MODE_DATAGRAM, // Socket is bound to a port and listening for datagrams
|
||||
SOCKET_MODE_STREAM, // Socket has an open stream
|
||||
SOCKET_MODE_CLOSED, // Socket is closed and resources are freed
|
||||
};
|
||||
|
||||
class NanostackBuffer {
|
||||
public:
|
||||
NanostackBuffer *next; /*<! next buffer */
|
||||
ns_address_t ns_address; /*<! address where data is received */
|
||||
uint16_t length; /*<! data length in this buffer */
|
||||
uint8_t payload[1]; /*<! Trailing buffer data */
|
||||
};
|
||||
|
||||
class NanostackSocket {
|
||||
public:
|
||||
static void socket_callback(void *cb);
|
||||
static void* operator new(std::size_t sz);
|
||||
static void operator delete(void* ptr);
|
||||
|
||||
NanostackSocket(int8_t protocol);
|
||||
~NanostackSocket(void);
|
||||
bool open(void);
|
||||
void close(void);
|
||||
bool closed(void) {return SOCKET_MODE_CLOSED == mode;}
|
||||
bool is_bound(void);
|
||||
void set_bound(void);
|
||||
bool is_connecting(void);
|
||||
void set_connecting(ns_address_t *addr);
|
||||
void set_connected(void);
|
||||
|
||||
// Socket events from nanostack
|
||||
void event_data(socket_callback_t *sock_cb);
|
||||
void event_bind_done(socket_callback_t *sock_cb);
|
||||
void event_connnect_closed(socket_callback_t *sock_cb);
|
||||
void event_tx_done(socket_callback_t *sock_cb);
|
||||
|
||||
// Run callback to signal the next layer of the NSAPI
|
||||
void signal_event(void);
|
||||
|
||||
// Add or remove a socket to the listening socket
|
||||
void accept_list_add(NanostackSocket *socket);
|
||||
NanostackSocket * accept_list_remove(void);
|
||||
|
||||
bool data_available(void);
|
||||
size_t data_copy_and_free(void *dest, size_t len, SocketAddress *address, bool stream);
|
||||
void data_free_all(void);
|
||||
void data_attach(NanostackBuffer *data_buf);
|
||||
|
||||
void (*callback)(void *);
|
||||
void *callback_data;
|
||||
int8_t socket_id; /*!< allocated socket ID */
|
||||
int8_t proto; /*!< UDP or TCP */
|
||||
bool addr_valid;
|
||||
ns_address_t ns_address;
|
||||
private:
|
||||
NanostackBuffer *rxBufChain; /*!< Receive buffers */
|
||||
socket_mode_t mode;
|
||||
};
|
||||
|
||||
static Semaphore connect_semaphore(0);
|
||||
static NanostackSocket * socket_tbl[NS_INTERFACE_SOCKETS_MAX] = {0};
|
||||
|
||||
static int map_mesh_error(mesh_error_t err)
|
||||
{
|
||||
switch (err) {
|
||||
case MESH_ERROR_NONE: return 0;
|
||||
case MESH_ERROR_MEMORY: return NSAPI_ERROR_NO_MEMORY;
|
||||
case MESH_ERROR_PARAM: return NSAPI_ERROR_UNSUPPORTED;
|
||||
case MESH_ERROR_STATE: return NSAPI_ERROR_DEVICE_ERROR;
|
||||
default: return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void convert_mbed_addr_to_ns(ns_address_t *ns_addr,
|
||||
const SocketAddress *s_addr)
|
||||
{
|
||||
ns_addr->type = ADDRESS_IPV6;
|
||||
ns_addr->identifier = s_addr->get_port();
|
||||
const char *str = s_addr->get_ip_address();
|
||||
stoip6(str, strlen(str), ns_addr->address);
|
||||
}
|
||||
|
||||
static void convert_ns_addr_to_mbed(SocketAddress *s_addr, const ns_address_t *ns_addr)
|
||||
{
|
||||
char str[40];
|
||||
ip6tos(ns_addr->address, str);
|
||||
s_addr->set_port(ns_addr->identifier);
|
||||
s_addr->set_ip_address(str);
|
||||
}
|
||||
|
||||
void* NanostackSocket::operator new(std::size_t sz) {
|
||||
return MALLOC(sz);
|
||||
}
|
||||
void NanostackSocket::operator delete(void* ptr) {
|
||||
FREE(ptr);
|
||||
}
|
||||
|
||||
NanostackSocket::NanostackSocket(int8_t protocol)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
|
||||
callback = NULL;
|
||||
callback_data = NULL;
|
||||
socket_id = -1;
|
||||
rxBufChain = NULL;
|
||||
proto = protocol;
|
||||
addr_valid = false;
|
||||
memset(&ns_address, 0, sizeof(ns_address));
|
||||
mode = SOCKET_MODE_UNOPENED;
|
||||
}
|
||||
|
||||
NanostackSocket::~NanostackSocket()
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
|
||||
if (mode != SOCKET_MODE_CLOSED) {
|
||||
close();
|
||||
}
|
||||
if (socket_id >= 0) {
|
||||
int ret = socket_free(socket_id);
|
||||
MBED_ASSERT(0 == ret);
|
||||
MBED_ASSERT(socket_tbl[socket_id] == this);
|
||||
socket_id = -1;
|
||||
data_free_all();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool NanostackSocket::open(void)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT(SOCKET_MODE_UNOPENED == mode);
|
||||
|
||||
int temp_socket = socket_open(proto, 0, socket_callback);
|
||||
|
||||
if (temp_socket < 0) {
|
||||
tr_error("NanostackSocket::open() failed");
|
||||
return false;
|
||||
}
|
||||
if (temp_socket >= NS_INTERFACE_SOCKETS_MAX) {
|
||||
MBED_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
if (socket_tbl[temp_socket] != NULL) {
|
||||
MBED_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
socket_id = temp_socket;
|
||||
socket_tbl[socket_id] = this;
|
||||
mode = SOCKET_MODE_OPENED;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void NanostackSocket::close()
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT(mode != SOCKET_MODE_CLOSED);
|
||||
|
||||
if (socket_id >= 0) {
|
||||
int ret = socket_close(socket_id, (addr_valid ? &ns_address : NULL));
|
||||
MBED_ASSERT(0 == ret);
|
||||
} else {
|
||||
MBED_ASSERT(SOCKET_MODE_UNOPENED == mode);
|
||||
}
|
||||
|
||||
data_free_all();
|
||||
|
||||
mode = SOCKET_MODE_CLOSED;
|
||||
signal_event();
|
||||
}
|
||||
|
||||
bool NanostackSocket::is_bound()
|
||||
{
|
||||
return SOCKET_MODE_DATAGRAM == mode;
|
||||
}
|
||||
|
||||
void NanostackSocket::set_bound()
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT(SOCKET_MODE_OPENED == mode);
|
||||
if (SOCKET_UDP == proto) {
|
||||
mode = SOCKET_MODE_DATAGRAM;
|
||||
}
|
||||
}
|
||||
|
||||
bool NanostackSocket::is_connecting()
|
||||
{
|
||||
return SOCKET_MODE_CONNECTING == mode;
|
||||
}
|
||||
|
||||
void NanostackSocket::set_connecting(ns_address_t *addr)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT(SOCKET_MODE_OPENED == mode);
|
||||
|
||||
memcpy(&ns_address, addr, sizeof(ns_address_t));
|
||||
mode = SOCKET_MODE_CONNECTING;
|
||||
}
|
||||
|
||||
void NanostackSocket::set_connected()
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT(SOCKET_MODE_CONNECTING == mode);
|
||||
|
||||
mode = SOCKET_MODE_STREAM;
|
||||
}
|
||||
|
||||
void NanostackSocket::signal_event()
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
|
||||
if (callback != NULL) {
|
||||
callback(callback_data);
|
||||
}
|
||||
}
|
||||
|
||||
void NanostackSocket::socket_callback(void *cb) {
|
||||
nanostack_assert_locked();
|
||||
|
||||
socket_callback_t *sock_cb = (socket_callback_t *) cb;
|
||||
NanostackSocket *socket = socket_tbl[sock_cb->socket_id];
|
||||
MBED_ASSERT(socket != NULL);
|
||||
|
||||
tr_debug("socket_callback() sock=%d, event=%d, interface=%d, data len=%d",
|
||||
sock_cb->socket_id, sock_cb->event_type, sock_cb->interface_id, sock_cb->d_len);
|
||||
|
||||
switch (sock_cb->event_type) {
|
||||
case SOCKET_DATA:
|
||||
tr_debug("SOCKET_DATA, sock=%d, bytes=%d", sock_cb->socket_id, sock_cb->d_len);
|
||||
socket->event_data(sock_cb);
|
||||
break;
|
||||
case SOCKET_BIND_DONE:
|
||||
tr_debug("SOCKET_BIND_DONE");
|
||||
socket->event_bind_done(sock_cb);
|
||||
break;
|
||||
case SOCKET_BIND_FAIL: // Not used in NS
|
||||
tr_debug("SOCKET_BIND_FAIL");
|
||||
break;
|
||||
case SOCKET_BIND_AUTH_FAIL: // Not used in NS
|
||||
tr_debug("SOCKET_BIND_AUTH_FAIL");
|
||||
break;
|
||||
case SOCKET_SERVER_CONNECT_TO_CLIENT: // Not used in NS
|
||||
tr_debug("SOCKET_SERVER_CONNECT_TO_CLIENT");
|
||||
break;
|
||||
case SOCKET_TX_FAIL:
|
||||
tr_debug("SOCKET_TX_FAIL");
|
||||
break;
|
||||
case SOCKET_CONNECT_CLOSED:
|
||||
tr_debug("SOCKET_CONNECT_CLOSED");
|
||||
socket->event_connnect_closed(sock_cb);
|
||||
break;
|
||||
case SOCKET_CONNECT_FAIL_CLOSED: // Not used in NS
|
||||
tr_debug("SOCKET_CONNECT_FAIL_CLOSED");
|
||||
break;
|
||||
case SOCKET_NO_ROUTE:
|
||||
tr_debug("SOCKET_NO_ROUTE");
|
||||
break;
|
||||
case SOCKET_TX_DONE:
|
||||
tr_debug("SOCKET_TX_DONE, %d bytes sent", sock_cb->d_len);
|
||||
socket->event_tx_done(sock_cb);
|
||||
break;
|
||||
default:
|
||||
// SOCKET_NO_RAM, error case for SOCKET_TX_DONE
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool NanostackSocket::data_available()
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT((SOCKET_MODE_DATAGRAM == mode) ||
|
||||
(SOCKET_MODE_CONNECTING == mode) ||
|
||||
(SOCKET_MODE_STREAM == mode));
|
||||
|
||||
return (NULL == rxBufChain) ? false : true;
|
||||
}
|
||||
|
||||
size_t NanostackSocket::data_copy_and_free(void *dest, size_t len,
|
||||
SocketAddress *address, bool stream)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT((SOCKET_MODE_DATAGRAM == mode) ||
|
||||
(mode == SOCKET_MODE_STREAM));
|
||||
|
||||
NanostackBuffer *data_buf = rxBufChain;
|
||||
if (NULL == data_buf) {
|
||||
// No data
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (address) {
|
||||
convert_ns_addr_to_mbed(address, &data_buf->ns_address);
|
||||
}
|
||||
|
||||
size_t copy_size = (len > data_buf->length) ? data_buf->length : len;
|
||||
memcpy(dest, data_buf->payload, copy_size);
|
||||
|
||||
if (stream && (copy_size < data_buf->length)) {
|
||||
// Update the size in the buffer
|
||||
size_t new_buf_size = data_buf->length - copy_size;
|
||||
memmove(data_buf->payload, data_buf->payload + copy_size, new_buf_size);
|
||||
data_buf->length = new_buf_size;
|
||||
} else {
|
||||
// Entire packet used so free it
|
||||
rxBufChain = data_buf->next;
|
||||
FREE(data_buf);
|
||||
}
|
||||
|
||||
return copy_size;
|
||||
}
|
||||
|
||||
void NanostackSocket::data_free_all(void)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
// No mode requirement
|
||||
|
||||
NanostackBuffer *buffer = rxBufChain;
|
||||
while (buffer != NULL) {
|
||||
NanostackBuffer *next_buffer = buffer->next;
|
||||
FREE(buffer);
|
||||
buffer = next_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
void NanostackSocket::data_attach(NanostackBuffer *data_buf)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT((SOCKET_MODE_DATAGRAM == mode) ||
|
||||
(SOCKET_MODE_STREAM == mode));
|
||||
|
||||
// Add to linked list
|
||||
tr_debug("data_attach socket=%p", this);
|
||||
if (NULL == rxBufChain) {
|
||||
rxBufChain = data_buf;
|
||||
} else {
|
||||
NanostackBuffer *buf_tmp = rxBufChain;
|
||||
while (NULL != buf_tmp->next) {
|
||||
buf_tmp = buf_tmp->next;
|
||||
}
|
||||
buf_tmp->next = data_buf;
|
||||
}
|
||||
signal_event();
|
||||
}
|
||||
|
||||
void NanostackSocket::event_data(socket_callback_t *sock_cb)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT((SOCKET_MODE_DATAGRAM == mode) ||
|
||||
(SOCKET_MODE_STREAM == mode));
|
||||
|
||||
// Allocate buffer
|
||||
NanostackBuffer *recv_buff = (NanostackBuffer *) MALLOC(
|
||||
sizeof(NanostackBuffer) + sock_cb->d_len);
|
||||
if (NULL == recv_buff) {
|
||||
tr_error("alloc failed!");
|
||||
return;
|
||||
}
|
||||
recv_buff->next = NULL;
|
||||
|
||||
// Write data to buffer
|
||||
int16_t length = socket_read(sock_cb->socket_id,
|
||||
&recv_buff->ns_address, recv_buff->payload,
|
||||
sock_cb->d_len);
|
||||
if (length < 0) {
|
||||
tr_error("socket_read failed!");
|
||||
FREE(recv_buff);
|
||||
return;
|
||||
}
|
||||
recv_buff->length = length;
|
||||
|
||||
data_attach(recv_buff);
|
||||
}
|
||||
|
||||
void NanostackSocket::event_tx_done(socket_callback_t *sock_cb)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT((SOCKET_MODE_STREAM == mode) ||
|
||||
(SOCKET_MODE_DATAGRAM == mode));
|
||||
|
||||
signal_event();
|
||||
}
|
||||
|
||||
void NanostackSocket::event_bind_done(socket_callback_t *sock_cb)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
MBED_ASSERT(SOCKET_MODE_CONNECTING == mode);
|
||||
|
||||
set_connected();
|
||||
signal_event();
|
||||
}
|
||||
|
||||
void NanostackSocket::event_connnect_closed(socket_callback_t *sock_cb)
|
||||
{
|
||||
nanostack_assert_locked();
|
||||
|
||||
// Only TCP sockets can be closed by the remote end
|
||||
MBED_ASSERT((SOCKET_MODE_STREAM == mode) ||
|
||||
(SOCKET_MODE_CONNECTING == mode));
|
||||
close();
|
||||
}
|
||||
|
||||
void NanostackInterface::mesh_network_handler(mesh_connection_status_t status)
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
if (status == MESH_CONNECTED) {
|
||||
connect_semaphore.release();
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
}
|
||||
|
||||
int NanostackInterface::register_rf()
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
rf_device_id = rf_device_register();
|
||||
if (rf_device_id < 0) {
|
||||
nanostack_unlock();
|
||||
return -1;
|
||||
}
|
||||
// Read mac address after registering the device.
|
||||
rf_read_mac_address(eui64);
|
||||
sprintf(mac_addr_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", eui64[0], eui64[1], eui64[2], eui64[3], eui64[4], eui64[5], eui64[6], eui64[7]);
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NanostackInterface::actual_connect()
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
mesh_error_t status = get_mesh_api()->connect();
|
||||
if (status != MESH_ERROR_NONE) {
|
||||
nanostack_unlock();
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
// Release mutex before blocking
|
||||
nanostack_unlock();
|
||||
|
||||
int32_t count = connect_semaphore.wait(30000);
|
||||
if (count <= 0) {
|
||||
return NSAPI_ERROR_DHCP_FAILURE; // sort of...
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NanostackInterface::disconnect()
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
mesh_error_t status = get_mesh_api()->disconnect();
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
int ThreadInterface::connect()
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
mesh_api = MeshInterfaceFactory::createInterface(MESH_TYPE_THREAD);
|
||||
if (!mesh_api) {
|
||||
nanostack_unlock();
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
if (register_rf() < 0) {
|
||||
nanostack_unlock();
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
mesh_error_t status = ((MeshThread *)mesh_api)->init(rf_device_id, AbstractMesh::mesh_network_handler_t(static_cast<NanostackInterface *>(this), &ThreadInterface::mesh_network_handler), eui64, NULL);
|
||||
if (status != MESH_ERROR_NONE) {
|
||||
nanostack_unlock();
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
int ret = this->actual_connect();
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int LoWPANNDInterface::connect()
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
mesh_api = MeshInterfaceFactory::createInterface(MESH_TYPE_6LOWPAN_ND);
|
||||
if (!mesh_api) {
|
||||
nanostack_unlock();
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
if (register_rf() < 0) {
|
||||
nanostack_unlock();
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
mesh_error_t status = ((Mesh6LoWPAN_ND *)mesh_api)->init(rf_device_id, AbstractMesh::mesh_network_handler_t(static_cast<NanostackInterface *>(this), &LoWPANNDInterface::mesh_network_handler));
|
||||
if (status != MESH_ERROR_NONE) {
|
||||
nanostack_unlock();
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
int ret = this->actual_connect();
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_open(void **handle, nsapi_protocol_t protocol)
|
||||
{
|
||||
// Validate parameters
|
||||
if (NULL == handle) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
int8_t ns_proto;
|
||||
if (NSAPI_UDP == protocol) {
|
||||
ns_proto = SOCKET_UDP;
|
||||
} else if (NSAPI_TCP == protocol) {
|
||||
ns_proto = SOCKET_TCP;
|
||||
} else {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
*handle = (void*)NULL;
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
NanostackSocket * socket = new NanostackSocket(ns_proto);
|
||||
if (NULL == socket) {
|
||||
nanostack_unlock();
|
||||
tr_debug("socket_open() ret=%i", NSAPI_ERROR_NO_MEMORY);
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
if (!socket->open()) {
|
||||
delete socket;
|
||||
nanostack_unlock();
|
||||
tr_debug("socket_open() ret=%i", NSAPI_ERROR_DEVICE_ERROR);
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
*handle = (void*)socket;
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
tr_debug("socket_open() socket=%p, sock_id=%d, ret=0", socket, socket->socket_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_close(void *handle)
|
||||
{
|
||||
// Validate parameters
|
||||
NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
|
||||
if (NULL == handle) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
tr_debug("socket_close(socket=%p) sock_id=%d", socket, socket->socket_id);
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
delete socket;
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned int size)
|
||||
{
|
||||
// Validate parameters
|
||||
NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
|
||||
if (NULL == handle) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
int ret;
|
||||
if (socket->closed()) {
|
||||
ret = NSAPI_ERROR_NO_CONNECTION;
|
||||
} else if (NANOSTACK_SOCKET_TCP == socket->proto) {
|
||||
tr_error("socket_sendto() not supported with SOCKET_STREAM!");
|
||||
ret = NSAPI_ERROR_UNSUPPORTED;
|
||||
} else {
|
||||
ns_address_t ns_address;
|
||||
convert_mbed_addr_to_ns(&ns_address, &address);
|
||||
if (!socket->is_bound()) {
|
||||
socket->set_bound();
|
||||
}
|
||||
int8_t send_to_status = ::socket_sendto(socket->socket_id, &ns_address,
|
||||
(uint8_t *)data, size);
|
||||
/*
|
||||
* \return 0 on success.
|
||||
* \return -1 invalid socket id.
|
||||
* \return -2 Socket memory allocation fail.
|
||||
* \return -3 TCP state not established.
|
||||
* \return -4 Socket tx process busy.
|
||||
* \return -5 TLS authentication not ready.
|
||||
* \return -6 Packet too short.
|
||||
* */
|
||||
if (-4 == send_to_status) {
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
} else if (0 != send_to_status) {
|
||||
tr_error("socket_sendto: error=%d", send_to_status);
|
||||
ret = NSAPI_ERROR_DEVICE_ERROR;
|
||||
} else {
|
||||
ret = size;
|
||||
}
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
tr_debug("socket_sendto(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size)
|
||||
{
|
||||
// Validate parameters
|
||||
NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
|
||||
if (NULL == handle) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
if (NULL == buffer) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
if (0 == size) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
int ret;
|
||||
if (socket->closed()) {
|
||||
ret = NSAPI_ERROR_NO_CONNECTION;
|
||||
} else if (NANOSTACK_SOCKET_TCP == socket->proto) {
|
||||
tr_error("recv_from() not supported with SOCKET_STREAM!");
|
||||
ret = NSAPI_ERROR_UNSUPPORTED;
|
||||
} else if (!socket->data_available()) {
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
} else {
|
||||
ret = socket->data_copy_and_free(buffer, size, address, false);
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
tr_debug("socket_recvfrom(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_bind(void *handle, const SocketAddress &address)
|
||||
{
|
||||
// Validate parameters
|
||||
NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
|
||||
if (NULL == handle) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
ns_address_t ns_address;
|
||||
ns_address.type = ADDRESS_IPV6;
|
||||
memset(ns_address.address, 0, sizeof ns_address.address);
|
||||
ns_address.identifier = address.get_port();
|
||||
int ret = NSAPI_ERROR_DEVICE_ERROR;
|
||||
if (0 == ::socket_bind(socket->socket_id, &ns_address)) {
|
||||
socket->set_bound();
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
tr_debug("socket_bind(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *NanostackInterface::get_ip_address()
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
const char *ret = NULL;
|
||||
if (mesh_api && mesh_api->getOwnIpAddress(ip_addr_str, sizeof ip_addr_str)) {
|
||||
ret = ip_addr_str;
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *NanostackInterface::get_mac_address()
|
||||
{
|
||||
return mac_addr_str;
|
||||
}
|
||||
|
||||
int NanostackInterface::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int NanostackInterface::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_listen(void *handle, int backlog)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_connect(void *handle, const SocketAddress &addr)
|
||||
{
|
||||
// Validate parameters
|
||||
NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
|
||||
if (NULL == handle) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
int ret;
|
||||
ns_address_t ns_addr;
|
||||
int random_port = socket->is_bound() ? 0 : 1;
|
||||
convert_mbed_addr_to_ns(&ns_addr, &addr);
|
||||
if (0 == ::socket_connect(socket->socket_id, &ns_addr, random_port)) {
|
||||
socket->set_connecting(&ns_addr);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
tr_debug("socket_connect(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_accept(void **handle, void *server)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_send(void *handle, const void *p, unsigned size)
|
||||
{
|
||||
// Validate parameters
|
||||
NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
|
||||
if (NULL == handle) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
int ret;
|
||||
if (socket->closed()) {
|
||||
ret = NSAPI_ERROR_NO_CONNECTION;
|
||||
} else if (socket->is_connecting()) {
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
} else {
|
||||
ret = ::socket_sendto(socket->socket_id, &socket->ns_address, (uint8_t*)p, size);
|
||||
/*
|
||||
* \return 0 on success.
|
||||
* \return -1 invalid socket id.
|
||||
* \return -2 Socket memory allocation fail.
|
||||
* \return -3 TCP state not established.
|
||||
* \return -4 Socket tx process busy.
|
||||
* \return -5 TLS authentication not ready.
|
||||
* \return -6 Packet too short.
|
||||
* */
|
||||
if (-4 == ret) {
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
} else if (ret != 0) {
|
||||
tr_warning("socket_sendto ret %i, socket_id %i", ret, socket->socket_id);
|
||||
ret = NSAPI_ERROR_DEVICE_ERROR;
|
||||
} else {
|
||||
ret = size;
|
||||
}
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
tr_debug("socket_send(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NanostackInterface::socket_recv(void *handle, void *data, unsigned size)
|
||||
{
|
||||
// Validate parameters
|
||||
NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
|
||||
if (NULL == handle) {
|
||||
MBED_ASSERT(false);
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
int ret;
|
||||
if (socket->closed()) {
|
||||
ret = NSAPI_ERROR_NO_CONNECTION;
|
||||
} else if (socket->data_available()) {
|
||||
ret = socket->data_copy_and_free(data, size, NULL, true);
|
||||
} else {
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
tr_debug("socket_recv(socket=%p) sock_id=%d, ret=%i", socket, socket->socket_id, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void NanostackInterface::socket_attach(void *handle, void (*callback)(void *), void *id)
|
||||
{
|
||||
// Validate parameters
|
||||
NanostackSocket * socket = static_cast<NanostackSocket *>(handle);
|
||||
if (NULL == handle) {
|
||||
MBED_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
socket->callback = callback;
|
||||
socket->callback_data = id;
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
tr_debug("socket_attach(socket=%p) sock_id=%d", socket, socket->socket_id);
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (c) 2016 ARM Limited. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef NANOSTACK_INTERFACE_H_
|
||||
#define NANOSTACK_INTERFACE_H_
|
||||
|
||||
#include "NetworkStack.h"
|
||||
#include "MeshInterface.h"
|
||||
|
||||
#include "mbed-mesh-api/Mesh6LoWPAN_ND.h"
|
||||
#include "mbed-mesh-api/MeshThread.h"
|
||||
|
||||
class NanostackInterface : public MeshInterface, public NetworkStack {
|
||||
public:
|
||||
int disconnect();
|
||||
|
||||
/** Get the internally stored IP address
|
||||
/return IP address of the interface or null if not yet connected
|
||||
*/
|
||||
const char *get_ip_address();
|
||||
|
||||
/** Get the internally stored MAC address
|
||||
/return MAC address of the interface
|
||||
*/
|
||||
const char *get_mac_address();
|
||||
|
||||
protected:
|
||||
|
||||
/** 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(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
|
||||
*/
|
||||
virtual int socket_close(void *handle);
|
||||
|
||||
/** 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(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
|
||||
*/
|
||||
virtual 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
|
||||
*/
|
||||
virtual 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 sockey
|
||||
* @param server Socket handle to server to accept from
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual 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
|
||||
*/
|
||||
virtual 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
|
||||
*/
|
||||
virtual 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
|
||||
*/
|
||||
virtual 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
|
||||
*/
|
||||
virtual 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
|
||||
*/
|
||||
virtual void socket_attach(void *handle, 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 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(void *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(void *handle, int level, int optname, void *optval, unsigned *optlen);
|
||||
|
||||
protected:
|
||||
int register_rf();
|
||||
int actual_connect();
|
||||
|
||||
virtual AbstractMesh *get_mesh_api() const = 0;
|
||||
void mesh_network_handler(mesh_connection_status_t status);
|
||||
AbstractMesh *mesh_api;
|
||||
int8_t rf_device_id;
|
||||
uint8_t eui64[8];
|
||||
char ip_addr_str[40];
|
||||
char mac_addr_str[24];
|
||||
};
|
||||
|
||||
class LoWPANNDInterface : public NanostackInterface {
|
||||
public:
|
||||
int connect();
|
||||
protected:
|
||||
Mesh6LoWPAN_ND *get_mesh_api() const { return static_cast<Mesh6LoWPAN_ND *>(mesh_api); }
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class ThreadInterface : public NanostackInterface {
|
||||
public:
|
||||
int connect();
|
||||
protected:
|
||||
MeshThread *get_mesh_api() const { return static_cast<MeshThread *>(mesh_api); }
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* NANOSTACK_INTERFACE_H_ */
|
|
@ -1 +1 @@
|
|||
https://github.com/ARMmbed/nanostack-libservice-mirror.git/#e3f7da74a143
|
||||
https://github.com/ARMmbed/nanostack-libservice-mirror/#5490767fc3f8b9f204be20f88456f63a84810d06
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
https://github.com/ARMmbed/sal-iface-6lowpan-morpheus-private-mirror.git/#2b4852e22679
|
|
@ -1 +1 @@
|
|||
https://github.com/ARMmbed/sal-stack-nanostack-eventloop-mirror.git/#627b9769e352
|
||||
https://github.com/ARMmbed/sal-stack-nanostack-eventloop-mirror/#dcbeaf4babf7d74d252e905fd15d1d63bbaaf9c2
|
||||
|
|
|
@ -1 +1 @@
|
|||
https://github.com/ARMmbed/sal-stack-nanostack-private-mirror.git/#1374c77b03fb
|
||||
https://github.com/ARMmbed/sal-stack-nanostack-private-mirror/#c83ddc4f776847d62ae3aa53d591157adc910b59
|
||||
|
|
Loading…
Reference in New Issue