Source code of Windows XP (NT5)
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.

576 lines
14 KiB

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