static void s_get_interface (zre_udp_t *self) { #if defined (__UNIX__) # if defined (HAVE_GETIFADDRS) && defined (HAVE_FREEIFADDRS) struct ifaddrs *interfaces; if (getifaddrs (&interfaces) == 0) { struct ifaddrs *interface = interfaces; while (interface) { // Hopefully the last interface will be WiFi or Ethernet if (interface->ifa_addr->sa_family == AF_INET) { self->address = *(struct sockaddr_in *) interface->ifa_addr; self->broadcast = *(struct sockaddr_in *) interface->ifa_broadaddr; self->broadcast.sin_port = htons (self->port_nbr); if (s_wireless_nic (interface->ifa_name)) break; } interface = interface->ifa_next; } } freeifaddrs (interfaces); # else struct ifreq ifr; memset (&ifr, 0, sizeof (ifr)); # if !defined (LIBZRE_HAVE_ANDROID) // TODO: Using hardcoded wlan0 is ugly if (!s_wireless_nic ("wlan0")) s_handle_io_error ("wlan0_not_exist"); # endif int sock = 0; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) s_handle_io_error ("foo_socket_not_opened"); // Get interface address ifr.ifr_addr.sa_family = AF_INET; strncpy (ifr.ifr_name, "wlan0", sizeof (ifr.ifr_name)); int rc = ioctl (sock, SIOCGIFADDR, (caddr_t) &ifr, sizeof (struct ifreq)); if (rc == -1) s_handle_io_error ("siocgifaddr"); // Get interface broadcast address memcpy (&self->address, ((struct sockaddr_in *) &ifr.ifr_addr), sizeof (struct sockaddr_in)); rc = ioctl (sock, SIOCGIFBRDADDR, (caddr_t) &ifr, sizeof (struct ifreq)); if (rc == -1) s_handle_io_error ("siocgifbrdaddr"); memcpy (&self->broadcast, ((struct sockaddr_in *) &ifr.ifr_broadaddr), sizeof (struct sockaddr_in)); self->broadcast.sin_port = htons (self->port_nbr); close (sock); # endif # elif defined (__WINDOWS__) // Currently does not filter for wireless NIC ULONG addr_size = 0; DWORD rc = GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &addr_size); assert (rc == ERROR_BUFFER_OVERFLOW); PIP_ADAPTER_ADDRESSES pip_addresses = malloc (addr_size); rc = GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pip_addresses, &addr_size); assert (rc == NO_ERROR); PIP_ADAPTER_ADDRESSES cur_address = pip_addresses; while (cur_address) { PIP_ADAPTER_UNICAST_ADDRESS pUnicast = cur_address->FirstUnicastAddress; PIP_ADAPTER_PREFIX pPrefix = cur_address->FirstPrefix; if (pUnicast && pPrefix) { // self->broadcast.sin_addr is replaced with 255.255.255.255 in zre_udp_send() self->address = *(struct sockaddr_in *)(pUnicast->Address.lpSockaddr); self->broadcast = *(struct sockaddr_in *)(pPrefix->Address.lpSockaddr); self->broadcast.sin_addr.s_addr |= htonl ((1 << (32 - pPrefix->PrefixLength)) - 1); } self->broadcast.sin_port = htons (self->port_nbr); cur_address = cur_address->Next; } free (pip_addresses); # else # error "Interface detection TBD on this operating system" # endif }
zre_udp_t * zre_udp_new (int port_nbr) { zre_udp_t *self = (zre_udp_t *) zmalloc (sizeof (zre_udp_t)); self->port_nbr = port_nbr; // Create UDP socket self->handle = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (self->handle == -1) s_handle_io_error ("socket"); // Ask operating system to let us do broadcasts from socket int on = 1; if (setsockopt (self->handle, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_BROADCAST)"); // Allow multiple processes to bind to socket; incoming // messages will come to each process if (setsockopt (self->handle, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_REUSEADDR)"); #if defined (SO_REUSEPORT) if (setsockopt (self->handle, SOL_SOCKET, SO_REUSEPORT, &on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_REUSEPORT)"); #endif // PROBLEM: this design will not survive the network interface being // killed and restarted while the program is running. struct sockaddr_in sockaddr = { 0 }; sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons (self->port_nbr); sockaddr.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (self->handle, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) == -1) s_handle_io_error ("bind"); # if defined (__UNIX__) # if defined (HAVE_GETIFADDRS) && defined (HAVE_FREEIFADDRS) struct ifaddrs *interfaces; if (getifaddrs (&interfaces) == 0) { struct ifaddrs *interface = interfaces; while (interface) { // Hopefully the last interface will be WiFi if (interface->ifa_addr->sa_family == AF_INET) { self->address = *(struct sockaddr_in *) interface->ifa_addr; self->broadcast = *(struct sockaddr_in *) interface->ifa_broadaddr; self->broadcast.sin_port = htons (self->port_nbr); if (s_wireless_nic (interface->ifa_name)) break; } interface = interface->ifa_next; } } freeifaddrs (interfaces); # else struct ifreq ifr; memset (&ifr, 0, sizeof (ifr)); /* TODO: Using hardcoded wlan0 is ugly */ # if !defined ( LIBZRE_HAVE_ANDROID ) if (!s_wireless_nic ("wlan0")) s_handle_io_error ("wlan0_not_exist"); # endif int sock = 0; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) s_handle_io_error ("foo_socket_not_opened"); ifr.ifr_addr.sa_family = AF_INET; strncpy (ifr.ifr_name, "wlan0", sizeof (ifr.ifr_name)); int rc = ioctl (sock, SIOCGIFADDR, (caddr_t) &ifr, sizeof (struct ifreq)); if (rc == -1) s_handle_io_error ("siocgifaddr"); memcpy (&self->address, ((struct sockaddr_in*) &ifr.ifr_addr), sizeof (struct sockaddr_in)); rc = ioctl (sock, SIOCGIFBRDADDR, (caddr_t) &ifr, sizeof (struct ifreq)); if (rc == -1) s_handle_io_error ("siocgifbrdaddr"); memcpy (&self->broadcast, ((struct sockaddr_in*) &ifr.ifr_broadaddr), sizeof (struct sockaddr_in)); self->broadcast.sin_port = htons (self->port_nbr); close (sock); # endif if (self->host) free (self->host); self->host = zmalloc (INET_ADDRSTRLEN); inet_ntop (AF_INET, &self->address.sin_addr, self->host, sizeof (sockaddr)); # elif defined (__WINDOWS__) s_win_get_interface(self); if (self->host) free (self->host); self->host = zmalloc (INET_ADDRSTRLEN); getnameinfo ((struct sockaddr *)&self->address, sizeof (self->address), self->host, INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); # else # error "Interface detection TBD on this operating system" # endif return self; }