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
|
|
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
|
8239
|
200 int gaim_network_listen(short start, short end)
|
8231
|
201 {
|
8239
|
202 int ret = 0;
|
8231
|
203
|
8239
|
204 if (gaim_prefs_get_bool("/core/network/ports_range_use") ||
|
|
205 (start > end) || (start < 1024) || (end < 1024)) {
|
|
206 start = gaim_prefs_get_int("/core/network/ports_range_start");
|
|
207 end = gaim_prefs_get_int("/core/network/ports_range_end");
|
|
208 }
|
8231
|
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 }
|