1062 lines
35 KiB
C++
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;
|
||
|
}
|