mirror of https://github.com/lukechilds/node.git
82 changed files with 1807 additions and 310 deletions
@ -0,0 +1,54 @@ |
|||||
|
/*
|
||||
|
* Copyright (c) 1995, 1999 |
||||
|
* Berkeley Software Design, Inc. All rights reserved. |
||||
|
* |
||||
|
* Redistribution and use in source and binary forms, with or without |
||||
|
* modification, are permitted provided that the following conditions |
||||
|
* are met: |
||||
|
* 1. Redistributions of source code must retain the above copyright |
||||
|
* notice, this list of conditions and the following disclaimer. |
||||
|
* |
||||
|
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND |
||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE |
||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
|
* SUCH DAMAGE. |
||||
|
* |
||||
|
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp |
||||
|
*/ |
||||
|
|
||||
|
#ifndef _IFADDRS_H_ |
||||
|
#define _IFADDRS_H_ |
||||
|
|
||||
|
struct ifaddrs { |
||||
|
struct ifaddrs *ifa_next; |
||||
|
char *ifa_name; |
||||
|
unsigned int ifa_flags; |
||||
|
struct sockaddr *ifa_addr; |
||||
|
struct sockaddr *ifa_netmask; |
||||
|
struct sockaddr *ifa_dstaddr; |
||||
|
void *ifa_data; |
||||
|
}; |
||||
|
|
||||
|
/*
|
||||
|
* This may have been defined in <net/if.h>. Note that if <net/if.h> is |
||||
|
* to be included it must be included before this header file. |
||||
|
*/ |
||||
|
#ifndef ifa_broadaddr |
||||
|
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ |
||||
|
#endif |
||||
|
|
||||
|
#include <sys/cdefs.h> |
||||
|
|
||||
|
__BEGIN_DECLS |
||||
|
extern int getifaddrs(struct ifaddrs **ifap); |
||||
|
extern void freeifaddrs(struct ifaddrs *ifa); |
||||
|
__END_DECLS |
||||
|
|
||||
|
#endif |
@ -0,0 +1,702 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013, Kenneth MacKay |
||||
|
Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement n° 289016) |
||||
|
All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||
|
are permitted provided that the following conditions are met: |
||||
|
* Redistributions of source code must retain the above copyright notice, this |
||||
|
list of conditions and the following disclaimer. |
||||
|
* Redistributions in binary form must reproduce the above copyright notice, |
||||
|
this list of conditions and the following disclaimer in the documentation |
||||
|
and/or other materials provided with the distribution. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
*/ |
||||
|
|
||||
|
#include "android-ifaddrs.h" |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <errno.h> |
||||
|
#include <unistd.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <net/if_arp.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <linux/netlink.h> |
||||
|
#include <linux/rtnetlink.h> |
||||
|
|
||||
|
typedef struct NetlinkList |
||||
|
{ |
||||
|
struct NetlinkList *m_next; |
||||
|
struct nlmsghdr *m_data; |
||||
|
unsigned int m_size; |
||||
|
} NetlinkList; |
||||
|
|
||||
|
static int netlink_socket(void) |
||||
|
{ |
||||
|
struct sockaddr_nl l_addr; |
||||
|
|
||||
|
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
||||
|
if(l_socket < 0) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
memset(&l_addr, 0, sizeof(l_addr)); |
||||
|
l_addr.nl_family = AF_NETLINK; |
||||
|
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) |
||||
|
{ |
||||
|
close(l_socket); |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
return l_socket; |
||||
|
} |
||||
|
|
||||
|
static int netlink_send(int p_socket, int p_request) |
||||
|
{ |
||||
|
char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))]; |
||||
|
|
||||
|
struct nlmsghdr *l_hdr; |
||||
|
struct rtgenmsg *l_msg; |
||||
|
struct sockaddr_nl l_addr; |
||||
|
|
||||
|
memset(l_buffer, 0, sizeof(l_buffer)); |
||||
|
|
||||
|
l_hdr = (struct nlmsghdr *)l_buffer; |
||||
|
l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr); |
||||
|
|
||||
|
l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg)); |
||||
|
l_hdr->nlmsg_type = p_request; |
||||
|
l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; |
||||
|
l_hdr->nlmsg_pid = 0; |
||||
|
l_hdr->nlmsg_seq = p_socket; |
||||
|
l_msg->rtgen_family = AF_UNSPEC; |
||||
|
|
||||
|
memset(&l_addr, 0, sizeof(l_addr)); |
||||
|
l_addr.nl_family = AF_NETLINK; |
||||
|
return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); |
||||
|
} |
||||
|
|
||||
|
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) |
||||
|
{ |
||||
|
struct sockaddr_nl l_addr; |
||||
|
struct msghdr l_msg; |
||||
|
|
||||
|
struct iovec l_iov; |
||||
|
l_iov.iov_base = p_buffer; |
||||
|
l_iov.iov_len = p_len; |
||||
|
|
||||
|
for(;;) |
||||
|
{ |
||||
|
int l_result; |
||||
|
l_msg.msg_name = (void *)&l_addr; |
||||
|
l_msg.msg_namelen = sizeof(l_addr); |
||||
|
l_msg.msg_iov = &l_iov; |
||||
|
l_msg.msg_iovlen = 1; |
||||
|
l_msg.msg_control = NULL; |
||||
|
l_msg.msg_controllen = 0; |
||||
|
l_msg.msg_flags = 0; |
||||
|
l_result = recvmsg(p_socket, &l_msg, 0); |
||||
|
|
||||
|
if(l_result < 0) |
||||
|
{ |
||||
|
if(errno == EINTR) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
return -2; |
||||
|
} |
||||
|
|
||||
|
/* Buffer was too small */ |
||||
|
if(l_msg.msg_flags & MSG_TRUNC) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
return l_result; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) |
||||
|
{ |
||||
|
size_t l_size = 4096; |
||||
|
void *l_buffer = NULL; |
||||
|
|
||||
|
for(;;) |
||||
|
{ |
||||
|
int l_read; |
||||
|
|
||||
|
free(l_buffer); |
||||
|
l_buffer = malloc(l_size); |
||||
|
if (l_buffer == NULL) |
||||
|
{ |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
l_read = netlink_recv(p_socket, l_buffer, l_size); |
||||
|
*p_size = l_read; |
||||
|
if(l_read == -2) |
||||
|
{ |
||||
|
free(l_buffer); |
||||
|
return NULL; |
||||
|
} |
||||
|
if(l_read >= 0) |
||||
|
{ |
||||
|
pid_t l_pid = getpid(); |
||||
|
struct nlmsghdr *l_hdr; |
||||
|
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) |
||||
|
{ |
||||
|
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if(l_hdr->nlmsg_type == NLMSG_DONE) |
||||
|
{ |
||||
|
*p_done = 1; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if(l_hdr->nlmsg_type == NLMSG_ERROR) |
||||
|
{ |
||||
|
free(l_buffer); |
||||
|
return NULL; |
||||
|
} |
||||
|
} |
||||
|
return l_buffer; |
||||
|
} |
||||
|
|
||||
|
l_size *= 2; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) |
||||
|
{ |
||||
|
NetlinkList *l_item = malloc(sizeof(NetlinkList)); |
||||
|
if (l_item == NULL) |
||||
|
{ |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
l_item->m_next = NULL; |
||||
|
l_item->m_data = p_data; |
||||
|
l_item->m_size = p_size; |
||||
|
return l_item; |
||||
|
} |
||||
|
|
||||
|
static void freeResultList(NetlinkList *p_list) |
||||
|
{ |
||||
|
NetlinkList *l_cur; |
||||
|
while(p_list) |
||||
|
{ |
||||
|
l_cur = p_list; |
||||
|
p_list = p_list->m_next; |
||||
|
free(l_cur->m_data); |
||||
|
free(l_cur); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static NetlinkList *getResultList(int p_socket, int p_request) |
||||
|
{ |
||||
|
int l_size; |
||||
|
int l_done; |
||||
|
NetlinkList *l_list; |
||||
|
NetlinkList *l_end; |
||||
|
|
||||
|
if(netlink_send(p_socket, p_request) < 0) |
||||
|
{ |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
l_list = NULL; |
||||
|
l_end = NULL; |
||||
|
|
||||
|
l_done = 0; |
||||
|
while(!l_done) |
||||
|
{ |
||||
|
NetlinkList *l_item; |
||||
|
|
||||
|
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); |
||||
|
/* Error */ |
||||
|
if(!l_hdr) |
||||
|
{ |
||||
|
freeResultList(l_list); |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
l_item = newListItem(l_hdr, l_size); |
||||
|
if (!l_item) |
||||
|
{ |
||||
|
freeResultList(l_list); |
||||
|
return NULL; |
||||
|
} |
||||
|
if(!l_list) |
||||
|
{ |
||||
|
l_list = l_item; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
l_end->m_next = l_item; |
||||
|
} |
||||
|
l_end = l_item; |
||||
|
} |
||||
|
return l_list; |
||||
|
} |
||||
|
|
||||
|
static size_t maxSize(size_t a, size_t b) |
||||
|
{ |
||||
|
return (a > b ? a : b); |
||||
|
} |
||||
|
|
||||
|
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) |
||||
|
{ |
||||
|
switch(p_family) |
||||
|
{ |
||||
|
case AF_INET: |
||||
|
return sizeof(struct sockaddr_in); |
||||
|
case AF_INET6: |
||||
|
return sizeof(struct sockaddr_in6); |
||||
|
case AF_PACKET: |
||||
|
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); |
||||
|
default: |
||||
|
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) |
||||
|
{ |
||||
|
switch(p_family) |
||||
|
{ |
||||
|
case AF_INET: |
||||
|
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); |
||||
|
break; |
||||
|
case AF_INET6: |
||||
|
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); |
||||
|
break; |
||||
|
case AF_PACKET: |
||||
|
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); |
||||
|
((struct sockaddr_ll*)p_dest)->sll_halen = p_size; |
||||
|
break; |
||||
|
default: |
||||
|
memcpy(p_dest->sa_data, p_data, p_size); |
||||
|
break; |
||||
|
} |
||||
|
p_dest->sa_family = p_family; |
||||
|
} |
||||
|
|
||||
|
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) |
||||
|
{ |
||||
|
if(!*p_resultList) |
||||
|
{ |
||||
|
*p_resultList = p_entry; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
struct ifaddrs *l_cur = *p_resultList; |
||||
|
while(l_cur->ifa_next) |
||||
|
{ |
||||
|
l_cur = l_cur->ifa_next; |
||||
|
} |
||||
|
l_cur->ifa_next = p_entry; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList) |
||||
|
{ |
||||
|
struct ifaddrs *l_entry; |
||||
|
|
||||
|
char *l_index; |
||||
|
char *l_name; |
||||
|
char *l_addr; |
||||
|
char *l_data; |
||||
|
|
||||
|
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); |
||||
|
|
||||
|
size_t l_nameSize = 0; |
||||
|
size_t l_addrSize = 0; |
||||
|
size_t l_dataSize = 0; |
||||
|
|
||||
|
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); |
||||
|
struct rtattr *l_rta; |
||||
|
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) |
||||
|
{ |
||||
|
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); |
||||
|
switch(l_rta->rta_type) |
||||
|
{ |
||||
|
case IFLA_ADDRESS: |
||||
|
case IFLA_BROADCAST: |
||||
|
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); |
||||
|
break; |
||||
|
case IFLA_IFNAME: |
||||
|
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); |
||||
|
break; |
||||
|
case IFLA_STATS: |
||||
|
l_dataSize += NLMSG_ALIGN(l_rtaSize); |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize); |
||||
|
if (l_entry == NULL) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
memset(l_entry, 0, sizeof(struct ifaddrs)); |
||||
|
l_entry->ifa_name = ""; |
||||
|
|
||||
|
l_index = ((char *)l_entry) + sizeof(struct ifaddrs); |
||||
|
l_name = l_index + sizeof(int); |
||||
|
l_addr = l_name + l_nameSize; |
||||
|
l_data = l_addr + l_addrSize; |
||||
|
|
||||
|
/* Save the interface index so we can look it up when handling the
|
||||
|
* addresses. |
||||
|
*/ |
||||
|
memcpy(l_index, &l_info->ifi_index, sizeof(int)); |
||||
|
|
||||
|
l_entry->ifa_flags = l_info->ifi_flags; |
||||
|
|
||||
|
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); |
||||
|
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) |
||||
|
{ |
||||
|
void *l_rtaData = RTA_DATA(l_rta); |
||||
|
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); |
||||
|
switch(l_rta->rta_type) |
||||
|
{ |
||||
|
case IFLA_ADDRESS: |
||||
|
case IFLA_BROADCAST: |
||||
|
{ |
||||
|
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); |
||||
|
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); |
||||
|
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; |
||||
|
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; |
||||
|
if(l_rta->rta_type == IFLA_ADDRESS) |
||||
|
{ |
||||
|
l_entry->ifa_addr = (struct sockaddr *)l_addr; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; |
||||
|
} |
||||
|
l_addr += NLMSG_ALIGN(l_addrLen); |
||||
|
break; |
||||
|
} |
||||
|
case IFLA_IFNAME: |
||||
|
strncpy(l_name, l_rtaData, l_rtaDataSize); |
||||
|
l_name[l_rtaDataSize] = '\0'; |
||||
|
l_entry->ifa_name = l_name; |
||||
|
break; |
||||
|
case IFLA_STATS: |
||||
|
memcpy(l_data, l_rtaData, l_rtaDataSize); |
||||
|
l_entry->ifa_data = l_data; |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
addToEnd(p_resultList, l_entry); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks) |
||||
|
{ |
||||
|
int l_num = 0; |
||||
|
struct ifaddrs *l_cur = *p_links; |
||||
|
while(l_cur && l_num < p_numLinks) |
||||
|
{ |
||||
|
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs); |
||||
|
int l_index; |
||||
|
memcpy(&l_index, l_indexPtr, sizeof(int)); |
||||
|
if(l_index == p_index) |
||||
|
{ |
||||
|
return l_cur; |
||||
|
} |
||||
|
|
||||
|
l_cur = l_cur->ifa_next; |
||||
|
++l_num; |
||||
|
} |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) |
||||
|
{ |
||||
|
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); |
||||
|
struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks); |
||||
|
|
||||
|
size_t l_nameSize = 0; |
||||
|
size_t l_addrSize = 0; |
||||
|
|
||||
|
int l_addedNetmask = 0; |
||||
|
|
||||
|
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); |
||||
|
struct rtattr *l_rta; |
||||
|
struct ifaddrs *l_entry; |
||||
|
|
||||
|
char *l_name; |
||||
|
char *l_addr; |
||||
|
|
||||
|
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) |
||||
|
{ |
||||
|
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); |
||||
|
if(l_info->ifa_family == AF_PACKET) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
switch(l_rta->rta_type) |
||||
|
{ |
||||
|
case IFA_ADDRESS: |
||||
|
case IFA_LOCAL: |
||||
|
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) |
||||
|
{ |
||||
|
/* Make room for netmask */ |
||||
|
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); |
||||
|
l_addedNetmask = 1; |
||||
|
} |
||||
|
case IFA_BROADCAST: |
||||
|
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); |
||||
|
break; |
||||
|
case IFA_LABEL: |
||||
|
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); |
||||
|
if (l_entry == NULL) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
memset(l_entry, 0, sizeof(struct ifaddrs)); |
||||
|
l_entry->ifa_name = (l_interface ? l_interface->ifa_name : ""); |
||||
|
|
||||
|
l_name = ((char *)l_entry) + sizeof(struct ifaddrs); |
||||
|
l_addr = l_name + l_nameSize; |
||||
|
|
||||
|
l_entry->ifa_flags = l_info->ifa_flags; |
||||
|
if(l_interface) |
||||
|
{ |
||||
|
l_entry->ifa_flags |= l_interface->ifa_flags; |
||||
|
} |
||||
|
|
||||
|
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); |
||||
|
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) |
||||
|
{ |
||||
|
void *l_rtaData = RTA_DATA(l_rta); |
||||
|
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); |
||||
|
switch(l_rta->rta_type) |
||||
|
{ |
||||
|
case IFA_ADDRESS: |
||||
|
case IFA_BROADCAST: |
||||
|
case IFA_LOCAL: |
||||
|
{ |
||||
|
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); |
||||
|
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); |
||||
|
if(l_info->ifa_family == AF_INET6) |
||||
|
{ |
||||
|
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) |
||||
|
{ |
||||
|
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Apparently in a point-to-point network IFA_ADDRESS contains
|
||||
|
* the dest address and IFA_LOCAL contains the local address |
||||
|
*/ |
||||
|
if(l_rta->rta_type == IFA_ADDRESS) |
||||
|
{ |
||||
|
if(l_entry->ifa_addr) |
||||
|
{ |
||||
|
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
l_entry->ifa_addr = (struct sockaddr *)l_addr; |
||||
|
} |
||||
|
} |
||||
|
else if(l_rta->rta_type == IFA_LOCAL) |
||||
|
{ |
||||
|
if(l_entry->ifa_addr) |
||||
|
{ |
||||
|
l_entry->ifa_dstaddr = l_entry->ifa_addr; |
||||
|
} |
||||
|
l_entry->ifa_addr = (struct sockaddr *)l_addr; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; |
||||
|
} |
||||
|
l_addr += NLMSG_ALIGN(l_addrLen); |
||||
|
break; |
||||
|
} |
||||
|
case IFA_LABEL: |
||||
|
strncpy(l_name, l_rtaData, l_rtaDataSize); |
||||
|
l_name[l_rtaDataSize] = '\0'; |
||||
|
l_entry->ifa_name = l_name; |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) |
||||
|
{ |
||||
|
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); |
||||
|
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); |
||||
|
char l_mask[16] = {0}; |
||||
|
unsigned i; |
||||
|
for(i=0; i<(l_prefix/8); ++i) |
||||
|
{ |
||||
|
l_mask[i] = 0xff; |
||||
|
} |
||||
|
if(l_prefix % 8) |
||||
|
{ |
||||
|
l_mask[i] = 0xff << (8 - (l_prefix % 8)); |
||||
|
} |
||||
|
|
||||
|
makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); |
||||
|
l_entry->ifa_netmask = (struct sockaddr *)l_addr; |
||||
|
} |
||||
|
|
||||
|
addToEnd(p_resultList, l_entry); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) |
||||
|
{ |
||||
|
|
||||
|
int l_numLinks = 0; |
||||
|
pid_t l_pid = getpid(); |
||||
|
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) |
||||
|
{ |
||||
|
unsigned int l_nlsize = p_netlinkList->m_size; |
||||
|
struct nlmsghdr *l_hdr; |
||||
|
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) |
||||
|
{ |
||||
|
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if(l_hdr->nlmsg_type == NLMSG_DONE) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if(l_hdr->nlmsg_type == RTM_NEWLINK) |
||||
|
{ |
||||
|
if(interpretLink(l_hdr, p_resultList) == -1) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
++l_numLinks; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return l_numLinks; |
||||
|
} |
||||
|
|
||||
|
static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) |
||||
|
{ |
||||
|
pid_t l_pid = getpid(); |
||||
|
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) |
||||
|
{ |
||||
|
unsigned int l_nlsize = p_netlinkList->m_size; |
||||
|
struct nlmsghdr *l_hdr; |
||||
|
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) |
||||
|
{ |
||||
|
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if(l_hdr->nlmsg_type == NLMSG_DONE) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if(l_hdr->nlmsg_type == RTM_NEWADDR) |
||||
|
{ |
||||
|
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int getifaddrs(struct ifaddrs **ifap) |
||||
|
{ |
||||
|
int l_socket; |
||||
|
int l_result; |
||||
|
int l_numLinks; |
||||
|
NetlinkList *l_linkResults; |
||||
|
NetlinkList *l_addrResults; |
||||
|
|
||||
|
if(!ifap) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
*ifap = NULL; |
||||
|
|
||||
|
l_socket = netlink_socket(); |
||||
|
if(l_socket < 0) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
l_linkResults = getResultList(l_socket, RTM_GETLINK); |
||||
|
if(!l_linkResults) |
||||
|
{ |
||||
|
close(l_socket); |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
l_addrResults = getResultList(l_socket, RTM_GETADDR); |
||||
|
if(!l_addrResults) |
||||
|
{ |
||||
|
close(l_socket); |
||||
|
freeResultList(l_linkResults); |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
l_result = 0; |
||||
|
l_numLinks = interpretLinks(l_socket, l_linkResults, ifap); |
||||
|
if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) |
||||
|
{ |
||||
|
l_result = -1; |
||||
|
} |
||||
|
|
||||
|
freeResultList(l_linkResults); |
||||
|
freeResultList(l_addrResults); |
||||
|
close(l_socket); |
||||
|
return l_result; |
||||
|
} |
||||
|
|
||||
|
void freeifaddrs(struct ifaddrs *ifa) |
||||
|
{ |
||||
|
struct ifaddrs *l_cur; |
||||
|
while(ifa) |
||||
|
{ |
||||
|
l_cur = ifa; |
||||
|
ifa = ifa->ifa_next; |
||||
|
free(l_cur); |
||||
|
} |
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
|
* |
||||
|
* 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 "uv.h" |
||||
|
#include "task.h" |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
|
||||
|
TEST_IMPL(udp_bind) { |
||||
|
struct sockaddr_in addr; |
||||
|
uv_loop_t* loop; |
||||
|
uv_udp_t h1, h2; |
||||
|
int r; |
||||
|
|
||||
|
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); |
||||
|
|
||||
|
loop = uv_default_loop(); |
||||
|
|
||||
|
r = uv_udp_init(loop, &h1); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
r = uv_udp_init(loop, &h2); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
r = uv_udp_bind(&h1, (const struct sockaddr*) &addr, 0); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
r = uv_udp_bind(&h2, (const struct sockaddr*) &addr, 0); |
||||
|
ASSERT(r == UV_EADDRINUSE); |
||||
|
|
||||
|
uv_close((uv_handle_t*) &h1, NULL); |
||||
|
uv_close((uv_handle_t*) &h2, NULL); |
||||
|
|
||||
|
r = uv_run(loop, UV_RUN_DEFAULT); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
MAKE_VALGRIND_HAPPY(); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
TEST_IMPL(udp_bind_reuseaddr) { |
||||
|
struct sockaddr_in addr; |
||||
|
uv_loop_t* loop; |
||||
|
uv_udp_t h1, h2; |
||||
|
int r; |
||||
|
|
||||
|
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); |
||||
|
|
||||
|
loop = uv_default_loop(); |
||||
|
|
||||
|
r = uv_udp_init(loop, &h1); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
r = uv_udp_init(loop, &h2); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
r = uv_udp_bind(&h1, (const struct sockaddr*) &addr, UV_UDP_REUSEADDR); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
r = uv_udp_bind(&h2, (const struct sockaddr*) &addr, UV_UDP_REUSEADDR); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
uv_close((uv_handle_t*) &h1, NULL); |
||||
|
uv_close((uv_handle_t*) &h2, NULL); |
||||
|
|
||||
|
r = uv_run(loop, UV_RUN_DEFAULT); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
MAKE_VALGRIND_HAPPY(); |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,100 @@ |
|||||
|
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
|
* |
||||
|
* 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 "uv.h" |
||||
|
#include "task.h" |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#define CHECK_HANDLE(handle) \ |
||||
|
ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) |
||||
|
|
||||
|
static uv_udp_t server; |
||||
|
static uv_udp_t client; |
||||
|
|
||||
|
static int sv_send_cb_called; |
||||
|
static int close_cb_called; |
||||
|
|
||||
|
|
||||
|
static void close_cb(uv_handle_t* handle) { |
||||
|
CHECK_HANDLE(handle); |
||||
|
close_cb_called++; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static void sv_send_cb(uv_udp_send_t* req, int status) { |
||||
|
ASSERT(req != NULL); |
||||
|
ASSERT(status == 0); |
||||
|
CHECK_HANDLE(req->handle); |
||||
|
|
||||
|
sv_send_cb_called++; |
||||
|
|
||||
|
uv_close((uv_handle_t*) req->handle, close_cb); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
TEST_IMPL(udp_multicast_interface6) { |
||||
|
int r; |
||||
|
uv_udp_send_t req; |
||||
|
uv_buf_t buf; |
||||
|
struct sockaddr_in6 addr; |
||||
|
struct sockaddr_in6 baddr; |
||||
|
|
||||
|
ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr)); |
||||
|
|
||||
|
r = uv_udp_init(uv_default_loop(), &server); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
ASSERT(0 == uv_ip6_addr("::", 0, &baddr)); |
||||
|
r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
#if defined(__APPLE__) |
||||
|
r = uv_udp_set_multicast_interface(&server, "::1%lo0"); |
||||
|
#else |
||||
|
r = uv_udp_set_multicast_interface(&server, NULL); |
||||
|
#endif |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
/* server sends "PING" */ |
||||
|
buf = uv_buf_init("PING", 4); |
||||
|
r = uv_udp_send(&req, |
||||
|
&server, |
||||
|
&buf, |
||||
|
1, |
||||
|
(const struct sockaddr*)&addr, |
||||
|
sv_send_cb); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
ASSERT(close_cb_called == 0); |
||||
|
ASSERT(sv_send_cb_called == 0); |
||||
|
|
||||
|
/* run the loop till all events are processed */ |
||||
|
uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
||||
|
|
||||
|
ASSERT(sv_send_cb_called == 1); |
||||
|
ASSERT(close_cb_called == 1); |
||||
|
|
||||
|
MAKE_VALGRIND_HAPPY(); |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,153 @@ |
|||||
|
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
|
* |
||||
|
* 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 "uv.h" |
||||
|
#include "task.h" |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
|
||||
|
#define CHECK_HANDLE(handle) \ |
||||
|
ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) |
||||
|
|
||||
|
static uv_udp_t server; |
||||
|
static uv_udp_t client; |
||||
|
|
||||
|
static int cl_recv_cb_called; |
||||
|
|
||||
|
static int sv_send_cb_called; |
||||
|
|
||||
|
static int close_cb_called; |
||||
|
|
||||
|
static void alloc_cb(uv_handle_t* handle, |
||||
|
size_t suggested_size, |
||||
|
uv_buf_t* buf) { |
||||
|
static char slab[65536]; |
||||
|
CHECK_HANDLE(handle); |
||||
|
ASSERT(suggested_size <= sizeof(slab)); |
||||
|
buf->base = slab; |
||||
|
buf->len = sizeof(slab); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static void close_cb(uv_handle_t* handle) { |
||||
|
CHECK_HANDLE(handle); |
||||
|
close_cb_called++; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static void sv_send_cb(uv_udp_send_t* req, int status) { |
||||
|
ASSERT(req != NULL); |
||||
|
ASSERT(status == 0); |
||||
|
CHECK_HANDLE(req->handle); |
||||
|
|
||||
|
sv_send_cb_called++; |
||||
|
|
||||
|
uv_close((uv_handle_t*) req->handle, close_cb); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static void cl_recv_cb(uv_udp_t* handle, |
||||
|
ssize_t nread, |
||||
|
const uv_buf_t* buf, |
||||
|
const struct sockaddr* addr, |
||||
|
unsigned flags) { |
||||
|
CHECK_HANDLE(handle); |
||||
|
ASSERT(flags == 0); |
||||
|
|
||||
|
cl_recv_cb_called++; |
||||
|
|
||||
|
if (nread < 0) { |
||||
|
ASSERT(0 && "unexpected error"); |
||||
|
} |
||||
|
|
||||
|
if (nread == 0) { |
||||
|
/* Returning unused buffer */ |
||||
|
/* Don't count towards cl_recv_cb_called */ |
||||
|
ASSERT(addr == NULL); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
ASSERT(addr != NULL); |
||||
|
ASSERT(nread == 4); |
||||
|
ASSERT(!memcmp("PING", buf->base, nread)); |
||||
|
|
||||
|
/* we are done with the client handle, we can close it */ |
||||
|
uv_close((uv_handle_t*) &client, close_cb); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
TEST_IMPL(udp_multicast_join6) { |
||||
|
int r; |
||||
|
uv_udp_send_t req; |
||||
|
uv_buf_t buf; |
||||
|
struct sockaddr_in6 addr; |
||||
|
|
||||
|
ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr)); |
||||
|
|
||||
|
r = uv_udp_init(uv_default_loop(), &server); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
r = uv_udp_init(uv_default_loop(), &client); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
/* bind to the desired port */ |
||||
|
r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
/* join the multicast channel */ |
||||
|
#if defined(__APPLE__) |
||||
|
r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); |
||||
|
#else |
||||
|
r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); |
||||
|
#endif |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
buf = uv_buf_init("PING", 4); |
||||
|
|
||||
|
/* server sends "PING" */ |
||||
|
r = uv_udp_send(&req, |
||||
|
&server, |
||||
|
&buf, |
||||
|
1, |
||||
|
(const struct sockaddr*) &addr, |
||||
|
sv_send_cb); |
||||
|
ASSERT(r == 0); |
||||
|
|
||||
|
ASSERT(close_cb_called == 0); |
||||
|
ASSERT(cl_recv_cb_called == 0); |
||||
|
ASSERT(sv_send_cb_called == 0); |
||||
|
|
||||
|
/* run the loop till all events are processed */ |
||||
|
uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
||||
|
|
||||
|
ASSERT(cl_recv_cb_called == 1); |
||||
|
ASSERT(sv_send_cb_called == 1); |
||||
|
ASSERT(close_cb_called == 2); |
||||
|
|
||||
|
MAKE_VALGRIND_HAPPY(); |
||||
|
return 0; |
||||
|
} |
Loading…
Reference in new issue