// cwinsock.h : header file
//           

#ifndef __CWINSOCK_H__
#define __CWINSOCK_H__

#include <winsock.h>

// return values for most member functions
#define CWINSOCK_NOERROR            (0)
#define CWINSOCK_WINDOWS_ERROR      (1)
#define CWINSOCK_WINSOCK_ERROR      (2)
#define CWINSOCK_PROGRAMMING_ERROR  (3)

// message to be posted to the socket window for async events
#define CWINSOCK_EVENT_NOTIFICATION (WM_USER + 1)

// wParam of messages sent to application windows
#define CWINSOCK_DONE_WRITING               (1) // lParam = pointer to data
#define CWINSOCK_ERROR_WRITING              (2) // lParam = pointer to data
#define CWINSOCK_DONE_READING               (3) // lParam = # data chunks in queue
#define CWINSOCK_ERROR_READING              (4)
#define CWINSOCK_READY_TO_ACCEPT_CONNECTION (5)
#define CWINSOCK_YOU_ARE_CONNECTED          (6)
#define CWINSOCK_LOST_CONNECTION            (7)

// buffer sizes
#define READ_BUF_LEN (1000)

// structure used for datagram socket read/write queue
typedef struct tagDATAGRAMDATA
{
  LPVOID      pData;
  int         nLen;
  SOCKADDR_IN sin;
} DATAGRAMDATA, FAR * LPDATAGRAMDATA;

// structure used for stream socket read/write queue
typedef struct tagSTREAMDATA
{
  LPVOID pData;
  int    nLen;
} STREAMDATA, FAR * LPSTREAMDATA;

/////////////////////////////////////////////////////////////////////////////
// CWinSock
//
class CWinSock
{
private:
  WORD m_wVersionRequired;   // WinSock version required by application
  int m_nLastError;          // last WinSock error
  WSADATA m_wsaData;         // WinSock information

public:
  CWinSock(WORD wVersionRequired = MAKEWORD(1, 1));
  int Startup();
  int Shutdown();
  void Information(LPWSADATA pwsaData);
  int LastError() { return m_nLastError; }
};

/////////////////////////////////////////////////////////////////////////////
// CDatagramSocket
//
class CDatagramSocket : public CWnd
{
private:
  CWnd *m_pParentWnd;      // window to receive event notification
  UINT m_uMsg;             // message to send to m_pParentWnd on event
  SOCKET m_s;              // socket handle
  SOCKADDR_IN m_sinLocal;  // name bound to socket m_s
  int m_nLastError;        // last WinSock error
  BOOL m_bServer;          // TRUE if socket m_s is bound to a name
  CPtrList m_listWrite;    // data waiting to be sent
  CPtrList m_listRead;     // data read

public:
  CDatagramSocket(CWnd *pParentWnd, UINT uMsg);
  virtual ~CDatagramSocket();
  int CreateSocket(int nLocalPort);
  int CreateSocket(LPSTR pszLocalService = NULL);
  int DestroySocket();
  int Write(int nLen, LPVOID pData, LPSTR pszRemoteName, int nRemotePort);
  int Write(int nLen, LPVOID pData, LPSTR pszRemoteName, LPSTR pszRemoteService);
  int Write(int nLen, LPVOID pData, LPSOCKADDR_IN psinRemote);
  LPVOID Read(LPINT pnLen, LPSOCKADDR_IN psinRemote = NULL);
  int LastError() { return m_nLastError; }

private:
  void InitVars(BOOL bInitLastError = TRUE);
  LONG HandleRead(WPARAM wParam, LPARAM lParam);
  LONG HandleWrite(WPARAM wParam, LPARAM lParam);

  // message map functions
protected:
  //{{AFX_MSG(CStreamSocket)
  //}}AFX_MSG
  LONG OnWinSockEvent(WPARAM wParam, LPARAM lParam);
  DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////
// CStreamSocket
//
class CStreamSocket : public CWnd
{
private:
  CWnd *m_pParentWnd;      // window to receive event notification
  UINT m_uMsg;             // message to send to m_pParentWnd on event
  SOCKET m_s;              // socket handle
  SOCKADDR_IN m_sinLocal;  // name bound to socket m_s
  SOCKADDR_IN m_sinRemote; // name on other side of m_s
  int m_nLastError;        // last WinSock error
  BOOL m_bServer;          // TRUE if socket m_s is bound to a name
  CPtrList m_listWrite;    // data waiting to be sent
  CPtrList m_listRead;     // data read

public:
  CStreamSocket(CWnd *pParentWnd, UINT uMsg);
  virtual ~CStreamSocket();
  int CreateSocket(int nLocalPort);
  int CreateSocket(LPSTR pszLocalService = NULL);
  int DestroySocket();
  int Connect(LPSTR pszRemoteName, int nRemotePort);
  int Connect(LPSTR pszRemoteName, LPSTR pszRemoteService);
  int Connect(LPSOCKADDR_IN psinRemote);
  int Accept(CStreamSocket *pStreamSocket);
  int Write(int nLen, LPVOID pData);
  LPVOID Read(LPINT pnLen);
  int GetPeerName(LPSOCKADDR_IN psinRemote);
  int LastError() { return m_nLastError; }

private:
  void InitVars(BOOL bInitLastError = TRUE);
  LONG HandleRead(WPARAM wParam, LPARAM lParam);
  LONG HandleWrite(WPARAM wParam, LPARAM lParam);

  // message map functions
protected:
  //{{AFX_MSG(CStreamSocket)
  //}}AFX_MSG
  LONG OnWinSockEvent(WPARAM wParam, LPARAM lParam);
  DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////
// CWinSockErrorBox
//
void CWinSockErrorBox(int nError, LPSTR pszMessage = NULL);

#endif // __CWINSOCK_H__
