home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / remote / srvstoc.c < prev    next >
C/C++ Source or Header  |  1997-10-12  |  12KB  |  474 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright 1995 - 1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /*++
  13.  
  14. Copyright (c) 1997  Microsoft Corporation
  15.  
  16. Module Name:
  17.  
  18.     SrvStoC.c
  19.  
  20. Abstract:
  21.  
  22.     This file implements the server-to-client flow
  23.     of data for remote server.  The data is the output
  24.     of the child program intermingled with client input.
  25.  
  26. Author:
  27.  
  28.     Dave Hart  30 May 1997
  29.  
  30. Environment:
  31.  
  32.     Console App. User mode.
  33.  
  34. Revision History:
  35.  
  36. --*/
  37.  
  38. #include <windows.h>
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <io.h>
  42. #include <string.h>
  43. #include "Remote.h"
  44. #include "Server.h"
  45.  
  46.  
  47. VOID
  48. FASTCALL
  49. StartServerToClientFlow(
  50.     VOID
  51.     )
  52. {
  53.     PREMOTE_CLIENT pClient;
  54.  
  55.     //
  56.     // Start read operations against the temp file for
  57.     // all active clients that aren't currently doing
  58.     // read temp/write client operations and that are
  59.     // fully connected.
  60.     //
  61.  
  62.     for (pClient = (PREMOTE_CLIENT) ClientListHead.Flink;
  63.          pClient != (PREMOTE_CLIENT) &ClientListHead;
  64.          pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
  65.  
  66.  
  67.         if (! pClient->cbWrite) {
  68.  
  69.             StartReadTempFile( pClient );
  70.         }
  71.     }
  72. }
  73.  
  74.  
  75. VOID
  76. FASTCALL
  77. StartReadTempFile(
  78.     PREMOTE_CLIENT pClient
  79.     )
  80. {
  81.     //
  82.     // pClient->cbWrite is used dually.  WriteSessionOutputCompleted
  83.     // uses it when 0 bytes are written to know how much to ask
  84.     // to write when it resubmits the request.  We use it to
  85.     // indicate whether a read temp/write session chain of I/Os
  86.     // is currently active for this client.
  87.     //
  88.  
  89.     if (pClient->cbWrite) {
  90.  
  91.         ErrorExit("StartReadTempFile entered with nonzero cbWrite.");
  92.     }
  93.  
  94.     if (dwWriteFilePointer > pClient->dwFilePos) {
  95.  
  96.         pClient->cbWrite = min(BUFFSIZE,
  97.                                dwWriteFilePointer - pClient->dwFilePos);
  98.  
  99.         pClient->WriteOverlapped.OffsetHigh = 0;
  100.         pClient->WriteOverlapped.Offset = pClient->dwFilePos;
  101.  
  102.         if ( ! ReadFileEx(
  103.                    pClient->rSaveFile,
  104.                    pClient->ReadTempBuffer,
  105.                    pClient->cbWrite,
  106.                    &pClient->WriteOverlapped,
  107.                    ReadTempFileCompleted
  108.                    )) {
  109.  
  110.             if (ERROR_HANDLE_EOF == GetLastError()) {
  111.  
  112.                 pClient->cbWrite = 0;
  113.  
  114.             } else {
  115.  
  116.                 TRACE(SESSION, ("ReadFileEx for temp file failed error %d, closing client.\n", GetLastError()));
  117.  
  118.                 CloseClient(pClient);
  119.             }
  120.         }
  121.  
  122.     }
  123. }
  124.  
  125. VOID
  126. WINAPI
  127. ReadTempFileCompleted(
  128.     DWORD dwError,
  129.     DWORD cbRead,
  130.     LPOVERLAPPED lpO
  131.     )
  132. {
  133.     PREMOTE_CLIENT pClient;
  134.  
  135.     pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, WriteOverlapped);
  136.  
  137.     if (HandleSessionError(pClient, dwError)) {
  138.  
  139.         return;
  140.     }
  141.  
  142.  
  143.     if (cbRead != pClient->cbWrite) {
  144.  
  145.         TRACE(SESSION, ("Read %d from temp file asked for %d\n", cbRead, pClient->cbWrite));
  146.     }
  147.  
  148.     if (cbRead) {
  149.  
  150.         pClient->cbReadTempBuffer = cbRead;
  151.         pClient->dwFilePos += cbRead;
  152.  
  153.         StartWriteSessionOutput(pClient);
  154.  
  155.     } else {
  156.  
  157.         //
  158.         // Note that the server to client flow is halting for now
  159.         // for this client.
  160.         //
  161.  
  162.         pClient->cbWrite = 0;
  163.     }
  164. }
  165.  
  166.  
  167. VOID
  168. FASTCALL
  169. StartWriteSessionOutput(
  170.     PREMOTE_CLIENT pClient
  171.     )
  172. {
  173.     DWORD cbRead;
  174.     char *pch;
  175.  
  176.     cbRead = pClient->cbReadTempBuffer;
  177.  
  178.     //
  179.     // We need to split commands from other text read
  180.     // from the temp file and hold off on writing them
  181.     // to the client until we make sure we're not the
  182.     // client that submitted it.  This isn't perfect
  183.     // since we match on client name which can be
  184.     // duplicated but it solves the problem of
  185.     // duplicated input most of the time.
  186.     //
  187.  
  188.     for (pch = pClient->ReadTempBuffer;
  189.          pch < pClient->ReadTempBuffer + cbRead;
  190.          pch++) {
  191.  
  192.         if ( ! (pClient->ServerFlags & SFLG_READINGCOMMAND) ) {
  193.  
  194.             if (BEGINMARK == *pch) {
  195.  
  196.                 pClient->ServerFlags |= SFLG_READINGCOMMAND;
  197.  
  198.                 if (pch != pClient->ReadTempBuffer &&
  199.                     pClient->cbWriteBuffer) {
  200.  
  201.                     //
  202.                     // Start a write of everything we've come across
  203.                     // before the start of this command, with
  204.                     // WriteSessionOutputCompletedWriteNext specified
  205.                     // so we can continue processing the remainder
  206.                     // of pReadTempBuffer.
  207.                     //
  208.  
  209.                     pClient->cbReadTempBuffer -= ( pch - pClient->ReadTempBuffer) + 1;
  210.                     cbRead = pClient->cbReadTempBuffer;
  211.  
  212.                     #if DBG
  213.                         if (pClient->cbReadTempBuffer == (DWORD)-1) {
  214.                             ErrorExit("cbReadTempBuffer underflow.");
  215.                         }
  216.                     #endif
  217.  
  218.                     MoveMemory(pClient->ReadTempBuffer, pch + 1, cbRead);
  219.  
  220.                     pClient->cbWrite = pClient->cbWriteBuffer;
  221.  
  222.                     pClient->WriteOverlapped.OffsetHigh = 0;
  223.                     pClient->WriteOverlapped.Offset = 0;
  224.  
  225.                     if ( ! WriteFileEx(
  226.                                pClient->PipeWriteH,
  227.                                pClient->WriteBuffer,
  228.                                pClient->cbWrite,
  229.                                &pClient->WriteOverlapped,
  230.                                WriteSessionOutputCompletedWriteNext
  231.                                )) {
  232.  
  233.                         CloseClient(pClient);
  234.                     }
  235.  
  236.                     TRACE(SESSION, ("%x Wrote %d bytes pre-command output\n", pClient, pClient->cbWrite));
  237.  
  238.                     pClient->cbWriteBuffer = 0;
  239.  
  240.                     return;
  241.                 }
  242.  
  243.             } else {
  244.  
  245.                 if (pClient->cbWriteBuffer == BUFFSIZE) {
  246.  
  247.                     ErrorExit("cbWriteBuffer overflow");
  248.                 }
  249.  
  250.                 pClient->WriteBuffer[ pClient->cbWriteBuffer++ ] = *pch;
  251.             }
  252.  
  253.         } else {
  254.  
  255.             if (ENDMARK == *pch ||
  256.                 pClient->cbCommandBuffer == BUFFSIZE) {
  257.  
  258.                 pClient->ServerFlags &= ~SFLG_READINGCOMMAND;
  259.  
  260.                 //
  261.                 // Preceding ENDMARK is the pClient in hex ascii of the
  262.                 // client that generated the command, not null terminated.
  263.                 //
  264.  
  265.                 if (ENDMARK == *pch) {
  266.  
  267.                     pClient->cbCommandBuffer -=
  268.                         min(pClient->cbCommandBuffer, sizeof(pClient->HexAsciiId));
  269.  
  270.                 }
  271.  
  272.                 //
  273.                 // We hide each client's input from their output pipe
  274.                 // because their local remote.exe has already displayed it.
  275.                 //
  276.  
  277.                 if ( pClient->cbCommandBuffer &&
  278.                      ! (ENDMARK == *pch &&
  279.                         ! memcmp(
  280.                               pch - sizeof(pClient->HexAsciiId),
  281.                               pClient->HexAsciiId,
  282.                               sizeof(pClient->HexAsciiId)))) {
  283.  
  284.                     //
  285.                     // Start a write of the accumulated command with
  286.                     // WriteSessionOutputCompletedWriteNext specified
  287.                     // so we can continue processing the remainder
  288.                     // of pReadTempBuffer.
  289.                     //
  290.  
  291.                     pClient->cbReadTempBuffer -= (pch - pClient->ReadTempBuffer) + 1;
  292.                     MoveMemory(pClient->ReadTempBuffer, pch + 1, pClient->cbReadTempBuffer);
  293.  
  294.                     pClient->cbWrite = pClient->cbCommandBuffer;
  295.                     pClient->cbCommandBuffer = 0;
  296.  
  297.                     pClient->WriteOverlapped.OffsetHigh = 0;
  298.                     pClient->WriteOverlapped.Offset = 0;
  299.  
  300.                     if ( ! WriteFileEx(
  301.                                pClient->PipeWriteH,
  302.                                pClient->CommandBuffer,
  303.                                pClient->cbWrite,
  304.                                &pClient->WriteOverlapped,
  305.                                WriteSessionOutputCompletedWriteNext
  306.                                )) {
  307.  
  308.                         CloseClient(pClient);
  309.                         return;
  310.  
  311.                     } else {
  312.  
  313.                         TRACE(SESSION, ("%x Wrote %d bytes command\n", pClient, pClient->cbWrite));
  314.  
  315.                         return;
  316.  
  317.                     }
  318.  
  319.                 } else {
  320.  
  321.                     //
  322.                     // We're eating this command for this session.
  323.                     //
  324.  
  325.                     pClient->cbCommandBuffer = 0;
  326.                 }
  327.  
  328.             } else {
  329.  
  330.                 pClient->CommandBuffer[ pClient->cbCommandBuffer++ ] = *pch;
  331.  
  332.             }
  333.         }
  334.     }
  335.  
  336.     //
  337.     // We're done with the ReadTempBuffer.
  338.     //
  339.  
  340.     pClient->cbReadTempBuffer = 0;
  341.  
  342.     if (pClient->cbWriteBuffer) {
  343.  
  344.         pClient->cbWrite = pClient->cbWriteBuffer;
  345.  
  346.         pClient->WriteOverlapped.OffsetHigh = 0;
  347.         pClient->WriteOverlapped.Offset = 0;
  348.  
  349.         if ( ! WriteFileEx(
  350.                    pClient->PipeWriteH,
  351.                    pClient->WriteBuffer,
  352.                    pClient->cbWrite,
  353.                    &pClient->WriteOverlapped,
  354.                    WriteSessionOutputCompletedReadNext
  355.                    )) {
  356.  
  357.             CloseClient(pClient);
  358.             return;
  359.  
  360.         } else {
  361.  
  362.             TRACE(SESSION, ("%x Wrote %d bytes normal\n", pClient, pClient->cbWrite));
  363.  
  364.             pClient->cbWriteBuffer = 0;
  365.         }
  366.  
  367.     } else {
  368.  
  369.         //
  370.         // Write buffer is empty.
  371.         //
  372.  
  373.         pClient->cbWrite = 0;
  374.  
  375.         StartReadTempFile(pClient);
  376.  
  377.     }
  378. }
  379.  
  380.  
  381. BOOL
  382. FASTCALL
  383. WriteSessionOutputCompletedCommon(
  384.     PREMOTE_CLIENT pClient,
  385.     DWORD dwError,
  386.     DWORD cbWritten,
  387.     LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
  388.     )
  389. {
  390.     if (HandleSessionError(pClient, dwError)) {
  391.  
  392.         return TRUE;
  393.     }
  394.  
  395.     if (!pClient->cbWrite) {
  396.  
  397.         ErrorExit("Zero cbWrite in WriteSessionOutputCompletedCommon");
  398.     }
  399.  
  400.     if (!cbWritten && pClient->cbWrite) {
  401.  
  402.         printf("WriteSessionOutput zero bytes written of %d.\n", pClient->cbWrite);
  403.         ErrorExit("WriteSessionOutputCompletedCommon failure");
  404.  
  405.         return TRUE;
  406.     }
  407.  
  408.     #if DBG
  409.         if (cbWritten != pClient->cbWrite) {
  410.             printf("%x cbWritten %d cbWrite %d\n", pClient, cbWritten, pClient->cbWrite);
  411.         }
  412.     #endif
  413.  
  414.     return FALSE;
  415. }
  416.  
  417.  
  418. VOID
  419. WINAPI
  420. WriteSessionOutputCompletedWriteNext(
  421.     DWORD dwError,
  422.     DWORD cbWritten,
  423.     LPOVERLAPPED lpO
  424.     )
  425. {
  426.     PREMOTE_CLIENT pClient;
  427.  
  428.     pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, WriteOverlapped);
  429.  
  430.     if (WriteSessionOutputCompletedCommon(
  431.             pClient,
  432.             dwError,
  433.             cbWritten,
  434.             WriteSessionOutputCompletedWriteNext
  435.             )) {
  436.  
  437.         return;
  438.     }
  439.  
  440.     StartWriteSessionOutput(pClient);
  441. }
  442.  
  443.  
  444. VOID
  445. WINAPI
  446. WriteSessionOutputCompletedReadNext(
  447.     DWORD dwError,
  448.     DWORD cbWritten,
  449.     LPOVERLAPPED lpO
  450.     )
  451. {
  452.     PREMOTE_CLIENT pClient;
  453.  
  454.     pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, WriteOverlapped);
  455.  
  456.     if (WriteSessionOutputCompletedCommon(
  457.             pClient,
  458.             dwError,
  459.             cbWritten,
  460.             WriteSessionOutputCompletedReadNext
  461.             )) {
  462.  
  463.         return;
  464.     }
  465.  
  466.     //
  467.     // Start another temp file read.
  468.     //
  469.  
  470.     pClient->cbWrite = 0;
  471.  
  472.     StartReadTempFile(pClient);
  473. }
  474.