Click here to Skip to main content
15,896,727 members
Articles / Desktop Programming / MFC

FTP Client Class

Rate me:
Please Sign up or sign in to vote.
4.85/5 (80 votes)
8 Dec 2012CPOL4 min read 780.5K   48.2K   246  
A non-MFC class to encapsulate the FTP protocol.
////////////////////////////////////////////////////////////////////////////////
//
// From David J. Kruglinski (Inside Visual C++).
//
////////////////////////////////////////////////////////////////////////////////

// removed baseclass CObject
// removed baseclass CException
// removed all LPCTSTR LPTSTR
// _select only defined to avoid compiler warning in WIN32
// make it run on linux

#ifndef INC_BLOCKINGSOCKET_H
#define INC_BLOCKINGSOCKET_H

#include <string>
#include <string.h>
#include <memory>
#include "Definements.h"

#ifdef WIN32
   #ifdef _WINSOCKAPI_
      #ifndef _WINSOCK2API_
      // NOTICE: In Microsoft Visual Studio you can add the header 'winsock2.h" to 
      //         "Configuration --> Properties --> C/C++ --> Advanced --> Forced Include File"
      #pragma message("\nIt is recommended to include 'winsock2.h' instead of 'winsock.h'\n")
      #endif
   #else
      #include <winsock2.h>
   #endif
#elif defined(unix)
   #include <sys/socket.h>
   #include <arpa/inet.h>   // needed for inet_ntoa and inet_addr
   #include <netdb.h>       // needed for gethostbyname and gethostbyaddr
   #include <errno.h>
#endif

namespace nsSocket
{

#ifdef WIN32
   typedef int socklen_t;
   inline int _select(UINT_PTR /*nfds*/, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout)
   {
      // The nfds parameter is ignored in windows (included only for 
      // compatibility with Berkeley sockets).
      return select(0, readfds, writefds, exceptfds, timeout);
   }
#elif defined(unix)
   typedef unsigned int SOCKET;
   typedef sockaddr SOCKADDR;
   typedef sockaddr* LPSOCKADDR;
   typedef sockaddr_in SOCKADDR_IN;
   typedef sockaddr_in* LPSOCKADDR_IN;
   typedef timeval TIMEVAL;
   #define SOCKET_ERROR   (-1) 
   #define INVALID_SOCKET (SOCKET)(~0)
   #define closesocket close 
   #define WSAGetLastError() errno
   #define WSAEINTR EINTR
   inline int _select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval *__restrict timeout)
   {
      return select(nfds, readfds, writefds, exceptfds, timeout);
   }
#endif   

   typedef const struct sockaddr* LPCSOCKADDR;

///////////////////////////////////////////////////////////////////////////////////////
//***************************** CBlockingSocketException  ***************************//
///////////////////////////////////////////////////////////////////////////////////////
class CBlockingSocketException
{
public:
   // Constructor
   CBlockingSocketException(LPCTSTR pchMessage);
   virtual ~CBlockingSocketException() {}
   
   virtual bool GetErrorMessage(LPTSTR lpstrError, UINT nMaxError, PUINT pnHelpContext = NULL);
   virtual tstring GetErrorMessage(PUINT pnHelpContext = NULL);
   
private:
   int     m_nError;
   tstring m_strMessage;
};

///////////////////////////////////////////////////////////////////////////////////////
//*********************************** CSockAddr  ************************************//
///////////////////////////////////////////////////////////////////////////////////////
class CSockAddr : public sockaddr_in
{
public:
   // constructors
   CSockAddr()
   {
      sin_family        = AF_INET; // specifies address family
      sin_port          = 0;       // ip port
      sin_addr.s_addr   = 0;       // ip address
   }
   
   CSockAddr(const SOCKADDR& sa)
            { memcpy(this, &sa, sizeof(SOCKADDR)); }
   
   CSockAddr(const SOCKADDR_IN& sin) 
            { memcpy(this, &sin, sizeof(SOCKADDR_IN)); }
   
   CSockAddr(ULONG ulAddr, USHORT ushPort = 0) // parms are host byte ordered
            { 
               sin_family      = AF_INET;          // specifies address family
               sin_port        = htons(ushPort);   // ip port
               sin_addr.s_addr = htonl(ulAddr);    // ip address
            }
   
   CSockAddr(const char* pchIP, USHORT ushPort = 0) // dotted IP addr string
            { 
               sin_family = AF_INET;               // specifies address family
               sin_port = htons(ushPort);          // ip port
               sin_addr.s_addr = inet_addr(pchIP); // ip address
            } // already network byte ordered
   
   // Return the address in dotted-decimal format
   tstring DottedDecimal()
      { return nsHelper::CCnv::ConvertToTString(inet_ntoa(sin_addr)); }

   // Get port and address (even though they're public)
   USHORT Port() const
            { return ntohs(sin_port); }
   
   ULONG IPAddr() const
            { return ntohl(sin_addr.s_addr); }
   
   // operators added for efficiency
   CSockAddr& operator=(const SOCKADDR& sa)
            {
               memcpy(this, &sa, sizeof(SOCKADDR));
               return *this;
            }

   CSockAddr& operator=(const SOCKADDR_IN& sin)
            { 
               memcpy(this, &sin, sizeof(SOCKADDR_IN));
               return *this; 
            }

   operator SOCKADDR()
            { return *((LPSOCKADDR) this); }

   operator LPSOCKADDR()
            { return (LPSOCKADDR) this; }

   operator LPSOCKADDR_IN()
            { return (LPSOCKADDR_IN) this; }
};

///////////////////////////////////////////////////////////////////////////////////////
//********************************* CBlockingSocket  ********************************//
///////////////////////////////////////////////////////////////////////////////////////

class IBlockingSocket
{
public:
   virtual ~IBlockingSocket() {};
   virtual IBlockingSocket* CreateInstance() const = 0;
   virtual void Create(int nType = SOCK_STREAM) = 0;
   virtual void Connect(LPCSOCKADDR psa) const = 0;
   virtual void Bind(LPCSOCKADDR psa) const = 0;
   virtual void Listen() const = 0;
   virtual void Cleanup() = 0;
   virtual bool Accept(IBlockingSocket& s, LPSOCKADDR psa) const = 0;
   virtual void Close() = 0;
   virtual int  Write(const char* pch, int nSize, int nSecs) const = 0;
   virtual int  Receive(char* pch, int nSize, int nSecs) const = 0;
   virtual void GetPeerAddr(LPSOCKADDR psa) const = 0;
   virtual void GetSockAddr(LPSOCKADDR psa) const = 0;
   virtual operator SOCKET() const = 0;
   virtual bool CheckReadability() const = 0;
   virtual CSockAddr   GetHostByName(const char* pchName, USHORT ushPort = 0) = 0;
   virtual const char* GetHostByAddr(LPCSOCKADDR psa) = 0;
};

// member functions truly block and must not be used in UI threads
// use this class as an alternative to the MFC CSocket class
class CBlockingSocket : public IBlockingSocket
{
public:
   CBlockingSocket();
   virtual ~CBlockingSocket();

   virtual IBlockingSocket* CreateInstance() const;

   void Cleanup();
   void Create(int nType = SOCK_STREAM);
   void Close();

   void Bind(LPCSOCKADDR psa) const;
   void Listen() const;
   void Connect(LPCSOCKADDR psa) const;
   bool Accept(IBlockingSocket& s, LPSOCKADDR psa) const;
   int  Send(const char* pch, int nSize, int nSecs) const;
   int  Write(const char* pch, int nSize, int nSecs) const;
   int  Receive(char* pch, int nSize, int nSecs) const;
   int  SendDatagram(const char* pch, int nSize, LPCSOCKADDR psa, int nSecs) const;
   int  ReceiveDatagram(char* pch, int nSize, LPSOCKADDR psa, int nSecs) const;
   void GetPeerAddr(LPSOCKADDR psa) const;
   void GetSockAddr(LPSOCKADDR psa) const;
   bool CheckReadability() const;

   CSockAddr   GetHostByName(const char* pchName, USHORT ushPort = 0);
   const char* GetHostByAddr(LPCSOCKADDR psa);

   operator SOCKET() const { return m_hSocket; }

private:
   SOCKET m_hSocket;
};

std::auto_ptr<IBlockingSocket> CreateDefaultBlockingSocketInstance();

///////////////////////////////////////////////////////////////////////////////////////
//******************************** CHttpBlockingSocket ******************************//
///////////////////////////////////////////////////////////////////////////////////////
class CHttpBlockingSocket : public CBlockingSocket
{
public:
   enum {nSizeRecv = 1000}; // max receive buffer size (> hdr line length)

   CHttpBlockingSocket();
   ~CHttpBlockingSocket();

   int ReadHttpHeaderLine(char* pch, int nSize, int nSecs);
   int ReadHttpResponse(char* pch, int nSize, int nSecs);

private:
   char*  m_pReadBuf; // read buffer
   int    m_nReadBuf; // number of bytes in the read buffer
};

}

#endif // INC_BLOCKINGSOCKET_H

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions