Subject: windows: support to bind to a specific IPv6 address

This commit is contained in:
Leonardo Maccari Rufino 2017-06-05 13:59:22 -03:00 committed by Andy Green
parent 2ce39fe26c
commit af7f943e05
7 changed files with 203 additions and 37 deletions

View file

@ -1906,46 +1906,14 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
v = (struct sockaddr *)&serv_addr6;
n = sizeof(struct sockaddr_in6);
bzero((char *) &serv_addr6, sizeof(serv_addr6));
if (iface &&
interface_to_sa(vhost, iface,
(struct sockaddr_in *)v, n) < 0) {
lwsl_err("Unable to find interface %s\n", iface);
return -1;
}
#ifndef WIN32
if (iface) {
struct ifaddrs *addrs, *addr;
char ip[NI_MAXHOST];
unsigned int i;
getifaddrs(&addrs);
for (addr = addrs; addr; addr = addr->ifa_next) {
if (!addr->ifa_addr ||
addr->ifa_addr->sa_family != AF_INET6)
continue;
getnameinfo(addr->ifa_addr,
sizeof(struct sockaddr_in6),
ip, sizeof(ip),
NULL, 0, NI_NUMERICHOST);
i = 0;
while (ip[i])
if (ip[i++] == '%') {
ip[i - 1] = '\0';
break;
}
if (!strcmp(ip, iface)) {
serv_addr6.sin6_scope_id =
if_nametoindex(addr->ifa_name);
break;
}
if (interface_to_sa(vhost, iface,
(struct sockaddr_in *)v, n) < 0) {
lwsl_err("Unable to find interface %s\n", iface);
return -1;
}
freeifaddrs(addrs);
serv_addr6.sin6_scope_id = lws_get_addr_scope(iface);
}
#endif
serv_addr6.sin6_family = AF_INET6;
serv_addr6.sin6_port = htons(port);
@ -2000,6 +1968,108 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
return port;
}
#if defined(LWS_USE_IPV6)
LWS_EXTERN unsigned long
lws_get_addr_scope(const char *ipaddr)
{
unsigned long scope = 0;
#ifndef WIN32
struct ifaddrs *addrs, *addr;
char ip[NI_MAXHOST];
unsigned int i;
getifaddrs(&addrs);
for (addr = addrs; addr; addr = addr->ifa_next) {
if (!addr->ifa_addr ||
addr->ifa_addr->sa_family != AF_INET6)
continue;
getnameinfo(addr->ifa_addr,
sizeof(struct sockaddr_in6),
ip, sizeof(ip),
NULL, 0, NI_NUMERICHOST);
i = 0;
while (ip[i])
if (ip[i++] == '%') {
ip[i - 1] = '\0';
break;
}
if (!strcmp(ip, ipaddr)) {
scope = if_nametoindex(addr->ifa_name);
break;
}
}
freeifaddrs(addrs);
#else
PIP_ADAPTER_ADDRESSES adapter, addrs = NULL;
PIP_ADAPTER_UNICAST_ADDRESS addr;
ULONG size = 0;
DWORD ret;
struct sockaddr_in6 *sockaddr;
char ip[NI_MAXHOST];
unsigned int i;
int found = 0;
for (i = 0; i < 5; i++)
{
ret = GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX,
NULL, addrs, &size);
if ((ret == NO_ERROR) || (ret == ERROR_NO_DATA)) {
break;
} else if (ret == ERROR_BUFFER_OVERFLOW)
{
if (addrs)
free(addrs);
addrs = (IP_ADAPTER_ADDRESSES *) malloc(size);
} else
{
if (addrs)
{
free(addrs);
addrs = NULL;
}
lwsl_err("Failed to get IPv6 address table (%d)", ret);
break;
}
}
if ((ret == NO_ERROR) && (addrs))
{
adapter = addrs;
while ((adapter) && (!found))
{
addr = adapter->FirstUnicastAddress;
while ((addr) && (!found))
{
if (addr->Address.lpSockaddr->sa_family == AF_INET6)
{
sockaddr = (struct sockaddr_in6 *) (addr->Address.lpSockaddr);
lws_plat_inet_ntop(sockaddr->sin6_family, &sockaddr->sin6_addr,
ip, sizeof(ip));
if (!strcmp(ip, ipaddr)) {
scope = sockaddr->sin6_scope_id;
found = 1;
break;
}
}
addr = addr->Next;
}
adapter = adapter->Next;
}
}
if (addrs)
free(addrs);
#endif
return scope;
}
#endif
LWS_EXTERN void
lws_restart_ws_ping_pong_timer(struct lws *wsi)
{

View file

@ -433,6 +433,12 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
return inet_ntop(af, src, dst, cnt);
}
LWS_VISIBLE int
lws_plat_inet_pton(int af, const char *src, void *dst)
{
return 1; // inet_pton(af, src, dst);
}
LWS_VISIBLE lws_fop_fd_t IRAM_ATTR
_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
const char *vpath, lws_fop_flags_t *flags)

View file

@ -630,6 +630,13 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
return 0;
}
LWS_VISIBLE int
lws_plat_inet_pton(int af, const char *src, void *dst)
{
//return inet_pton(af, src, dst);
return 1;
}
LWS_VISIBLE int
lws_plat_init(struct lws_context *context,
struct lws_context_creation_info *info)

View file

@ -261,6 +261,13 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
return "lws_plat_inet_ntop";
}
LWS_VISIBLE int
lws_plat_inet_pton(int af, const char *src, void *dst)
{
//return inet_pton(af, src, dst);
return 1;
}
LWS_VISIBLE lws_fop_fd_t
_lws_plat_file_open(lws_plat_file_open(struct lws_plat_file_ops *fops,
const char *filename, lws_fop_flags_t *flags)

View file

@ -616,6 +616,12 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
return inet_ntop(af, src, dst, cnt);
}
LWS_VISIBLE int
lws_plat_inet_pton(int af, const char *src, void *dst)
{
return inet_pton(af, src, dst);
}
LWS_VISIBLE lws_fop_fd_t
_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
const char *vpath, lws_fop_flags_t *flags)

View file

@ -398,6 +398,16 @@ LWS_VISIBLE LWS_EXTERN int
lws_interface_to_sa(int ipv6,
const char *ifname, struct sockaddr_in *addr, size_t addrlen)
{
#ifdef LWS_USE_IPV6
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
if (ipv6) {
if (lws_plat_inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) {
return 0;
}
}
#endif
long long address = inet_addr(ifname);
if (address == INADDR_NONE) {
@ -525,6 +535,59 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
return ok ? dst : NULL;
}
LWS_VISIBLE int
lws_plat_inet_pton(int af, const char *src, void *dst)
{
WCHAR *buffer;
DWORD bufferlen = strlen(src) + 1;
BOOL ok = FALSE;
buffer = lws_malloc(bufferlen * 2);
if (!buffer) {
lwsl_err("Out of memory\n");
return -1;
}
if (MultiByteToWideChar(CP_ACP, 0, src, bufferlen, buffer, bufferlen) <= 0) {
lwsl_err("Failed to convert multi byte to wide char\n");
lws_free(buffer);
return -1;
}
if (af == AF_INET) {
struct sockaddr_in dstaddr;
int dstaddrlen = sizeof(dstaddr);
bzero(&dstaddr, sizeof(dstaddr));
dstaddr.sin_family = AF_INET;
if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
ok = TRUE;
memcpy(dst, &dstaddr.sin_addr, sizeof(dstaddr.sin_addr));
}
#ifdef LWS_USE_IPV6
} else if (af == AF_INET6) {
struct sockaddr_in6 dstaddr;
int dstaddrlen = sizeof(dstaddr);
bzero(&dstaddr, sizeof(dstaddr));
dstaddr.sin6_family = AF_INET6;
if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
ok = TRUE;
memcpy(dst, &dstaddr.sin6_addr, sizeof(dstaddr.sin6_addr));
}
#endif
} else
lwsl_err("Unsupported type\n");
if (!ok) {
int rv = WSAGetLastError();
lwsl_err("WSAAddressToString() : %d\n", rv);
}
lws_free(buffer);
return ok ? 1 : -1;
}
LWS_VISIBLE lws_fop_fd_t
_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
const char *vpath, lws_fop_flags_t *flags)

View file

@ -1674,6 +1674,11 @@ LWS_EXTERN int
lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
const char *iface);
#if defined(LWS_USE_IPV6)
LWS_EXTERN unsigned long
lws_get_addr_scope(const char *ipaddr);
#endif
LWS_EXTERN void
lws_close_free_wsi(struct lws *wsi, enum lws_close_status);
@ -2163,6 +2168,8 @@ LWS_EXTERN unsigned long long
time_in_microseconds(void);
LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt);
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_plat_inet_pton(int af, const char *src, void *dst);
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len);