configure: add stuff for spell checking
[rofl0r-ixchat.git] / src / common / network.c
blob0def86641bcd6c49f5622c0317131045b50119bf
1 /* X-Chat
2 * Copyright (C) 2001 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 /* ipv4 and ipv6 networking functions with a common interface */
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <glib.h>
27 #define WANTSOCKET
28 #define WANTARPA
29 #define WANTDNS
30 #include "inet.h"
32 #define NETWORK_PRIVATE
33 #include "network.h"
35 #define RAND_INT(n) ((int)(rand() / (RAND_MAX + 1.0) * (n)))
38 /* ================== COMMON ================= */
40 static void
41 net_set_socket_options (int sok)
43 socklen_t sw;
45 sw = 1;
46 setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &sw, sizeof (sw));
47 sw = 1;
48 setsockopt (sok, SOL_SOCKET, SO_KEEPALIVE, (char *) &sw, sizeof (sw));
51 char *
52 net_ip (guint32 addr)
54 struct in_addr ia;
56 ia.s_addr = htonl (addr);
57 return inet_ntoa (ia);
60 void
61 net_store_destroy (netstore * ns)
63 #ifdef USE_IPV6
64 if (ns->ip6_hostent)
65 freeaddrinfo (ns->ip6_hostent);
66 #endif
67 free (ns);
70 netstore *
71 net_store_new (void)
73 netstore *ns;
75 ns = malloc (sizeof (netstore));
76 memset (ns, 0, sizeof (netstore));
78 return ns;
81 #ifndef USE_IPV6
83 /* =================== IPV4 ================== */
86 A note about net_resolve and lookupd:
88 Many IRC networks rely on round-robin DNS for load balancing, rotating the list
89 of IP address on each query. However, this method breaks when DNS queries are
90 cached. Mac OS X and Darwin handle DNS lookups through the lookupd daemon, which
91 caches queries in its default configuration: thus, if we always pick the first
92 address, we will be stuck with the same host (which might be down!) until the
93 TTL reaches 0 or lookupd is reset (typically, at reboot). Therefore, we need to
94 pick a random address from the result list, instead of always using the first.
97 char *
98 net_resolve (netstore * ns, char *hostname, int port, char **real_host)
100 ns->ip4_hostent = gethostbyname (hostname);
101 if (!ns->ip4_hostent)
102 return NULL;
104 memset (&ns->addr, 0, sizeof (ns->addr));
105 #ifdef LOOKUPD
106 int count = 0;
107 while (ns->ip4_hostent->h_addr_list[count]) count++;
108 memcpy (&ns->addr.sin_addr,
109 ns->ip4_hostent->h_addr_list[RAND_INT(count)],
110 ns->ip4_hostent->h_length);
111 #else
112 memcpy (&ns->addr.sin_addr, ns->ip4_hostent->h_addr,
113 ns->ip4_hostent->h_length);
114 #endif
115 ns->addr.sin_port = htons (port);
116 ns->addr.sin_family = AF_INET;
118 *real_host = strdup (ns->ip4_hostent->h_name);
119 return strdup (inet_ntoa (ns->addr.sin_addr));
123 net_connect (netstore * ns, int sok4, int sok6, int *sok_return)
125 *sok_return = sok4;
126 return connect (sok4, (struct sockaddr *) &ns->addr, sizeof (ns->addr));
129 void
130 net_bind (netstore * tobindto, int sok4, int sok6)
132 bind (sok4, (struct sockaddr *) &tobindto->addr, sizeof (tobindto->addr));
135 void
136 net_sockets (int *sok4, int *sok6)
138 *sok4 = socket (AF_INET, SOCK_STREAM, 0);
139 *sok6 = -1;
140 net_set_socket_options (*sok4);
143 void
144 udp_sockets (int *sok4, int *sok6)
146 *sok4 = socket (AF_INET, SOCK_DGRAM, 0);
147 *sok6 = -1;
150 void
151 net_store_fill_any (netstore *ns)
153 ns->addr.sin_family = AF_INET;
154 ns->addr.sin_addr.s_addr = INADDR_ANY;
155 ns->addr.sin_port = 0;
158 void
159 net_store_fill_v4 (netstore *ns, guint32 addr, int port)
161 ns->addr.sin_family = AF_INET;
162 ns->addr.sin_addr.s_addr = addr;
163 ns->addr.sin_port = port;
166 guint32
167 net_getsockaddr_v4 (netstore *ns)
169 return ns->addr.sin_addr.s_addr;
173 net_getsockport (int sok4, int sok6)
175 struct sockaddr_in addr;
176 int len = sizeof (addr);
178 if (getsockname (sok4, (struct sockaddr *)&addr, &len) == -1)
179 return -1;
180 return addr.sin_port;
183 #else
185 /* =================== IPV6 ================== */
187 char *
188 net_resolve (netstore * ns, char *hostname, int port, char **real_host)
190 struct addrinfo hints;
191 char ipstring[MAX_HOSTNAME];
192 char portstring[MAX_HOSTNAME];
193 int ret;
195 /* if (ns->ip6_hostent)
196 freeaddrinfo (ns->ip6_hostent);*/
198 sprintf (portstring, "%d", port);
200 memset (&hints, 0, sizeof (struct addrinfo));
201 hints.ai_family = PF_UNSPEC; /* support ipv6 and ipv4 */
202 hints.ai_flags = AI_CANONNAME;
203 hints.ai_socktype = SOCK_STREAM;
205 if (port == 0)
206 ret = getaddrinfo (hostname, NULL, &hints, &ns->ip6_hostent);
207 else
208 ret = getaddrinfo (hostname, portstring, &hints, &ns->ip6_hostent);
209 if (ret != 0)
210 return NULL;
212 #ifdef LOOKUPD /* See note about lookupd above the IPv4 version of net_resolve. */
213 struct addrinfo *tmp;
214 int count = 0;
216 for (tmp = ns->ip6_hostent; tmp; tmp = tmp->ai_next)
217 count ++;
219 count = RAND_INT(count);
221 while (count--) ns->ip6_hostent = ns->ip6_hostent->ai_next;
222 #endif
224 /* find the numeric IP number */
225 ipstring[0] = 0;
226 getnameinfo (ns->ip6_hostent->ai_addr, ns->ip6_hostent->ai_addrlen,
227 ipstring, sizeof (ipstring), NULL, 0, NI_NUMERICHOST);
229 if (ns->ip6_hostent->ai_canonname)
230 *real_host = strdup (ns->ip6_hostent->ai_canonname);
231 else
232 *real_host = strdup (hostname);
234 return strdup (ipstring);
237 /* the only thing making this interface unclean, this shitty sok4, sok6 business */
240 net_connect (netstore * ns, int sok4, int sok6, int *sok_return)
242 struct addrinfo *res, *res0;
243 int error = -1;
245 res0 = ns->ip6_hostent;
247 for (res = res0; res; res = res->ai_next)
249 /* sok = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
250 if (sok < 0)
251 continue;*/
252 switch (res->ai_family)
254 case AF_INET:
255 error = connect (sok4, res->ai_addr, res->ai_addrlen);
256 *sok_return = sok4;
257 break;
258 case AF_INET6:
259 error = connect (sok6, res->ai_addr, res->ai_addrlen);
260 *sok_return = sok6;
261 break;
262 default:
263 error = 1;
266 if (error == 0)
267 break;
270 return error;
273 void
274 net_bind (netstore * tobindto, int sok4, int sok6)
276 bind (sok4, tobindto->ip6_hostent->ai_addr,
277 tobindto->ip6_hostent->ai_addrlen);
278 bind (sok6, tobindto->ip6_hostent->ai_addr,
279 tobindto->ip6_hostent->ai_addrlen);
282 void
283 net_sockets (int *sok4, int *sok6)
285 *sok4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
286 *sok6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
287 net_set_socket_options (*sok4);
288 net_set_socket_options (*sok6);
291 void
292 udp_sockets (int *sok4, int *sok6)
294 *sok4 = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
295 *sok6 = socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
298 /* the following functions are used only by MSPROXY and are not
299 proper ipv6 implementations - do not use in new code! */
301 void
302 net_store_fill_any (netstore *ns)
304 struct addrinfo *ai;
305 struct sockaddr_in *sin;
307 ai = ns->ip6_hostent;
308 if (!ai) {
309 ai = malloc (sizeof (struct addrinfo));
310 memset (ai, 0, sizeof (struct addrinfo));
311 ns->ip6_hostent = ai;
313 sin = (struct sockaddr_in *)ai->ai_addr;
314 if (!sin) {
315 sin = malloc (sizeof (struct sockaddr_in));
316 memset (sin, 0, sizeof (struct sockaddr_in));
317 ai->ai_addr = (struct sockaddr *)sin;
319 ai->ai_family = AF_INET;
320 ai->ai_addrlen = sizeof(struct sockaddr_in);
321 sin->sin_family = AF_INET;
322 sin->sin_addr.s_addr = INADDR_ANY;
323 sin->sin_port = 0;
324 ai->ai_next = NULL;
327 void
328 net_store_fill_v4 (netstore *ns, guint32 addr, int port)
330 struct addrinfo *ai;
331 struct sockaddr_in *sin;
333 ai = ns->ip6_hostent;
334 if (!ai) {
335 ai = malloc (sizeof (struct addrinfo));
336 memset (ai, 0, sizeof (struct addrinfo));
337 ns->ip6_hostent = ai;
339 sin = (struct sockaddr_in *)ai->ai_addr;
340 if (!sin) {
341 sin = malloc (sizeof (struct sockaddr_in));
342 memset (sin, 0, sizeof (struct sockaddr_in));
343 ai->ai_addr = (struct sockaddr *)sin;
345 ai->ai_family = AF_INET;
346 ai->ai_addrlen = sizeof(struct sockaddr_in);
347 sin->sin_family = AF_INET;
348 sin->sin_addr.s_addr = addr;
349 sin->sin_port = port;
350 ai->ai_next = NULL;
353 guint32
354 net_getsockaddr_v4 (netstore *ns)
356 struct addrinfo *ai;
357 struct sockaddr_in *sin;
359 ai = ns->ip6_hostent;
361 while (ai->ai_family != AF_INET) {
362 ai = ai->ai_next;
363 if (!ai)
364 return 0;
366 sin = (struct sockaddr_in *)ai->ai_addr;
367 return sin->sin_addr.s_addr;
371 net_getsockport (int sok4, int sok6)
373 struct sockaddr_in addr;
374 int len = sizeof (addr);
376 if (getsockname (sok4, (struct sockaddr *)&addr, &len) == -1)
377 return -1;
378 return addr.sin_port;
381 #endif