src/network.c

changeset 8231
347c8992c445
child 8239
d19f1c66720c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/network.c	Thu Feb 12 00:36:55 2004 +0000
@@ -0,0 +1,244 @@
+/**
+ * @file network.c Network Implementation
+ * @ingroup core
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+
+#include "debug.h"
+#include "account.h"
+#include "network.h"
+#include "prefs.h"
+
+void
+gaim_network_set_local_ip(const char *ip)
+{
+	g_return_if_fail(ip != NULL);
+
+	gaim_prefs_set_string("/core/network/public_ip", ip);
+}
+
+const char *
+gaim_network_get_local_ip(void)
+{
+	const char *ip;
+
+	if (gaim_prefs_get_bool("/core/network/auto_ip"))
+		return NULL;
+
+	ip = gaim_prefs_get_string("/core/network/public_ip");
+
+	if (ip == NULL || *ip == '\0')
+		return NULL;
+
+	return ip;
+}
+
+static const char *
+gaim_network_get_local_ip_from_fd(int fd)
+{
+	struct sockaddr_in addr;
+	socklen_t len;
+	static char ip[16];
+	const char *tmp;
+
+	g_return_val_if_fail(fd > 0, NULL);
+
+	len = sizeof(addr);
+	if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) {
+		gaim_debug_warning("network", "getsockname: %s\n", strerror(errno));
+		return NULL;
+	}
+
+	tmp = inet_ntoa(addr.sin_addr);
+	strncpy(ip, tmp, sizeof(ip));
+	return ip;
+}
+
+const char *
+gaim_network_get_local_system_ip(int fd)
+{
+	struct hostent *host;
+	char localhost[129];
+	long unsigned add;
+	static char ip[46];
+	const char *tmp = NULL;
+
+	if (fd != -1)
+		tmp = gaim_network_get_local_ip_from_fd(fd);
+
+	if (tmp)
+		return tmp;
+
+	if (gethostname(localhost, 128) < 0)
+		return NULL;
+
+	if ((host = gethostbyname(localhost)) == NULL)
+		return NULL;
+
+	memcpy(&add, host->h_addr_list[0], 4);
+	add = htonl(add);
+
+	g_snprintf(ip, 16, "%lu.%lu.%lu.%lu",
+			   ((add >> 24) & 255),
+			   ((add >> 16) & 255),
+			   ((add >>  8) & 255),
+			   add & 255);
+
+	return ip;
+}
+
+const char *
+gaim_network_get_ip_for_account(const GaimAccount *account, int fd)
+{
+	if (account && (gaim_account_get_public_ip(account) != NULL))
+		return gaim_account_get_public_ip(account);
+	else if (gaim_network_get_local_ip() != NULL)
+		return gaim_network_get_local_ip();
+	else
+		return gaim_network_get_local_system_ip(fd);
+}
+
+static int gaim_network_do_listen(short portnum)
+{
+#if HAVE_GETADDRINFO
+	int listenfd;
+	const int on = 1;
+	struct addrinfo hints, *res, *ressave;
+	char serv[5];
+
+	snprintf(serv, sizeof(serv), "%d", portnum);
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_flags = AI_PASSIVE;
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	if (getaddrinfo(NULL /* any IP */, serv, &hints, &res) != 0) {
+		gaim_debug_warning("network", "getaddrinfo: %s\n", strerror(errno));
+		return -1;
+	}
+	ressave = res;
+	do {
+		listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+		if (listenfd < 0)
+			continue;
+		setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+		if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
+			break; /* success */
+		close(listenfd);
+	} while ( (res = res->ai_next) );
+
+	if (!res)
+		return -1;
+
+	freeaddrinfo(ressave);
+#else
+	int listenfd;
+	const int on = 1;
+	struct sockaddr_in sockin;
+
+	if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		gaim_debug_warning("network", "socket: %s\n", strerror(errno));
+		return -1;
+	}
+
+	if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0) {
+		gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno));
+		close(listenfd);
+		return -1;
+	}
+
+	memset(&sockin, 0, sizeof(struct sockaddr_in));
+	sockin.sin_family = AF_INET;
+	sockin.sin_port = htons(portnum);
+
+	if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) {
+		gaim_debug_warning("network", "bind: %s\n", strerror(errno));
+		close(listenfd);
+		return -1;
+	}
+#endif
+
+	if (listen(listenfd, 4) != 0) {
+		gaim_debug_warning("network", "listen: %s\n", strerror(errno));
+		close(listenfd);
+		return -1;
+	}
+	fcntl(listenfd, F_SETFL, O_NONBLOCK);
+
+	gaim_debug_info("network", "Listening on port: %hu\n", gaim_network_get_port_from_fd(listenfd));
+	return listenfd;
+}
+
+int gaim_network_listen(short portnum)
+{
+	int ret = 0, start, end;
+
+	if (!gaim_prefs_get_bool("/core/network/ports_range_use") || portnum)
+		return gaim_network_do_listen(portnum);
+
+	start = gaim_prefs_get_int("/core/network/ports_range_start");
+	end = gaim_prefs_get_int("/core/network/ports_range_end");
+
+	for (; start <= end; start++) {
+		ret = gaim_network_do_listen(start);
+		if (ret >= 0)
+			break;
+	}
+
+	return ret;
+}
+
+short gaim_network_get_port_from_fd(int fd)
+{
+	struct sockaddr_in addr;
+	socklen_t len;
+
+	g_return_val_if_fail(fd > 0, 0);
+
+	len = sizeof(addr);
+	if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) {
+		gaim_debug_warning("network", "getsockname: %s\n", strerror(errno));
+		return 0;
+	}
+
+	return ntohs(addr.sin_port);
+}
+
+void
+gaim_network_init(void)
+{
+	gaim_prefs_add_none  ("/core/network");
+	gaim_prefs_add_bool  ("/core/network/auto_ip", TRUE);
+	gaim_prefs_add_string("/core/network/public_ip", "");
+	gaim_prefs_add_bool  ("/core/network/ports_range_use", FALSE);
+	gaim_prefs_add_int   ("/core/network/ports_range_start", 1024);
+	gaim_prefs_add_int   ("/core/network/ports_range_end", 2048);
+}

mercurial