Maintain a circular buffer of recent commands, add to crashlog.
[openttd-joker.git] / src / network / core / host.cpp
blob840efabe484ed5c749c7334eb26fc4ee13fb7522
1 /* $Id: host.cpp 17693 2009-10-04 17:16:41Z rubidium $ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file host.cpp Functions related to getting host specific data (IPs). */
12 #ifdef ENABLE_NETWORK
14 #include "../../stdafx.h"
15 #include "../../debug.h"
16 #include "address.h"
18 #include "../../safeguards.h"
20 /**
21 * Internal implementation for finding the broadcast IPs.
22 * This function is implemented multiple times for multiple targets.
23 * @param broadcast the list of broadcasts to write into.
25 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast);
27 #if defined(PSP)
28 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // PSP implementation
32 #elif defined(BEOS_NET_SERVER) || defined(__HAIKU__) /* doesn't have neither getifaddrs or net/if.h */
33 /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
34 extern "C" int _netstat(int fd, char **output, int verbose);
36 int seek_past_header(char **pos, const char *header)
38 char *new_pos = strstr(*pos, header);
39 if (new_pos == 0) {
40 return B_ERROR;
42 *pos += strlen(header) + new_pos - *pos + 1;
43 return B_OK;
46 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // BEOS implementation
48 int sock = socket(AF_INET, SOCK_DGRAM, 0);
50 if (sock < 0) {
51 DEBUG(net, 0, "[core] error creating socket");
52 return;
55 char *output_pointer = NULL;
56 int output_length = _netstat(sock, &output_pointer, 1);
57 if (output_length < 0) {
58 DEBUG(net, 0, "[core] error running _netstat");
59 return;
62 char **output = &output_pointer;
63 if (seek_past_header(output, "IP Interfaces:") == B_OK) {
64 for (;;) {
65 uint32 n;
66 int fields, read;
67 uint8 i1, i2, i3, i4, j1, j2, j3, j4;
68 uint32 ip;
69 uint32 netmask;
71 fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n",
72 &n, &i1, &i2, &i3, &i4, &j1, &j2, &j3, &j4, &read);
73 read += 1;
74 if (fields != 9) {
75 break;
78 ip = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4;
79 netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4;
81 if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) {
82 sockaddr_storage address;
83 memset(&address, 0, sizeof(address));
84 ((sockaddr_in*)&address)->sin_addr.s_addr = htonl(ip | ~netmask);
85 NetworkAddress addr(address, sizeof(sockaddr));
86 if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
88 if (read < 0) {
89 break;
91 *output += read;
93 closesocket(sock);
97 #elif defined(HAVE_GETIFADDRS)
98 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // GETIFADDRS implementation
100 struct ifaddrs *ifap, *ifa;
102 if (getifaddrs(&ifap) != 0) return;
104 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
105 if (!(ifa->ifa_flags & IFF_BROADCAST)) continue;
106 if (ifa->ifa_broadaddr == NULL) continue;
107 if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;
109 NetworkAddress addr(ifa->ifa_broadaddr, sizeof(sockaddr));
110 if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
112 freeifaddrs(ifap);
115 #elif defined(WIN32)
116 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // Win32 implementation
118 SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
119 if (sock == INVALID_SOCKET) return;
121 DWORD len = 0;
122 int num = 2;
123 INTERFACE_INFO *ifo = CallocT<INTERFACE_INFO>(num);
125 for (;;) {
126 if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, ifo, num * sizeof(*ifo), &len, NULL, NULL) == 0) break;
127 free(ifo);
128 if (WSAGetLastError() != WSAEFAULT) {
129 closesocket(sock);
130 return;
132 num *= 2;
133 ifo = CallocT<INTERFACE_INFO>(num);
136 for (uint j = 0; j < len / sizeof(*ifo); j++) {
137 if (ifo[j].iiFlags & IFF_LOOPBACK) continue;
138 if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue;
140 sockaddr_storage address;
141 memset(&address, 0, sizeof(address));
142 /* iiBroadcast is unusable, because it always seems to be set to 255.255.255.255. */
143 memcpy(&address, &ifo[j].iiAddress.Address, sizeof(sockaddr));
144 ((sockaddr_in*)&address)->sin_addr.s_addr = ifo[j].iiAddress.AddressIn.sin_addr.s_addr | ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr;
145 NetworkAddress addr(address, sizeof(sockaddr));
146 if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
149 free(ifo);
150 closesocket(sock);
153 #else /* not HAVE_GETIFADDRS */
155 #include "../../string_func.h"
157 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // !GETIFADDRS implementation
159 SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
160 if (sock == INVALID_SOCKET) return;
162 char buf[4 * 1024]; // Arbitrary buffer size
163 struct ifconf ifconf;
165 ifconf.ifc_len = sizeof(buf);
166 ifconf.ifc_buf = buf;
167 if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) {
168 closesocket(sock);
169 return;
172 const char *buf_end = buf + ifconf.ifc_len;
173 for (const char *p = buf; p < buf_end;) {
174 const struct ifreq *req = (const struct ifreq*)p;
176 if (req->ifr_addr.sa_family == AF_INET) {
177 struct ifreq r;
179 strecpy(r.ifr_name, req->ifr_name, lastof(r.ifr_name));
180 if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 &&
181 (r.ifr_flags & IFF_BROADCAST) &&
182 ioctl(sock, SIOCGIFBRDADDR, &r) != -1) {
183 NetworkAddress addr(&r.ifr_broadaddr, sizeof(sockaddr));
184 if (!broadcast->Contains(addr)) *broadcast->Append() = addr;
188 p += sizeof(struct ifreq);
189 #if defined(AF_LINK) && !defined(SUNOS)
190 p += req->ifr_addr.sa_len - sizeof(struct sockaddr);
191 #endif
194 closesocket(sock);
196 #endif /* all NetworkFindBroadcastIPsInternals */
199 * Find the IPv4 broadcast addresses; IPv6 uses a completely different
200 * strategy for broadcasting.
201 * @param broadcast the list of broadcasts to write into.
203 void NetworkFindBroadcastIPs(NetworkAddressList *broadcast)
205 NetworkFindBroadcastIPsInternal(broadcast);
207 /* Now display to the debug all the detected ips */
208 DEBUG(net, 3, "Detected broadcast addresses:");
209 int i = 0;
210 for (NetworkAddress *addr = broadcast->Begin(); addr != broadcast->End(); addr++) {
211 addr->SetPort(NETWORK_DEFAULT_PORT);
212 DEBUG(net, 3, "%d) %s", i++, addr->GetHostname());
216 #endif /* ENABLE_NETWORK */