# host.cpp

Go to the documentation of this file.

    00001 /* $Id: host.cpp 15718 2009-03-15 00:32:18Z rubidium $ */
    00002
    00005 #ifdef ENABLE_NETWORK
    00006
    00007 #include "../../stdafx.h"
    00008 #include "../../debug.h"
    00009 #include "os_abstraction.h"
    00010 #include "../../core/alloc_func.hpp"
    00011
    00018 static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit);
    00019
    00020 #if defined(PSP)
    00021 static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // PSP implementation
    00022 {
    00023   return 0;
    00024 }
    00025
    00026 #elif defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */
    00027 /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
    00028 int _netstat(int fd, char **output, int verbose);
    00029
    00030 int seek_past_header(char **pos, const char *header)
    00031 {
    00032   char *new_pos = strstr(*pos, header);
    00033   if (new_pos == 0) {
    00034     return B_ERROR;
    00035   }
    00036   *pos += strlen(header) + new_pos - *pos + 1;
    00037   return B_OK;
    00038 }
    00039
    00040 static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // BEOS implementation
    00041 {
    00042   int sock = socket(AF_INET, SOCK_DGRAM, 0);
    00043
    00044   if (sock < 0) {
    00045     DEBUG(net, 0, "[core] error creating socket");
    00046     return 0;
    00047   }
    00048
    00049   char *output_pointer = NULL;
    00050   int output_length = _netstat(sock, &output_pointer, 1);
    00051   if (output_length < 0) {
    00052     DEBUG(net, 0, "[core] error running _netstat");
    00053     return 0;
    00054   }
    00055
    00056   int index;
    00057   char **output = &output_pointer;
    00058   if (seek_past_header(output, "IP Interfaces:") == B_OK) {
    00059     while (index != limit) {
    00060
    00061       uint32 n, fields, read;
    00062       uint8 i1, i2, i3, i4, j1, j2, j3, j4;
    00063       struct in_addr inaddr;
    00064       uint32 ip;
    00065       uint32 netmask;
    00066
    00067       fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n",
    00068                         &n, &i1, &i2, &i3, &i4, &j1, &j2, &j3, &j4, &read);
    00069       read += 1;
    00070       if (fields != 9) {
    00071         break;
    00072       }
    00073
    00074       ip      = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4;
    00075       netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4;
    00076
    00077       if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) {
    00078         inaddr.s_addr = htonl(ip | ~netmask);
    00079         broadcast[index] = inaddr.s_addr;
    00080         index++;
    00081       }
    00082       if (read < 0) {
    00083         break;
    00084       }
    00085       *output += read;
    00086     }
    00087     closesocket(sock);
    00088   }
    00089
    00090   return index;
    00091 }
    00092
    00093 #elif defined(HAVE_GETIFADDRS)
    00094 static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // GETIFADDRS implementation
    00095 {
    00096   struct ifaddrs *ifap, *ifa;
    00097
    00098   if (getifaddrs(&ifap) != 0) return 0;
    00099
    00100   int index = 0;
    00101   for (ifa = ifap; ifa != NULL && index != limit; ifa = ifa->ifa_next) {
    00102     if (!(ifa->ifa_flags & IFF_BROADCAST)) continue;
    00103     if (ifa->ifa_broadaddr == NULL) continue;
    00104     if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;
    00105
    00106     broadcast[index] = ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr;
    00107     index++;
    00108   }
    00109   freeifaddrs(ifap);
    00110
    00111   return index;
    00112 }
    00113
    00114 #elif defined(WIN32)
    00115 static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // Win32 implementation
    00116 {
    00117   SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
    00118   if (sock == INVALID_SOCKET) return 0;
    00119
    00120   DWORD len = 0;
    00121   INTERFACE_INFO *ifo = AllocaM(INTERFACE_INFO, limit);
    00122   memset(ifo, 0, limit * sizeof(*ifo));
    00123   if ((WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, &ifo[0], limit * sizeof(*ifo), &len, NULL, NULL)) != 0) {
    00124     closesocket(sock);
    00125     return 0;
    00126   }
    00127
    00128   int index = 0;
    00129   for (uint j = 0; j < len / sizeof(*ifo) && index != limit; j++) {
    00130     if (ifo[j].iiFlags & IFF_LOOPBACK) continue;
    00131     if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue;
    00132
    00133     /* iiBroadcast is unusable, because it always seems to be set to 255.255.255.255. */
    00134     broadcast[index++] = ifo[j].iiAddress.AddressIn.sin_addr.s_addr | ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr;
    00135   }
    00136
    00137   closesocket(sock);
    00138   return index;
    00139 }
    00140
    00141 #else /* not HAVE_GETIFADDRS */
    00142
    00143 #include "../../string_func.h"
    00144
    00145 static int NetworkFindBroadcastIPsInternal(uint32 *broadcast, int limit) // !GETIFADDRS implementation
    00146 {
    00147   SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
    00148   if (sock == INVALID_SOCKET) return 0;
    00149
    00150   char buf[4 * 1024]; // Arbitrary buffer size
    00151   struct ifconf ifconf;
    00152
    00153   ifconf.ifc_len = sizeof(buf);
    00154   ifconf.ifc_buf = buf;
    00155   if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) {
    00156     closesocket(sock);
    00157     return 0;
    00158   }
    00159
    00160   const char *buf_end = buf + ifconf.ifc_len;
    00161   int index = 0;
    00162   for (const char *p = buf; p < buf_end && index != limit;) {
    00163     const struct ifreq *req = (const struct ifreq*)p;
    00164
    00165     if (req->ifr_addr.sa_family == AF_INET) {
    00166       struct ifreq r;
    00167
    00168       strecpy(r.ifr_name, req->ifr_name, lastof(r.ifr_name));
    00169       if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 &&
    00170           r.ifr_flags & IFF_BROADCAST &&
    00171           ioctl(sock, SIOCGIFBRDADDR, &r) != -1) {
    00172         broadcast[index++] = ((struct sockaddr_in*)&r.ifr_broadaddr)->sin_addr.s_addr;
    00173       }
    00174     }
    00175
    00176     p += sizeof(struct ifreq);
    00177 #if defined(AF_LINK) && !defined(SUNOS)
    00178     p += req->ifr_addr.sa_len - sizeof(struct sockaddr);
    00179 #endif
    00180   }
    00181
    00182   closesocket(sock);
    00183
    00184   return index;
    00185 }
    00186 #endif /* all NetworkFindBroadcastIPsInternals */
    00187
    00193 void NetworkFindBroadcastIPs(uint32 *broadcast, int limit)
    00194 {
    00195   int count = NetworkFindBroadcastIPsInternal(broadcast, limit);
    00196
    00197   /* Make sure the list is terminated. */
    00198   broadcast[count] = 0;
    00199
    00200   /* Now display to the debug all the detected ips */
    00201   DEBUG(net, 3, "Detected broadcast addresses:");
    00202   for (int i = 0; broadcast[i] != 0; i++) {
    00203     DEBUG(net, 3, "%d) %s", i, inet_ntoa(*(struct in_addr *)&broadcast[i])); // inet_ntoa(inaddr));
    00204   }
    00205 }
    00206
    00207
    00213 uint32 NetworkResolveHost(const char *hostname)
    00214 {
    00215   /* Is this an IP address? */
    00216   in_addr_t ip = inet_addr(hostname);
    00217
    00218   if (ip != INADDR_NONE) return ip;
    00219
    00220   /* No, try to resolve the name */
    00221   struct in_addr addr;
    00222 #if !defined(PSP)
    00223   struct hostent *he = gethostbyname(hostname);
    00224   if (he == NULL) {
    00225     DEBUG(net, 0, "[NET] Cannot resolve %s", hostname);
    00226     return 0;
    00227   }
    00228   addr = *(struct in_addr *)he->h_addr_list[0];
    00229 #else
    00230   int rid = -1;
    00231   char buf[1024];
    00232
    00233   /* Create a resolver */
    00234   if (sceNetResolverCreate(&rid, buf, sizeof(buf)) < 0) {
    00235     DEBUG(net, 0, "[NET] Error connecting resolver");
    00236     return 0;
    00237   }
    00238
    00239   /* Try to resolve the name */
    00240   if (sceNetResolverStartNtoA(rid, hostname, &addr, 2, 3) < 0) {
    00241     DEBUG(net, 0, "[NET] Cannot resolve %s", hostname);
    00242     sceNetResolverDelete(rid);
    00243     return 0;
    00244   }
    00245   sceNetResolverDelete(rid);
    00246 #endif /* PSP */
    00247
    00248   DEBUG(net, 1, "[NET] Resolved %s to %s", hostname, inet_ntoa(addr));
    00249   ip = addr.s_addr;
    00250   return ip;
    00251 }
    00252
    00253 #endif /* ENABLE_NETWORK */