rubidium@9844: /* $Id$ */ rubidium@9844: rubidium@9844: /** @file host.cpp Functions related to getting host specific data (IPs). */ rubidium@9844: rubidium@9844: #ifdef ENABLE_NETWORK rubidium@9844: rubidium@9844: #include "../../stdafx.h" rubidium@9844: #include "../../debug.h" rubidium@9844: #include "os_abstraction.h" rubidium@9844: rubidium@9844: /** rubidium@9844: * Internal implementation for finding the broadcast IPs. rubidium@9844: * This function is implemented multiple times for multiple targets. rubidium@9844: * @param broadcast the list of broadcasts to write into. rubidium@9844: * @param limit the maximum number of items to add. rubidium@9844: */ rubidium@9844: static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit); rubidium@9844: rubidium@9844: #if defined(PSP) rubidium@9844: static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // PSP implementation rubidium@9844: { rubidium@9844: return 0; rubidium@9844: } rubidium@9844: rubidium@9844: #elif defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */ rubidium@9844: /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */ rubidium@9844: int _netstat(int fd, char **output, int verbose); rubidium@9844: rubidium@9844: int seek_past_header(char **pos, const char *header) rubidium@9844: { rubidium@9844: char *new_pos = strstr(*pos, header); rubidium@9844: if (new_pos == 0) { rubidium@9844: return B_ERROR; rubidium@9844: } rubidium@9844: *pos += strlen(header) + new_pos - *pos + 1; rubidium@9844: return B_OK; rubidium@9844: } rubidium@9844: rubidium@9844: static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // BEOS implementation rubidium@9844: { rubidium@9844: int sock = socket(AF_INET, SOCK_DGRAM, 0); rubidium@9844: rubidium@9844: if (sock < 0) { rubidium@9844: DEBUG(net, 0, "[core] error creating socket"); rubidium@9844: return; rubidium@9844: } rubidium@9844: rubidium@9844: char *output_pointer = NULL; rubidium@9844: int output_length = _netstat(sock, &output_pointer, 1); rubidium@9844: if (output_length < 0) { rubidium@9844: DEBUG(net, 0, "[core] error running _netstat"); rubidium@9844: return; rubidium@9844: } rubidium@9844: rubidium@9844: int index; rubidium@9844: char **output = &output_pointer; rubidium@9844: if (seek_past_header(output, "IP Interfaces:") == B_OK) { rubidium@9844: while (index != limit) { rubidium@9844: rubidium@9844: uint32 n, fields, read; rubidium@9844: uint8 i1, i2, i3, i4, j1, j2, j3, j4; rubidium@9844: struct in_addr inaddr; rubidium@9844: uint32 ip; rubidium@9844: uint32 netmask; rubidium@9844: rubidium@9844: fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n", rubidium@9844: &n, &i1, &i2, &i3, &i4, &j1, &j2, &j3, &j4, &read); rubidium@9844: read += 1; rubidium@9844: if (fields != 9) { rubidium@9844: break; rubidium@9844: } rubidium@9844: rubidium@9844: ip = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4; rubidium@9844: netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4; rubidium@9844: rubidium@9844: if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) { rubidium@9844: inaddr.s_addr = htonl(ip | ~netmask); rubidium@9844: broadcast[index] = inaddr.s_addr; rubidium@9844: index++; rubidium@9844: } rubidium@9844: if (read < 0) { rubidium@9844: break; rubidium@9844: } rubidium@9844: *output += read; rubidium@9844: } rubidium@9844: closesocket(sock); rubidium@9844: } rubidium@9844: rubidium@9844: return index; rubidium@9844: } rubidium@9844: rubidium@9844: #elif defined(HAVE_GETIFADDRS) rubidium@9844: static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // GETIFADDRS implementation rubidium@9844: { rubidium@9844: struct ifaddrs *ifap, *ifa; rubidium@9844: rubidium@9844: if (getifaddrs(&ifap) != 0) return 0; rubidium@9844: rubidium@9844: int index = 0; rubidium@9844: for (ifa = ifap; ifa != NULL && index != limit; ifa = ifa->ifa_next) { rubidium@9844: if (!(ifa->ifa_flags & IFF_BROADCAST)) continue; rubidium@9844: if (ifa->ifa_broadaddr == NULL) continue; rubidium@9844: if (ifa->ifa_broadaddr->sa_family != AF_INET) continue; rubidium@9844: rubidium@9844: broadcast[index] = ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr; rubidium@9844: index++; rubidium@9844: } rubidium@9844: freeifaddrs(ifap); rubidium@9844: rubidium@9844: return index; rubidium@9844: } rubidium@9844: rubidium@9844: #elif defined(WIN32) rubidium@9844: static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // Win32 implementation rubidium@9844: { rubidium@9844: SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); rubidium@9844: if (sock == INVALID_SOCKET) return 0; rubidium@9844: rubidium@9844: DWORD len = 0; rubidium@9844: INTERFACE_INFO ifo[MAX_INTERFACES]; rubidium@9844: memset(&ifo[0], 0, sizeof(ifo)); rubidium@9844: if ((WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, &ifo[0], sizeof(ifo), &len, NULL, NULL)) != 0) { rubidium@9844: closesocket(sock); rubidium@9844: return; rubidium@9844: } rubidium@9844: rubidium@9844: int index = 0; rubidium@9844: for (int j = 0; j < len / sizeof(*ifo) && index != limit; j++) { rubidium@9844: if (ifo[j].iiFlags & IFF_LOOPBACK) continue; rubidium@9844: if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue; rubidium@9844: rubidium@9844: /* iiBroadcast is unusable, because it always seems to be set to 255.255.255.255. */ rubidium@9844: broadcast[index++] = ifo[j].iiAddress.AddressIn.sin_addr.s_addr | ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr; rubidium@9844: } rubidium@9844: rubidium@9844: closesocket(sock); rubidium@9844: return index; rubidium@9844: } rubidium@9844: rubidium@9844: #else /* not HAVE_GETIFADDRS */ rubidium@9844: static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // !GETIFADDRS implementation rubidium@9844: { rubidium@9844: SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); rubidium@9844: if (sock == INVALID_SOCKET) return 0; rubidium@9844: rubidium@9844: char buf[4 * 1024]; // Arbitrary buffer size rubidium@9844: struct ifconf ifconf; rubidium@9844: rubidium@9844: ifconf.ifc_len = sizeof(buf); rubidium@9844: ifconf.ifc_buf = buf; rubidium@9844: if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) { rubidium@9844: closesocket(sock); rubidium@9844: return 0; rubidium@9844: } rubidium@9844: rubidium@9844: const char *buf_end = buf + ifconf.ifc_len; rubidium@9844: int index; rubidium@9844: for (const char *p = buf; p < buf_end && index != 0;) { rubidium@9844: const struct ifreq* req = (const struct ifreq*)p; rubidium@9844: rubidium@9844: if (req->ifr_addr.sa_family == AF_INET) { rubidium@9844: struct ifreq r; rubidium@9844: rubidium@9844: strncpy(r.ifr_name, req->ifr_name, lengthof(r.ifr_name)); rubidium@9844: if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 && rubidium@9844: r.ifr_flags & IFF_BROADCAST && rubidium@9844: ioctl(sock, SIOCGIFBRDADDR, &r) != -1) { rubidium@9844: broadcast[index++] = ((struct sockaddr_in*)&r.ifr_broadaddr)->sin_addr.s_addr; rubidium@9844: } rubidium@9844: } rubidium@9844: rubidium@9844: p += sizeof(struct ifreq); rubidium@9844: #if defined(AF_LINK) && !defined(SUNOS) rubidium@9844: p += req->ifr_addr.sa_len - sizeof(struct sockaddr); rubidium@9844: #endif rubidium@9844: } rubidium@9844: rubidium@9844: closesocket(sock); rubidium@9844: } rubidium@9844: #endif /* all NetworkFindBroadcastIPsInternals */ rubidium@9844: rubidium@9844: /** rubidium@9844: * Find the IPs to broadcast. rubidium@9844: * @param broadcast the list of broadcasts to write into. rubidium@9844: * @param limit the maximum number of items to add. rubidium@9844: */ rubidium@9844: void NetworkFindBroadcastIPs(uint32 *broadcast, int limit) rubidium@9844: { rubidium@9844: int count = NetworkFindBroadcastIPsInternal(broadcast, limit); rubidium@9844: rubidium@9844: /* Make sure the list is terminated. */ rubidium@9844: broadcast[count] = 0; rubidium@9844: rubidium@9844: /* Now display to the debug all the detected ips */ rubidium@9844: DEBUG(net, 3, "Detected broadcast addresses:"); rubidium@9844: for (int i = 0; broadcast[i] != 0; i++) { rubidium@9844: DEBUG(net, 3, "%d) %s", i, inet_ntoa(*(struct in_addr *)&broadcast[i])); //inet_ntoa(inaddr)); rubidium@9844: } rubidium@9844: } rubidium@9844: rubidium@9844: rubidium@9844: /** rubidium@9844: * Resolve a hostname to an ip. rubidium@9844: * @param hsotname the hostname to resolve rubidium@9844: * @return the IP belonging to that hostname, or 0 on failure. rubidium@9844: */ rubidium@9844: uint32 NetworkResolveHost(const char *hostname) rubidium@9844: { rubidium@9844: /* Is this an IP address? */ rubidium@9844: in_addr_t ip = inet_addr(hostname); rubidium@9844: rubidium@9844: if (ip != INADDR_NONE) return ip; rubidium@9844: rubidium@9844: /* No, try to resolve the name */ rubidium@9844: struct in_addr addr; rubidium@9844: #if !defined(PSP) rubidium@9844: struct hostent *he = gethostbyname(hostname); rubidium@9844: if (he == NULL) { rubidium@9844: DEBUG(net, 0, "[NET] Cannot resolve %s", hostname); rubidium@9844: return 0; rubidium@9844: } rubidium@9844: addr = *(struct in_addr *)he->h_addr_list[0]; rubidium@9844: #else rubidium@9844: int rid = -1; rubidium@9844: char buf[1024]; rubidium@9844: rubidium@9844: /* Create a resolver */ rubidium@9844: if (sceNetResolverCreate(&rid, buf, sizeof(buf)) < 0) { rubidium@9844: DEBUG(net, 0, "[NET] Error connecting resolver"); rubidium@9844: return 0; rubidium@9844: } rubidium@9844: rubidium@9844: /* Try to resolve the name */ rubidium@9844: if (sceNetResolverStartNtoA(rid, hostname, &addr, 2, 3) < 0) { rubidium@9844: DEBUG(net, 0, "[NET] Cannot resolve %s", hostname); rubidium@9844: sceNetResolverDelete(rid); rubidium@9844: return 0; rubidium@9844: } rubidium@9844: sceNetResolverDelete(rid); rubidium@9844: #endif /* PSP */ rubidium@9844: rubidium@9844: DEBUG(net, 1, "[NET] Resolved %s to %s", hostname, inet_ntoa(addr)); rubidium@9844: ip = addr.s_addr; rubidium@9844: return ip; rubidium@9844: } rubidium@9844: rubidium@9844: #endif /* ENABLE_NETWORK */