📄 ftp_data.c
字号:
/*---------------------------------------------------------------------
*
* Program: AC_FTP.EXE Asynch Ftp Client (TCP)
*
* filename: FTP_DATA.C
*
* copyright by Bob Quinn, 1995
*
* Description:
* Client application that uses "file transfer protocol" (ftp)
* service as described by RFC 959.
*
* This module contains the functions that deal with the FTP
* data connection (for sending and receiving data between
* client and server to service LIST, RECV and STOR commands).
*
* This software is not subject to any export provision of
* the United States Department of Commerce, and may be
* exported to any country or planet.
*
* Permission is granted to anyone to use this software for any
* purpose on any computer system, and to alter it and redistribute
* it freely, subject to the following restrictions:
*
* 1. The author is not responsible for the consequences of
* use of this software, no matter how awful, even if they
* arise from flaws in it.
*
* 2. The origin of this software must not be misrepresented,
* either by explicit claim or by omission. Since few users
* ever read sources, credits must appear in the documentation.
*
* 3. Altered versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
* Since few users ever read sources, credits must appear in
* the documentation.
*
* 4. This notice may not be removed or altered.
*
---------------------------------------------------------------------*/
#include "..\wsa_xtra.h"
#include <windows.h>
#include <windowsx.h>
#include "..\winsockx.h"
#include <string.h> /* for _fmemcpy() & _fmemset() */
#include <stdlib.h> /* for _ltoa() */
#include <winsock.h>
#include "resource.h"
#include <direct.h> /* for Microsoft find file structure */
#include "ac_ftp.h"
/*--------------------------------------------------------------
* Function: InitDataConn()
*
* Description: Set up a listening socket for a data connection
*/
SOCKET InitDataConn(PSOCKADDR_IN lpstName, HWND hDlg, u_int nAsyncMsg)
{
int nRet;
SOCKET hLstnSock;
int nLen = SOCKADDR_LEN;
if (bDebug) {
wsprintf(achTempBuf,
"InitDataConn() Qlen:%d Cmd[0]:%d [1]:%d [2]:%d [3]:%d, State:%d\n",
nQLen, astFtpCmd[0].nFtpCmd, astFtpCmd[1].nFtpCmd,
astFtpCmd[2].nFtpCmd, astFtpCmd[3].nFtpCmd, nAppState);
OutputDebugString (achTempBuf);
}
lByteCount = 0; /* init byte counter */
/* Get a TCP socket to use for data connection listen*/
hLstnSock = socket (AF_INET, SOCK_STREAM, 0);
if (hLstnSock == INVALID_SOCKET) {
WSAperror(WSAGetLastError(), "socket()", hInst);
} else {
/* Request async notification for most events */
nRet = WSAAsyncSelect(hLstnSock, hDlg, nAsyncMsg,
(FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE));
if (nRet == SOCKET_ERROR) {
WSAperror(WSAGetLastError(), "WSAAsyncSelect()", hInst);
} else {
/* Name the local socket with bind() */
lpstName->sin_family = PF_INET;
lpstName->sin_port = 0; /* any port will do */
nRet = bind(hLstnSock,(LPSOCKADDR)lpstName,SOCKADDR_LEN);
if (nRet == SOCKET_ERROR) {
WSAperror(WSAGetLastError(), "bind()", hInst);
} else {
/* Get local port number assigned by bind() */
nRet = getsockname(hLstnSock,(LPSOCKADDR)lpstName,
(int FAR *)&nLen);
if (nRet == SOCKET_ERROR) {
WSAperror(WSAGetLastError(), "getsockname()", hInst);
} else {
/* Listen for incoming connection requests */
nRet = listen(hLstnSock, 5);
if (nRet == SOCKET_ERROR) {
WSAperror(WSAGetLastError(), "listen()", hInst);
}
}
}
}
/* If we haven't had an error but we still don't know the local
* IP address, then we need to try to get it before we return */
if (!lpstName->sin_addr.s_addr) {
lpstName->sin_addr.s_addr = GetHostID();
if (!lpstName->sin_addr.s_addr) {
MessageBox (hDlg, "Can't get local IP address",
"InitDataConn() Failed", MB_OK | MB_ICONASTERISK);
nRet = SOCKET_ERROR;
}
}
/* If we had an error or we still don't know our IP address,
* then we have a problem. Clean up */
if (nRet == SOCKET_ERROR) {
closesocket(hLstnSock);
hLstnSock = INVALID_SOCKET;
}
}
return (hLstnSock);
} /* end InitDataConn() */
/*--------------------------------------------------------------
* Function: AcceptDataConn()
*
* Description: Accept an incoming data connection
*/
SOCKET AcceptDataConn(SOCKET hLstnSock, PSOCKADDR_IN pstName)
{
SOCKET hDataSock;
int nRet, nLen = SOCKADDR_LEN, nOptval;
if (bDebug) {
wsprintf(achTempBuf,
"AcceptDataConn() Qlen:%d Cmd[0]:%d [1]:%d [2]:%d [3]:%d, State:%d\n",
nQLen, astFtpCmd[0].nFtpCmd, astFtpCmd[1].nFtpCmd,
astFtpCmd[2].nFtpCmd, astFtpCmd[3].nFtpCmd, nAppState);
OutputDebugString (achTempBuf);
}
hDataSock = accept (hLstnSock, (LPSOCKADDR)pstName, (LPINT)&nLen);
if (hDataSock == SOCKET_ERROR) {
int WSAErr = WSAGetLastError();
if (WSAErr != WSAEWOULDBLOCK)
WSAperror (WSAErr, "accept", hInst);
} else if (bReAsync) {
/* This SHOULD be unnecessary, since all new sockets are supposed
* to inherit properties of the listening socket (like all the
* asynch events registered but some WinSocks don't do this.
* Request async notification for most events */
nRet = WSAAsyncSelect(hDataSock, hWinMain, WSA_ASYNC+1,
(FD_READ | FD_WRITE | FD_CLOSE));
if (nRet == SOCKET_ERROR) {
WSAperror(WSAGetLastError(), "WSAAsyncSelect()", hInst);
}
/* Try to get lots of buffer space */
nOptval = astFtpCmd[0].nFtpCmd==STOR ? SO_SNDBUF : SO_RCVBUF;
GetBuf(hDataSock, INPUT_SIZE*2, nOptval);
}
return (hDataSock);
} /* end AcceptData() */
/*--------------------------------------------------------------
* Function: SendData()
*
* Description: Open data file, read and send
*/
long SendData(SOCKET *hDataSock, HFILE hDataFile, int len)
{
static int cbReadFromFile; /* bytes read from file */
static int cbSentToServer; /* number of buffered bytes sent */
static HFILE hLastFile; /* handle of last file sent */
long cbTotalSent = 0; /* total bytes sent */
int nRet, WSAErr, cbBytesToSend;
/* Reset our counters when we access a new file */
if (hLastFile != hDataFile) {
cbReadFromFile = 0;
cbSentToServer = 0;
hLastFile = hDataFile;
}
/* Read data from file, and send it. */
do {
if (bIOBeep)
MessageBeep(0xFFFF);
/* calculate what's left to send */
cbBytesToSend = cbReadFromFile - cbSentToServer;
if (cbBytesToSend <= 0) {
/* read data from input file, if we need it */
if (!bFromNul) {
cbReadFromFile = _lread(hDataFile, achOutBuf, INPUT_SIZE);
if (cbReadFromFile == HFILE_ERROR) {
MessageBox (hWinMain, "Error reading data file",
"SendData() Failed", MB_OK | MB_ICONASTERISK);
break;
} else if (!cbReadFromFile){
/* EOF: no more data to send */
CloseFtpConn(hDataSock, (PSTR)0, 0, hWinMain);
EndData();
break;
} else {
cbBytesToSend = cbReadFromFile; /* send as much as we read */
}
} else {
/* just send whatever's in memory (up to our max) */
if (lByteCount < MAXNULPUT) {
cbBytesToSend = INPUT_SIZE;
} else {
CloseFtpConn(hDataSock, (PSTR)0, 0, hWinMain);
EndData();
}
}
cbSentToServer = 0; /* reset tally */
}
/* Send data to server */
nRet = send (*hDataSock, &(achOutBuf[cbSentToServer]),
((len < cbBytesToSend) ? len : cbBytesToSend), 0);
if (nRet == SOCKET_ERROR) {
WSAErr = WSAGetLastError();
/* Display significant errors */
if (WSAErr != WSAEWOULDBLOCK)
WSAperror(WSAErr, (LPSTR)"send()", hInst);
} else {
/* Update byte counter, and display. */
lByteCount += nRet;
_ltoa(lByteCount, achTempBuf, 10);
SetDlgItemText(hWinMain, IDC_DATA_RATE, achTempBuf);
cbSentToServer += nRet;/* tally bytes sent since last file read */
cbTotalSent += nRet;/* tally total bytes sent since we started */
}
} while (nRet != SOCKET_ERROR);
return (cbTotalSent);
} /* end SendData() */
/*--------------------------------------------------------------
* Function: RecvData()
*
* Description: Receive data from net and write to open data file
*/
int RecvData(SOCKET hDataSock, HFILE hDataFile, LPSTR achInBuf, int len)
{
static HFILE hLastFile; /* handle of last file sent */
static int cbBytesBuffered; /* total bytes received */
int cbBytesRcvd = 0;
int nRet=0, WSAErr;
if (hDataFile != hLastFile) {
hLastFile = hDataFile;
cbBytesBuffered = 0;
}
/* Read as much as we can from server */
while (cbBytesBuffered < len) {
nRet = recv (hDataSock,&(achInBuf[cbBytesBuffered]),
len-cbBytesBuffered, 0);
if (nRet == SOCKET_ERROR) {
WSAErr = WSAGetLastError();
/* Display significant errors */
if (WSAErr != WSAEWOULDBLOCK)
WSAperror(WSAErr, (LPSTR)"recv()", hInst);
/* exit recv() loop on any error */
goto recv_end;
} else if (nRet == 0) { /* Other side closed socket */
/* quit if server closed connection */
goto recv_end;
} else {
/* Update byte counter, and display */
lByteCount += nRet;
_ltoa(lByteCount, achTempBuf, 10);
SetDlgItemText(hWinMain, IDC_DATA_RATE, achTempBuf);
cbBytesRcvd += nRet; /* tally bytes read */
cbBytesBuffered += nRet;
}
}
recv_end:
if (!bToNul &&
((cbBytesBuffered > (len-MTU_SIZE)) ||
((nRet == SOCKET_ERROR) && WSAGetLastError() != WSAEWOULDBLOCK) ||
(nRet == 0))) {
/* If we have a lot buffered, write to data file */
nRet = _lwrite(hDataFile, achInBuf, cbBytesBuffered);
if (nRet == HFILE_ERROR)
MessageBox (hWinMain, "Can't write to local file",
"RecvData() Failed", MB_OK | MB_ICONASTERISK);
cbBytesBuffered = 0;
} else if (bToNul)
cbBytesBuffered = 0;
return (cbBytesRcvd);
} /* end RecvData() */
/*--------------------------------------------------------------
* Function: EndData()
*
* Description: Close up the data connection
*/
void EndData (void) {
LONG dByteRate;
LONG lMSecs;
/* Calculate data transfer rate, and display */
lMSecs = (LONG) GetTickCount() - lStartTime;
if (lMSecs <= 55)
lMSecs = 27; /* about half of 55Msec PC clock resolution */
/* Socket Check should not be necessary, but some WinSocks
* mistakenly post FD_CLOSE to listen socket after close */
nAppState &= ~(DATACONNECTED);
SetDlgItemText (hWinMain, IDC_STATUS, "Status: connected");
if (lByteCount > 0L) {
dByteRate = (lByteCount/lMSecs); /* data rate (bytes/Msec) */
wsprintf (achTempBuf,"%ld bytes %s in %ld.%ld seconds (%ld.%ld Kbytes/sec)",
lByteCount,
((astFtpCmd[0].nFtpCmd==STOR) ? "sent":"received"),
lMSecs/1000, lMSecs%1000,
(dByteRate*1000)/1024, (dByteRate*1000)%1024);
SetDlgItemText (hWinMain, IDC_DATA_RATE, achTempBuf);
if (hLogFile != HFILE_ERROR)
_lwrite (hLogFile, achTempBuf, strlen(achTempBuf));
}
lStartTime = 0L;
if (hDataFile != HFILE_ERROR) {
_lclose (hDataFile);
hDataFile = HFILE_ERROR;
if (astFtpCmd[0].nFtpCmd == LIST) {
wsprintf (achTempBuf, "notepad %s", szTempFile);
WinExec (achTempBuf, SW_SHOW);
}
}
astFtpCmd[0].nFtpCmd = 0; /* reset pending command */
} /* end EndData() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -