| 156 if (ip == NULL || *ip == '\0') { |
163 if (ip == NULL || *ip == '\0') { |
| 157 /* Check if STUN discovery was already done */ |
164 /* Check if STUN discovery was already done */ |
| 158 stun = gaim_stun_discover(NULL); |
165 stun = gaim_stun_discover(NULL); |
| 159 if (stun != NULL && stun->status == GAIM_STUN_STATUS_DISCOVERED) |
166 if (stun != NULL && stun->status == GAIM_STUN_STATUS_DISCOVERED) |
| 160 return stun->publicip; |
167 return stun->publicip; |
| 161 } |
168 |
| 162 |
169 /* attempt to get the ip from a NAT device */ |
| 163 |
170 ip = gaim_upnp_get_public_ip(); |
| 164 /* attempt to get the ip from a NAT device */ |
|
| 165 if ((controlInfo = gaim_upnp_discover()) != NULL) { |
|
| 166 ip = gaim_upnp_get_public_ip(controlInfo); |
|
| 167 |
|
| 168 g_free(controlInfo->controlURL); |
|
| 169 g_free(controlInfo->serviceType); |
|
| 170 g_free(controlInfo); |
|
| 171 |
171 |
| 172 if (ip != NULL) |
172 if (ip != NULL) |
| 173 return ip; |
173 return ip; |
| 174 } |
174 } |
| 175 |
175 |
| 176 /* Just fetch the IP of the local system */ |
176 /* Just fetch the IP of the local system */ |
| 177 return gaim_network_get_local_system_ip(fd); |
177 return gaim_network_get_local_system_ip(fd); |
| 178 } |
178 } |
| 179 |
179 |
| 180 |
180 |
| 181 static int |
181 static void |
| 182 gaim_network_do_listen(unsigned short port, int socket_type) |
182 gaim_network_set_upnp_port_mapping_cb(gboolean success, gpointer data) |
| |
183 { |
| |
184 ListenUPnPData *ldata = data; |
| |
185 |
| |
186 if (!success) { |
| |
187 gaim_debug_warning("network", "Couldn't create UPnP mapping for...\n"); |
| |
188 if (ldata->retry) { |
| |
189 ldata->retry = FALSE; |
| |
190 ldata->adding = FALSE; |
| |
191 gaim_upnp_remove_port_mapping( |
| |
192 gaim_network_get_port_from_fd(ldata->listenfd), |
| |
193 (ldata->socket_type == SOCK_STREAM) ? "TCP" : "UDP", |
| |
194 gaim_network_set_upnp_port_mapping_cb, ldata); |
| |
195 return; |
| |
196 } |
| |
197 } else if (!ldata->adding) { |
| |
198 /* We've tried successfully to remove the port mapping. |
| |
199 * Try to add it again */ |
| |
200 ldata->adding = TRUE; |
| |
201 gaim_upnp_set_port_mapping( |
| |
202 gaim_network_get_port_from_fd(ldata->listenfd), |
| |
203 (ldata->socket_type == SOCK_STREAM) ? "TCP" : "UDP", |
| |
204 gaim_network_set_upnp_port_mapping_cb, ldata); |
| |
205 return; |
| |
206 } |
| |
207 |
| |
208 if (ldata->cb) |
| |
209 ldata->cb(ldata->listenfd, ldata->cb_data); |
| |
210 |
| |
211 g_free(ldata); |
| |
212 } |
| |
213 |
| |
214 |
| |
215 static gboolean |
| |
216 gaim_network_do_listen(unsigned short port, int socket_type, GaimNetworkListenCallback cb, gpointer cb_data) |
| 183 { |
217 { |
| 184 int listenfd = -1; |
218 int listenfd = -1; |
| 185 const int on = 1; |
219 const int on = 1; |
| 186 GaimUPnPControlInfo* controlInfo = NULL; |
|
| 187 #if HAVE_GETADDRINFO |
220 #if HAVE_GETADDRINFO |
| 188 int errnum; |
221 int errnum; |
| 189 struct addrinfo hints, *res, *next; |
222 struct addrinfo hints, *res, *next; |
| 190 char serv[6]; |
223 char serv[6]; |
| |
224 ListenUPnPData *ld; |
| 191 |
225 |
| 192 /* |
226 /* |
| 193 * Get a list of addresses on this machine. |
227 * Get a list of addresses on this machine. |
| 194 */ |
228 */ |
| 195 snprintf(serv, sizeof(serv), "%hu", port); |
229 snprintf(serv, sizeof(serv), "%hu", port); |
| 202 #ifndef _WIN32 |
236 #ifndef _WIN32 |
| 203 gaim_debug_warning("network", "getaddrinfo: %s\n", gai_strerror(errnum)); |
237 gaim_debug_warning("network", "getaddrinfo: %s\n", gai_strerror(errnum)); |
| 204 if (errnum == EAI_SYSTEM) |
238 if (errnum == EAI_SYSTEM) |
| 205 gaim_debug_warning("network", "getaddrinfo: system error: %s\n", strerror(errno)); |
239 gaim_debug_warning("network", "getaddrinfo: system error: %s\n", strerror(errno)); |
| 206 #else |
240 #else |
| 207 gaim_debug_warning("network", "getaddrinfo: Error Code = %d\n", errnum); |
241 gaim_debug_warning("network", "getaddrinfo: Error Code = %d\n", errnum); |
| 208 #endif |
242 #endif |
| 209 return -1; |
243 return FALSE; |
| 210 } |
244 } |
| 211 |
245 |
| 212 /* |
246 /* |
| 213 * Go through the list of addresses and attempt to listen on |
247 * Go through the list of addresses and attempt to listen on |
| 214 * one of them. |
248 * one of them. |
| 228 } |
262 } |
| 229 |
263 |
| 230 freeaddrinfo(res); |
264 freeaddrinfo(res); |
| 231 |
265 |
| 232 if (next == NULL) |
266 if (next == NULL) |
| 233 return -1; |
267 return FALSE; |
| 234 #else |
268 #else |
| 235 struct sockaddr_in sockin; |
269 struct sockaddr_in sockin; |
| 236 |
270 |
| 237 if ((listenfd = socket(AF_INET, socket_type, 0)) < 0) { |
271 if ((listenfd = socket(AF_INET, socket_type, 0)) < 0) { |
| 238 gaim_debug_warning("network", "socket: %s\n", strerror(errno)); |
272 gaim_debug_warning("network", "socket: %s\n", strerror(errno)); |
| 239 return -1; |
273 return FALSE; |
| 240 } |
274 } |
| 241 |
275 |
| 242 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) |
276 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) |
| 243 gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno)); |
277 gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno)); |
| 244 |
278 |
| 247 sockin.sin_port = htons(port); |
281 sockin.sin_port = htons(port); |
| 248 |
282 |
| 249 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { |
283 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { |
| 250 gaim_debug_warning("network", "bind: %s\n", strerror(errno)); |
284 gaim_debug_warning("network", "bind: %s\n", strerror(errno)); |
| 251 close(listenfd); |
285 close(listenfd); |
| 252 return -1; |
286 return FALSE; |
| 253 } |
287 } |
| 254 #endif |
288 #endif |
| 255 |
289 |
| 256 if (socket_type == SOCK_STREAM && listen(listenfd, 4) != 0) { |
290 if (socket_type == SOCK_STREAM && listen(listenfd, 4) != 0) { |
| 257 gaim_debug_warning("network", "listen: %s\n", strerror(errno)); |
291 gaim_debug_warning("network", "listen: %s\n", strerror(errno)); |
| 258 close(listenfd); |
292 close(listenfd); |
| 259 return -1; |
293 return FALSE; |
| 260 } |
294 } |
| 261 fcntl(listenfd, F_SETFL, O_NONBLOCK); |
295 fcntl(listenfd, F_SETFL, O_NONBLOCK); |
| 262 |
296 |
| 263 if ((controlInfo = gaim_upnp_discover()) != NULL) { |
|
| 264 char *type_desc = (socket_type == SOCK_STREAM) ? "TCP" : "UDP"; |
|
| 265 if (!gaim_upnp_set_port_mapping(controlInfo, |
|
| 266 gaim_network_get_port_from_fd(listenfd), |
|
| 267 type_desc)) { |
|
| 268 gaim_upnp_remove_port_mapping(controlInfo, |
|
| 269 gaim_network_get_port_from_fd(listenfd), |
|
| 270 type_desc); |
|
| 271 gaim_upnp_set_port_mapping(controlInfo, |
|
| 272 gaim_network_get_port_from_fd(listenfd), |
|
| 273 type_desc); |
|
| 274 |
|
| 275 } |
|
| 276 g_free(controlInfo->serviceType); |
|
| 277 g_free(controlInfo->controlURL); |
|
| 278 g_free(controlInfo); |
|
| 279 } |
|
| 280 |
|
| 281 gaim_debug_info("network", "Listening on port: %hu\n", gaim_network_get_port_from_fd(listenfd)); |
297 gaim_debug_info("network", "Listening on port: %hu\n", gaim_network_get_port_from_fd(listenfd)); |
| 282 return listenfd; |
298 |
| 283 } |
299 ld = g_new0(ListenUPnPData, 1); |
| 284 |
300 ld->listenfd = listenfd; |
| 285 int |
301 ld->adding = TRUE; |
| 286 gaim_network_listen(unsigned short port, int socket_type) |
302 ld->retry = TRUE; |
| |
303 ld->cb = cb; |
| |
304 ld->cb_data = cb_data; |
| |
305 |
| |
306 gaim_upnp_set_port_mapping( |
| |
307 gaim_network_get_port_from_fd(listenfd), |
| |
308 (socket_type == SOCK_STREAM) ? "TCP" : "UDP", |
| |
309 gaim_network_set_upnp_port_mapping_cb, ld); |
| |
310 |
| |
311 return TRUE; |
| |
312 } |
| |
313 |
| |
314 gboolean |
| |
315 gaim_network_listen(unsigned short port, int socket_type, |
| |
316 GaimNetworkListenCallback cb, gpointer cb_data) |
| 287 { |
317 { |
| 288 g_return_val_if_fail(port != 0, -1); |
318 g_return_val_if_fail(port != 0, -1); |
| 289 |
319 |
| 290 return gaim_network_do_listen(port, socket_type); |
320 return gaim_network_do_listen(port, socket_type, cb, cb_data); |
| 291 } |
321 } |
| 292 |
322 |
| 293 int |
323 gboolean |
| 294 gaim_network_listen_range(unsigned short start, unsigned short end, |
324 gaim_network_listen_range(unsigned short start, unsigned short end, |
| 295 int socket_type) |
325 int socket_type, GaimNetworkListenCallback cb, gpointer cb_data) |
| 296 { |
326 { |
| 297 int ret = -1; |
327 gboolean ret = FALSE; |
| 298 |
328 |
| 299 if (gaim_prefs_get_bool("/core/network/ports_range_use")) { |
329 if (gaim_prefs_get_bool("/core/network/ports_range_use")) { |
| 300 start = gaim_prefs_get_int("/core/network/ports_range_start"); |
330 start = gaim_prefs_get_int("/core/network/ports_range_start"); |
| 301 end = gaim_prefs_get_int("/core/network/ports_range_end"); |
331 end = gaim_prefs_get_int("/core/network/ports_range_end"); |
| 302 } else { |
332 } else { |
| 303 if (end < start) |
333 if (end < start) |
| 304 end = start; |
334 end = start; |
| 305 } |
335 } |
| 306 |
336 |
| 307 for (; start <= end; start++) { |
337 for (; start <= end; start++) { |
| 308 ret = gaim_network_do_listen(start, socket_type); |
338 ret = gaim_network_do_listen(start, socket_type, cb, cb_data); |
| 309 if (ret >= 0) |
339 if (ret) |
| 310 break; |
340 break; |
| 311 } |
341 } |
| 312 |
342 |
| 313 return ret; |
343 return ret; |
| 314 } |
344 } |
| 337 gaim_prefs_add_bool ("/core/network/auto_ip", TRUE); |
367 gaim_prefs_add_bool ("/core/network/auto_ip", TRUE); |
| 338 gaim_prefs_add_string("/core/network/public_ip", ""); |
368 gaim_prefs_add_string("/core/network/public_ip", ""); |
| 339 gaim_prefs_add_bool ("/core/network/ports_range_use", FALSE); |
369 gaim_prefs_add_bool ("/core/network/ports_range_use", FALSE); |
| 340 gaim_prefs_add_int ("/core/network/ports_range_start", 1024); |
370 gaim_prefs_add_int ("/core/network/ports_range_start", 1024); |
| 341 gaim_prefs_add_int ("/core/network/ports_range_end", 2048); |
371 gaim_prefs_add_int ("/core/network/ports_range_end", 2048); |
| 342 } |
372 |
| |
373 gaim_upnp_discover(NULL, NULL); |
| |
374 } |