Mercurial > pidgin
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 } |
