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 / client.c next >
C/C++ Source or Header  |  1997-10-12  |  18KB  |  764 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright 1992 - 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 1992 - 1997 Microsoft Corporation
  15.  
  16. Module Name:
  17.  
  18.     Client.c
  19.  
  20. Abstract:
  21.  
  22.     The Client component of Remote. Connects to the remote
  23.     server using named pipes. It sends its stdin to
  24.     the server and output everything from server to
  25.     its stdout.
  26.  
  27. Author:
  28.  
  29.     Rajivendra Nath  2-Jan-1992
  30.     Dave Hart        Summer 1997   single-pipe operation
  31.  
  32. Environment:
  33.  
  34.     Console App. User mode.
  35.  
  36. Revision History:
  37.  
  38. --*/
  39.  
  40. #include <windows.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <process.h>
  44. #include <io.h>
  45. #include <string.h>
  46. #include "Remote.h"
  47.  
  48. BOOL fAsyncPipe = TRUE;    // need this so server has it TRUE
  49.  
  50.  
  51. HANDLE*
  52. EstablishSession(
  53.     char *server,
  54.     char *pipe
  55.     );
  56.  
  57. DWORD
  58. WINAPI
  59. SendServerInp(
  60.     LPVOID pvParam
  61.     );
  62.  
  63. BOOL
  64. FilterClientInp(
  65.     char *buff,
  66.     int count
  67.     );
  68.  
  69.  
  70. BOOL
  71. Mych(
  72.     DWORD ctrlT
  73.     );
  74.  
  75. VOID
  76. SendMyInfo(
  77.     PHANDLE Pipes
  78.     );
  79.  
  80.  
  81.  
  82. HANDLE MyStdInp;
  83. HANDLE MyStdOut;
  84.  
  85. //
  86. // ReadPipe and WritePipe are referenced by multiple
  87. // threads so need to be volatile.
  88. //
  89.  
  90. volatile HANDLE ReadPipe;
  91. volatile HANDLE WritePipe;
  92.  
  93.  
  94. CONSOLE_SCREEN_BUFFER_INFO csbi;
  95.  
  96. char   MyEchoStr[30];
  97. BOOL   CmdSent;
  98. DWORD  LinesToSend=LINESTOSEND;
  99.  
  100. VOID
  101. Client(
  102.     char* Server,
  103.     char* Pipe
  104.     )
  105. {
  106.     HANDLE *Connection;
  107.     DWORD  dwThreadID;
  108.     HANDLE hThread;
  109.     DWORD  cb;
  110.     OVERLAPPED ol;
  111.     char   rgchBuf[1024];
  112.  
  113.  
  114.     MyStdInp=GetStdHandle(STD_INPUT_HANDLE);
  115.     MyStdOut=GetStdHandle(STD_OUTPUT_HANDLE);
  116.  
  117.     printf("**************************************\n");
  118.     printf("***********     REMOTE    ************\n");
  119.     printf("***********     CLIENT    ************\n");
  120.     printf("**************************************\n");
  121.  
  122.     if ((Connection=EstablishSession(Server,Pipe))==NULL)
  123.         return;
  124.  
  125.  
  126.     ReadPipe=Connection[0];
  127.     WritePipe=Connection[1];
  128.  
  129.     SetConsoleCtrlHandler((PHANDLER_ROUTINE)Mych,TRUE);
  130.  
  131.     // Start Thread For Client --> Server Flow
  132.     hThread = (HANDLE)
  133.         _beginthreadex(
  134.             NULL,             // security
  135.             0,                // default stack size
  136.             SendServerInp,    // thread proc
  137.             NULL,             // parm
  138.             0,                // not suspended
  139.             &dwThreadID
  140.             );
  141.  
  142.     if ( ! hThread)
  143.     {
  144.  
  145.         Errormsg("REMOTE /C Could Not Create Thread.");
  146.         return;
  147.     }
  148.  
  149.  
  150.     ZeroMemory(&ol, sizeof(ol));
  151.  
  152.     ol.hEvent =
  153.         CreateEvent(
  154.             NULL,      // security
  155.             TRUE,      // auto-reset
  156.             FALSE,     // initially nonsignaled
  157.             NULL       // unnamed
  158.             );
  159.  
  160.     while (ReadFileSynch(ReadPipe, rgchBuf, sizeof rgchBuf, &cb, 0, &ol)) {
  161.  
  162.         if (cb) {
  163.            if ( ! WriteFile(MyStdOut, rgchBuf, cb, &cb, NULL)) {
  164.                break;
  165.            }
  166.         }
  167.  
  168.     }
  169.  
  170.     CloseHandle(ol.hEvent);
  171.  
  172.     printf("*** SESSION OVER ***");
  173.     fflush(stdout);
  174.  
  175.     //
  176.     // Terminate the keyboard reading thread.
  177.     //
  178.  
  179.     TerminateThread(hThread, 0);
  180.     CloseHandle(hThread);
  181.     CloseClientPipes();
  182.  
  183.     printf("\n");
  184.     fflush(stdout);
  185.  
  186. }
  187.  
  188.  
  189. DWORD
  190. WINAPI
  191. SendServerInp(
  192.     LPVOID pvParam
  193.     )
  194. {
  195.     DWORD  dread,dwrote;
  196.     OVERLAPPED ol;
  197.     char buff[512];
  198.  
  199.     UNREFERENCED_PARAMETER(pvParam);
  200.  
  201.     ZeroMemory(&ol, sizeof(ol));
  202.  
  203.     ol.hEvent =
  204.         CreateEvent(
  205.             NULL,      // security
  206.             TRUE,      // auto-reset
  207.             FALSE,     // initially nonsignaled
  208.             NULL       // unnamed
  209.             );
  210.  
  211.  
  212.     while(ReadFile(MyStdInp,buff,sizeof buff,&dread,NULL))
  213.     {
  214.         if (FilterClientInp(buff,dread))
  215.             continue;
  216.         if (!WriteFileSynch(WritePipe,buff,dread,&dwrote,0,&ol))
  217.             break;
  218.     }
  219.  
  220.     return 0;
  221. }
  222.  
  223.  
  224.  
  225. BOOL
  226. FilterClientInp(
  227.     char *buff,
  228.     int count
  229.     )
  230. {
  231.  
  232.     if (count==0)
  233.         return(TRUE);
  234.  
  235.     if (buff[0]==2)     // Adhoc screening of ^B so that i386kd/mipskd
  236.         return(TRUE);   // do not terminate.
  237.  
  238.     if (buff[0]==COMMANDCHAR)
  239.     {
  240.         switch (buff[1])
  241.         {
  242.         case 'k':
  243.         case 'K':
  244.         case 'q':
  245.         case 'Q':
  246.               CloseClientPipes();
  247.               return(FALSE);
  248.  
  249.         case 'h':
  250.         case 'H':
  251.               printf("%cM : Send Message\n",COMMANDCHAR);
  252.               printf("%cP : Show Popup on Server\n",COMMANDCHAR);
  253.               printf("%cS : Status of Server\n",COMMANDCHAR);
  254.               printf("%cQ : Quit client\n",COMMANDCHAR);
  255.               printf("%cH : This Help\n",COMMANDCHAR);
  256.               return(TRUE);
  257.  
  258.         default:
  259.               return(FALSE);
  260.         }
  261.  
  262.     }
  263.     return(FALSE);
  264. }
  265.  
  266. BOOL
  267. Mych(
  268.    DWORD ctrlT
  269.    )
  270.  
  271. {
  272.     char  c[2];
  273.     DWORD tmp;
  274.     OVERLAPPED ol;
  275.  
  276.     c[0]=CTRLC;
  277.  
  278.     if (ctrlT==CTRL_C_EVENT)
  279.     {
  280.         ZeroMemory(&ol, sizeof(ol));
  281.  
  282.         ol.hEvent =
  283.             CreateEvent(
  284.                 NULL,      // security
  285.                 TRUE,      // auto-reset
  286.                 FALSE,     // initially nonsignaled
  287.                 NULL       // unnamed
  288.                 );
  289.  
  290.         if (INVALID_HANDLE_VALUE != WritePipe &&
  291.             !WriteFileSynch(WritePipe,c,1,&tmp,0,&ol))
  292.         {
  293.             CloseHandle(ol.hEvent);
  294.             Errormsg("Error Sending ^c");
  295.             return(FALSE);
  296.         }
  297.         CloseHandle(ol.hEvent);
  298.         return(TRUE);
  299.     }
  300.     if ((ctrlT==CTRL_BREAK_EVENT)||
  301.         (ctrlT==CTRL_CLOSE_EVENT)||
  302.         (ctrlT==CTRL_LOGOFF_EVENT)||
  303.         (ctrlT==CTRL_SHUTDOWN_EVENT)
  304.        ) {
  305.  
  306.        CloseClientPipes();
  307.     }
  308.     return(FALSE);
  309. }
  310.  
  311. VOID
  312. CloseClientPipes(
  313.     VOID
  314.     )
  315. {
  316.     HANDLE WriteHandle, ReadHandle;
  317.  
  318.     WriteHandle = (HANDLE) InterlockedExchange(
  319.         (LPLONG) &WritePipe,
  320.         (LONG)   INVALID_HANDLE_VALUE
  321.         );
  322.  
  323.     if (INVALID_HANDLE_VALUE != WriteHandle) {
  324.  
  325.         CloseHandle(WriteHandle);
  326.  
  327.         ReadHandle = (HANDLE) InterlockedExchange(
  328.             (LPLONG) &ReadPipe,
  329.             (LONG)   INVALID_HANDLE_VALUE
  330.             );
  331.  
  332.         if (INVALID_HANDLE_VALUE != ReadHandle &&
  333.             WriteHandle != ReadHandle) {
  334.  
  335.             CloseHandle(ReadHandle);
  336.         }
  337.     }
  338. }
  339.  
  340.  
  341. VOID
  342. HandleConnectError(
  343.     char *server,
  344.     char *srvpipename
  345.     )
  346. {
  347.     DWORD Err = GetLastError();
  348.     char  msg[128];
  349.  
  350.     Errormsg("*** Unable to Connect ***");
  351.  
  352.     //
  353.     // Print a helpful message
  354.     //
  355.  
  356.     switch(Err)
  357.     {
  358.         case ERROR_FILE_NOT_FOUND:
  359.             sprintf(msg,"invalid pipe name %s", srvpipename);
  360.             break;
  361.  
  362.         case ERROR_BAD_NETPATH:
  363.             sprintf(msg,"\\\\%s not found", server);
  364.             break;
  365.  
  366.         default:
  367.             FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|
  368.                            FORMAT_MESSAGE_IGNORE_INSERTS,
  369.                            NULL, Err, 0, msg, sizeof(msg), NULL);
  370.             break;
  371.  
  372.     }
  373.  
  374.     printf("Diagnosis: %s\n",msg);
  375.  
  376.     //
  377.     // If the machine exists but the pipe doesn't do an
  378.     // automatic remote /q to list pipes available on
  379.     // that machine.
  380.     //
  381.  
  382.     if (ERROR_FILE_NOT_FOUND == Err) {
  383.  
  384.         printf("\nREMOTE /Q %s\n", server);
  385.         fflush(stdout);
  386.         QueryRemotePipes(server);
  387.     }
  388. }
  389.  
  390.  
  391.  
  392. HANDLE*
  393. EstablishSession(
  394.     char *server,
  395.     char *srvpipename
  396.     )
  397. {
  398.     extern BOOL bForceTwoPipes;
  399.     static HANDLE PipeH[2];
  400.     char   pipenameSrvIn[200];
  401.     char   pipenameSrvOut[200];
  402.     BOOL   fOldServer;
  403.     DWORD  dwError;
  404.     DWORD  RetryCount = 0;
  405.  
  406.     //
  407.     // Since in single-pipe operation we'll be using the same
  408.     // pipe in two threads, we have to open the handles for
  409.     // overlapped operation, even though we always want
  410.     // synchronous operation.
  411.     //
  412.  
  413.     sprintf(pipenameSrvIn ,SERVER_READ_PIPE ,server,srvpipename);
  414.     sprintf(pipenameSrvOut,SERVER_WRITE_PIPE,server,srvpipename);
  415.  
  416.     if (bForceTwoPipes) {
  417.  
  418.         dwError = ERROR_NOT_SUPPORTED;
  419.  
  420.     } else {
  421.  
  422.       RetrySrvBidi:
  423.  
  424.         if (INVALID_HANDLE_VALUE ==
  425.                (PipeH[1] =
  426.                     CreateFile(
  427.                         pipenameSrvIn,
  428.                         GENERIC_READ | GENERIC_WRITE,
  429.                         0,
  430.                         NULL,
  431.                         OPEN_EXISTING,
  432.                         FILE_FLAG_OVERLAPPED,
  433.                         NULL
  434.                         ))) {
  435.  
  436.             dwError = GetLastError();
  437.  
  438.             if (ERROR_PIPE_BUSY == dwError) {
  439.  
  440.                 printf( "All pipe instances busy, waiting for another...\n");
  441.  
  442.                 WaitNamedPipe(
  443.                     pipenameSrvIn,
  444.                     15000
  445.                     );
  446.  
  447.                 if (RetryCount++ < 6) {
  448.                     goto RetrySrvBidi;
  449.                 }
  450.             }
  451.  
  452.             if (ERROR_ACCESS_DENIED != dwError &&
  453.                 ERROR_NOT_SUPPORTED != dwError) {
  454.  
  455.                 HandleConnectError(server, srvpipename);
  456.                 return NULL;
  457.             }
  458.  
  459.         } else {
  460.  
  461.             PipeH[0] = PipeH[1];
  462.             fAsyncPipe = TRUE;
  463.  
  464.             printf("Connected...\n\n");
  465.  
  466.             SendMyInfo(PipeH);
  467.  
  468.             return PipeH;
  469.         }
  470.     }
  471.  
  472.  
  473.     //
  474.     // Old remote servers don't allow you to open the
  475.     // server IN pipe for READ access, so go down the
  476.     // old path, notably opening OUT first so the
  477.     // server knows we'll be using both pipes.  We'll
  478.     // also come down this path on Win95 because
  479.     // it doesn't allow you to open an overlapped
  480.     // pipe handle.  Or if remote /c mach pipe /2 is used.
  481.     //
  482.  
  483.     fOldServer = (ERROR_ACCESS_DENIED == dwError);
  484.  
  485.   RetrySrvOut:
  486.  
  487.     if (INVALID_HANDLE_VALUE ==
  488.             (PipeH[0] =
  489.                 CreateFile(
  490.                     pipenameSrvOut,
  491.                     GENERIC_READ,
  492.                     0,
  493.                     NULL,
  494.                     OPEN_EXISTING,
  495.                     0,
  496.                     NULL
  497.                     ))) {
  498.  
  499.         if (ERROR_PIPE_BUSY == GetLastError()) {
  500.  
  501.             printf( "All OUT pipe instances busy, waiting for another...\n");
  502.  
  503.             WaitNamedPipe(
  504.                 pipenameSrvOut,
  505.                 32000              // server recycles abandoned
  506.                 );                 // OUT pipe after two minutes
  507.  
  508.             if (RetryCount++ < 6) {
  509.                 goto RetrySrvOut;
  510.             }
  511.         }
  512.  
  513.         HandleConnectError(server, srvpipename);
  514.         return NULL;
  515.  
  516.     }
  517.  
  518.  
  519.   RetrySrvIn:
  520.  
  521.     if (INVALID_HANDLE_VALUE ==
  522.            (PipeH[1] =
  523.                CreateFile(
  524.                     pipenameSrvIn,
  525.                     GENERIC_WRITE,
  526.                     0,
  527.                     NULL,
  528.                     OPEN_EXISTING,
  529.                     0,
  530.                     NULL
  531.                     ))) {
  532.  
  533.         dwError = GetLastError();
  534.  
  535.         if (ERROR_PIPE_BUSY == dwError) {
  536.  
  537.             printf( "All IN pipe instances busy, waiting for another...\n");
  538.  
  539.             WaitNamedPipe(
  540.                 pipenameSrvIn,
  541.                 15000
  542.                 );
  543.  
  544.             if (RetryCount++ < 6) {
  545.                 goto RetrySrvIn;
  546.            }
  547.         }
  548.  
  549.         HandleConnectError(server, srvpipename);
  550.         return NULL;
  551.  
  552.     }
  553.  
  554.     fAsyncPipe = FALSE;
  555.  
  556.     printf("Connected... %s\n\n",
  557.            fOldServer
  558.                ? "to two-pipe remote server."
  559.                : "using two pipes."
  560.            );
  561.  
  562.     SendMyInfo(PipeH);
  563.  
  564.     return PipeH;
  565. }
  566.  
  567.  
  568.  
  569. VOID
  570. SendMyInfo(
  571.     PHANDLE pipeH
  572.     )
  573. {
  574.     HANDLE rPipe=pipeH[0];
  575.     HANDLE wPipe=pipeH[1];
  576.  
  577.     DWORD  hostlen;
  578.     WORD   BytesToSend=sizeof(SESSION_STARTUPINFO);
  579.     DWORD  tmp;
  580.     OVERLAPPED ol;
  581.     SESSION_STARTUPINFO ssi;
  582.     SESSION_STARTREPLY  ssr;
  583.  
  584.     ol.hEvent =
  585.         CreateEvent(
  586.             NULL,      // security
  587.             TRUE,      // auto-reset
  588.             FALSE,     // initially nonsignaled
  589.             NULL       // unnamed
  590.             );
  591.  
  592.     ssi.Size=BytesToSend;
  593.     ssi.Version=VERSION;
  594.  
  595.     hostlen = sizeof(ssi.ClientName) / sizeof(ssi.ClientName[0]);
  596.     GetComputerName(ssi.ClientName, &hostlen);
  597.     ssi.LinesToSend=LinesToSend;
  598.     ssi.Flag=ClientToServerFlag;
  599.  
  600.     {
  601.         DWORD NewCode=MAGICNUMBER;
  602.         char  Name[MAX_COMPUTERNAME_LENGTH+1];
  603.  
  604.         strcpy(Name,(char *)ssi.ClientName);
  605.         memcpy(&Name[11],(char *)&NewCode,sizeof(NewCode));
  606.  
  607.         //
  608.         // The server needs to know if we're doing single-pipe
  609.         // operation so it can complete the connection properly.
  610.         // So if we are, change the first byte of the first
  611.         // send (the computername, which is later superceded
  612.         // by the one in the SESSION_STARTUPINFO structure)
  613.         // to an illegal computername character, question mark.
  614.         //
  615.  
  616.         if (wPipe == rPipe) {
  617.  
  618.              Name[0] = '?';
  619.         }
  620.  
  621.         WriteFileSynch(wPipe,(char *)Name,HOSTNAMELEN-1,&tmp,0,&ol);
  622.         ReadFileSynch(rPipe ,(char *)&ssr.MagicNumber,sizeof(ssr.MagicNumber),&tmp,0,&ol);
  623.  
  624.         if (ssr.MagicNumber!=MAGICNUMBER)
  625.         {
  626.             SetLastError(ERROR_INVALID_PARAMETER);
  627.             ErrorExit("Pipe connected but server not recognized.\n");
  628.         }
  629.  
  630.         //Get Rest of the info-its not the old server
  631.  
  632.         ReadFileSynch(
  633.             rPipe,
  634.             (char *)&ssr + sizeof(ssr.MagicNumber),
  635.             sizeof(ssr)-sizeof(ssr.MagicNumber),
  636.             &tmp,
  637.             0,
  638.             &ol
  639.             );
  640.  
  641.     }
  642.  
  643.     if (!WriteFileSynch(wPipe,(char *)&ssi,BytesToSend,&tmp,0,&ol))
  644.     {
  645.        Errormsg("INFO Send Error");
  646.     }
  647.  
  648.     CloseHandle(ol.hEvent);
  649. }
  650.  
  651.  
  652. VOID
  653. QueryRemotePipes(
  654.     char* pszServer
  655.     )
  656. {
  657.     HANDLE hQPipe;
  658.     DWORD  dwRead;
  659.     DWORD  dwError;
  660.     char   fullname[400];
  661.     char*  msg;
  662.     int    msgLen;
  663.  
  664.     if (pszServer[0] == '\\' && pszServer[1] == '\\') {
  665.         pszServer += 2;
  666.     }
  667.  
  668.     printf("Querying server \\\\%s\n", pszServer);
  669.  
  670.     sprintf(fullname, QUERY_DEBUGGERS_PIPE, pszServer);
  671.         
  672.     //  
  673.     // Send request and display the query result
  674.     //                                                                                
  675.                                                                                    
  676.     hQPipe = CreateFile(fullname,
  677.         GENERIC_READ | GENERIC_WRITE,
  678.         0,
  679.         NULL,
  680.         OPEN_EXISTING,
  681.         FILE_ATTRIBUTE_NORMAL,
  682.         NULL);
  683.     
  684.     if(hQPipe == INVALID_HANDLE_VALUE) {
  685.  
  686.         dwError = GetLastError();
  687.  
  688.         if (ERROR_FILE_NOT_FOUND == dwError) {
  689.  
  690.             printf("No Remote servers running on \\\\%s\n", pszServer);
  691.  
  692.         } else if (ERROR_BAD_NETPATH == dwError) {
  693.  
  694.             printf("\\\\%s not found on the network\n", pszServer);
  695.  
  696.         } else {
  697.  
  698.             FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
  699.                            FORMAT_MESSAGE_IGNORE_INSERTS,
  700.                            NULL, dwError, 0,
  701.                            fullname, sizeof(fullname), NULL);
  702.  
  703.             printf("Can't query server %s: %s\n", pszServer, fullname);
  704.         }
  705.  
  706.         return;
  707.     }                                                                                  
  708.     
  709.     //  Send Query Command
  710.     if(!WriteFile(hQPipe, "q", 1, &dwRead, NULL)
  711.         || (dwRead != 1))
  712.     {
  713.         printf("\nError: Can't send command\n");
  714.         goto failure;
  715.     }
  716.  
  717.     if(!ReadFile(hQPipe, 
  718.              &msgLen,
  719.              sizeof(int),      // read msg dimension
  720.              &dwRead,                                    
  721.              NULL) 
  722.         || (dwRead != sizeof(int)))
  723.     {
  724.         printf("\nError: Can't read message\n");
  725.         goto failure;
  726.     }
  727.  
  728.     if(!msgLen)
  729.     {
  730.         printf("\nNo visible sessions on server %s", pszServer);
  731.         goto failure;
  732.     }
  733.  
  734.     if(msgLen > 65535)        // error
  735.     {
  736.         printf("Error querying server %s, got %d for msg length, 65535 max.\n",
  737.                pszServer,
  738.                msgLen
  739.                );
  740.         goto failure;
  741.     }
  742.     
  743.     if((msg = (char*)malloc(msgLen*sizeof(char))) == NULL)
  744.     {
  745.         printf("\nOut of memory\n");
  746.         goto failure;    
  747.     }
  748.  
  749.     ReadFile(hQPipe, 
  750.              msg,
  751.              msgLen * sizeof(char),      // read msg
  752.              &dwRead,                                    
  753.              NULL);                                                                
  754.  
  755.     printf("\nVisible sessions on server %s:\n\n", pszServer);
  756.     
  757.     printf("%s\n", msg);
  758.     free(msg);
  759.  
  760.  failure:
  761.  
  762.     CloseHandle(hQPipe);
  763. }
  764.