windows-nt/Source/XPSP1/NT/net/irda/irtranp/complete.cpp
2020-09-26 16:20:57 +08:00

1062 lines
35 KiB
C++

//---------------------------------------------------------------------
// Copyright (C)1998 Microsoft Corporation, All Rights Reserved.
//
// complete.cpp
//
// This is the main for the IrTran-P service.
//---------------------------------------------------------------------
#include "precomp.h"
#include "irrecv.h"
#include <malloc.h>
extern BOOL LaunchUi( wchar_t * cmdline ); // Defined: ..\irxfer\
extern CCONNECTION_MAP *g_pConnectionMap; // Defined: irtranp.cpp
extern BOOL ReceivesAllowed(); // Defined: irtranp.cpp
extern BOOL CheckSaveAsUPF(); // Defined: irtranp.cpp
//---------------------------------------------------------------------
// Constants:
//---------------------------------------------------------------------
#define DEFAULT_TIMEOUT 10000
//---------------------------------------------------------------------
// ExplorePictures()
//
//---------------------------------------------------------------------
DWORD ExplorePictures()
{
# define EXPLORER_EXE TEXT("explorer.exe")
DWORD dwStatus = NO_ERROR;
DWORD dwFlags;
HANDLE hUserToken = ::GetUserToken();
WCHAR *pwszPath;
WCHAR *pwszCommandLine;
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
if (CheckExploreOnCompletion() && (hUserToken))
{
memset(&StartupInfo,0,sizeof(StartupInfo));
memset(&ProcessInfo,0,sizeof(ProcessInfo));
pwszPath = CCONNECTION::ConstructPicturesSubDirectory();
if (!pwszPath)
{
dwStatus = ERROR_IRTRANP_OUT_OF_MEMORY;
return dwStatus;
}
pwszCommandLine = (WCHAR*)_alloca( sizeof(WCHAR)
* (wcslen(pwszPath)+wcslen(EXPLORER_EXE)+6) ); // 4 is space + 2 quotes + trailing zero + 2 extra
wcscpy(pwszCommandLine,EXPLORER_EXE);
wcscat(pwszCommandLine,TEXT(" \""));
wcscat(pwszCommandLine,pwszPath);
wcscat(pwszCommandLine,TEXT("\""));
dwFlags = 0;
if (!CreateProcessAsUserW(
hUserToken,
0, // App name in command line.
pwszCommandLine,
0, // lpProcessAttributes (security)
0, // lpThreadAttributes (security)
FALSE, // bInheritHandles
dwFlags,
0, // pEnvironment block
pwszPath, // Current Directory
&StartupInfo,
&ProcessInfo ))
{
dwStatus = GetLastError();
#ifdef DBG_ERROR
DbgPrint("IrTranP: CreateProcessAsUser() failed: %d\n",dwStatus);
#endif
}
FreeMemory(pwszPath);
}
return dwStatus;
}
//---------------------------------------------------------------------
// ReceiveComplete()
//
//---------------------------------------------------------------------
void ReceiveComplete( IN CCONNECTION *pConnection,
IN DWORD dwStatusCode )
{
DWORD dwStatus = NO_ERROR;
handle_t hBinding = ::GetRpcBinding();
if (!pConnection)
{
return;
}
// Hide the progress dialog:
if (hBinding)
{
#ifdef DBG_RETURN_STATUS
DbgPrint("ReceiveComplete(): StatusCode: 0x%x (%d)\n",
dwStatusCode, dwStatusCode );
#endif
ReceiveFinished( hBinding, pConnection->GetUiCookie(), dwStatusCode );
}
if ( (dwStatusCode == NO_ERROR)
|| (dwStatusCode == ERROR_SCEP_UNSPECIFIED_DISCONNECT)
|| (dwStatusCode == ERROR_SCEP_USER_DISCONNECT)
|| (dwStatusCode == ERROR_SCEP_PROVIDER_DISCONNECT) )
{
dwStatus = pConnection->Impersonate();
if (dwStatus == NO_ERROR)
{
dwStatus = ExplorePictures();
}
dwStatus = pConnection->RevertToSelf();
}
}
//---------------------------------------------------------------------
// ProcessConnectRequest()
//
// Called by ProcessClient() when the input PDU message type is
// MSG_TYPE_CONNECT_REQ.
//
// pConnection - The newly established Winsock connection with the
// camera.
//
// pPdu - The SCEP PDU holding the connect request. It was
// allocated in ProcessClient() by AssemblePdu() and
// will always be free'd when ProcessConnectRequest()
// finishes.
//
// dwPduSize - The size of the input PDU in bytes.
//
//---------------------------------------------------------------------
DWORD ProcessConnectRequest( IN CCONNECTION *pConnection,
IN SCEP_HEADER *pPdu,
IN DWORD dwPduSize )
{
DWORD dwStatus;
DWORD dwRespPduSize;
BOOL fReceivesAllowed = ::ReceivesAllowed();
SCEP_HEADER *pRespPdu;
CIOPACKET *pNewIoPacket; // Posted IO packet (by SendPdu()).
CSCEP_CONNECTION *pScepConnection
= (CSCEP_CONNECTION*)pConnection->GetScepConnection();
if (fReceivesAllowed)
{
// Build an connection accept acknowledgement:
dwStatus = pScepConnection->BuildConnectRespPdu(&pRespPdu,
&dwRespPduSize);
}
else
{
// Build a connect NACK:
dwStatus = pScepConnection->BuildConnectNackPdu(&pRespPdu,
&dwRespPduSize);
}
if (dwStatus == NO_ERROR)
{
pConnection->SendPdu(pRespPdu,dwRespPduSize,&pNewIoPacket);
if (pNewIoPacket)
{
pNewIoPacket->SetWritePdu(pRespPdu);
}
else
{
DeletePdu(pRespPdu);
}
if (!fReceivesAllowed)
{
// Note: After sending a NACK, the camera should close
// the connection, but at lease some don't, so I'm
// forced to slam the connection...
pConnection->CloseSocket(); // Was: ShutdownSocket().
}
}
DeletePdu(pPdu);
return dwStatus;
}
//---------------------------------------------------------------------
// ProcessConnectResponse()
//
// Called by ProcessClient() when the input PDU message type is
// MSG_TYPE_CONNECT_RESP.
//
// NOTE: Note implemented in the IrTran-P server, because the server
// is not currently setup to connect to a camera to download
// pictures back to the camera... We should never get this PDU
// during normal operation.
//
// pConnection - The newly established Winsock connection with the
// camera.
//
// pPdu - The SCEP PDU holding the connect request. It was
// allocated in ProcessClient() by AssemblePdu() and
// will always be free'd when ProcessConnectResponse()
// finishes.
//
// dwPduSize - The size of the input PDU in bytes.
//
//---------------------------------------------------------------------
DWORD ProcessConnectResponse( CCONNECTION *pConnection,
SCEP_HEADER *pPdu,
DWORD dwPduSize )
{
DWORD dwStatus = NO_ERROR;
#ifdef DBG_ERROR
DbgPrint("ProcessClient(): Unimplemented MSG_TYPE_CONNECT_RESP\n");
#endif
DeletePdu(pPdu);
return dwStatus;
}
//---------------------------------------------------------------------
// ProcessData()
//
// Called by ProcessClient() when the input PDU message type is
// MSG_TYPE_DATA.
//
// pConnection - The newly established Winsock connection with the
// camera.
//
// pPdu - The SCEP PDU holding the connect request. It was
// allocated in ProcessClient() by AssemblePdu() and
// will always be free'd when ProcessConnectResponse()
// finishes.
//
// dwPduSize - The size of the input PDU in bytes.
//
//---------------------------------------------------------------------
DWORD ProcessData( CCONNECTION *pConnection,
SCEP_HEADER *pPdu,
DWORD dwPduSize,
COMMAND_HEADER *pCommandHeader,
UCHAR *pUserData,
DWORD dwUserDataSize )
{
DWORD dwStatus = NO_ERROR;
DWORD dwRespPduSize;
DWORD dwBftpOp = 0;
UCHAR *pPutData;
DWORD dwPutDataSize;
DWORD dwJpegOffset;
DWORD dwJpegSize;
SCEP_HEADER *pRespPdu;
CIOPACKET *pNewIoPacket; // Posted IO packet (by SendPdu()).
CSCEP_CONNECTION *pScepConnection
= (CSCEP_CONNECTION*)pConnection->GetScepConnection();
// First, check to see if this is an abort PDU, send by the camera:
if ( (pCommandHeader) && (pCommandHeader->PduType == PDU_TYPE_ABORT) )
{
DeletePdu(pPdu);
return ERROR_SCEP_ABORT;
}
// Is one of the 2nd through Nth fragments of a fragmented PDU?
if ( (pScepConnection->IsFragmented())
&& (pScepConnection->GetSequenceNo() > 0))
{
#ifdef DBG_IO
DbgPrint("ProcessClient(): Put Fragment: SequenceNo: %d RestNo: %d\n",
pScepConnection->GetSequenceNo(),
pScepConnection->GetRestNo() );
#endif
pConnection->WritePictureFile( pUserData,
dwUserDataSize,
&pNewIoPacket );
if (pNewIoPacket)
{
pNewIoPacket->SetWritePdu(pPdu);
}
else
{
DeletePdu(pPdu);
}
if (pScepConnection->GetDFlag() == DFLAG_LAST_FRAGMENT)
{
#ifdef DBG_IO
DbgPrint("ProcessClient(): Put ACK\n");
#endif
pScepConnection->BuildPutRespPdu( PDU_TYPE_REPLY_ACK,
ERROR_PUT_NO_ERROR,
&pRespPdu,
&dwRespPduSize);
pConnection->SendPdu( pRespPdu,
dwRespPduSize,
&pNewIoPacket);
if (pNewIoPacket)
{
pNewIoPacket->SetWritePdu(pRespPdu);
}
else
{
DeletePdu(pRespPdu);
}
}
}
else if (pCommandHeader)
{
// Length4 in the COMMAN_HEADER is the user data size
// plus the bytes for machine ids (16), the DestPid (2),
// SrcPid (2) and CommandId (2) so offset by 22.
#ifdef DBG_IO
DbgPrint("ProcessData(): SaveAsUPF(): %d\n",
pConnection->CheckSaveAsUPF() );
#endif
dwStatus = pScepConnection->ParseBftp( pUserData,
dwUserDataSize,
pConnection->CheckSaveAsUPF(),
&dwBftpOp,
&pPutData,
&dwPutDataSize );
if ((dwStatus == NO_ERROR) && (IsBftpQuery(dwBftpOp)))
{
pScepConnection->BuildWht0RespPdu(dwBftpOp,
&pRespPdu,
&dwRespPduSize);
pConnection->SendPdu( pRespPdu,
dwRespPduSize,
&pNewIoPacket );
if (pNewIoPacket)
{
pNewIoPacket->SetWritePdu(pRespPdu);
}
else
{
DeletePdu(pRespPdu);
}
DeletePdu(pPdu);
}
else if ((dwStatus == NO_ERROR) && (IsBftpPut(dwBftpOp)))
{
//
// Ok, we have a bFTP PUT command, so open a file
// and get ready to start collecting image data.
//
dwStatus = pScepConnection->ParseUpfHeaders( pPutData,
dwPutDataSize,
&dwJpegOffset,
&dwJpegSize );
pConnection->SetJpegOffsetAndSize(dwJpegOffset,dwJpegSize);
dwStatus = pConnection->Impersonate();
dwStatus = pConnection->CreatePictureFile();
dwStatus = pConnection->SetPictureFileTime( pScepConnection->GetCreateTime() );
dwStatus = pConnection->RevertToSelf();
dwStatus = pConnection->WritePictureFile( pPutData,
dwPutDataSize,
&pNewIoPacket );
if (pNewIoPacket)
{
pNewIoPacket->SetWritePdu(pPdu);
}
else
{
DeletePdu(pPdu);
}
if (pScepConnection->IsFragmented())
{
#ifdef DBG_IO
DbgPrint("ProcessClient(): Image File: %s Size: %d\n",
pScepConnection->GetFileName(),
pCommandHeader->Length4 );
DbgPrint("ProcessClient(): SequenceNo: %d RestNo: %d\n",
pScepConnection->GetSequenceNo(),
pScepConnection->GetRestNo() );
#endif
}
else
{
#ifdef DBG_IO
DbgPrint("ProcessClient(): Put Command: Unfragmented\n");
#endif
}
}
else if (IsBftpError(dwBftpOp))
{
#ifdef DBG_ERROR
DbgPrint("ProcessClient(): bFTP Error: %d\n", dwStatus );
#endif
DeletePdu(pPdu);
dwStatus = ERROR_BFTP_INVALID_PROTOCOL;
}
else
{
#ifdef DBG_ERROR
DbgPrint("ProcessClient(): Unknown bFTP Command: %d\n",dwBftpOp);
#endif
DeletePdu(pPdu);
dwStatus = ERROR_BFTP_INVALID_PROTOCOL;
}
}
return dwStatus;
}
//---------------------------------------------------------------------
// ProcessDisconnect()
//
// Called by ProcessClient() when the input PDU message type is
// MSG_TYPE_DISCONNECT.
//
// pConnection - The newly established Winsock connection with the
// camera.
//
// pPdu - The SCEP PDU holding the connect request. It was
// allocated in ProcessClient() by AssemblePdu() and
// will always be free'd when ProcessConnectResponse()
// finishes.
//
// dwPduSize - The size of the input PDU in bytes.
//
//---------------------------------------------------------------------
DWORD ProcessDisconnect( CCONNECTION *pConnection,
SCEP_HEADER *pPdu,
DWORD dwPduSize )
{
DWORD dwStatus = NO_ERROR;
// Don't need to do anything special here, since
// ParsePdu() will set dwStatus to one of:
// ERROR_SCEP_UNSPECIFIED_DISCONNECT (5002)
// ERROR_SCEP_USER_DISCONNECT (5003)
// or ERROR_SCEP_PROVIDER_DISCONNECT (5004)
#ifdef DBG_IO
DbgPrint("ProcessClient(): Disconnect: %d\n",dwStatus);
#endif
pConnection->SetReceiveComplete(TRUE);
DeletePdu(pPdu);
return dwStatus;
}
//---------------------------------------------------------------------
// ProcessClient()
//
//---------------------------------------------------------------------
DWORD ProcessClient( CIOSTATUS *pIoStatus,
CIOPACKET *pIoPacket,
DWORD dwNumBytes )
{
char *pBuffer;
DWORD dwStatus = NO_ERROR;
SOCKET Socket = pIoPacket->GetSocket();
CCONNECTION *pConnection;
CSCEP_CONNECTION *pScepConnection;
SCEP_HEADER *pPdu;
DWORD dwPduSize;
COMMAND_HEADER *pCommandHeader;
UCHAR *pUserData; // Location of bFTP data.
DWORD dwUserDataSize;
DWORD dwError = 0;
handle_t hBinding;
WCHAR wsCmdLine[80];
pConnection = g_pConnectionMap->Lookup(Socket);
if (!pConnection)
{
return ERROR_IRTRANP_OUT_OF_MEMORY;
}
pScepConnection = (CSCEP_CONNECTION*)pConnection->GetScepConnection();
ASSERT(pScepConnection);
pBuffer = pIoPacket->GetReadBuffer();
while (dwStatus == NO_ERROR)
{
dwStatus = pScepConnection->AssemblePdu( pBuffer,
dwNumBytes,
&pPdu,
&dwPduSize );
if (dwStatus == NO_ERROR)
{
dwStatus = pScepConnection->ParsePdu( pPdu,
dwPduSize,
&pCommandHeader,
&pUserData,
&dwUserDataSize );
switch (pPdu->MsgType)
{
case MSG_TYPE_CONNECT_REQ:
// Message was an SCEP Connection Request:
wcscpy(wsCmdLine,L"irftp.exe /h");
if (!LaunchUi(wsCmdLine))
{
dwError = GetLastError();
#ifdef DBG_ERROR
DbgPrint("LaunchUi(): Failed: %d\n",dwError);
#endif
}
hBinding = pIoStatus->GetRpcBinding();
if (hBinding)
{
COOKIE cookie;
dwError = ReceiveInProgress( hBinding, L"", &cookie, TRUE );
pConnection->SetUiCookie( cookie );
#ifdef DBG_ERROR
if (dwError)
{
DbgPrint("ReceiveInProgress() returned: %d\n",
dwError);
}
#endif
}
dwStatus = ProcessConnectRequest(pConnection,
pPdu,
dwPduSize );
if ((dwStatus) || (!ReceivesAllowed()))
{
ReceiveComplete(pConnection,dwStatus);
}
break;
case MSG_TYPE_CONNECT_RESP:
// Message was a reply from a connection request:
dwStatus = ProcessConnectResponse(pConnection,
pPdu,
dwPduSize );
break;
case MSG_TYPE_DATA:
// Message is a SCEP command of some sort:
dwStatus = ProcessData(pConnection,
pPdu,
dwPduSize,
pCommandHeader,
pUserData,
dwUserDataSize );
break;
case MSG_TYPE_DISCONNECT:
// Message from the camera was a disconnect:
ProcessDisconnect(pConnection,
pPdu,
dwPduSize );
ReceiveComplete(pConnection,dwStatus);
break;
default:
#ifdef DBG_ERROR
DbgPrint("ProcessClient(): Unknown MSG_TYPE_xxx: %d\n",
pPdu->MsgType );
#endif
DeletePdu(pPdu);
break;
}
}
else
{
break;
}
pBuffer = 0;
dwNumBytes = 0;
}
if (dwStatus == ERROR_CONTINUE)
{
dwStatus = NO_ERROR;
}
return dwStatus;
}
//---------------------------------------------------------------------
// SendAbortPdu()
//
// Stop the camera.
//
// I should be able to send a Stop PDU, followed by a Disconnect, or
// maybe an Abort PDU, but these don't work on all the cameras, so I
// currently end up just doing a hard close on the connection to the
// camera.
//---------------------------------------------------------------------
DWORD SendAbortPdu( IN CCONNECTION *pConnection )
{
DWORD dwStatus = NO_ERROR;
#if TRUE
if (pConnection)
{
pConnection->CloseSocket();
}
#else
DWORD dwPduSize;
SCEP_HEADER *pPdu;
CIOPACKET *pNewIoPacket = 0;
CSCEP_CONNECTION *pScepConnection
= (CSCEP_CONNECTION*)pConnection->GetScepConnection();
if (pScepConnection)
{
dwStatus = pScepConnection->BuildStopPdu(&pPdu,&dwPduSize);
if (dwStatus != NO_ERROR)
{
pConnection->CloseSocket();
return dwStatus;
}
dwStatus = pConnection->SendPdu(pPdu,dwPduSize,&pNewIoPacket);
if (dwStatus != NO_ERROR)
{
DeletePdu(pPdu);
pConnection->CloseSocket();
return dwStatus;
}
pNewIoPacket->SetWritePdu(pPdu);
dwStatus = pScepConnection->BuildDisconnectPdu(
REASON_CODE_PROVIDER_DISCONNECT,
&pPdu,
&dwPduSize);
if (dwStatus != NO_ERROR)
{
pConnection->CloseSocket();
return dwStatus;
}
dwStatus = pConnection->SendPdu(pPdu,dwPduSize,&pNewIoPacket);
if (dwStatus != NO_ERROR)
{
DeletePdu(pPdu);
pConnection->CloseSocket();
return dwStatus;
}
pNewIoPacket->SetWritePdu(pPdu);
}
#endif
return dwStatus;
}
//---------------------------------------------------------------------
// MapStatusCode()
//
//---------------------------------------------------------------------
DWORD MapStatusCode( DWORD dwStatus,
DWORD dwDefaultStatus )
{
// The Facility part of an error code are the first 12 bits of the
// high word (16bits):
#define FACILITY_MASK 0x0FFF0000
// If the error code is already an IrTran-P error code, then don't
// remap it:
if ( ((dwStatus&FACILITY_MASK) >> 16) == FACILITY_IRTRANP)
{
return dwStatus;
}
// Map other errors:
if (dwStatus != NO_ERROR)
{
if ( (dwStatus == ERROR_DISK_FULL)
|| (dwStatus == ERROR_WRITE_FAULT)
|| (dwStatus == ERROR_WRITE_PROTECT)
|| (dwStatus == ERROR_GEN_FAILURE)
|| (dwStatus == ERROR_NOT_DOS_DISK) )
{
dwStatus = ERROR_IRTRANP_DISK_FULL;
}
else
{
dwStatus = dwDefaultStatus;
}
}
return dwStatus;
}
//---------------------------------------------------------------------
// ProcessIoPackets()
//
//---------------------------------------------------------------------
DWORD ProcessIoPackets( CIOSTATUS *pIoStatus )
{
DWORD dwStatus = NO_ERROR;
DWORD dwProcessStatus = NO_ERROR; // Processing IO status.
DWORD dwNumBytes;
ULONG_PTR dwKey;
DWORD dwTimeout = DEFAULT_TIMEOUT;
LONG lPendingIos; // # of pending reads/writes on a CCONNECTION.
LONG lPendingReads; // # of pending reads on a CCONNECTION.
LONG lPendingWrites; // # of pending file writes on a CCONNECTION.
OVERLAPPED *pOverlapped;
CCONNECTION *pConnection;
CCONNECTION *pNewConnection;
CSCEP_CONNECTION *pScepConnection;
CIOPACKET *pIoPacket = 0;
CIOPACKET *pNewIoPacket = 0;
HANDLE hIoCompletionPort = pIoStatus->GetIoCompletionPort();
// Wait on the IO completion port for incomming connections:
while (TRUE)
{
pIoStatus->IncrementNumPendingThreads();
dwNumBytes = 0;
dwKey = 0;
pOverlapped = 0;
if (!GetQueuedCompletionStatus( hIoCompletionPort,
&dwNumBytes,
&dwKey,
&pOverlapped,
dwTimeout ))
{
dwStatus = GetLastError();
pIoStatus->DecrementNumPendingThreads();
if (dwStatus != WAIT_TIMEOUT)
{
// Got an error. Two cases during an error,
// data may or may not have been dequeued from
// the IO completion port.
if (pOverlapped)
{
pIoPacket = CIOPACKET::CIoPacketFromOverlapped(pOverlapped);
pConnection = g_pConnectionMap->Lookup(dwKey);
// ASSERT(pConnection);
if (!pConnection)
{
delete pIoPacket;
continue;
}
if (pIoPacket->GetIoPacketKind() == PACKET_KIND_READ)
{
lPendingReads = pConnection->DecrementPendingReads();
ASSERT(lPendingReads >= 0);
}
else if (pIoPacket->GetIoPacketKind() == PACKET_KIND_WRITE_FILE)
{
lPendingWrites = pConnection->DecrementPendingWrites();
ASSERT(lPendingWrites >= 0);
SCEP_HEADER *pPdu = (SCEP_HEADER*)pIoPacket->GetWritePdu();
if (pPdu)
{
DeletePdu(pPdu);
}
}
else if (pIoPacket->GetIoPacketKind() == PACKET_KIND_WRITE_SOCKET)
{
SCEP_HEADER *pPdu = (SCEP_HEADER*)pIoPacket->GetWritePdu();
if (pPdu)
{
DeletePdu(pPdu);
}
}
else if (pIoPacket->GetIoPacketKind() == PACKET_KIND_LISTEN)
{
// One of the listen sockets was shutdown (closed):
delete pIoPacket;
continue;
}
// Check to see if there was a transmission error, or
// there was an error writing the picture to disk:
if (dwStatus != ERROR_NETNAME_DELETED)
{
DWORD dwStatusCode;
SendAbortPdu(pConnection);
pConnection->DeletePictureFile();
dwStatusCode = MapStatusCode(
dwStatus,
ERROR_SCEP_PROVIDER_DISCONNECT);
ReceiveComplete(pConnection,dwStatusCode);
}
else
{
// if (pConnection->IncompleteFile())
dwProcessStatus = MapStatusCode(
dwProcessStatus,
ERROR_SCEP_INVALID_PROTOCOL );
ReceiveComplete(pConnection,dwProcessStatus);
}
// Delete the connection if there are no more pending
// IOs...
lPendingIos = pConnection->NumPendingIos();
if (lPendingIos == 0)
{
g_pConnectionMap->Remove(dwKey);
delete pConnection;
}
#ifdef DBG_ERROR
if (dwStatus != ERROR_NETNAME_DELETED)
{
DbgPrint("GetQueuedCompletionStatus(): Socket: %d PendingIos: %d Failed: 0x%x\n",
dwKey, lPendingIos, dwStatus );
}
#endif
delete pIoPacket;
}
else
{
#ifdef DBG_ERROR
DbgPrint("GetQueuedCompletionStatus(): Socket: %d Failed: %d (no overlapped)\n",
dwKey, dwStatus );
#endif
ReceiveComplete(pConnection,ERROR_SCEP_PROVIDER_DISCONNECT);
}
continue;
}
else
{
// Wait timeout, loop back and continue...
}
}
else
{
// IO completed. Either we got a new connection to a client,
// or more data has come in from an existing connection to
// a client.
// First, check to see if the shudown (uninintalize code)
// wants us to shutdown:
if ((dwKey == IOKEY_SHUTDOWN) && (!pOverlapped))
{
return dwStatus;
}
pConnection = g_pConnectionMap->Lookup(dwKey);
if (!pConnection)
{
#ifdef DBG_ERROR
DbgPrint("ProcessIoPackets(): Lookup(%d) Failed: Bytes: %d pOverlapped: 0x%x\n",
dwKey,
dwNumBytes,
pOverlapped );
#endif
pIoPacket = CIOPACKET::CIoPacketFromOverlapped(pOverlapped);
if (pIoPacket)
{
delete pIoPacket;
}
continue;
}
pIoStatus->DecrementNumPendingThreads();
pIoPacket = CIOPACKET::CIoPacketFromOverlapped(pOverlapped);
DWORD dwKind = pIoPacket->GetIoPacketKind();
if (dwKind == PACKET_KIND_LISTEN)
{
// New connection:
lPendingReads = pConnection->DecrementPendingReads();
ASSERT(lPendingReads >= 0);
#ifdef DBG_IO
SOCKADDR_IRDA *pAddrLocal = 0;
SOCKADDR_IRDA *pAddrFrom = 0;
pIoPacket->GetSockAddrs(&pAddrLocal,&pAddrFrom);
DbgPrint("ProcessIoPackets(): Accepted connection from 0x%2.2x%2.2x%2.2x%2.2x, service %s\n",
pAddrFrom->irdaDeviceID[0],
pAddrFrom->irdaDeviceID[1],
pAddrFrom->irdaDeviceID[2],
pAddrFrom->irdaDeviceID[3],
pAddrFrom->irdaServiceName );
#endif
pScepConnection = new CSCEP_CONNECTION;
if (!pScepConnection)
{
#ifdef DBG_ERROR
DbgPrint("ProcessIoPackets(): Out of memeory.\n");
#endif
delete pIoPacket;
continue;
}
pNewConnection = new CCONNECTION(
PACKET_KIND_READ,
pIoPacket->GetSocket(),
pIoPacket->GetIoCompletionPort(),
pScepConnection,
::CheckSaveAsUPF() );
if (!pNewConnection)
{
#ifdef DBG_ERROR
DbgPrint("ProcessIoPackets(): Out of memeory.\n");
#endif
delete pScepConnection;
delete pIoPacket;
continue;
}
g_pConnectionMap->Add(pNewConnection,
pNewConnection->GetSocket() );
delete pIoPacket;
dwStatus = pNewConnection->PostMoreIos();
dwStatus = pConnection->PostMoreIos();
}
else if (dwKind == PACKET_KIND_WRITE_SOCKET)
{
#ifdef DBG_IO
DbgPrint("ProcessIoPackets(): Write completed: Socket: %d Bytes: %d\n",
dwKey,
dwNumBytes );
#endif
SCEP_HEADER *pPdu = (SCEP_HEADER*)pIoPacket->GetWritePdu();
if (pPdu)
{
DeletePdu(pPdu);
}
delete pIoPacket;
}
else if (dwKind == PACKET_KIND_WRITE_FILE)
{
lPendingWrites = pConnection->DecrementPendingWrites();
ASSERT(lPendingWrites >= 0);
#ifdef DBG_IO
DbgPrint("ProcessIoPackets(): Write File: Handle: %d Bytes: %d NumPendingIos: %d\n",
dwKey, dwNumBytes, pConnection->NumPendingIos() );
#endif
SCEP_HEADER *pPdu = (SCEP_HEADER*)pIoPacket->GetWritePdu();
if (pPdu)
{
DeletePdu(pPdu);
}
delete pIoPacket;
}
else
{
// Incomming data from connection client:
ASSERT(dwKind == PACKET_KIND_READ);
lPendingReads = pConnection->DecrementPendingReads();
ASSERT(lPendingReads >= 0);
#ifdef DBG_IO
DbgPrint("ProcessIoPackets(): Read completed: Socket: %d Bytes: %d\n",
dwKey,
dwNumBytes );
#endif
if (dwNumBytes)
{
dwProcessStatus
= ProcessClient(pIoStatus,pIoPacket,dwNumBytes);
if (dwProcessStatus == NO_ERROR)
{
dwStatus = pConnection->PostMoreIos();
}
else
{
#ifdef DBG_ERROR
if ( (dwProcessStatus != ERROR_SCEP_UNSPECIFIED_DISCONNECT)
&& (dwProcessStatus != ERROR_SCEP_USER_DISCONNECT)
&& (dwProcessStatus != ERROR_SCEP_PROVIDER_DISCONNECT) )
{
DbgPrint("ProcessIoPackets(): ProcessClient(): Failed: 0x%x\n",dwProcessStatus);
}
#endif
pConnection->CloseSocket();
}
delete pIoPacket;
}
else
{
if (pConnection->NumPendingIos() == 0)
{
g_pConnectionMap->RemoveConnection(pConnection);
delete pConnection;
pConnection = 0;
}
delete pIoPacket;
}
}
}
}
return 0;
}