驱动老牛
|
阅读:2116回复:18
TdiRecv (80分)
98的TDI RECV
Status = pDt->TdiReceiveEntry(&((PTDICONTEXT98)pTdiContext)->ConnRequest, &Flags, &RecvLen, NB); DebugString(\"Recv Status = %X\",Status); if ( Status == TDI_PENDING ) { Wait_Semaphore(CallBack.cbm_sem, BLOCK_SVC_INTS); DebugString(\"recv wait complete %d\",CallBack.Length); *ReturnLength=CallBack.Length; Status=CallBack.cbm_status; } 我把这个函数加了异常处理 和SEND是完全一样的 SEND能成功,这个RECV也能成功收到数据 就是会产生异常 到了CATCH里。这是为何? |
|
沙发#
发布于:2005-06-07 16:10
NB->VirtualAddress指向的页锁定了吗?
不锁定可能会出错。 |
|
驱动老牛
|
板凳#
发布于:2005-06-07 16:14
NB->VirtualAddress指向的页锁定了吗? 如何锁定,我是用下面的方法分配的 NdisAllocateBufferPool(&NStatus,&PoolHandle,iNumber); NdisAllocateBuffer(&NStatus,&NB,PoolHandle,Data,DataLen); 但是SEND没问题呀? |
|
地板#
发布于:2005-06-07 16:18
给你个封装好的函数
unsigned int CSocket::Receive(unsigned char *buf, unsigned int len) { if(!m_pConnRequest)return 0; unsigned char* pBuf; DWORD pLinBuf, nPages, pLockedBuf; unsigned int nBytesSent; int res = 0; TDI_STATUS err; pLinBuf = (unsigned long)buf; nPages = ((pLinBuf + len - 1) >> 12) - (pLinBuf >> 12) + 1; if (nPages!=0) { pLockedBuf = _LinPageLock(pLinBuf >> 12, nPages, PAGEMAPGLOBAL); if (pLockedBuf==0) { } } PNDIS_BUFFER pNB; pNB = (PNDIS_BUFFER)_HeapAllocate(sizeof(NDIS_BUFFER), HEAPZEROINIT); memcpy((PVOID)&pNB->Signature, \"NBUF\", 4); pNB->VirtualAddress = (PVOID)(pLockedBuf + (pLinBuf & 0xfff)); pNB->Length = len; m_pConnRequest->RequestNotifyObject = EventReceiveCallback; m_pConnRequest->RequestContext = this; err = TdiReceive(m_pConnRequest,0, &len,pNB); if (err == TDI_PENDING) { //waiting ... Wait_Semaphore(m_EventSem,BLOCK_SVC_INTS); } _LinPageUnLock(((DWORD) pLockedBuf) >> 12, nPages, PAGEMAPGLOBAL); if (pNB) _HeapFree(pNB, 0); return len; } |
|
驱动老牛
|
地下室#
发布于:2005-06-07 18:18
我已经把代码全部改成差不多一样的了,但还是有个异常,而且第二次加载这个驱动的时候系统就死机了。
NTSTATUS TdiRecv(PTDICONTEXT pTdiContext,PVOID Data,ULONG DataLen,ULONG *ReturnLength) { CALLBACK CallBack; USHORT Flags=TDI_RECEIVE_NORMAL; PNDIS_BUFFER NB; TDI_STATUS Status=STATUS_SUCCESS; TDIDispatchTable *pDt; NDIS_STATUS NStatus; NDIS_HANDLE PoolHandle; UINT iNumber=1; UINT RecvLen=DataLen; ULONG ulLinBuf, nPages,pLockBuf; __try { pDt=GetTDIDispatchTable(); CallBack.cbm_sem=Create_Semaphore(0); CallBack.Command=2; if(CallBack.cbm_sem==NULL) { DebugString(\"CreateSemaphore error %X\",0); } ((PTDICONTEXT98)pTdiContext)->ConnRequest.RequestNotifyObject = CompleteConnection; ((PTDICONTEXT98)pTdiContext)->ConnRequest.RequestContext = &CallBack; ulLinBuf = (unsigned long)Data; nPages = ((ulLinBuf + DataLen - 1) >> 12) - (ulLinBuf >> 12) + 1; if (nPages!=0) { pLockBuf = _LinPageLock(ulLinBuf >> 12, nPages, PAGEMAPGLOBAL); if (pLockBuf==0) { DebugString(\"Lock Page error %d\",1); return 0; } } else { DebugString(\"Lock Page error %d\",0); return 0; } /* NdisAllocateBufferPool(&NStatus,&PoolHandle,iNumber); NdisAllocateBuffer(&NStatus,&NB,PoolHandle,(PVOID)((unsigned char *)pLockBuf + ((ULONG)Data & 0xfff)),DataLen); if(NStatus!=STATUS_SUCCESS) { DebugString(\"Tdi Recv Allocate buffer error %X\",NStatus); return 0; } */ NB = (PNDIS_BUFFER)_HeapAllocate(sizeof(NDIS_BUFFER), HEAPZEROINIT); memcpy((PVOID)&NB->Signature, \"NBUF\", 4); NB->VirtualAddress = (PVOID)(pLockBuf + (ulLinBuf & 0xfff)); NB->Length = DataLen; // NB->VirtualAddress = (PVOID)((unsigned char *)pLockBuf + ((ULONG)Data & 0xfff)); Status = pDt->TdiReceiveEntry(&((PTDICONTEXT98)pTdiContext)->ConnRequest, &Flags, &RecvLen, NB); // DebugString(\"Recv Status = %X\",Status); if ( Status == TDI_PENDING ) { Wait_Semaphore(CallBack.cbm_sem, BLOCK_SVC_INTS); // DebugString(\"recv wait complete %d\",CallBack.Length); *ReturnLength=CallBack.Length; Status=CallBack.cbm_status; } else { DebugString(\"Recv return direct %d\",RecvLen); *ReturnLength=RecvLen; } if(!_LinPageUnLock(((DWORD) pLockBuf) >> 12, nPages, PAGEMAPGLOBAL)) { DebugString(\"Unlock page error %d\",0); } Destroy_Semaphore(CallBack.cbm_sem); //NdisFreeBuffer(NB); //NdisFreeBufferPool(PoolHandle); if (NB) _HeapFree(NB, 0); } __except (EXCEPTION_EXECUTE_HANDLER) { DebugString(\"Exception recv: %X\",Status); //就出现在这里 } return Status; } |
|
驱动老牛
|
5楼#
发布于:2005-06-07 21:11
会不会和其他环境有关系,这个是个客户端,服务器是个普通的应用程序。
|
|
6楼#
发布于:2005-06-08 09:12
服务器程序是应用程序不影响。
检查一下你的回调函数,有没有问题。 实在不行就把代码一段一段的封起来再试了,呵呵。 |
|
驱动老牛
|
7楼#
发布于:2005-06-08 10:03
这种问题我觉得比较怪异 完整历程已经过了,状态和长度都对,数据也对
就是TdiReceiveEntry调用完后就直接到异常里了,异常码是STATUS_ACCESS_VIOLATION 但是我要把Wait_Semaphore去了就没事 而且再次调用的时候就死机了。 |
|
8楼#
发布于:2005-06-08 12:11
建议用全局的信号量,不要用局部变量。
|
|
驱动老牛
|
9楼#
发布于:2005-06-08 13:44
非常感谢你的帮助 能不能加我QQ聊聊?
|
|
10楼#
发布于:2005-06-08 14:32
在receive的时候调用Wait_Semaphore应该不可以,没有分析过98,可以类比2k的代码,你的receive是一个回调函数,是在dpc里面被调用,这个时候调用KeWaitForSingleObject去切换线程肯定是不可以的。
98虽然不同,但os原理是一样的,不要去调用Wait_Semophore,最好安装回调函数,在回调函数里处理。看看98上tdi有没有这种机制 |
|
驱动老牛
|
11楼#
发布于:2005-06-08 14:40
在receive的时候调用Wait_Semaphore应该不可以,没有分析过98,可以类比2k的代码,你的receive是一个回调函数,是在dpc里面被调用,这个时候调用KeWaitForSingleObject去切换线程肯定是不可以的。 回调是安了的,在回调里释放的。98里必须安装回调函数,我在SEND CONN里都是这么用的都没有问题就是RECEIVE里就不行。 而且我看网上几乎所有的RECV实现都是这么做的。 |
|
12楼#
发布于:2005-06-08 15:21
[quote]在receive的时候调用Wait_Semaphore应该不可以,没有分析过98,可以类比2k的代码,你的receive是一个回调函数,是在dpc里面被调用,这个时候调用KeWaitForSingleObject去切换线程肯定是不可以的。 回调是安了的,在回调里释放的。98里必须安装回调函数,我在SEND CONN里都是这么用的都没有问题就是RECEIVE里就不行。 而且我看网上几乎所有的RECV实现都是这么做的。 [/quote] 1。网上Recv里面调了Wait_Semaphore吗? 2。还是类比2k,Send是在passiv level,recevice是在dpc,所以send 可以,但receive就会有问题 |
|
驱动老牛
|
13楼#
发布于:2005-06-08 15:49
[quote][quote]在receive的时候调用Wait_Semaphore应该不可以,没有分析过98,可以类比2k的代码,你的receive是一个回调函数,是在dpc里面被调用,这个时候调用KeWaitForSingleObject去切换线程肯定是不可以的。 回调是安了的,在回调里释放的。98里必须安装回调函数,我在SEND CONN里都是这么用的都没有问题就是RECEIVE里就不行。 而且我看网上几乎所有的RECV实现都是这么做的。 [/quote] 1。网上Recv里面调了Wait_Semaphore吗? 2。还是类比2k,Send是在passiv level,recevice是在dpc,所以send 可以,但receive就会有问题 [/quote] 网上例子比较少,但偶尔发现的代码里都是这样。 我跟踪发现并不是这出错因为调用完RECEIVE后进行完成历程完了就直接到了异常里去了,后面那句调试输出都没有出来。 这几天发现的问题太奇怪了,这个东东我都搞了一个星期了 |
|
14楼#
发布于:2005-06-08 16:08
不要用Wait_semaphore,如果还有问题,再分析
|
|
驱动老牛
|
15楼#
发布于:2005-06-08 16:19
不要用Wait_semaphore,如果还有问题,再分析 我已经换成WaitForSingleObject了,但是错误还是一样的。 Status = pDt->TdiReceiveEntry(&((PTDICONTEXT98)pTdiContext)->ConnRequest, &Flags, &RecvLen, NB); DebugString(\"Recv Status = %X\",Status); if ( Status == TDI_PENDING ) { WaitEvent(CallBack.m_Event); WaitEvent是封装了的。 |
|
16楼#
发布于:2005-06-08 16:34
[quote]不要用Wait_semaphore,如果还有问题,再分析 我已经换成WaitForSingleObject了,但是错误还是一样的。 Status = pDt->TdiReceiveEntry(&((PTDICONTEXT98)pTdiContext)->ConnRequest, &Flags, &RecvLen, NB); DebugString(\"Recv Status = %X\",Status); if ( Status == TDI_PENDING ) { WaitEvent(CallBack.m_Event); WaitEvent是封装了的。 [/quote] WaitForSingleOjbect和Wait_Semaphore是一样的,都不要用,总之在这里不能等待, |
|
驱动老牛
|
17楼#
发布于:2005-06-08 16:58
如果不等的话,问题是我怎么知道什么时候返回了
|
|
驱动老牛
|
18楼#
发布于:2005-06-08 17:58
晕死,活人让尿憋死了,怎样都是对的只是回调函数必须是__cdecl类型,希望大家不要犯类似的错误。
非常感谢两位的热切帮助,分已给出......... |
|