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/>.
10 /** @file host.cpp Functions related to getting host specific data (IPs). */
14 #include "../../stdafx.h"
15 #include "../../debug.h"
19 * Internal implementation for finding the broadcast IPs.
20 * This function is implemented multiple times for multiple targets.
21 * @param broadcast the list of broadcasts to write into.
23 static void NetworkFindBroadcastIPsInternal(NetworkAddressList
*broadcast
);
26 static void NetworkFindBroadcastIPsInternal(NetworkAddressList
*broadcast
) // PSP implementation
30 #elif defined(BEOS_NET_SERVER) || defined(__HAIKU__) /* doesn't have neither getifaddrs or net/if.h */
31 /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
32 extern "C" int _netstat(int fd
, char **output
, int verbose
);
34 int seek_past_header(char **pos
, const char *header
)
36 char *new_pos
= strstr(*pos
, header
);
40 *pos
+= strlen(header
) + new_pos
- *pos
+ 1;
44 static void NetworkFindBroadcastIPsInternal(NetworkAddressList
*broadcast
) // BEOS implementation
46 int sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
49 DEBUG(net
, 0, "[core] error creating socket");
53 char *output_pointer
= NULL
;
54 int output_length
= _netstat(sock
, &output_pointer
, 1);
55 if (output_length
< 0) {
56 DEBUG(net
, 0, "[core] error running _netstat");
60 char **output
= &output_pointer
;
61 if (seek_past_header(output
, "IP Interfaces:") == B_OK
) {
65 uint8 i1
, i2
, i3
, i4
, j1
, j2
, j3
, j4
;
69 fields
= sscanf(*output
, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n",
70 &n
, &i1
, &i2
, &i3
, &i4
, &j1
, &j2
, &j3
, &j4
, &read
);
76 ip
= (uint32
)i1
<< 24 | (uint32
)i2
<< 16 | (uint32
)i3
<< 8 | (uint32
)i4
;
77 netmask
= (uint32
)j1
<< 24 | (uint32
)j2
<< 16 | (uint32
)j3
<< 8 | (uint32
)j4
;
79 if (ip
!= INADDR_LOOPBACK
&& ip
!= INADDR_ANY
) {
80 sockaddr_storage address
;
81 memset(&address
, 0, sizeof(address
));
82 ((sockaddr_in
*)&address
)->sin_addr
.s_addr
= htonl(ip
| ~netmask
);
83 NetworkAddress
addr(address
, sizeof(sockaddr
));
84 if (!broadcast
->Contains(addr
)) *broadcast
->Append() = addr
;
95 #elif defined(HAVE_GETIFADDRS)
96 static void NetworkFindBroadcastIPsInternal(NetworkAddressList
*broadcast
) // GETIFADDRS implementation
98 struct ifaddrs
*ifap
, *ifa
;
100 if (getifaddrs(&ifap
) != 0) return;
102 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
103 if (!(ifa
->ifa_flags
& IFF_BROADCAST
)) continue;
104 if (ifa
->ifa_broadaddr
== NULL
) continue;
105 if (ifa
->ifa_broadaddr
->sa_family
!= AF_INET
) continue;
107 NetworkAddress
addr(ifa
->ifa_broadaddr
, sizeof(sockaddr
));
108 if (!broadcast
->Contains(addr
)) *broadcast
->Append() = addr
;
114 static void NetworkFindBroadcastIPsInternal(NetworkAddressList
*broadcast
) // Win32 implementation
116 SOCKET sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
117 if (sock
== INVALID_SOCKET
) return;
121 INTERFACE_INFO
*ifo
= xcalloct
<INTERFACE_INFO
>(num
);
124 if (WSAIoctl(sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, ifo
, num
* sizeof(*ifo
), &len
, NULL
, NULL
) == 0) break;
126 if (WSAGetLastError() != WSAEFAULT
) {
131 ifo
= xcalloct
<INTERFACE_INFO
>(num
);
134 for (uint j
= 0; j
< len
/ sizeof(*ifo
); j
++) {
135 if (ifo
[j
].iiFlags
& IFF_LOOPBACK
) continue;
136 if (!(ifo
[j
].iiFlags
& IFF_BROADCAST
)) continue;
138 sockaddr_storage address
;
139 memset(&address
, 0, sizeof(address
));
140 /* iiBroadcast is unusable, because it always seems to be set to 255.255.255.255. */
141 memcpy(&address
, &ifo
[j
].iiAddress
.Address
, sizeof(sockaddr
));
142 ((sockaddr_in
*)&address
)->sin_addr
.s_addr
= ifo
[j
].iiAddress
.AddressIn
.sin_addr
.s_addr
| ~ifo
[j
].iiNetmask
.AddressIn
.sin_addr
.s_addr
;
143 NetworkAddress
addr(address
, sizeof(sockaddr
));
144 if (!broadcast
->Contains(addr
)) *broadcast
->Append() = addr
;
151 #else /* not HAVE_GETIFADDRS */
153 #include "../../string.h"
155 static void NetworkFindBroadcastIPsInternal(NetworkAddressList
*broadcast
) // !GETIFADDRS implementation
157 SOCKET sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
158 if (sock
== INVALID_SOCKET
) return;
160 char buf
[4 * 1024]; // Arbitrary buffer size
161 struct ifconf ifconf
;
163 ifconf
.ifc_len
= sizeof(buf
);
164 ifconf
.ifc_buf
= buf
;
165 if (ioctl(sock
, SIOCGIFCONF
, &ifconf
) == -1) {
170 const char *buf_end
= buf
+ ifconf
.ifc_len
;
171 for (const char *p
= buf
; p
< buf_end
;) {
172 const struct ifreq
*req
= (const struct ifreq
*)p
;
174 if (req
->ifr_addr
.sa_family
== AF_INET
) {
177 bstrcpy (r
.ifr_name
, req
->ifr_name
);
178 if (ioctl(sock
, SIOCGIFFLAGS
, &r
) != -1 &&
179 (r
.ifr_flags
& IFF_BROADCAST
) &&
180 ioctl(sock
, SIOCGIFBRDADDR
, &r
) != -1) {
181 NetworkAddress
addr(&r
.ifr_broadaddr
, sizeof(sockaddr
));
182 if (!broadcast
->Contains(addr
)) *broadcast
->Append() = addr
;
186 p
+= sizeof(struct ifreq
);
187 #if defined(AF_LINK) && !defined(SUNOS)
188 p
+= req
->ifr_addr
.sa_len
- sizeof(struct sockaddr
);
194 #endif /* all NetworkFindBroadcastIPsInternals */
197 * Find the IPv4 broadcast addresses; IPv6 uses a completely different
198 * strategy for broadcasting.
199 * @param broadcast the list of broadcasts to write into.
201 void NetworkFindBroadcastIPs(NetworkAddressList
*broadcast
)
203 NetworkFindBroadcastIPsInternal(broadcast
);
205 /* Now display to the debug all the detected ips */
206 DEBUG(net
, 3, "Detected broadcast addresses:");
208 for (NetworkAddress
*addr
= broadcast
->Begin(); addr
!= broadcast
->End(); addr
++) {
209 addr
->SetPort(NETWORK_DEFAULT_PORT
);
210 DEBUG(net
, 3, "%d) %s", i
++, addr
->GetHostname());
214 #endif /* ENABLE_NETWORK */