src/lib/net.c 1.79

1.79 2010/03/10 23:41:17 angie
Instead of errAborting in low-level net.c routines, pass errors up to higher-level code, most of which already checks for error return values.
Index: src/lib/net.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/lib/net.c,v
retrieving revision 1.78
retrieving revision 1.79
diff -b -B -U 4 -r1.78 -r1.79
--- src/lib/net.c	18 Dec 2009 22:48:27 -0000	1.78
+++ src/lib/net.c	10 Mar 2010 23:41:17 -0000	1.79
@@ -49,9 +49,9 @@
 if ((sd = netStreamSocket()) < 0)
     return sd;
 if ((err = connect(sd, (struct sockaddr*)&sai, sizeof(sai))) < 0)
    {
-   warn("Couldn't connect to %s %d", hostName, port);
+   errnoWarn("Couldn't connect to %s %d", hostName, port);
    close(sd);
    return err;
    }
 return sd;
@@ -408,33 +408,33 @@
 	}
     }
 }
 
-void sendFtpCommandOnly(int sd, char *cmd)
+static void sendFtpCommandOnly(int sd, char *cmd)
 /* send command to ftp server */
 {   
 mustWriteFd(sd, cmd, strlen(cmd));
 }
 
 #define NET_FTP_TIMEOUT 1000000
 
-struct dyString *receiveFtpReply(int sd, char *cmd, boolean seeResult)
+static boolean receiveFtpReply(int sd, char *cmd, struct dyString **retReply)
 /* send command to ftp server and check resulting reply code, 
-   give error if not desired reply */
+ * warn and return FALSE if not desired reply.  If retReply is non-NULL, store reply text there. */
 {
-struct dyString *rs = NULL;
-int reply = 0;
-char buf[4*1024];
-int readSize;
 char *startLastLine = NULL;
-
-rs = newDyString(4*1024);
+struct dyString *rs = newDyString(4*1024);
 while (1)
     {
+    int readSize = 0;
     while (1)
 	{
+	char buf[4*1024];
 	if (!readReadyWait(sd, NET_FTP_TIMEOUT))
-	    errAbort("ftp server response timed out > %d microsec", NET_FTP_TIMEOUT);
+	    {
+	    warn("ftp server response timed out > %d microsec", NET_FTP_TIMEOUT);
+	    return FALSE;
+	    }
 	if ((readSize = read(sd, buf, sizeof(buf))) == 0)
 	    break;
 
 	dyStringAppendN(rs, buf, readSize);
@@ -461,30 +461,33 @@
 	
     if (readSize == 0)
 	break;  // EOF
     /* must be some text info we can't use, ignore it till we get status code */
-
     }
 
-reply = atoi(startLastLine);
-
+int reply = atoi(startLastLine);
 if ((reply < 200) || (reply > 399))
-    errAbort("ftp server error on cmd=[%s] response=[%s]\n",cmd,rs->string);
-    
-if (!seeResult) dyStringFree(&rs);
+    {
+    warn("ftp server error on cmd=[%s] response=[%s]\n",cmd,rs->string);
+    return FALSE;
+    }
 
-return rs;
+if (retReply)
+    *retReply = rs;
+else
+    dyStringFree(&rs);
+return TRUE;
 }
 
-struct dyString *sendFtpCommand(int sd, char *cmd, boolean seeResult)
+static boolean sendFtpCommand(int sd, char *cmd, struct dyString **retReply)
 /* send command to ftp server and check resulting reply code, 
-   give error if not desired reply */
+ * warn and return FALSE if not desired reply.  If retReply is non-NULL, store reply text there. */
 {   
 sendFtpCommandOnly(sd, cmd);
-return receiveFtpReply(sd, cmd, seeResult);
+return receiveFtpReply(sd, cmd, retReply);
 }
 
-int parsePasvPort(char *rs)
+static int parsePasvPort(char *rs)
 /* parse PASV reply to get the port and return it */
 {
 char *words[7];
 int wordCount;
@@ -500,9 +503,9 @@
 return result;
 }    
 
 
-long long parseFtpSIZE(char *rs)
+static long long parseFtpSIZE(char *rs)
 /* parse reply to SIZE and return it */
 {
 char *words[3];
 int wordCount;
@@ -515,9 +518,9 @@
 return result;
 }    
 
 
-time_t parseFtpMDTM(char *rs)
+static time_t parseFtpMDTM(char *rs)
 /* parse reply to MDTM and return it
  * 200 YYYYMMDDhhmmss */
 {
 char *words[3];
@@ -565,24 +568,39 @@
 }    
 
 
 static int openFtpControlSocket(char *host, int port, char *user, char *password)
-/* Open a socket to host,port; authenticate anonymous ftp; set type to I; return socket desc. */
+/* Open a socket to host,port; authenticate anonymous ftp; set type to I; 
+ * return socket desc or -1 if there was an error. */
 {
-int sd = netMustConnect(host, port);
+int sd = netConnect(host, port);
+if (sd < 0)
+    return -1;
 
 /* First read the welcome msg */
 if (readReadyWait(sd, NET_FTP_TIMEOUT))
-    sendFtpCommand(sd, "", FALSE);
+    sendFtpCommand(sd, "", NULL);
 
 char cmd[256];
 safef(cmd,sizeof(cmd),"USER %s\r\n", user);
-sendFtpCommand(sd, cmd, FALSE);
+if (!sendFtpCommand(sd, cmd, NULL))
+    {
+    close(sd);
+    return -1;
+    }
 
 safef(cmd,sizeof(cmd),"PASS %s\r\n", password);
-sendFtpCommand(sd, cmd, FALSE);
+if (!sendFtpCommand(sd, cmd, NULL))
+    {
+    close(sd);
+    return -1;
+    }
 
-sendFtpCommand(sd, "TYPE I\r\n", FALSE);
+if (!sendFtpCommand(sd, "TYPE I\r\n", NULL))
+    {
+    close(sd);
+    return -1;
+    }
 /* 200 Type set to I */
 /* (send the data as binary, so can support compressed files) */
 return sd;
 }
@@ -604,17 +622,28 @@
     return TRUE;
     }
 
 int sd = openFtpControlSocket(npu.host, atoi(npu.port), npu.user, npu.password);
+if (sd < 0)
+    return FALSE;
 char cmd[256];
 safef(cmd,sizeof(cmd),"SIZE %s\r\n", npu.file);
-struct dyString *rs = sendFtpCommand(sd, cmd, TRUE);
+struct dyString *rs = NULL;
+if (!sendFtpCommand(sd, cmd, &rs))
+    {
+    close(sd);
+    return FALSE;
+    }
 *retSize = parseFtpSIZE(rs->string);
 /* 200 12345 */
 dyStringFree(&rs);
 
 safef(cmd,sizeof(cmd),"MDTM %s\r\n", npu.file);
-rs = sendFtpCommand(sd, cmd, TRUE);
+if (!sendFtpCommand(sd, cmd, &rs))
+    {
+    close(sd);
+    return FALSE;
+    }
 *retTime = parseFtpMDTM(rs->string);
 /* 200 YYYYMMDDhhmmss */
 dyStringFree(&rs);
 close(sd);   
@@ -665,10 +694,11 @@
 close(sd);
 close(sdata);
 }
 
-int netGetOpenFtpSockets(char *url, int *retCtrlSd)
-/* Return a socket descriptor for url data (url can end in ";byterange:start-end".
+static int netGetOpenFtpSockets(char *url, int *retCtrlSd)
+/* Return a socket descriptor for url data (url can end in ";byterange:start-end",
+ * or -1 if error.
  * If retCtrlSd is non-null, keep the control socket alive and set *retCtrlSd.
  * Otherwise, create a pipe and fork to keep control socket alive in the child 
  * process until we are done fetching data. */
 {
@@ -679,35 +709,64 @@
 netParseUrl(url, &npu);
 if (!sameString(npu.protocol, "ftp"))
     errAbort("netGetOpenFtpSockets: url (%s) is not for ftp.", url);
 int sd = openFtpControlSocket(npu.host, atoi(npu.port), npu.user, npu.password);
+if (sd == -1)
+    return -1;
 
-struct dyString *rs = sendFtpCommand(sd, "PASV\r\n", TRUE);
+struct dyString *rs = NULL;
+if (!sendFtpCommand(sd, "PASV\r\n", &rs))
+    {
+    close(sd);
+    return -1;
+    }
 /* 227 Entering Passive Mode (128,231,210,81,222,250) */
 
 if (npu.byteRangeStart != -1)
     {
     safef(cmd,sizeof(cmd),"REST %lld\r\n", (long long) npu.byteRangeStart);
-    sendFtpCommand(sd, cmd, FALSE);
+    if (!sendFtpCommand(sd, cmd, NULL))
+	{
+	close(sd);
+	return -1;
+	}
     }
 
 safef(cmd,sizeof(cmd),"RETR %s\r\n", npu.file);
 sendFtpCommandOnly(sd, cmd);  
 
-int sdata = netMustConnect(npu.host, parsePasvPort(rs->string));
+int sdata = netConnect(npu.host, parsePasvPort(rs->string));
+dyStringFree(&rs);
+if (sdata < 0)
+    {
+    close(sd);
+    return -1;
+    }
 
 int secondsWaited = 0;
 while (TRUE)
     {
     if (secondsWaited >= 10)
-	errAbort("ftp server error on cmd=[%s] timed-out waiting for data or error\n", cmd);
+	{
+	warn("ftp server error on cmd=[%s] timed-out waiting for data or error\n", cmd);
+	close(sd);
+	close(sdata);
+	return -1;
+	}
     if (readReadyWait(sdata, NET_FTP_TIMEOUT))
 	break;   // we have some data
     if (readReadyWait(sd, 0)) /* wait in microsec */
-	receiveFtpReply(sd, cmd, FALSE);  // this can see an error like bad filename
+	{
+	// this can see an error like bad filename
+	if (!receiveFtpReply(sd, cmd, NULL))
+	    {
+	    close(sd);
+	    close(sdata);
+	    return -1;
+	    }
+	}
     ++secondsWaited;
     }
-dyStringFree(&rs);
 
 if (retCtrlSd != NULL)
     {
     *retCtrlSd = sd;
@@ -723,12 +782,12 @@
     fflush(stderr);
     /* make a pipe (fds go in pipefd[0] and pipefd[1])  */
     int pipefd[2];
     if (pipe(pipefd) != 0)
-	errAbort("netGetOpenFtp: failed to create pipe: %s", strerror(errno));
+	errAbort("netGetOpenFtpSockets: failed to create pipe: %s", strerror(errno));
     int pid = fork();
     if (pid < 0)
-	errnoAbort("can't fork in netGetOpenFtp");
+	errnoAbort("can't fork in netGetOpenFtpSockets");
     if (pid == 0)
 	{
 	/* child */
 	sendFtpDataToPipe(pipefd, sd, sdata, npu);
@@ -744,42 +803,38 @@
     return pipefd[0];
     }
 }
 
-int netGetOpenFtp(char *url)
-/* Return a socket descriptor for url data (url can end in ";byterange:start-end". */
-{
-return netGetOpenFtpSockets(url, NULL);
-}
-
 int netHttpConnect(char *url, char *method, char *protocol, char *agent, char *optionalHeader)
-/* Parse URL, connect to associated server on port,
- * and send most of the request to the server.  If
- * specified in the url send user name and password
- * too.  Typically the "method" will be "GET" or "POST"
+/* Parse URL, connect to associated server on port, and send most of
+ * the request to the server.  If specified in the url send user name
+ * and password too.  Typically the "method" will be "GET" or "POST"
  * and the agent will be the name of your program or
- * library. optionalHeader may be NULL or contain
- * additional header lines such as cookie info. */
+ * library. optionalHeader may be NULL or contain additional header
+ * lines such as cookie info. 
+ * Return data socket, or -1 if error.*/
 {
 struct netParsedUrl npu;
 struct dyString *dy = newDyString(512);
-int sd;
+int sd = -1;
 
 /* Parse the URL and connect. */
 netParseUrl(url, &npu);
 if (sameString(npu.protocol, "http"))
     {
-    sd = netMustConnect(npu.host, atoi(npu.port));
+    sd = netConnect(npu.host, atoi(npu.port));
     }
 else if (sameString(npu.protocol, "https"))
     {
-    sd = netMustConnectHttps(npu.host, atoi(npu.port));
+    sd = netConnectHttps(npu.host, atoi(npu.port));
     }
 else
     {
     errAbort("netHttpConnect: url (%s) is not for http.", url);
     return -1;  /* never gets here, fixes compiler complaint */
     }
+if (sd < 0)
+    return -1;
 
 /* Ask remote server for a file. */
 dyStringPrintf(dy, "%s %s %s\r\n", method, npu.file, protocol);
 dyStringPrintf(dy, "User-Agent: %s\r\n", agent);
@@ -879,9 +933,10 @@
 return status;
 }
 
 int netUrlOpenSockets(char *url, int *retCtrlSocket)
-/* Return socket descriptor (low-level file handle) for read()ing url data. 
+/* Return socket descriptor (low-level file handle) for read()ing url data,
+ * or -1 if error. 
  * If retCtrlSocket is non-NULL and url is FTP, set *retCtrlSocket
  * to the FTP control socket which is left open for a persistent connection.
  * close(result) (and close(*retCtrlSocket) if applicable) when done. */
 {
@@ -894,10 +949,10 @@
 return -1;    
 }
 
 int netUrlOpen(char *url)
-/* Return socket descriptor (low-level file handle) for read()ing url data. 
- * Just close(result) when done. */
+/* Return socket descriptor (low-level file handle) for read()ing url data,
+ * or -1 if error.  Just close(result) when done. */
 {
 return netUrlOpenSockets(url, NULL);
 }
 
@@ -917,8 +972,10 @@
 struct dyString *netSlurpUrl(char *url)
 /* Go grab all of URL and return it as dynamic string. */
 {
 int sd = netUrlOpen(url);
+if (sd < 0)
+    errAbort("netSlurpUrl: failed to open socket for [%s]", url);
 struct dyString *dy = netSlurpFile(sd);
 close(sd);
 return dy;
 }
@@ -1048,8 +1105,13 @@
 	    {
 	    *redirectedSd = sd;
 	    *redirectedUrl = url;
 	    }
+	else
+	    {
+	    *redirectedSd = -1;
+	    *redirectedUrl = NULL;
+	    }
 	return TRUE;
 	}
     close(sd);
     if (redirectCount > 0)