FTP_DATA.C
上传用户:tjfeida
上传日期:2013-03-10
资源大小:1917k
文件大小:12k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. /*---------------------------------------------------------------------
  2.  *
  3.  *  Program: AC_FTP.EXE Asynch Ftp Client (TCP)
  4.  *
  5.  *  filename: FTP_DATA.C
  6.  *
  7.  *  copyright by Bob Quinn, 1995
  8.  *   
  9.  *  Description:
  10.  *    Client application that uses "file transfer protocol" (ftp)
  11.  *    service as described by RFC 959.  
  12.  *
  13.  *    This module contains the functions that deal with the FTP
  14.  *    data connection (for sending and receiving data between 
  15.  *    client and server to service LIST, RECV and STOR commands). 
  16.  *
  17.  *  This software is not subject to any  export  provision  of
  18.  *  the  United  States  Department  of  Commerce,  and may be
  19.  *  exported to any country or planet.
  20.  *
  21.  *  Permission is granted to anyone to use this  software  for any  
  22.  *  purpose  on  any computer system, and to alter it and redistribute 
  23.  *  it freely, subject to the following  restrictions:
  24.  *
  25.  *  1. The author is not responsible for the consequences of
  26.  *     use of this software, no matter how awful, even if they
  27.  *     arise from flaws in it.
  28.  *
  29.  *  2. The origin of this software must not be misrepresented,
  30.  *     either by explicit claim or by omission.  Since few users
  31.  *     ever read sources, credits must appear in the documentation.
  32.  *
  33.  *  3. Altered versions must be plainly marked as such, and
  34.  *     must not be misrepresented as being the original software.
  35.  *     Since few users ever read sources, credits must appear in
  36.  *     the documentation.
  37.  *
  38.  *  4. This notice may not be removed or altered.
  39.  *  
  40.  ---------------------------------------------------------------------*/
  41. #include "..wsa_xtra.h" 
  42. #include <windows.h>
  43. #include <windowsx.h>
  44. #include "..winsockx.h"
  45. #include <string.h>    /* for _fmemcpy() & _fmemset() */
  46. #include <stdlib.h>    /* for _ltoa() */
  47. #include <winsock.h>
  48. #include "resource.h"
  49. #include <direct.h>    /* for Microsoft find file structure */
  50. #include "ac_ftp.h"
  51. /*--------------------------------------------------------------
  52.  * Function: InitDataConn()
  53.  *
  54.  * Description: Set up a listening socket for a data connection
  55.  */
  56. SOCKET InitDataConn(PSOCKADDR_IN lpstName, HWND hDlg, u_int nAsyncMsg)
  57. {
  58.   int nRet;
  59.   SOCKET hLstnSock;
  60.   int nLen = SOCKADDR_LEN;
  61.   
  62.   if (bDebug) {
  63.     wsprintf(achTempBuf, 
  64.       "InitDataConn()   Qlen:%d Cmd[0]:%d [1]:%d [2]:%d [3]:%d, State:%dn", 
  65.       nQLen, astFtpCmd[0].nFtpCmd, astFtpCmd[1].nFtpCmd,
  66.       astFtpCmd[2].nFtpCmd, astFtpCmd[3].nFtpCmd, nAppState);
  67.     OutputDebugString (achTempBuf);    
  68.   }
  69.   lByteCount = 0;  /* init byte counter */
  70.   
  71.   /* Get a TCP socket to use for data connection listen*/
  72.   hLstnSock = socket (AF_INET, SOCK_STREAM, 0);
  73.   if (hLstnSock == INVALID_SOCKET)  {
  74.     WSAperror(WSAGetLastError(), "socket()", hInst);
  75.   } else {
  76.     /* Request async notification for most events */
  77.     nRet = WSAAsyncSelect(hLstnSock, hDlg, nAsyncMsg, 
  78.            (FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE));
  79.     if (nRet == SOCKET_ERROR) {
  80.       WSAperror(WSAGetLastError(), "WSAAsyncSelect()", hInst);
  81.     } else {
  82.                    
  83.       /* Name the local socket with bind() */
  84.       lpstName->sin_family = PF_INET;
  85.       lpstName->sin_port   = 0;  /* any port will do */
  86.       nRet = bind(hLstnSock,(LPSOCKADDR)lpstName,SOCKADDR_LEN);
  87.       if (nRet == SOCKET_ERROR) {
  88.     WSAperror(WSAGetLastError(), "bind()", hInst);
  89.       } else {
  90.         
  91.         /* Get local port number assigned by bind() */
  92.         nRet = getsockname(hLstnSock,(LPSOCKADDR)lpstName, 
  93.             (int FAR *)&nLen);
  94.         if (nRet == SOCKET_ERROR) {
  95.       WSAperror(WSAGetLastError(), "getsockname()", hInst);
  96.         } else {
  97.           /* Listen for incoming connection requests */
  98.           nRet = listen(hLstnSock, 5);
  99.           if (nRet == SOCKET_ERROR) {
  100.         WSAperror(WSAGetLastError(), "listen()", hInst);
  101.           }
  102.         }
  103.       }
  104.     }
  105.     /* If we haven't had an error but we still don't know the local 
  106.      *  IP address, then we need to try to get it before we return */
  107.     if (!lpstName->sin_addr.s_addr) {
  108.       lpstName->sin_addr.s_addr = GetHostID();
  109.       if (!lpstName->sin_addr.s_addr) {
  110.         MessageBox (hDlg, "Can't get local IP address", 
  111.           "InitDataConn() Failed", MB_OK | MB_ICONASTERISK);
  112.         nRet = SOCKET_ERROR;
  113.       }
  114.     }
  115.     /* If we had an error or we still don't know our IP address, 
  116.      *  then we have a problem.  Clean up */
  117.     if (nRet == SOCKET_ERROR) {
  118.   closesocket(hLstnSock);
  119.   hLstnSock = INVALID_SOCKET;
  120.     }
  121.   }
  122.   return (hLstnSock);
  123. } /* end InitDataConn() */
  124. /*--------------------------------------------------------------
  125.  * Function: AcceptDataConn()
  126.  *
  127.  * Description: Accept an incoming data connection
  128.  */
  129. SOCKET AcceptDataConn(SOCKET hLstnSock, PSOCKADDR_IN pstName)
  130. {
  131.   SOCKET hDataSock;
  132.   int nRet, nLen = SOCKADDR_LEN, nOptval;
  133.   
  134.   if (bDebug) {
  135.     wsprintf(achTempBuf, 
  136.       "AcceptDataConn() Qlen:%d Cmd[0]:%d [1]:%d [2]:%d [3]:%d, State:%dn", 
  137.       nQLen, astFtpCmd[0].nFtpCmd, astFtpCmd[1].nFtpCmd,
  138.       astFtpCmd[2].nFtpCmd, astFtpCmd[3].nFtpCmd, nAppState);
  139.     OutputDebugString (achTempBuf);    
  140.   }
  141.   hDataSock = accept (hLstnSock, (LPSOCKADDR)pstName, (LPINT)&nLen);
  142.   if (hDataSock == SOCKET_ERROR) {
  143.     int WSAErr = WSAGetLastError();
  144.     if (WSAErr != WSAEWOULDBLOCK)
  145.       WSAperror (WSAErr, "accept", hInst);
  146.   } else if (bReAsync) {
  147.     /* This SHOULD be unnecessary, since all new sockets are supposed
  148.      *  to inherit properties of the listening socket (like all the
  149.      *  asynch events registered but some WinSocks don't do this.
  150.      * Request async notification for most events */
  151.     nRet = WSAAsyncSelect(hDataSock, hWinMain, WSA_ASYNC+1, 
  152.            (FD_READ | FD_WRITE | FD_CLOSE));
  153.     if (nRet == SOCKET_ERROR) {
  154.       WSAperror(WSAGetLastError(), "WSAAsyncSelect()", hInst);
  155.     }
  156.     /* Try to get lots of buffer space */
  157.     nOptval = astFtpCmd[0].nFtpCmd==STOR ? SO_SNDBUF : SO_RCVBUF;
  158.     GetBuf(hDataSock, INPUT_SIZE*2, nOptval);
  159.   }
  160.   return (hDataSock);
  161. } /* end AcceptData() */
  162. /*--------------------------------------------------------------
  163.  * Function: SendData()
  164.  *
  165.  * Description: Open data file, read and send
  166.  */
  167. long SendData(SOCKET *hDataSock, HFILE hDataFile, int len)
  168. {
  169.   static int cbReadFromFile;         /* bytes read from file */
  170.   static int cbSentToServer;         /* number of buffered bytes sent */
  171.   static HFILE hLastFile;            /* handle of last file sent */
  172.   long cbTotalSent = 0;              /* total bytes sent */
  173.   int nRet, WSAErr, cbBytesToSend;
  174.   /* Reset our counters when we access a new file */
  175.   if (hLastFile != hDataFile) {
  176.     cbReadFromFile = 0;
  177.     cbSentToServer = 0;
  178.     hLastFile = hDataFile;
  179.   }
  180.     
  181.   /* Read data from file, and send it. */
  182.   do {
  183.     if (bIOBeep)
  184.       MessageBeep(0xFFFF);
  185.     /* calculate what's left to send */
  186.     cbBytesToSend = cbReadFromFile - cbSentToServer; 
  187.     if (cbBytesToSend <= 0) {
  188.     
  189.       /* read data from input file, if we need it */
  190.       if (!bFromNul) {
  191.         cbReadFromFile = _lread(hDataFile, achOutBuf, INPUT_SIZE);
  192.         if (cbReadFromFile == HFILE_ERROR) {
  193.           MessageBox (hWinMain, "Error reading data file", 
  194.             "SendData() Failed", MB_OK | MB_ICONASTERISK);
  195.           break;
  196.         } else if (!cbReadFromFile){
  197.           /* EOF: no more data to send */
  198.           CloseFtpConn(hDataSock, (PSTR)0, 0, hWinMain);
  199.           EndData();
  200.           break;
  201.         } else {
  202.           cbBytesToSend = cbReadFromFile; /* send as much as we read */
  203.         } 
  204.       } else {
  205.         /* just send whatever's in memory (up to our max) */
  206.         if (lByteCount < MAXNULPUT) {
  207.           cbBytesToSend = INPUT_SIZE;
  208.         } else {
  209.           CloseFtpConn(hDataSock, (PSTR)0, 0, hWinMain);
  210.           EndData();
  211.         }
  212.       }
  213.       cbSentToServer = 0;  /* reset tally */
  214.     }
  215.     /* Send data to server */
  216.     nRet = send (*hDataSock, &(achOutBuf[cbSentToServer]), 
  217.                 ((len < cbBytesToSend) ? len : cbBytesToSend), 0);
  218.     if (nRet == SOCKET_ERROR) {
  219.       WSAErr = WSAGetLastError();
  220.       /* Display significant errors */
  221.       if (WSAErr != WSAEWOULDBLOCK)
  222.         WSAperror(WSAErr, (LPSTR)"send()", hInst);
  223.     } else {
  224.       /* Update byte counter, and display. */
  225.       lByteCount += nRet;
  226.       _ltoa(lByteCount, achTempBuf, 10);
  227.       SetDlgItemText(hWinMain, IDC_DATA_RATE, achTempBuf);
  228.       cbSentToServer += nRet;/* tally bytes sent since last file read */
  229.       cbTotalSent    += nRet;/* tally total bytes sent since we started */
  230.     }
  231.   } while (nRet != SOCKET_ERROR);
  232.   return (cbTotalSent);
  233. } /* end SendData() */
  234. /*--------------------------------------------------------------
  235.  * Function: RecvData()
  236.  *
  237.  * Description: Receive data from net and write to open data file 
  238.  */
  239. int RecvData(SOCKET hDataSock, HFILE hDataFile, LPSTR achInBuf, int len)
  240. {
  241.   static HFILE hLastFile;          /* handle of last file sent */
  242.   static int cbBytesBuffered;      /* total bytes received */
  243.   int cbBytesRcvd = 0;
  244.   int nRet=0, WSAErr;
  245.    if (hDataFile != hLastFile) {
  246.       hLastFile = hDataFile;
  247.       cbBytesBuffered = 0; 
  248.    }
  249.                                                        
  250.   /* Read as much as we can from server */
  251.     while (cbBytesBuffered < len) {
  252.       nRet = recv (hDataSock,&(achInBuf[cbBytesBuffered]), 
  253.         len-cbBytesBuffered, 0);
  254.       if (nRet == SOCKET_ERROR) {
  255.         WSAErr = WSAGetLastError();
  256.         /* Display significant errors */
  257.         if (WSAErr != WSAEWOULDBLOCK)
  258.           WSAperror(WSAErr, (LPSTR)"recv()", hInst);
  259.         /* exit recv() loop on any error */
  260.           goto recv_end;
  261.       } else if (nRet == 0) { /* Other side closed socket */
  262.         /* quit if server closed connection */
  263.         goto recv_end;
  264.           
  265.       } else {
  266.         /* Update byte counter, and display */
  267.         lByteCount += nRet;
  268.         _ltoa(lByteCount, achTempBuf, 10);
  269.         SetDlgItemText(hWinMain, IDC_DATA_RATE, achTempBuf);
  270.         cbBytesRcvd += nRet;     /* tally bytes read */
  271.         cbBytesBuffered += nRet;
  272.       }
  273.     }
  274. recv_end:
  275.   if (!bToNul && 
  276.       ((cbBytesBuffered > (len-MTU_SIZE)) || 
  277.        ((nRet == SOCKET_ERROR) && WSAGetLastError() != WSAEWOULDBLOCK) || 
  278.        (nRet == 0))) {
  279.     /* If we have a lot buffered, write to data file */
  280.     nRet = _lwrite(hDataFile, achInBuf, cbBytesBuffered);
  281.     if (nRet == HFILE_ERROR)
  282.       MessageBox (hWinMain, "Can't write to local file", 
  283.         "RecvData() Failed", MB_OK | MB_ICONASTERISK);
  284.     cbBytesBuffered = 0;
  285.   } else if (bToNul)
  286.     cbBytesBuffered = 0;
  287.   return (cbBytesRcvd);
  288. } /* end RecvData() */
  289. /*--------------------------------------------------------------
  290.  * Function: EndData()
  291.  *
  292.  * Description: Close up the data connection
  293.  */
  294. void EndData (void) {
  295.   LONG dByteRate;
  296.   LONG lMSecs;
  297.   /* Calculate data transfer rate, and display */
  298.   lMSecs = (LONG) GetTickCount() - lStartTime;
  299.   if (lMSecs <= 55)
  300.     lMSecs = 27;  /* about half of 55Msec PC clock resolution */
  301.               
  302.   /* Socket Check should not be necessary, but some WinSocks            
  303.    *  mistakenly post FD_CLOSE to listen socket after close */
  304.   nAppState &= ~(DATACONNECTED);
  305.   SetDlgItemText (hWinMain, IDC_STATUS, "Status: connected");
  306.             
  307.   if (lByteCount > 0L) {
  308.     dByteRate = (lByteCount/lMSecs); /* data rate (bytes/Msec) */
  309.     wsprintf (achTempBuf,"%ld bytes %s in %ld.%ld seconds (%ld.%ld Kbytes/sec)",
  310.       lByteCount, 
  311.       ((astFtpCmd[0].nFtpCmd==STOR) ? "sent":"received"),
  312.       lMSecs/1000, lMSecs%1000, 
  313.       (dByteRate*1000)/1024, (dByteRate*1000)%1024);
  314.     SetDlgItemText (hWinMain, IDC_DATA_RATE, achTempBuf);
  315.     if (hLogFile != HFILE_ERROR)
  316.       _lwrite (hLogFile, achTempBuf, strlen(achTempBuf));
  317.   }
  318.   lStartTime = 0L;
  319.   if (hDataFile != HFILE_ERROR) {
  320.     _lclose (hDataFile);
  321.     hDataFile = HFILE_ERROR;
  322.     if (astFtpCmd[0].nFtpCmd == LIST) {
  323.       wsprintf (achTempBuf, "notepad %s", szTempFile);
  324.       WinExec (achTempBuf, SW_SHOW);
  325.     }
  326.   }
  327.   astFtpCmd[0].nFtpCmd = 0;  /* reset pending command */
  328. } /* end EndData() */