changeset 10711:00483ba950bf

[gaim-migrate @ 12301] Add some comments to the proxy code, rename some functions, and shuffle things around in a way that I think makes it much more readable. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Mon, 21 Mar 2005 02:14:46 +0000
parents a2c0ce632bec
children b41c48d890d8
files src/proxy.c
diffstat 1 files changed, 254 insertions(+), 208 deletions(-) [+]
line wrap: on
line diff
--- a/src/proxy.c	Mon Mar 21 02:12:51 2005 +0000
+++ b/src/proxy.c	Mon Mar 21 02:14:46 2005 +0000
@@ -191,8 +191,9 @@
 
 #ifdef __unix__ 
 
-/*  This structure represents both a pending DNS request and
- *  a free child process.
+/*
+ * This structure represents both a pending DNS request and
+ * a free child process.
  */
 typedef struct {
 	char *host;
@@ -222,7 +223,238 @@
 	gpointer data;
 } queued_dns_request_t;
 
-static void req_free(pending_dns_request_t *req)
+/*
+ * Begin the DNS resolver child process functions.
+ */
+#ifdef HAVE_SIGNAL_H
+static void
+trap_gdb_bug()
+{
+	const char *message =
+		"Gaim's DNS child got a SIGTRAP signal. \n"
+		"This can be caused by trying to run gaim inside gdb.\n"
+		"There is a known gdb bug which prevents this.  Supposedly gaim\n"
+		"should have detected you were using gdb and used an ugly hack,\n"
+		"check cope_with_gdb_brokenness() in proxy.c.\n\n"
+		"For more info about this bug, see http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n";
+	fputs("\n* * *\n",stderr);
+	fputs(message,stderr);
+	fputs("* * *\n\n",stderr);
+	execlp("xmessage","xmessage","-center", message, NULL);
+	_exit(1);
+}
+#endif
+
+static void
+cope_with_gdb_brokenness()
+{
+#ifdef __linux__
+	static gboolean already_done = FALSE;
+	char s[256], e[512];
+	int n;
+	pid_t ppid;
+
+	if(already_done)
+		return;
+	already_done = TRUE;
+	ppid = getppid();
+	snprintf(s, sizeof(s), "/proc/%d/exe", ppid);
+	n = readlink(s, e, sizeof(e));
+	if(n < 0)
+		return;
+
+	e[MIN(n,sizeof(e)-1)] = '\0';
+
+	if(strstr(e,"gdb")) {
+		gaim_debug_info("dns",
+				   "Debugger detected, performing useless query...\n");
+		gethostbyname("x.x.x.x.x");
+	}
+#endif
+}
+
+static void
+gaim_dns_resolverthread(int child_out, int child_in, gboolean show_debug)
+{
+	dns_params_t dns_params;
+	const size_t zero = 0;
+	int rc;
+#if HAVE_GETADDRINFO
+	struct addrinfo hints, *res, *tmp;
+	char servname[20];
+#else
+	struct sockaddr_in sin;
+	const size_t addrlen = sizeof(sin);
+#endif
+
+#ifdef HAVE_SIGNAL_H
+	signal(SIGHUP, SIG_DFL);
+	signal(SIGINT, SIG_DFL);
+	signal(SIGQUIT, SIG_DFL);
+	signal(SIGCHLD, SIG_DFL);
+	signal(SIGTERM, SIG_DFL);
+	signal(SIGTRAP, trap_gdb_bug);
+#endif
+
+	/*
+	 * We resolve 1 host name for each iteration of this
+	 * while loop.
+	 *
+	 * The top half of this reads in the hostname and port
+	 * number from the socket with our parent.  The bottom
+	 * half of this resolves the IP (blocking) and sends
+	 * the result back to our parent, when finished.
+	 */
+	while (1) {
+		const char ch = 'Y';
+		fd_set fds;
+		struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 };
+		FD_ZERO(&fds);
+		FD_SET(child_in, &fds);
+		rc = select(child_in + 1, &fds, NULL, NULL, &tv);
+		if (!rc) {
+			if (show_debug)
+				fprintf(stderr,"dns[%d]: nobody needs me... =(\n", getpid());
+			break;
+		}
+		rc = read(child_in, &dns_params, sizeof(dns_params_t));
+		if (rc < 0) {
+			perror("read()");
+			break;
+		}
+		if (rc == 0) {
+			if (show_debug)
+				fprintf(stderr,"dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid());
+			_exit(0);
+		}
+		if (dns_params.hostname[0] == '\0') {
+			fprintf(stderr, "dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params.port);
+			_exit(1);
+		}
+		/* Tell our parent that we read the data successfully */
+		write(child_out, &ch, sizeof(ch));
+
+		/* We have the hostname and port, now resolve the IP */
+
+#if HAVE_GETADDRINFO
+		g_snprintf(servname, sizeof(servname), "%d", dns_params.port);
+		memset(&hints, 0, sizeof(hints));
+
+		/* This is only used to convert a service
+		 * name to a port number. As we know we are
+		 * passing a number already, we know this
+		 * value will not be really used by the C
+		 * library.
+		 */
+		hints.ai_socktype = SOCK_STREAM;
+		rc = getaddrinfo(dns_params.hostname, servname, &hints, &res);
+		write(child_out, &rc, sizeof(rc));
+		if (rc != 0) {
+			close(child_out);
+			if (show_debug)
+				fprintf(stderr,"dns[%d] Error: getaddrinfo returned %d\n",
+					getpid(), rc);
+			dns_params.hostname[0] = '\0';
+			continue;
+		}
+		tmp = res;
+		while (res) {
+			size_t ai_addrlen = res->ai_addrlen;
+			write(child_out, &ai_addrlen, sizeof(ai_addrlen));
+			write(child_out, res->ai_addr, res->ai_addrlen);
+			res = res->ai_next;
+		}
+		freeaddrinfo(tmp);
+		write(child_out, &zero, sizeof(zero));
+#else
+		if (!inet_aton(dns_params.hostname, &sin.sin_addr)) {
+			struct hostent *hp;
+			if (!(hp = gethostbyname(dns_params.hostname))) {
+				write(child_out, &h_errno, sizeof(int));
+				close(child_out);
+				if (show_debug)
+					fprintf(stderr,"DNS Error: %d\n", h_errno);
+				_exit(0);
+			}
+			memset(&sin, 0, sizeof(struct sockaddr_in));
+			memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
+			sin.sin_family = hp->h_addrtype;
+		} else
+			sin.sin_family = AF_INET;
+
+		sin.sin_port = htons(dns_params.port);
+		write(child_out, &addrlen, sizeof(addrlen));
+		write(child_out, &sin, addrlen);
+		write(child_out, &zero, sizeof(zero));
+#endif
+		dns_params.hostname[0] = '\0';
+	}
+
+	close(child_out);
+	close(child_in);
+
+	_exit(0);
+}
+
+static pending_dns_request_t *
+gaim_dns_new_resolverthread(gboolean show_debug)
+{
+	pending_dns_request_t *req;
+	int child_out[2], child_in[2];
+
+	/* Create pipes for communicating with the child process */
+	if (pipe(child_out) || pipe(child_in)) {
+		gaim_debug_error("dns",
+				   "Could not create pipes: %s\n", strerror(errno));
+		return NULL;
+	}
+
+	req = g_new(pending_dns_request_t, 1);
+
+	cope_with_gdb_brokenness();
+
+	/* Fork! */
+	req->dns_pid = fork();
+
+	/* If we are the child process... */
+	if (req->dns_pid == 0) {
+		/* We should not access the parent's side of the pipes, so close them */
+		close(child_out[0]);
+		close(child_in[1]);
+
+		gaim_dns_resolverthread(child_out[1], child_in[0], show_debug);
+		/* The thread calls _exit() rather than returning, so we never get here */
+	}
+
+	/* We should not access the child's side of the pipes, so close them */
+	close(child_out[1]);
+	close(child_in[0]);
+	if (req->dns_pid == -1) {
+		gaim_debug_error("dns",
+				   "Could not create child process for DNS: %s\n",
+				   strerror(errno));
+		g_free(req);
+		return NULL;
+	}
+
+	req->fd_out = child_out[0];
+	req->fd_in = child_in[1];
+	number_of_dns_children++;
+	gaim_debug_info("dns",
+			   "Created new DNS child %d, there are now %d children.\n",
+			   req->dns_pid, number_of_dns_children);
+
+	return req;
+}
+/*
+ * End the DNS resolver child process functions.
+ */
+
+/*
+ * Begin the functions for dealing with the DNS child processes.
+ */
+static void
+req_free(pending_dns_request_t *req)
 {
 	g_return_if_fail(req != NULL);
 
@@ -235,7 +467,8 @@
 	number_of_dns_children--;
 }
 
-static int send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params)
+static int
+send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params)
 {
 	char ch;
 	int rc;
@@ -276,9 +509,11 @@
 	return 0;
 }
 
-static void host_resolved(gpointer data, gint source, GaimInputCondition cond);
+static void
+host_resolved(gpointer data, gint source, GaimInputCondition cond);
 
-static void release_dns_child(pending_dns_request_t *req)
+static void
+release_dns_child(pending_dns_request_t *req)
 {
 	g_free(req->host);
 	req->host = NULL;
@@ -315,7 +550,8 @@
 	}
 }
 
-static void host_resolved(gpointer data, gint source, GaimInputCondition cond)
+static void
+host_resolved(gpointer data, gint source, GaimInputCondition cond)
 {
 	pending_dns_request_t *req = (pending_dns_request_t*)data;
 	int rc, err;
@@ -378,163 +614,12 @@
 
 	release_dns_child(req);
 }
-
-static void trap_gdb_bug()
-{
-	const char *message =
-		"Gaim's DNS child got a SIGTRAP signal. \n"
-		"This can be caused by trying to run gaim inside gdb.\n"
-		"There is a known gdb bug which prevents this.  Supposedly gaim\n"
-		"should have detected you were using gdb and used an ugly hack,\n"
-		"check cope_with_gdb_brokenness() in proxy.c.\n\n"
-		"For more info about this bug, see http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n";
-	fputs("\n* * *\n",stderr);
-	fputs(message,stderr);
-	fputs("* * *\n\n",stderr);
-	execlp("xmessage","xmessage","-center", message, NULL);
-	_exit(1);
-}
-
-static void cope_with_gdb_brokenness()
-{
-#ifdef __linux__
-	static gboolean already_done = FALSE;
-	char s[256], e[512];
-	int n;
-	pid_t ppid;
-
-	if(already_done)
-		return;
-	already_done = TRUE;
-	ppid = getppid();
-	snprintf(s, sizeof(s), "/proc/%d/exe", ppid);
-	n = readlink(s, e, sizeof(e));
-	if(n < 0)
-		return;
-
-	e[MIN(n,sizeof(e)-1)] = '\0';
-
-	if(strstr(e,"gdb")) {
-		gaim_debug_info("dns",
-				   "Debugger detected, performing useless query...\n");
-		gethostbyname("x.x.x.x.x");
-	}
-#endif
-}
-
-static void
-gaim_dns_childthread(int child_out, int child_in, dns_params_t *dns_params, gboolean show_debug)
-{
-	const size_t zero = 0;
-	int rc;
-#if HAVE_GETADDRINFO
-	struct addrinfo hints, *res, *tmp;
-	char servname[20];
-#else
-	struct sockaddr_in sin;
-	const size_t addrlen = sizeof(sin);
-#endif
-
-#ifdef HAVE_SIGNAL_H
-	signal(SIGHUP, SIG_DFL);
-	signal(SIGINT, SIG_DFL);
-	signal(SIGQUIT, SIG_DFL);
-	signal(SIGCHLD, SIG_DFL);
-	signal(SIGTERM, SIG_DFL);
-	signal(SIGTRAP, trap_gdb_bug);
-#endif
+/*
+ * End the functions for dealing with the DNS child processes.
+ */
 
-	while (1) {
-		if (dns_params->hostname[0] == '\0') {
-			const char ch = 'Y';
-			fd_set fds;
-			struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 };
-			FD_ZERO(&fds);
-			FD_SET(child_in, &fds);
-			rc = select(child_in + 1, &fds, NULL, NULL, &tv);
-			if (!rc) {
-				if (show_debug)
-					fprintf(stderr,"dns[%d]: nobody needs me... =(\n", getpid());
-				break;
-			}
-			rc = read(child_in, dns_params, sizeof(dns_params_t));
-			if (rc < 0) {
-				perror("read()");
-				break;
-			}
-			if (rc == 0) {
-				if (show_debug)
-					fprintf(stderr,"dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid());
-				_exit(0);
-			}
-			if (dns_params->hostname[0] == '\0') {
-				fprintf(stderr, "dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params->port);
-				_exit(1);
-			}
-			write(child_out, &ch, sizeof(ch));
-		}
-
-#if HAVE_GETADDRINFO
-		g_snprintf(servname, sizeof(servname), "%d", dns_params->port);
-		memset(&hints, 0, sizeof(hints));
-
-		/* This is only used to convert a service
-		 * name to a port number. As we know we are
-		 * passing a number already, we know this
-		 * value will not be really used by the C
-		 * library.
-		 */
-		hints.ai_socktype = SOCK_STREAM;
-		rc = getaddrinfo(dns_params->hostname, servname, &hints, &res);
-		write(child_out, &rc, sizeof(rc));
-		if (rc != 0) {
-			close(child_out);
-			if (show_debug)
-				fprintf(stderr,"dns[%d] Error: getaddrinfo returned %d\n",
-					getpid(), rc);
-			dns_params->hostname[0] = '\0';
-			continue;
-		}
-		tmp = res;
-		while (res) {
-			size_t ai_addrlen = res->ai_addrlen;
-			write(child_out, &ai_addrlen, sizeof(ai_addrlen));
-			write(child_out, res->ai_addr, res->ai_addrlen);
-			res = res->ai_next;
-		}
-		freeaddrinfo(tmp);
-		write(child_out, &zero, sizeof(zero));
-#else
-		if (!inet_aton(dns_params->hostname, &sin.sin_addr)) {
-			struct hostent *hp;
-			if (!(hp = gethostbyname(dns_params->hostname))) {
-				write(child_out, &h_errno, sizeof(int));
-				close(child_out);
-				if (show_debug)
-					fprintf(stderr,"DNS Error: %d\n", h_errno);
-				_exit(0);
-			}
-			memset(&sin, 0, sizeof(struct sockaddr_in));
-			memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
-			sin.sin_family = hp->h_addrtype;
-		} else
-			sin.sin_family = AF_INET;
-
-		sin.sin_port = htons(dns_params->port);
-		write(child_out, &addrlen, sizeof(addrlen));
-		write(child_out, &sin, addrlen);
-		write(child_out, &zero, sizeof(zero));
-#endif
-		dns_params->hostname[0] = '\0';
-	}
-
-	close(child_out);
-	close(child_in);
-
-	_exit(0);
-}
-
-int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data)
+int
+gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data)
 {
 	pending_dns_request_t *req = NULL;
 	dns_params_t dns_params;
@@ -569,8 +654,6 @@
 
 	/* We need to create a new DNS request child */
 	if (req == NULL) {
-		int child_out[2], child_in[2];
-
 		if (number_of_dns_children >= MAX_DNS_CHILDREN) {
 			queued_dns_request_t *r = g_new(queued_dns_request_t, 1);
 			memcpy(&(r->params), &dns_params, sizeof(dns_params));
@@ -586,47 +669,8 @@
 			return 0;
 		}
 
-		/* Create pipes for communicating with the child process */
-		if (pipe(child_out) || pipe(child_in)) {
-			gaim_debug_error("dns",
-					   "Could not create pipes: %s\n", strerror(errno));
-			return -1;
-		}
-
-		req = g_new(pending_dns_request_t, 1);
-
-		cope_with_gdb_brokenness();
-
-		/* Fork! */
-		req->dns_pid = fork();
-
-		/* If we are the child process... */
-		if (req->dns_pid == 0) {
-			/* We should not access the parent's side of the pipe, so close them... */
-			close(child_out[0]);
-			close(child_in[1]);
-
-			gaim_dns_childthread(child_out[1], child_in[0], &dns_params, show_debug);
-			/* The thread calls _exit() rather than returning, so we never get here */
-		}
-
-		/* We should not access the child's side of the pipe, so close them... */
-		close(child_out[1]);
-		close(child_in[0]);
-		if (req->dns_pid == -1) {
-			gaim_debug_error("dns",
-					   "Could not create child process for DNS: %s\n",
-					   strerror(errno));
-			g_free(req);
-			return -1;
-		}
-
-		req->fd_out = child_out[0];
-		req->fd_in = child_in[1];
-		number_of_dns_children++;
-		gaim_debug_info("dns",
-				   "Created new DNS child %d, there are now %d children.\n",
-				   req->dns_pid, number_of_dns_children);
+		req = gaim_dns_new_resolverthread(show_debug);
+		send_dns_request_to_child(req, &dns_params);
 	}
 
 	req->host = g_strdup(hostname);
@@ -717,8 +761,10 @@
 	return 0;
 }
 
-int gaim_gethostbyname_async(const char *hostname, int port,
-							  dns_callback_t callback, gpointer data) {
+int
+gaim_gethostbyname_async(const char *hostname, int port,
+							  dns_callback_t callback, gpointer data)
+{
 	dns_tdata *td;
 	struct sockaddr_in sin;
 	GError* err = NULL;