Preparing new layout - added net/NetworkSocketAPI

Origin: https://developer.mbed.org/teams/NetworkSocketAPI/code/NetworkSocketAPI/
pull/2216/head^2
Bogdan Marinescu 2016-04-05 17:30:31 +03:00 committed by Marcus Shawcroft
commit 9f668f1a8f
11 changed files with 843 additions and 0 deletions

214
DnsQuery/DnsQuery.cpp Normal file
View File

@ -0,0 +1,214 @@
/* 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;
}
int32_t dnsQuery(NetworkInterface *iface, const char *host, char *ip)
{
if (isIP(host)) {
strcpy(ip, host);
return 0;
}
UDPSocket sock(iface);
int32_t err;
for (unsigned i = 0; i < DNS_COUNT; i++) {
err = sock.open(DNS_IPS[0], 53);
if (err < 0) {
return err;
}
err = dnsQuery(&sock, host, ip);
sock.close();
return err;
}
sock.close();
return NS_ERROR_DNS_FAILURE;
}
int32_t dnsQuery(UDPSocket *socket, const char *hostname, char *ipaddress)
{
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->send(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->recv(packet, 1024);
if (response_length > 0 ) {
if (!resolve(packet, ipaddress)) {
delete packet;
return NS_ERROR_DNS_FAILURE;
}
// cleanup and return
delete packet;
return 0;
}
delete packet;
return NS_ERROR_DNS_FAILURE;
}

41
DnsQuery/DnsQuery.h Normal file
View File

@ -0,0 +1,41 @@
/*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __DNSQUERY_H__
#define __DNSQUERY_H__
#include "NetworkInterface.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(NetworkInterface *iface, const char *host, char *ip);
int32_t dnsQuery(UDPSocket *sock, const char *host, char *ip);
#endif // __DNSQUERY_H__

39
EthernetInterface.h Normal file
View File

@ -0,0 +1,39 @@
/* EthernetInterface Base Class
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ETHERNET_INTERFACE_H
#define ETHERNET_INTERFACE_H
#include "NetworkInterface.h"
/** EthernetInterface class
* Common interface that is shared between ethernet hardware
*/
class EthernetInterface : public NetworkInterface
{
public:
/** Start the interface
* @return 0 on success
*/
virtual int32_t connect() = 0;
/** Stop the interface
* @return 0 on success
*/
virtual int32_t disconnect() = 0;
};
#endif

29
NetworkInterface.cpp Normal file
View File

@ -0,0 +1,29 @@
/* NetworkInterface Base Class
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NetworkInterface.h"
#include "DnsQuery.h"
bool NetworkInterface::isConnected()
{
return getIPAddress() != 0;
}
int32_t NetworkInterface::getHostByName(const char *name, char *ip)
{
return dnsQuery(this, name, ip);
}

92
NetworkInterface.h Normal file
View File

@ -0,0 +1,92 @@
/* NetworkInterface Base Class
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NETWORK_INTERFACE_H
#define NETWORK_INTERFACE_H
#include "SocketInterface.h"
#include "stdint.h"
/** Maximum storage needed for IP address and MAC addresses
*/
#define NS_IP_SIZE 16
#define NS_MAC_SIZE 18
/**
* @enum ns_error_t
* @brief enum of standardized error codes
*/
enum ns_error_t {
NS_ERROR_WOULD_BLOCK = -3000, /*!< no data is not available but call is non-blocking */
NS_ERROR_TIMEOUT = -3001, /*!< operation took longer than allowed */
NS_ERROR_NO_CONNECTION = -3002, /*!< not connected to a network */
NS_ERROR_NO_SOCKET = -3003, /*!< socket not available for use */
NS_ERROR_NO_ADDRESS = -3004, /*!< IP address is not known */
NS_ERROR_NO_MEMORY = -3005, /*!< memory resource not available */
NS_ERROR_DNS_FAILURE = -3006, /*!< DNS failed to complete successfully */
NS_ERROR_DHCP_FAILURE = -3007, /*!< DHCP failed to complete successfully */
NS_ERROR_AUTH_FAILURE = -3008, /*!< connection to access point faield */
NS_ERROR_DEVICE_ERROR = -3009 /*!< failure interfacing with the network procesor */
};
/** NetworkInterface class
* Common interface that is shared between all hardware that
* can connect to a network over IP.
*/
class NetworkInterface
{
public:
virtual ~NetworkInterface() {};
/** Get the IP address
* @return IP address of the interface or 0 if not yet connected
*/
virtual const char *getIPAddress() = 0;
/** Get the current MAC address
* @return String MAC address of the interface
*/
virtual const char *getMACAddress() = 0;
/** Get the current status of the interface
* @return true if connected
*/
virtual bool isConnected();
/** Looks up the specified host's IP address
* @param name URL of host
* @param ip Buffer to hold IP address, must be at least SOCK_IP_SIZE
* @return 0 on success
*/
virtual int32_t getHostByName(const char *name, char *ip);
protected:
friend class Socket;
/** Internally create a socket
* @param proto The type of socket to open, NS_TCP or NS_UDP
* @return The allocated socket
*/
virtual SocketInterface *createSocket(ns_protocol_t proto) = 0;
/** Internally destroy a socket
* @param socket An allocated SocketInterface
* @returns 0 on success
*/
virtual void destroySocket(SocketInterface *socket) = 0;
};
#endif

130
Socket.cpp Normal file
View File

@ -0,0 +1,130 @@
/* 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"
#include <string.h>
Socket::Socket(NetworkInterface *iface, ns_protocol_t proto)
: _iface(iface)
, _proto(proto)
, _socket(0)
{
memset(_ip_address, 0, NS_IP_SIZE);
_port = 0;
}
Socket::~Socket()
{
if (_socket) {
close();
}
}
int32_t Socket::open(const char *address, uint16_t port)
{
int32_t err;
err = close();
if (err) {
return err;
}
err = _iface->getHostByName(address, _ip_address);
_port = port;
if (err) {
return err;
}
_socket = _iface->createSocket(_proto);
if (!_socket) {
return NS_ERROR_NO_SOCKET;
}
err = _socket->open(_ip_address, _port);
if (err) {
_iface->destroySocket(_socket);
_socket = 0;
}
return err;
}
int32_t Socket::close()
{
if (!_socket) {
return 0;
}
SocketInterface *socket = _socket;
_socket = 0;
int32_t err = socket->close();
if (!err) {
_iface->destroySocket(socket);
}
return err;
}
int32_t Socket::send(const void *data, uint32_t size)
{
if (!_socket) {
return NS_ERROR_NO_CONNECTION;
}
return _socket->send(data, size);
}
int32_t Socket::recv(void *data, uint32_t size, bool blocking)
{
while (true) {
if (!_socket) {
return NS_ERROR_NO_CONNECTION;
}
int32_t recv = _socket->recv(data, size);
if (recv != NS_ERROR_WOULD_BLOCK || !blocking) {
return recv;
}
}
}
const char *Socket::getIPAddress() const
{
if (_ip_address[0]) {
return _ip_address;
} else {
return 0;
}
}
uint16_t Socket::getPort() const
{
return _port;
}
bool Socket::isConnected()
{
if (!_socket) {
return false;
}
return _socket->isConnected();
}

85
Socket.h Normal file
View File

@ -0,0 +1,85 @@
/* 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 "NetworkInterface.h"
/** Abstract socket class
* API for handling general sockets. Supports IP address operations
* and sending/recieving data.
*/
class Socket
{
public:
~Socket();
/** Open a connection to the underlying address
* @param address URL or IP address to connect to
* @param port Port to connect to
* @return 0 on success
*/
int32_t open(const char *address, uint16_t port);
/** Close an open connection
* @return 0 on success
*/
int32_t close();
/** Send data over the socket
* @param data Buffer of data to send
* @param size Size of data to send
* @return Number of bytes sent or a negative value on failure
*/
int32_t send(const void *data, uint32_t size);
/** Recieve data over the socket
* @param data Buffer to store recieved data
* @param size Size of provided buffer
* @param blocking If true wait for data, otherwise return NS_ERROR_WOULD_BLOCK
* @return Number of bytes recieved or a negative value on failure
*/
int32_t recv(void *data, uint32_t size, bool blocking = true);
/** Gets the IP address
* @return IP address to connect to
*/
const char *getIPAddress() const;
/** Gets the port
* @return Port to connect to
*/
uint16_t getPort() const;
/** Returns status of socket
* @return true if connected
*/
bool isConnected();
protected:
Socket(NetworkInterface *iface, ns_protocol_t proto);
private:
NetworkInterface *_iface;
ns_protocol_t _proto;
SocketInterface *_socket;
char _ip_address[NS_IP_SIZE];
uint16_t _port;
};
#endif

83
SocketInterface.h Normal file
View File

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

39
TCPSocket.h Normal file
View File

@ -0,0 +1,39 @@
/* 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 TCP_SOCKET_H
#define TCP_SOCKET_H
#include "Socket.h"
/** TCPSocket class
* API for handling TCP sockets. The implementation is determined
* by the interface passed during construction.
*/
class TCPSocket : public Socket
{
public:
/** Create a socket using the specified network interface
* No network operations are performed until the socket is actually used
* @param iface The network interface to use
* @param url Optional URL to connect to, copied internally
* @param port Optional port to connect to
*/
TCPSocket(NetworkInterface *iface)
: Socket(iface, NS_TCP) {}
};
#endif

39
UDPSocket.h Normal file
View File

@ -0,0 +1,39 @@
/* 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 UDP_SOCKET_H
#define UDP_SOCKET_H
#include "Socket.h"
/** UDPSocket class
* API for handling UDP sockets. The implementation is determined
* by the interface passed during construction.
*/
class UDPSocket : public Socket
{
public:
/** Create a socket using the specified network interface
* No network operations are performed until the socket is actually used
* @param iface The network interface to use
* @param ip Optional URL to connect to, copied internally
* @param port Optional port to connect to
*/
UDPSocket(NetworkInterface *iface)
: Socket(iface, NS_UDP) {}
};
#endif

52
WiFiInterface.h Normal file
View File

@ -0,0 +1,52 @@
/* WiFiInterface Base Class
* Copyright (c) 2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WIFI_INTERFACE_H
#define WIFI_INTERFACE_H
#include "NetworkInterface.h"
/** Enum for WiFi encryption types
*/
enum ns_security_t {
NS_SECURITY_NONE = 0, /*!< open access point */
NS_SECURITY_WEP, /*!< phrase conforms to WEP */
NS_SECURITY_WPA, /*!< phrase conforms to WPA */
NS_SECURITY_WPA2, /*!< phrase conforms to WPA2 */
};
/** WiFiInterface class
* Common interface that is shared between WiFi devices
*/
class WiFiInterface : public NetworkInterface
{
public:
/** Start the interface
* @param ssid Name of the network to connect to
* @param pass Security passphrase to connect to the network
* @param security Type of encryption to connect with
* @return 0 on success
*/
virtual int32_t connect(const char *ssid, const char *pass, ns_security_t security = NS_SECURITY_NONE) = 0;
/** Stop the interface
* @return 0 on success
*/
virtual int32_t disconnect() = 0;
};
#endif