📄 rcmd.c
字号:
return (cip->errNo);
}
return (kNoErr);
}
return (kErrNotConnected);
} /* SendCommand */
#else /* NO_SIGNALS */
static int
SendCommand(const FTPCIPtr cip, const char *cmdspec, va_list ap)
{
longstring command;
int result;
volatile FTPCIPtr vcip;
volatile FTPSigProc osigpipe;
int sj;
if (cip->cout != NULL) {
#ifdef HAVE_VSNPRINTF
(void) vsnprintf(command, sizeof(command) - 1, cmdspec, ap);
command[sizeof(command) - 1] = '\0';
#else
(void) vsprintf(command, cmdspec, ap);
#endif
if ((strncmp(command, "PASS", SZ(4)) != 0) || ((strcmp(cip->user, "anonymous") == 0) && (cip->firewallType == kFirewallNotInUse)))
PrintF(cip, "Cmd: %s\n", command);
else
PrintF(cip, "Cmd: %s\n", "PASS xxxxxxxx");
(void) STRNCAT(command, "\r\n"); /* Use TELNET end-of-line. */
cip->lastFTPCmdResultStr[0] = '\0';
cip->lastFTPCmdResultNum = -1;
osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenCtrl);
vcip = cip;
#ifdef HAVE_SIGSETJMP
sj = sigsetjmp(gBrokenCtrlJmp, 1);
#else
sj = setjmp(gBrokenCtrlJmp);
#endif /* HAVE_SIGSETJMP */
if (sj != 0) {
(void) signal(SIGPIPE, (FTPSigProc) osigpipe);
FTPShutdownHost(vcip);
if (vcip->eofOkay == 0) {
Error(cip, kDontPerror, "Remote host has closed the connection.\n");
vcip->errNo = kErrRemoteHostClosedConnection;
return(vcip->errNo);
}
return (kNoErr);
}
result = fputs(command, cip->cout);
if (result < 0) {
(void) signal(SIGPIPE, osigpipe);
cip->errNo = kErrSocketWriteFailed;
Error(cip, kDoPerror, "Could not write to control stream.\n");
return (cip->errNo);
}
result = fflush(cip->cout);
if (result < 0) {
(void) signal(SIGPIPE, osigpipe);
cip->errNo = kErrSocketWriteFailed;
Error(cip, kDoPerror, "Could not write to control stream.\n");
return (cip->errNo);
}
(void) signal(SIGPIPE, osigpipe);
return (kNoErr);
}
return (kErrNotConnected);
} /* SendCommand */
#endif /* NO_SIGNALS */
/* For "simple" (i.e. not data transfer) commands, this routine is used
* to send the command and receive one response. It returns the codeType
* field of the 'Response' as the result, or a negative number upon error.
*/
/*VARARGS*/
int
FTPCmd(const FTPCIPtr cip, const char *const cmdspec, ...)
{
va_list ap;
int result;
ResponsePtr rp;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
rp = InitResponse();
if (rp == NULL) {
result = kErrMallocFailed;
cip->errNo = kErrMallocFailed;
Error(cip, kDontPerror, "Malloc failed.\n");
return (cip->errNo);
}
va_start(ap, cmdspec);
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(cip->ctrlTimeout);
#endif /* NO_SIGNALS */
result = SendCommand(cip, cmdspec, ap);
va_end(ap);
if (result < 0) {
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
return (result);
}
/* Get the response to the command we sent. */
result = GetResponse(cip, rp);
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
if (result == kNoErr)
result = rp->codeType;
DoneWithResponse(cip, rp);
return (result);
} /* FTPCmd */
/* This is for debugging the library -- don't use. */
/*VARARGS*/
int
FTPCmdNoResponse(const FTPCIPtr cip, const char *const cmdspec, ...)
{
va_list ap;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
va_start(ap, cmdspec);
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(cip->ctrlTimeout);
#endif /* NO_SIGNALS */
(void) SendCommand(cip, cmdspec, ap);
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
va_end(ap);
return (kNoErr);
} /* FTPCmdNoResponse */
int
WaitResponse(const FTPCIPtr cip, unsigned int sec)
{
int result;
fd_set ss;
struct timeval tv;
int fd;
#ifdef NO_SIGNALS
fd = cip->ctrlSocketR;
#else /* NO_SIGNALS */
if (cip->cin == NULL)
return (-1);
fd = fileno(cip->cin);
#endif /* NO_SIGNALS */
if (fd < 0)
return (-1);
FD_ZERO(&ss);
FD_SET(fd, &ss);
tv.tv_sec = (unsigned long) sec;
tv.tv_usec = 0;
result = select(fd + 1, SELECT_TYPE_ARG234 &ss, NULL, NULL, &tv);
return (result);
} /* WaitResponse */
/* For "simple" (i.e. not data transfer) commands, this routine is used
* to send the command and receive one response. It returns the codeType
* field of the 'Response' as the result, or a negative number upon error.
*/
/*VARARGS*/
int
RCmd(const FTPCIPtr cip, ResponsePtr rp, const char *cmdspec, ...)
{
va_list ap;
int result;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
va_start(ap, cmdspec);
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(cip->ctrlTimeout);
#endif /* NO_SIGNALS */
result = SendCommand(cip, cmdspec, ap);
va_end(ap);
if (result < 0) {
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
return (result);
}
/* Get the response to the command we sent. */
result = GetResponse(cip, rp);
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
if (result == kNoErr)
result = rp->codeType;
return (result);
} /* RCmd */
/* Returns -1 if an error occurred, or 0 if not.
* This differs from RCmd, which returns the code class of a response.
*/
/*VARARGS*/
int
FTPStartDataCmd(const FTPCIPtr cip, int netMode, int type, longest_int startPoint, const char *cmdspec, ...)
{
va_list ap;
int result;
int respCode;
ResponsePtr rp;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
result = FTPSetTransferType(cip, type);
if (result < 0)
return (result);
/* Re-set the cancellation flag. */
cip->cancelXfer = 0;
/* To transfer data, we do these things in order as specifed by
* the RFC.
*
* First, we tell the other side to set up a data line. This
* is done below by calling OpenDataConnection(), which sets up
* the socket. When we do that, the other side detects a connection
* attempt, so it knows we're there. Then tell the other side
* (by using listen()) that we're willing to receive a connection
* going to our side.
*/
if ((result = OpenDataConnection(cip, cip->dataPortMode)) < 0)
goto done;
/* If asked, attempt to start at a later position in the remote file. */
if (startPoint != (longest_int) 0) {
if ((startPoint == kSizeUnknown) || ((result = SetStartOffset(cip, startPoint)) != 0))
startPoint = (longest_int) 0;
}
cip->startPoint = startPoint;
/* Now we tell the server what we want to do. This sends the
* the type of transfer we want (RETR, STOR, LIST, etc) and the
* parameters for that (files to send, directories to list, etc).
*/
va_start(ap, cmdspec);
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(cip->ctrlTimeout);
#endif /* NO_SIGNALS */
result = SendCommand(cip, cmdspec, ap);
va_end(ap);
if (result < 0) {
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
goto done;
}
/* Get the response to the transfer command we sent, to see if
* they can accomodate the request. If everything went okay,
* we will get a preliminary response saying that the transfer
* initiation was successful and that the data is there for
* reading (for retrieves; for sends, they will be waiting for
* us to send them something).
*/
rp = InitResponse();
if (rp == NULL) {
Error(cip, kDontPerror, "Malloc failed.\n");
cip->errNo = kErrMallocFailed;
result = cip->errNo;
goto done;
}
result = GetResponse(cip, rp);
#ifndef NO_SIGNALS
if (cip->ctrlTimeout > 0)
(void) alarm(0);
#endif /* NO_SIGNALS */
if (result < 0)
goto done;
respCode = rp->codeType;
DoneWithResponse(cip, rp);
if (respCode > 2) {
cip->errNo = kErrCouldNotStartDataTransfer;
result = cip->errNo;
goto done;
}
/* Now we accept the data connection that the other side is offering
* to us. Then we can do the actual I/O on the data we want.
*/
cip->netMode = netMode;
if ((result = AcceptDataConnection(cip)) < 0)
goto done;
return (kNoErr);
done:
(void) FTPEndDataCmd(cip, 0);
return (result);
} /* FTPStartDataCmd */
void
FTPAbortDataTransfer(const FTPCIPtr cip)
{
ResponsePtr rp;
int result;
if (cip->dataSocket != kClosedFileDescriptor) {
PrintF(cip, "Starting abort sequence.\n");
SendTelnetInterrupt(cip); /* Probably could get by w/o doing this. */
result = FTPCmdNoResponse(cip, "ABOR");
if (result != kNoErr) {
/* Linger could cause close to block, so unset it. */
(void) SetLinger(cip, cip->dataSocket, 0);
CloseDataConnection(cip);
PrintF(cip, "Could not send abort command.\n");
return;
}
if (cip->abortTimeout > 0) {
result = WaitResponse(cip, (unsigned int) cip->abortTimeout);
if (result <= 0) {
/* Error or no response received to ABOR in time. */
(void) SetLinger(cip, cip->dataSocket, 0);
CloseDataConnection(cip);
PrintF(cip, "No response received to abort request.\n");
return;
}
}
rp = InitResponse();
if (rp == NULL) {
Error(cip, kDontPerror, "Malloc failed.\n");
cip->errNo = kErrMallocFailed;
result = cip->errNo;
return;
}
result = GetResponse(cip, rp);
if (result < 0) {
/* Shouldn't happen, and doesn't matter if it does. */
(void) SetLinger(cip, cip->dataSocket, 0);
CloseDataConnection(cip);
PrintF(cip, "Invalid response to abort request.\n");
DoneWithResponse(cip, rp);
return;
}
DoneWithResponse(cip, rp);
/* A response to the abort request has been received.
* Now the only thing left to do is close the data
* connection, making sure to turn off linger mode
* since we don't care about straggling data bits.
*/
(void) SetLinger(cip, cip->dataSocket, 0);
CloseDataConnection(cip); /* Must close (by protocol). */
PrintF(cip, "End abort.\n");
}
} /* FTPAbortDataTransfer */
int
FTPEndDataCmd(const FTPCIPtr cip, int didXfer)
{
int result;
int respCode;
ResponsePtr rp;
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
CloseDataConnection(cip);
result = kNoErr;
if (didXfer) {
/* Get the response to the data transferred. Most likely a message
* saying that the transfer completed succesfully. However, if
* we tried to abort the transfer using ABOR, we will have a response
* to that command instead.
*/
rp = InitResponse();
if (rp == NULL) {
Error(cip, kDontPerror, "Malloc failed.\n");
cip->errNo = kErrMallocFailed;
result = cip->errNo;
return (result);
}
result = GetResponse(cip, rp);
if (result < 0)
return (result);
respCode = rp->codeType;
DoneWithResponse(cip, rp);
if (respCode != 2) {
cip->errNo = kErrDataTransferFailed;
result = cip->errNo;
} else {
result = kNoErr;
}
}
return (result);
} /* FTPEndDataCmd */
int
BufferGets(char *buf, size_t bufsize, int inStream, char *secondaryBuf, char **secBufPtr, char **secBufLimit, size_t secBufSize)
{
int err;
char *src;
char *dst;
char *dstlim;
int len;
int nr;
int haveEof = 0;
err = 0;
dst = buf;
dstlim = dst + bufsize - 1; /* Leave room for NUL. */
src = (*secBufPtr);
for ( ; dst < dstlim; ) {
if (src >= (*secBufLimit)) {
/* Fill the buffer. */
/* Don't need to poll it here. The routines that use BufferGets don't
* need any special processing during timeouts (i.e. progress reports),
* so go ahead and just let it block until there is data to read.
*/
nr = (int) read(inStream, secondaryBuf, secBufSize);
if (nr == 0) {
/* EOF. */
haveEof = 1;
goto done;
} else if (nr < 0) {
/* Error. */
err = -1;
goto done;
}
(*secBufPtr) = secondaryBuf;
(*secBufLimit) = secondaryBuf + nr;
src = (*secBufPtr);
if (nr < (int) secBufSize)
src[nr] = '\0';
}
if (*src == '\r') {
++src;
} else {
if (*src == '\n') {
/* *dst++ = *src++; */ ++src;
goto done;
}
*dst++ = *src++;
}
}
done:
(*secBufPtr) = src;
*dst = '\0';
len = (int) (dst - buf);
if (err < 0)
return (err);
if ((len == 0) && (haveEof == 1))
return (-1);
return (len); /* May be zero, if a blank line. */
} /* BufferGets */
/* eof */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -