📄 ftpdlib.c
字号:
ftpdSessionDelete (pSlot);
return (ERROR);
}
}
}
/*
* Processing halted due to pending server shutdown.
* Remove all resources and exit.
*/
ftpdSessionDelete (pSlot);
return (OK);
}
/*******************************************************************************
*
* ftpdDataConnGet - get a fresh data connection socket for FTP data transfer
*
* FTP uses upto two connections per session (as described above) at any
* time. The command connection (cmdSock) is maintained throughout the
* FTP session to pass the request command strings and replies between
* the client and the server. For commands that require bulk data transfer
* such as contents of a file or a list of files in a directory, FTP
* sets up dynamic data connections separate from the command connection.
* This function, ftpdDataConnGet, is responsible for creating
* such connections.
*
* Setting up the data connection is performed in two ways. If the dataSock
* is already initialized and we're in passive mode (as indicated by the
* FTPD_PASSIVE bit of the status field in the FTPD_SESSION_SLOT) we need to
* wait for our client to make a connection to us -- so we just do an accept
* on this already initialized dataSock. If the dataSock is already
* initialized and we're not in passive mode, we just use the already
* existing connection. Otherwise, we need to initialize a new socket and
* make a connection to the the port where client is accepting new
* connections. This port number is in general set by "PORT" command (see
* ftpdWorkTask()).
*/
LOCAL STATUS ftpdDataConnGet
(
FTPD_SESSION_DATA *pSlot /* pointer to the work slot */
)
{
FAST int newSock; /* new connection socket */
int addrLen; /* to be used with accept */
struct sockaddr_in addr; /* to be used with accept */
int on = 1; /* to be used to turn things on */
int retry = 0; /* retry counter initialized to zero */
/* command socket is invalid, return immediately */
if (pSlot->cmdSock == FTPD_SOCK_FREE)
return (ERROR);
pSlot->byteCount = 0;
if (pSlot->dataSock != FTPD_SOCK_FREE)
{
/* data socket is already initialized */
/* are we being passive? (should we wait for client to connect
* to us rather than connecting to the client?)
*/
if (pSlot->status & FTPD_PASSIVE)
{
/* we're being passive. wait for our client to connect to us. */
addrLen = sizeof (struct sockaddr);
if ((newSock = accept (pSlot->dataSock, (struct sockaddr *) &addr,
&addrLen)) < 0)
{
ftpdCmdSend (pSlot, pSlot->cmdSock,
425, "Can't open data connection",
0, 0, 0, 0, 0, 0);
ftpdSockFree (&pSlot->dataSock);
/* we can't be passive no more */
pSlot->status &= ~FTPD_PASSIVE;
return (ERROR);
}
/*
* Enable the keep alive option to prevent misbehaving clients
* from locking the server.
*/
if (setsockopt (newSock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
sizeof (on)) != 0)
{
ftpdSockFree (&pSlot->dataSock);
return (ERROR);
}
/* Check for window size validity */
if (ftpdWindowSize < 0 || ftpdWindowSize > 65536)
ftpdWindowSize = FTPD_WINDOW_SIZE;
/* set the window size */
if (setsockopt(newSock, SOL_SOCKET, SO_SNDBUF,
(char *)&ftpdWindowSize, sizeof (ftpdWindowSize)))
printf("Couldn't set the Send Window to 10k\n");
if (setsockopt(newSock, SOL_SOCKET, SO_RCVBUF,
(char *)&ftpdWindowSize, sizeof (ftpdWindowSize)))
printf("Couldn't set the Send Window to 10k\n");
/* replace the dataSock with our new connection */
(void) close (pSlot->dataSock);
pSlot->dataSock = newSock;
/* N.B.: we stay passive */
if (ftpdCmdSend (pSlot, pSlot->cmdSock,
150, "Opening %s mode data connection",
pSlot->status & FTPD_ASCII_TYPE ? (int) "ASCII"
: (int) "BINARY", 0, 0, 0, 0, 0) == ERROR)
{
(void) close (pSlot->dataSock);
return (ERROR);
}
return (OK);
}
else
{
/* reuse the old connection -- it's still useful */
if (ftpdCmdSend (pSlot, pSlot->cmdSock,
125, "Using existing data connection",
0, 0, 0, 0, 0, 0) == ERROR)
{
ftpdSockFree (&pSlot->dataSock);
return (ERROR);
}
return (OK);
}
}
else
{
/* Determine address for local end of connection. */
addrLen = sizeof (struct sockaddr);
if (getsockname (pSlot->cmdSock, (struct sockaddr *) &addr, &addrLen)
< 0)
{
return (ERROR);
}
/* Replace control port with default data port. */
addr.sin_port = htons (FTP_DATA_PORT);
/* open a new data socket */
if ((pSlot->dataSock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
{
return (ERROR);
}
if (setsockopt (pSlot->dataSock, SOL_SOCKET,
SO_REUSEADDR, (char *) &on, sizeof (on)) < 0 ||
bind (pSlot->dataSock, (struct sockaddr *) &addr,
sizeof (addr)) < 0)
{
ftpdSockFree (&pSlot->dataSock);
return (ERROR);
}
/* Set socket address to PORT command values or default. */
bcopy ( (char *)&pSlot->dataAddr, (char *)&addr,
sizeof (struct sockaddr_in));
/* try until we get a connection to the client's port */
while (connect (pSlot->dataSock,
(struct sockaddr *) &addr, sizeof (addr)) < 0)
{
if ((errno & 0xffff) == EADDRINUSE && retry < FTPD_WAIT_MAX)
{
taskDelay (FTPD_WAIT_INTERVAL * sysClkRateGet ());
retry += FTPD_WAIT_INTERVAL;
continue;
}
/* timeout -- we give up */
ftpdCmdSend (pSlot, pSlot->cmdSock,
425, "Can't build data connection",
0, 0, 0, 0, 0, 0);
ftpdSockFree (&pSlot->dataSock);
return (ERROR);
}
/*
* Enable the keep alive option to prevent misbehaving clients
* from locking the secondary task during file transfers.
*/
if (setsockopt (pSlot->dataSock, SOL_SOCKET, SO_KEEPALIVE,
(char *) &on, sizeof (on)) != 0)
{
ftpdSockFree (&pSlot->dataSock);
return (ERROR);
}
/* Check for window size validity */
if (ftpdWindowSize < 0 || ftpdWindowSize > 65536)
ftpdWindowSize = FTPD_WINDOW_SIZE;
/* set the window size */
if (setsockopt(pSlot->dataSock, SOL_SOCKET, SO_SNDBUF,
(char *)&ftpdWindowSize, sizeof (ftpdWindowSize)))
printf("Couldn't set the Send Window to 10k\n");
if (setsockopt(pSlot->dataSock, SOL_SOCKET, SO_RCVBUF,
(char *)&ftpdWindowSize, sizeof (ftpdWindowSize)))
printf("Couldn't set the Send Window to 10k\n");
if (ftpdCmdSend (pSlot, pSlot->cmdSock,
150, "Opening %s mode data connection",
pSlot->status & FTPD_ASCII_TYPE ? (int) "ASCII" :
(int) "BINARY", 0, 0, 0, 0, 0) == ERROR)
{
ftpdSockFree (&pSlot->dataSock);
return (ERROR);
}
}
return (OK);
}
/*******************************************************************************
*
* ftpdDataStreamSend - send FTP data over data connection
*
* When our FTP client does a "RETR" (send me a file) and we find an existing
* file, ftpdWorkTask() will call us to perform the actual shipment of the
* file in question over the data connection.
*
* We do the initialization of the new data connection ourselves here
* and make sure that everything is fine and dandy before shipping the
* contents of the file. Special attention is given to the type of
* the file representation -- ASCII or BINARY. If it's binary, we
* don't perform the prepending of "\r" character in front of each
* "\n" character. Otherwise, we have to do this for the ASCII files.
*
* SEE ALSO:
* ftpdDataStreamReceive which is symmetric to this function.
*/
LOCAL void ftpdDataStreamSend
(
FTPD_SESSION_DATA *pSlot, /* pointer to our session slot */
FILE *inStream /* pointer to the input file stream */
)
{
FAST char *pBuf; /* pointer to the session buffer */
FAST int netFd; /* output socket */
FAST int fileFd; /* input file descriptor */
FAST char ch; /* character holder */
FAST int cnt; /* number of chars read/written */
FAST FILE *outStream; /* buffered output socket stream */
int retval = 0;
/* get a fresh connection or reuse the old one */
if (ftpdDataConnGet (pSlot) == ERROR)
{
dataError (pSlot);
return;
}
pBuf = &pSlot->buf [0];
if (pSlot->status & FTPD_ASCII_TYPE)
{
/* ASCII representation */
/* get a buffered I/O stream for this output data socket */
if ((outStream = fdopen (pSlot->dataSock, "w")) == NULL)
{
dataError (pSlot);
return;
}
/* write out the contents of the file and do the '\r' prepending */
while ((ch = getc (inStream)) != (char) EOF)
{
pSlot->byteCount++;
/* if '\n' is encountered, we prepend a '\r' */
if (ch == '\n')
{
if (ferror (outStream))
{
dataError (pSlot);
fclose (outStream);
return;
}
if (putc ('\r', outStream) == EOF)
{
dataError (pSlot);
fclose (outStream);
return;
}
}
if (putc (ch, outStream) == EOF)
{
dataError (pSlot);
fclose (outStream);
return;
}
/* Abort the file transfer if a shutdown is in progress. */
if (ch == '\n' && ftpsShutdownFlag)
{
dataError (pSlot);
fclose (outStream);
return;
}
}
/* flush it out */
(void) fflush (outStream);
if (ferror (inStream))
{
/* error in reading the file */
fileError (pSlot);
fclose (outStream);
return;
}
if (ferror (outStream))
{
/* error in sending the file */
dataError (pSlot);
fclose (outStream);
return;
}
fclose (outStream);
/* everything is okay */
transferOkay (pSlot);
}
else if (pSlot->status & FTPD_BINARY_TYPE)
{
/* BINARY representation */
netFd = pSlot->dataSock;
/* get a raw descriptor for this input file */
fileFd = fileno (inStream);
/* unbuffered block I/O between file and network */
while ((cnt = read (fileFd, pBuf, BUFSIZE)) > 0 &&
(retval = write (netFd, pBuf, cnt)) == cnt)
{
pSlot->byteCount += cnt;
if (ftpsShutdownFlag)
{
/* Abort the file transfer if a shutdown is in progress. */
cnt = 1;
break;
}
}
/* cnt should be zero if the transfer ended normally */
if (cnt != 0)
{
if (cnt < 0)
{
fileError (pSlot);
return;
}
ftpdDebugMsg ("read %d bytes, wrote %d bytes\n", cnt, retval,0,0);
dataError (pSlot);
return;
}
transferOkay (pSlot);
}
else
unImplementedType (pSlot); /* invalide representation type */
}
/*******************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -