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