|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
net\routing\ipx\sap\netio.c
Abstract: This module handles network io for sap agent
Author:
Vadim Eydelman 05-15-1995
Revision History:
--*/
#include "sapp.h"
// Queues and synchronization associated with net io
typedef struct _IO_QUEUES { HANDLE IQ_AdptHdl; // Handle to SAP socket port
HANDLE IQ_RecvEvent; // Event signalled when recv completes
#if DBG
LIST_ENTRY IQ_SentPackets; // Packets that are being sent
LIST_ENTRY IQ_RcvdPackets; // Packets that are being received
#endif
CRITICAL_SECTION IQ_Lock; // Queue data protection
} IO_QUEUES, *PIO_QUEUES;
IO_QUEUES IOQueues;
VOID CALLBACK IoCompletionProc ( DWORD error, DWORD cbTransferred, LPOVERLAPPED ovlp );
VOID CALLBACK SendCompletionProc ( DWORD status, DWORD cbSent, PIO_PARAM_BLOCK sreq ); VOID CALLBACK RecvCompletionProc ( DWORD status, DWORD cbSent, PIO_PARAM_BLOCK rreq );
DWORD CreateIOQueue ( HANDLE *RecvEvent ) { DWORD status; InitializeCriticalSection (&IOQueues.IQ_Lock); #if DBG
InitializeListHead (&IOQueues.IQ_SentPackets); InitializeListHead (&IOQueues.IQ_RcvdPackets); #endif
IOQueues.IQ_AdptHdl = INVALID_HANDLE_VALUE;
IOQueues.IQ_RecvEvent = CreateEvent (NULL, FALSE, // auto-reset (reset by recv operation
// and when thread is signalled (it may
// not post new request if limit is
// exceded)
FALSE, // not signalled
NULL); if (IOQueues.IQ_RecvEvent!=NULL) { INT i; *RecvEvent = IOQueues.IQ_RecvEvent; return NO_ERROR; } else { status = GetLastError (); Trace (DEBUG_FAILURES, "Failed to create recv comp event (gle:%ld)", status); } DeleteCriticalSection (&IOQueues.IQ_Lock); return status; }
VOID DeleteIOQueue ( VOID ) { CloseHandle (IOQueues.IQ_RecvEvent); DeleteCriticalSection (&IOQueues.IQ_Lock); }
DWORD StartIO ( VOID ) { DWORD status=NO_ERROR;
EnterCriticalSection (&IOQueues.IQ_Lock); if (IOQueues.IQ_AdptHdl==INVALID_HANDLE_VALUE) { USHORT sockNum; IpxSockCpy (&sockNum, IPX_SAP_SOCKET); Trace (DEBUG_NET_IO, "Creating socket port."); IOQueues.IQ_AdptHdl = CreateSocketPort (sockNum); if (IOQueues.IQ_AdptHdl!=INVALID_HANDLE_VALUE) { status = NO_ERROR; if (! BindIoCompletionCallback( IOQueues.IQ_AdptHdl, IoCompletionProc, 0)) { status = GetLastError(); } if (status==NO_ERROR) { BOOL res; LeaveCriticalSection (&IOQueues.IQ_Lock); res = SetEvent (IOQueues.IQ_RecvEvent); ASSERTMSG ("Could not set recv event ", res); return NO_ERROR; } else { status = GetLastError (); Trace (DEBUG_FAILURES, "Failed to create completion port (gle:%ld)", status); } DeleteSocketPort (IOQueues.IQ_AdptHdl); IOQueues.IQ_AdptHdl = INVALID_HANDLE_VALUE; } else { status = GetLastError (); Trace (DEBUG_FAILURES, "Failed to create adapter port (gle:%ld)", status); IF_LOG (EVENTLOG_ERROR_TYPE) { RouterLogErrorA (RouterEventLogHdl, ROUTERLOG_IPXSAP_SAP_SOCKET_IN_USE, 0, NULL, status);
} } } LeaveCriticalSection (&IOQueues.IQ_Lock); return status; }
VOID StopIO ( VOID ) { EnterCriticalSection (&IOQueues.IQ_Lock); if (IOQueues.IQ_AdptHdl!=INVALID_HANDLE_VALUE) { DWORD status; HANDLE Port = IOQueues.IQ_AdptHdl; IOQueues.IQ_AdptHdl = INVALID_HANDLE_VALUE; LeaveCriticalSection (&IOQueues.IQ_Lock);
Trace (DEBUG_NET_IO, "Deleting socket port."); DeleteSocketPort (Port);
} else LeaveCriticalSection (&IOQueues.IQ_Lock); }
/*++
******************************************************************* I o C o m p l e t i o n P r o c
Routine Description: Called on completion of each io request Arguments: error - result of io cbTransferred - number of bytes actually sent ovlp - overlapped structure associated with io request Return Value: None ******************************************************************* --*/ VOID CALLBACK IoCompletionProc ( DWORD error, DWORD cbTransferred, LPOVERLAPPED ovlp ) { PIO_PARAM_BLOCK req = CONTAINING_RECORD (ovlp, IO_PARAM_BLOCK, ovlp); // Get actual parameters adjusted by the adapter dll
IpxAdjustIoCompletionParams (ovlp, &cbTransferred, &error); (*req->comp)(error, cbTransferred, req); }
/*++
******************************************************************* E n q u e u e S e n d R e q u e s t
Routine Description: Sets adapter id field in request io param block and enqueues send request to adapter's driver. Arguments: sreq - io parameter block, the following fields must be set: intf - pointer to interface external data buffer - pointer to buffer that contains data to be sent cbBuffer - count of bytes of data in the buffer Return Value: None ******************************************************************* --*/ VOID EnqueueSendRequest ( PIO_PARAM_BLOCK sreq ) { DWORD status;
sreq->status = ERROR_IO_PENDING; sreq->ovlp.hEvent = NULL; sreq->comp = SendCompletionProc; #if DBG
EnterCriticalSection (&IOQueues.IQ_Lock); InsertTailList (&IOQueues.IQ_SentPackets, &sreq->link); LeaveCriticalSection (&IOQueues.IQ_Lock); #endif
status = IpxSendPacket (IOQueues.IQ_AdptHdl, sreq->adpt, sreq->buffer, sreq->cbBuffer, &sreq->rsvd, &sreq->ovlp, NULL ); // If request failed and thus completion routine won't be called
// we'll simulate completion ourselves so that request won't get
// lost
if (status!=NO_ERROR) SendCompletionProc (status, 0, sreq); }
/*++
******************************************************************* S e n d C o m p l e t i o n P r o c
Routine Description: Called on completion for each sent packet. Sets fields of send request io param block and enqueues it to completion queue. Arguments: status - result of io cbSent - number of bytes actually sent context - context associated with send request (IO_PARAM_BLOCK) Return Value: None ******************************************************************* --*/ VOID CALLBACK SendCompletionProc ( DWORD status, DWORD cbSent, PIO_PARAM_BLOCK sreq ) { BOOL res; BOOL releaseSend = FALSE;
sreq->compTime = GetTickCount (); sreq->status = status; if (status!=NO_ERROR) { #define dstPtr (sreq->buffer+FIELD_OFFSET (SAP_BUFFER, Dst.Network))
Trace (DEBUG_FAILURES, "Error %d while sending to" " %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x" " on adapter %d.", status, *dstPtr, *(dstPtr+1), *(dstPtr+2), *(dstPtr+3), *(dstPtr+4), *(dstPtr+5), *(dstPtr+6), *(dstPtr+7), *(dstPtr+8), *(dstPtr+9), *(dstPtr+10), *(dstPtr+11), sreq->adpt); #undef dstPtr
} sreq->cbBuffer = cbSent;
#if DBG
// Maintain queue of posted requests
EnterCriticalSection (&IOQueues.IQ_Lock); RemoveEntryList (&sreq->link); LeaveCriticalSection (&IOQueues.IQ_Lock); #endif
ProcessCompletedIORequest (sreq);
}
/*++
******************************************************************* E n q u e u e R e c v R e q u e s t
Routine Description: Enqueues recv request to be posted to the network driver. Arguments: rreq - io parameter block, the following fields must be set: buffer - pointer to buffer to receive data cbBuffer - size of the buffer Return Value: TRUE - need more recv requests (number of posted requests is below low water mark) FALSE - no more requests needed.
******************************************************************* --*/ VOID EnqueueRecvRequest ( PIO_PARAM_BLOCK rreq ) { DWORD status;
rreq->status = ERROR_IO_PENDING; rreq->adpt = INVALID_ADAPTER_INDEX; rreq->ovlp.hEvent = IOQueues.IQ_RecvEvent; rreq->comp = RecvCompletionProc; #if DBG
EnterCriticalSection (&IOQueues.IQ_Lock); InsertTailList (&IOQueues.IQ_RcvdPackets, &rreq->link); LeaveCriticalSection (&IOQueues.IQ_Lock); #endif
status = IpxRecvPacket (IOQueues.IQ_AdptHdl, rreq->buffer, rreq->cbBuffer, &rreq->rsvd, &rreq->ovlp, NULL ); if (status==NO_ERROR) { NOTHING; } else { Trace (DEBUG_FAILURES, "Error %d while posting receive packet", status); // If request failed and thus completion routine won't be called
// we'll simulate completion ourselves so that request won't get
// lost
RecvCompletionProc (status, 0, rreq); } }
/*++
******************************************************************* R e c v C o m p l e t i o n P r o c
Routine Description: Called on completion of each received packet. Sets fields of recv request io param block and enqueues it to completion queue. Arguments: status - result of io cbSent - number of bytes actually sent context - context associated with send request (IO_PARAM_BLOCK) Return Value: None ******************************************************************* --*/ VOID CALLBACK RecvCompletionProc ( DWORD status, DWORD cbRecvd, PIO_PARAM_BLOCK rreq ) { BOOL completed=TRUE;
rreq->adpt = GetNicId (&rreq->rsvd); rreq->compTime = GetTickCount (); rreq->cbBuffer = cbRecvd; rreq->status = status;
if (status!=NO_ERROR) Trace (DEBUG_FAILURES, "Error %d while receiving packet on adapter %d.", status, rreq->adpt); #if DBG
EnterCriticalSection (&IOQueues.IQ_Lock); RemoveEntryList (&rreq->link); LeaveCriticalSection (&IOQueues.IQ_Lock); #endif
ProcessCompletedIORequest (rreq); }
/*++
******************************************************************* D u m p P a c k e t
Routine Description: Dumps IPX SAP packet fields to stdio Arguments: Packet - pointer to IPX SAP packet count - size of the packet Return Value: None ******************************************************************* --*/ /*
#if DBG
VOID DumpPacket ( PSAP_BUFFER packet, DWORD count ) { SS_PRINTF(("Length : %d.", GETUSHORT (&packet->Length))); SS_PRINTF(("Packet type : %02X.", packet->PacketType)); SS_PRINTF(("Dest. net : %02X%02X%02X%02X.", packet->Dst.Net[0], packet->Dst.Net[1], packet->Dst.Net[2], packet->Dst.Net[3])); SS_PRINTF(("Dest. node : %02X%02X%02X%02X%02X%02X.", packet->Dst.Node[0], packet->Dst.Node[1], packet->Dst.Node[2], packet->Dst.Node[3], packet->Dst.Node[4], packet->Dst.Node[5])); SS_PRINTF(("Dest. socket : %04X.", GETUSHORT (&packet->Dst.Socket))); SS_PRINTF(("Src. net : %02X%02X%02X%02X.", packet->Src.Net[0], packet->Src.Net[1], packet->Src.Net[2], packet->Src.Net[3])); SS_PRINTF(("Src. node : %02X%02X%02X%02X%02X%02X.", packet->Src.Node[0], packet->Src.Node[1], packet->Src.Node[2], packet->Src.Node[3], packet->Src.Node[4], packet->Src.Node[5])); SS_PRINTF(("Src. socket : %04X.", GETUSHORT (&packet->Src.Socket))); if (count>=(DWORD)FIELD_OFFSET(SAP_BUFFER, Entries[0])) { INT j; SS_PRINTF(("SAP Operation : %d.", GETUSHORT (&packet->Operation))); for (j=0; (j<7) && (count>=(DWORD)FIELD_OFFSET (SAP_BUFFER, Entries[j+1])); j++) { SS_PRINTF(("Server type : %04X.", GETUSHORT (&packet->Entries[j].Type))); SS_PRINTF(("Server name : %.48s.", packet->Entries[j].Name)); SS_PRINTF(("Server net : %02X%02X%02X%02X.", packet->Entries[j].Network[0], packet->Entries[j].Network[1], packet->Entries[j].Network[2], packet->Entries[j].Network[3])); SS_PRINTF(("Server node : %02X%02X%02X%02X%02X%02X.", packet->Entries[j].Node[0], packet->Entries[j].Node[1], packet->Entries[j].Node[2], packet->Entries[j].Node[3], packet->Entries[j].Node[4], packet->Entries[j].Node[5])); SS_PRINTF(("Server socket : %02X%02X.", packet->Entries[j].Socket[0], packet->Entries[j].Socket[1])); SS_PRINTF(("Server hops : %d.", GETUSHORT (&packet->Entries[j].HopCount))); } if ((j==0) && (count>=(DWORD)FIELD_OFFSET (SAP_BUFFER, Entries[0].Name))) SS_PRINTF(("Server type : %04X.", GETUSHORT (&packet->Entries[0].Type))); } }
#endif
*/
|