Tue, 24 Feb 2004 04:29:44 +0000
[gaim-migrate @ 9054]
// comments are bad in C. I'm not sure why this code wasn't just removed,
though, since it's now in the toolbar code... Oh, and someone needs to set
things up so the conversation code can trigger buttons on the toolbar,
*before* release.
| 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
c1397ca0a619
[gaim-migrate @ 8968]
Herman Bloggs <herman@bluedigits.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 | ||
| 33 | void | |
| 34 | gaim_network_set_local_ip(const char *ip) | |
| 35 | { | |
| 36 | g_return_if_fail(ip != NULL); | |
| 37 | ||
| 38 | gaim_prefs_set_string("/core/network/public_ip", ip); | |
| 39 | } | |
| 40 | ||
| 41 | const char * | |
| 42 | gaim_network_get_local_ip(void) | |
| 43 | { | |
| 44 | const char *ip; | |
| 45 | ||
| 46 | if (gaim_prefs_get_bool("/core/network/auto_ip")) | |
| 47 | return NULL; | |
| 48 | ||
| 49 | ip = gaim_prefs_get_string("/core/network/public_ip"); | |
| 50 | ||
| 51 | if (ip == NULL || *ip == '\0') | |
| 52 | return NULL; | |
| 53 | ||
| 54 | return ip; | |
| 55 | } | |
| 56 | ||
| 57 | static const char * | |
| 58 | gaim_network_get_local_ip_from_fd(int fd) | |
| 59 | { | |
| 60 | struct sockaddr_in addr; | |
| 61 | socklen_t len; | |
| 62 | static char ip[16]; | |
| 63 | const char *tmp; | |
| 64 | ||
| 65 | g_return_val_if_fail(fd > 0, NULL); | |
| 66 | ||
| 67 | len = sizeof(addr); | |
| 68 | if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) { | |
| 69 | gaim_debug_warning("network", "getsockname: %s\n", strerror(errno)); | |
| 70 | return NULL; | |
| 71 | } | |
| 72 | ||
| 73 | tmp = inet_ntoa(addr.sin_addr); | |
| 74 | strncpy(ip, tmp, sizeof(ip)); | |
| 75 | return ip; | |
| 76 | } | |
| 77 | ||
| 78 | const char * | |
| 79 | gaim_network_get_local_system_ip(int fd) | |
| 80 | { | |
| 81 | struct hostent *host; | |
| 82 | char localhost[129]; | |
| 83 | long unsigned add; | |
| 84 | static char ip[46]; | |
| 85 | const char *tmp = NULL; | |
| 86 | ||
| 87 | if (fd != -1) | |
| 88 | tmp = gaim_network_get_local_ip_from_fd(fd); | |
| 89 | ||
| 90 | if (tmp) | |
| 91 | return tmp; | |
| 92 | ||
| 93 | if (gethostname(localhost, 128) < 0) | |
| 94 | return NULL; | |
| 95 | ||
| 96 | if ((host = gethostbyname(localhost)) == NULL) | |
| 97 | return NULL; | |
| 98 | ||
| 99 | memcpy(&add, host->h_addr_list[0], 4); | |
| 100 | add = htonl(add); | |
| 101 | ||
| 102 | g_snprintf(ip, 16, "%lu.%lu.%lu.%lu", | |
| 103 | ((add >> 24) & 255), | |
| 104 | ((add >> 16) & 255), | |
| 105 | ((add >> 8) & 255), | |
| 106 | add & 255); | |
| 107 | ||
| 108 | return ip; | |
| 109 | } | |
| 110 | ||
| 111 | const char * | |
| 112 | gaim_network_get_ip_for_account(const GaimAccount *account, int fd) | |
| 113 | { | |
| 114 | if (account && (gaim_account_get_public_ip(account) != NULL)) | |
| 115 | return gaim_account_get_public_ip(account); | |
| 116 | else if (gaim_network_get_local_ip() != NULL) | |
| 117 | return gaim_network_get_local_ip(); | |
| 118 | else | |
| 119 | return gaim_network_get_local_system_ip(fd); | |
| 120 | } | |
| 121 | ||
|
8251
091ca9b900c1
[gaim-migrate @ 8974]
Mark Doliner <markdoliner@pidgin.im>
parents:
8250
diff
changeset
|
122 | static int gaim_network_do_listen(unsigned short port) |
| 8231 | 123 | { |
| 124 | #if HAVE_GETADDRINFO | |
| 125 | int listenfd; | |
| 126 | const int on = 1; | |
| 127 | struct addrinfo hints, *res, *ressave; | |
| 128 | char serv[5]; | |
| 129 | ||
|
8251
091ca9b900c1
[gaim-migrate @ 8974]
Mark Doliner <markdoliner@pidgin.im>
parents:
8250
diff
changeset
|
130 | snprintf(serv, sizeof(serv), "%d", port); |
| 8231 | 131 | memset(&hints, 0, sizeof(struct addrinfo)); |
| 132 | hints.ai_flags = AI_PASSIVE; | |
| 133 | hints.ai_family = AF_UNSPEC; | |
| 134 | hints.ai_socktype = SOCK_STREAM; | |
| 135 | if (getaddrinfo(NULL /* any IP */, serv, &hints, &res) != 0) { | |
| 136 | gaim_debug_warning("network", "getaddrinfo: %s\n", strerror(errno)); | |
| 137 | return -1; | |
| 138 | } | |
| 139 | ressave = res; | |
| 140 | do { | |
| 141 | listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); | |
| 142 | if (listenfd < 0) | |
| 143 | continue; | |
| 144 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); | |
| 145 | if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) | |
| 146 | break; /* success */ | |
| 147 | close(listenfd); | |
| 148 | } while ( (res = res->ai_next) ); | |
| 149 | ||
| 150 | if (!res) | |
| 151 | return -1; | |
| 152 | ||
| 153 | freeaddrinfo(ressave); | |
| 154 | #else | |
| 155 | int listenfd; | |
| 156 | const int on = 1; | |
| 157 | struct sockaddr_in sockin; | |
| 158 | ||
| 159 | if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
| 160 | gaim_debug_warning("network", "socket: %s\n", strerror(errno)); | |
| 161 | return -1; | |
| 162 | } | |
| 163 | ||
| 164 | if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) { | |
| 165 | gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno)); | |
| 166 | close(listenfd); | |
| 167 | return -1; | |
| 168 | } | |
| 169 | ||
| 170 | memset(&sockin, 0, sizeof(struct sockaddr_in)); | |
| 171 | sockin.sin_family = AF_INET; | |
|
8251
091ca9b900c1
[gaim-migrate @ 8974]
Mark Doliner <markdoliner@pidgin.im>
parents:
8250
diff
changeset
|
172 | sockin.sin_port = htons(port); |
| 8231 | 173 | |
| 174 | if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { | |
| 175 | gaim_debug_warning("network", "bind: %s\n", strerror(errno)); | |
| 176 | close(listenfd); | |
| 177 | return -1; | |
| 178 | } | |
| 179 | #endif | |
| 180 | ||
| 181 | if (listen(listenfd, 4) != 0) { | |
| 182 | gaim_debug_warning("network", "listen: %s\n", strerror(errno)); | |
| 183 | close(listenfd); | |
| 184 | return -1; | |
| 185 | } | |
| 186 | fcntl(listenfd, F_SETFL, O_NONBLOCK); | |
| 187 | ||
| 188 | gaim_debug_info("network", "Listening on port: %hu\n", gaim_network_get_port_from_fd(listenfd)); | |
| 189 | return listenfd; | |
| 190 | } | |
| 191 | ||
|
8250
e855dcce1fa0
[gaim-migrate @ 8973]
Mark Doliner <markdoliner@pidgin.im>
parents:
8248
diff
changeset
|
192 | int gaim_network_listen(unsigned short port) |
|
8246
c83c0421149a
[gaim-migrate @ 8969]
Mark Doliner <markdoliner@pidgin.im>
parents:
8245
diff
changeset
|
193 | { |
|
8250
e855dcce1fa0
[gaim-migrate @ 8973]
Mark Doliner <markdoliner@pidgin.im>
parents:
8248
diff
changeset
|
194 | g_return_val_if_fail(port != 0, -1); |
|
e855dcce1fa0
[gaim-migrate @ 8973]
Mark Doliner <markdoliner@pidgin.im>
parents:
8248
diff
changeset
|
195 | |
|
8246
c83c0421149a
[gaim-migrate @ 8969]
Mark Doliner <markdoliner@pidgin.im>
parents:
8245
diff
changeset
|
196 | return gaim_network_do_listen(port); |
|
c83c0421149a
[gaim-migrate @ 8969]
Mark Doliner <markdoliner@pidgin.im>
parents:
8245
diff
changeset
|
197 | } |
|
c83c0421149a
[gaim-migrate @ 8969]
Mark Doliner <markdoliner@pidgin.im>
parents:
8245
diff
changeset
|
198 | |
|
8250
e855dcce1fa0
[gaim-migrate @ 8973]
Mark Doliner <markdoliner@pidgin.im>
parents:
8248
diff
changeset
|
199 | int gaim_network_listen_range(unsigned short start, unsigned short end) |
| 8231 | 200 | { |
|
8240
2e5f97ed575d
[gaim-migrate @ 8963]
Mark Doliner <markdoliner@pidgin.im>
parents:
8239
diff
changeset
|
201 | int ret = -1; |
| 8231 | 202 | |
|
8250
e855dcce1fa0
[gaim-migrate @ 8973]
Mark Doliner <markdoliner@pidgin.im>
parents:
8248
diff
changeset
|
203 | if (gaim_prefs_get_bool("/core/network/ports_range_use")) { |
|
8239
d19f1c66720c
[gaim-migrate @ 8962]
Mark Doliner <markdoliner@pidgin.im>
parents:
8231
diff
changeset
|
204 | start = gaim_prefs_get_int("/core/network/ports_range_start"); |
|
d19f1c66720c
[gaim-migrate @ 8962]
Mark Doliner <markdoliner@pidgin.im>
parents:
8231
diff
changeset
|
205 | end = gaim_prefs_get_int("/core/network/ports_range_end"); |
|
8250
e855dcce1fa0
[gaim-migrate @ 8973]
Mark Doliner <markdoliner@pidgin.im>
parents:
8248
diff
changeset
|
206 | } else { |
|
e855dcce1fa0
[gaim-migrate @ 8973]
Mark Doliner <markdoliner@pidgin.im>
parents:
8248
diff
changeset
|
207 | if (end < start) |
|
e855dcce1fa0
[gaim-migrate @ 8973]
Mark Doliner <markdoliner@pidgin.im>
parents:
8248
diff
changeset
|
208 | end = start; |
|
8239
d19f1c66720c
[gaim-migrate @ 8962]
Mark Doliner <markdoliner@pidgin.im>
parents:
8231
diff
changeset
|
209 | } |
| 8231 | 210 | |
| 211 | for (; start <= end; start++) { | |
| 212 | ret = gaim_network_do_listen(start); | |
| 213 | if (ret >= 0) | |
| 214 | break; | |
| 215 | } | |
| 216 | ||
| 217 | return ret; | |
| 218 | } | |
| 219 | ||
| 220 | short gaim_network_get_port_from_fd(int fd) | |
| 221 | { | |
| 222 | struct sockaddr_in addr; | |
| 223 | socklen_t len; | |
| 224 | ||
| 225 | g_return_val_if_fail(fd > 0, 0); | |
| 226 | ||
| 227 | len = sizeof(addr); | |
| 228 | if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) { | |
| 229 | gaim_debug_warning("network", "getsockname: %s\n", strerror(errno)); | |
| 230 | return 0; | |
| 231 | } | |
| 232 | ||
| 233 | return ntohs(addr.sin_port); | |
| 234 | } | |
| 235 | ||
| 236 | void | |
| 237 | gaim_network_init(void) | |
| 238 | { | |
| 239 | gaim_prefs_add_none ("/core/network"); | |
| 240 | gaim_prefs_add_bool ("/core/network/auto_ip", TRUE); | |
| 241 | gaim_prefs_add_string("/core/network/public_ip", ""); | |
| 242 | gaim_prefs_add_bool ("/core/network/ports_range_use", FALSE); | |
| 243 | gaim_prefs_add_int ("/core/network/ports_range_start", 1024); | |
| 244 | gaim_prefs_add_int ("/core/network/ports_range_end", 2048); | |
| 245 | } |