Mercurial > pidgin.yaz
annotate src/network.c @ 9449:ad93d76666dd
[gaim-migrate @ 10273]
Minor changes to the listen function in network.c
We were using strerror() to print the string form of
errno when getaddrinfo() failed, but that is incorrect.
getaddrinfo() does not use errno or strerror. It retuns an
integer error code which can be converted to a string with
gai_strerror(errorcode)
When we didn't have getaddrinfo, and we were unable to set
SO_REUSEADDR, we would abort the listen attempt. That's not
necessary becuase SO_REUSEADDR isn't vital, it's just nice
to have (right?)
struct addrinfo *res was not getting freed when we did not have
any interfaces to listen on (incredibly rare)
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Mon, 05 Jul 2004 15:43:26 +0000 |
parents | e40f9afd420e |
children | 0de62d92fb3b |
rev | line source |
---|---|
8231 | 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 | |
8245
91c6629b1ee8
[gaim-migrate @ 8968]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
8240
diff
changeset
|
26 #include "internal.h" |
8231 | 27 |
28 #include "debug.h" | |
29 #include "account.h" | |
30 #include "network.h" | |
31 #include "prefs.h" | |
32 | |
8838 | 33 const unsigned char * |
34 gaim_network_ip_atoi(const char *ip) | |
35 { | |
36 static unsigned char ret[4]; | |
8981 | 37 gchar *delimiter = "."; |
8838 | 38 gchar **split; |
39 int i; | |
40 | |
41 g_return_val_if_fail(ip != NULL, NULL); | |
42 | |
8981 | 43 split = g_strsplit(ip, delimiter, 4); |
8838 | 44 for (i = 0; split[i] != NULL; i++) |
45 ret[i] = atoi(split[i]); | |
46 g_strfreev(split); | |
47 | |
48 /* i should always be 4 */ | |
49 if (i != 4) | |
50 return NULL; | |
51 | |
52 return ret; | |
53 } | |
54 | |
8231 | 55 void |
8834 | 56 gaim_network_set_public_ip(const char *ip) |
8231 | 57 { |
58 g_return_if_fail(ip != NULL); | |
59 | |
8838 | 60 /* XXX - Ensure the IP address is valid */ |
61 | |
8231 | 62 gaim_prefs_set_string("/core/network/public_ip", ip); |
63 } | |
64 | |
65 const char * | |
8834 | 66 gaim_network_get_public_ip(void) |
8231 | 67 { |
68 const char *ip; | |
69 | |
70 ip = gaim_prefs_get_string("/core/network/public_ip"); | |
71 | |
72 if (ip == NULL || *ip == '\0') | |
73 return NULL; | |
74 | |
75 return ip; | |
76 } | |
77 | |
78 static const char * | |
79 gaim_network_get_local_ip_from_fd(int fd) | |
80 { | |
81 struct sockaddr_in addr; | |
82 socklen_t len; | |
83 static char ip[16]; | |
84 const char *tmp; | |
85 | |
8840 | 86 g_return_val_if_fail(fd >= 0, NULL); |
8231 | 87 |
88 len = sizeof(addr); | |
89 if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) { | |
90 gaim_debug_warning("network", "getsockname: %s\n", strerror(errno)); | |
91 return NULL; | |
92 } | |
93 | |
94 tmp = inet_ntoa(addr.sin_addr); | |
95 strncpy(ip, tmp, sizeof(ip)); | |
8838 | 96 |
8231 | 97 return ip; |
98 } | |
99 | |
100 const char * | |
101 gaim_network_get_local_system_ip(int fd) | |
102 { | |
103 struct hostent *host; | |
104 char localhost[129]; | |
105 long unsigned add; | |
106 static char ip[46]; | |
107 const char *tmp = NULL; | |
108 | |
8840 | 109 if (fd >= 0) |
8231 | 110 tmp = gaim_network_get_local_ip_from_fd(fd); |
111 | |
112 if (tmp) | |
113 return tmp; | |
114 | |
115 if (gethostname(localhost, 128) < 0) | |
116 return NULL; | |
117 | |
118 if ((host = gethostbyname(localhost)) == NULL) | |
119 return NULL; | |
120 | |
121 memcpy(&add, host->h_addr_list[0], 4); | |
122 add = htonl(add); | |
123 | |
124 g_snprintf(ip, 16, "%lu.%lu.%lu.%lu", | |
125 ((add >> 24) & 255), | |
126 ((add >> 16) & 255), | |
127 ((add >> 8) & 255), | |
128 add & 255); | |
129 | |
130 return ip; | |
131 } | |
132 | |
133 const char * | |
8838 | 134 gaim_network_get_my_ip(int fd) |
8231 | 135 { |
8834 | 136 const char *ip = NULL; |
137 | |
138 /* Check if the user specified an IP manually */ | |
139 if (!gaim_prefs_get_bool("/core/network/auto_ip")) { | |
140 ip = gaim_network_get_public_ip(); | |
141 if (ip != NULL) | |
142 return ip; | |
143 } | |
144 | |
145 /* Just fetch the IP of the local system */ | |
146 return gaim_network_get_local_system_ip(fd); | |
8231 | 147 } |
148 | |
8834 | 149 static int |
150 gaim_network_do_listen(unsigned short port) | |
8231 | 151 { |
152 int listenfd; | |
153 const int on = 1; | |
9449 | 154 #if HAVE_GETADDRINFO |
155 int errnum; | |
156 struct addrinfo hints, *res, *next; | |
8231 | 157 char serv[5]; |
158 | |
9449 | 159 /* |
160 * Get a list of addresses on this machine. | |
161 */ | |
162 snprintf(serv, sizeof(serv), "%hu", port); | |
8231 | 163 memset(&hints, 0, sizeof(struct addrinfo)); |
164 hints.ai_flags = AI_PASSIVE; | |
165 hints.ai_family = AF_UNSPEC; | |
166 hints.ai_socktype = SOCK_STREAM; | |
9449 | 167 errnum = getaddrinfo(NULL /* any IP */, serv, &hints, &res); |
168 if (errnum != 0) { | |
169 gaim_debug_warning("network", "getaddrinfo: %s\n", gai_strerror(errnum)); | |
170 if (errnum == EAI_SYSTEM) | |
171 gaim_debug_warning("network", "getaddrinfo: system error: %s\n", strerror(errno)); | |
8231 | 172 return -1; |
173 } | |
9449 | 174 |
175 /* | |
176 * Go through the list of addresses and attempt to listen on | |
177 * one of them. | |
178 * XXX - Try IPv6 addresses first? | |
179 */ | |
180 for (next = res; next != NULL; next = next->ai_next) { | |
8231 | 181 listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); |
182 if (listenfd < 0) | |
183 continue; | |
9449 | 184 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) |
185 gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno)); | |
8231 | 186 if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) |
187 break; /* success */ | |
188 close(listenfd); | |
9449 | 189 } |
8231 | 190 |
9449 | 191 freeaddrinfo(res); |
8231 | 192 |
9449 | 193 if (next == NULL) |
194 return -1; | |
8231 | 195 #else |
196 struct sockaddr_in sockin; | |
197 | |
198 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
199 gaim_debug_warning("network", "socket: %s\n", strerror(errno)); | |
200 return -1; | |
201 } | |
202 | |
9449 | 203 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) |
8231 | 204 gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno)); |
205 | |
206 memset(&sockin, 0, sizeof(struct sockaddr_in)); | |
9449 | 207 sockin.sin_family = PF_INET; |
8251 | 208 sockin.sin_port = htons(port); |
8231 | 209 |
210 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { | |
211 gaim_debug_warning("network", "bind: %s\n", strerror(errno)); | |
212 close(listenfd); | |
213 return -1; | |
214 } | |
215 #endif | |
216 | |
217 if (listen(listenfd, 4) != 0) { | |
218 gaim_debug_warning("network", "listen: %s\n", strerror(errno)); | |
219 close(listenfd); | |
220 return -1; | |
221 } | |
222 fcntl(listenfd, F_SETFL, O_NONBLOCK); | |
223 | |
224 gaim_debug_info("network", "Listening on port: %hu\n", gaim_network_get_port_from_fd(listenfd)); | |
225 return listenfd; | |
226 } | |
227 | |
8834 | 228 int |
229 gaim_network_listen(unsigned short port) | |
8246 | 230 { |
8250 | 231 g_return_val_if_fail(port != 0, -1); |
232 | |
8246 | 233 return gaim_network_do_listen(port); |
234 } | |
235 | |
8834 | 236 int |
237 gaim_network_listen_range(unsigned short start, unsigned short end) | |
8231 | 238 { |
8240 | 239 int ret = -1; |
8231 | 240 |
8250 | 241 if (gaim_prefs_get_bool("/core/network/ports_range_use")) { |
8239 | 242 start = gaim_prefs_get_int("/core/network/ports_range_start"); |
243 end = gaim_prefs_get_int("/core/network/ports_range_end"); | |
8250 | 244 } else { |
245 if (end < start) | |
246 end = start; | |
8239 | 247 } |
8231 | 248 |
249 for (; start <= end; start++) { | |
250 ret = gaim_network_do_listen(start); | |
251 if (ret >= 0) | |
252 break; | |
253 } | |
254 | |
255 return ret; | |
256 } | |
257 | |
8834 | 258 unsigned short |
259 gaim_network_get_port_from_fd(int fd) | |
8231 | 260 { |
261 struct sockaddr_in addr; | |
262 socklen_t len; | |
263 | |
9449 | 264 g_return_val_if_fail(fd >= 0, 0); |
8231 | 265 |
266 len = sizeof(addr); | |
267 if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) { | |
268 gaim_debug_warning("network", "getsockname: %s\n", strerror(errno)); | |
269 return 0; | |
270 } | |
271 | |
272 return ntohs(addr.sin_port); | |
273 } | |
274 | |
275 void | |
276 gaim_network_init(void) | |
277 { | |
278 gaim_prefs_add_none ("/core/network"); | |
279 gaim_prefs_add_bool ("/core/network/auto_ip", TRUE); | |
280 gaim_prefs_add_string("/core/network/public_ip", ""); | |
281 gaim_prefs_add_bool ("/core/network/ports_range_use", FALSE); | |
282 gaim_prefs_add_int ("/core/network/ports_range_start", 1024); | |
283 gaim_prefs_add_int ("/core/network/ports_range_end", 2048); | |
284 } |