host.cpp

Go to the documentation of this file.
00001 /* $Id: host.cpp 17693 2009-10-04 17:16:41Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #ifdef ENABLE_NETWORK
00013 
00014 #include "../../stdafx.h"
00015 #include "../../debug.h"
00016 #include "address.h"
00017 
00023 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast);
00024 
00025 #if defined(PSP)
00026 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // PSP implementation
00027 {
00028 }
00029 
00030 #elif defined(BEOS_NET_SERVER) || defined(__HAIKU__) /* doesn't have neither getifaddrs or net/if.h */
00031 /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
00032 extern "C" int _netstat(int fd, char **output, int verbose);
00033 
00034 int seek_past_header(char **pos, const char *header)
00035 {
00036   char *new_pos = strstr(*pos, header);
00037   if (new_pos == 0) {
00038     return B_ERROR;
00039   }
00040   *pos += strlen(header) + new_pos - *pos + 1;
00041   return B_OK;
00042 }
00043 
00044 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // BEOS implementation
00045 {
00046   int sock = socket(AF_INET, SOCK_DGRAM, 0);
00047 
00048   if (sock < 0) {
00049     DEBUG(net, 0, "[core] error creating socket");
00050     return;
00051   }
00052 
00053   char *output_pointer = NULL;
00054   int output_length = _netstat(sock, &output_pointer, 1);
00055   if (output_length < 0) {
00056     DEBUG(net, 0, "[core] error running _netstat");
00057     return;
00058   }
00059 
00060   char **output = &output_pointer;
00061   if (seek_past_header(output, "IP Interfaces:") == B_OK) {
00062     for (;;) {
00063       uint32 n;
00064       int fields, read;
00065       uint8 i1, i2, i3, i4, j1, j2, j3, j4;
00066       uint32 ip;
00067       uint32 netmask;
00068 
00069       fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n",
00070                         &n, &i1, &i2, &i3, &i4, &j1, &j2, &j3, &j4, &read);
00071       read += 1;
00072       if (fields != 9) {
00073         break;
00074       }
00075 
00076       ip      = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4;
00077       netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4;
00078 
00079       if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) {
00080         sockaddr_storage address;
00081         memset(&address, 0, sizeof(address));
00082         ((sockaddr_in*)&address)->sin_addr.s_addr = htonl(ip | ~netmask);
00083         NetworkAddress addr(address, sizeof(sockaddr));
00084         if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
00085       }
00086       if (read < 0) {
00087         break;
00088       }
00089       *output += read;
00090     }
00091     closesocket(sock);
00092   }
00093 }
00094 
00095 #elif defined(HAVE_GETIFADDRS)
00096 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // GETIFADDRS implementation
00097 {
00098   struct ifaddrs *ifap, *ifa;
00099 
00100   if (getifaddrs(&ifap) != 0) return;
00101 
00102   for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
00103     if (!(ifa->ifa_flags & IFF_BROADCAST)) continue;
00104     if (ifa->ifa_broadaddr == NULL) continue;
00105     if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;
00106 
00107     NetworkAddress addr(ifa->ifa_broadaddr, sizeof(sockaddr));
00108     if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
00109   }
00110   freeifaddrs(ifap);
00111 }
00112 
00113 #elif defined(WIN32)
00114 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // Win32 implementation
00115 {
00116   SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
00117   if (sock == INVALID_SOCKET) return;
00118 
00119   DWORD len = 0;
00120   int num = 2;
00121   INTERFACE_INFO *ifo = CallocT<INTERFACE_INFO>(num);
00122 
00123   for (;;) {
00124     if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, ifo, num * sizeof(*ifo), &len, NULL, NULL) == 0) break;
00125     free(ifo);
00126     if (WSAGetLastError() != WSAEFAULT) {
00127       closesocket(sock);
00128       return;
00129     }
00130     num *= 2;
00131     ifo = CallocT<INTERFACE_INFO>(num);
00132   }
00133 
00134   for (uint j = 0; j < len / sizeof(*ifo); j++) {
00135     if (ifo[j].iiFlags & IFF_LOOPBACK) continue;
00136     if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue;
00137 
00138     sockaddr_storage address;
00139     memset(&address, 0, sizeof(address));
00140     /* iiBroadcast is unusable, because it always seems to be set to 255.255.255.255. */
00141     memcpy(&address, &ifo[j].iiAddress.Address, sizeof(sockaddr));
00142     ((sockaddr_in*)&address)->sin_addr.s_addr = ifo[j].iiAddress.AddressIn.sin_addr.s_addr | ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr;
00143     NetworkAddress addr(address, sizeof(sockaddr));
00144     if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
00145   }
00146 
00147   free(ifo);
00148   closesocket(sock);
00149 }
00150 
00151 #else /* not HAVE_GETIFADDRS */
00152 
00153 #include "../../string_func.h"
00154 
00155 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // !GETIFADDRS implementation
00156 {
00157   SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
00158   if (sock == INVALID_SOCKET) return;
00159 
00160   char buf[4 * 1024]; // Arbitrary buffer size
00161   struct ifconf ifconf;
00162 
00163   ifconf.ifc_len = sizeof(buf);
00164   ifconf.ifc_buf = buf;
00165   if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) {
00166     closesocket(sock);
00167     return;
00168   }
00169 
00170   const char *buf_end = buf + ifconf.ifc_len;
00171   for (const char *p = buf; p < buf_end;) {
00172     const struct ifreq *req = (const struct ifreq*)p;
00173 
00174     if (req->ifr_addr.sa_family == AF_INET) {
00175       struct ifreq r;
00176 
00177       strecpy(r.ifr_name, req->ifr_name, lastof(r.ifr_name));
00178       if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 &&
00179           (r.ifr_flags & IFF_BROADCAST) &&
00180           ioctl(sock, SIOCGIFBRDADDR, &r) != -1) {
00181         NetworkAddress addr(&r.ifr_broadaddr, sizeof(sockaddr));
00182         if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
00183       }
00184     }
00185 
00186     p += sizeof(struct ifreq);
00187 #if defined(AF_LINK) && !defined(SUNOS)
00188     p += req->ifr_addr.sa_len - sizeof(struct sockaddr);
00189 #endif
00190   }
00191 
00192   closesocket(sock);
00193 }
00194 #endif /* all NetworkFindBroadcastIPsInternals */
00195 
00201 void NetworkFindBroadcastIPs(NetworkAddressList *broadcast)
00202 {
00203   NetworkFindBroadcastIPsInternal(broadcast);
00204 
00205   /* Now display to the debug all the detected ips */
00206   DEBUG(net, 3, "Detected broadcast addresses:");
00207   int i = 0;
00208   for (NetworkAddress *addr = broadcast->Begin(); addr != broadcast->End(); addr++) {
00209     addr->SetPort(NETWORK_DEFAULT_PORT);
00210     DEBUG(net, 3, "%d) %s", i++, addr->GetHostname());
00211   }
00212 }
00213 
00214 #endif /* ENABLE_NETWORK */

Generated on Mon Aug 30 19:36:55 2010 for OpenTTD by  doxygen 1.6.1