📄 wsasimpl.c
字号:
/*---------------------------------------------------------------------
*
* Program: WSASIMPL.DLL Simplified WinSock API (for TCP Clients)
*
* filename: wsasimpl.c
*
* copyright by Bob Quinn, 1995
*
* Description:
* This DLL provides an "encapsulated WinSock API," as described in
* Chapter 12 of _Windows Sockets Network Programming_. It uses
* a helper task. a hidden window and asynchronous operation mode
* to provide basic functionality for TCP client applications.
*
* 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.
*
---------------------------------------------------------------------*/
#define STRICT
#include "..\wsa_xtra.h"
#include <windows.h>
#include <windowsx.h>
#include <winsock.h>
#include "resource.h"
#include <string.h> /* for _fmemcpy() */
#include <stdlib.h> /* for atoi() */
#include "..\winsockx.h"
#define TIMEOUT_ID WM_USER+1
/*------- important data structures ------*/
typedef struct TaskData {
HTASK hTask; /* Task ID: primary key */
int nRefCount; /* Number of sockets owned by task */
struct TaskData *lpstNext; /* Pointer to next entry in linked list */
} TASKDATA, *PTASKDATA, FAR *LPTASKDATA;
typedef struct ConnData {
SOCKET hSock; /* Conection socket */
LPTASKDATA lpstTask; /* Pointer to Task structure */
HWND hwnd; /* Handle of subclassed window */
SOCKADDR_IN stRmtName; /* Remote host address & port */
int nTimeout; /* Timeout (in millisecs) */
DWORD lpfnWndProc; /* Window procedure (before subclassed) */
struct ConnData *lpstNext; /* Pointer to next entry in linked list */
} CONNDATA, *PCONNDATA, FAR *LPCONNDATA;
/*-------------- global data -------------*/
char szAppName[] = "wsasimpl";
HWND hWinMain;
HINSTANCE hInst;
WSADATA stWSAData;
LPCONNDATA lpstConnHead = 0L; /* Head of connection data list */
LPTASKDATA lpstTaskHead = 0L; /* Head of task data list */
/*-------- exported function prototypes ---------*/
int WINAPI LibMain (HANDLE, WORD, WORD, LPSTR);
LONG CALLBACK SubclassProc (HWND, UINT, WPARAM, LPARAM);
SOCKET WINAPI ConnectTCP(LPSTR, LPSTR);
int WINAPI SendData(SOCKET, LPSTR, int);
int WINAPI RecvData(SOCKET, LPSTR, int, int);
int WINAPI CloseTCP(SOCKET, LPSTR, int);
/*-------- internal function prototypes ---------*/
int DoSend(SOCKET, LPSTR, int, LPCONNDATA);
int DoRecv(SOCKET, LPSTR, int, LPCONNDATA);
LPCONNDATA NewConn (SOCKET, PSOCKADDR_IN);
LPCONNDATA FindConn (SOCKET, HWND);
void RemoveConn (LPCONNDATA);
LPTASKDATA NewTask (HTASK);
LPTASKDATA FindTask (HTASK);
void RemoveTask (LPTASKDATA);
u_short GetPort (LPSTR);
/*--------------------------------------------------------------------
* Function: LibMain()
*
* Description: DLL entry point (we don't have much to do here)
*/
int PASCAL LibMain
(HANDLE hInstance,
WORD wDataSeg,
WORD wHeapSize,
LPSTR lpszCmdLine)
{
lpszCmdLine = lpszCmdLine; /* avoid warnings */
wDataSeg = wDataSeg;
wHeapSize = wHeapSize;
hInst = hInstance; /* save instance handle */
// GlobalLock(hInst);
return (1);
} /* end LibMain() */
/*--------------------------------------------------------------------
* Function: SubclassProc()
*
* Description: process messages bound for calling application to
* filter out "reentrant" mouse and keyboard messages while a
* blocking network operation is pending.
*/
LONG CALLBACK SubclassProc
(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
LPCONNDATA lpstConn; /* Work Pointer */
lpstConn = FindConn(0, hwnd); /* find our socket structure */
switch (msg) {
case WM_QUIT:
/* Close this connection */
if (lpstConn) {
CloseTCP(lpstConn->hSock, (LPSTR)0, INPUT_SIZE);
RemoveConn(lpstConn);
/* Release Timer (if it's active) */
if (lpstConn->nTimeout)
KillTimer(hwnd, TIMEOUT_ID);
}
break;
case WM_CLOSE:
case WM_TIMER:
/* If Timeout or Close request, cancel pending */
if(lpstConn && WSAIsBlocking())
WSACancelBlockingCall();
break;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONDBLCLK:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MOUSEACTIVATE:
case WM_MOUSEMOVE:
case WM_NCHITTEST:
case WM_NCLBUTTONDBLCLK:
case WM_NCLBUTTONDOWN:
case WM_NCLBUTTONUP:
case WM_NCMBUTTONDBLCLK:
case WM_NCMBUTTONDOWN:
case WM_NCMBUTTONUP:
case WM_NCMOUSEMOVE:
case WM_NCRBUTTONDBLCLK:
case WM_NCRBUTTONDOWN:
case WM_NCRBUTTONUP:
case WM_NEXTDLGCTL:
case WM_RBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
/* Eat all mouse and keyboard messages */
return (0L);
default:
break;
} /* end switch (msg) */
if (lpstConn) {
/* Let original (pre-subclass) window handler process message */
return (CallWindowProc ((WNDPROC)(lpstConn->lpfnWndProc),
hwnd, msg, wParam, lParam));
} else {
return (0L); /* this should never occur */
}
} /* end SubClassProc() */
/*---------------------------------------------------------------
* Function: ConnectTCP()
*
* Description: get a TCP socket and connect to server (along with
* other maintenance stuff, like subclassing window, and registering
* task).
*/
SOCKET WINAPI ConnectTCP(LPSTR szDestination, LPSTR szService)
{
int nRet;
HTASK hTask;
SOCKET hSock;
LPTASKDATA lpstTask;
LPCONNDATA lpstConn;
SOCKADDR_IN stRmtName;
#ifndef WIN32
hTask = GetCurrentTask(); /* Task handle: for our records */
#else
hTask = GetCurrentProcess(); /* or Process handle (if 32-bit) */
#endif
lpstTask = FindTask (hTask);
if (!lpstTask) {
/* If task isn't registered, then register it (call WSAStartup()) */
lpstTask = NewTask(hTask);
}
if (lpstTask) {
/* Get a TCP socket */
hSock = socket (AF_INET, SOCK_STREAM, 0);
if (hSock == INVALID_SOCKET) {
WSAperror(WSAGetLastError(), "socket()", hInst);
} else {
/* Get destination address */
stRmtName.sin_addr.s_addr = GetAddr(szDestination);
if (stRmtName.sin_addr.s_addr != INADDR_NONE) {
/* Get destination port number */
stRmtName.sin_port = GetPort(szService);
if (stRmtName.sin_port) {
/* Create a new socket structure */
lpstConn = NewConn(hSock, &stRmtName);
if (lpstConn) {
/* Subclass the active window passed
* NOTE: This reveals one limitation in our API. This is the
* same window we'll subclass during sends and receives, so
* we won't capture user I/O if application sends calls the
* SendData() or RecvData() from a different window. */
lpstConn->lpstTask = lpstTask;
lpstConn->hwnd = GetActiveWindow();
lpstConn->lpfnWndProc = GetWindowLong(lpstConn->hwnd,GWL_WNDPROC);
SetWindowLong (lpstConn->hwnd, GWL_WNDPROC, (DWORD)SubclassProc);
/* Initiate non-blocking connect to server */
stRmtName.sin_family = PF_INET;
nRet = connect(hSock,(LPSOCKADDR)&stRmtName,SOCKADDR_LEN);
/* Unsubclass active window now that we're done blocking */
SetWindowLong(lpstConn->hwnd,GWL_WNDPROC,(DWORD)lpstConn->lpfnWndProc);
if (nRet == SOCKET_ERROR) {
int WSAErr = WSAGetLastError();
if (WSAErr != WSAEINTR) {
/* Display all errors except "operation interrupted"*/
WSAperror(WSAErr, "connect()", hInst);
RemoveConn(lpstConn);
lpstTask = 0L;
closesocket(hSock);
hSock = INVALID_SOCKET;
}
}
} else {
/* Can't create a connection structure */
closesocket(hSock);
hSock = INVALID_SOCKET;
}
} else {
/* Can't resolve destination port number */
closesocket(hSock);
hSock = INVALID_SOCKET;
}
} else {
/* Can't resolve destination address */
closesocket(hSock);
hSock = INVALID_SOCKET;
}
}
/* If we failed, we need to clean up */
if (hSock == INVALID_SOCKET && lpstTask) {
RemoveTask(lpstTask);
}
}
return (hSock);
} /* end ConnectTCP() */
/*--------------------------------------------------------------
* Function: SendData()
*
* Description: Send data amount requested from buffer passed
*/
int WINAPI SendData(SOCKET hSock, LPSTR lpOutBuf, int cbTotalToSend)
{
LPCONNDATA lpstConn;
int cbTotalSent = 0, cbSent;
int nRet = SOCKET_ERROR; /* assume error */
lpstConn = FindConn(hSock, 0);
if (!lpstConn) {
/* Socket not found, so it's not valid */
WSASetLastError(WSAENOTSOCK);
} else {
/* Subclass the window provided at connnect to filter message traffic */
SetWindowLong (lpstConn->hwnd, GWL_WNDPROC, (DWORD)SubclassProc);
while (((cbTotalToSend - cbTotalSent) > 0) &&
(lpstConn->hSock != INVALID_SOCKET)) {
cbSent = DoSend(hSock,
lpOutBuf+cbTotalSent,
cbTotalToSend - cbTotalSent,
lpstConn);
if (cbSent != SOCKET_ERROR) {
/* Tally and Quit the loop if we've sent amount requested */
cbTotalSent += cbSent;
if ((cbTotalToSend - cbTotalSent) <= 0)
break;
} else {
/* If send failed, return an error */
cbTotalSent = SOCKET_ERROR;
}
}
/* Unsubclass active window before we leave */
SetWindowLong(lpstConn->hwnd, GWL_WNDPROC, (long)lpstConn->lpfnWndProc);
}
return (cbTotalSent);
} /* end SendData() */
/*--------------------------------------------------------------
* Function: DoSend()
*
* Description: Send data. We call this function from SendData(),
* or in response to FD_WRITE asynchronous notification.
*/
int DoSend(SOCKET hSock, LPSTR lpOutBuf, int cbTotalToSend,
LPCONNDATA lpstConn)
{
int cbTotalSent = 0;
int cbLeftToSend = cbTotalToSend;
int nRet, WSAErr;
/* Send as much data as we can */
while (cbLeftToSend > 0) {
/* Send data to client */
nRet = send (hSock, lpOutBuf+cbTotalSent,
cbLeftToSend < MTU_SIZE ? cbLeftToSend : MTU_SIZE, 0);
if (nRet == SOCKET_ERROR) {
WSAErr = WSAGetLastError();
/* Display all errors except "operation interrupted" */
if (WSAErr != WSAEINTR) {
/* unsubclass first so user can respond to error) */
SetWindowLong(lpstConn->hwnd, GWL_WNDPROC,
(DWORD)lpstConn->lpfnWndProc);
WSAperror(WSAErr, (LPSTR)"send()", hInst);
}
break;
} else {
/* Update byte counter, and display. */
cbTotalSent += nRet;
}
/* calculate what's left to send */
cbLeftToSend = cbTotalSent - cbTotalToSend;
}
return (cbTotalSent);
} /* end DoSend() */
/*--------------------------------------------------------------
* Function: RecvData()
*
* Description: Recieve data amount requested into buffer passed
*/
int WINAPI RecvData(SOCKET hSock, LPSTR lpInBuf, int cbTotalToRecv, int nTimeout)
{
LPCONNDATA lpstConn;
int cbTotalRcvd = 0, cbRcvd;
int nRet = SOCKET_ERROR; /* assume error */
lpstConn = FindConn(hSock, 0);
if (!lpstConn) {
/* Socket not found, so it's not valid */
WSASetLastError(WSAENOTSOCK);
} else {
/* Subclass the active window to filter message traffic */
SetWindowLong (lpstConn->hwnd, GWL_WNDPROC, (DWORD)SubclassProc);
/* Set a timer, if requested */
if (nTimeout) {
lpstConn->nTimeout = nTimeout;
SetTimer(hWinMain, TIMEOUT_ID, nTimeout, 0L);
}
while (((cbTotalToRecv - cbTotalRcvd) > 0) &&
(lpstConn->hSock != INVALID_SOCKET)) {
cbRcvd = DoRecv(hSock,
lpInBuf+cbTotalRcvd,
cbTotalToRecv - cbTotalRcvd,
lpstConn);
if (cbRcvd != SOCKET_ERROR) {
/* Tally and Quit if we've received amount requested */
cbTotalRcvd += cbRcvd;
if ((cbTotalToRecv - cbTotalRcvd) <= 0) {
if (lpstConn->nTimeout)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -