mirror of https://github.com/ARMmbed/mbed-os.git
commit
9ab05ae7c5
|
@ -0,0 +1,53 @@
|
|||
/* CellularInterface
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CELLULAR_INTERFACE_H
|
||||
#define CELLULAR_INTERFACE_H
|
||||
|
||||
#include "network-socket/NetworkInterface.h"
|
||||
|
||||
|
||||
/** CellularInterface class
|
||||
*
|
||||
* Common interface that is shared between ethernet hardware
|
||||
*/
|
||||
class CellularInterface : public NetworkInterface
|
||||
{
|
||||
public:
|
||||
/** Start the interface
|
||||
*
|
||||
* @param apn Optional name of the network to connect to
|
||||
* @param username Optional username for your APN
|
||||
* @param password Optional password for your APN
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int connect(const char *apn = 0, const char *username = 0, const char *password = 0) = 0;
|
||||
|
||||
/** Stop the interface
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int disconnect() = 0;
|
||||
|
||||
/** Get the local MAC address
|
||||
*
|
||||
* @return Null-terminated representation of the local MAC address
|
||||
*/
|
||||
virtual const char *get_mac_address() = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,216 @@
|
|||
/* Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "DnsQuery.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define DNS_COUNT (sizeof DNS_IPS / sizeof DNS_IPS[0])
|
||||
const char *DNS_IPS[] = {
|
||||
"8.8.8.8",
|
||||
"209.244.0.3",
|
||||
"84.200.69.80",
|
||||
"8.26.56.26",
|
||||
"208.67.222.222"
|
||||
};
|
||||
|
||||
static bool isIP(const char *host)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; host[i]; i++) {
|
||||
if (!(host[i] >= '0' && host[i] <= '9') && host[i] != '.') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ending with '.' garuntees host
|
||||
if (i > 0 && host[i-1] == '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool parseRR(uint8_t *resp, int &c, char *adr)
|
||||
{
|
||||
int n = 0;
|
||||
while((n=resp[c++]) != 0) {
|
||||
if ((n & 0xc0) != 0) {
|
||||
// This is a link
|
||||
c++;
|
||||
break;
|
||||
} else {
|
||||
// skip this segment, not interested in string domain names
|
||||
c+= n;
|
||||
}
|
||||
}
|
||||
|
||||
int TYPE = (((int)resp[c])<<8) + resp[c+1];
|
||||
int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
|
||||
int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
|
||||
|
||||
c+= 10;
|
||||
if ((CLASS == 1) && (TYPE == 1)) {
|
||||
sprintf(adr,"%d.%d.%d.%d", resp[c], resp[c+1], resp[c+2], resp[c+3]);
|
||||
c+= RDLENGTH;
|
||||
return true;
|
||||
}
|
||||
c+= RDLENGTH;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool resolve(unsigned char *resp, char *ipaddress)
|
||||
{
|
||||
|
||||
int ID = (((int)resp[0]) <<8) + resp[1];
|
||||
int QR = resp[2] >>7;
|
||||
int Opcode = (resp[2]>>3) & 0x0F;
|
||||
int RCODE = (resp[3] & 0x0F);
|
||||
int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
|
||||
|
||||
if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int c = 12;
|
||||
int d;
|
||||
// Skip domain question
|
||||
while( (d=resp[c++]) != 0) {
|
||||
c+=d;
|
||||
}
|
||||
c+= 4; // skip QTYPE and QCLASS
|
||||
|
||||
// Here comes the resource record
|
||||
for (int ans = 0 ; ans < ANCOUNT; ans++) {
|
||||
if (parseRR(resp, c, ipaddress)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int32_t query(UDPSocket *socket, const SocketAddress &addr, const char *hostname, char *ipaddress)
|
||||
{
|
||||
int len = 0;
|
||||
if (hostname == NULL) {
|
||||
return false;
|
||||
}
|
||||
len = strlen(hostname);
|
||||
if ((len > 128) || (len == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int packetlen = /* size of HEADER structure */ 12 + /* size of QUESTION Structure */5 + len + 1;
|
||||
uint8_t *packet = new uint8_t[packetlen]; /* this is the UDP packet to send to the DNS */
|
||||
if (packet == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill the header
|
||||
memset(packet, 0, packetlen);
|
||||
packet[1] = 1; // ID = 1
|
||||
packet[5] = 1; // QDCOUNT = 1 (contains one question)
|
||||
packet[2] = 1; // recursion requested
|
||||
|
||||
int c = 13; // point to NAME element in question section or request
|
||||
int cnt = 12; // points to the counter of
|
||||
packet[cnt] = 0;
|
||||
for (int i = 0 ; i < len ; i++) {
|
||||
if (hostname[i] != '.') {
|
||||
// Copy the character and increment the character counter
|
||||
packet[cnt]++;
|
||||
packet[c++] = hostname[i];
|
||||
} else {
|
||||
// Finished with this part, so go to the next
|
||||
cnt = c++;
|
||||
packet[cnt] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate this domain name with a zero entry
|
||||
packet[c++] = 0;
|
||||
|
||||
// Set QTYPE
|
||||
packet[c++] = 0;
|
||||
packet[c++] = 1;
|
||||
// Set QCLASS
|
||||
packet[c++] = 0;
|
||||
packet[c++] = 1;
|
||||
|
||||
|
||||
if (socket->sendto(addr, packet, packetlen) < 0) {
|
||||
delete packet;
|
||||
return false;
|
||||
}
|
||||
delete packet;
|
||||
|
||||
packet = new uint8_t [1024];
|
||||
|
||||
// Receive the answer from DNS
|
||||
int response_length = 0;
|
||||
response_length = socket->recvfrom(NULL, packet, 1024);
|
||||
|
||||
if (response_length > 0 ) {
|
||||
if (!resolve(packet, ipaddress)) {
|
||||
delete packet;
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
||||
// cleanup and return
|
||||
delete packet;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delete packet;
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
||||
int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip)
|
||||
{
|
||||
if (isIP(host)) {
|
||||
strcpy(ip, host);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UDPSocket sock(iface);
|
||||
|
||||
for (unsigned i = 0; i < DNS_COUNT; i++) {
|
||||
return query(&sock, SocketAddress(DNS_IPS[0], 53), host, ip);
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
||||
int32_t dnsQuery(UDPSocket *socket, const char *host, char *ip)
|
||||
{
|
||||
if (isIP(host)) {
|
||||
strcpy(ip, host);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < DNS_COUNT; i++) {
|
||||
return query(socket, SocketAddress(DNS_IPS[0], 53), host, ip);
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __DNSQUERY_H__
|
||||
#define __DNSQUERY_H__
|
||||
|
||||
#include "NetworkStack.h"
|
||||
#include "UDPSocket.h"
|
||||
|
||||
|
||||
/** Function dnsQuery implements the functionality to query a domain name
|
||||
* server for an IP-Address of a given hostname.
|
||||
* @param iface : Network interface to use for DNS resolution.
|
||||
* @param sock : Previously opened socket to use for DNS resolution.
|
||||
* @param hostname : The hostname of interest as a string.
|
||||
* Format must be without http:// or www. IE google.com, mbed.org, etc.
|
||||
* If a standard IP Address is passed, it will be copied into ip unmodified.
|
||||
* @param ipaddress : A reference to a IPADDRESS_t object which will receive
|
||||
* the resolved IP Address of the host in question.
|
||||
* @returns 0 on succes, NS_DNS_FAILURE if host is not found,
|
||||
* or a negative value for other errors.
|
||||
*/
|
||||
int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip);
|
||||
int32_t dnsQuery(UDPSocket *sock, const char *host, char *ip);
|
||||
|
||||
|
||||
#endif // __DNSQUERY_H__
|
|
@ -0,0 +1,50 @@
|
|||
/* EthInterface
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ETH_INTERFACE_H
|
||||
#define ETH_INTERFACE_H
|
||||
|
||||
#include "network-socket/NetworkInterface.h"
|
||||
|
||||
|
||||
/** EthInterface class
|
||||
*
|
||||
* Common interface that is shared between ethernet hardware.
|
||||
*/
|
||||
class EthInterface : public NetworkInterface
|
||||
{
|
||||
public:
|
||||
/** Start the interface
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int connect() = 0;
|
||||
|
||||
/** Stop the interface
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int disconnect() = 0;
|
||||
|
||||
/** Get the local MAC address
|
||||
*
|
||||
* @return Null-terminated representation of the local MAC address
|
||||
*/
|
||||
virtual const char *get_mac_address() = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
/* MeshInterface
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MESH_INTERFACE_H
|
||||
#define MESH_INTERFACE_H
|
||||
|
||||
#include "network-socket/NetworkInterface.h"
|
||||
|
||||
|
||||
/** MeshInterface class
|
||||
*
|
||||
* Common interface that is shared between mesh hardware
|
||||
*/
|
||||
class MeshInterface : public NetworkInterface
|
||||
{
|
||||
public:
|
||||
/** Start the interface
|
||||
*
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int connect() = 0;
|
||||
|
||||
/** Stop the interface
|
||||
*
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int disconnect() = 0;
|
||||
|
||||
/** Get the local MAC address
|
||||
*
|
||||
* @return Null-terminated representation of the local MAC address
|
||||
*/
|
||||
virtual const char *get_mac_address() = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
/* NetworkStack
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NETWORK_INTERFACE_H
|
||||
#define NETWORK_INTERFACE_H
|
||||
|
||||
// Predeclared class
|
||||
class NetworkStack;
|
||||
|
||||
|
||||
/** NetworkInterface class
|
||||
*
|
||||
* Common interface that is shared between network devices
|
||||
*/
|
||||
class NetworkInterface {
|
||||
public:
|
||||
virtual ~NetworkInterface() {};
|
||||
|
||||
/** Get the local IP address
|
||||
*
|
||||
* @return Null-terminated representation of the local IP address
|
||||
* or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address() = 0;
|
||||
|
||||
protected:
|
||||
friend class Socket;
|
||||
friend class UDPSocket;
|
||||
friend class TCPSocket;
|
||||
friend class TCPServer;
|
||||
friend class SocketAddress;
|
||||
template <typename IF>
|
||||
friend NetworkStack *nsapi_create_stack(IF *iface);
|
||||
|
||||
/** Provide access to the NetworkStack object
|
||||
*
|
||||
* @return The underlying NetworkStack object
|
||||
*/
|
||||
virtual NetworkStack *get_stack() = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,257 @@
|
|||
/* Socket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NetworkStack.h"
|
||||
#include "DnsQuery.h"
|
||||
#include "mbed.h"
|
||||
#include "stddef.h"
|
||||
#include <new>
|
||||
|
||||
|
||||
// Default NetworkStack operations
|
||||
int NetworkStack::gethostbyname(SocketAddress *address, const char *name)
|
||||
{
|
||||
char buffer[NSAPI_IP_SIZE];
|
||||
int err = dnsQuery(this, name, buffer);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
address->set_ip_address(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetworkStack::setstackopt(int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int NetworkStack::getstackopt(int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int NetworkStack::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int NetworkStack::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
// NetworkStackWrapper class for encapsulating the raw nsapi_stack structure
|
||||
class NetworkStackWrapper : public NetworkStack
|
||||
{
|
||||
private:
|
||||
inline nsapi_stack_t *_stack()
|
||||
{
|
||||
return reinterpret_cast<nsapi_stack_t *>(
|
||||
reinterpret_cast<uint8_t *>(this)
|
||||
- offsetof(nsapi_stack_t, _stack_buffer));
|
||||
}
|
||||
|
||||
inline const nsapi_stack_api_t *_stack_api()
|
||||
{
|
||||
return _stack()->stack_api;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual const char *get_ip_address()
|
||||
{
|
||||
if (!_stack_api()->get_ip_address) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t buffer[sizeof(SocketAddress)];
|
||||
SocketAddress *address = new (buffer) SocketAddress(_stack_api()->get_ip_address(_stack()));
|
||||
return address->get_ip_address();
|
||||
}
|
||||
|
||||
virtual int gethostbyname(SocketAddress *address, const char *name)
|
||||
{
|
||||
if (!_stack_api()->gethostbyname) {
|
||||
return NetworkStack::gethostbyname(address, name);
|
||||
}
|
||||
|
||||
nsapi_addr_t addr = {NSAPI_IPv4, 0};
|
||||
int err = _stack_api()->gethostbyname(_stack(), &addr, name);
|
||||
address->set_addr(addr);
|
||||
return err;
|
||||
}
|
||||
|
||||
virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
if (!_stack_api()->setstackopt) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->setstackopt(_stack(), level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
virtual int getstackopt(int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
if (!_stack_api()->getstackopt) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->getstackopt(_stack(), level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int socket_open(nsapi_socket_t *socket, nsapi_protocol_t proto)
|
||||
{
|
||||
if (!_stack_api()->socket_open) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_open(_stack(), socket, proto);
|
||||
}
|
||||
|
||||
virtual int socket_close(nsapi_socket_t socket)
|
||||
{
|
||||
if (!_stack_api()->socket_close) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_close(_stack(), socket);
|
||||
}
|
||||
|
||||
virtual int socket_bind(nsapi_socket_t socket, const SocketAddress &address)
|
||||
{
|
||||
if (!_stack_api()->socket_bind) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_bind(_stack(), socket, address.get_addr(), address.get_port());
|
||||
}
|
||||
|
||||
virtual int socket_listen(nsapi_socket_t socket, int backlog)
|
||||
{
|
||||
if (!_stack_api()->socket_listen) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_listen(_stack(), socket, backlog);
|
||||
}
|
||||
|
||||
virtual int socket_connect(nsapi_socket_t socket, const SocketAddress &address)
|
||||
{
|
||||
if (!_stack_api()->socket_connect) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_connect(_stack(), socket, address.get_addr(), address.get_port());
|
||||
}
|
||||
|
||||
virtual int socket_accept(nsapi_socket_t *socket, nsapi_socket_t server)
|
||||
{
|
||||
if (!_stack_api()->socket_accept) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_accept(_stack(), socket, server);
|
||||
}
|
||||
|
||||
virtual int socket_send(nsapi_socket_t socket, const void *data, unsigned size)
|
||||
{
|
||||
if (!_stack_api()->socket_send) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_send(_stack(), socket, data, size);
|
||||
}
|
||||
|
||||
virtual int socket_recv(nsapi_socket_t socket, void *data, unsigned size)
|
||||
{
|
||||
if (!_stack_api()->socket_recv) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_recv(_stack(), socket, data, size);
|
||||
}
|
||||
|
||||
virtual int socket_sendto(nsapi_socket_t socket, const SocketAddress &address, const void *data, unsigned size)
|
||||
{
|
||||
if (!_stack_api()->socket_sendto) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_sendto(_stack(), socket, address.get_addr(), address.get_port(), data, size);
|
||||
}
|
||||
|
||||
virtual int socket_recvfrom(nsapi_socket_t socket, SocketAddress *address, void *data, unsigned size)
|
||||
{
|
||||
if (!_stack_api()->socket_recvfrom) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_addr_t addr = {NSAPI_IPv4, 0};
|
||||
uint16_t port = 0;
|
||||
|
||||
int err = _stack_api()->socket_recvfrom(_stack(), socket, &addr, &port, data, size);
|
||||
|
||||
if (address) {
|
||||
address->set_addr(addr);
|
||||
address->set_port(port);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
virtual void socket_attach(nsapi_socket_t socket, void (*callback)(void *), void *data)
|
||||
{
|
||||
if (!_stack_api()->socket_attach) {
|
||||
return;
|
||||
}
|
||||
|
||||
return _stack_api()->socket_attach(_stack(), socket, callback, data);
|
||||
}
|
||||
|
||||
virtual int setsockopt(nsapi_socket_t socket, int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
if (!_stack_api()->setsockopt) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->setsockopt(_stack(), socket, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
virtual int getsockopt(nsapi_socket_t socket, int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
if (!_stack_api()->getsockopt) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return _stack_api()->getsockopt(_stack(), socket, level, optname, optval, optlen);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Conversion function for network stacks
|
||||
NetworkStack *nsapi_create_stack(nsapi_stack_t *stack)
|
||||
{
|
||||
MBED_ASSERT(sizeof stack->_stack_buffer >= sizeof(NetworkStackWrapper));
|
||||
return new (stack->_stack_buffer) NetworkStackWrapper;
|
||||
}
|
||||
|
||||
NetworkStack *nsapi_create_stack(NetworkStack *stack)
|
||||
{
|
||||
return stack;
|
||||
}
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
/* NetworkStack
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NETWORK_STACK_H
|
||||
#define NETWORK_STACK_H
|
||||
|
||||
#include "nsapi_types.h"
|
||||
#include "network-socket/SocketAddress.h"
|
||||
#include "network-socket/NetworkInterface.h"
|
||||
|
||||
|
||||
/** NetworkStack class
|
||||
*
|
||||
* Common interface that is shared between hardware that
|
||||
* can connect to a network over IP. By implementing the
|
||||
* NetworkStack, a network stack can be used as a target
|
||||
* for instantiating network sockets.
|
||||
*/
|
||||
class NetworkStack
|
||||
{
|
||||
public:
|
||||
virtual ~NetworkStack() {};
|
||||
|
||||
/** Get the local IP address
|
||||
*
|
||||
* @return Null-terminated representation of the local IP address
|
||||
* or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address() = 0;
|
||||
|
||||
/** Translates a hostname to an IP address
|
||||
*
|
||||
* The hostname may be either a domain name or an IP address. If the
|
||||
* hostname is an IP address, no network transactions will be performed.
|
||||
*
|
||||
* If no stack-specific DNS resolution is provided, the hostname
|
||||
* will be resolve using a UDP socket on the stack.
|
||||
*
|
||||
* @param address Destination for the host SocketAddress
|
||||
* @param host Hostname to resolve
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int gethostbyname(SocketAddress *address, const char *host);
|
||||
|
||||
/* Set stack-specific stack options
|
||||
*
|
||||
* The setstackopt allow an application to pass stack-specific hints
|
||||
* to the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and the stack is unmodified.
|
||||
*
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen);
|
||||
|
||||
/* Get stack-specific stack options
|
||||
*
|
||||
* The getstackopt allow an application to retrieve stack-specific hints
|
||||
* from the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
|
||||
*
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Destination for option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int getstackopt(int level, int optname, void *optval, unsigned *optlen);
|
||||
|
||||
protected:
|
||||
friend class Socket;
|
||||
friend class UDPSocket;
|
||||
friend class TCPSocket;
|
||||
friend class TCPServer;
|
||||
|
||||
/** Opens a socket
|
||||
*
|
||||
* Creates a network socket and stores it in the specified handle.
|
||||
* The handle must be passed to following calls on the socket.
|
||||
*
|
||||
* A stack may have a finite number of sockets, in this case
|
||||
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
|
||||
*
|
||||
* @param handle Destination for the handle to a newly created socket
|
||||
* @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto) = 0;
|
||||
|
||||
/** Close the socket
|
||||
*
|
||||
* Closes any open connection and deallocates any memory associated
|
||||
* with the socket.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int socket_close(nsapi_socket_t handle) = 0;
|
||||
|
||||
/** Bind a specific address to a socket
|
||||
*
|
||||
* Binding a socket specifies the address and port on which to recieve
|
||||
* data. If the IP address is zeroed, only the port is bound.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param address Local address to bind
|
||||
* @return 0 on success, negative error code on failure.
|
||||
*/
|
||||
virtual int socket_bind(nsapi_socket_t handle, const SocketAddress &address) = 0;
|
||||
|
||||
/** Listen for connections on a TCP socket
|
||||
*
|
||||
* Marks the socket as a passive socket that can be used to accept
|
||||
* incoming connections.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param backlog Number of pending connections that can be queued
|
||||
* simultaneously
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int socket_listen(nsapi_socket_t handle, int backlog) = 0;
|
||||
|
||||
/** Connects TCP socket to a remote host
|
||||
*
|
||||
* Initiates a connection to a remote server specified by the
|
||||
* indicated address.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param address The SocketAddress of the remote host
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int socket_connect(nsapi_socket_t handle, const SocketAddress &address) = 0;
|
||||
|
||||
/** Accepts a connection on a TCP socket
|
||||
*
|
||||
* The server socket must be bound and set to listen for connections.
|
||||
* On a new connection, creates a network socket and stores it in the
|
||||
* specified handle. The handle must be passed to following calls on
|
||||
* the socket.
|
||||
*
|
||||
* A stack may have a finite number of sockets, in this case
|
||||
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
|
||||
*
|
||||
* This call is non-blocking. If accept would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param handle Destination for a handle to the newly created sockey
|
||||
* @param server Socket handle to server to accept from
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int socket_accept(nsapi_socket_t *handle, nsapi_socket_t server) = 0;
|
||||
|
||||
/** Send data over a TCP socket
|
||||
*
|
||||
* The socket must be connected to a remote host. Returns the number of
|
||||
* bytes sent from the buffer.
|
||||
*
|
||||
* This call is non-blocking. If send would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param data Buffer of data to send to the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
virtual int socket_send(nsapi_socket_t handle, const void *data, unsigned size) = 0;
|
||||
|
||||
/** Receive data over a TCP socket
|
||||
*
|
||||
* The socket must be connected to a remote host. Returns the number of
|
||||
* bytes received into the buffer.
|
||||
*
|
||||
* This call is non-blocking. If recv would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param data Destination buffer for data received from the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of received bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
virtual int socket_recv(nsapi_socket_t handle, void *data, unsigned size) = 0;
|
||||
|
||||
/** Send a packet over a UDP socket
|
||||
*
|
||||
* Sends data to the specified address. Returns the number of bytes
|
||||
* sent from the buffer.
|
||||
*
|
||||
* This call is non-blocking. If sendto would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param address The SocketAddress of the remote host
|
||||
* @param data Buffer of data to send to the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
virtual int socket_sendto(nsapi_socket_t handle, const SocketAddress &address, const void *data, unsigned size) = 0;
|
||||
|
||||
/** Receive a packet over a UDP socket
|
||||
*
|
||||
* Receives data and stores the source address in address if address
|
||||
* is not NULL. Returns the number of bytes received into the buffer.
|
||||
*
|
||||
* This call is non-blocking. If recvfrom would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param address Destination for the source address or NULL
|
||||
* @param data Destination buffer for data received from the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of received bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
virtual int socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, void *buffer, unsigned size) = 0;
|
||||
|
||||
/** Register a callback on state change of the socket
|
||||
*
|
||||
* The specified callback will be called on state changes such as when
|
||||
* the socket can recv/send/accept successfully and on when an error
|
||||
* occurs. The callback may also be called spuriously without reason.
|
||||
*
|
||||
* The callback may be called in an interrupt context and should not
|
||||
* perform expensive operations such as recv/send calls.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param callback Function to call on state change
|
||||
* @param data Argument to pass to callback
|
||||
*/
|
||||
virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data) = 0;
|
||||
|
||||
/* Set stack-specific socket options
|
||||
*
|
||||
* The setsockopt allow an application to pass stack-specific hints
|
||||
* to the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int setsockopt(nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen);
|
||||
|
||||
/* Get stack-specific socket options
|
||||
*
|
||||
* The getstackopt allow an application to retrieve stack-specific hints
|
||||
* from the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Destination for option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen);
|
||||
};
|
||||
|
||||
|
||||
/** Convert a raw nsapi_stack_t object into a C++ NetworkStack object
|
||||
*
|
||||
* @param stack Reference to an object that can be converted to a stack
|
||||
* - A raw nsapi_stack_t object
|
||||
* - A reference to a network stack
|
||||
* - A reference to a network interface
|
||||
* @return Reference to the underlying network stack
|
||||
*/
|
||||
NetworkStack *nsapi_create_stack(nsapi_stack_t *stack);
|
||||
NetworkStack *nsapi_create_stack(NetworkStack *stack);
|
||||
|
||||
template <typename IF>
|
||||
NetworkStack *nsapi_create_stack(IF *iface)
|
||||
{
|
||||
return nsapi_create_stack(static_cast<NetworkInterface *>(iface)->get_stack());
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,157 @@
|
|||
/* Socket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Socket.h"
|
||||
|
||||
Socket::Socket()
|
||||
: _stack(0)
|
||||
, _socket(0)
|
||||
, _timeout(osWaitForever)
|
||||
{
|
||||
}
|
||||
|
||||
int Socket::open(NetworkStack *stack)
|
||||
{
|
||||
_lock.lock();
|
||||
|
||||
if (_stack != NULL || stack == NULL) {
|
||||
_lock.unlock();
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
_stack = stack;
|
||||
|
||||
nsapi_socket_t socket;
|
||||
int err = _stack->socket_open(&socket, get_proto());
|
||||
if (err) {
|
||||
_lock.unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
_socket = socket;
|
||||
_event.attach(this, &Socket::event);
|
||||
_stack->socket_attach(_socket, Callback<void()>::thunk, &_event);
|
||||
|
||||
_lock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Socket::close()
|
||||
{
|
||||
_lock.lock();
|
||||
|
||||
int ret = 0;
|
||||
if (_socket) {
|
||||
_stack->socket_attach(_socket, 0, 0);
|
||||
nsapi_socket_t socket = _socket;
|
||||
_socket = 0;
|
||||
ret = _stack->socket_close(socket);
|
||||
}
|
||||
|
||||
// Wakeup anything in a blocking operation
|
||||
// on this socket
|
||||
event();
|
||||
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Socket::bind(uint16_t port)
|
||||
{
|
||||
// Underlying bind is thread safe
|
||||
SocketAddress addr(0, port);
|
||||
return bind(addr);
|
||||
}
|
||||
|
||||
int Socket::bind(const char *address, uint16_t port)
|
||||
{
|
||||
// Underlying bind is thread safe
|
||||
SocketAddress addr(address, port);
|
||||
return bind(addr);
|
||||
}
|
||||
|
||||
int Socket::bind(const SocketAddress &address)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
} else {
|
||||
ret = _stack->socket_bind(_socket, address);
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Socket::set_blocking(bool blocking)
|
||||
{
|
||||
// Socket::set_timeout is thread safe
|
||||
set_timeout(blocking ? -1 : 0);
|
||||
}
|
||||
|
||||
void Socket::set_timeout(int timeout)
|
||||
{
|
||||
_lock.lock();
|
||||
|
||||
if (timeout >= 0) {
|
||||
_timeout = (uint32_t)timeout;
|
||||
} else {
|
||||
_timeout = osWaitForever;
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
int Socket::setsockopt(int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
} else {
|
||||
ret = _stack->setsockopt(_socket, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Socket::getsockopt(int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
} else {
|
||||
ret = _stack->getsockopt(_socket, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void Socket::attach(Callback<void()> callback)
|
||||
{
|
||||
_lock.lock();
|
||||
|
||||
_callback = callback;
|
||||
|
||||
_lock.unlock();
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
/* Socket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SOCKET_H
|
||||
#define SOCKET_H
|
||||
|
||||
#include "network-socket/SocketAddress.h"
|
||||
#include "network-socket/NetworkStack.h"
|
||||
#include "rtos/Mutex.h"
|
||||
#include "Callback.h"
|
||||
|
||||
#ifndef NSAPI_NO_INCLUDE_MBED
|
||||
#include "mbed.h" // needed for backwards compatability
|
||||
#endif
|
||||
|
||||
|
||||
/** Abstract socket class
|
||||
*/
|
||||
class Socket {
|
||||
public:
|
||||
/** Destroy a socket
|
||||
*
|
||||
* Closes socket if the socket is still open
|
||||
*/
|
||||
virtual ~Socket() {}
|
||||
|
||||
/** Opens a socket
|
||||
*
|
||||
* Creates a network socket on the network stack of the given
|
||||
* network interface. Not needed if stack is passed to the
|
||||
* socket's constructor.
|
||||
*
|
||||
* @param stack Network stack as target for socket
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int open(NetworkStack *stack);
|
||||
|
||||
template <typename S>
|
||||
int open(S *stack) {
|
||||
return open(nsapi_create_stack(stack));
|
||||
}
|
||||
|
||||
/** Close the socket
|
||||
*
|
||||
* Closes any open connection and deallocates any memory associated
|
||||
* with the socket. Called from destructor if socket is not closed.
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int close();
|
||||
|
||||
/** Bind a specific address to a socket
|
||||
*
|
||||
* Binding a socket specifies the address and port on which to recieve
|
||||
* data.
|
||||
*
|
||||
* @param port Local port to bind
|
||||
* @return 0 on success, negative error code on failure.
|
||||
*/
|
||||
int bind(uint16_t port);
|
||||
|
||||
/** Bind a specific address to a socket
|
||||
*
|
||||
* Binding a socket specifies the address and port on which to recieve
|
||||
* data. If the IP address is zeroed, only the port is bound.
|
||||
*
|
||||
* @param address Null-terminated local address to bind
|
||||
* @param port Local port to bind
|
||||
* @return 0 on success, negative error code on failure.
|
||||
*/
|
||||
int bind(const char *address, uint16_t port);
|
||||
|
||||
/** Bind a specific address to a socket
|
||||
*
|
||||
* Binding a socket specifies the address and port on which to recieve
|
||||
* data. If the IP address is zeroed, only the port is bound.
|
||||
*
|
||||
* @param address Local address to bind
|
||||
* @return 0 on success, negative error code on failure.
|
||||
*/
|
||||
int bind(const SocketAddress &address);
|
||||
|
||||
/** Set blocking or non-blocking mode of the socket
|
||||
*
|
||||
* Initially all sockets are in blocking mode. In non-blocking mode
|
||||
* blocking operations such as send/recv/accept return
|
||||
* NSAPI_ERROR_WOULD_BLOCK if they can not continue.
|
||||
*
|
||||
* set_blocking(false) is equivalent to set_timeout(-1)
|
||||
* set_blocking(true) is equivalent to set_timeout(0)
|
||||
*
|
||||
* @param blocking true for blocking mode, false for non-blocking mode.
|
||||
*/
|
||||
void set_blocking(bool blocking);
|
||||
|
||||
/** Set timeout on blocking socket operations
|
||||
*
|
||||
* Initially all sockets have unbounded timeouts. NSAPI_ERROR_WOULD_BLOCK
|
||||
* is returned if a blocking operation takes longer than the specified
|
||||
* timeout. A timeout of 0 removes the timeout from the socket. A negative
|
||||
* value give the socket an unbounded timeout.
|
||||
*
|
||||
* set_timeout(0) is equivalent to set_blocking(false)
|
||||
* set_timeout(-1) is equivalent to set_blocking(true)
|
||||
*
|
||||
* @param timeout Timeout in milliseconds
|
||||
*/
|
||||
void set_timeout(int timeout);
|
||||
|
||||
/* Set stack-specific socket options
|
||||
*
|
||||
* The setsockopt allow an application to pass stack-specific hints
|
||||
* to the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
|
||||
*
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int setsockopt(int level, int optname, const void *optval, unsigned optlen);
|
||||
|
||||
/* Get stack-specific socket options
|
||||
*
|
||||
* The getstackopt allow an application to retrieve stack-specific hints
|
||||
* from the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
|
||||
*
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Destination for option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int getsockopt(int level, int optname, void *optval, unsigned *optlen);
|
||||
|
||||
/** Register a callback on state change of the socket
|
||||
*
|
||||
* The specified callback will be called on state changes such as when
|
||||
* the socket can recv/send/accept successfully and on when an error
|
||||
* occurs. The callback may also be called spuriously without reason.
|
||||
*
|
||||
* The callback may be called in an interrupt context and should not
|
||||
* perform expensive operations such as recv/send calls.
|
||||
*
|
||||
* @param func Function to call on state change
|
||||
*/
|
||||
void attach(mbed::Callback<void()> func);
|
||||
|
||||
/** Register a callback on state change of the socket
|
||||
*
|
||||
* The specified callback will be called on state changes such as when
|
||||
* the socket can recv/send/accept successfully and on when an error
|
||||
* occurs. The callback may also be called spuriously without reason.
|
||||
*
|
||||
* The callback may be called in an interrupt context and should not
|
||||
* perform expensive operations such as recv/send calls.
|
||||
*
|
||||
* @param obj Pointer to object to call method on
|
||||
* @param method Method to call on state change
|
||||
*/
|
||||
template <typename T, typename M>
|
||||
void attach(T *obj, M method) {
|
||||
attach(mbed::Callback<void()>(obj, method));
|
||||
}
|
||||
|
||||
protected:
|
||||
Socket();
|
||||
virtual nsapi_protocol_t get_proto() = 0;
|
||||
virtual void event() = 0;
|
||||
|
||||
NetworkStack *_stack;
|
||||
nsapi_socket_t _socket;
|
||||
uint32_t _timeout;
|
||||
mbed::Callback<void()> _event;
|
||||
mbed::Callback<void()> _callback;
|
||||
rtos::Mutex _lock;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,282 @@
|
|||
/* Socket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SocketAddress.h"
|
||||
#include "NetworkInterface.h"
|
||||
#include "NetworkStack.h"
|
||||
#include <string.h>
|
||||
#include "mbed.h"
|
||||
|
||||
|
||||
static bool ipv4_is_valid(const char *addr)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// Check each digit for [0-9.]
|
||||
for (; addr[i]; i++) {
|
||||
if (!(addr[i] >= '0' && addr[i] <= '9') && addr[i] != '.') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ending with '.' garuntees host
|
||||
if (i > 0 && addr[i-1] == '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ipv6_is_valid(const char *addr)
|
||||
{
|
||||
// Check each digit for [0-9a-fA-F:]
|
||||
for (int i = 0; addr[i]; i++) {
|
||||
if (!(addr[i] >= '0' && addr[i] <= '9') &&
|
||||
!(addr[i] >= 'a' && addr[i] <= 'f') &&
|
||||
!(addr[i] >= 'A' && addr[i] <= 'F') &&
|
||||
addr[i] != ':') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ipv4_from_address(uint8_t *bytes, const char *addr)
|
||||
{
|
||||
int count = 0;
|
||||
int i = 0;
|
||||
|
||||
for (; count < NSAPI_IPv4_BYTES; count++) {
|
||||
int scanned = sscanf(&addr[i], "%hhu", &bytes[count]);
|
||||
if (scanned < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (; addr[i] != '.'; i++) {
|
||||
if (!addr[i]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) {
|
||||
int count = 0;
|
||||
int i = 0;
|
||||
|
||||
for (; count < NSAPI_IPv6_BYTES/2; count++) {
|
||||
int scanned = sscanf(&chunk[i], "%hx", &shorts[count]);
|
||||
if (scanned < 1) {
|
||||
return count;
|
||||
}
|
||||
|
||||
for (; chunk[i] != ':'; i++) {
|
||||
if (!chunk[i]) {
|
||||
return count+1;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void ipv6_from_address(uint8_t *bytes, const char *addr)
|
||||
{
|
||||
// Start with zeroed address
|
||||
uint16_t shorts[NSAPI_IPv6_BYTES/2];
|
||||
memset(shorts, 0, sizeof shorts);
|
||||
|
||||
int suffix = 0;
|
||||
|
||||
// Find double colons and scan suffix
|
||||
for (int i = 0; addr[i]; i++) {
|
||||
if (addr[i] == ':' && addr[i+1] == ':') {
|
||||
suffix = ipv6_scan_chunk(shorts, &addr[i+2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Move suffix to end
|
||||
memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0],
|
||||
suffix*sizeof(uint16_t));
|
||||
|
||||
// Scan prefix
|
||||
ipv6_scan_chunk(shorts, &addr[0]);
|
||||
|
||||
// Flip bytes
|
||||
for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
|
||||
bytes[2*i+0] = (uint8_t)(shorts[i] >> 8);
|
||||
bytes[2*i+1] = (uint8_t)(shorts[i] >> 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void ipv4_to_address(char *addr, const uint8_t *bytes)
|
||||
{
|
||||
sprintf(addr, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
|
||||
}
|
||||
|
||||
static void ipv6_to_address(char *addr, const uint8_t *bytes)
|
||||
{
|
||||
for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
|
||||
sprintf(&addr[5*i], "%02x%02x", bytes[2*i], bytes[2*i+1]);
|
||||
addr[5*i+4] = ':';
|
||||
}
|
||||
addr[NSAPI_IPv6_SIZE-1] = '\0';
|
||||
}
|
||||
|
||||
|
||||
SocketAddress::SocketAddress(nsapi_addr_t addr, uint16_t port)
|
||||
{
|
||||
_ip_address[0] = '\0';
|
||||
set_addr(addr);
|
||||
set_port(port);
|
||||
}
|
||||
|
||||
SocketAddress::SocketAddress(const char *addr, uint16_t port)
|
||||
{
|
||||
_ip_address[0] = '\0';
|
||||
set_ip_address(addr);
|
||||
set_port(port);
|
||||
}
|
||||
|
||||
SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port)
|
||||
{
|
||||
_ip_address[0] = '\0';
|
||||
set_ip_bytes(bytes, version);
|
||||
set_port(port);
|
||||
}
|
||||
|
||||
SocketAddress::SocketAddress(const SocketAddress &addr)
|
||||
{
|
||||
_ip_address[0] = '\0';
|
||||
set_addr(addr.get_addr());
|
||||
set_port(addr.get_port());
|
||||
}
|
||||
|
||||
void SocketAddress::set_ip_address(const char *addr)
|
||||
{
|
||||
_ip_address[0] = '\0';
|
||||
|
||||
if (addr && ipv4_is_valid(addr)) {
|
||||
_addr.version = NSAPI_IPv4;
|
||||
ipv4_from_address(_addr.bytes, addr);
|
||||
} else if (addr && ipv6_is_valid(addr)) {
|
||||
_addr.version = NSAPI_IPv6;
|
||||
ipv6_from_address(_addr.bytes, addr);
|
||||
} else {
|
||||
_addr = (nsapi_addr_t){};
|
||||
}
|
||||
}
|
||||
|
||||
void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version)
|
||||
{
|
||||
nsapi_addr_t addr;
|
||||
addr.version = version;
|
||||
memcpy(addr.bytes, bytes, NSAPI_IP_BYTES);
|
||||
set_addr(addr);
|
||||
}
|
||||
|
||||
void SocketAddress::set_addr(nsapi_addr_t addr)
|
||||
{
|
||||
_ip_address[0] = '\0';
|
||||
_addr = addr;
|
||||
}
|
||||
|
||||
void SocketAddress::set_port(uint16_t port)
|
||||
{
|
||||
_port = port;
|
||||
}
|
||||
|
||||
const char *SocketAddress::get_ip_address() const
|
||||
{
|
||||
char *ip_address = (char *)_ip_address;
|
||||
|
||||
if (!ip_address[0]) {
|
||||
if (_addr.version == NSAPI_IPv4) {
|
||||
ipv4_to_address(ip_address, _addr.bytes);
|
||||
} else if (_addr.version == NSAPI_IPv6) {
|
||||
ipv6_to_address(ip_address, _addr.bytes);
|
||||
}
|
||||
}
|
||||
|
||||
return ip_address;
|
||||
}
|
||||
|
||||
const void *SocketAddress::get_ip_bytes() const
|
||||
{
|
||||
return _addr.bytes;
|
||||
}
|
||||
|
||||
nsapi_version_t SocketAddress::get_ip_version() const
|
||||
{
|
||||
return _addr.version;
|
||||
}
|
||||
|
||||
nsapi_addr_t SocketAddress::get_addr() const
|
||||
{
|
||||
return _addr;
|
||||
}
|
||||
|
||||
uint16_t SocketAddress::get_port() const
|
||||
{
|
||||
return _port;
|
||||
}
|
||||
|
||||
SocketAddress::operator bool() const
|
||||
{
|
||||
int count = 0;
|
||||
if (_addr.version == NSAPI_IPv4) {
|
||||
count = NSAPI_IPv4_BYTES;
|
||||
} else if (_addr.version == NSAPI_IPv6) {
|
||||
count = NSAPI_IPv6_BYTES;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (_addr.bytes[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SocketAddress::_SocketAddress(NetworkStack *iface, const char *host, uint16_t port)
|
||||
{
|
||||
_ip_address[0] = '\0';
|
||||
|
||||
// Check for valid IP addresses
|
||||
if (host && ipv4_is_valid(host)) {
|
||||
_addr.version = NSAPI_IPv4;
|
||||
ipv4_from_address(_addr.bytes, host);
|
||||
_port = port;
|
||||
} else if (host && ipv6_is_valid(host)) {
|
||||
_addr.version = NSAPI_IPv6;
|
||||
ipv6_from_address(_addr.bytes, host);
|
||||
_port = port;
|
||||
} else {
|
||||
// DNS lookup
|
||||
int err = iface->gethostbyname(this, host);
|
||||
if (err) {
|
||||
_addr = (nsapi_addr_t){};
|
||||
_port = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/* SocketAddress
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SOCKET_ADDRESS_H
|
||||
#define SOCKET_ADDRESS_H
|
||||
|
||||
#include "nsapi_types.h"
|
||||
#include "toolchain.h"
|
||||
|
||||
// Predeclared classes
|
||||
class NetworkStack;
|
||||
class NetworkInterface;
|
||||
|
||||
|
||||
/** SocketAddress class
|
||||
*
|
||||
* Representation of an IP address and port pair.
|
||||
*/
|
||||
class SocketAddress {
|
||||
public:
|
||||
/** Create a SocketAddress from a hostname and port
|
||||
*
|
||||
* The hostname may be either a domain name or an IP address. If the
|
||||
* hostname is an IP address, no network transactions will be performed.
|
||||
*
|
||||
* On failure, the IP address and port will be set to zero
|
||||
*
|
||||
* @param stack Network stack to use for DNS resolution
|
||||
* @param host Hostname to resolve
|
||||
* @param port Optional 16-bit port
|
||||
*/
|
||||
template <typename S>
|
||||
SocketAddress(S *stack, const char *host, uint16_t port = 0)
|
||||
{
|
||||
_SocketAddress(nsapi_create_stack(stack), host, port);
|
||||
}
|
||||
|
||||
/** Create a SocketAddress from a raw IP address and port
|
||||
*
|
||||
* @param addr Raw IP address
|
||||
* @param port Optional 16-bit port
|
||||
*/
|
||||
SocketAddress(nsapi_addr_t addr = (nsapi_addr_t){}, uint16_t port = 0);
|
||||
|
||||
/** Create a SocketAddress from an IP address and port
|
||||
*
|
||||
* @param host Null-terminated representation of the IP address
|
||||
* @param port Optional 16-bit port
|
||||
*/
|
||||
SocketAddress(const char *addr, uint16_t port = 0);
|
||||
|
||||
/** Create a SocketAddress from raw IP bytes, IP version, and port
|
||||
*
|
||||
* @param bytes Raw IP address in big-endian order
|
||||
* @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6
|
||||
* @param port Optional 16-bit port
|
||||
*/
|
||||
SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port = 0);
|
||||
|
||||
/** Create a SocketAddress from another SocketAddress
|
||||
*
|
||||
* @param address SocketAddress to copy
|
||||
*/
|
||||
SocketAddress(const SocketAddress &addr);
|
||||
|
||||
/** Set the IP address
|
||||
*
|
||||
* @param addr Null-terminated represention of the IP address
|
||||
*/
|
||||
void set_ip_address(const char *addr);
|
||||
|
||||
/** Set the raw IP bytes and IP version
|
||||
*
|
||||
* @param bytes Raw IP address in big-endian order
|
||||
* @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6
|
||||
*/
|
||||
void set_ip_bytes(const void *bytes, nsapi_version_t version);
|
||||
|
||||
/** Set the raw IP address
|
||||
*
|
||||
* @param addr Raw IP address
|
||||
*/
|
||||
void set_addr(nsapi_addr_t addr);
|
||||
|
||||
/** Set the port
|
||||
*
|
||||
* @param port 16-bit port
|
||||
*/
|
||||
void set_port(uint16_t port);
|
||||
|
||||
/** Get the IP address
|
||||
*
|
||||
* @return Null-terminated representation of the IP Address
|
||||
*/
|
||||
const char *get_ip_address() const;
|
||||
|
||||
/* Get the raw IP bytes
|
||||
*
|
||||
* @return Raw IP address in big-endian order
|
||||
*/
|
||||
const void *get_ip_bytes() const;
|
||||
|
||||
/** Get the IP address version
|
||||
*
|
||||
* @return IP address version, NSAPI_IPv4 or NSAPI_IPv6
|
||||
*/
|
||||
nsapi_version_t get_ip_version() const;
|
||||
|
||||
/** Get the raw IP address
|
||||
*
|
||||
* @return Raw IP address
|
||||
*/
|
||||
nsapi_addr_t get_addr() const;
|
||||
|
||||
/** Get the port
|
||||
*
|
||||
* @return The 16-bit port
|
||||
*/
|
||||
uint16_t get_port() const;
|
||||
|
||||
/** Test if address is zero
|
||||
*
|
||||
* @return True if address is not zero
|
||||
*/
|
||||
operator bool() const;
|
||||
|
||||
private:
|
||||
void _SocketAddress(NetworkStack *iface, const char *host, uint16_t port);
|
||||
|
||||
char _ip_address[NSAPI_IP_SIZE];
|
||||
nsapi_addr_t _addr;
|
||||
uint16_t _port;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,110 @@
|
|||
/* Socket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TCPServer.h"
|
||||
#include "Timer.h"
|
||||
|
||||
TCPServer::TCPServer()
|
||||
: _pending(0), _accept_sem(0)
|
||||
{
|
||||
}
|
||||
|
||||
TCPServer::~TCPServer()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
nsapi_protocol_t TCPServer::get_proto()
|
||||
{
|
||||
return NSAPI_TCP;
|
||||
}
|
||||
|
||||
int TCPServer::listen(int backlog)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
} else {
|
||||
ret = _stack->socket_listen(_socket, backlog);
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TCPServer::accept(TCPSocket *connection)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
_pending = 0;
|
||||
void *socket;
|
||||
ret = _stack->socket_accept(&socket, _socket);
|
||||
|
||||
if (0 == ret) {
|
||||
connection->_lock.lock();
|
||||
|
||||
if (connection->_socket) {
|
||||
connection->close();
|
||||
}
|
||||
|
||||
connection->_stack = _stack;
|
||||
connection->_socket = socket;
|
||||
connection->_event = Callback<void()>(connection, &TCPSocket::event);
|
||||
_stack->socket_attach(socket, &Callback<void()>::thunk, &connection->_event);
|
||||
|
||||
connection->_lock.unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
if (NSAPI_ERROR_WOULD_BLOCK == ret) {
|
||||
int32_t count;
|
||||
|
||||
_lock.unlock();
|
||||
count = _accept_sem.wait(_timeout);
|
||||
_lock.lock();
|
||||
|
||||
if (count < 1) {
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TCPServer::event()
|
||||
{
|
||||
int32_t acount = _accept_sem.wait(0);
|
||||
if (acount <= 1) {
|
||||
_accept_sem.release();
|
||||
}
|
||||
|
||||
_pending += 1;
|
||||
if (_callback && _pending == 1) {
|
||||
_callback();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/* TCPServer
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TCPSERVER_H
|
||||
#define TCPSERVER_H
|
||||
|
||||
#include "network-socket/Socket.h"
|
||||
#include "network-socket/TCPSocket.h"
|
||||
#include "network-socket/NetworkStack.h"
|
||||
#include "network-socket/NetworkInterface.h"
|
||||
#include "rtos/Semaphore.h"
|
||||
|
||||
|
||||
/** TCP socket server
|
||||
*/
|
||||
class TCPServer : public Socket {
|
||||
public:
|
||||
/** Create an uninitialized socket
|
||||
*
|
||||
* Must call open to initialize the socket on a network stack.
|
||||
*/
|
||||
TCPServer();
|
||||
|
||||
/** Create a socket on a network interface
|
||||
*
|
||||
* Creates and opens a socket on the network stack of the given
|
||||
* network interface.
|
||||
*
|
||||
* @param stack Network stack as target for socket
|
||||
*/
|
||||
TCPServer(NetworkStack *stack);
|
||||
|
||||
template <typename IF>
|
||||
TCPServer(IF *iface)
|
||||
: _pending(0), _accept_sem(0)
|
||||
{
|
||||
open(iface->get_stack());
|
||||
}
|
||||
|
||||
/** Destroy a socket
|
||||
*
|
||||
* Closes socket if the socket is still open
|
||||
*/
|
||||
virtual ~TCPServer();
|
||||
|
||||
/** Listen for connections on a TCP socket
|
||||
*
|
||||
* Marks the socket as a passive socket that can be used to accept
|
||||
* incoming connections.
|
||||
*
|
||||
* @param backlog Number of pending connections that can be queued
|
||||
* simultaneously, defaults to 1
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int listen(int backlog = 1);
|
||||
|
||||
/** Accepts a connection on a TCP socket
|
||||
*
|
||||
* The server socket must be bound and set to listen for connections.
|
||||
* On a new connection, creates a network socket using the specified
|
||||
* socket instance.
|
||||
*
|
||||
* By default, accept blocks until data is sent. If socket is set to
|
||||
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
|
||||
* immediately.
|
||||
*
|
||||
* @param socket TCPSocket instance that will handle the incoming connection.
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int accept(TCPSocket *connection);
|
||||
|
||||
protected:
|
||||
virtual nsapi_protocol_t get_proto();
|
||||
virtual void event();
|
||||
|
||||
volatile unsigned _pending;
|
||||
rtos::Semaphore _accept_sem;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,166 @@
|
|||
/* Socket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TCPSocket.h"
|
||||
#include "Timer.h"
|
||||
#include "mbed_assert.h"
|
||||
|
||||
TCPSocket::TCPSocket()
|
||||
: _pending(0), _read_sem(0), _write_sem(0),
|
||||
_read_in_progress(false), _write_in_progress(false)
|
||||
{
|
||||
}
|
||||
|
||||
TCPSocket::~TCPSocket()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
nsapi_protocol_t TCPSocket::get_proto()
|
||||
{
|
||||
return NSAPI_TCP;
|
||||
}
|
||||
|
||||
int TCPSocket::connect(const SocketAddress &address)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
} else {
|
||||
ret = _stack->socket_connect(_socket, address);
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TCPSocket::connect(const char *host, uint16_t port)
|
||||
{
|
||||
SocketAddress address(_stack, host, port);
|
||||
if (!address) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
||||
// connect is thread safe
|
||||
return connect(address);
|
||||
}
|
||||
|
||||
int TCPSocket::send(const void *data, unsigned size)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
// If this assert is hit then there are two threads
|
||||
// performing a send at the same time which is undefined
|
||||
// behavior
|
||||
MBED_ASSERT(!_write_in_progress);
|
||||
_write_in_progress = true;
|
||||
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
_pending = 0;
|
||||
int sent = _stack->socket_send(_socket, data, size);
|
||||
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != sent)) {
|
||||
ret = sent;
|
||||
break;
|
||||
} else {
|
||||
int32_t count;
|
||||
|
||||
// Release lock before blocking so other threads
|
||||
// accessing this object aren't blocked
|
||||
_lock.unlock();
|
||||
count = _write_sem.wait(_timeout);
|
||||
_lock.lock();
|
||||
|
||||
if (count < 1) {
|
||||
// Semaphore wait timed out so break out and return
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_write_in_progress = false;
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TCPSocket::recv(void *data, unsigned size)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
// If this assert is hit then there are two threads
|
||||
// performing a recv at the same time which is undefined
|
||||
// behavior
|
||||
MBED_ASSERT(!_read_in_progress);
|
||||
_read_in_progress = true;
|
||||
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
_pending = 0;
|
||||
int recv = _stack->socket_recv(_socket, data, size);
|
||||
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) {
|
||||
ret = recv;
|
||||
break;
|
||||
} else {
|
||||
int32_t count;
|
||||
|
||||
// Release lock before blocking so other threads
|
||||
// accessing this object aren't blocked
|
||||
_lock.unlock();
|
||||
count = _read_sem.wait(_timeout);
|
||||
_lock.lock();
|
||||
|
||||
if (count < 1) {
|
||||
// Semaphore wait timed out so break out and return
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_read_in_progress = false;
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TCPSocket::event()
|
||||
{
|
||||
int32_t wcount = _write_sem.wait(0);
|
||||
if (wcount <= 1) {
|
||||
_write_sem.release();
|
||||
}
|
||||
int32_t rcount = _read_sem.wait(0);
|
||||
if (rcount <= 1) {
|
||||
_read_sem.release();
|
||||
}
|
||||
|
||||
_pending += 1;
|
||||
if (_callback && _pending == 1) {
|
||||
_callback();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/* TCPSocket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TCPSOCKET_H
|
||||
#define TCPSOCKET_H
|
||||
|
||||
#include "network-socket/Socket.h"
|
||||
#include "network-socket/NetworkStack.h"
|
||||
#include "network-socket/NetworkInterface.h"
|
||||
#include "rtos/Semaphore.h"
|
||||
|
||||
|
||||
/** TCP socket connection
|
||||
*/
|
||||
class TCPSocket : public Socket {
|
||||
public:
|
||||
/** Create an uninitialized socket
|
||||
*
|
||||
* Must call open to initialize the socket on a network stack.
|
||||
*/
|
||||
TCPSocket();
|
||||
|
||||
/** Create a socket on a network interface
|
||||
*
|
||||
* Creates and opens a socket on the network stack of the given
|
||||
* network interface.
|
||||
*
|
||||
* @param stack Network stack as target for socket
|
||||
*/
|
||||
template <typename S>
|
||||
TCPSocket(S *stack)
|
||||
: _pending(0), _read_sem(0), _write_sem(0),
|
||||
_read_in_progress(false), _write_in_progress(false)
|
||||
{
|
||||
open(stack);
|
||||
}
|
||||
|
||||
/** Destroy a socket
|
||||
*
|
||||
* Closes socket if the socket is still open
|
||||
*/
|
||||
virtual ~TCPSocket();
|
||||
|
||||
/** Connects TCP socket to a remote host
|
||||
*
|
||||
* Initiates a connection to a remote server specified by either
|
||||
* a domain name or an IP address and a port.
|
||||
*
|
||||
* @param host Hostname of the remote host
|
||||
* @param port Port of the remote host
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int connect(const char *host, uint16_t port);
|
||||
|
||||
/** Connects TCP socket to a remote host
|
||||
*
|
||||
* Initiates a connection to a remote server specified by the
|
||||
* indicated address.
|
||||
*
|
||||
* @param address The SocketAddress of the remote host
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int connect(const SocketAddress &address);
|
||||
|
||||
/** Send data over a TCP socket
|
||||
*
|
||||
* The socket must be connected to a remote host. Returns the number of
|
||||
* bytes sent from the buffer.
|
||||
*
|
||||
* By default, send blocks until data is sent. If socket is set to
|
||||
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
|
||||
* immediately.
|
||||
*
|
||||
* @param data Buffer of data to send to the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
int send(const void *data, unsigned size);
|
||||
|
||||
/** Receive data over a TCP socket
|
||||
*
|
||||
* The socket must be connected to a remote host. Returns the number of
|
||||
* bytes received into the buffer.
|
||||
*
|
||||
* By default, recv blocks until data is sent. If socket is set to
|
||||
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
|
||||
* immediately.
|
||||
*
|
||||
* @param data Destination buffer for data received from the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of received bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
int recv(void *data, unsigned size);
|
||||
|
||||
protected:
|
||||
friend class TCPServer;
|
||||
|
||||
virtual nsapi_protocol_t get_proto();
|
||||
virtual void event();
|
||||
|
||||
volatile unsigned _pending;
|
||||
rtos::Semaphore _read_sem;
|
||||
rtos::Semaphore _write_sem;
|
||||
bool _read_in_progress;
|
||||
bool _write_in_progress;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,151 @@
|
|||
/* Socket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
#include "mbed_assert.h"
|
||||
|
||||
UDPSocket::UDPSocket()
|
||||
: _pending(0), _read_sem(0), _write_sem(0),
|
||||
_read_in_progress(false), _write_in_progress(false)
|
||||
{
|
||||
}
|
||||
|
||||
UDPSocket::~UDPSocket()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
nsapi_protocol_t UDPSocket::get_proto()
|
||||
{
|
||||
return NSAPI_UDP;
|
||||
}
|
||||
|
||||
int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigned size)
|
||||
{
|
||||
SocketAddress address(_stack, host, port);
|
||||
if (!address) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
||||
// sendto is thread safe
|
||||
return sendto(address, data, size);
|
||||
}
|
||||
|
||||
int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
// If this assert is hit then there are two threads
|
||||
// performing a send at the same time which is undefined
|
||||
// behavior
|
||||
MBED_ASSERT(!_write_in_progress);
|
||||
_write_in_progress = true;
|
||||
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
_pending = 0;
|
||||
int sent = _stack->socket_sendto(_socket, address, data, size);
|
||||
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != sent)) {
|
||||
ret = sent;
|
||||
break;
|
||||
} else {
|
||||
int32_t count;
|
||||
|
||||
// Release lock before blocking so other threads
|
||||
// accessing this object aren't blocked
|
||||
_lock.unlock();
|
||||
count = _write_sem.wait(_timeout);
|
||||
_lock.lock();
|
||||
|
||||
if (count < 1) {
|
||||
// Semaphore wait timed out so break out and return
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_write_in_progress = false;
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size)
|
||||
{
|
||||
_lock.lock();
|
||||
int ret;
|
||||
|
||||
// If this assert is hit then there are two threads
|
||||
// performing a recv at the same time which is undefined
|
||||
// behavior
|
||||
MBED_ASSERT(!_read_in_progress);
|
||||
_read_in_progress = true;
|
||||
|
||||
while (true) {
|
||||
if (!_socket) {
|
||||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
break;
|
||||
}
|
||||
|
||||
_pending = 0;
|
||||
int recv = _stack->socket_recvfrom(_socket, address, buffer, size);
|
||||
if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK != recv)) {
|
||||
ret = recv;
|
||||
break;
|
||||
} else {
|
||||
int32_t count;
|
||||
|
||||
// Release lock before blocking so other threads
|
||||
// accessing this object aren't blocked
|
||||
_lock.unlock();
|
||||
count = _read_sem.wait(_timeout);
|
||||
_lock.lock();
|
||||
|
||||
if (count < 1) {
|
||||
// Semaphore wait timed out so break out and return
|
||||
ret = NSAPI_ERROR_WOULD_BLOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_read_in_progress = false;
|
||||
_lock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void UDPSocket::event()
|
||||
{
|
||||
int32_t wcount = _write_sem.wait(0);
|
||||
if (wcount <= 1) {
|
||||
_write_sem.release();
|
||||
}
|
||||
int32_t rcount = _read_sem.wait(0);
|
||||
if (rcount <= 1) {
|
||||
_read_sem.release();
|
||||
}
|
||||
|
||||
_pending += 1;
|
||||
if (_callback && _pending == 1) {
|
||||
_callback();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/* UDPSocket
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef UDPSOCKET_H
|
||||
#define UDPSOCKET_H
|
||||
|
||||
#include "network-socket/Socket.h"
|
||||
#include "network-socket/NetworkStack.h"
|
||||
#include "network-socket/NetworkInterface.h"
|
||||
#include "rtos/Semaphore.h"
|
||||
|
||||
|
||||
/** UDP socket
|
||||
*/
|
||||
class UDPSocket : public Socket {
|
||||
public:
|
||||
/** Create an uninitialized socket
|
||||
*
|
||||
* Must call open to initialize the socket on a network stack.
|
||||
*/
|
||||
UDPSocket();
|
||||
|
||||
/** Create a socket on a network interface
|
||||
*
|
||||
* Creates and opens a socket on the network stack of the given
|
||||
* network interface.
|
||||
*
|
||||
* @param stack Network stack as target for socket
|
||||
*/
|
||||
template <typename S>
|
||||
UDPSocket(S *stack)
|
||||
: _pending(0), _read_sem(0), _write_sem(0),
|
||||
_read_in_progress(false), _write_in_progress(false)
|
||||
{
|
||||
open(stack);
|
||||
}
|
||||
|
||||
/** Destroy a socket
|
||||
*
|
||||
* Closes socket if the socket is still open
|
||||
*/
|
||||
virtual ~UDPSocket();
|
||||
|
||||
/** Send a packet over a UDP socket
|
||||
*
|
||||
* Sends data to the specified address specified by either a domain name
|
||||
* or an IP address and port. Returns the number of bytes sent from the
|
||||
* buffer.
|
||||
*
|
||||
* By default, sendto blocks until data is sent. If socket is set to
|
||||
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
|
||||
* immediately.
|
||||
*
|
||||
* @param host Hostname of the remote host
|
||||
* @param port Port of the remote host
|
||||
* @param data Buffer of data to send to the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
int sendto(const char *host, uint16_t port, const void *data, unsigned size);
|
||||
|
||||
/** Send a packet over a UDP socket
|
||||
*
|
||||
* Sends data to the specified address. Returns the number of bytes
|
||||
* sent from the buffer.
|
||||
*
|
||||
* By default, sendto blocks until data is sent. If socket is set to
|
||||
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
|
||||
* immediately.
|
||||
*
|
||||
* @param address The SocketAddress of the remote host
|
||||
* @param data Buffer of data to send to the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
int sendto(const SocketAddress &address, const void *data, unsigned size);
|
||||
|
||||
/** Receive a packet over a UDP socket
|
||||
*
|
||||
* Receives data and stores the source address in address if address
|
||||
* is not NULL. Returns the number of bytes received into the buffer.
|
||||
*
|
||||
* By default, recvfrom blocks until data is sent. If socket is set to
|
||||
* non-blocking or times out, NSAPI_ERROR_WOULD_BLOCK is returned
|
||||
* immediately.
|
||||
*
|
||||
* @param address Destination for the source address or NULL
|
||||
* @param data Destination buffer for data received from the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of received bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
int recvfrom(SocketAddress *address, void *data, unsigned size);
|
||||
|
||||
protected:
|
||||
virtual nsapi_protocol_t get_proto();
|
||||
virtual void event();
|
||||
|
||||
volatile unsigned _pending;
|
||||
rtos::Semaphore _read_sem;
|
||||
rtos::Semaphore _write_sem;
|
||||
bool _read_in_progress;
|
||||
bool _write_in_progress;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,70 @@
|
|||
/* WiFiInterface
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WIFI_INTERFACE_H
|
||||
#define WIFI_INTERFACE_H
|
||||
|
||||
#include "network-socket/NetworkInterface.h"
|
||||
|
||||
|
||||
/** Enum of WiFi encryption types
|
||||
*
|
||||
* The security type specifies a particular security to use when
|
||||
* connected to a WiFi network
|
||||
*
|
||||
* @enum nsapi_protocol_t
|
||||
*/
|
||||
enum nsapi_security_t {
|
||||
NSAPI_SECURITY_NONE = 0, /*!< open access point */
|
||||
NSAPI_SECURITY_WEP, /*!< phrase conforms to WEP */
|
||||
NSAPI_SECURITY_WPA, /*!< phrase conforms to WPA */
|
||||
NSAPI_SECURITY_WPA2, /*!< phrase conforms to WPA2 */
|
||||
};
|
||||
|
||||
/** WiFiInterface class
|
||||
*
|
||||
* Common interface that is shared between WiFi devices
|
||||
*/
|
||||
class WiFiInterface: public NetworkInterface
|
||||
{
|
||||
public:
|
||||
/** Start the interface
|
||||
*
|
||||
* Attempts to connect to a WiFi network. If passphrase is invalid,
|
||||
* NSAPI_ERROR_AUTH_ERROR is returned.
|
||||
*
|
||||
* @param ssid Name of the network to connect to
|
||||
* @param pass Security passphrase to connect to the network
|
||||
* @param security Type of encryption for connection
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE) = 0;
|
||||
|
||||
/** Stop the interface
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int disconnect() = 0;
|
||||
|
||||
/** Get the local MAC address
|
||||
*
|
||||
* @return Null-terminated representation of the local MAC address
|
||||
*/
|
||||
virtual const char *get_mac_address() = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,47 @@
|
|||
/* nsapi.h - The network socket API
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NSAPI_H
|
||||
#define NSAPI_H
|
||||
|
||||
|
||||
// entry point for nsapi types
|
||||
#include "nsapi_types.h"
|
||||
|
||||
// disable bug-compatible mbed inclusion
|
||||
#define NSAPI_NO_INCLUDE_MBED
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// entry point for C++ api
|
||||
#include "network-socket/SocketAddress.h"
|
||||
#include "network-socket/NetworkStack.h"
|
||||
|
||||
#include "network-socket/NetworkInterface.h"
|
||||
#include "network-socket/EthInterface.h"
|
||||
#include "network-socket/WiFiInterface.h"
|
||||
#include "network-socket/CellularInterface.h"
|
||||
#include "network-socket/MeshInterface.h"
|
||||
|
||||
#include "network-socket/Socket.h"
|
||||
#include "network-socket/UDPSocket.h"
|
||||
#include "network-socket/TCPSocket.h"
|
||||
#include "network-socket/TCPServer.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,445 @@
|
|||
/* nsapi.h - The network socket API
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NSAPI_TYPES_H
|
||||
#define NSAPI_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** Enum of standardized error codes
|
||||
*
|
||||
* Valid error codes have negative values and may
|
||||
* be returned by any network operation.
|
||||
*
|
||||
* @enum nsapi_error_t
|
||||
*/
|
||||
typedef enum nsapi_error {
|
||||
NSAPI_ERROR_WOULD_BLOCK = -3001, /*!< no data is not available but call is non-blocking */
|
||||
NSAPI_ERROR_UNSUPPORTED = -3002, /*!< unsupported functionality */
|
||||
NSAPI_ERROR_PARAMETER = -3003, /*!< invalid configuration */
|
||||
NSAPI_ERROR_NO_CONNECTION = -3004, /*!< not connected to a network */
|
||||
NSAPI_ERROR_NO_SOCKET = -3005, /*!< socket not available for use */
|
||||
NSAPI_ERROR_NO_ADDRESS = -3006, /*!< IP address is not known */
|
||||
NSAPI_ERROR_NO_MEMORY = -3007, /*!< memory resource not available */
|
||||
NSAPI_ERROR_DNS_FAILURE = -3008, /*!< DNS failed to complete successfully */
|
||||
NSAPI_ERROR_DHCP_FAILURE = -3009, /*!< DHCP failed to complete successfully */
|
||||
NSAPI_ERROR_AUTH_FAILURE = -3010, /*!< connection to access point faield */
|
||||
NSAPI_ERROR_DEVICE_ERROR = -3011, /*!< failure interfacing with the network procesor */
|
||||
} nsapi_error_t;
|
||||
|
||||
|
||||
/** Maximum size of IP address representation
|
||||
*/
|
||||
#define NSAPI_IP_SIZE NSAPI_IPv6_SIZE
|
||||
|
||||
/** Maximum number of bytes for IP address
|
||||
*/
|
||||
#define NSAPI_IP_BYTES NSAPI_IPv6_BYTES
|
||||
|
||||
/** Maximum size of MAC address representation
|
||||
*/
|
||||
#define NSAPI_MAC_SIZE 18
|
||||
|
||||
/** Maximum number of bytes for MAC address
|
||||
*/
|
||||
#define NSAPI_MAC_BYTES 6
|
||||
|
||||
/** Size of IPv4 representation
|
||||
*/
|
||||
#define NSAPI_IPv4_SIZE 16
|
||||
|
||||
/** Number of bytes in IPv4 address
|
||||
*/
|
||||
#define NSAPI_IPv4_BYTES 4
|
||||
|
||||
/** Size of IPv6 representation
|
||||
*/
|
||||
#define NSAPI_IPv6_SIZE 40
|
||||
|
||||
/** Number of bytes in IPv6 address
|
||||
*/
|
||||
#define NSAPI_IPv6_BYTES 16
|
||||
|
||||
/** Enum of IP address versions
|
||||
*
|
||||
* The IP version specifies the type of an IP address.
|
||||
*
|
||||
* @enum nsapi_version_t
|
||||
*/
|
||||
typedef enum nsapi_version {
|
||||
NSAPI_IPv4, /*!< Address is IPv4 */
|
||||
NSAPI_IPv6, /*!< Address is IPv6 */
|
||||
} nsapi_version_t;
|
||||
|
||||
/** IP address structure for passing IP addresses by value
|
||||
*/
|
||||
typedef struct nsapi_addr {
|
||||
/** IP version
|
||||
* NSAPI_IPv4 or NSAPI_IPv6
|
||||
*/
|
||||
nsapi_version_t version;
|
||||
|
||||
/** IP address
|
||||
* The raw bytes of the IP address stored in big-endian format
|
||||
*/
|
||||
uint8_t bytes[NSAPI_IP_BYTES];
|
||||
} nsapi_addr_t;
|
||||
|
||||
|
||||
/** Opaque handle for network sockets
|
||||
*/
|
||||
typedef void *nsapi_socket_t;
|
||||
|
||||
|
||||
/** Enum of socket protocols
|
||||
*
|
||||
* The socket protocol specifies a particular protocol to
|
||||
* be used with a newly created socket.
|
||||
*
|
||||
* @enum nsapi_protocol_t
|
||||
*/
|
||||
typedef enum nsapi_protocol {
|
||||
NSAPI_TCP, /*!< Socket is of TCP type */
|
||||
NSAPI_UDP, /*!< Socket is of UDP type */
|
||||
} nsapi_protocol_t;
|
||||
|
||||
/* Enum of standardized stack option levels
|
||||
*
|
||||
* @enum nsapi_level_t
|
||||
*/
|
||||
typedef enum nsapi_level {
|
||||
NSAPI_STACK, /*!< Stack option level */
|
||||
NSAPI_SOCKET, /*!< Socket option level */
|
||||
} nsapi_level_t;
|
||||
|
||||
/* Enum of standardized stack options
|
||||
*
|
||||
* These options may not be supported on all stacks, in which
|
||||
* case NSAPI_ERROR_UNSUPPORTED may be returned from setsockopt.
|
||||
*
|
||||
* @enum nsapi_option_t
|
||||
*/
|
||||
typedef enum nsapi_option {
|
||||
NSAPI_REUSEADDR, /*!< Allow bind to reuse local addresses */
|
||||
NSAPI_KEEPALIVE, /*!< Enables sending of keepalive messages */
|
||||
NSAPI_KEEPIDLE, /*!< Sets timeout value to initiate keepalive */
|
||||
NSAPI_KEEPINTVL, /*!< Sets timeout value for keepalive */
|
||||
NSAPI_LINGER, /*!< Keeps close from returning until queues empty */
|
||||
NSAPI_SNDBUF, /*!< Sets send buffer size */
|
||||
NSAPI_RCVBUF, /*!< Sets recv buffer size */
|
||||
} nsapi_option_t;
|
||||
|
||||
|
||||
/** nsapi_stack structure
|
||||
*
|
||||
* Stack structure representing a specific instance of a stack.
|
||||
*/
|
||||
typedef struct nsapi_stack {
|
||||
/** Network stack operation table
|
||||
*
|
||||
* Provides access to the underlying api of the stack. This is not
|
||||
* flattened into the nsapi_stack to allow allocation in read-only
|
||||
* memory.
|
||||
*/
|
||||
const struct nsapi_stack_api *stack_api;
|
||||
|
||||
/** Opaque handle for network stacks
|
||||
*/
|
||||
void *stack;
|
||||
|
||||
// Internal nsapi buffer
|
||||
unsigned _stack_buffer[16];
|
||||
} nsapi_stack_t;
|
||||
|
||||
/** nsapi_stack_api structure
|
||||
*
|
||||
* Common api structure for network stack operations. A network stack
|
||||
* can provide a nsapi_stack_api structure filled out with the
|
||||
* appropriate implementation.
|
||||
*
|
||||
* Unsupported operations can be left as null pointers.
|
||||
*/
|
||||
typedef struct nsapi_stack_api
|
||||
{
|
||||
/** Get the local IP address
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @return Local IP Address or null address if not connected
|
||||
*/
|
||||
nsapi_addr_t (*get_ip_address)(nsapi_stack_t *stack);
|
||||
|
||||
/** Translates a hostname to an IP address
|
||||
*
|
||||
* The hostname may be either a domain name or an IP address. If the
|
||||
* hostname is an IP address, no network transactions will be performed.
|
||||
*
|
||||
* If no stack-specific DNS resolution is provided, the hostname
|
||||
* will be resolve using a UDP socket on the stack.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param addr Destination for the host IP address
|
||||
* @param host Hostname to resolve
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*gethostbyname)(nsapi_stack_t *stack, nsapi_addr_t *addr, const char *host);
|
||||
|
||||
/* Set stack-specific stack options
|
||||
*
|
||||
* The setstackopt allow an application to pass stack-specific hints
|
||||
* to the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and the stack is unmodified.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*setstackopt)(nsapi_stack_t *stack, int level, int optname, const void *optval, unsigned optlen);
|
||||
|
||||
/* Get stack-specific stack options
|
||||
*
|
||||
* The getstackopt allow an application to retrieve stack-specific hints
|
||||
* from the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Destination for option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*getstackopt)(nsapi_stack_t *stack, int level, int optname, void *optval, unsigned *optlen);
|
||||
|
||||
/** Opens a socket
|
||||
*
|
||||
* Creates a network socket and stores it in the specified handle.
|
||||
* The handle must be passed to following calls on the socket.
|
||||
*
|
||||
* A stack may have a finite number of sockets, in this case
|
||||
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
|
||||
*
|
||||
* @param stack Stack context
|
||||
* @param socket Destination for the handle to a newly created socket
|
||||
* @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*socket_open)(nsapi_stack_t *stack, nsapi_socket_t *socket, nsapi_protocol_t proto);
|
||||
|
||||
/** Close the socket
|
||||
*
|
||||
* Closes any open connection and deallocates any memory associated
|
||||
* with the socket.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*socket_close)(nsapi_stack_t *stack, nsapi_socket_t socket);
|
||||
|
||||
/** Bind a specific address to a socket
|
||||
*
|
||||
* Binding a socket specifies the address and port on which to recieve
|
||||
* data. If the IP address is zeroed, only the port is bound.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param addr Local address to bind, may be null
|
||||
* @param port Local port to bind
|
||||
* @return 0 on success, negative error code on failure.
|
||||
*/
|
||||
int (*socket_bind)(nsapi_stack_t *stack, nsapi_socket_t socket, nsapi_addr_t addr, uint16_t port);
|
||||
|
||||
/** Listen for connections on a TCP socket
|
||||
*
|
||||
* Marks the socket as a passive socket that can be used to accept
|
||||
* incoming connections.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param backlog Number of pending connections that can be queued
|
||||
* simultaneously
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*socket_listen)(nsapi_stack_t *stack, nsapi_socket_t socket, int backlog);
|
||||
|
||||
/** Connects TCP socket to a remote host
|
||||
*
|
||||
* Initiates a connection to a remote server specified by the
|
||||
* indicated address.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param addr The address of the remote host
|
||||
* @param port The port of the remote host
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*socket_connect)(nsapi_stack_t *stack, nsapi_socket_t socket, nsapi_addr_t addr, uint16_t port);
|
||||
|
||||
/** Accepts a connection on a TCP socket
|
||||
*
|
||||
* The server socket must be bound and set to listen for connections.
|
||||
* On a new connection, creates a network socket and stores it in the
|
||||
* specified handle. The handle must be passed to following calls on
|
||||
* the socket.
|
||||
*
|
||||
* A stack may have a finite number of sockets, in this case
|
||||
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
|
||||
*
|
||||
* This call is non-blocking. If accept would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Destination for a handle to the newly created sockey
|
||||
* @param server Socket handle to server to accept from
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*socket_accept)(nsapi_stack_t *stack, nsapi_socket_t *socket, nsapi_socket_t server);
|
||||
|
||||
/** Send data over a TCP socket
|
||||
*
|
||||
* The socket must be connected to a remote host. Returns the number of
|
||||
* bytes sent from the buffer.
|
||||
*
|
||||
* This call is non-blocking. If send would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param data Buffer of data to send to the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
int (*socket_send)(nsapi_stack_t *stack, nsapi_socket_t socket, const void *data, unsigned size);
|
||||
|
||||
/** Receive data over a TCP socket
|
||||
*
|
||||
* The socket must be connected to a remote host. Returns the number of
|
||||
* bytes received into the buffer.
|
||||
*
|
||||
* This call is non-blocking. If recv would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param data Destination buffer for data received from the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of received bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
int (*socket_recv)(nsapi_stack_t *stack, nsapi_socket_t socket, void *data, unsigned size);
|
||||
|
||||
/** Send a packet over a UDP socket
|
||||
*
|
||||
* Sends data to the specified address. Returns the number of bytes
|
||||
* sent from the buffer.
|
||||
*
|
||||
* This call is non-blocking. If sendto would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param addr The address of the remote host
|
||||
* @param port The port of the remote host
|
||||
* @param data Buffer of data to send to the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
int (*socket_sendto)(nsapi_stack_t *stack, nsapi_socket_t socket, nsapi_addr_t addr, uint16_t port, const void *data, unsigned size);
|
||||
|
||||
/** Receive a packet over a UDP socket
|
||||
*
|
||||
* Receives data and stores the source address in address if address
|
||||
* is not NULL. Returns the number of bytes received into the buffer.
|
||||
*
|
||||
* This call is non-blocking. If recvfrom would block,
|
||||
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param addr Destination for the address of the remote host
|
||||
* @param port Destination for the port of the remote host
|
||||
* @param data Destination buffer for data received from the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of received bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
int (*socket_recvfrom)(nsapi_stack_t *stack, nsapi_socket_t socket, nsapi_addr_t *addr, uint16_t *port, void *buffer, unsigned size);
|
||||
|
||||
/** Register a callback on state change of the socket
|
||||
*
|
||||
* The specified callback will be called on state changes such as when
|
||||
* the socket can recv/send/accept successfully and on when an error
|
||||
* occurs. The callback may also be called spuriously without reason.
|
||||
*
|
||||
* The callback may be called in an interrupt context and should not
|
||||
* perform expensive operations such as recv/send calls.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param callback Function to call on state change
|
||||
* @param data Argument to pass to callback
|
||||
*/
|
||||
void (*socket_attach)(nsapi_stack_t *stack, nsapi_socket_t socket, void (*callback)(void *), void *data);
|
||||
|
||||
/* Set stack-specific socket options
|
||||
*
|
||||
* The setsockopt allow an application to pass stack-specific hints
|
||||
* to the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*setsockopt)(nsapi_stack_t *stack, nsapi_socket_t socket, int level, int optname, const void *optval, unsigned optlen);
|
||||
|
||||
/* Get stack-specific socket options
|
||||
*
|
||||
* The getstackopt allow an application to retrieve stack-specific hints
|
||||
* from the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
|
||||
*
|
||||
* @param stack Stack handle
|
||||
* @param socket Socket handle
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Destination for option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*getsockopt)(nsapi_stack_t *stack, nsapi_socket_t socket, int level, int optname, void *optval, unsigned *optlen);
|
||||
} nsapi_stack_api_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue