OpenTTD Source: src/network/core/host.cpp Source File

OpenTTD Source 1.11.0-RC1

host.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
7
10 #include "../../stdafx.h"
11 #include "../../debug.h"
12 #include "address.h"
13
14 #include "../../safeguards.h"
15
21 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast);
22
23 #if defined(__HAIKU__) /* doesn't have neither getifaddrs or net/if.h */
24 /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
25 extern "C" int _netstat(int fd, char **output, int verbose);
26
27 int seek_past_header(char **pos, const char *header)
28 {
29 char *new_pos = strstr(*pos, header);
30 if (new_pos == 0) {
31 return B_ERROR;
32 }
33 *pos += strlen(header) + new_pos - *pos + 1;
34 return B_OK;
35 }
36
37 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // BEOS implementation
38 {
39 int sock = socket(AF_INET, SOCK_DGRAM, 0);
40
41 if (sock < 0) {
42 DEBUG(net, 0, "[core] error creating socket");
43 return;
44 }
45
46 char *output_pointer = nullptr;
47 int output_length = _netstat(sock, &output_pointer, 1);
48 if (output_length < 0) {
49 DEBUG(net, 0, "[core] error running _netstat");
50 return;
51 }
52
53 char **output = &output_pointer;
54 if (seek_past_header(output, "IP Interfaces:") == B_OK) {
55 for (;;) {
56 uint32 n;
57 int fields, read;
58 uint8 i1, i2, i3, i4, j1, j2, j3, j4;
59 uint32 ip;
60 uint32 netmask;
61
62 fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n",
63 &n, &i1, &i2, &i3, &i4, &j1, &j2, &j3, &j4, &read);
64 read += 1;
65 if (fields != 9) {
66 break;
67 }
68
69 ip = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4;
70 netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4;
71
72 if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) {
73 sockaddr_storage address;
74 memset(&address, 0, sizeof(address));
75 ((sockaddr_in*)&address)->sin_addr.s_addr = htonl(ip | ~netmask);
76 NetworkAddress addr(address, sizeof(sockaddr));
77 if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr);
78 }
79 if (read < 0) {
80 break;
81 }
82 *output += read;
83 }
84 closesocket(sock);
85 }
86 }
87
88 #elif defined(HAVE_GETIFADDRS)
89 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // GETIFADDRS implementation
90 {
91 struct ifaddrs *ifap, *ifa;
92
93 if (getifaddrs(&ifap) != 0) return;
94
95 for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) {
96 if (!(ifa->ifa_flags & IFF_BROADCAST)) continue;
97 if (ifa->ifa_broadaddr == nullptr) continue;
98 if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;
99
100 NetworkAddress addr(ifa->ifa_broadaddr, sizeof(sockaddr));
101 if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr);
102 }
103 freeifaddrs(ifap);
104 }
105
106 #elif defined(_WIN32)
107 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // Win32 implementation
108 {
109 SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
110 if (sock == INVALID_SOCKET) return;
111
112 DWORD len = 0;
113 int num = 2;
114 INTERFACE_INFO *ifo = CallocT<INTERFACE_INFO>(num);
115
116 for (;;) {
117 if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, nullptr, 0, ifo, num * sizeof(*ifo), &len, nullptr, nullptr) == 0) break;
118 free(ifo);
119 if (WSAGetLastError() != WSAEFAULT) {
120 closesocket(sock);
121 return;
122 }
123 num *= 2;
124 ifo = CallocT<INTERFACE_INFO>(num);
125 }
126
127 for (uint j = 0; j < len / sizeof(*ifo); j++) {
128 if (ifo[j].iiFlags & IFF_LOOPBACK) continue;
129 if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue;
130
131 sockaddr_storage address;
132 memset(&address, 0, sizeof(address));
133 /* iiBroadcast is unusable, because it always seems to be set to 255.255.255.255. */
134 memcpy(&address, &ifo[j].iiAddress.Address, sizeof(sockaddr));
135 ((sockaddr_in*)&address)->sin_addr.s_addr = ifo[j].iiAddress.AddressIn.sin_addr.s_addr | ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr;
136 NetworkAddress addr(address, sizeof(sockaddr));
137 if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr);
138 }
139
140 free(ifo);
141 closesocket(sock);
142 }
143
144 #else /* not HAVE_GETIFADDRS */
145
146 #include "../../string_func.h"
147
148 static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // !GETIFADDRS implementation
149 {
150 SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
151 if (sock == INVALID_SOCKET) return;
152
153 char buf[4 * 1024]; // Arbitrary buffer size
154 struct ifconf ifconf;
155
156 ifconf.ifc_len = sizeof(buf);
157 ifconf.ifc_buf = buf;
158 if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) {
159 closesocket(sock);
160 return;
161 }
162
163 const char *buf_end = buf + ifconf.ifc_len;
164 for (const char *p = buf; p < buf_end;) {
165 const struct ifreq *req = (const struct ifreq*)p;
166
167 if (req->ifr_addr.sa_family == AF_INET) {
168 struct ifreq r;
169
170 strecpy(r.ifr_name, req->ifr_name, lastof(r.ifr_name));
171 if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 &&
172 (r.ifr_flags & IFF_BROADCAST) &&
173 ioctl(sock, SIOCGIFBRDADDR, &r) != -1) {
174 NetworkAddress addr(&r.ifr_broadaddr, sizeof(sockaddr));
175 if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr);
176 }
177 }
178
179 p += sizeof(struct ifreq);
180 #if defined(AF_LINK) && !defined(SUNOS)
181 p += req->ifr_addr.sa_len - sizeof(struct sockaddr);
182 #endif
183 }
184
185 closesocket(sock);
186 }
187 #endif /* all NetworkFindBroadcastIPsInternals */
188
194 void NetworkFindBroadcastIPs(NetworkAddressList *broadcast)
195 {
196 NetworkFindBroadcastIPsInternal(broadcast);
197
198 /* Now display to the debug all the detected ips */
199 DEBUG(net, 3, "Detected broadcast addresses:");
200 int i = 0;
201 for (NetworkAddress &addr : *broadcast) {
202 addr.SetPort(NETWORK_DEFAULT_PORT);
203 DEBUG(net, 3, "%d) %s", i++, addr.GetHostname());
204 }
205 }
NETWORK_DEFAULT_PORT
static const uint16 NETWORK_DEFAULT_PORT
The default port of the game server (TCP & UDP)
Definition: config.h:29
NetworkAddressList
std::vector< NetworkAddress > NetworkAddressList
Type for a list of addresses.
Definition: address.h:20
address.h
DEBUG
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:35
NetworkFindBroadcastIPsInternal
static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast)
Internal implementation for finding the broadcast IPs.
Definition: host.cpp:148
NetworkAddress
Wrapper for (un)resolved network addresses; there's no reason to transform a numeric IP to a string a...
Definition: address.h:29
NetworkFindBroadcastIPs
void NetworkFindBroadcastIPs(NetworkAddressList *broadcast)
Find the IPv4 broadcast addresses; IPv6 uses a completely different strategy for broadcasting.
Definition: host.cpp:194
strecpy
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
Definition: string.cpp:112
free
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: stdafx.h:454
lastof
#define lastof(x)
Get the last element of an fixed size array.
Definition: stdafx.h:383