Base class for IP Based Networking Libraries

Dependencies:   DnsQuery

Dependents:   TempTower BSDInterfaceTests HelloBSDInterface ESP8266InterfaceTests ... more

For a complete getting started guide see the wiki...

Network Socket API

The Network Socket API provides a common interface for using sockets on network devices. The API provides a simple class-based interface that should be familiar to users experienced with other socket APIs. Additionally, the API provides a simple interface for implementing network devices, making it easy to connect hardware agnostic programs to new devices.

Network Interfaces

The NetworkInterface provides an abstract class for network devices that support sockets. Devices should provide a DeviceInterface class that inherits this interface and adds implementation specific methods for using the device. A NetworkInterface must be provided to a Socket constructor to open a socket on the interface. Currently two subclasses are defined for common devices, EthernetInterface and WiFiInterface.

Sockets

The Socket class is used for managing network sockets. Once opened, the socket provides a pipe through which data can sent and recieved to a specific endpoint. The socket class can be instantiated as either a TCPSocket or a UDPSocket which defines the protocol used for the connection.

Committer:
Christopher Haster
Date:
Wed Apr 20 02:56:07 2016 -0500
Revision:
111:df01ca3e89b3
Parent:
105:2fd212f8da61
Child:
120:6eb542426f15
Add workaround for bug in newlib scanf

https://bugs.launchpad.net/gcc-arm-embedded/+bug/1399224

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Christopher Haster 89:b1d417383c0d 1 /* Socket
Christopher Haster 89:b1d417383c0d 2 * Copyright (c) 2015 ARM Limited
Christopher Haster 89:b1d417383c0d 3 *
Christopher Haster 89:b1d417383c0d 4 * Licensed under the Apache License, Version 2.0 (the "License");
Christopher Haster 89:b1d417383c0d 5 * you may not use this file except in compliance with the License.
Christopher Haster 89:b1d417383c0d 6 * You may obtain a copy of the License at
Christopher Haster 89:b1d417383c0d 7 *
Christopher Haster 89:b1d417383c0d 8 * http://www.apache.org/licenses/LICENSE-2.0
Christopher Haster 89:b1d417383c0d 9 *
Christopher Haster 89:b1d417383c0d 10 * Unless required by applicable law or agreed to in writing, software
Christopher Haster 89:b1d417383c0d 11 * distributed under the License is distributed on an "AS IS" BASIS,
Christopher Haster 89:b1d417383c0d 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Christopher Haster 89:b1d417383c0d 13 * See the License for the specific language governing permissions and
Christopher Haster 89:b1d417383c0d 14 * limitations under the License.
Christopher Haster 89:b1d417383c0d 15 */
Christopher Haster 89:b1d417383c0d 16
Christopher Haster 89:b1d417383c0d 17 #include "SocketAddress.h"
Christopher Haster 105:2fd212f8da61 18 #include "NetworkStack.h"
Christopher Haster 89:b1d417383c0d 19 #include <string.h>
Christopher Haster 89:b1d417383c0d 20 #include "mbed.h"
Christopher Haster 89:b1d417383c0d 21
Christopher Haster 100:90d8f662de83 22
Christopher Haster 100:90d8f662de83 23 static bool ipv4_is_valid(const char *addr)
Christopher Haster 94:644df37bb05b 24 {
Christopher Haster 94:644df37bb05b 25 int i = 0;
Christopher Haster 94:644df37bb05b 26
Christopher Haster 94:644df37bb05b 27 // Check each digit for [0-9.]
Christopher Haster 94:644df37bb05b 28 for (; addr[i]; i++) {
Christopher Haster 94:644df37bb05b 29 if (!(addr[i] >= '0' && addr[i] <= '9') && addr[i] != '.') {
Christopher Haster 94:644df37bb05b 30 return false;
Christopher Haster 94:644df37bb05b 31 }
Christopher Haster 94:644df37bb05b 32 }
Christopher Haster 94:644df37bb05b 33
Christopher Haster 94:644df37bb05b 34 // Ending with '.' garuntees host
Christopher Haster 94:644df37bb05b 35 if (i > 0 && addr[i-1] == '.') {
Christopher Haster 94:644df37bb05b 36 return false;
Christopher Haster 94:644df37bb05b 37 }
Christopher Haster 94:644df37bb05b 38
Christopher Haster 94:644df37bb05b 39 return true;
Christopher Haster 94:644df37bb05b 40 }
Christopher Haster 94:644df37bb05b 41
Christopher Haster 100:90d8f662de83 42 static bool ipv6_is_valid(const char *addr)
Christopher Haster 94:644df37bb05b 43 {
Christopher Haster 94:644df37bb05b 44 // Check each digit for [0-9a-fA-F:]
Christopher Haster 94:644df37bb05b 45 for (int i = 0; addr[i]; i++) {
Christopher Haster 94:644df37bb05b 46 if (!(addr[i] >= '0' && addr[i] <= '9') &&
Christopher Haster 94:644df37bb05b 47 !(addr[i] >= 'a' && addr[i] <= 'f') &&
Christopher Haster 94:644df37bb05b 48 !(addr[i] >= 'A' && addr[i] <= 'F') &&
Christopher Haster 94:644df37bb05b 49 addr[i] != ':') {
Christopher Haster 94:644df37bb05b 50 return false;
Christopher Haster 94:644df37bb05b 51 }
Christopher Haster 94:644df37bb05b 52 }
Christopher Haster 94:644df37bb05b 53
Christopher Haster 94:644df37bb05b 54 return true;
Christopher Haster 94:644df37bb05b 55 }
Christopher Haster 94:644df37bb05b 56
Christopher Haster 100:90d8f662de83 57 static void ipv4_from_address(uint8_t *bytes, const char *addr)
Christopher Haster 94:644df37bb05b 58 {
Christopher Haster 111:df01ca3e89b3 59 int count = 0;
Christopher Haster 111:df01ca3e89b3 60 int i = 0;
Christopher Haster 111:df01ca3e89b3 61
Christopher Haster 111:df01ca3e89b3 62 for (; count < NSAPI_IPv4_BYTES; count++) {
Christopher Haster 111:df01ca3e89b3 63 int scanned = sscanf(&addr[i], "%hhu", &bytes[count]);
Christopher Haster 111:df01ca3e89b3 64 if (scanned < 1) {
Christopher Haster 111:df01ca3e89b3 65 return;
Christopher Haster 111:df01ca3e89b3 66 }
Christopher Haster 111:df01ca3e89b3 67
Christopher Haster 111:df01ca3e89b3 68 for (; addr[i] != '.'; i++) {
Christopher Haster 111:df01ca3e89b3 69 if (!addr[i]) {
Christopher Haster 111:df01ca3e89b3 70 return;
Christopher Haster 111:df01ca3e89b3 71 }
Christopher Haster 111:df01ca3e89b3 72 }
Christopher Haster 111:df01ca3e89b3 73
Christopher Haster 111:df01ca3e89b3 74 i++;
Christopher Haster 111:df01ca3e89b3 75 }
Christopher Haster 94:644df37bb05b 76 }
Christopher Haster 94:644df37bb05b 77
Christopher Haster 100:90d8f662de83 78 static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) {
Christopher Haster 100:90d8f662de83 79 int count = 0;
Christopher Haster 100:90d8f662de83 80 int i = 0;
Christopher Haster 100:90d8f662de83 81
Christopher Haster 100:90d8f662de83 82 for (; count < NSAPI_IPv6_BYTES/2; count++) {
Christopher Haster 100:90d8f662de83 83 int scanned = sscanf(&chunk[i], "%hx", &shorts[count]);
Christopher Haster 100:90d8f662de83 84 if (scanned < 1) {
Christopher Haster 100:90d8f662de83 85 return count;
Christopher Haster 100:90d8f662de83 86 }
Christopher Haster 100:90d8f662de83 87
Christopher Haster 100:90d8f662de83 88 for (; chunk[i] != ':'; i++) {
Christopher Haster 100:90d8f662de83 89 if (!chunk[i]) {
Christopher Haster 100:90d8f662de83 90 return count+1;
Christopher Haster 100:90d8f662de83 91 }
Christopher Haster 100:90d8f662de83 92 }
Christopher Haster 100:90d8f662de83 93
Christopher Haster 100:90d8f662de83 94 i++;
Christopher Haster 100:90d8f662de83 95 }
Christopher Haster 100:90d8f662de83 96
Christopher Haster 100:90d8f662de83 97 return count;
Christopher Haster 100:90d8f662de83 98 }
Christopher Haster 100:90d8f662de83 99
Christopher Haster 100:90d8f662de83 100 static void ipv6_from_address(uint8_t *bytes, const char *addr)
Christopher Haster 94:644df37bb05b 101 {
Christopher Haster 100:90d8f662de83 102 // Start with zeroed address
Christopher Haster 94:644df37bb05b 103 uint16_t shorts[NSAPI_IPv6_BYTES/2];
Christopher Haster 100:90d8f662de83 104 memset(shorts, 0, sizeof shorts);
Christopher Haster 100:90d8f662de83 105
Christopher Haster 100:90d8f662de83 106 int suffix = 0;
Christopher Haster 94:644df37bb05b 107
Christopher Haster 100:90d8f662de83 108 // Find double colons and scan suffix
Christopher Haster 100:90d8f662de83 109 for (int i = 0; addr[i]; i++) {
Christopher Haster 100:90d8f662de83 110 if (addr[i] == ':' && addr[i+1] == ':') {
Christopher Haster 100:90d8f662de83 111 suffix = ipv6_scan_chunk(shorts, &addr[i+2]);
Christopher Haster 100:90d8f662de83 112 break;
Christopher Haster 100:90d8f662de83 113 }
Christopher Haster 100:90d8f662de83 114 }
Christopher Haster 100:90d8f662de83 115
Christopher Haster 100:90d8f662de83 116 // Move suffix to end
Christopher Haster 100:90d8f662de83 117 memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0],
Christopher Haster 100:90d8f662de83 118 suffix*sizeof(uint16_t));
Christopher Haster 100:90d8f662de83 119
Christopher Haster 100:90d8f662de83 120 // Scan prefix
Christopher Haster 100:90d8f662de83 121 ipv6_scan_chunk(shorts, &addr[0]);
Christopher Haster 100:90d8f662de83 122
Christopher Haster 100:90d8f662de83 123 // Flip bytes
Christopher Haster 94:644df37bb05b 124 for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
Christopher Haster 94:644df37bb05b 125 bytes[2*i+0] = (uint8_t)(shorts[i] >> 8);
Christopher Haster 94:644df37bb05b 126 bytes[2*i+1] = (uint8_t)(shorts[i] >> 0);
Christopher Haster 94:644df37bb05b 127 }
Christopher Haster 94:644df37bb05b 128 }
Christopher Haster 94:644df37bb05b 129
Christopher Haster 94:644df37bb05b 130 static void ipv4_to_address(char *addr, const uint8_t *bytes)
Christopher Haster 94:644df37bb05b 131 {
Christopher Haster 94:644df37bb05b 132 sprintf(addr, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
Christopher Haster 94:644df37bb05b 133 }
Christopher Haster 94:644df37bb05b 134
Christopher Haster 94:644df37bb05b 135 static void ipv6_to_address(char *addr, const uint8_t *bytes)
Christopher Haster 94:644df37bb05b 136 {
Christopher Haster 100:90d8f662de83 137 for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
Christopher Haster 100:90d8f662de83 138 sprintf(&addr[5*i], "%02x%02x", bytes[2*i], bytes[2*i+1]);
Christopher Haster 100:90d8f662de83 139 addr[5*i+4] = ':';
Christopher Haster 100:90d8f662de83 140 }
Christopher Haster 100:90d8f662de83 141 addr[NSAPI_IPv6_SIZE-1] = '\0';
Christopher Haster 100:90d8f662de83 142 }
Christopher Haster 97:68232387bc75 143
Christopher Haster 94:644df37bb05b 144
Christopher Haster 105:2fd212f8da61 145 SocketAddress::SocketAddress(NetworkStack *iface, const char *host, uint16_t port)
Christopher Haster 89:b1d417383c0d 146 {
Christopher Haster 94:644df37bb05b 147 // Check for valid IP addresses
Christopher Haster 100:90d8f662de83 148 if (host && ipv4_is_valid(host)) {
Christopher Haster 94:644df37bb05b 149 _ip_version = NSAPI_IPv4;
Christopher Haster 100:90d8f662de83 150 ipv4_from_address(_ip_bytes, host);
Christopher Haster 100:90d8f662de83 151 } else if (host && ipv6_is_valid(host)) {
Christopher Haster 94:644df37bb05b 152 _ip_version = NSAPI_IPv6;
Christopher Haster 100:90d8f662de83 153 ipv4_from_address(_ip_bytes, host);
Christopher Haster 94:644df37bb05b 154 } else {
Christopher Haster 94:644df37bb05b 155 // DNS lookup
Christopher Haster 95:b3c679f20d13 156 int err = iface->gethostbyname(this, host);
Christopher Haster 94:644df37bb05b 157 if (!err) {
Christopher Haster 94:644df37bb05b 158 set_port(port);
Christopher Haster 94:644df37bb05b 159 } else {
Christopher Haster 94:644df37bb05b 160 _ip_version = NSAPI_IPv4;
Christopher Haster 94:644df37bb05b 161 memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
Christopher Haster 94:644df37bb05b 162 set_port(0);
Christopher Haster 94:644df37bb05b 163 }
Christopher Haster 89:b1d417383c0d 164 }
Christopher Haster 89:b1d417383c0d 165 }
Christopher Haster 89:b1d417383c0d 166
Christopher Haster 89:b1d417383c0d 167 SocketAddress::SocketAddress(const char *addr, uint16_t port)
Christopher Haster 89:b1d417383c0d 168 {
Christopher Haster 89:b1d417383c0d 169 set_ip_address(addr);
Christopher Haster 89:b1d417383c0d 170 set_port(port);
Christopher Haster 89:b1d417383c0d 171 }
Christopher Haster 89:b1d417383c0d 172
Christopher Haster 94:644df37bb05b 173 SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port)
Christopher Haster 94:644df37bb05b 174 {
Christopher Haster 94:644df37bb05b 175 set_ip_bytes(bytes, version);
Christopher Haster 94:644df37bb05b 176 set_port(port);
Christopher Haster 94:644df37bb05b 177 }
Christopher Haster 94:644df37bb05b 178
Christopher Haster 89:b1d417383c0d 179 SocketAddress::SocketAddress(const SocketAddress &addr)
Christopher Haster 89:b1d417383c0d 180 {
Christopher Haster 94:644df37bb05b 181 set_ip_bytes(addr.get_ip_bytes(), addr.get_ip_version());
Christopher Haster 89:b1d417383c0d 182 set_port(addr.get_port());
Christopher Haster 89:b1d417383c0d 183 }
Christopher Haster 89:b1d417383c0d 184
Christopher Haster 89:b1d417383c0d 185 void SocketAddress::set_ip_address(const char *addr)
Christopher Haster 89:b1d417383c0d 186 {
Christopher Haster 94:644df37bb05b 187 _ip_address[0] = '\0';
Christopher Haster 94:644df37bb05b 188
Christopher Haster 100:90d8f662de83 189 if (addr && ipv4_is_valid(addr)) {
Christopher Haster 94:644df37bb05b 190 _ip_version = NSAPI_IPv4;
Christopher Haster 100:90d8f662de83 191 ipv4_from_address(_ip_bytes, addr);
Christopher Haster 100:90d8f662de83 192 } else if (addr && ipv6_is_valid(addr)) {
Christopher Haster 94:644df37bb05b 193 _ip_version = NSAPI_IPv6;
Christopher Haster 100:90d8f662de83 194 ipv6_from_address(_ip_bytes, addr);
Christopher Haster 94:644df37bb05b 195 } else {
Christopher Haster 94:644df37bb05b 196 _ip_version = NSAPI_IPv4;
Christopher Haster 94:644df37bb05b 197 memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
Christopher Haster 94:644df37bb05b 198 }
Christopher Haster 94:644df37bb05b 199 }
Christopher Haster 94:644df37bb05b 200
Christopher Haster 94:644df37bb05b 201 void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version)
Christopher Haster 94:644df37bb05b 202 {
Christopher Haster 94:644df37bb05b 203 _ip_address[0] = '\0';
Christopher Haster 94:644df37bb05b 204
Christopher Haster 94:644df37bb05b 205 if (_ip_version == NSAPI_IPv4) {
Christopher Haster 94:644df37bb05b 206 _ip_version = NSAPI_IPv4;
Christopher Haster 94:644df37bb05b 207 memcpy(_ip_bytes, bytes, NSAPI_IPv4_BYTES);
Christopher Haster 94:644df37bb05b 208 } else if (_ip_version == NSAPI_IPv6) {
Christopher Haster 94:644df37bb05b 209 _ip_version = NSAPI_IPv6;
Christopher Haster 94:644df37bb05b 210 memcpy(_ip_bytes, bytes, NSAPI_IPv6_BYTES);
Christopher Haster 94:644df37bb05b 211 } else {
Christopher Haster 94:644df37bb05b 212 _ip_version = NSAPI_IPv4;
Christopher Haster 94:644df37bb05b 213 memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
Christopher Haster 94:644df37bb05b 214 }
Christopher Haster 89:b1d417383c0d 215 }
Christopher Haster 89:b1d417383c0d 216
Christopher Haster 89:b1d417383c0d 217 void SocketAddress::set_port(uint16_t port)
Christopher Haster 89:b1d417383c0d 218 {
Christopher Haster 89:b1d417383c0d 219 _port = port;
Christopher Haster 89:b1d417383c0d 220 }
Christopher Haster 89:b1d417383c0d 221
Christopher Haster 89:b1d417383c0d 222 const char *SocketAddress::get_ip_address() const
Christopher Haster 89:b1d417383c0d 223 {
Christopher Haster 94:644df37bb05b 224 char *ip_address = (char *)_ip_address;
Christopher Haster 94:644df37bb05b 225
Christopher Haster 94:644df37bb05b 226 if (!ip_address[0]) {
Christopher Haster 94:644df37bb05b 227 if (_ip_version == NSAPI_IPv4) {
Christopher Haster 94:644df37bb05b 228 ipv4_to_address(ip_address, _ip_bytes);
Christopher Haster 97:68232387bc75 229 } else if (_ip_version == NSAPI_IPv6) {
Christopher Haster 94:644df37bb05b 230 ipv6_to_address(ip_address, _ip_bytes);
Christopher Haster 94:644df37bb05b 231 }
Christopher Haster 89:b1d417383c0d 232 }
Christopher Haster 94:644df37bb05b 233
Christopher Haster 94:644df37bb05b 234 return ip_address;
Christopher Haster 94:644df37bb05b 235 }
Christopher Haster 94:644df37bb05b 236
Christopher Haster 94:644df37bb05b 237 const void *SocketAddress::get_ip_bytes() const
Christopher Haster 94:644df37bb05b 238 {
Christopher Haster 94:644df37bb05b 239 return _ip_bytes;
Christopher Haster 94:644df37bb05b 240 }
Christopher Haster 94:644df37bb05b 241
Christopher Haster 94:644df37bb05b 242 nsapi_version_t SocketAddress::get_ip_version() const
Christopher Haster 94:644df37bb05b 243 {
Christopher Haster 94:644df37bb05b 244 return _ip_version;
Christopher Haster 89:b1d417383c0d 245 }
Christopher Haster 89:b1d417383c0d 246
Christopher Haster 89:b1d417383c0d 247 uint16_t SocketAddress::get_port() const
Christopher Haster 89:b1d417383c0d 248 {
Christopher Haster 89:b1d417383c0d 249 return _port;
Christopher Haster 89:b1d417383c0d 250 }
Christopher Haster 94:644df37bb05b 251
Christopher Haster 94:644df37bb05b 252 SocketAddress::operator bool() const
Christopher Haster 94:644df37bb05b 253 {
Christopher Haster 94:644df37bb05b 254 int count = 0;
Christopher Haster 94:644df37bb05b 255 if (_ip_version == NSAPI_IPv4) {
Christopher Haster 94:644df37bb05b 256 count = NSAPI_IPv4_BYTES;
Christopher Haster 94:644df37bb05b 257 } else if (_ip_version == NSAPI_IPv6) {
Christopher Haster 94:644df37bb05b 258 count = NSAPI_IPv6_BYTES;
Christopher Haster 94:644df37bb05b 259 }
Christopher Haster 94:644df37bb05b 260
Christopher Haster 94:644df37bb05b 261 for (int i = 0; i < count; i++) {
Christopher Haster 94:644df37bb05b 262 if (_ip_bytes[i]) {
Christopher Haster 94:644df37bb05b 263 return true;
Christopher Haster 94:644df37bb05b 264 }
Christopher Haster 94:644df37bb05b 265 }
Christopher Haster 94:644df37bb05b 266
Christopher Haster 94:644df37bb05b 267 return false;
Christopher Haster 94:644df37bb05b 268 }