Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1032 lines
36 KiB

  1. //---------------------------------------------------------------------
  2. // Copyright (C)1998 Microsoft Corporation, All Rights Reserved.
  3. //
  4. // complete.cpp
  5. //
  6. // This is the main for the IrTran-P service.
  7. //---------------------------------------------------------------------
  8. #include "precomp.h"
  9. #include <malloc.h>
  10. #include <irmonftp.h>
  11. extern BOOL LaunchUi( wchar_t * cmdline ); // Defined: ..\irxfer\
  12. extern CCONNECTION_MAP *g_pConnectionMap; // Defined: irtranp.cpp
  13. extern BOOL ReceivesAllowed(); // Defined: irtranp.cpp
  14. extern BOOL CheckSaveAsUPF(); // Defined: irtranp.cpp
  15. //---------------------------------------------------------------------
  16. // Constants:
  17. //---------------------------------------------------------------------
  18. #define DEFAULT_TIMEOUT 10000
  19. //---------------------------------------------------------------------
  20. // ExplorePictures()
  21. //
  22. //---------------------------------------------------------------------
  23. DWORD ExplorePictures()
  24. {
  25. # define EXPLORER_EXE L"explorer.exe"
  26. DWORD dwStatus = NO_ERROR;
  27. DWORD dwFlags;
  28. DWORD cb;
  29. WCHAR *pwszPath;
  30. WCHAR *pwszCommandLine;
  31. BOOL bResult;
  32. STARTUPINFO StartupInfo;
  33. PROCESS_INFORMATION ProcessInfo;
  34. WCHAR ApplicationName[MAX_PATH+1+(sizeof(EXPLORER_EXE)/sizeof(TCHAR))+1];
  35. if (CheckExploreOnCompletion() ) {
  36. ZeroMemory(&StartupInfo,sizeof(StartupInfo));
  37. ZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
  38. pwszPath = CCONNECTION::ConstructPicturesSubDirectory(0, &cb);
  39. if (!pwszPath) {
  40. dwStatus = ERROR_IRTRANP_OUT_OF_MEMORY;
  41. return dwStatus;
  42. }
  43. cb = sizeof(WCHAR) * (wcslen(pwszPath)+wcslen(EXPLORER_EXE)+6);
  44. __try
  45. {
  46. pwszCommandLine = (WCHAR*)_alloca( cb ); // 4 is space + 2 quotes + trailing zero + 2 extra
  47. }
  48. __except(EXCEPTION_EXECUTE_HANDLER)
  49. {
  50. FreeMemory(pwszPath);
  51. return 0;
  52. }
  53. StringCbCopy(pwszCommandLine,cb,EXPLORER_EXE);
  54. StringCbCat(pwszCommandLine,cb,TEXT(" \""));
  55. StringCbCat(pwszCommandLine,cb,pwszPath);
  56. StringCbCat(pwszCommandLine,cb,TEXT("\""));
  57. cb=GetSystemWindowsDirectoryW(ApplicationName,sizeof(ApplicationName)/sizeof(WCHAR));
  58. if (cb == 0) {
  59. #ifdef DBG_ERROR
  60. DbgPrint("IrTranP: GetSystemWindowsDirectoryW() failed: %d\n",GetLastError());
  61. #endif
  62. FreeMemory(pwszPath);
  63. return GetLastError();
  64. }
  65. StringCbCatW(ApplicationName,sizeof(ApplicationName),TEXT("\\"));
  66. StringCbCatW(ApplicationName,sizeof(ApplicationName),EXPLORER_EXE);
  67. dwFlags = 0;
  68. bResult=CreateProcessW(
  69. ApplicationName, // App name in command line.
  70. pwszCommandLine,
  71. 0, // lpProcessAttributes (security)
  72. 0, // lpThreadAttributes (security)
  73. FALSE, // bInheritHandles
  74. dwFlags,
  75. 0, // pEnvironment block
  76. pwszPath, // Current Directory
  77. &StartupInfo,
  78. &ProcessInfo
  79. );
  80. if (bResult) {
  81. dwStatus = GetLastError();
  82. #ifdef DBG_ERROR
  83. DbgPrint("IrTranP: CreateProcessAsUser() failed: %d\n",dwStatus);
  84. #endif
  85. } else {
  86. CloseHandle(ProcessInfo.hProcess);
  87. CloseHandle(ProcessInfo.hThread);
  88. }
  89. FreeMemory(pwszPath);
  90. }
  91. return dwStatus;
  92. }
  93. //---------------------------------------------------------------------
  94. // ReceiveComplete()
  95. //
  96. //---------------------------------------------------------------------
  97. void ReceiveComplete( IN CCONNECTION *pConnection,
  98. IN DWORD dwStatusCode )
  99. {
  100. DWORD dwStatus = NO_ERROR;
  101. if (!pConnection) {
  102. return;
  103. }
  104. // Hide the progress dialog:
  105. #ifdef DBG_RETURN_STATUS
  106. DbgPrint("ReceiveComplete(): StatusCode: 0x%x (%d)\n",
  107. dwStatusCode, dwStatusCode );
  108. #endif
  109. _ReceiveFinished( NULL, pConnection->GetUiCookie(), dwStatusCode );
  110. if ( (dwStatusCode == NO_ERROR)
  111. || (dwStatusCode == ERROR_SCEP_UNSPECIFIED_DISCONNECT)
  112. || (dwStatusCode == ERROR_SCEP_USER_DISCONNECT)
  113. || (dwStatusCode == ERROR_SCEP_PROVIDER_DISCONNECT) )
  114. {
  115. dwStatus = ExplorePictures();
  116. }
  117. }
  118. //---------------------------------------------------------------------
  119. // ProcessConnectRequest()
  120. //
  121. // Called by ProcessClient() when the input PDU message type is
  122. // MSG_TYPE_CONNECT_REQ.
  123. //
  124. // pConnection - The newly established Winsock connection with the
  125. // camera.
  126. //
  127. // pPdu - The SCEP PDU holding the connect request. It was
  128. // allocated in ProcessClient() by AssemblePdu() and
  129. // will always be free'd when ProcessConnectRequest()
  130. // finishes.
  131. //
  132. // dwPduSize - The size of the input PDU in bytes.
  133. //
  134. //---------------------------------------------------------------------
  135. DWORD ProcessConnectRequest( IN CCONNECTION *pConnection,
  136. IN SCEP_HEADER *pPdu,
  137. IN DWORD dwPduSize )
  138. {
  139. DWORD dwStatus;
  140. DWORD dwRespPduSize;
  141. BOOL fReceivesAllowed = ::ReceivesAllowed();
  142. SCEP_HEADER *pRespPdu;
  143. CIOPACKET *pNewIoPacket; // Posted IO packet (by SendPdu()).
  144. CSCEP_CONNECTION *pScepConnection
  145. = (CSCEP_CONNECTION*)pConnection->GetScepConnection();
  146. if (fReceivesAllowed)
  147. {
  148. // Build an connection accept acknowledgement:
  149. dwStatus = pScepConnection->BuildConnectRespPdu(&pRespPdu,
  150. &dwRespPduSize);
  151. }
  152. else
  153. {
  154. // Build a connect NACK:
  155. dwStatus = pScepConnection->BuildConnectNackPdu(&pRespPdu,
  156. &dwRespPduSize);
  157. }
  158. if (dwStatus == NO_ERROR)
  159. {
  160. pConnection->SendPdu(pRespPdu,dwRespPduSize,&pNewIoPacket);
  161. if (pNewIoPacket)
  162. {
  163. pNewIoPacket->SetWritePdu(pRespPdu);
  164. }
  165. else
  166. {
  167. DeletePdu(pRespPdu);
  168. }
  169. if (!fReceivesAllowed)
  170. {
  171. // Note: After sending a NACK, the camera should close
  172. // the connection, but at lease some don't, so I'm
  173. // forced to slam the connection...
  174. pConnection->CloseSocket(); // Was: ShutdownSocket().
  175. }
  176. }
  177. DeletePdu(pPdu);
  178. return dwStatus;
  179. }
  180. //---------------------------------------------------------------------
  181. // ProcessConnectResponse()
  182. //
  183. // Called by ProcessClient() when the input PDU message type is
  184. // MSG_TYPE_CONNECT_RESP.
  185. //
  186. // NOTE: Note implemented in the IrTran-P server, because the server
  187. // is not currently setup to connect to a camera to download
  188. // pictures back to the camera... We should never get this PDU
  189. // during normal operation.
  190. //
  191. // pConnection - The newly established Winsock connection with the
  192. // camera.
  193. //
  194. // pPdu - The SCEP PDU holding the connect request. It was
  195. // allocated in ProcessClient() by AssemblePdu() and
  196. // will always be free'd when ProcessConnectResponse()
  197. // finishes.
  198. //
  199. // dwPduSize - The size of the input PDU in bytes.
  200. //
  201. //---------------------------------------------------------------------
  202. DWORD ProcessConnectResponse( CCONNECTION *pConnection,
  203. SCEP_HEADER *pPdu,
  204. DWORD dwPduSize )
  205. {
  206. DWORD dwStatus = NO_ERROR;
  207. #ifdef DBG_ERROR
  208. DbgPrint("ProcessClient(): Unimplemented MSG_TYPE_CONNECT_RESP\n");
  209. #endif
  210. DeletePdu(pPdu);
  211. return dwStatus;
  212. }
  213. //---------------------------------------------------------------------
  214. // ProcessData()
  215. //
  216. // Called by ProcessClient() when the input PDU message type is
  217. // MSG_TYPE_DATA.
  218. //
  219. // pConnection - The newly established Winsock connection with the
  220. // camera.
  221. //
  222. // pPdu - The SCEP PDU holding the connect request. It was
  223. // allocated in ProcessClient() by AssemblePdu() and
  224. // will always be free'd when ProcessConnectResponse()
  225. // finishes.
  226. //
  227. // dwPduSize - The size of the input PDU in bytes.
  228. //
  229. //---------------------------------------------------------------------
  230. DWORD ProcessData( CCONNECTION *pConnection,
  231. SCEP_HEADER *pPdu,
  232. DWORD dwPduSize,
  233. COMMAND_HEADER *pCommandHeader,
  234. UCHAR *pUserData,
  235. DWORD dwUserDataSize )
  236. {
  237. DWORD dwStatus = NO_ERROR;
  238. DWORD dwRespPduSize;
  239. DWORD dwBftpOp = 0;
  240. UCHAR *pPutData;
  241. DWORD dwPutDataSize;
  242. DWORD dwJpegOffset;
  243. DWORD dwJpegSize;
  244. SCEP_HEADER *pRespPdu;
  245. CIOPACKET *pNewIoPacket; // Posted IO packet (by SendPdu()).
  246. CSCEP_CONNECTION *pScepConnection
  247. = (CSCEP_CONNECTION*)pConnection->GetScepConnection();
  248. // First, check to see if this is an abort PDU, send by the camera:
  249. if ( (pCommandHeader) && (pCommandHeader->PduType == PDU_TYPE_ABORT) )
  250. {
  251. DeletePdu(pPdu);
  252. return ERROR_SCEP_ABORT;
  253. }
  254. // Is one of the 2nd through Nth fragments of a fragmented PDU?
  255. if ( (pScepConnection->IsFragmented())
  256. && (pScepConnection->GetSequenceNo() > 0))
  257. {
  258. #ifdef DBG_IO
  259. DbgPrint("ProcessClient(): Put Fragment: SequenceNo: %d RestNo: %d\n",
  260. pScepConnection->GetSequenceNo(),
  261. pScepConnection->GetRestNo() );
  262. #endif
  263. pConnection->WritePictureFile( pUserData,
  264. dwUserDataSize,
  265. &pNewIoPacket );
  266. if (pNewIoPacket)
  267. {
  268. pNewIoPacket->SetWritePdu(pPdu);
  269. }
  270. else
  271. {
  272. DeletePdu(pPdu);
  273. }
  274. if (pScepConnection->GetDFlag() == DFLAG_LAST_FRAGMENT)
  275. {
  276. #ifdef DBG_IO
  277. DbgPrint("ProcessClient(): Put ACK\n");
  278. #endif
  279. pScepConnection->BuildPutRespPdu( PDU_TYPE_REPLY_ACK,
  280. ERROR_PUT_NO_ERROR,
  281. &pRespPdu,
  282. &dwRespPduSize);
  283. pConnection->SendPdu( pRespPdu,
  284. dwRespPduSize,
  285. &pNewIoPacket);
  286. if (pNewIoPacket)
  287. {
  288. pNewIoPacket->SetWritePdu(pRespPdu);
  289. }
  290. else
  291. {
  292. DeletePdu(pRespPdu);
  293. }
  294. }
  295. }
  296. else if (pCommandHeader)
  297. {
  298. // Length4 in the COMMAN_HEADER is the user data size
  299. // plus the bytes for machine ids (16), the DestPid (2),
  300. // SrcPid (2) and CommandId (2) so offset by 22.
  301. #ifdef DBG_IO
  302. DbgPrint("ProcessData(): SaveAsUPF(): %d\n",
  303. pConnection->CheckSaveAsUPF() );
  304. #endif
  305. dwStatus = pScepConnection->ParseBftp( pUserData,
  306. dwUserDataSize,
  307. pConnection->CheckSaveAsUPF(),
  308. &dwBftpOp,
  309. &pPutData,
  310. &dwPutDataSize );
  311. if ((dwStatus == NO_ERROR) && (IsBftpQuery(dwBftpOp)))
  312. {
  313. pScepConnection->BuildWht0RespPdu(dwBftpOp,
  314. &pRespPdu,
  315. &dwRespPduSize);
  316. pConnection->SendPdu( pRespPdu,
  317. dwRespPduSize,
  318. &pNewIoPacket );
  319. if (pNewIoPacket)
  320. {
  321. pNewIoPacket->SetWritePdu(pRespPdu);
  322. }
  323. else
  324. {
  325. DeletePdu(pRespPdu);
  326. }
  327. DeletePdu(pPdu);
  328. }
  329. else if ((dwStatus == NO_ERROR) && (IsBftpPut(dwBftpOp)))
  330. {
  331. //
  332. // Ok, we have a bFTP PUT command, so open a file
  333. // and get ready to start collecting image data.
  334. //
  335. dwStatus = pScepConnection->ParseUpfHeaders( pPutData,
  336. dwPutDataSize,
  337. &dwJpegOffset,
  338. &dwJpegSize );
  339. if (dwStatus != NO_ERROR)
  340. return dwStatus;
  341. pConnection->SetJpegOffsetAndSize(dwJpegOffset,dwJpegSize);
  342. dwStatus = pConnection->CreatePictureFile();
  343. dwStatus = pConnection->SetPictureFileTime( pScepConnection->GetCreateTime() );
  344. dwStatus = pConnection->WritePictureFile( pPutData,
  345. dwPutDataSize,
  346. &pNewIoPacket );
  347. if (pNewIoPacket)
  348. {
  349. pNewIoPacket->SetWritePdu(pPdu);
  350. }
  351. else
  352. {
  353. DeletePdu(pPdu);
  354. }
  355. if (pScepConnection->IsFragmented())
  356. {
  357. #ifdef DBG_IO
  358. DbgPrint("ProcessClient(): Image File: %s Size: %d\n",
  359. pScepConnection->GetFileName(),
  360. pCommandHeader->Length4 );
  361. DbgPrint("ProcessClient(): SequenceNo: %d RestNo: %d\n",
  362. pScepConnection->GetSequenceNo(),
  363. pScepConnection->GetRestNo() );
  364. #endif
  365. }
  366. else
  367. {
  368. #ifdef DBG_IO
  369. DbgPrint("ProcessClient(): Put Command: Unfragmented\n");
  370. #endif
  371. }
  372. }
  373. else if (IsBftpError(dwBftpOp))
  374. {
  375. #ifdef DBG_ERROR
  376. DbgPrint("ProcessData(): bFTP Error: %d\n", dwStatus );
  377. #endif
  378. DeletePdu(pPdu);
  379. dwStatus = ERROR_BFTP_INVALID_PROTOCOL;
  380. }
  381. else
  382. {
  383. #ifdef DBG_ERROR
  384. DbgPrint("ProcessData(): Unknown bFTP Command: %d\n",dwBftpOp);
  385. #endif
  386. DeletePdu(pPdu);
  387. dwStatus = ERROR_BFTP_INVALID_PROTOCOL;
  388. }
  389. }
  390. return dwStatus;
  391. }
  392. //---------------------------------------------------------------------
  393. // ProcessDisconnect()
  394. //
  395. // Called by ProcessClient() when the input PDU message type is
  396. // MSG_TYPE_DISCONNECT.
  397. //
  398. // pConnection - The newly established Winsock connection with the
  399. // camera.
  400. //
  401. // pPdu - The SCEP PDU holding the connect request. It was
  402. // allocated in ProcessClient() by AssemblePdu() and
  403. // will always be free'd when ProcessConnectResponse()
  404. // finishes.
  405. //
  406. // dwPduSize - The size of the input PDU in bytes.
  407. //
  408. //---------------------------------------------------------------------
  409. DWORD ProcessDisconnect( CCONNECTION *pConnection,
  410. SCEP_HEADER *pPdu,
  411. DWORD dwPduSize )
  412. {
  413. DWORD dwStatus = NO_ERROR;
  414. // Don't need to do anything special here, since
  415. // ParsePdu() will set dwStatus to one of:
  416. // ERROR_SCEP_UNSPECIFIED_DISCONNECT (5002)
  417. // ERROR_SCEP_USER_DISCONNECT (5003)
  418. // or ERROR_SCEP_PROVIDER_DISCONNECT (5004)
  419. #ifdef DBG_IO
  420. DbgPrint("ProcessClient(): Disconnect: %d\n",dwStatus);
  421. #endif
  422. pConnection->SetReceiveComplete(TRUE);
  423. DeletePdu(pPdu);
  424. return dwStatus;
  425. }
  426. //---------------------------------------------------------------------
  427. // ProcessClient()
  428. //
  429. //---------------------------------------------------------------------
  430. DWORD ProcessClient( CIOSTATUS *pIoStatus,
  431. CIOPACKET *pIoPacket,
  432. DWORD dwNumBytes )
  433. {
  434. char *pBuffer;
  435. DWORD dwStatus = NO_ERROR;
  436. SOCKET Socket = pIoPacket->GetSocket();
  437. CCONNECTION *pConnection;
  438. CSCEP_CONNECTION *pScepConnection;
  439. SCEP_HEADER *pPdu;
  440. DWORD dwPduSize;
  441. COMMAND_HEADER *pCommandHeader;
  442. UCHAR *pUserData; // Location of bFTP data.
  443. DWORD dwUserDataSize;
  444. DWORD dwError = 0;
  445. handle_t hBinding;
  446. WCHAR wsCmdLine[80];
  447. pConnection = g_pConnectionMap->Lookup(Socket);
  448. if (!pConnection)
  449. {
  450. return ERROR_IRTRANP_OUT_OF_MEMORY;
  451. }
  452. pScepConnection = (CSCEP_CONNECTION*)pConnection->GetScepConnection();
  453. ASSERT(pScepConnection);
  454. pBuffer = pIoPacket->GetReadBuffer();
  455. while (dwStatus == NO_ERROR)
  456. {
  457. dwStatus = pScepConnection->AssemblePdu( pBuffer,
  458. dwNumBytes,
  459. &pPdu,
  460. &dwPduSize );
  461. if (dwStatus == NO_ERROR)
  462. {
  463. dwStatus = pScepConnection->ParsePdu( pPdu,
  464. dwPduSize,
  465. &pCommandHeader,
  466. &pUserData,
  467. &dwUserDataSize );
  468. switch (pPdu->MsgType)
  469. {
  470. case MSG_TYPE_CONNECT_REQ:
  471. // Message was an SCEP Connection Request:
  472. StringCchCopy(wsCmdLine,sizeof(wsCmdLine)/sizeof(wsCmdLine[0]),L"irftp.exe /h");
  473. if (!LaunchUi(wsCmdLine))
  474. {
  475. dwError = GetLastError();
  476. #ifdef DBG_ERROR
  477. DbgPrint("LaunchUi(): Failed: %d\n",dwError);
  478. #endif
  479. }
  480. {
  481. COOKIE cookie;
  482. dwError = _ReceiveInProgress( NULL, L"", &cookie, TRUE );
  483. pConnection->SetUiCookie( cookie );
  484. #ifdef DBG_ERROR
  485. if (dwError)
  486. {
  487. DbgPrint("ReceiveInProgress() returned: %d\n",
  488. dwError);
  489. }
  490. #endif
  491. }
  492. dwStatus = ProcessConnectRequest(pConnection,
  493. pPdu,
  494. dwPduSize );
  495. if ((dwStatus) || (!ReceivesAllowed()))
  496. {
  497. ReceiveComplete(pConnection,dwStatus);
  498. }
  499. break;
  500. case MSG_TYPE_CONNECT_RESP:
  501. // Message was a reply from a connection request:
  502. dwStatus = ProcessConnectResponse(pConnection,
  503. pPdu,
  504. dwPduSize );
  505. break;
  506. case MSG_TYPE_DATA:
  507. // Message is a SCEP command of some sort:
  508. dwStatus = ProcessData(pConnection,
  509. pPdu,
  510. dwPduSize,
  511. pCommandHeader,
  512. pUserData,
  513. dwUserDataSize );
  514. break;
  515. case MSG_TYPE_DISCONNECT:
  516. // Message from the camera was a disconnect:
  517. ProcessDisconnect(pConnection,
  518. pPdu,
  519. dwPduSize );
  520. ReceiveComplete(pConnection,dwStatus);
  521. break;
  522. default:
  523. #ifdef DBG_ERROR
  524. DbgPrint("ProcessClient(): Unknown MSG_TYPE_xxx: %d\n",
  525. pPdu->MsgType );
  526. #endif
  527. DeletePdu(pPdu);
  528. break;
  529. }
  530. }
  531. else
  532. {
  533. break;
  534. }
  535. pBuffer = 0;
  536. dwNumBytes = 0;
  537. }
  538. if (dwStatus == ERROR_CONTINUE)
  539. {
  540. dwStatus = NO_ERROR;
  541. }
  542. return dwStatus;
  543. }
  544. //---------------------------------------------------------------------
  545. // SendAbortPdu()
  546. //
  547. // Stop the camera.
  548. //
  549. // I should be able to send a Stop PDU, followed by a Disconnect, or
  550. // maybe an Abort PDU, but these don't work on all the cameras, so I
  551. // currently end up just doing a hard close on the connection to the
  552. // camera.
  553. //---------------------------------------------------------------------
  554. DWORD SendAbortPdu( IN CCONNECTION *pConnection )
  555. {
  556. DWORD dwStatus = NO_ERROR;
  557. if (pConnection) {
  558. pConnection->CloseSocket();
  559. }
  560. return dwStatus;
  561. }
  562. //---------------------------------------------------------------------
  563. // MapStatusCode()
  564. //
  565. //---------------------------------------------------------------------
  566. DWORD MapStatusCode( DWORD dwStatus,
  567. DWORD dwDefaultStatus )
  568. {
  569. // The Facility part of an error code are the first 12 bits of the
  570. // high word (16bits):
  571. #define FACILITY_MASK 0x0FFF0000
  572. // If the error code is already an IrTran-P error code, then don't
  573. // remap it:
  574. if ( ((dwStatus&FACILITY_MASK) >> 16) == FACILITY_IRTRANP)
  575. {
  576. return dwStatus;
  577. }
  578. // Map other errors:
  579. if (dwStatus != NO_ERROR)
  580. {
  581. if ( (dwStatus == ERROR_DISK_FULL)
  582. || (dwStatus == ERROR_WRITE_FAULT)
  583. || (dwStatus == ERROR_WRITE_PROTECT)
  584. || (dwStatus == ERROR_GEN_FAILURE)
  585. || (dwStatus == ERROR_NOT_DOS_DISK) )
  586. {
  587. dwStatus = ERROR_IRTRANP_DISK_FULL;
  588. }
  589. else
  590. {
  591. dwStatus = dwDefaultStatus;
  592. }
  593. }
  594. return dwStatus;
  595. }
  596. //---------------------------------------------------------------------
  597. // ProcessIoPackets()
  598. //
  599. //---------------------------------------------------------------------
  600. DWORD ProcessIoPackets( CIOSTATUS *pIoStatus )
  601. {
  602. DWORD dwStatus = NO_ERROR;
  603. DWORD dwProcessStatus = NO_ERROR; // Processing IO status.
  604. DWORD dwNumBytes;
  605. ULONG_PTR dwKey;
  606. DWORD dwTimeout = DEFAULT_TIMEOUT;
  607. LONG lPendingIos; // # of pending reads/writes on a CCONNECTION.
  608. LONG lPendingReads; // # of pending reads on a CCONNECTION.
  609. LONG lPendingWrites; // # of pending file writes on a CCONNECTION.
  610. OVERLAPPED *pOverlapped;
  611. CCONNECTION *pConnection;
  612. CCONNECTION *pNewConnection;
  613. CSCEP_CONNECTION *pScepConnection;
  614. CIOPACKET *pIoPacket = 0;
  615. CIOPACKET *pNewIoPacket = 0;
  616. HANDLE hIoCompletionPort = pIoStatus->GetIoCompletionPort();
  617. // Wait on the IO completion port for incomming connections:
  618. while (TRUE)
  619. {
  620. pIoStatus->IncrementNumPendingThreads();
  621. dwNumBytes = 0;
  622. dwKey = 0;
  623. pOverlapped = 0;
  624. if (!GetQueuedCompletionStatus( hIoCompletionPort,
  625. &dwNumBytes,
  626. &dwKey,
  627. &pOverlapped,
  628. dwTimeout ))
  629. {
  630. dwStatus = GetLastError();
  631. pIoStatus->DecrementNumPendingThreads();
  632. if (dwStatus != WAIT_TIMEOUT)
  633. {
  634. // Got an error. Two cases during an error,
  635. // data may or may not have been dequeued from
  636. // the IO completion port.
  637. if (pOverlapped)
  638. {
  639. pIoPacket = CIOPACKET::CIoPacketFromOverlapped(pOverlapped);
  640. pConnection = g_pConnectionMap->Lookup(dwKey);
  641. // ASSERT(pConnection);
  642. if (!pConnection)
  643. {
  644. delete pIoPacket;
  645. continue;
  646. }
  647. if (pIoPacket->GetIoPacketKind() == PACKET_KIND_READ)
  648. {
  649. lPendingReads = pConnection->DecrementPendingReads();
  650. ASSERT(lPendingReads >= 0);
  651. }
  652. else if (pIoPacket->GetIoPacketKind() == PACKET_KIND_WRITE_FILE)
  653. {
  654. lPendingWrites = pConnection->DecrementPendingWrites();
  655. ASSERT(lPendingWrites >= 0);
  656. SCEP_HEADER *pPdu = (SCEP_HEADER*)pIoPacket->GetWritePdu();
  657. if (pPdu)
  658. {
  659. DeletePdu(pPdu);
  660. }
  661. }
  662. else if (pIoPacket->GetIoPacketKind() == PACKET_KIND_WRITE_SOCKET)
  663. {
  664. SCEP_HEADER *pPdu = (SCEP_HEADER*)pIoPacket->GetWritePdu();
  665. if (pPdu)
  666. {
  667. DeletePdu(pPdu);
  668. }
  669. }
  670. else if (pIoPacket->GetIoPacketKind() == PACKET_KIND_LISTEN)
  671. {
  672. // One of the listen sockets was shutdown (closed):
  673. delete pIoPacket;
  674. continue;
  675. }
  676. // Check to see if there was a transmission error, or
  677. // there was an error writing the picture to disk:
  678. if (dwStatus != ERROR_NETNAME_DELETED)
  679. {
  680. DWORD dwStatusCode;
  681. SendAbortPdu(pConnection);
  682. pConnection->DeletePictureFile();
  683. dwStatusCode = MapStatusCode(
  684. dwStatus,
  685. ERROR_SCEP_PROVIDER_DISCONNECT);
  686. ReceiveComplete(pConnection,dwStatusCode);
  687. }
  688. else
  689. {
  690. // if (pConnection->IncompleteFile())
  691. dwProcessStatus = MapStatusCode(
  692. dwProcessStatus,
  693. ERROR_SCEP_INVALID_PROTOCOL );
  694. ReceiveComplete(pConnection,dwProcessStatus);
  695. }
  696. // Delete the connection if there are no more pending
  697. // IOs...
  698. lPendingIos = pConnection->NumPendingIos();
  699. if (lPendingIos == 0)
  700. {
  701. g_pConnectionMap->Remove(dwKey);
  702. delete pConnection;
  703. }
  704. #ifdef DBG_ERROR
  705. if (dwStatus != ERROR_NETNAME_DELETED)
  706. {
  707. DbgPrint("GetQueuedCompletionStatus(): Socket: %d PendingIos: %d Failed: 0x%x\n",
  708. dwKey, lPendingIos, dwStatus );
  709. }
  710. #endif
  711. delete pIoPacket;
  712. }
  713. else
  714. {
  715. #ifdef DBG_ERROR
  716. DbgPrint("GetQueuedCompletionStatus(): Socket: %d Failed: %d (no overlapped)\n",
  717. dwKey, dwStatus );
  718. #endif
  719. ReceiveComplete(pConnection,ERROR_SCEP_PROVIDER_DISCONNECT);
  720. }
  721. continue;
  722. }
  723. else
  724. {
  725. // Wait timeout, loop back and continue...
  726. }
  727. }
  728. else
  729. {
  730. // IO completed. Either we got a new connection to a client,
  731. // or more data has come in from an existing connection to
  732. // a client.
  733. // First, check to see if the shudown (uninintalize code)
  734. // wants us to shutdown:
  735. if ((dwKey == IOKEY_SHUTDOWN) && (!pOverlapped))
  736. {
  737. return dwStatus;
  738. }
  739. pConnection = g_pConnectionMap->Lookup(dwKey);
  740. if (!pConnection)
  741. {
  742. #ifdef DBG_ERROR
  743. DbgPrint("ProcessIoPackets(): Lookup(%d) Failed: Bytes: %d pOverlapped: 0x%x\n",
  744. dwKey,
  745. dwNumBytes,
  746. pOverlapped );
  747. #endif
  748. pIoPacket = CIOPACKET::CIoPacketFromOverlapped(pOverlapped);
  749. if (pIoPacket)
  750. {
  751. delete pIoPacket;
  752. }
  753. continue;
  754. }
  755. pIoStatus->DecrementNumPendingThreads();
  756. pIoPacket = CIOPACKET::CIoPacketFromOverlapped(pOverlapped);
  757. DWORD dwKind = pIoPacket->GetIoPacketKind();
  758. if (dwKind == PACKET_KIND_LISTEN)
  759. {
  760. // New connection:
  761. lPendingReads = pConnection->DecrementPendingReads();
  762. ASSERT(lPendingReads >= 0);
  763. #ifdef DBG_IO
  764. SOCKADDR_IRDA *pAddrLocal = 0;
  765. SOCKADDR_IRDA *pAddrFrom = 0;
  766. pIoPacket->GetSockAddrs(&pAddrLocal,&pAddrFrom);
  767. DbgPrint("ProcessIoPackets(): Accepted connection from 0x%2.2x%2.2x%2.2x%2.2x, service %s\n",
  768. pAddrFrom->irdaDeviceID[0],
  769. pAddrFrom->irdaDeviceID[1],
  770. pAddrFrom->irdaDeviceID[2],
  771. pAddrFrom->irdaDeviceID[3],
  772. pAddrFrom->irdaServiceName );
  773. #endif
  774. pScepConnection = new CSCEP_CONNECTION;
  775. if (!pScepConnection)
  776. {
  777. #ifdef DBG_ERROR
  778. DbgPrint("ProcessIoPackets(): Out of memeory.\n");
  779. #endif
  780. delete pIoPacket;
  781. continue;
  782. }
  783. pNewConnection = new CCONNECTION(
  784. PACKET_KIND_READ,
  785. pIoPacket->GetSocket(),
  786. pIoPacket->GetIoCompletionPort(),
  787. pScepConnection,
  788. ::CheckSaveAsUPF() );
  789. if (!pNewConnection)
  790. {
  791. #ifdef DBG_ERROR
  792. DbgPrint("ProcessIoPackets(): Out of memeory.\n");
  793. #endif
  794. delete pScepConnection;
  795. delete pIoPacket;
  796. continue;
  797. }
  798. g_pConnectionMap->Add(pNewConnection,
  799. pNewConnection->GetSocket() );
  800. delete pIoPacket;
  801. dwStatus = pNewConnection->PostMoreIos();
  802. dwStatus = pConnection->PostMoreIos();
  803. }
  804. else if (dwKind == PACKET_KIND_WRITE_SOCKET)
  805. {
  806. #ifdef DBG_IO
  807. DbgPrint("ProcessIoPackets(): Write completed: Socket: %d Bytes: %d\n",
  808. dwKey,
  809. dwNumBytes );
  810. #endif
  811. SCEP_HEADER *pPdu = (SCEP_HEADER*)pIoPacket->GetWritePdu();
  812. if (pPdu)
  813. {
  814. DeletePdu(pPdu);
  815. }
  816. delete pIoPacket;
  817. }
  818. else if (dwKind == PACKET_KIND_WRITE_FILE)
  819. {
  820. lPendingWrites = pConnection->DecrementPendingWrites();
  821. ASSERT(lPendingWrites >= 0);
  822. #ifdef DBG_IO
  823. DbgPrint("ProcessIoPackets(): Write File: Handle: %d Bytes: %d NumPendingIos: %d\n",
  824. dwKey, dwNumBytes, pConnection->NumPendingIos() );
  825. #endif
  826. SCEP_HEADER *pPdu = (SCEP_HEADER*)pIoPacket->GetWritePdu();
  827. if (pPdu)
  828. {
  829. DeletePdu(pPdu);
  830. }
  831. delete pIoPacket;
  832. }
  833. else
  834. {
  835. // Incomming data from connection client:
  836. ASSERT(dwKind == PACKET_KIND_READ);
  837. lPendingReads = pConnection->DecrementPendingReads();
  838. ASSERT(lPendingReads >= 0);
  839. #ifdef DBG_IO
  840. DbgPrint("ProcessIoPackets(): Read completed: Socket: %d Bytes: %d\n",
  841. dwKey,
  842. dwNumBytes );
  843. #endif
  844. if (dwNumBytes)
  845. {
  846. dwProcessStatus
  847. = ProcessClient(pIoStatus,pIoPacket,dwNumBytes);
  848. if (dwProcessStatus == NO_ERROR)
  849. {
  850. dwStatus = pConnection->PostMoreIos();
  851. }
  852. else
  853. {
  854. #ifdef DBG_ERROR
  855. if ( (dwProcessStatus != ERROR_SCEP_UNSPECIFIED_DISCONNECT)
  856. && (dwProcessStatus != ERROR_SCEP_USER_DISCONNECT)
  857. && (dwProcessStatus != ERROR_SCEP_PROVIDER_DISCONNECT) )
  858. {
  859. DbgPrint("ProcessIoPackets(): ProcessClient(): Failed: 0x%x\n",dwProcessStatus);
  860. }
  861. #endif
  862. pConnection->CloseSocket();
  863. }
  864. delete pIoPacket;
  865. }
  866. else
  867. {
  868. if (pConnection->NumPendingIos() == 0)
  869. {
  870. g_pConnectionMap->RemoveConnection(pConnection);
  871. delete pConnection;
  872. pConnection = 0;
  873. }
  874. delete pIoPacket;
  875. }
  876. }
  877. }
  878. }
  879. return 0;
  880. }