home *** CD-ROM | disk | FTP | other *** search
- // cwinsock.cpp : implementation file
- //
-
- #include "afxwin.h"
- #include "afxext.h"
- #include <memory.h>
- #include <stdlib.h>
- #include "cwinsock.h"
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char BASED_CODE THIS_FILE[] = __FILE__;
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
- // CWinSock
- /////////////////////////////////////////////////////////////////////////////
-
- /////////////////////////////////////////////////////////////////////////////
- // CWinSock constructor
- //
- // Constructs the CWinSock object. Initializes member variables
- //
- CWinSock::CWinSock(WORD wVersionRequired/*= MAKEWORD(1, 1)*/)
- {
- // initialize member variables
- m_wVersionRequired = wVersionRequired;
- m_nLastError = 0;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CWinSock::Startup()
- //
- // Start the WinSock sub-system.
- //
- int CWinSock::Startup()
- {
- int nStatus = CWINSOCK_NOERROR;
-
- m_nLastError = WSAStartup(m_wVersionRequired, &m_wsaData);
-
- if (m_nLastError != 0)
- nStatus = CWINSOCK_WINSOCK_ERROR;
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CWinSock::Shutdown()
- //
- // Shutdown the WinSock sub-system.
- //
- int CWinSock::Shutdown()
- {
- int nStatus = CWINSOCK_NOERROR;
-
- if (WSACleanup() != 0)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- }
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CWinSock::Information()
- //
- // Copy the WinSock information structure.
- //
- void CWinSock::Information(LPWSADATA pwsaData)
- {
- memcpy(pwsaData, &m_wsaData, sizeof(WSADATA));
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket
- /////////////////////////////////////////////////////////////////////////////
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket constructor
- //
- // Constructs the CDatagramSocket object. Initializes member variables
- //
- CDatagramSocket::CDatagramSocket(CWnd *pParentWnd, UINT uMsg)
- {
- // initialize member variables
- m_pParentWnd = pParentWnd;
- ASSERT(m_pParentWnd != NULL);
- m_uMsg = uMsg;
- ASSERT(m_uMsg != 0);
- InitVars();
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket destructor
- //
- CDatagramSocket::~CDatagramSocket()
- {
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::InitVars()
- //
- // Initialize class member variables.
- //
- void CDatagramSocket::InitVars(BOOL bInitLastError/*= TRUE*/)
- {
- if (bInitLastError)
- m_nLastError = 0;
-
- m_s = INVALID_SOCKET;
- memset(&m_sinLocal, 0, sizeof(SOCKADDR_IN));
- m_bServer = FALSE;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::CreateSocket()
- //
- // Create a hidden window that will receive asynchronous messages
- // from WinSock. Also creates a socket and optionally binds it to
- // a name if the socket is a server socket.
- //
- // This version of the CreateSocket() function takes a
- // port number, in host order, as input. A port number
- // should only be specified if the socket is to be bound
- // to a certain port. If you don't care which port is
- // assigned to the socket, just call CreateSocket() without
- // any parameter, causing CreateSocket(NULL) to be called.
- //
- int CDatagramSocket::CreateSocket(int nLocalPort)
- {
- // if this version of the function is being called,
- // a valid port number must be specified
- if (nLocalPort <= 0)
- return CWINSOCK_PROGRAMMING_ERROR;
-
- // convert the port number into a string and
- // call the version of CreateSocket() which
- // accepts a string
- char pszLocalService[18];
- _itoa(nLocalPort, pszLocalService, 10);
- return CreateSocket(pszLocalService);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::CreateSocket()
- //
- // Create a hidden window that will receive asynchronous messages
- // from WinSock. Also creates a socket and optionally binds it to
- // a name if the socket is a server socket.
- //
- // This version of the CreateSocket() function takes a
- // string containing a service name or port number.
- // A parameter should only be specified if the socket is to be
- // bound to a certain port. If you don't care which port is
- // assigned to the socket, just call CreateSocket() without
- // any parameter, causing CreateSocket(NULL) to be called.
- //
- int CDatagramSocket::CreateSocket(LPSTR pszLocalService/*= NULL*/)
- {
- int nStatus = CWINSOCK_NOERROR;
-
- while (1)
- {
- // Make sure the socket isn't already created.
- // If the socket handle is valid, return from this
- // function right away so the existing parameters of
- // the object are not tampered with.
- if (m_s != INVALID_SOCKET)
- return CWINSOCK_PROGRAMMING_ERROR;
-
- InitVars();
-
- // create the hidden window
- RECT rect;
- rect.left = 0;
- rect.top = 0;
- rect.right = 100;
- rect.bottom = 100;
- if (Create(NULL, NULL, WS_OVERLAPPEDWINDOW, rect, m_pParentWnd, 0) == 0)
- {
- nStatus = CWINSOCK_WINDOWS_ERROR;
- break;
- }
-
- // create the socket
- m_s = socket(PF_INET, SOCK_DGRAM, 0);
- if (m_s == INVALID_SOCKET)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- DestroyWindow();
- break;
- }
-
- // If pszLocalService is not NULL, this is a server socket
- // that will accept data on the specified port.
- if (pszLocalService != NULL)
- {
- // this socket is bound to a port number
- // so set the server flag
- m_bServer = TRUE;
-
- // assign the address family
- m_sinLocal.sin_family = AF_INET;
-
- // assign the service port (may have to do a database lookup
- // if a service port number was not specified)
- m_sinLocal.sin_port = htons(atoi(pszLocalService));
- if (m_sinLocal.sin_port == 0)
- {
- LPSERVENT pSent = getservbyname(pszLocalService, "udp");
- if (pSent == NULL)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- closesocket(m_s);
- DestroyWindow();
- break;
- }
- m_sinLocal.sin_port = pSent->s_port;
- }
-
- // assign the IP address
- m_sinLocal.sin_addr.s_addr = htonl(INADDR_ANY);
-
- // bind the server socket to the name containing the port
- if (bind(m_s, (LPSOCKADDR)&m_sinLocal, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- closesocket(m_s);
- DestroyWindow();
- break;
- }
- }
-
- // start asynchronous event notification
- long lEvent = FD_READ | FD_WRITE;
- if (WSAAsyncSelect(m_s, m_hWnd, CWINSOCK_EVENT_NOTIFICATION, lEvent) ==
- SOCKET_ERROR)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- closesocket(m_s);
- DestroySocket();
- break;
- }
-
- break;
- }
-
- // if anything failed in this function, set the
- // socket variables appropriately
- if (nStatus != CWINSOCK_NOERROR)
- InitVars(FALSE);
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::DestroySocket()
- //
- // Close the socket, remove any queued data,
- // and destroy the hidden window.
- //
- int CDatagramSocket::DestroySocket()
- {
- int nStatus = CWINSOCK_NOERROR;
-
- // make sure the socket is valid
- if (m_s == INVALID_SOCKET)
- nStatus = CWINSOCK_PROGRAMMING_ERROR;
- else
- {
- // remove any data in the write queue
- while (!m_listWrite.IsEmpty())
- {
- LPDATAGRAMDATA pDatagramData = (LPDATAGRAMDATA)m_listWrite.RemoveHead();
- LPVOID pData = pDatagramData->pData;
- delete pDatagramData;
-
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_WRITING,
- (LPARAM)pData);
- }
-
- // remove any data in the read queue
- while (!m_listRead.IsEmpty())
- {
- LPDATAGRAMDATA pDatagramData = (LPDATAGRAMDATA)m_listRead.RemoveHead();
- free(pDatagramData->pData);
- delete pDatagramData;
- }
-
- // close the socket and initialize variables
- closesocket(m_s);
- InitVars();
-
- // destroy the hidden window
- DestroyWindow();
- }
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::Write()
- //
- // Write data to the socket specified by the name and port.
- //
- // This version of the Write() function takes an integer
- // representing the length of the data to send, a pointer
- // to the data to send, a pointer to a string representing
- // the host name to send the data to, and an integer
- // representing the port number to send to.
- //
- // The data pointed to by pData must remain valid until either
- // the Write() function returns with an error, or the
- // write's completion is notified by the m_uMsg being sent
- // to the window that owns this datagram object with wParam set
- // to CWINSOCK_DONE_WRITING or CWINSOCK_ERROR_WRITING.
- //
- int CDatagramSocket::Write(int nLen, LPVOID pData,
- LPSTR pszRemoteName, int nRemotePort)
- {
- // convert the port number into a string and
- // call the version of Write() which accepts
- // a string service name or number
- char pszRemoteService[18];
- _itoa(nRemotePort, pszRemoteService, 10);
- return Write(nLen, pData, pszRemoteName, pszRemoteService);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::Write()
- //
- // Write data to the socket specified by the name and service
- // name or number.
- //
- // This version of the Write() function takes an integer
- // representing the length of the data to send, a pointer
- // to the data to send, a pointer to a string representing
- // the host name to send the data to, and a string representing
- // the service name or port number to send the data to.
- //
- // The data pointed to by pData must remain valid until either
- // the Write() function returns with an error, or the
- // write's completion is notified by the m_uMsg being sent
- // to the window that owns this datagram object with wParam set
- // to CWINSOCK_DONE_WRITING or CWINSOCK_ERROR_WRITING.
- //
- int CDatagramSocket::Write(int nLen, LPVOID pData,
- LPSTR pszRemoteName, LPSTR pszRemoteService)
- {
- int nStatus = CWINSOCK_NOERROR; // error status
- LPHOSTENT pHent; // pointer to host entry structure
- LPSERVENT pSent; // pointer to service entry structure
- SOCKADDR_IN sinRemote; // Internet address of destination
-
- while (1)
- {
- // assign the address family
- sinRemote.sin_family = AF_INET;
-
- // assign the service port (may have to do a database lookup
- // if a service port number was not specified)
- sinRemote.sin_port = htons(atoi(pszRemoteService));
- if (sinRemote.sin_port == 0)
- {
- pSent = getservbyname(pszRemoteService, "udp");
- if (pSent == NULL)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- break;
- }
- sinRemote.sin_port = pSent->s_port;
- }
-
- // assign the IP address (may have to do a database lookup
- // if a dotted decimal IP address was not specified)
- sinRemote.sin_addr.s_addr = inet_addr(pszRemoteName);
- if (sinRemote.sin_addr.s_addr == INADDR_NONE)
- {
- pHent = gethostbyname(pszRemoteName);
- if (pHent == NULL)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- break;
- }
- sinRemote.sin_addr.s_addr = *(u_long *)pHent->h_addr;
- }
-
- // call the version of Write() that takes an
- // Internet address structure
- return Write(nLen, pData, &sinRemote);
- }
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::Write()
- //
- // Write data to the socket specified by the Internet address.
- //
- // This version of the Write() function takes an integer
- // representing the length of the data to send, a pointer
- // to the data to send, and a pointer to an Internet address
- // structure to send the data to.
- //
- // The data pointed to by pData must remain valid until either
- // the Write() function returns with an error, or the
- // write's completion is notified by the m_uMsg being sent
- // to the window that owns this datagram object with wParam set
- // to CWINSOCK_DONE_WRITING or CWINSOCK_ERROR_WRITING.
- //
- int CDatagramSocket::Write(int nLen, LPVOID pData, LPSOCKADDR_IN psinRemote)
- {
- int nStatus = CWINSOCK_NOERROR;
-
- while (1)
- {
- // dynamically allocate a structure to hold the
- // data pointer, the data's length, and the destination address
- LPDATAGRAMDATA pDatagramData = new DATAGRAMDATA;
- if (pDatagramData == NULL)
- {
- nStatus = CWINSOCK_WINDOWS_ERROR;
- break;
- }
- pDatagramData->pData = pData;
- pDatagramData->nLen = nLen;
- memcpy(&(pDatagramData->sin), psinRemote, sizeof(SOCKADDR_IN));
-
- // add the data to the list
- TRY
- {
- m_listWrite.AddTail(pDatagramData);
- }
- CATCH (CMemoryException, e)
- {
- nStatus = CWINSOCK_WINDOWS_ERROR;
- break;
- }
- END_CATCH
-
- // trigger the FD_WRITE handler to try to send
- PostMessage(CWINSOCK_EVENT_NOTIFICATION, m_s, WSAMAKESELECTREPLY(FD_WRITE, 0));
- break;
- }
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::Read()
- //
- // Read data that has been received by the socket.
- //
- // This function takes a pointer to an integer that will be filled
- // with the length of the data read and an optional pointer
- // to an Internet address structure that will be filled with
- // the address of the sender of the data.
- //
- // A pointer to the data is returned on success. The application
- // using this object must free this pointer. NULL is returned on failure.
- //
- LPVOID CDatagramSocket::Read(LPINT pnLen, LPSOCKADDR_IN psinRemote/*= NULL*/)
- {
- LPVOID pData = NULL;
-
- // check to see if there is data to retrieve
- if (!m_listRead.IsEmpty())
- {
- // remove the stream data from the list
- LPDATAGRAMDATA pDatagramData = (LPDATAGRAMDATA)m_listRead.RemoveHead();
- pData = pDatagramData->pData;
- *pnLen = pDatagramData->nLen;
- if (psinRemote != NULL)
- memcpy(psinRemote, &(pDatagramData->sin), sizeof(SOCKADDR_IN));
- delete pDatagramData;
- }
-
- return pData;
- }
-
- // message map
- BEGIN_MESSAGE_MAP(CDatagramSocket, CWnd)
- //{{AFX_MSG_MAP(CDatagramSocket)
- //}}AFX_MSG_MAP
- ON_MESSAGE(CWINSOCK_EVENT_NOTIFICATION, OnWinSockEvent)
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::OnWinSockEvent()
- //
- // Called when there is an asynchronous event on the socket.
- //
- LONG CDatagramSocket::OnWinSockEvent(WPARAM wParam, LPARAM lParam)
- {
- // check for an error
- if (WSAGETSELECTERROR(lParam) != 0)
- return 0L;
-
- // what event are we being notified of?
- switch (WSAGETSELECTEVENT(lParam))
- {
- case FD_READ:
- return HandleRead(wParam, lParam);
- break;
- case FD_WRITE:
- return HandleWrite(wParam, lParam);
- break;
- default:
- // this should never happen
- ASSERT(0);
- break;
- }
-
- return 0L;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::HandleRead()
- //
- // Called when there is an asynchronous read event on the socket.
- //
- // If the read was successful, the data, its length, and the address
- // of the sender of the data, are stored in the read queue. Upon
- // a successful read, the application window using this object is
- // then notified with the m_uMsg message (wParam set to
- // CWINSOCK_DONE_READING; lParam set to the number of data chunks
- // in the read queue). At this point, the application should call
- // Read(). If the read fails for some reason, the m_uMsg is sent
- // with wParam set to CWINSOCK_ERROR_READING.
- //
- LONG CDatagramSocket::HandleRead(WPARAM wParam, LPARAM lParam)
- {
- while (1)
- {
- // allocate memory for incoming data
- LPVOID pData = malloc(READ_BUF_LEN);
- LPDATAGRAMDATA pDatagramData = new DATAGRAMDATA;
- if ((pData == NULL) || (pDatagramData == NULL))
- {
- // free anything that was allocated
- if (pData != NULL)
- free(pData);
- pData = NULL;
- if (pDatagramData != NULL)
- delete pDatagramData;
- pDatagramData = NULL;
-
- // tell the parent that a possible data read failed
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_READING);
-
- // fake the event to try again
- PostMessage(CWINSOCK_EVENT_NOTIFICATION, m_s,
- WSAMAKESELECTREPLY(FD_READ, 0));
-
- break;
- }
-
- // receive data
- int nAddrLen = sizeof(SOCKADDR_IN);
- int nBytesRead = recvfrom(m_s, (LPSTR)pData, READ_BUF_LEN, 0,
- (LPSOCKADDR)&(pDatagramData->sin), &nAddrLen);
- if (nBytesRead == SOCKET_ERROR)
- {
- // free memory for incoming data
- free(pData);
- pData = NULL;
- delete pDatagramData;
- pDatagramData = NULL;
-
- // if the error is just that the read would block,
- // don't do anything; we'll get another FD_READ soon
- m_nLastError = WSAGetLastError();
- if (m_nLastError == WSAEWOULDBLOCK)
- m_nLastError = 0;
- else
- // tell the parent that a data read failed
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_READING);
-
- break;
- }
-
- // add the data to the list
- pDatagramData->pData = pData;
- pDatagramData->nLen = nBytesRead;
- TRY
- {
- m_listRead.AddTail(pDatagramData);
- }
- CATCH (CMemoryException, e)
- {
- free(pData);
- pData = NULL;
- delete pDatagramData;
- pDatagramData = NULL;
- // tell the parent that a data read failed
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_READING);
- break;
- }
- END_CATCH
-
- // tell the parent that data has been read
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_DONE_READING,
- (LPARAM)m_listRead.GetCount());
-
- break;
- }
-
- return 0L;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDatagramSocket::HandleWrite()
- //
- // Called when there is an asynchronous write event on the socket.
- //
- // If there is data in the write queue waiting to be sent,
- // a WinSock send is attempted. If the send is successful,
- // a m_uMsg message is sent to the application window with
- // wParam set to CWINSOCK_DONE_WRITING and lParam set to the
- // address of the data that was sent. On send failure,
- // wParam is set to CWINSOCK_ERROR_WRITING and lParam set to
- // the address of the data which couldn't be sent. In either
- // case, the application may free the pointer pointing to
- // the data or reuse that data buffer.
- //
- LONG CDatagramSocket::HandleWrite(WPARAM wParam, LPARAM lParam)
- {
- while (1)
- {
- // check to see if there is any data to send
- if (m_listWrite.IsEmpty())
- break;
-
- // get pointers to data, data length, and destination address
- LPDATAGRAMDATA pDatagramData = (LPDATAGRAMDATA)m_listWrite.GetHead();
- LPVOID pData = pDatagramData->pData;
- int nLen = pDatagramData->nLen;
- SOCKADDR_IN sin;
- memcpy(&sin, &(pDatagramData->sin), sizeof(SOCKADDR_IN));
-
- // send the data
- BOOL bRemove = FALSE; // remove data from queue?
- int nBytesSent = sendto(m_s, (LPCSTR)pData, nLen, 0,
- (LPSOCKADDR)&sin, sizeof(SOCKADDR_IN));
- if (nBytesSent == SOCKET_ERROR)
- {
- // if the error is just that the send would block,
- // don't do anything; we'll get another FD_WRITE soon
- m_nLastError = WSAGetLastError();
- if (m_nLastError == WSAEWOULDBLOCK)
- m_nLastError = 0;
- else
- {
- bRemove = TRUE;
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_WRITING,
- (LPARAM)pData);
- }
- }
- else
- {
- // if data was sent, we must still check to see
- // if all the bytes were sent
- bRemove = TRUE;
- if (nBytesSent == nLen)
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_DONE_WRITING,
- (LPARAM)pData);
- else
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_WRITING,
- (LPARAM)pData);
- }
-
- // if the data was sent or there was a real
- // error, remove the data from the queue
- if (bRemove)
- {
- delete pDatagramData;
- m_listWrite.RemoveHead();
- }
-
- // if there is more data to send, trigger this FD_WRITE handler
- if (!m_listWrite.IsEmpty())
- PostMessage(CWINSOCK_EVENT_NOTIFICATION, m_s,
- WSAMAKESELECTREPLY(FD_WRITE, 0));
-
- break;
- }
-
- return 0L;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket
- /////////////////////////////////////////////////////////////////////////////
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket constructor
- //
- // Constructs the CStreamSocket object. Initializes member variables
- //
- CStreamSocket::CStreamSocket(CWnd *pParentWnd, UINT uMsg)
- {
- m_pParentWnd = pParentWnd;
- ASSERT(m_pParentWnd != NULL);
- m_uMsg = uMsg;
- ASSERT(m_uMsg != 0);
- InitVars();
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket destructor
- //
- CStreamSocket::~CStreamSocket()
- {
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::InitVars()
- //
- // Initialize class member variables.
- //
- void CStreamSocket::InitVars(BOOL bInitLastError/*= TRUE*/)
- {
- if (bInitLastError)
- m_nLastError = 0;
-
- m_s = INVALID_SOCKET;
- memset(&m_sinLocal, 0, sizeof(SOCKADDR_IN));
- memset(&m_sinRemote, 0, sizeof(SOCKADDR_IN));
- m_bServer = FALSE;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::CreateSocket()
- //
- // Create a hidden window that will receive asynchronous messages
- // from WinSock. Also creates a socket and optionally binds it to
- // a name if the socket is a server socket.
- //
- // This version of the CreateSocket() function takes a
- // port number, in host order, as input. A port number
- // should only be specified if the socket is to be bound
- // to a certain port. If you don't care which port is
- // assigned to the socket, just call CreateSocket() without
- // any parameter, causing CreateSocket(NULL) to be called.
- //
- int CStreamSocket::CreateSocket(int nLocalPort)
- {
- // if this version of the function is being called,
- // a valid port number must be specified
- if (nLocalPort <= 0)
- return CWINSOCK_PROGRAMMING_ERROR;
-
- // convert the port number into a string and
- // call the version of CreateSocket() which
- // accepts a string
- char pszLocalService[18];
- _itoa(nLocalPort, pszLocalService, 10);
- return CreateSocket(pszLocalService);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::CreateSocket()
- //
- // Create a hidden window that will receive asynchronous messages
- // from WinSock. Also creates a socket and optionally binds it to
- // a name if the socket is a server socket.
- //
- // This version of the CreateSocket() function takes a
- // string containing a service name or port number.
- // A parameter should only be specified if the socket is to be
- // bound to a certain port. If you don't care which port is
- // assigned to the socket, just call CreateSocket() without
- // any parameter, causing CreateSocket(NULL) to be called.
- //
- int CStreamSocket::CreateSocket(LPSTR pszLocalService/*= NULL*/)
- {
- int nStatus = CWINSOCK_NOERROR;
-
- while (1)
- {
- // Make sure the socket isn't already created.
- // If the socket handle is valid, return from this
- // function right away so the existing parameters of
- // the object are not tampered with.
- if (m_s != INVALID_SOCKET)
- return CWINSOCK_PROGRAMMING_ERROR;
-
- InitVars();
-
- // create the hidden window
- RECT rect;
- rect.left = 0;
- rect.top = 0;
- rect.right = 100;
- rect.bottom = 100;
- if (Create(NULL, NULL, WS_OVERLAPPEDWINDOW, rect, m_pParentWnd, 0) == 0)
- {
- nStatus = CWINSOCK_WINDOWS_ERROR;
- break;
- }
-
- // create the socket
- m_s = socket(PF_INET, SOCK_STREAM, 0);
- if (m_s == INVALID_SOCKET)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- DestroyWindow();
- break;
- }
-
- // If pszLocalService is not NULL, this is a server socket
- // that will accept data on the specified port.
- if (pszLocalService != NULL)
- {
- // this socket is bound to a port number
- // so set the server flag
- m_bServer = TRUE;
-
- // assign the address family
- m_sinLocal.sin_family = AF_INET;
-
- // assign the service port (may have to do a database lookup
- // if a service port number was not specified)
- m_sinLocal.sin_port = htons(atoi(pszLocalService));
- if (m_sinLocal.sin_port == 0)
- {
- LPSERVENT pSent = getservbyname(pszLocalService, "tcp");
- if (pSent == NULL)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- closesocket(m_s);
- DestroyWindow();
- break;
- }
- m_sinLocal.sin_port = pSent->s_port;
- }
-
- // assign the IP address
- m_sinLocal.sin_addr.s_addr = htonl(INADDR_ANY);
-
- // bind the server socket to the name containing the port
- if (bind(m_s, (LPSOCKADDR)&m_sinLocal, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- closesocket(m_s);
- DestroyWindow();
- break;
- }
- }
-
- // start asynchronous event notification
- long lEvent;
- if (m_bServer)
- lEvent = FD_READ | FD_WRITE | FD_ACCEPT | FD_CLOSE;
- else
- lEvent = FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE;
- if (WSAAsyncSelect(m_s, m_hWnd, CWINSOCK_EVENT_NOTIFICATION, lEvent) ==
- SOCKET_ERROR)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- closesocket(m_s);
- DestroySocket();
- break;
- }
-
- // if this is a server, listen for client connections
- if (m_bServer)
- {
- if (listen(m_s, 3) == SOCKET_ERROR)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- closesocket(m_s);
- DestroySocket();
- break;
- }
- }
-
- break;
- }
-
- // if anything failed in this function, set the
- // socket variables appropriately
- if (nStatus != CWINSOCK_NOERROR)
- InitVars(FALSE);
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::DestroySocket()
- //
- // Close the socket, remove any queued data,
- // and destroy the hidden window.
- //
- int CStreamSocket::DestroySocket()
- {
- int nStatus = CWINSOCK_NOERROR;
-
- // make sure the socket is valid
- if (m_s == INVALID_SOCKET)
- nStatus = CWINSOCK_PROGRAMMING_ERROR;
- else
- {
- // remove any data in the write queue
- while (!m_listWrite.IsEmpty())
- {
- LPSTREAMDATA pStreamData = (LPSTREAMDATA)m_listWrite.RemoveHead();
- LPVOID pData = pStreamData->pData;
- delete pStreamData;
-
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_WRITING,
- (LPARAM)pData);
- }
-
- // remove any data in the read queue
- while (!m_listRead.IsEmpty())
- {
- LPSTREAMDATA pStreamData = (LPSTREAMDATA)m_listRead.RemoveHead();
- free(pStreamData->pData);
- delete pStreamData;
- }
-
- // close the socket and initialize variables
- closesocket(m_s);
- InitVars();
-
- // destroy the hidden window
- DestroyWindow();
- }
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::Connect()
- //
- // Connect the client socket to a server specified by the name and port.
- //
- // This version of the Conncet() function takes a pointer to a
- // string representing the host name to send the data to and
- // an integer representing the port number to connect to.
- //
- int CStreamSocket::Connect(LPSTR pszRemoteName, int nRemotePort)
- {
- // convert the port number into a string and
- // call the version of Connect() which accepts
- // a string service name or number
- char pszRemoteService[18];
- _itoa(nRemotePort, pszRemoteService, 10);
- return Connect(pszRemoteName, pszRemoteService);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::Connect()
- //
- // Connect the client socket to a server specified by the name and
- // service name or port.
- //
- // This version of the Connect() function takes a pointer to a
- // string representing the host name to send the data to and
- // an integer representing the service name or port number to
- // connect to.
- //
- int CStreamSocket::Connect(LPSTR pszRemoteName, LPSTR pszRemoteService)
- {
- int nStatus = CWINSOCK_NOERROR; // error status
- LPHOSTENT pHent; // pointer to host entry structure
- LPSERVENT pSent; // pointer to service entry structure
- SOCKADDR_IN sinRemote; // Internet address of destination
-
- while (1)
- {
- // assign the address family
- sinRemote.sin_family = AF_INET;
-
- // assign the service port (may have to do a database lookup
- // if a service port number was not specified)
- sinRemote.sin_port = htons(atoi(pszRemoteService));
- if (sinRemote.sin_port == 0)
- {
- pSent = getservbyname(pszRemoteService, "tcp");
- if (pSent == NULL)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- break;
- }
- sinRemote.sin_port = pSent->s_port;
- }
-
- // assign the IP address (may have to do a database lookup
- // if a dotted decimal IP address was not specified)
- sinRemote.sin_addr.s_addr = inet_addr(pszRemoteName);
- if (sinRemote.sin_addr.s_addr == INADDR_NONE)
- {
- pHent = gethostbyname(pszRemoteName);
- if (pHent == NULL)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- break;
- }
- sinRemote.sin_addr.s_addr = *(u_long *)pHent->h_addr;
- }
-
- // call the version of Connect() that takes an
- // Internet address structure
- return Connect(&sinRemote);
- }
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::Connect()
- //
- // Connect the client socket to a server specified by the
- // Internet address.
- //
- // This version of the Connect() function takes a pointer
- // to an Internet address structure to connect to.
- //
- int CStreamSocket::Connect(LPSOCKADDR_IN psinRemote)
- {
- int nStatus = CWINSOCK_NOERROR;
-
- while (1)
- {
- // only clients should call connect
- if (m_bServer)
- {
- nStatus = CWINSOCK_PROGRAMMING_ERROR;
- break;
- }
-
- // copy the Internet address of the remote server to connect to
- memcpy(&m_sinRemote, psinRemote, sizeof(SOCKADDR_IN));
-
- // attempt the asynchronous connect
- if (connect(m_s, (LPSOCKADDR)&m_sinRemote, sizeof(SOCKADDR_IN)) ==
- SOCKET_ERROR)
- {
- m_nLastError = WSAGetLastError();
- if (m_nLastError == WSAEWOULDBLOCK)
- m_nLastError = 0;
- else
- nStatus = CWINSOCK_WINSOCK_ERROR;
- break;
- }
-
- break;
- }
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::Accept()
- //
- // Accept a connection request from a client.
- //
- // This function takes a pointer to a CStreamSocket object. This
- // pointer will become the newly connected socket.
- //
- int CStreamSocket::Accept(CStreamSocket *pStreamSocket)
- {
- int nStatus = CWINSOCK_NOERROR;
-
- while (1)
- {
- // must have valid CStreamSocket object pointer passed in
- if (pStreamSocket == NULL)
- {
- ASSERT(0);
- nStatus = CWINSOCK_PROGRAMMING_ERROR;
- break;
- }
-
- // only servers should call accept
- if (!m_bServer)
- {
- nStatus = CWINSOCK_PROGRAMMING_ERROR;
- break;
- }
-
- // Make sure the socket isn't already created.
- // If the socket handle is valid, return from this
- // function right away so the existing parameters of
- // the object are not tampered with.
- if (pStreamSocket->m_s != INVALID_SOCKET)
- return CWINSOCK_PROGRAMMING_ERROR;
-
- pStreamSocket->InitVars();
-
- // create the hidden window
- RECT rect;
- rect.left = 0;
- rect.top = 0;
- rect.right = 100;
- rect.bottom = 100;
- if (pStreamSocket->Create(NULL, NULL, WS_OVERLAPPEDWINDOW, rect,
- pStreamSocket->m_pParentWnd, 0) == 0)
- {
- nStatus = CWINSOCK_WINDOWS_ERROR;
- break;
- }
-
- // accept the client connection
- pStreamSocket->m_s = accept(m_s, NULL, NULL);
- if (pStreamSocket->m_s == INVALID_SOCKET)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- pStreamSocket->DestroyWindow();
- break;
- }
-
- // start asynchronous event notification
- long lEvent;
- lEvent = FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE;
- if (WSAAsyncSelect(pStreamSocket->m_s, pStreamSocket->m_hWnd,
- CWINSOCK_EVENT_NOTIFICATION, lEvent) == SOCKET_ERROR)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- closesocket(pStreamSocket->m_s);
- pStreamSocket->DestroySocket();
- break;
- }
-
- break;
- }
-
- // if anything failed in this function, set the
- // socket variables appropriately
- if (nStatus == CWINSOCK_WINSOCK_ERROR)
- pStreamSocket->InitVars(FALSE);
- else if (nStatus == CWINSOCK_NOERROR)
- // notify the parent if the connection was accepted successfully
- pStreamSocket->m_pParentWnd->PostMessage(pStreamSocket->m_uMsg,
- CWINSOCK_YOU_ARE_CONNECTED);
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::Write()
- //
- // Write data to the socket..
- //
- // This function takes an integer representing the length of the
- // data to send and a pointer to the data to send.
- //
- // The data pointed to by pData must remain valid until either
- // the Write() function returns with an error, or the
- // write's completion is notified by the m_uMsg being sent
- // to the window that owns this datagram object with wParam set
- // to CWINSOCK_DONE_WRITING or CWINSOCK_ERROR_WRITING.
- //
- int CStreamSocket::Write(int nLen, LPVOID pData)
- {
- int nStatus = CWINSOCK_NOERROR;
-
- while (1)
- {
- // dynamically allocate a structure to hold the
- // data pointer and the data's length
- LPSTREAMDATA pStreamData = new STREAMDATA;
- if (pStreamData == NULL)
- {
- nStatus = CWINSOCK_WINDOWS_ERROR;
- break;
- }
- pStreamData->pData = pData;
- pStreamData->nLen = nLen;
-
- // add the data to the list
- TRY
- {
- m_listWrite.AddTail(pStreamData);
- }
- CATCH (CMemoryException, e)
- {
- delete pStreamData;
- nStatus = CWINSOCK_WINDOWS_ERROR;
- break;
- }
- END_CATCH
-
- // trigger the FD_WRITE handler to try to send
- PostMessage(CWINSOCK_EVENT_NOTIFICATION, m_s, WSAMAKESELECTREPLY(FD_WRITE, 0));
- break;
- }
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::Read()
- //
- // Read data that has been received by the socket.
- //
- // This function takes a pointer to an integer that will be filled
- // with the length of the data read.
- //
- // A pointer to the data is returned on success. The application
- // using this object must free this pointer. NULL is returned on failure.
- //
- LPVOID CStreamSocket::Read(LPINT pnLen)
- {
- LPVOID pData = NULL;
-
- // check to see if there is data to retrieve
- if (!m_listRead.IsEmpty())
- {
- // remove the stream data from the list
- LPSTREAMDATA pStreamData = (LPSTREAMDATA)m_listRead.RemoveHead();
- pData = pStreamData->pData;
- *pnLen = pStreamData->nLen;
- delete pStreamData;
- }
-
- return pData;
- }
-
- // message map
- BEGIN_MESSAGE_MAP(CStreamSocket, CWnd)
- //{{AFX_MSG_MAP(CStreamSocket)
- //}}AFX_MSG_MAP
- ON_MESSAGE(CWINSOCK_EVENT_NOTIFICATION, OnWinSockEvent)
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::OnWinSockEvent()
- //
- // Called when there is an asynchronous event on the socket.
- //
- LONG CStreamSocket::OnWinSockEvent(WPARAM wParam, LPARAM lParam)
- {
- // check for an error
- if (WSAGETSELECTERROR(lParam) != 0)
- return 0L;
-
- // what event are we being notified of?
- switch (WSAGETSELECTEVENT(lParam))
- {
- case FD_READ:
- return HandleRead(wParam, lParam);
- break;
- case FD_WRITE:
- return HandleWrite(wParam, lParam);
- break;
- case FD_ACCEPT:
- // tell the parent window that a client would like to connect
- // to the server socket
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_READY_TO_ACCEPT_CONNECTION);
- break;
- case FD_CONNECT:
- // tell the parent window that the socket has connected
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_YOU_ARE_CONNECTED);
- break;
- case FD_CLOSE:
- // check for more data queued on the socket
- // (don't tell the application that the socket is closed
- // until all data has been read and notification has been posted)
- if (HandleRead(wParam, lParam))
- {
- // fake the close event to try again
- PostMessage(CWINSOCK_EVENT_NOTIFICATION, wParam, lParam);
- break;
- }
-
- // tell the parent window that the socket is closed
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_LOST_CONNECTION);
- break;
- default:
- // this should never happen
- ASSERT(0);
- break;
- }
-
- return 0L;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::HandleRead()
- //
- // Called when there is an asynchronous read event on the socket.
- //
- // If the read was successful, the data and its length are stored
- // in the read queue. Upon a successful read, the application
- // window using this object is then notified with the m_uMsg message
- // (wParam set to CWINSOCK_DONE_READING; lParam set to the number of
- // data chunks in the read queue). At this point, the application
- // should call Read(). If the read fails for some reason, the m_uMsg
- // is sent with wParam set to CWINSOCK_ERROR_READING.
- //
- LONG CStreamSocket::HandleRead(WPARAM wParam, LPARAM lParam)
- {
- while (1)
- {
- // allocate memory for incoming data
- LPVOID pData = malloc(READ_BUF_LEN);
- LPSTREAMDATA pStreamData = new STREAMDATA;
- if ((pData == NULL) || (pStreamData == NULL))
- {
- // free anything that was allocated
- if (pData != NULL)
- free(pData);
- pData = NULL;
- if (pStreamData != NULL)
- delete pStreamData;
- pStreamData = NULL;
-
- // tell the parent that a possible data read failed
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_READING);
-
- // fake the event to try again
- PostMessage(CWINSOCK_EVENT_NOTIFICATION, m_s,
- WSAMAKESELECTREPLY(FD_READ, 0));
-
- break;
- }
-
- // receive data
- int nBytesRead = recv(m_s, (LPSTR)pData, READ_BUF_LEN, 0);
- if (nBytesRead == SOCKET_ERROR)
- {
- // free memory for incoming data
- free(pData);
- pData = NULL;
- delete pStreamData;
- pStreamData = NULL;
-
- // if the error is just that the read would block,
- // don't do anything; we'll get another FD_READ soon
- m_nLastError = WSAGetLastError();
- if (m_nLastError == WSAEWOULDBLOCK)
- m_nLastError = 0;
- else
- // tell the parent that a data read failed
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_READING);
-
- break;
- }
-
- // make sure some data was read
- if (nBytesRead == 0)
- {
- // free memory for incoming data
- free(pData);
- pData = NULL;
- delete pStreamData;
- pStreamData = NULL;
-
- break;
- }
-
- // add the data to the list
- pStreamData->pData = pData;
- pStreamData->nLen = nBytesRead;
- TRY
- {
- m_listRead.AddTail(pStreamData);
- }
- CATCH (CMemoryException, e)
- {
- free(pData);
- pData = NULL;
- delete pStreamData;
- pStreamData = NULL;
- // tell the parent that a data read failed
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_READING);
- break;
- }
- END_CATCH
-
- // tell the parent that data has been read
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_DONE_READING,
- (LPARAM)m_listRead.GetCount());
-
- // 1 is returned if there is data so CStreamSocket::OnWinSockEvent()'s
- // FD_CLOSE handler will know when the socket can really be closed
- return 1L;
-
- break;
- }
-
- return 0L;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::HandleWrite()
- //
- // Called when there is an asynchronous write event on the socket.
- //
- // If there is data in the write queue waiting to be sent,
- // a WinSock send is attempted. If the send is successful,
- // a m_uMsg message is sent to the application window with
- // wParam set to CWINSOCK_DONE_WRITING and lParam set to the
- // address of the data that was sent. On send failure,
- // wParam is set to CWINSOCK_ERROR_WRITING and lParam set to
- // the address of the data which couldn't be sent. In either
- // case, the application may free the pointer pointing to
- // the data or reuse that data buffer. It is possible for the
- // entire amount of data to not be sent in one call to send().
- // In this case, an attempt is made to send the remaining portion
- // of that block of data the next time HandleWrite() is invoked.
- //
- //
- LONG CStreamSocket::HandleWrite(WPARAM wParam, LPARAM lParam)
- {
- LPSTREAMDATA pStreamData; // pointer to stream data structure
- LPVOID pData; // pointer to buffer to send
- int nLen; // total length of buffer to send
- static LPVOID pDataRemaining = NULL; // pointer into buffer to send
- static int nLenRemaining = 0; // number of bytes left to send
-
- while (1)
- {
- // check to see if there is any data to send
- if (m_listWrite.IsEmpty())
- break;
-
- // if we are not in the middle of another buffer send,
- // get data and data length from the write queue
- pStreamData = (LPSTREAMDATA)m_listWrite.GetHead(); // not RemoveHead()
- pData = pStreamData->pData;
- nLen = pStreamData->nLen;
- if (pDataRemaining == NULL)
- {
- pDataRemaining = pData;
- nLenRemaining = nLen;
- }
-
- // send the data
- BOOL bRemove = FALSE; // remove data from queue?
- int nBytesSent = send(m_s, (LPCSTR)pDataRemaining, nLenRemaining, 0);
- if (nBytesSent == SOCKET_ERROR)
- {
- // if the error is just that the send would block,
- // don't do anything; we'll get another FD_WRITE soon
- m_nLastError = WSAGetLastError();
- if (m_nLastError == WSAEWOULDBLOCK)
- m_nLastError = 0;
- else
- {
- bRemove = TRUE;
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_ERROR_WRITING,
- (LPARAM)pData);
- }
- }
- else
- {
- // if data was sent, we must still check to see
- // if all the bytes were sent
- if (nBytesSent == nLenRemaining)
- {
- bRemove = TRUE;
- m_pParentWnd->PostMessage(m_uMsg, CWINSOCK_DONE_WRITING,
- (LPARAM)pData);
- }
- else
- {
- // the complete buffer was not sent so adjust
- // these values accordingly
- pDataRemaining = (LPVOID)((LPCSTR)pDataRemaining + nBytesSent);
- nLenRemaining = nLenRemaining - nBytesSent;
- }
- }
-
- // if the data was completely sent or there was
- // a real error, remove the data from the queue
- if (bRemove)
- {
- delete pStreamData;
- m_listWrite.RemoveHead();
- pDataRemaining = NULL;
- nLenRemaining = 0;
- }
-
- // if there is more data to send, trigger this FD_WRITE handler
- if (!m_listWrite.IsEmpty())
- PostMessage(CWINSOCK_EVENT_NOTIFICATION, m_s,
- WSAMAKESELECTREPLY(FD_WRITE, 0));
-
- break;
- }
-
- return 0L;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CStreamSocket::GetPeerName()
- //
- // Copies the Internet address of the other end of the socket
- // connection into the pointer provided.
- // Useful for server's to use after an Accept().
- //
- int CStreamSocket::GetPeerName(LPSOCKADDR_IN psinRemote)
- {
- int nStatus = CWINSOCK_NOERROR;
- int nLen = sizeof(SOCKADDR_IN);
-
- // make sure the listening socket doesn't call this function
- if (m_bServer)
- nStatus = CWINSOCK_PROGRAMMING_ERROR;
- else if (getpeername(m_s, (LPSOCKADDR)psinRemote, &nLen) == SOCKET_ERROR)
- {
- m_nLastError = WSAGetLastError();
- nStatus = CWINSOCK_WINSOCK_ERROR;
- }
-
- return nStatus;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Utility functions
- /////////////////////////////////////////////////////////////////////////////
-
- /////////////////////////////////////////////////////////////////////////////
- // CWinSockErrorBox
- //
- void CWinSockErrorBox(int nError, LPSTR pszMessage/*= NULL*/)
- {
- #define ERROR_BUF_LEN (1000)
- char pszError[ERROR_BUF_LEN];
-
- wsprintf(pszError, "WinSock error %d: ", nError);
-
- switch (nError)
- {
- case WSAEINTR:
- lstrcat(pszError, "Interrupted system call");
- break;
- case WSAEBADF:
- lstrcat(pszError, "Bad file number");
- break;
- case WSAEACCES:
- lstrcat(pszError, "Permission denied");
- break;
- case WSAEFAULT:
- lstrcat(pszError, "Bad address");
- break;
- case WSAEINVAL:
- lstrcat(pszError, "Invalid argument");
- break;
- case WSAEMFILE:
- lstrcat(pszError, "Too many open files");
- break;
- case WSAEWOULDBLOCK:
- lstrcat(pszError, "Operation would block");
- break;
- case WSAEINPROGRESS:
- lstrcat(pszError, "Operation now in progress");
- break;
- case WSAEALREADY:
- lstrcat(pszError, "Operation already in progress");
- break;
- case WSAENOTSOCK:
- lstrcat(pszError, "Socket operation on non-socket");
- break;
- case WSAEDESTADDRREQ:
- lstrcat(pszError, "Destination address required");
- break;
- case WSAEMSGSIZE:
- lstrcat(pszError, "Message too long");
- break;
- case WSAEPROTOTYPE:
- lstrcat(pszError, "Protocol wrong type for socket");
- break;
- case WSAENOPROTOOPT:
- lstrcat(pszError, "Protocol not available");
- break;
- case WSAEPROTONOSUPPORT:
- lstrcat(pszError, "Protocol not supported");
- break;
- case WSAESOCKTNOSUPPORT:
- lstrcat(pszError, "Socket type not supported");
- break;
- case WSAEOPNOTSUPP:
- lstrcat(pszError, "Operation not supported on socket");
- break;
- case WSAEPFNOSUPPORT:
- lstrcat(pszError, "Protocol family not supported");
- break;
- case WSAEAFNOSUPPORT:
- lstrcat(pszError, "Address family not supported by protocol family");
- break;
- case WSAEADDRINUSE:
- lstrcat(pszError, "Address already in use");
- break;
- case WSAEADDRNOTAVAIL:
- lstrcat(pszError, "Can't assign requested address");
- break;
- case WSAENETDOWN:
- lstrcat(pszError, "Network is down");
- break;
- case WSAENETUNREACH:
- lstrcat(pszError, "Network is unreachable");
- break;
- case WSAENETRESET:
- lstrcat(pszError, "Network dropped connection on reset");
- break;
- case WSAECONNABORTED:
- lstrcat(pszError, "Software caused connection abort");
- break;
- case WSAECONNRESET:
- lstrcat(pszError, "Connection reset by peer");
- break;
- case WSAENOBUFS:
- lstrcat(pszError, "No buffer space available");
- break;
- case WSAEISCONN:
- lstrcat(pszError, "Socket is already connected");
- break;
- case WSAENOTCONN:
- lstrcat(pszError, "Socket is not connected");
- break;
- case WSAESHUTDOWN:
- lstrcat(pszError, "Can't send after socket shutdown");
- break;
- case WSAETOOMANYREFS:
- lstrcat(pszError, "Too many references: can't splice");
- break;
- case WSAETIMEDOUT:
- lstrcat(pszError, "Connection timed out");
- break;
- case WSAECONNREFUSED:
- lstrcat(pszError, "Connection refused");
- break;
- case WSAELOOP:
- lstrcat(pszError, "Too many levels of symbolic links");
- break;
- case WSAENAMETOOLONG:
- lstrcat(pszError, "File name too long");
- break;
- case WSAEHOSTDOWN:
- lstrcat(pszError, "Host is down");
- break;
- case WSAEHOSTUNREACH:
- lstrcat(pszError, "No route to host");
- break;
- case WSAENOTEMPTY:
- lstrcat(pszError, "Directory not empty");
- break;
- case WSAEPROCLIM:
- lstrcat(pszError, "Too many processes");
- break;
- case WSAEUSERS:
- lstrcat(pszError, "Too many users");
- break;
- case WSAEDQUOT:
- lstrcat(pszError, "Disc quota exceeded");
- break;
- case WSAESTALE:
- lstrcat(pszError, "Stale NFS file handle");
- break;
- case WSAEREMOTE:
- lstrcat(pszError, "Too many levels of remote in path");
- break;
- #ifdef _WIN32
- case WSAEDISCON:
- lstrcat(pszError, "Disconnect");
- break;
- #endif
- case WSASYSNOTREADY:
- lstrcat(pszError, "Network sub-system is unusable");
- break;
- case WSAVERNOTSUPPORTED:
- lstrcat(pszError, "WinSock DLL cannot support this application");
- break;
- case WSANOTINITIALISED:
- lstrcat(pszError, "WinSock not initialized");
- break;
- case WSAHOST_NOT_FOUND:
- lstrcat(pszError, "Host not found");
- break;
- case WSATRY_AGAIN:
- lstrcat(pszError, "Non-authoritative host not found");
- break;
- case WSANO_RECOVERY:
- lstrcat(pszError, "Non-recoverable error");
- break;
- case WSANO_DATA:
- lstrcat(pszError, "Valid name, no data record of requested type");
- break;
- default:
- lstrcpy(pszError, "Not a WinSock error");
- break;
- }
-
- lstrcat(pszError, "\n");
-
- int n = lstrlen(pszError);
- if (pszMessage != NULL)
- n += lstrlen(pszMessage);
- if ((pszMessage != NULL) && (n < ERROR_BUF_LEN))
- lstrcat(pszError, pszMessage);
-
- AfxMessageBox(pszError);
- }
-