comparison src/network.c @ 8231:f50c059b6384

[gaim-migrate @ 8954] This is Tim Ringenbach's patch to move some IP-related functions into the new gaim_network namespace, improve the local IP checking functionality by opening a socket, change some prefs, and add the ability to modify these prefs in the UI. Some ft.c bugs were fixed, and OSCAR, Jabber and Yahoo were updated to reflect the changes. The DCC SEND portion of this patch was not committed, as per his request (unless I misunderstood? :) committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Thu, 12 Feb 2004 00:36:55 +0000
parents
children 5220e0898252
comparison
equal deleted inserted replaced
8230:4e354776ae2a 8231:f50c059b6384
1 /**
2 * @file network.c Network Implementation
3 * @ingroup core
4 *
5 * gaim
6 *
7 * Gaim is the legal property of its developers, whose names are too numerous
8 * to list here. Please refer to the COPYRIGHT file distributed with this
9 * source distribution.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include <errno.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <netdb.h>
30 #include <fcntl.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <sys/stat.h>
34 #include <arpa/inet.h>
35
36 #include "debug.h"
37 #include "account.h"
38 #include "network.h"
39 #include "prefs.h"
40
41 void
42 gaim_network_set_local_ip(const char *ip)
43 {
44 g_return_if_fail(ip != NULL);
45
46 gaim_prefs_set_string("/core/network/public_ip", ip);
47 }
48
49 const char *
50 gaim_network_get_local_ip(void)
51 {
52 const char *ip;
53
54 if (gaim_prefs_get_bool("/core/network/auto_ip"))
55 return NULL;
56
57 ip = gaim_prefs_get_string("/core/network/public_ip");
58
59 if (ip == NULL || *ip == '\0')
60 return NULL;
61
62 return ip;
63 }
64
65 static const char *
66 gaim_network_get_local_ip_from_fd(int fd)
67 {
68 struct sockaddr_in addr;
69 socklen_t len;
70 static char ip[16];
71 const char *tmp;
72
73 g_return_val_if_fail(fd > 0, NULL);
74
75 len = sizeof(addr);
76 if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) {
77 gaim_debug_warning("network", "getsockname: %s\n", strerror(errno));
78 return NULL;
79 }
80
81 tmp = inet_ntoa(addr.sin_addr);
82 strncpy(ip, tmp, sizeof(ip));
83 return ip;
84 }
85
86 const char *
87 gaim_network_get_local_system_ip(int fd)
88 {
89 struct hostent *host;
90 char localhost[129];
91 long unsigned add;
92 static char ip[46];
93 const char *tmp = NULL;
94
95 if (fd != -1)
96 tmp = gaim_network_get_local_ip_from_fd(fd);
97
98 if (tmp)
99 return tmp;
100
101 if (gethostname(localhost, 128) < 0)
102 return NULL;
103
104 if ((host = gethostbyname(localhost)) == NULL)
105 return NULL;
106
107 memcpy(&add, host->h_addr_list[0], 4);
108 add = htonl(add);
109
110 g_snprintf(ip, 16, "%lu.%lu.%lu.%lu",
111 ((add >> 24) & 255),
112 ((add >> 16) & 255),
113 ((add >> 8) & 255),
114 add & 255);
115
116 return ip;
117 }
118
119 const char *
120 gaim_network_get_ip_for_account(const GaimAccount *account, int fd)
121 {
122 if (account && (gaim_account_get_public_ip(account) != NULL))
123 return gaim_account_get_public_ip(account);
124 else if (gaim_network_get_local_ip() != NULL)
125 return gaim_network_get_local_ip();
126 else
127 return gaim_network_get_local_system_ip(fd);
128 }
129
130 static int gaim_network_do_listen(short portnum)
131 {
132 #if HAVE_GETADDRINFO
133 int listenfd;
134 const int on = 1;
135 struct addrinfo hints, *res, *ressave;
136 char serv[5];
137
138 snprintf(serv, sizeof(serv), "%d", portnum);
139 memset(&hints, 0, sizeof(struct addrinfo));
140 hints.ai_flags = AI_PASSIVE;
141 hints.ai_family = AF_UNSPEC;
142 hints.ai_socktype = SOCK_STREAM;
143 if (getaddrinfo(NULL /* any IP */, serv, &hints, &res) != 0) {
144 gaim_debug_warning("network", "getaddrinfo: %s\n", strerror(errno));
145 return -1;
146 }
147 ressave = res;
148 do {
149 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
150 if (listenfd < 0)
151 continue;
152 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
153 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
154 break; /* success */
155 close(listenfd);
156 } while ( (res = res->ai_next) );
157
158 if (!res)
159 return -1;
160
161 freeaddrinfo(ressave);
162 #else
163 int listenfd;
164 const int on = 1;
165 struct sockaddr_in sockin;
166
167 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
168 gaim_debug_warning("network", "socket: %s\n", strerror(errno));
169 return -1;
170 }
171
172 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) {
173 gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno));
174 close(listenfd);
175 return -1;
176 }
177
178 memset(&sockin, 0, sizeof(struct sockaddr_in));
179 sockin.sin_family = AF_INET;
180 sockin.sin_port = htons(portnum);
181
182 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) {
183 gaim_debug_warning("network", "bind: %s\n", strerror(errno));
184 close(listenfd);
185 return -1;
186 }
187 #endif
188
189 if (listen(listenfd, 4) != 0) {
190 gaim_debug_warning("network", "listen: %s\n", strerror(errno));
191 close(listenfd);
192 return -1;
193 }
194 fcntl(listenfd, F_SETFL, O_NONBLOCK);
195
196 gaim_debug_info("network", "Listening on port: %hu\n", gaim_network_get_port_from_fd(listenfd));
197 return listenfd;
198 }
199
200 int gaim_network_listen(short portnum)
201 {
202 int ret = 0, start, end;
203
204 if (!gaim_prefs_get_bool("/core/network/ports_range_use") || portnum)
205 return gaim_network_do_listen(portnum);
206
207 start = gaim_prefs_get_int("/core/network/ports_range_start");
208 end = gaim_prefs_get_int("/core/network/ports_range_end");
209
210 for (; start <= end; start++) {
211 ret = gaim_network_do_listen(start);
212 if (ret >= 0)
213 break;
214 }
215
216 return ret;
217 }
218
219 short gaim_network_get_port_from_fd(int fd)
220 {
221 struct sockaddr_in addr;
222 socklen_t len;
223
224 g_return_val_if_fail(fd > 0, 0);
225
226 len = sizeof(addr);
227 if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) {
228 gaim_debug_warning("network", "getsockname: %s\n", strerror(errno));
229 return 0;
230 }
231
232 return ntohs(addr.sin_port);
233 }
234
235 void
236 gaim_network_init(void)
237 {
238 gaim_prefs_add_none ("/core/network");
239 gaim_prefs_add_bool ("/core/network/auto_ip", TRUE);
240 gaim_prefs_add_string("/core/network/public_ip", "");
241 gaim_prefs_add_bool ("/core/network/ports_range_use", FALSE);
242 gaim_prefs_add_int ("/core/network/ports_range_start", 1024);
243 gaim_prefs_add_int ("/core/network/ports_range_end", 2048);
244 }