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