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 / remoteds.c < prev    next >
C/C++ Source or Header  |  1997-10-12  |  15KB  |  564 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. // remoteds.c, a "directory service" for the limited job of
  14. // finding remote.exe servers on the same domain/workgroup.
  15. //
  16. // Dave Hart written summer 1997.
  17. //
  18. // Copyright 1997 Microsoft Corp.
  19. //
  20. //
  21. // A handy way to use this program is under remote on a single
  22. // or a few machines:
  23. //
  24. //    remote /s remoteds FindRemote
  25. //
  26. // Clients connect with remote /c machinename FindRemote
  27. //
  28. // Only remote.exe's running debuggers or with /V+ are visible
  29. // via remoteds, as with remote /q.
  30. //
  31. // Remote clients notify remoteds using mailslots, see srvad.c.
  32. //
  33. //
  34.  
  35. #include <windows.h>
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <stdlib.h>
  39. #include <process.h>
  40.  
  41. typedef char RECEIVEBUF[1024];
  42.  
  43. typedef struct tagSERVERENTRY {
  44.     int     nPID;                   // zero PID means unused slot
  45.     union {
  46.         FILETIME FileTime;
  47.         LARGE_INTEGER liTime;
  48.     };
  49.     char   *pszMachine;
  50.     char   *pszPipe;
  51.     char   *pszChildCmd;
  52. } SERVERENTRY;
  53.  
  54. #define TABLE_INITIAL_ALLOC 1 // 128       // beginning table size
  55. #define TABLE_ALLOC_DELTA   1 // 16        // grows by this many units
  56.  
  57. HANDLE       hTableHeap;
  58. SERVERENTRY *Table;
  59. int          nTableSize;
  60. int          nTableHiWater;          // highest used slot so far
  61. CRITICAL_SECTION csTable;
  62.  
  63. char szPrompt[] = "remote server search> ";
  64.  
  65.  
  66.  
  67. unsigned WINAPI     InteractThread(void * UnusedParm);
  68. unsigned WINAPI     CleanupThread(void * UnusedParm);
  69. VOID     __fastcall UpdateTimeStamp(LPFILETIME lpFileTime);
  70. VOID     __fastcall ReallocTable(int nNewTableSize);
  71.  
  72.  
  73. int
  74. main(
  75.     int argc,
  76.     char **argv
  77.     )
  78. {
  79.     char *      pszMailslot = "\\\\.\\MAILSLOT\\REMOTE\\DEBUGGERS";
  80.     HANDLE      hMailslot;
  81.     BOOL        b;
  82.     HANDLE      hThread;
  83.     DWORD       dwTID;
  84.     char *      pszMachine;
  85.     int         cchMachine;
  86.     char *      pszPID;
  87.     int         nPID;
  88.     char *      pszPipe;
  89.     int         cchPipe;
  90.     char *      pszChildCmd;
  91.     int         i;
  92.     int         nFirstAvailable;
  93.     BOOL        fStopping;
  94.     BOOL        fFound;
  95.     int         cb;
  96.     char *      pchStrings;
  97.     char *      pch;
  98.     DWORD       cbRead;
  99.     DWORD       iBuf;
  100.     DWORD       rgcbBuf[2];
  101.     RECEIVEBUF  rgBuf[2];
  102.     RECEIVEBUF  szBuf;
  103.     char        szRemoteCmd[512];
  104.  
  105.     InitializeCriticalSection(&csTable);
  106.  
  107.     ReallocTable(TABLE_INITIAL_ALLOC);
  108.  
  109.     hMailslot =
  110.         CreateMailslot(
  111.             pszMailslot,
  112.             0,
  113.             MAILSLOT_WAIT_FOREVER,
  114.             NULL
  115.             );
  116.  
  117.     if (INVALID_HANDLE_VALUE == hMailslot) {
  118.  
  119.         DWORD dwErr = GetLastError();
  120.  
  121.         if (ERROR_ALREADY_EXISTS == dwErr) {
  122.             printf("Cannot receive on %s,\n"
  123.                    "is remoteds or rdsrelay already running on this machine?\n",
  124.                    pszMailslot);
  125.         } else {
  126.             printf("CreateMailslot(%s) failed error %d\n",
  127.                     pszMailslot,
  128.                     dwErr);
  129.         }
  130.         return 2;
  131.     }
  132.  
  133.  
  134.     hThread = (HANDLE) _beginthreadex(
  135.                                       NULL,
  136.                                       0,
  137.                                       InteractThread,
  138.                                       NULL,
  139.                                       0,
  140.                                       &dwTID
  141.                                      );
  142.  
  143.     if ( ! hThread) {
  144.         printf("Can't start InteractThread %d\n", GetLastError());
  145.         return 3;
  146.     }
  147.  
  148.     CloseHandle(hThread);
  149.  
  150.     hThread = (HANDLE) _beginthreadex(
  151.                                       NULL,
  152.                                       0,
  153.                                       CleanupThread,
  154.                                       NULL,
  155.                                       0,
  156.                                       &dwTID
  157.                                      );
  158.  
  159.  
  160.     if ( ! hThread) {
  161.         printf("Can't start CleanupThread %d\n", GetLastError());
  162.         return 3;
  163.     }
  164.  
  165.     CloseHandle(hThread);
  166.  
  167.  
  168.     //
  169.     // loop reading and processing mailslot messsages
  170.     //
  171.  
  172.     iBuf = 0;
  173.     ZeroMemory(rgcbBuf, sizeof(rgcbBuf));
  174.     ZeroMemory(rgBuf, sizeof(rgBuf));
  175.  
  176.     while(TRUE)
  177.     {
  178.         b = ReadFile(
  179.                 hMailslot,
  180.                 rgBuf[ iBuf ],
  181.                 sizeof(rgBuf[ iBuf ]) - 1,  // so I can null terminate if needed
  182.                 &rgcbBuf[ iBuf ],
  183.                 NULL
  184.                 );
  185.  
  186.         if ( ! b) {
  187.             printf("ReadFile(hMailslot) failed error %d\n", GetLastError());
  188.             return 4;
  189.         }
  190.  
  191.         //
  192.         // It's the nature of mailslots and multiple transports
  193.         // that we'll get the identical message several times in
  194.         // quick succession.  Don't waste time searching the table
  195.         // for these duplicates.
  196.         //
  197.  
  198.         if ( rgcbBuf[0] == rgcbBuf[1] &&
  199.              ! memcmp(rgBuf[0], rgBuf[1], rgcbBuf[0])) {
  200.  
  201.             continue;               // duplicate
  202.         }
  203.  
  204.         //
  205.         // Make a working copy into szBuf/cbRead that we can
  206.         // modify so the original buffer is available for
  207.         // detecting received duplicates.
  208.         //
  209.  
  210.         cbRead = rgcbBuf[ iBuf ];
  211.         CopyMemory(szBuf, rgBuf[ iBuf ], cbRead);
  212.  
  213.         //
  214.         // Toggle buffers for the next read.
  215.         //
  216.  
  217.         iBuf = !iBuf;
  218.  
  219.         if (szBuf[ cbRead - 1 ]) {
  220.             printf("Received string not null terminated.\n");
  221.             szBuf[cbRead] = 0;
  222.         }
  223.  
  224.         pszMachine = szBuf;
  225.  
  226.         pch = strchr(szBuf, '\t');
  227.  
  228.         if (!pch) {
  229.             printf("Received string no 1st tab\n");
  230.             continue;
  231.         }
  232.         *pch = '\0';
  233.  
  234.         pszPID = ++pch;
  235.  
  236.         pch = strchr(pch, '\t');
  237.  
  238.         if (!pch) {
  239.             printf("Received string no 2nd tab\n");
  240.             continue;
  241.         }
  242.         *pch = '\0';
  243.  
  244.         pszPipe = ++pch;
  245.  
  246.         pch = strchr(pch, '\t');
  247.  
  248.         if (!pch) {
  249.             printf("Received string no 3nd tab\n");
  250.             continue;
  251.         }
  252.         *pch = '\0';
  253.  
  254.         pszChildCmd = ++pch;
  255.  
  256.         //
  257.         // If it ends with ^B it's going away.
  258.         //
  259.  
  260.         pch = strchr(pch, '\x2');
  261.  
  262.         if (pch) {
  263.             *pch = 0;
  264.             fStopping = TRUE;
  265.         } else {
  266.             fStopping = FALSE;
  267.         }
  268.  
  269.  
  270.         nPID = strtol(pszPID, NULL, 10);
  271.         _strlwr(pszMachine);
  272.         _strlwr(pszPipe);
  273.  
  274.         if (fStopping) {
  275.  
  276.             //
  277.             // display the ending remote's info
  278.             //
  279.  
  280.             sprintf(szRemoteCmd, "remote /c %s %s", pszMachine, pszPipe);
  281.             printf("\r%-36s %-20s   [stop]\n%s", szRemoteCmd, pszChildCmd, szPrompt);
  282.             fflush(stdout);
  283.         }
  284.  
  285.         EnterCriticalSection(&csTable);
  286.  
  287.         nFirstAvailable = -1;
  288.  
  289.         for (i = 0, fFound = FALSE;
  290.              i <= nTableHiWater;
  291.              i++) {
  292.  
  293.             if (-1 == nFirstAvailable && 0 == Table[i].nPID) {
  294.                 nFirstAvailable = i;
  295.             }
  296.  
  297.             if (Table[i].nPID == nPID &&
  298.                 ! strcmp(Table[i].pszMachine, pszMachine) &&
  299.                 ! strcmp(Table[i].pszPipe, pszPipe)) {
  300.  
  301.                 fFound = TRUE;
  302.                 break;
  303.             }
  304.         }
  305.  
  306.  
  307.         if (fFound) {
  308.  
  309.             if (fStopping) {
  310.  
  311.                 //
  312.                 // Remove it from the table
  313.                 //
  314.  
  315.                 free(Table[i].pszMachine);
  316.                 ZeroMemory(&Table[i], sizeof(Table[i]));
  317.  
  318.                 if (nTableHiWater == i) {
  319.                     nTableHiWater--;
  320.                 }
  321.  
  322.             } else { // starting
  323.  
  324.                 // printf("Found at slot %d\n", i);
  325.                 // timestamp is updated below
  326.             }
  327.  
  328.         } else if ( ! fStopping) {
  329.  
  330.             //
  331.             // we have a new entry, display it
  332.             //
  333.  
  334.             sprintf(szRemoteCmd, "remote /c %s %s", pszMachine, pszPipe);
  335.             printf("\r%-36s %-20s   [start]\n%s", szRemoteCmd, pszChildCmd, szPrompt);
  336.             fflush(stdout);
  337.  
  338.             //
  339.             // Does it fit in the table or do we need to grow it?
  340.             //
  341.  
  342.             if (-1 == nFirstAvailable) {
  343.  
  344.                 if (++nTableHiWater >= nTableSize) {
  345.                     ReallocTable(nTableSize + TABLE_ALLOC_DELTA);
  346.                 }
  347.  
  348.                 i = nTableHiWater;
  349.  
  350.             } else {
  351.  
  352.                 i = nFirstAvailable;
  353.             }
  354.  
  355.  
  356.             //
  357.             // Fill in a server entry in table, if we can
  358.             // allocate memory for the strings.
  359.             //
  360.  
  361.             cb = (cchMachine  = strlen(pszMachine) + 1) +
  362.                  (cchPipe     = strlen(pszPipe) + 1) +
  363.                  (              strlen(pszChildCmd) + 1);
  364.  
  365.             pchStrings = malloc(cb);
  366.  
  367.             if (pchStrings) {
  368.  
  369.                 Table[i].nPID = nPID;
  370.                 UpdateTimeStamp(&Table[i].FileTime);
  371.  
  372.                 Table[i].pszMachine = pchStrings;
  373.                 strcpy(Table[i].pszMachine, pszMachine);
  374.  
  375.                 Table[i].pszPipe = Table[i].pszMachine + cchMachine;
  376.                 strcpy(Table[i].pszPipe, pszPipe);
  377.  
  378.                 Table[i].pszChildCmd = Table[i].pszPipe + cchPipe;
  379.                 strcpy(Table[i].pszChildCmd, pszChildCmd);
  380.             }
  381.  
  382.         }
  383.  
  384.         UpdateTimeStamp(&Table[i].FileTime);
  385.  
  386.         LeaveCriticalSection(&csTable);
  387.  
  388.     }   // while (TRUE)
  389.  
  390.     return 0;    // never executed
  391. }
  392.  
  393.  
  394. //
  395. // InteractThread lets the user query the list of remote servers.
  396. //
  397.  
  398. unsigned WINAPI InteractThread(void * UnusedParm)
  399. {
  400.     char szQuery[1024];
  401.     char szLowerQuery[1024];
  402.     char szRemoteCmd[400];
  403.     int  i;
  404.     BOOL fAll;
  405.  
  406.  Help:
  407.     printf("Enter a string to search for, a machine or pipe name or command.\n");
  408.     printf("Enter * to list all remote servers.\n");
  409.     printf("Exit with ^B.\n");
  410.  
  411.     while (TRUE) {
  412.  
  413.         fputs(szPrompt, stdout);
  414.         fflush(stdout);
  415.         gets(szQuery);
  416.         _strlwr( strcpy(szLowerQuery, szQuery) );
  417.  
  418.         if (!strlen(szLowerQuery) ||
  419.             !strcmp(szLowerQuery, "?") ||
  420.             !strcmp(szLowerQuery, "h") ||
  421.             !strcmp(szLowerQuery, "help")) {
  422.  
  423.             goto Help;
  424.         }
  425.  
  426.         if (2 == szLowerQuery[0]) {           // ^B
  427.  
  428.             ExitProcess(0);
  429.         }
  430.  
  431.         fAll = ! strcmp(szLowerQuery, "*");
  432.  
  433.         EnterCriticalSection(&csTable);
  434.  
  435.         for (i = 0; i <= nTableHiWater; i++) {
  436.             if (Table[i].nPID) {
  437.                 if (fAll ||
  438.                     strstr(Table[i].pszMachine, szLowerQuery) ||
  439.                     strstr(Table[i].pszPipe, szLowerQuery) ||
  440.                     strstr(Table[i].pszChildCmd, szLowerQuery)) {
  441.  
  442.                     sprintf(szRemoteCmd, "remote /c %s %s", Table[i].pszMachine, Table[i].pszPipe);
  443.                     printf("%-40s %s\n", szRemoteCmd, Table[i].pszChildCmd);
  444.                 }
  445.             }
  446.         }
  447.  
  448.         LeaveCriticalSection(&csTable);
  449.  
  450.     }
  451.  
  452.     return 0;    // never executed
  453. }
  454.  
  455.  
  456. //
  457. // CleanupThread scavenges for old entries and frees them.
  458. // remote /s sends a broadcast at least every 2 hours.
  459. // We get some of them.  Age out entries after 12 hours.
  460. //
  461.  
  462. unsigned WINAPI CleanupThread(void * UnusedParm)
  463. {
  464.     LARGE_INTEGER liNow;
  465.     LARGE_INTEGER liTimeout;
  466.     int i;
  467.     char szRemoteCmd[400];
  468.  
  469.     liTimeout.QuadPart = (LONGLONG)10000000 * 60 * 60 * 12;  // 12 hours
  470.  
  471.     while (TRUE) {
  472.  
  473.         Sleep(15 * 60 * 1000);    // 10 minutes
  474.  
  475.         UpdateTimeStamp((LPFILETIME)&liNow);
  476.  
  477.         EnterCriticalSection(&csTable);
  478.  
  479.         for (i = nTableHiWater; i >= 0; i--) {
  480.  
  481.             if (Table[i].nPID) {
  482.  
  483.                 if (liNow.QuadPart - Table[i].liTime.QuadPart > liTimeout.QuadPart) {
  484.  
  485.                     //
  486.                     // display the ending remote's info
  487.                     //
  488.  
  489.                     sprintf(szRemoteCmd, "remote /c %s %s", Table[i].pszMachine, Table[i].pszPipe);
  490.                     printf("\r%-36s %-20s   [aged out]\n%s", szRemoteCmd, Table[i].pszChildCmd, szPrompt);
  491.                     fflush(stdout);
  492.  
  493.                     free(Table[i].pszMachine);
  494.                     ZeroMemory(&Table[i], sizeof(Table[i]));
  495.  
  496.                     if (nTableHiWater == i) {
  497.                         nTableHiWater--;
  498.                     }
  499.                 }
  500.  
  501.             }
  502.  
  503.         }
  504.  
  505.         LeaveCriticalSection(&csTable);
  506.     }
  507.  
  508.     return 0;    // never executed
  509. }
  510.  
  511.  
  512. VOID __fastcall UpdateTimeStamp(LPFILETIME lpFileTime)
  513. {
  514.     SYSTEMTIME SystemTime;
  515.  
  516.     GetSystemTime(&SystemTime);
  517.     SystemTimeToFileTime(&SystemTime, lpFileTime);
  518. }
  519.  
  520.  
  521. VOID __fastcall ReallocTable(int nNewTableSize)
  522. {
  523.     SERVERENTRY *pTableSave = Table;
  524.  
  525.     EnterCriticalSection(&csTable);
  526.  
  527.     nTableSize = nNewTableSize;
  528.  
  529.     if ( ! hTableHeap) {
  530.  
  531.         hTableHeap = HeapCreate(
  532.                          HEAP_NO_SERIALIZE,
  533.                          (TABLE_INITIAL_ALLOC + 1) * sizeof(Table[0]),  // size
  534.                          50000 * sizeof(Table[0])                       // max
  535.                          );
  536.         Table = HeapAlloc(
  537.                     hTableHeap,
  538.                     HEAP_ZERO_MEMORY,
  539.                     nTableSize * sizeof(Table[0])
  540.                     );
  541.     } else {
  542.  
  543.         Table = HeapReAlloc(
  544.                     hTableHeap,
  545.                     HEAP_ZERO_MEMORY,
  546.                     Table,
  547.                     nTableSize * sizeof(Table[0])
  548.                     );
  549.     }
  550.  
  551.     if (!Table) {
  552.         printf("\nremoteds: Out of memory allocating remote server table\n");
  553.         exit(ERROR_NOT_ENOUGH_MEMORY);
  554.     }
  555.  
  556.  
  557.     LeaveCriticalSection(&csTable);
  558.  
  559.     if (Table != pTableSave && pTableSave) {
  560.         printf("\nremoteds:  remote server table moved in HeapRealloc from %x to %x.\n", pTableSave, Table);
  561.         fflush(stdout);
  562.     }
  563. }
  564.