⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpdlib.c

📁 cpc-1631的BSP包for VxWorks操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -