📄 ftplib.c
字号:
** if (ftpXfer ("server", "fred", "magic", "",* "RETR %s", "/usr/fred", "myfile",* &ctrlSock, &dataSock) == ERROR)* return (ERROR);** while ((nBytes = read (dataSock, buf, sizeof (buf))) > 0)* {* ...* }** close (dataSock);** if (nBytes < 0) /@ read error? @/* status = ERROR;** if (ftpReplyGet (ctrlSock, TRUE) != FTP_COMPLETE)* status = ERROR;** if (ftpCommand (ctrlSock, "QUIT", 0, 0, 0, 0, 0, 0) != FTP_COMPLETE)* status = ERROR;** close (ctrlSock);* .CE** RETURNS:* OK, or ERROR if any socket cannot be created or if a connection cannot be* made.** SEE ALSO: ftpReplyGet()*/STATUS ftpXfer ( char *host, /* name of server host */ char *user, /* user name for host login */ char *passwd, /* password for host login */ char *acct, /* account for host login */ char *cmd, /* command to send to host */ char *dirname, /* directory to 'cd' to before sending command */ char *filename, /* filename to send with command */ int *pCtrlSock, /* where to return control socket fd */ int *pDataSock /* where to return data socket fd, */ /* (NULL == don't open data connection) */ ) { FAST int ctrlSock = ERROR; FAST int dataSock = ERROR; UINT32 ftpReply = 0; UINT32 retryCount = 0; int cmdResult; struct fd_set readFds; /* Used by select for PORT method */ int width; /* Used by select for PORT method */ BOOL dataSockPassive = TRUE; FTPLDEBUG ("ftpXfer: host:%s user:%s passwd:%s acct:%s cmd:%s dir:%s\n", \ FTPL_DEBUG_ERRORS,host,user,passwd,acct,cmd,dirname); if (((ctrlSock = ftpHookup (host)) == ERROR) || (ftpLogin (ctrlSock, user, passwd, acct) != OK) || (ftpCommand (ctrlSock, "TYPE I",0,0,0,0,0,0) != FTP_COMPLETE) || ((dirname[0] != EOS) && (ftpCommand (ctrlSock, "CWD %s", (int)dirname,0,0,0,0,0) != FTP_COMPLETE))) { /* Detected an error during command establishment */ FTPLDEBUG ("ftpXfer: Detected an error during command establishment errno:0x%08x", \ FTPL_DEBUG_ERRORS,errno,1,2,3,4,5); close (ctrlSock); return (ERROR); } /* * This is a special when an FTP command does not need to establish a * data connection. */ if (pDataSock == NULL) { if (ftpCommand (ctrlSock, cmd, (int)filename, 0, 0, 0, 0, 0) != FTP_COMPLETE) { /* FTP command error. */ FTPLDEBUG ("ftpXfer: error during command. errno:0x%08x", \ FTPL_DEBUG_ERRORS, errno,1,2,3,4,5); close (ctrlSock); return (ERROR); } } /* * At this point we are trying to establish the data socket. * We will first try using the modern, client-initiated PASV command. * If PASV fails, then we will fall back to the PORT command. */ /* Set up local data port and send the PORT command */ do { if ((dataSock = ftpDataConnInitPassiveMode (ctrlSock)) != ERROR) { FTPLDEBUG ("ftpXfer: notice - mode succeeded.\n ", \ FTPL_DEBUG_ERRORS, 0, 1, 2, 3, 4, 5); dataSockPassive = TRUE; /* We do not need to listen() on the socket */ } else { FTPLDEBUG ("ftpXfer: notice - PASV mode failed. Now trying older PORT connect method", \ FTPL_DEBUG_ERRORS, 0, 1, 2, 3, 4, 5); if ((dataSock = ftpDataConnInit (ctrlSock)) == ERROR) { FTPLDEBUG ("ftpXfer: ftpDataConnInit - error during trying of another port. errno:0x%08x", \ FTPL_DEBUG_ERRORS, errno, 1, 2, 3, 4, 5); close (ctrlSock); return (ERROR); } else dataSockPassive = FALSE; /* We will need to listen() on the socket */ } /* Send the FTP command. */ cmdResult = ftpCommandEnhanced (ctrlSock, cmd, (int)filename, 0, 0, 0, 0, 0, NULL, 0); if ((cmdResult/100) != FTP_PRELIM) { /* * The command has failed. Close the data socket and decode the error. */ close (dataSock); /* Check if something really bad happened: File not found, etc. */ if ((cmdResult/100) == FTP_ERROR) { FTPLDEBUG ("ftpXfer: response 0x%08x - aborting transfer.\n", \ FTPL_DEBUG_ERRORS, cmdResult, 1, 2, 3, 4, 5); close (ctrlSock); return (ERROR); } if ((cmdResult/100) == FTP_TRANSIENT && _func_ftpTransientFatal != NULL) { FTPLDEBUG ("ftpXfer: calling user-supplied applette to see if 0x%08x FTP_TRANSIENT is fatal for this command.\n", \ FTPL_DEBUG_ERRORS, cmdResult, 1, 2, 3, 4, 5); if ((* _func_ftpTransientFatal) (cmdResult) == TRUE) { FTPLDEBUG ("ftpXfer: user-supplied applette says 0x%08x FTP_TRANSIENT ** IS ** fatal for this command.\n", \ FTPL_DEBUG_ERRORS, cmdResult, 1, 2, 3, 4, 5); close (ctrlSock); errno = S_ftpLib_FATAL_TRANSIENT_RESPONSE; return (ERROR); } FTPLDEBUG ("ftpXfer: user-supplied applette says 0x%08x is ** NOT ** fatal for this command.\n", \ FTPL_DEBUG_ERRORS, cmdResult, 1, 2, 3, 4, 5); } if ((ftpReply = (cmdResult/100)) == FTP_TRANSIENT) { /* * If the error was due to transient error (e.x. the data port * was not available) retry the command * ftplTransientMaxRetryCount times. */ if (retryCount < ftplTransientMaxRetryCount) { ++retryCount; FTPLDEBUG ("ftpXfer: warning - reply was %d(decimal) - FTP_PRELIM - #%d attempt in %d ticks.\n", \ FTPL_DEBUG_ERRORS,cmdResult,retryCount, ftplTransientRetryInterval, 5, 6, 7); if (ftplTransientRetryInterval) taskDelay (ftplTransientRetryInterval); continue; /* try another port */ } else { /* Too many retries, close socket and return failure */ FTPLDEBUG ("ftpXfer: error - reply was %d(decimal) - FTP_PRELIM - attempt limit (%d) exceeded.\n", \ FTPL_DEBUG_ERRORS, cmdResult, ftplTransientMaxRetryCount, 5, 6, 7, 8); close (ctrlSock); errno = S_ftpLib_TRANSIENT_RETRY_LIMIT_EXCEEDED; return (ERROR); } /* Exit for any other error */ FTPLDEBUG ("ftpXfer: error - ftpCommand != FTP_PRELIM. errno:0x%08x\n", \ FTPL_DEBUG_ERRORS, errno, 1, 2, 3, 4, 5); close (ctrlSock); return (ERROR); } } if ( dataSockPassive == FALSE) { /* At this point do a select on the data & control socket */ FTPLDEBUG ("ftpXfer: notice - cmdResult:%d dataSock:%d ctrlSock:%d errno:0x%08x\n", \ FTPL_DEBUG_ERRORS, cmdResult, dataSock, ctrlSock, errno, 4, 5); FD_ZERO (&readFds); FD_SET (ctrlSock, &readFds); FD_SET (dataSock, &readFds); width = (dataSock > ctrlSock) ? dataSock : ctrlSock; width++; if (select (width, &readFds, NULL, NULL, NULL) == ERROR) { FTPLDEBUG ("ftpXfer: error - select()==ERROR. errno:0x%08x\n", \ FTPL_DEBUG_ERRORS,errno, 1, 2, 3, 4, 5); close (dataSock); close (ctrlSock); return (ERROR); } /* If the control socket is ready process it and take a decision, * try again or return error. If the data socket is ready call * ftpDataConnGet next. */ if (FD_ISSET (ctrlSock, &readFds) && ! FD_ISSET (dataSock, &readFds)) { close (dataSock); FTPLDEBUG ("ftpXfer: warning - control socket ready but data socket not ready\n", \ FTPL_DEBUG_ERRORS,0, 1, 2, 3, 4, 5); if ((ftpReply = ftpReplyGet (ctrlSock, FALSE)) == FTP_TRANSIENT) continue; /* Try another port */ /* Regardless of response close sockets */ FTPLDEBUG ("ftpXfer: error - sending QUIT command to host. errno:0x%08x\n", \ FTPL_DEBUG_ERRORS,errno,1,2,3,4,5); (void) ftpCommand (ctrlSock, "QUIT", 0, 0, 0, 0, 0, 0); close (ctrlSock); return (ERROR); } } /* PORT method requires checking for data socket connection */ } while ( ftpReply == FTP_TRANSIENT); /* Try again, we might need a different port */ /* If we used PASV mode, then the socket is ready for use */ if (!dataSockPassive) { /* * We used the PORT method to establish a connection. * The data socket connection is configured. Wait for the FTP server to connect * to us. */ if ((dataSock = ftpDataConnGet (dataSock)) == ERROR) { FTPLDEBUG ("ftpXfer: error - ftpDataConnGet()==ERROR. errno:0x%08x\n", \ FTPL_DEBUG_ERRORS,errno, 1, 2, 3, 4, 5); close (ctrlSock); return (ERROR); } } /* Store the control and data sockets */ if (pCtrlSock != NULL) *pCtrlSock = ctrlSock; if (pDataSock != NULL) *pDataSock = dataSock; return (OK); }/********************************************************************************* ftpReplyGet - get an FTP command reply** This routine has been superceded by ftpReplyGetEnhanced()** This routine gets a command reply on the specified control socket.** The three-digit reply code from the first line is saved and interpreted.* The left-most digit of the reply code identifies the type of code* (see RETURNS below).** The caller's error status is always set to the complete three-digit reply code* regardless of the actual reply value (see the manual entry for errnoGet()).* If the reply code indicates an error, the entire reply* is printed if the ftp error printing is enabled (see the manual* entry for ftpLibDebugOptionsSet()).** If an EOF is encountered on the specified control socket, but no EOF was* expected (<expecteof> == FALSE), then ERROR is returned.** RETURNS:* 1 = FTP_PRELIM (positive preliminary)* 2 = FTP_COMPLETE (positive completion)* 3 = FTP_CONTINUE (positive intermediate)* 4 = FTP_TRANSIENT (transient negative completion)* 5 = FTP_ERROR (permanent negative completion)** ERROR if there is a read/write error or an unexpected EOF.*/int ftpReplyGet ( int ctrlSock, /* control socket fd of FTP connection */ BOOL expecteof /* TRUE = EOF expected, FALSE = EOF is error */ ) { /* return most significant digit of reply */ return (ftpReplyGetEnhanced (ctrlSock, expecteof, NULL, 0) / 100); }/********************************************************************************* ftpReplyGetEnhanced - get an FTP command reply** This routine supercedes ftpReplyGet()** This routine gets a command reply on the specified control socket.** The three-digit reply code from the first line is saved and interpreted.* The left-most digit of the reply code identifies the type of code* (see RETURNS below).** The caller's error status is always set to the complete three-digit reply code* (see the manual entry for errnoGet()).* If the reply code indicates an error, the entire reply* is printed if the ftp error printing is enabled (see the manual* entry for ftpLibDebugOptionsSet()).** The last line of text retrieved from the servers response is stored* in the location specified by replyString. If replyString is NULL* the parameter is ignored.** If an EOF is encountered on the specified control socket, but no EOF was* expected (<expecteof> == FALSE), then ERROR is returned.** RETURNS:* The complete FTP response code (see RFC #959)** ERROR if there is a read/write error or an unexpected EOF.*/int ftpReplyGetEnhanced ( int ctrlSock, /* control socket fd of FTP connection */ BOOL expecteof, /* TRUE = EOF expected, FALSE = EOF is error */ char *replyString, /* Location to store text of reply, or NULL */ int stringLengthMax /* Maximum length of reply (not including NULL) */ ) { char c; FAST int codeType; FAST int code; FAST int dig; int continuation; int origCode; int stringIndex; BOOL eof; /* read all lines of a reply: * do * while not eof and not eol * process char * while not eof and not last line of reply */ origCode = 0; codeType = 0; do { /* read all characters of a line */ dig = 0; code = 0; stringIndex = 0; continuation = FALSE; while (!(eof = (read (ctrlSock, &c, 1) == 0)) && (c != '\n')) { /* Store the reply */ if (replyString != NULL) { if (stringIndex < stringLengthMax) { replyString[stringIndex] = c; stringIndex++; } } dig++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -