1 /* $Id: host.cpp 17693 2009-10-04 17:16:41Z rubidium $ */
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"
18 #include "../../safeguards.h"
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
);
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
);
42 *pos
+= strlen(header
) + new_pos
- *pos
+ 1;
46 static void NetworkFindBroadcastIPsInternal(NetworkAddressList
*broadcast
) // BEOS implementation
48 int sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
51 DEBUG(net
, 0, "[core] error creating socket");
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");
62 char **output
= &output_pointer
;
63 if (seek_past_header(output
, "IP Interfaces:") == B_OK
) {
67 uint8 i1
, i2
, i3
, i4
, j1
, j2
, j3
, j4
;
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
);
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
;
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
;
116 static void NetworkFindBroadcastIPsInternal(NetworkAddressList
*broadcast
) // Win32 implementation
118 SOCKET sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
119 if (sock
== INVALID_SOCKET
) return;
123 INTERFACE_INFO
*ifo
= CallocT
<INTERFACE_INFO
>(num
);
126 if (WSAIoctl(sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, ifo
, num
* sizeof(*ifo
), &len
, NULL
, NULL
) == 0) break;
128 if (WSAGetLastError() != WSAEFAULT
) {
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
;
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) {
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
) {
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
);
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:");
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 */