Subject: windows: support to bind to a specific IPv6 address
This commit is contained in:
parent
2ce39fe26c
commit
af7f943e05
7 changed files with 203 additions and 37 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue