From c5fbc0b0d3d334a0d63cc09652f194c8dac2a121 Mon Sep 17 00:00:00 2001
From: "Leigh B. Stoller" <stoller@flux.utah.edu>
Date: Tue, 3 Sep 2002 17:12:56 +0000
Subject: [PATCH] An utterly ridiculous hack for listening on an alternate
 socket, for the benefit of remote firewalled machines. Needs to be
 generalized, although with care to avoid select storms (which is why I did it
 this stupid way).

---
 tmcd/tmcd.c | 227 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 136 insertions(+), 91 deletions(-)

diff --git a/tmcd/tmcd.c b/tmcd/tmcd.c
index cc889a2b67..af45af5ad2 100644
--- a/tmcd/tmcd.c
+++ b/tmcd/tmcd.c
@@ -57,7 +57,6 @@
 
 int		debug = 0;
 static int	insecure = 0;
-static int	portnum = TBSERVER_PORT;
 static char     dbname[DBNAME_SIZE];
 static struct in_addr myipaddr;
 static char	fshostid[HOSTID_SIZE];
@@ -70,15 +69,16 @@ static int	checkprivkey(struct in_addr, char *);
 static void	tcpserver(int sock);
 static void	udpserver(int sock);
 static int      handle_request(int, struct sockaddr_in *, char *, int);
+static int	makesockets(int portnum, int *udpsockp, int *tcpsockp);
 int		client_writeback(int sock, void *buf, int len, int tcp);
 void		client_writeback_done(int sock, struct sockaddr_in *client);
 MYSQL_RES *	mydb_query(char *query, int ncols, ...);
 int		mydb_update(char *query, ...);
+static int	safesymlink(char *name1, char *name2);
 
 /* thread support */
 #define MAXCHILDREN	25
 #define MINCHILDREN	5
-static int	udpchild;
 static int	numchildren;
 static int	maxchildren = 15;
 static volatile int killme;
@@ -196,9 +196,10 @@ cleanup()
 int
 main(int argc, char **argv)
 {
-	int			tcpsock, udpsock, ch;
-	int			length, i, status, pid;
-	struct sockaddr_in	name;
+	int			tcpsock, udpsock, i, ch, foo[4];
+	int			alttcpsock, altudpsock;
+	int			status, pid;
+	int			portnum = TBSERVER_PORT;
 	FILE			*fp;
 	char			buf[BUFSIZ];
 	struct hostent		*he;
@@ -290,6 +291,102 @@ main(int argc, char **argv)
 	}
 	memcpy((char *)&myipaddr, he->h_addr, he->h_length);
 
+	if (makesockets(portnum, &udpsock, &tcpsock) < 0 ||
+	    makesockets(TBSERVER_PORT2, &altudpsock, &alttcpsock) < 0) {
+		error("Could not make sockets!");
+		exit(1);
+	}
+
+	signal(SIGTERM, cleanup);
+	signal(SIGINT, cleanup);
+	signal(SIGHUP, cleanup);
+
+	/*
+	 * Stash the pid away.
+	 */
+	sprintf(buf, "%s/tmcd.pid", _PATH_VARRUN);
+	fp = fopen(buf, "w");
+	if (fp != NULL) {
+		fprintf(fp, "%d\n", getpid());
+		(void) fclose(fp);
+	}
+
+	/*
+	 * Now fork a set of children to handle requests. We keep the
+	 * pool at a set level. No need to get too fancy at this point,
+	 * although this approach *is* rather bogus. 
+	 */
+	bzero(foo, sizeof(foo));
+	while (1) {
+		while (!killme && numchildren < maxchildren) {
+			int which = 0;
+			if (!foo[1])
+				which = 1;
+			else if (! foo[2])
+				which = 2;
+			else if (! foo[3])
+				which = 3;
+			
+			if ((pid = fork()) < 0) {
+				errorc("forking server");
+				goto done;
+			}
+			if (pid) {
+				foo[which] = pid;
+				numchildren++;
+				continue;
+			}
+			/* Child does useful work! Never Returns! */
+			signal(SIGTERM, SIG_DFL);
+			signal(SIGINT, SIG_DFL);
+			signal(SIGHUP, SIG_DFL);
+			
+			switch (which) {
+			case 0: tcpserver(tcpsock);
+				break;
+			case 1: udpserver(udpsock);
+				break;
+			case 2: udpserver(altudpsock);
+				break;
+			case 3: tcpserver(alttcpsock);
+				break;
+			}
+			exit(-1);
+		}
+
+		/*
+		 * Parent waits.
+		 */
+		pid = waitpid(-1, &status, 0);
+		if (pid < 0) {
+			errorc("waitpid failed");
+			continue;
+		}
+		error("server %d exited with status 0x%x!\n", pid, status);
+		numchildren--;
+		for (i = 0; i < (sizeof(foo)/sizeof(int)); i++) {
+			if (foo[i] == pid)
+				foo[i] = 0;
+		}
+		if (killme && !numchildren)
+			break;
+	}
+ done:
+	CLOSE(tcpsock);
+	close(udpsock);
+	info("daemon terminating\n");
+	exit(0);
+}
+
+/*
+ * Create sockets on specified port.
+ */
+static int
+makesockets(int portnum, int *udpsockp, int *tcpsockp)
+{
+	struct sockaddr_in	name;
+	int			length, i, udpsock, tcpsock;
+
 	/*
 	 * Setup TCP socket for incoming connections.
 	 */
@@ -352,69 +449,9 @@ main(int argc, char **argv)
 	}
 	info("listening on UDP port %d\n", ntohs(name.sin_port));
 
-	signal(SIGTERM, cleanup);
-	signal(SIGINT, cleanup);
-	signal(SIGHUP, cleanup);
-
-	/*
-	 * Stash the pid away.
-	 */
-	sprintf(buf, "%s/tmcd.pid", _PATH_VARRUN);
-	fp = fopen(buf, "w");
-	if (fp != NULL) {
-		fprintf(fp, "%d\n", getpid());
-		(void) fclose(fp);
-	}
-
-	/*
-	 * Now fork a set of children to handle requests. We keep the
-	 * pool at a set level. No need to get too fancy at this point. 
-	 */
-	while (1) {
-		while (!killme && numchildren < maxchildren) {
-			int doudp = (udpchild ? 0 : 1);
-			if ((pid = fork()) < 0) {
-				errorc("forking server");
-				goto done;
-			}
-			if (pid) {
-				if (doudp)
-					udpchild = pid;
-				numchildren++;
-				continue;
-			}
-			/* Child does useful work! Never Returns! */
-			signal(SIGTERM, SIG_DFL);
-			signal(SIGINT, SIG_DFL);
-			signal(SIGHUP, SIG_DFL);
-			
-			if (doudp) 
-				udpserver(udpsock);
-			else
-				tcpserver(tcpsock);
-			exit(-1);
-		}
-
-		/*
-		 * Parent waits.
-		 */
-		pid = waitpid(-1, &status, 0);
-		if (pid < 0) {
-			errorc("waitpid failed");
-			continue;
-		}
-		error("server %d exited with status 0x%x!\n", pid, status);
-		numchildren--;
-		if (pid == udpchild)
-			udpchild = 0;
-		if (killme && !numchildren)
-			break;
-	}
- done:
-	CLOSE(tcpsock);
-	close(udpsock);
-	info("daemon terminating\n");
-	exit(0);
+	*tcpsockp = tcpsock;
+	*udpsockp = udpsock;
+	return 0;
 }
 
 /*
@@ -428,14 +465,14 @@ udpserver(int sock)
 	struct sockaddr_in	client;
 	int			length, cc;
 	
-	info("udpserver starting\n");
+	info("udpserver starting: pid=%d sock=%d\n", getpid(), sock);
 
 	/*
 	 * Wait for udp connections.
 	 */
 	while (1) {
 		length = sizeof(client);		
-		cc = recvfrom(sock, buf, MYBUFSIZE - 1,
+		cc = recvfrom(sock, buf, sizeof(buf) - 1,
 			      0, (struct sockaddr *)&client, &length);
 		if (cc <= 0) {
 			if (cc < 0)
@@ -459,7 +496,7 @@ tcpserver(int sock)
 	struct sockaddr_in	client;
 	int			length, cc, newsock;
 	
-	info("tcpserver starting\n");
+	info("tcpserver starting: pid=%d sock=%d\n", getpid(), sock);
 
 	/*
 	 * Wait for TCP connections.
@@ -475,7 +512,7 @@ tcpserver(int sock)
 		/*
 		 * Read in the command request.
 		 */
-		if ((cc = READ(newsock, buf, MYBUFSIZE - 1)) <= 0) {
+		if ((cc = READ(newsock, buf, sizeof(buf) - 1)) <= 0) {
 			if (cc < 0)
 				errorc("Reading TCP request");
 			error("TCP connection aborted\n");
@@ -2289,6 +2326,32 @@ dosfshostiddead()
 	longjmp(sfshostiddeadline, 1);
 }
 
+static int
+safesymlink(char *name1, char *name2)
+{
+	/*
+	 * Really, there should be a cleaner way of doing this, but
+	 * this works, at least for now.  Perhaps using the DB and a
+	 * symlinking deamon alone would be better.
+	 */
+	if (setjmp(sfshostiddeadline) == 0) {
+		sfshostiddeadfl = 0;
+		signal(SIGALRM, dosfshostiddead);
+		alarm(1);
+
+		unlink(name2);
+		if (symlink(name1, name2) < 0) {
+			sfshostiddeadfl = 1;
+		}
+	}
+	alarm(0);
+	if (sfshostiddeadfl) {
+		errorc("symlinking %s to %s", name2, name1);
+		return -1;
+	}
+	return 0;
+}
+
 /*
  * Create dirsearch entry for node.
  */
@@ -2329,27 +2392,9 @@ COMMAND_PROTOTYPE(dosfshostid)
 	// sprintf(dspath, "/proj/%s/.sfs/%s/%s", pid, eid, nickname);
 	sprintf(dspath, "/proj/.sfs/%s.%s.%s", nickname, eid, pid);
 	
-	/*
-	 * Really, there should be a cleaner way of doing this, but
-	 * this works, at least for now.  Perhaps using the DB and a
-	 * symlinking deamon alone would be better.
-	 */
-	if (setjmp(sfshostiddeadline) == 0) {
-		sfshostiddeadfl = 0;
-		signal(SIGALRM, dosfshostiddead);
-		alarm(1);
-
-		unlink(dspath);
-		if (symlink(sfspath, dspath) < 0) {
-			sfshostiddeadfl = 1;
-		}
-	}
-	alarm(0);
-	if (sfshostiddeadfl) {
-		errorc("symlinking %s to %s", dspath, sfspath);
+	if (safesymlink(sfspath, dspath) < 0) {
 		return 1;
 	}
-
 	return 0;
 }
 
-- 
GitLab