Skip to content

Commit 7b27e78

Browse files
committed
Add IPv6 to WifiClient (client)
We need to be able to connect to remote servers over IPv6 too, and thats need different approach in DNS queries and connect(). As i'm trying to keep maximum compatibility, i introduce different behaviour if IPv6 is enabled, and backward compatible (as much as possible), if IPv6 is not enabled. IN future when IPv6 functions are tested well enough, it can be simplified. This implementation tested on esp32 in following scenarios using BasicHttpClient: IPv6 true: IPv6 only website (caveat 1) - OK Website with A and AAAA is present (caveat 1) - OK IPv4 only website - OK IPv6 not enabled: IPv6 only website - wont open (expected) Website with A and AAAA is present - OK, opens over IPv4 IPv4 only website - OK caveat 1 - sometimes SLAAC is slower than DHCPv4, so we might have status WL_CONNECTED, but IPv6 global scope is not ready yet. Signed-off-by: Denys Fedoryshchenko <[email protected]>
1 parent 9337b5c commit 7b27e78

File tree

4 files changed

+92
-7
lines changed

4 files changed

+92
-7
lines changed

libraries/WiFi/src/WiFiClient.cpp

+35-7
Original file line numberDiff line numberDiff line change
@@ -210,22 +210,43 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
210210
{
211211
return connect(ip,port,_timeout);
212212
}
213+
213214
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout)
214215
{
216+
ip_addr_t dstip;
217+
dstip = IPADDR_ANY_TYPE_INIT;
218+
IP_ADDR4(&dstip, ip[0], ip[1], ip[2], ip[3]);
219+
return connect(dstip, port, timeout);
220+
}
221+
222+
int WiFiClient::connect(ip_addr_t ip, uint16_t port, int32_t timeout)
223+
{
224+
struct sockaddr_storage serveraddr;
215225
_timeout = timeout;
216-
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
226+
int sockfd = -1;
227+
228+
if (IP_IS_V6(&ip)) {
229+
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
230+
struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serveraddr;
231+
memset((char *) tmpaddr, 0, sizeof(struct sockaddr_in6));
232+
tmpaddr->sin6_family = AF_INET6;
233+
inet6_addr_from_ip6addr(&tmpaddr->sin6_addr, ip_2_ip6(&ip));
234+
tmpaddr->sin6_port = htons(port);
235+
}
236+
if (sockfd == -1 && IP_IS_V4(&ip)) {
237+
sockfd = socket(AF_INET, SOCK_STREAM, 0);
238+
struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr;
239+
memset((char *) tmpaddr, 0, sizeof(struct sockaddr_in));
240+
tmpaddr->sin_family = AF_INET;
241+
tmpaddr->sin_addr.s_addr = ip4_addr_get_u32(&ip.u_addr.ip4);
242+
tmpaddr->sin_port = htons(port);
243+
}
217244
if (sockfd < 0) {
218245
log_e("socket: %d", errno);
219246
return 0;
220247
}
221248
fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFL, 0 ) | O_NONBLOCK );
222249

223-
uint32_t ip_addr = ip;
224-
struct sockaddr_in serveraddr;
225-
memset((char *) &serveraddr, 0, sizeof(serveraddr));
226-
serveraddr.sin_family = AF_INET;
227-
memcpy((void *)&serveraddr.sin_addr.s_addr, (const void *)(&ip_addr), 4);
228-
serveraddr.sin_port = htons(port);
229250
fd_set fdset;
230251
struct timeval tv;
231252
FD_ZERO(&fdset);
@@ -294,6 +315,13 @@ int WiFiClient::connect(const char *host, uint16_t port)
294315

295316
int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout)
296317
{
318+
if (WiFiGenericClass::getStatusBits() & WIFI_WANT_IP6_BIT) {
319+
ip_addr_t srv6;
320+
if(!WiFiGenericClass::hostByName6(host, srv6)){
321+
return 0;
322+
}
323+
return connect(srv6, port, timeout);
324+
}
297325
IPAddress srv((uint32_t)0);
298326
if(!WiFiGenericClass::hostByName(host, srv)){
299327
return 0;

libraries/WiFi/src/WiFiClient.h

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "Arduino.h"
2525
#include "Client.h"
2626
#include <memory>
27+
#include "lwip/ip_addr.h"
2728

2829
class WiFiClientSocketHandle;
2930
class WiFiClientRxBuffer;
@@ -49,6 +50,7 @@ class WiFiClient : public ESPLwIPClient
4950
WiFiClient();
5051
WiFiClient(int fd);
5152
~WiFiClient();
53+
int connect(ip_addr_t ip, uint16_t port, int32_t timeout);
5254
int connect(IPAddress ip, uint16_t port);
5355
int connect(IPAddress ip, uint16_t port, int32_t timeout);
5456
int connect(const char *host, uint16_t port);

libraries/WiFi/src/WiFiGeneric.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,25 @@ static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, v
13351335
xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT);
13361336
}
13371337

1338+
/**
1339+
* IPv6 compatible DNS callback
1340+
* @param name
1341+
* @param ipaddr
1342+
* @param callback_arg
1343+
*/
1344+
static void wifi_dns6_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
1345+
{
1346+
struct dns_api_msg *msg = (struct dns_api_msg *)callback_arg;
1347+
1348+
if(ipaddr && !msg->result) {
1349+
msg->ip_addr = *ipaddr;
1350+
msg->result = 1;
1351+
} else {
1352+
msg->result = -1;
1353+
}
1354+
xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT);
1355+
}
1356+
13381357
/**
13391358
* Resolve the given hostname to an IP address.
13401359
* @param aHostname Name to be resolved
@@ -1362,6 +1381,36 @@ int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
13621381
return (uint32_t)aResult != 0;
13631382
}
13641383

1384+
/**
1385+
* Resolve the given hostname to an IP6 address.
1386+
* @param aHostname Name to be resolved
1387+
* @param aResult IPv6Address structure to store the returned IP address
1388+
* @return 1 if aHostname was successfully converted to an IP address,
1389+
* else error code
1390+
*/
1391+
int WiFiGenericClass::hostByName6(const char* aHostname, ip_addr_t& aResult)
1392+
{
1393+
ip_addr_t addr;
1394+
struct dns_api_msg arg;
1395+
1396+
memset(&arg, 0x0, sizeof(arg));
1397+
waitStatusBits(WIFI_DNS_IDLE_BIT, 16000);
1398+
clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT);
1399+
1400+
err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns6_found_callback,
1401+
&arg, LWIP_DNS_ADDRTYPE_IPV6_IPV4);
1402+
if(err == ERR_OK) {
1403+
aResult = addr;
1404+
} else if(err == ERR_INPROGRESS) {
1405+
waitStatusBits(WIFI_DNS_DONE_BIT, 15000); //real internal timeout in lwip library is 14[s]
1406+
clearStatusBits(WIFI_DNS_DONE_BIT);
1407+
if (arg.result == 1)
1408+
aResult = arg.ip_addr;
1409+
}
1410+
setStatusBits(WIFI_DNS_IDLE_BIT);
1411+
return (uint32_t)err == ERR_OK || (err == ERR_INPROGRESS && arg.result == 1);
1412+
}
1413+
13651414
IPAddress WiFiGenericClass::calculateNetworkID(IPAddress ip, IPAddress subnet) {
13661415
IPAddress networkID;
13671416

libraries/WiFi/src/WiFiGeneric.h

+6
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ typedef enum {
152152
WIFI_TX_ANT_AUTO
153153
} wifi_tx_ant_t;
154154

155+
struct dns_api_msg {
156+
ip_addr_t ip_addr;
157+
int result;
158+
};
159+
155160
class WiFiGenericClass
156161
{
157162
public:
@@ -210,6 +215,7 @@ class WiFiGenericClass
210215

211216
public:
212217
static int hostByName(const char *aHostname, IPAddress &aResult);
218+
static int hostByName6(const char *aHostname, ip_addr_t &aResult);
213219

214220
static IPAddress calculateNetworkID(IPAddress ip, IPAddress subnet);
215221
static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet);

0 commit comments

Comments
 (0)