# 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 */