接下来,我们最后来看看怎么样实现一个服务提供者的最基本的实例,我们可以试图在这里对网络封包进行截取。
以下是基础服务提供者实例,对于分层服务提供者,麻烦!我懒得写了:
int WSPAPI WSPStartup(
WORD wVersion,
LPWSPDATA lpWSPData,
LPWSAPROTOCOL_INFOW lpProtocolInfo,
WSPUPCALLTABLE UpCallTable,
LPWSPPROC_TABLE lpProcTable)
{
int nTotalProtocols=0;
int nProviderPathLen=MAX_PATH;
TCHAR szLibraryPath[MAX_PATH]={ '/0' };
TCHAR szProviderPath[MAX_PATH]={ '/0' };;
LPWSAPROTOCOL_INFOW lpOrigProtocolInfo=NULL;
theApp.m_hLibOrigBase=NULL;
LPWSPSTARTUP WSPStartupFunc = NULL;
EnterCriticalSection(&theApp.m_CriticalSection);
if (!theApp.m_nEntityCount)
{
CFile f;
TCHAR szFileName[MAX_PATH]={ '/0' };
GetWindowsDirectory(szFileName,MAX_PATH);
sprintf(szFileName,"%s//%s",szFileName,OLD_BSP_CATALOG);
if(!f.Open(szFileName,CFile::modeRead)) return WSAEPROVIDERFAILEDINIT;
DWORD dwLen=f.GetLength();
DWORD dwSize=MAX_PATH+sizeof(WSAPROTOCOL_INFOW);
nTotalProtocols=dwLen/dwSize;
lpOrigProtocolInfo=new WSAPROTOCOL_INFOW[nTotalProtocols];
for(int i=0;i<nTotalProtocols;i++)
{
f.Seek(dwSize*i+MAX_PATH,0);
f.Read(&lpOrigProtocolInfo[i],sizeof(WSAPROTOCOL_INFOW));
if(lpProtocolInfo->ProviderId==lpOrigProtocolInfo->ProviderId)
{
f.Seek(dwSize*i,0);
f.Read(szProviderPath,MAX_PATH);
break;
}
}
f.Close();
delete[] lpOrigProtocolInfo; lpOrigProtocolInfo=NULL;
if(!ExpandEnvironmentStrings(szProviderPath,szLibraryPath,MAX_PATH)) return WSAEPROVIDERFAILEDINIT;
theApp.m_hLibOrigBase=LoadLibrary(szLibraryPath);
if(theApp.m_hLibOrigBase==NULL) return WSAEPROVIDERFAILEDINIT;
WSPStartupFunc=(LPWSPSTARTUP)GetProcAddress(theApp.m_hLibOrigBase,"WSPStartup";
if(WSPStartupFunc==NULL) return WSAEPROVIDERFAILEDINIT;
int nRet=(*WSPStartupFunc)(wVersion,lpWSPData,lpProtocolInfo,UpCallTable,lpProcTable);
if(nRet!=ERROR_SUCCESS) return nRet;
memmove(&theApp.m_NextProcTable, lpProcTable, sizeof(WSPPROC_TABLE));
lpProcTable->lpWSPAccept = WSPAccept;
lpProcTable->lpWSPAddressToString = WSPAddressToString;
lpProcTable->lpWSPAsyncSelect = WSPAsyncSelect;
lpProcTable->lpWSPBind = WSPBind;
lpProcTable->lpWSPCancelBlockingCall = WSPCancelBlockingCall;
lpProcTable->lpWSPCleanup = WSPCleanup;
lpProcTable->lpWSPCloseSocket = WSPCloseSocket;
lpProcTable->lpWSPConnect = WSPConnect;
lpProcTable->lpWSPDuplicateSocket = WSPDuplicateSocket;
lpProcTable->lpWSPEnumNetworkEvents = WSPEnumNetworkEvents;
lpProcTable->lpWSPEventSelect = WSPEventSelect;
lpProcTable->lpWSPGetOverlappedResult = WSPGetOverlappedResult;
lpProcTable->lpWSPGetPeerName = WSPGetPeerName;
lpProcTable->lpWSPGetSockOpt = WSPGetSockOpt;
lpProcTable->lpWSPGetSockName = WSPGetSockName;
lpProcTable->lpWSPGetQOSByName = WSPGetQOSByName;
lpProcTable->lpWSPIoctl = WSPIoctl;
lpProcTable->lpWSPJoinLeaf = WSPJoinLeaf;
lpProcTable->lpWSPListen = WSPListen;
lpProcTable->lpWSPRecv = WSPRecv;
lpProcTable->lpWSPRecvDisconnect = WSPRecvDisconnect;
lpProcTable->lpWSPRecvFrom = WSPRecvFrom;
lpProcTable->lpWSPSelect = WSPSelect;
lpProcTable->lpWSPSend = WSPSend;
lpProcTable->lpWSPSendDisconnect = WSPSendDisconnect;
lpProcTable->lpWSPSendTo = WSPSendTo;
lpProcTable->lpWSPSetSockOpt = WSPSetSockOpt;
lpProcTable->lpWSPShutdown = WSPShutdown;
lpProcTable->lpWSPSocket = WSPSocket;
lpProcTable->lpWSPStringToAddress = WSPStringToAddress;
theApp.m_lpWSPData = lpWSPData;
theApp.m_lpProcTable = lpProcTable;
}
else
{
lpWSPData = theApp.m_lpWSPData;
lpProcTable = theApp.m_lpProcTable;
}
theApp.m_nEntityCount++;
LeaveCriticalSection(&theApp.m_CriticalSection);
return 0;
}
int WSPAPI WSPCleanup (LPINT lpErrno)
{
int nRet=theApp.m_NextProcTable.lpWSPCleanup(lpErrno);
EnterCriticalSection(&theApp.m_CriticalSection);
theApp.m_nEntityCount--;
if (theApp.m_nEntityCount == 0)
{
FreeLibrary(theApp.m_hLibOrigBase);
theApp.m_hLibOrigBase = NULL;
}
LeaveCriticalSection(&theApp.m_CriticalSection);
return nRet;
}
对于不同的I/0操作模式,需要进行不同的处理
对于WSARecv,WSARecvFrom,WSASend,WSASendTo的重叠调用,保存重叠信息,重点是完成例程
// 客户程序如果用完成例程,那么将不能直接监视到收发的数据,为了解决这个问题
// 我们可以在服务提供者内提供我们自己的完成例程截获数据,在我们截获了数据之后,
// 再把控制权交还给客户机的完成例程。
//
// 首先,保存重叠操作参数信息的结构
typedef struct tagOVERLAPPED_RECORDER
{
DWORD dwType; // WSASend,WSASendTo,WSARecv,WSARecvFrom
// 用来标志监视的数据操作方式
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
const SOCKADDR_IN FAR *lpFromOrTo,
int iFromOrTolen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
}
OVERLAPPED_RECORDER, *POVERLAPPED_RECORDER, *LPOVERLAPPED_RECORDER;
// 其次替换重叠操作的完成例程为自定义的例程
// 例程完成后,控制权交给客户机的完成例程,我们可以删除上面保存的重叠参数信息结构了
// 完成例程原型如下:
void CALLBACK CompletionRoutine (
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);