remsrv.c 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. remsrv.c
  5. Abstract:
  6. This module implements remote debug server functionality.
  7. Author:
  8. Evan Green 27-Aug-2014
  9. Environment:
  10. Debug Client
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "dbgrtl.h"
  16. #include <minoca/debug/spproto.h>
  17. #include <minoca/lib/im.h>
  18. #include <minoca/debug/dbgext.h>
  19. #include "symbols.h"
  20. #include "dbgapi.h"
  21. #include "dbgrprof.h"
  22. #include "console.h"
  23. #include "userdbg.h"
  24. #include "dbgrcomm.h"
  25. #include "extsp.h"
  26. #include "consio.h"
  27. #include "remsrv.h"
  28. #include "sock.h"
  29. #include <assert.h>
  30. #include <ctype.h>
  31. #include <errno.h>
  32. #include <fcntl.h>
  33. #include <getopt.h>
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <unistd.h>
  38. //
  39. // ---------------------------------------------------------------- Definitions
  40. //
  41. #define DEBUGGER_SERVER_USAGE \
  42. "Usage: server [-r] <host> <port>\n" \
  43. " server <port>\n" \
  44. " server help\n" \
  45. " server status\n" \
  46. " server stop\n" \
  47. "This command opens up a debug server that others can connect to. \n" \
  48. "If -r is specified, then the server will connect in reverse mode, \n" \
  49. "reaching out to a single client directly. This is useful in situations \n"\
  50. "where the server cannot accept incoming connections.\n"
  51. //
  52. // ------------------------------------------------------ Data Type Definitions
  53. //
  54. //
  55. // ----------------------------------------------- Internal Function Prototypes
  56. //
  57. VOID
  58. DbgrpServerThread (
  59. PVOID Parameter
  60. );
  61. VOID
  62. DbgrpServerConnectionThread (
  63. PVOID Parameter
  64. );
  65. VOID
  66. DbgrpServerConnectionReceiveThread (
  67. PVOID Parameter
  68. );
  69. VOID
  70. DbgrpClientNetworkThread (
  71. PVOID Parameter
  72. );
  73. INT
  74. DbgrpClientSendInformation (
  75. PDEBUGGER_CONTEXT Context,
  76. INT Socket
  77. );
  78. INT
  79. DbgrpRemoteSendCommand (
  80. int Socket,
  81. PDEBUG_REMOTE_HEADER Header
  82. );
  83. INT
  84. DbgrpRemoteReceiveCommand (
  85. int Socket,
  86. PDEBUG_REMOTE_HEADER *Header
  87. );
  88. INT
  89. DbgrpRemoteSendData (
  90. int Socket,
  91. PVOID Data,
  92. ULONGLONG DataSize
  93. );
  94. INT
  95. DbgrpRemoteReceiveData (
  96. int Socket,
  97. PVOID Data,
  98. ULONGLONG DataSize
  99. );
  100. INT
  101. DbgrpServerCreateClient (
  102. PDEBUGGER_CONTEXT Context,
  103. INT ClientSocket,
  104. PSTR ClientHost,
  105. INT ClientPort
  106. );
  107. VOID
  108. DbgrpServerDestroyClient (
  109. PDEBUGGER_SERVER_CLIENT Client
  110. );
  111. VOID
  112. DbgrpServerAcquireLock (
  113. PDEBUGGER_CONTEXT Context
  114. );
  115. VOID
  116. DbgrpServerReleaseLock (
  117. PDEBUGGER_CONTEXT Context
  118. );
  119. INT
  120. DbgrpClientConvertRemoteAddressString (
  121. PSTR RemoteString,
  122. PSTR *HostString,
  123. PINT Port
  124. );
  125. //
  126. // -------------------------------------------------------------------- Globals
  127. //
  128. //
  129. // Define the set of commands that affect the local debugger, even when it's
  130. // acting as a remote client.
  131. //
  132. PSTR DbgrLocalOnlyCommands[] = {
  133. "q",
  134. "srcpath",
  135. "srcpath+",
  136. NULL
  137. };
  138. //
  139. // ------------------------------------------------------------------ Functions
  140. //
  141. INT
  142. DbgrServerCommand (
  143. PDEBUGGER_CONTEXT Context,
  144. PSTR *Arguments,
  145. ULONG ArgumentCount
  146. )
  147. /*++
  148. Routine Description:
  149. This routine starts or stops a remote server interface.
  150. Arguments:
  151. Context - Supplies a pointer to the application context.
  152. Arguments - Supplies an array of strings containing the arguments. The
  153. first argument is the command itself.
  154. ArgumentCount - Supplies the count of arguments. This is always at least
  155. one.
  156. Return Value:
  157. 0 on success.
  158. Returns an error code on failure.
  159. --*/
  160. {
  161. char *AfterScan;
  162. char *Host;
  163. char *HostCopy;
  164. BOOL LockHeld;
  165. int Port;
  166. BOOL Reverse;
  167. int Socket;
  168. int Status;
  169. Host = NULL;
  170. LockHeld = FALSE;
  171. Port = 0;
  172. Reverse = FALSE;
  173. Socket = -1;
  174. if (ArgumentCount == 2) {
  175. if (strstr(Arguments[1], "help") == 0) {
  176. DbgOut(DEBUGGER_SERVER_USAGE);
  177. Status = 0;
  178. goto ServerCommandEnd;
  179. } else if (strcasecmp(Arguments[1], "status") == 0) {
  180. if (Context->Server.Socket == -1) {
  181. DbgOut("Debug server not connected.\n");
  182. } else {
  183. if (Context->Server.Host != NULL) {
  184. DbgOut("Debug server listening at address %s, port %d.\n",
  185. Context->Server.Host,
  186. Context->Server.Port);
  187. } else {
  188. DbgOut("Debug server listening on port %d.\n",
  189. Context->Server.Port);
  190. }
  191. }
  192. Status = 0;
  193. goto ServerCommandEnd;
  194. } else if (strcasecmp(Arguments[1], "stop") == 0) {
  195. if (Context->Server.Socket == -1) {
  196. DbgOut("Debug server not connected.\n");
  197. } else {
  198. DbgrpServerDestroy(Context);
  199. }
  200. Status = 0;
  201. goto ServerCommandEnd;
  202. }
  203. Port = strtoul(Arguments[1], &AfterScan, 0);
  204. if ((AfterScan == Arguments[1]) || (*AfterScan != '\0')) {
  205. DbgOut("Invalid port number '%s'.\n", Arguments[1]);
  206. Status = EINVAL;
  207. goto ServerCommandEnd;
  208. }
  209. } else if (ArgumentCount == 3) {
  210. Host = Arguments[1];
  211. Port = strtoul(Arguments[2], &AfterScan, 0);
  212. if ((AfterScan == Arguments[2]) || (*AfterScan != '\0')) {
  213. DbgOut("Invalid port number '%s'.\n", Arguments[1]);
  214. Status = EINVAL;
  215. goto ServerCommandEnd;
  216. }
  217. } else if (ArgumentCount == 4) {
  218. if (strcasecmp(Arguments[1], "-r") != 0) {
  219. DbgOut("Unknown argument %s.\n", Arguments[1]);
  220. Status = EINVAL;
  221. goto ServerCommandEnd;
  222. }
  223. Reverse = TRUE;
  224. Host = Arguments[2];
  225. Port = strtoul(Arguments[3], &AfterScan, 0);
  226. if ((AfterScan == Arguments[3]) || (*AfterScan != '\0')) {
  227. DbgOut("Invalid port number '%s'.\n", Arguments[1]);
  228. Status = EINVAL;
  229. goto ServerCommandEnd;
  230. }
  231. } else if (ArgumentCount > 4) {
  232. DbgOut("Too many arguments. Try --help for usage.\n");
  233. Status = EINVAL;
  234. goto ServerCommandEnd;
  235. }
  236. if (Context->Server.Socket != -1) {
  237. DbgOut("Debug server already listening. Run server stop to kill it.\n");
  238. Status = EINVAL;
  239. goto ServerCommandEnd;
  240. }
  241. DbgrSocketInitializeLibrary();
  242. Socket = DbgrSocketCreateStreamSocket();
  243. if (Socket == -1) {
  244. DbgOut("Failed to create socket.\n");
  245. Status = EINVAL;
  246. goto ServerCommandEnd;
  247. }
  248. //
  249. // Do an ugly conversion until someone can be bothered to use
  250. // getnameinfo.
  251. //
  252. if ((Host != NULL) && (strcmp(Host, "localhost") == 0)) {
  253. Host = NULL;
  254. }
  255. //
  256. // In reverse mode, reach out to the client directly.
  257. //
  258. if (Reverse != FALSE) {
  259. if (Host == NULL) {
  260. Host = "127.0.0.1";
  261. }
  262. Status = DbgrSocketConnect(Socket, Host, Port);
  263. if (Status != 0) {
  264. DbgOut("Failed to connect to %s on port %d: %s\n",
  265. Host,
  266. Port,
  267. strerror(errno));
  268. Status = errno;
  269. goto ServerCommandEnd;
  270. }
  271. HostCopy = strdup(Host);
  272. Status = DbgrpServerCreateClient(Context, Socket, HostCopy, Port);
  273. if (Status != 0) {
  274. DbgOut("Failed to create client: %s\n", strerror(Status));
  275. DbgrSocketClose(Socket);
  276. Socket = -1;
  277. if (HostCopy != NULL) {
  278. free(HostCopy);
  279. }
  280. goto ServerCommandEnd;
  281. }
  282. Socket = -1;
  283. } else {
  284. Status = DbgrSocketBind(Socket, Host, Port);
  285. if (Status != 0) {
  286. DbgOut("Failed to bind to port %d.\n", Port);
  287. goto ServerCommandEnd;
  288. }
  289. Status = DbgrSocketListen(Socket);
  290. if (Status != 0) {
  291. DbgOut("Failed to listen: %s\n", strerror(errno));
  292. goto ServerCommandEnd;
  293. }
  294. DbgrpServerAcquireLock(Context);
  295. LockHeld = TRUE;
  296. Context->Server.ShutDown = 1;
  297. Status = DbgrOsCreateThread(DbgrpServerThread, Context);
  298. if (Status != 0) {
  299. goto ServerCommandEnd;
  300. }
  301. Context->Server.Socket = Socket;
  302. Context->Server.Host = NULL;
  303. Context->Server.Port = 0;
  304. Status = DbgrSocketGetName(Socket, &Host, &Port);
  305. if (Status == 0) {
  306. Context->Server.Host = Host;
  307. Context->Server.Port = Port;
  308. }
  309. Socket = -1;
  310. //
  311. // Wait for the server thread to come online before continuing.
  312. //
  313. while (Context->Server.ShutDown != 0) {
  314. CommStall(10);
  315. }
  316. DbgrpServerReleaseLock(Context);
  317. LockHeld = FALSE;
  318. DbgOut("Server listening on %s:%d\n",
  319. Context->Server.Host,
  320. Context->Server.Port);
  321. }
  322. Status = 0;
  323. ServerCommandEnd:
  324. if (Socket != -1) {
  325. DbgrSocketClose(Socket);
  326. }
  327. if (LockHeld != FALSE) {
  328. DbgrpServerReleaseLock(Context);
  329. }
  330. return Status;
  331. }
  332. INT
  333. DbgrClientMainLoop (
  334. PDEBUGGER_CONTEXT Context,
  335. PSTR RemoteString,
  336. BOOL ReverseRemote
  337. )
  338. /*++
  339. Routine Description:
  340. This routine implements the main loop of the debugger when connected to a
  341. remote server.
  342. Arguments:
  343. Context - Supplies a pointer to the debugger context.
  344. RemoteString - Supplies a pointer to the remote host to connect to.
  345. ReverseRemote - Supplies a boolean indicating whether or not the client
  346. should act in "reverse": opening up a port and waiting for the server
  347. to connect. This is useful in situations where the server cannot
  348. accept incoming connections.
  349. Return Value:
  350. 0 on success.
  351. Returns an error number on failure.
  352. --*/
  353. {
  354. PDEBUG_REMOTE_HEADER Command;
  355. ULONG CommandArgumentCount;
  356. PSTR CommandArguments[DEBUGGER_MAX_COMMAND_ARGUMENTS];
  357. PDEBUGGER_COMMAND_ENTRY CommandEntry;
  358. UINTN CommandIndex;
  359. INT Length;
  360. PSTR LocalHost;
  361. INT LocalPort;
  362. INT Match;
  363. INT Port;
  364. PSTR RemoteHost;
  365. PSTR RemoteServer;
  366. INT RemoteServerPort;
  367. INT RemoteServerSocket;
  368. INT Result;
  369. int Socket;
  370. RemoteHost = NULL;
  371. Socket = -1;
  372. Result = DbgrpClientConvertRemoteAddressString(RemoteString,
  373. &RemoteHost,
  374. &Port);
  375. if (Result != 0) {
  376. DbgOut("Invalid host string: '%s'.\n", RemoteString);
  377. goto ClientMainLoopEnd;
  378. }
  379. DbgrSocketInitializeLibrary();
  380. Socket = DbgrSocketCreateStreamSocket();
  381. if (Socket < 0) {
  382. DbgOut("Failed to create socket.\n");
  383. goto ClientMainLoopEnd;
  384. }
  385. Context->Client.Socket = Socket;
  386. //
  387. // If running in reverse, bind to the given host/port, and wait for an
  388. // incoming connection.
  389. //
  390. if (ReverseRemote != FALSE) {
  391. Result = DbgrSocketBind(Socket, RemoteHost, Port);
  392. if (Result != 0) {
  393. DbgOut("Failed to bind to %s:%d: %s.\n",
  394. RemoteHost,
  395. Port,
  396. strerror(errno));
  397. goto ClientMainLoopEnd;
  398. }
  399. Result = DbgrSocketListen(Socket);
  400. if (Result != 0) {
  401. DbgOut("Failed to listen.\n");
  402. goto ClientMainLoopEnd;
  403. }
  404. Result = DbgrSocketGetName(Socket, &LocalHost, &LocalPort);
  405. if (Result == 0) {
  406. DbgOut("Waiting for connection on %s:%d...\n",
  407. LocalHost,
  408. LocalPort);
  409. if (LocalHost != NULL) {
  410. free(LocalHost);
  411. }
  412. } else {
  413. DbgOut("Waiting for connection...\n");
  414. }
  415. RemoteServerSocket = DbgrSocketAccept(Socket,
  416. &RemoteServer,
  417. &RemoteServerPort);
  418. if (RemoteServerSocket < 0) {
  419. DbgOut("Failed to accept incoming connection.\n");
  420. goto ClientMainLoopEnd;
  421. }
  422. DbgOut("Connected to %s:%d\n", RemoteServer, RemoteServerPort);
  423. if (RemoteServer != NULL) {
  424. free(RemoteServer);
  425. }
  426. //
  427. // Replace the main socket with the newly accepted connection.
  428. //
  429. DbgrSocketClose(Socket);
  430. Socket = RemoteServerSocket;
  431. Context->Client.Socket = Socket;
  432. } else {
  433. DbgOut("Connecting to %s:%d...\n", RemoteHost, Port);
  434. Result = DbgrSocketConnect(Socket, RemoteHost, Port);
  435. if (Result != 0) {
  436. DbgOut("Failed to connect to %s.\n", RemoteHost);
  437. goto ClientMainLoopEnd;
  438. }
  439. }
  440. Result = DbgrpClientSendInformation(Context, Socket);
  441. if (Result != 0) {
  442. DbgOut("Failed to send client information.\n");
  443. goto ClientMainLoopEnd;
  444. }
  445. UiSetCommandText("");
  446. Result = DbgrOsCreateThread(DbgrpClientNetworkThread, Context);
  447. if (Result != 0) {
  448. DbgOut("Failed to create client network thread.\n");
  449. Context->Client.Socket = -1;
  450. goto ClientMainLoopEnd;
  451. }
  452. //
  453. // Don't echo commands, as the server does that.
  454. //
  455. Context->Flags &= ~DEBUGGER_FLAG_ECHO_COMMANDS;
  456. //
  457. // Loop breaking in and waiting for the target.
  458. //
  459. while ((Context->Flags & DEBUGGER_FLAG_EXITING) == 0) {
  460. //
  461. // Process a command from the user.
  462. //
  463. Result = DbgrGetCommand(Context);
  464. if (Result == FALSE) {
  465. Result = EINVAL;
  466. goto ClientMainLoopEnd;
  467. }
  468. if (Context->CommandBuffer[0] == '\0') {
  469. continue;
  470. }
  471. //
  472. // Determine if this command should be acted on locally.
  473. //
  474. CommandIndex = 0;
  475. Match = 1;
  476. while (DbgrLocalOnlyCommands[CommandIndex] != NULL) {
  477. Length = strlen(DbgrLocalOnlyCommands[CommandIndex]);
  478. Match = strncasecmp(Context->CommandBuffer,
  479. DbgrLocalOnlyCommands[CommandIndex],
  480. Length);
  481. if ((Match == 0) &&
  482. ((isspace(Context->CommandBuffer[Length]) != 0) ||
  483. (Context->CommandBuffer[Length] == '\0'))) {
  484. Result = DbgrpSplitCommandArguments(Context->CommandBuffer,
  485. CommandArguments,
  486. &CommandArgumentCount);
  487. if (Result == FALSE) {
  488. Result = EINVAL;
  489. goto ClientMainLoopEnd;
  490. }
  491. CommandEntry = DbgrLookupCommand(CommandArguments[0]);
  492. assert(CommandEntry != NULL);
  493. DbgOut("\n");
  494. CommandEntry->CommandRoutine(Context,
  495. CommandArguments,
  496. CommandArgumentCount);
  497. DbgOut("%s", Context->StandardOut.Prompt);
  498. break;
  499. }
  500. CommandIndex += 1;
  501. }
  502. if (Match == 0) {
  503. continue;
  504. }
  505. //
  506. // Send the command to the remote server.
  507. //
  508. Length = strlen(Context->CommandBuffer);
  509. Command = malloc(Length + sizeof(DEBUG_REMOTE_HEADER));
  510. if (Command == NULL) {
  511. DbgOut("Allocation failure.\n");
  512. continue;
  513. }
  514. Command->Command = DebugRemoteInput;
  515. Command->Length = Length;
  516. memcpy(Command + 1, Context->CommandBuffer, Length);
  517. Result = DbgrpRemoteSendCommand(Socket, Command);
  518. if (Result != 0) {
  519. DbgOut("Failed to send command.\n");
  520. break;
  521. }
  522. }
  523. //
  524. // Wait for the client thread to stop.
  525. //
  526. if (Context->Client.Socket != -1) {
  527. DbgrSocketShutdown(Socket);
  528. while (Context->Client.ShutDown == 0) {
  529. CommStall(10);
  530. }
  531. }
  532. ClientMainLoopEnd:
  533. if (Socket != -1) {
  534. DbgrSocketClose(Socket);
  535. Context->Client.Socket = -1;
  536. }
  537. if (RemoteHost != NULL) {
  538. free(RemoteHost);
  539. }
  540. DbgrSocketDestroyLibrary();
  541. return Result;
  542. }
  543. INT
  544. DbgrpClientRequestBreakIn (
  545. PDEBUGGER_CONTEXT Context
  546. )
  547. /*++
  548. Routine Description:
  549. This routine sends a break request across to the debug server.
  550. Arguments:
  551. Context - Supplies a pointer to the debugger context.
  552. Return Value:
  553. 0 on success.
  554. Non-zero on error.
  555. --*/
  556. {
  557. DEBUG_REMOTE_HEADER Header;
  558. INT Result;
  559. Header.Command = DebugRemoteBreakRequest;
  560. Header.Length = 0;
  561. Result = DbgrpRemoteSendCommand(Context->Client.Socket, &Header);
  562. return Result;
  563. }
  564. VOID
  565. DbgrpServerNotifyClients (
  566. PDEBUGGER_CONTEXT Context
  567. )
  568. /*++
  569. Routine Description:
  570. This routine notifies all debug clients connected to the given server that
  571. there is new activity to send off to the clients. This routine assumes the
  572. standard output lock is already held.
  573. Arguments:
  574. Context - Supplies a pointer to the debugger context.
  575. Return Value:
  576. None.
  577. --*/
  578. {
  579. PDEBUGGER_SERVER_CLIENT Client;
  580. PLIST_ENTRY CurrentEntry;
  581. char OutputCharacter;
  582. //
  583. // Note that if the server is ever changed to synchronize on something
  584. // other than the standard output lock, then it would need to be acquired
  585. // here. All callers of this function are holding the standard output lock.
  586. //
  587. OutputCharacter = 'o';
  588. CurrentEntry = Context->Server.ClientList.Next;
  589. while (CurrentEntry != &(Context->Server.ClientList)) {
  590. Client = LIST_VALUE(CurrentEntry, DEBUGGER_SERVER_CLIENT, ListEntry);
  591. CurrentEntry = CurrentEntry->Next;
  592. assert(Client->Context == Context);
  593. //
  594. // Wake up the client by writing to its pipe.
  595. //
  596. if ((Client->Pipe[1] != -1) && (Client->Update == 0)) {
  597. Client->Update = 1;
  598. write(Client->Pipe[1], &OutputCharacter, 1);
  599. }
  600. }
  601. return;
  602. }
  603. VOID
  604. DbgrpServerDestroy (
  605. PDEBUGGER_CONTEXT Context
  606. )
  607. /*++
  608. Routine Description:
  609. This routine tears down the debug server and all its connections.
  610. Arguments:
  611. Context - Supplies a pointer to the debugger context.
  612. Return Value:
  613. None.
  614. --*/
  615. {
  616. PDEBUGGER_SERVER_CLIENT Client;
  617. PLIST_ENTRY CurrentEntry;
  618. DbgrpServerAcquireLock(Context);
  619. if (Context->Server.Socket != -1) {
  620. Context->Server.ShutDown = 1;
  621. DbgrSocketClose(Context->Server.Socket);
  622. Context->Server.Socket = -1;
  623. }
  624. if (Context->Client.Socket != -1) {
  625. DbgrSocketShutdown(Context->Client.Socket);
  626. }
  627. if (Context->Server.Host != NULL) {
  628. free(Context->Server.Host);
  629. Context->Server.Host = NULL;
  630. }
  631. Context->Server.Port = 0;
  632. CurrentEntry = Context->Server.ClientList.Next;
  633. while (CurrentEntry != &(Context->Server.ClientList)) {
  634. Client = LIST_VALUE(CurrentEntry, DEBUGGER_SERVER_CLIENT, ListEntry);
  635. if (Client->Socket != -1) {
  636. DbgrSocketShutdown(Client->Socket);
  637. }
  638. //
  639. // Close the write end of the pipe to unblock the connection thread
  640. // trying to read it.
  641. //
  642. if (Client->Pipe[1] != -1) {
  643. close(Client->Pipe[1]);
  644. Client->Pipe[1] = -1;
  645. }
  646. CurrentEntry = CurrentEntry->Next;
  647. }
  648. DbgrpServerReleaseLock(Context);
  649. while ((LIST_EMPTY(&(Context->Server.ClientList)) == FALSE) ||
  650. (Context->Server.ShutDown != 0)) {
  651. CommStall(10);
  652. DbgrpServerAcquireLock(Context);
  653. DbgrpServerReleaseLock(Context);
  654. }
  655. //
  656. // Acquire and release the lock one more time as a barrier.
  657. //
  658. DbgrpServerAcquireLock(Context);
  659. DbgrpServerReleaseLock(Context);
  660. DbgrSocketDestroyLibrary();
  661. return;
  662. }
  663. //
  664. // --------------------------------------------------------- Internal Functions
  665. //
  666. VOID
  667. DbgrpServerThread (
  668. PVOID Parameter
  669. )
  670. /*++
  671. Routine Description:
  672. This routine is the entry point for the debug server thread that simply
  673. accepts new connections and spawns worker threads to handle them.
  674. Arguments:
  675. Parameter - Supplies a pointer supplied by the creator of the thread. In
  676. this case, the debugger application context.
  677. Return Value:
  678. None.
  679. --*/
  680. {
  681. char *ClientHost;
  682. int ClientPort;
  683. int ClientSocket;
  684. PDEBUGGER_CONTEXT Context;
  685. int Result;
  686. int Socket;
  687. Context = Parameter;
  688. //
  689. // Mark that the server thread has fired up.
  690. //
  691. Context->Server.ShutDown = 0;
  692. //
  693. // Loop accepting connections.
  694. //
  695. while (TRUE) {
  696. Socket = Context->Server.Socket;
  697. if (Context->Server.ShutDown != 0) {
  698. break;
  699. }
  700. ClientHost = NULL;
  701. ClientSocket = DbgrSocketAccept(Socket, &ClientHost, &ClientPort);
  702. if (ClientSocket < 0) {
  703. continue;
  704. }
  705. Result = DbgrpServerCreateClient(Context,
  706. ClientSocket,
  707. ClientHost,
  708. ClientPort);
  709. if (Result != 0) {
  710. DbgrSocketClose(ClientSocket);
  711. if (ClientHost != NULL) {
  712. free(ClientHost);
  713. }
  714. }
  715. }
  716. //
  717. // Mark that the server thread is done.
  718. //
  719. Context->Server.ShutDown = 0;
  720. return;
  721. }
  722. VOID
  723. DbgrpServerConnectionThread (
  724. PVOID Parameter
  725. )
  726. /*++
  727. Routine Description:
  728. This routine is the entry point for the thread that manages an individual
  729. connection with a client for the debug server.
  730. Arguments:
  731. Parameter - Supplies a pointer supplied by the creator of the thread. In
  732. this case, a pointer to the debugger server client connection.
  733. Return Value:
  734. None.
  735. --*/
  736. {
  737. PDEBUGGER_SERVER_CLIENT Client;
  738. PDEBUG_REMOTE_CLIENT_INFORMATION ClientInformation;
  739. PDEBUGGER_CONTEXT Context;
  740. PDEBUG_REMOTE_HEADER Header;
  741. BOOL LockHeld;
  742. void *Output;
  743. ULONGLONG OutputIndex;
  744. char PipeCharacter;
  745. PSTR Prompt;
  746. int Result;
  747. DEBUG_REMOTE_SERVER_INFORMATION ServerInformation;
  748. int Size;
  749. BOOL SourceAvailable;
  750. PSTR SourceFile;
  751. ULONG SourceFileLength;
  752. PDEBUG_REMOTE_SOURCE_INFORMATION SourceInformation;
  753. ULONGLONG SourceLine;
  754. Client = Parameter;
  755. Context = Client->Context;
  756. LockHeld = FALSE;
  757. Output = NULL;
  758. OutputIndex = 0;
  759. Prompt = NULL;
  760. SourceFile = NULL;
  761. SourceInformation = NULL;
  762. memset(&ServerInformation, 0, sizeof(DEBUG_REMOTE_SERVER_INFORMATION));
  763. ServerInformation.Header.Command = DebugRemoteServerInformation;
  764. ServerInformation.Header.Length =
  765. sizeof(DEBUG_REMOTE_SERVER_INFORMATION) -
  766. FIELD_OFFSET(DEBUG_REMOTE_SERVER_INFORMATION, ProtocolVersion);
  767. ServerInformation.ProtocolVersion = DEBUG_REMOTE_PROTOCOL_VERSION;
  768. Result = DbgrpRemoteSendCommand(Client->Socket,
  769. &(ServerInformation.Header));
  770. if (Result != 0) {
  771. DbgOut("Failed to send server information to client.\n");
  772. goto ServerConnectionThreadEnd;
  773. }
  774. Result = DbgrpRemoteReceiveCommand(
  775. Client->Socket,
  776. (PDEBUG_REMOTE_HEADER *)&ClientInformation);
  777. if (Result != 0) {
  778. DbgOut("Failed to receive client information.\n");
  779. goto ServerConnectionThreadEnd;
  780. }
  781. if (ClientInformation->Header.Command != DebugRemoteClientInformation) {
  782. DbgOut("Received something other than remote client information.\n");
  783. free(ClientInformation);
  784. goto ServerConnectionThreadEnd;
  785. }
  786. ClientInformation->User[DEBUG_REMOTE_USER_SIZE - 1] = '\0';
  787. ClientInformation->Host[DEBUG_REMOTE_HOST_SIZE - 1] = '\0';
  788. Client->HostName = strdup(ClientInformation->Host);
  789. Client->UserName = strdup(ClientInformation->User);
  790. free(ClientInformation);
  791. DbgOut("\nUser %s on %s connected at %s:%d.\n",
  792. Client->UserName,
  793. Client->HostName,
  794. Client->Host,
  795. Client->Port);
  796. //
  797. // Make sure the user name is something readable. Replace the user name
  798. // with the host name or the host address if it started empty.
  799. //
  800. if ((Client->UserName == NULL) || (strlen(Client->UserName) == 0)) {
  801. if (Client->UserName != NULL) {
  802. free(Client->UserName);
  803. Client->UserName = NULL;
  804. }
  805. if ((Client->HostName != NULL) && (strlen(Client->HostName) != 0)) {
  806. Client->UserName = strdup(Client->HostName);
  807. } else {
  808. Client->UserName = strdup(Client->Host);
  809. }
  810. }
  811. //
  812. // Start the receive thread.
  813. //
  814. assert(Client->ReceiveState == DebuggerServerReceiveNotStarted);
  815. Client->ReceiveState = DebuggerServerReceiveRunning;
  816. Result = DbgrOsCreateThread(DbgrpServerConnectionReceiveThread, Client);
  817. if (Result != 0) {
  818. Client->ReceiveState = DebuggerServerReceiveNotStarted;
  819. goto ServerConnectionThreadEnd;
  820. }
  821. while (TRUE) {
  822. //
  823. // Clear the update flag before going through and doing the update.
  824. //
  825. Client->Update = 0;
  826. //
  827. // Loop writing output to the client.
  828. //
  829. Result = 0;
  830. while (OutputIndex != Context->StandardOut.ConsoleBufferSize) {
  831. DbgrpServerAcquireLock(Context);
  832. LockHeld = TRUE;
  833. //
  834. // The check in the while loop was not synchronized, so take a look
  835. // again now that the lock is held.
  836. //
  837. if (OutputIndex == Context->StandardOut.ConsoleBufferSize) {
  838. break;
  839. }
  840. //
  841. // Allocate and initialize buffer containing the output that has
  842. // not yet been sent.
  843. //
  844. Size = Context->StandardOut.ConsoleBufferSize - OutputIndex;
  845. assert(Size ==
  846. Context->StandardOut.ConsoleBufferSize - OutputIndex);
  847. Output = malloc(Size + sizeof(DEBUG_REMOTE_HEADER));
  848. if (Output == NULL) {
  849. break;
  850. }
  851. memcpy(Output + sizeof(DEBUG_REMOTE_HEADER),
  852. Context->StandardOut.ConsoleBuffer + OutputIndex,
  853. Size);
  854. Header = Output;
  855. Header->Command = DebugRemoteOutput;
  856. Header->Length = Size;
  857. //
  858. // Drop the lock so the UI thread can continue, and then work on
  859. // sending the data.
  860. //
  861. DbgrpServerReleaseLock(Context);
  862. LockHeld = FALSE;
  863. Result = DbgrpRemoteSendCommand(Client->Socket, Header);
  864. if (Result != 0) {
  865. break;
  866. }
  867. OutputIndex += Size;
  868. }
  869. if (LockHeld != FALSE) {
  870. DbgrpServerReleaseLock(Context);
  871. LockHeld = FALSE;
  872. }
  873. if (Output != NULL) {
  874. free(Output);
  875. Output = NULL;
  876. }
  877. if (Result != 0) {
  878. break;
  879. }
  880. //
  881. // Check to see if the prompt has changed, and send the updated prompt
  882. // if so. Grab the source information while the lock is held.
  883. //
  884. assert((Prompt == NULL) && (SourceFile == NULL));
  885. SourceAvailable = FALSE;
  886. DbgrpServerAcquireLock(Context);
  887. if (Context->StandardOut.Prompt != NULL) {
  888. Prompt = strdup(Context->StandardOut.Prompt);
  889. }
  890. if (Context->SourceFile.Path != NULL) {
  891. SourceFile = strdup(Context->SourceFile.Path);
  892. }
  893. SourceLine = Context->SourceFile.LineNumber;
  894. if (Context->SourceFile.Contents != NULL) {
  895. SourceAvailable = TRUE;
  896. }
  897. DbgrpServerReleaseLock(Context);
  898. if (((Prompt == NULL) && (Client->Prompt != NULL)) ||
  899. ((Prompt != NULL) && (Client->Prompt == NULL)) ||
  900. ((Prompt != NULL) && (strcmp(Prompt, Client->Prompt) != 0))) {
  901. if (Client->Prompt != NULL) {
  902. free(Client->Prompt);
  903. }
  904. Client->Prompt = Prompt;
  905. Prompt = NULL;
  906. Size = 0;
  907. if (Client->Prompt != NULL) {
  908. Size = strlen(Client->Prompt);
  909. }
  910. Output = malloc(Size + sizeof(DEBUG_REMOTE_HEADER));
  911. if (Output == NULL) {
  912. break;
  913. }
  914. if (Size != 0) {
  915. memcpy(Output + sizeof(DEBUG_REMOTE_HEADER),
  916. Client->Prompt,
  917. Size);
  918. }
  919. Header = Output;
  920. Header->Command = DebugRemotePrompt;
  921. Header->Length = Size;
  922. Result = DbgrpRemoteSendCommand(Client->Socket, Header);
  923. if (Result != 0) {
  924. break;
  925. }
  926. }
  927. if (Prompt != NULL) {
  928. free(Prompt);
  929. Prompt = NULL;
  930. }
  931. if (Output != NULL) {
  932. free(Output);
  933. Output = NULL;
  934. }
  935. //
  936. // Send the updated source file and line if different.
  937. //
  938. if (((Client->SourceFile == NULL) && (SourceFile != NULL)) ||
  939. ((Client->SourceFile != NULL) && (SourceFile == NULL)) ||
  940. (Client->SourceLine != SourceLine) ||
  941. ((SourceFile != NULL) &&
  942. (strcmp(Client->SourceFile, SourceFile) != 0))) {
  943. if (Client->SourceFile != NULL) {
  944. free(Client->SourceFile);
  945. Client->SourceFile = NULL;
  946. }
  947. SourceFileLength = 0;
  948. if (SourceFile != NULL) {
  949. SourceFileLength = strlen(SourceFile);
  950. }
  951. SourceInformation = malloc(
  952. sizeof(DEBUG_REMOTE_SOURCE_INFORMATION) + SourceFileLength);
  953. if (SourceInformation != NULL) {
  954. SourceInformation->Header.Command =
  955. DebugRemoteSourceInformation;
  956. SourceInformation->Header.Length =
  957. SourceFileLength +
  958. (sizeof(DEBUG_REMOTE_SOURCE_INFORMATION) -
  959. FIELD_OFFSET(DEBUG_REMOTE_SOURCE_INFORMATION, LineNumber));
  960. if (SourceFileLength != 0) {
  961. memcpy(SourceInformation + 1,
  962. SourceFile,
  963. SourceFileLength);
  964. }
  965. SourceInformation->LineNumber = SourceLine;
  966. SourceInformation->SourceAvailable = SourceAvailable;
  967. Result = DbgrpRemoteSendCommand(Client->Socket,
  968. &(SourceInformation->Header));
  969. if (Result != 0) {
  970. break;
  971. }
  972. }
  973. Client->SourceFile = SourceFile;
  974. SourceFile = NULL;
  975. Client->SourceLine = SourceLine;
  976. }
  977. if (SourceFile != NULL) {
  978. free(SourceFile);
  979. SourceFile = NULL;
  980. }
  981. if (SourceInformation != NULL) {
  982. free(SourceInformation);
  983. SourceInformation = NULL;
  984. }
  985. //
  986. // If there's still another update to do, go back and do it.
  987. //
  988. if (Client->Update != 0) {
  989. continue;
  990. }
  991. //
  992. // Block on the pipe, which will be written to when there's something
  993. // to do.
  994. //
  995. Result = read(Client->Pipe[0], &PipeCharacter, 1);
  996. if (Result <= 0) {
  997. if (errno == EINTR) {
  998. continue;
  999. }
  1000. break;
  1001. }
  1002. }
  1003. ServerConnectionThreadEnd:
  1004. assert(LockHeld == FALSE);
  1005. if (Output != NULL) {
  1006. free(Output);
  1007. }
  1008. if (Prompt != NULL) {
  1009. free(Prompt);
  1010. }
  1011. if (SourceFile != NULL) {
  1012. free(SourceFile);
  1013. }
  1014. if (SourceInformation != NULL) {
  1015. free(SourceInformation);
  1016. }
  1017. //
  1018. // Stop the receive thread if needed.
  1019. //
  1020. if (Client->ReceiveState == DebuggerServerReceiveRunning) {
  1021. Client->ReceiveState = DebuggerServerReceiveShutDownRequested;
  1022. DbgrSocketShutdown(Client->Socket);
  1023. while (Client->ReceiveState != DebuggerServerReceiveShutDown) {
  1024. CommStall(10);
  1025. }
  1026. }
  1027. DbgOut("\nDisconnected from %s:%d.\n", Client->Host, Client->Port);
  1028. DbgrpServerAcquireLock(Context);
  1029. DbgrpServerDestroyClient(Client);
  1030. DbgrpServerReleaseLock(Context);
  1031. return;
  1032. }
  1033. VOID
  1034. DbgrpServerConnectionReceiveThread (
  1035. PVOID Parameter
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. This routine is the entry point for the thread that receives requests and
  1040. input from a remote client.
  1041. Arguments:
  1042. Parameter - Supplies a pointer supplied by the creator of the thread. In
  1043. this case, a pointer to the debugger context.
  1044. Return Value:
  1045. None.
  1046. --*/
  1047. {
  1048. PDEBUGGER_SERVER_CLIENT Client;
  1049. PDEBUGGER_CONTEXT Context;
  1050. PDEBUG_REMOTE_HEADER Header;
  1051. PDEBUGGER_REMOTE_COMMAND RemoteCommand;
  1052. INT Result;
  1053. INT Retries;
  1054. PDEBUG_REMOTE_SOURCE_DATA SourceData;
  1055. Client = Parameter;
  1056. Context = Client->Context;
  1057. Header = NULL;
  1058. Retries = 10;
  1059. while (Client->ReceiveState == DebuggerServerReceiveRunning) {
  1060. Result = DbgrpRemoteReceiveCommand(Client->Socket, &Header);
  1061. if (Result != 0) {
  1062. Retries -= 1;
  1063. if (Retries == 0) {
  1064. break;
  1065. }
  1066. continue;
  1067. }
  1068. Retries = 10;
  1069. switch (Header->Command) {
  1070. //
  1071. // Add a remote input command.
  1072. //
  1073. case DebugRemoteInput:
  1074. RemoteCommand = malloc(sizeof(DEBUGGER_REMOTE_COMMAND));
  1075. if (RemoteCommand == NULL) {
  1076. break;
  1077. }
  1078. memset(RemoteCommand, 0, sizeof(DEBUGGER_REMOTE_COMMAND));
  1079. RemoteCommand->Command = malloc(Header->Length + 1);
  1080. if (RemoteCommand->Command == NULL) {
  1081. free(RemoteCommand);
  1082. break;
  1083. }
  1084. memcpy(RemoteCommand->Command, Header + 1, Header->Length);
  1085. RemoteCommand->Command[Header->Length] = '\0';
  1086. if (Client->UserName != NULL) {
  1087. RemoteCommand->User = strdup(Client->UserName);
  1088. }
  1089. if (Client->HostName != NULL) {
  1090. RemoteCommand->Host = strdup(Client->HostName);
  1091. }
  1092. AcquireDebuggerLock(Context->StandardIn.Lock);
  1093. INSERT_BEFORE(&(RemoteCommand->ListEntry),
  1094. &(Context->StandardIn.RemoteCommandList));
  1095. ReleaseDebuggerLock(Context->StandardIn.Lock);
  1096. DbgrOsRemoteInputAdded();
  1097. break;
  1098. case DebugRemoteBreakRequest:
  1099. DbgOut("Requesting break in...\t\t[%s@%s]\n",
  1100. Client->UserName,
  1101. Client->HostName);
  1102. DbgRequestBreakIn(Context);
  1103. break;
  1104. case DebugRemoteSourceDataRequest:
  1105. //
  1106. // Send the current source data. The source file is protected by
  1107. // the standard out lock, which is the same physically but not
  1108. // conceptually as the server lock.
  1109. //
  1110. AcquireDebuggerLock(Context->StandardOut.Lock);
  1111. SourceData = malloc(sizeof(DEBUG_REMOTE_SOURCE_DATA) +
  1112. Context->SourceFile.Size);
  1113. if (SourceData != NULL) {
  1114. SourceData->Header.Command = DebugRemoteSourceData;
  1115. SourceData->Header.Length =
  1116. sizeof(DEBUG_REMOTE_SOURCE_DATA) -
  1117. (FIELD_OFFSET(DEBUG_REMOTE_SOURCE_DATA, FileNameCrc32)) +
  1118. Context->SourceFile.Size;
  1119. SourceData->FileNameCrc32 = 0;
  1120. if (Context->SourceFile.Path != NULL) {
  1121. SourceData->FileNameCrc32 = RtlComputeCrc32(
  1122. 0,
  1123. Context->SourceFile.Path,
  1124. RtlStringLength(Context->SourceFile.Path));
  1125. }
  1126. memcpy(SourceData + 1,
  1127. Context->SourceFile.Contents,
  1128. Context->SourceFile.Size);
  1129. }
  1130. ReleaseDebuggerLock(Context->StandardOut.Lock);
  1131. if (SourceData != NULL) {
  1132. DbgrpRemoteSendCommand(Client->Socket, &(SourceData->Header));
  1133. free(SourceData);
  1134. }
  1135. break;
  1136. default:
  1137. DbgOut("Unknown remote command 0x%x received.\n", Header->Command);
  1138. break;
  1139. }
  1140. }
  1141. Client->ReceiveState = DebuggerServerReceiveShutDown;
  1142. return;
  1143. }
  1144. VOID
  1145. DbgrpClientNetworkThread (
  1146. PVOID Parameter
  1147. )
  1148. /*++
  1149. Routine Description:
  1150. This routine is the entry point for the thread that manages network traffic
  1151. from a remote client.
  1152. Arguments:
  1153. Parameter - Supplies a pointer supplied by the creator of the thread. In
  1154. this case, a pointer to the debugger context.
  1155. Return Value:
  1156. None.
  1157. --*/
  1158. {
  1159. PDEBUGGER_CONTEXT Context;
  1160. ULONG CurrentNameLength;
  1161. PDEBUG_REMOTE_HEADER Header;
  1162. ULONG NameCrc32;
  1163. PSTR Output;
  1164. INT Result;
  1165. PDEBUG_REMOTE_SOURCE_DATA SourceData;
  1166. PSTR SourceFile;
  1167. PSTR SourceFileBuffer;
  1168. ULONGLONG SourceFileLength;
  1169. PDEBUG_REMOTE_SOURCE_INFORMATION SourceInformation;
  1170. ULONGLONG SourceLine;
  1171. Context = Parameter;
  1172. Context->Client.ShutDown = 0;
  1173. while (TRUE) {
  1174. Result = DbgrpRemoteReceiveCommand(Context->Client.Socket, &Header);
  1175. if (Result != 0) {
  1176. break;
  1177. }
  1178. assert(Header != NULL);
  1179. switch (Header->Command) {
  1180. case DebugRemoteOutput:
  1181. case DebugRemotePrompt:
  1182. if ((Header->Command == DebugRemotePrompt) &&
  1183. (Header->Length == 0)) {
  1184. DbgrpSetPromptText(Context, NULL);
  1185. UiEnableCommands(FALSE);
  1186. break;
  1187. }
  1188. Output = malloc(Header->Length + 1);
  1189. if (Output != NULL) {
  1190. memcpy(Output, Header + 1, Header->Length);
  1191. Output[Header->Length] = '\0';
  1192. if (Header->Command == DebugRemoteOutput) {
  1193. DbgOut("%s", Output);
  1194. } else {
  1195. assert(Header->Command == DebugRemotePrompt);
  1196. DbgrpSetPromptText(Context, Output);
  1197. UiEnableCommands(TRUE);
  1198. }
  1199. free(Output);
  1200. }
  1201. break;
  1202. case DebugRemoteSourceInformation:
  1203. //
  1204. // The source file name comes after the structure, so the source
  1205. // file size is the whole payload minus the fields in the source
  1206. // information (the header doesn't count in the length).
  1207. //
  1208. SourceInformation = (PDEBUG_REMOTE_SOURCE_INFORMATION)Header;
  1209. //
  1210. // Skip bogus lengths.
  1211. //
  1212. if (Header->Length <
  1213. (sizeof(DEBUG_REMOTE_SOURCE_INFORMATION) -
  1214. FIELD_OFFSET(DEBUG_REMOTE_SOURCE_INFORMATION, LineNumber))) {
  1215. break;
  1216. }
  1217. SourceFileLength =
  1218. Header->Length -
  1219. (sizeof(DEBUG_REMOTE_SOURCE_INFORMATION) -
  1220. FIELD_OFFSET(DEBUG_REMOTE_SOURCE_INFORMATION, LineNumber));
  1221. SourceFileBuffer = (PSTR)(SourceInformation + 1);
  1222. SourceFile = NULL;
  1223. if (SourceFileLength != 0) {
  1224. SourceFile = malloc(SourceFileLength + 1);
  1225. if (SourceFile != NULL) {
  1226. memcpy(SourceFile, SourceFileBuffer, SourceFileLength);
  1227. SourceFile[SourceFileLength] = '\0';
  1228. }
  1229. }
  1230. SourceLine = SourceInformation->LineNumber;
  1231. //
  1232. // The standard out lock protects the source file (which is the
  1233. // same physically but not conceptually as the debug server lock).
  1234. //
  1235. AcquireDebuggerLock(Context->StandardOut.Lock);
  1236. //
  1237. // If the line number is zero, just unhighlight the line.
  1238. //
  1239. if (SourceInformation->LineNumber == 0) {
  1240. DbgrpHighlightExecutingLine(Context, 0);
  1241. } else {
  1242. assert(SourceFile != NULL);
  1243. //
  1244. // If the file is the same, just move the line number.
  1245. //
  1246. if ((Context->SourceFile.Path != NULL) &&
  1247. (strcmp(Context->SourceFile.Path, SourceFile) == 0)) {
  1248. DbgrpHighlightExecutingLine(Context, SourceLine);
  1249. //
  1250. // The file needs to be loaded.
  1251. //
  1252. } else {
  1253. if (Context->SourceFile.Path != NULL) {
  1254. free(Context->SourceFile.Path);
  1255. Context->SourceFile.Path = NULL;
  1256. }
  1257. if (Context->SourceFile.ActualPath != NULL) {
  1258. free(Context->SourceFile.ActualPath);
  1259. Context->SourceFile.ActualPath = NULL;
  1260. }
  1261. if (Context->SourceFile.Contents != NULL) {
  1262. free(Context->SourceFile.Contents);
  1263. Context->SourceFile.Contents = NULL;
  1264. }
  1265. Context->SourceFile.LineNumber = 0;
  1266. Context->SourceFile.Path = SourceFile;
  1267. //
  1268. // First try to load the source locally.
  1269. //
  1270. Result = DbgrpLoadSourceFile(
  1271. Context,
  1272. SourceFile,
  1273. &(Context->SourceFile.ActualPath),
  1274. &(Context->SourceFile.Contents),
  1275. &(Context->SourceFile.Size));
  1276. if (Result == 0) {
  1277. Result = UiLoadSourceFile(
  1278. Context->SourceFile.ActualPath,
  1279. Context->SourceFile.Contents,
  1280. Context->SourceFile.Size);
  1281. if (Result != FALSE) {
  1282. DbgrpHighlightExecutingLine(Context, SourceLine);
  1283. }
  1284. //
  1285. // Source could not be loaded locally, try to request it
  1286. // from the server.
  1287. //
  1288. } else if (SourceInformation->SourceAvailable != 0) {
  1289. //
  1290. // Reuse the header to request the source data.
  1291. //
  1292. SourceInformation = NULL;
  1293. Header->Command = DebugRemoteSourceDataRequest;
  1294. Header->Length = 0;
  1295. Result = DbgrpRemoteSendCommand(Context->Client.Socket,
  1296. Header);
  1297. //
  1298. // If sending the request failed, blank out the screen.
  1299. //
  1300. if (Result != 0) {
  1301. UiLoadSourceFile(SourceFile, NULL, 0);
  1302. }
  1303. //
  1304. // Save the source line in the context for now.
  1305. //
  1306. Context->SourceFile.LineNumber = SourceLine;
  1307. }
  1308. SourceFile = NULL;
  1309. }
  1310. }
  1311. ReleaseDebuggerLock(Context->StandardOut.Lock);
  1312. if (SourceFile != NULL) {
  1313. free(SourceFile);
  1314. }
  1315. break;
  1316. case DebugRemoteSourceData:
  1317. //
  1318. // A response to a previous request to source data has come in.
  1319. // Load the file finally.
  1320. //
  1321. SourceData = (PDEBUG_REMOTE_SOURCE_DATA)Header;
  1322. //
  1323. // Skip bogus lengths.
  1324. //
  1325. if (Header->Length <
  1326. (sizeof(DEBUG_REMOTE_SOURCE_DATA) -
  1327. FIELD_OFFSET(DEBUG_REMOTE_SOURCE_DATA, FileNameCrc32))) {
  1328. break;
  1329. }
  1330. SourceFileLength =
  1331. Header->Length -
  1332. (sizeof(DEBUG_REMOTE_SOURCE_DATA) -
  1333. FIELD_OFFSET(DEBUG_REMOTE_SOURCE_DATA, FileNameCrc32));
  1334. SourceFileBuffer = (PSTR)(SourceData + 1);
  1335. SourceFile = NULL;
  1336. if (SourceFileLength != 0) {
  1337. SourceFile = malloc(SourceFileLength + 1);
  1338. if (SourceFile != NULL) {
  1339. memcpy(SourceFile, SourceFileBuffer, SourceFileLength);
  1340. SourceFile[SourceFileLength] = '\0';
  1341. }
  1342. }
  1343. //
  1344. // The standard out lock protects the source file (which is the
  1345. // same physically but not conceptually as the debug server lock).
  1346. //
  1347. AcquireDebuggerLock(Context->StandardOut.Lock);
  1348. if (Context->SourceFile.Path != NULL) {
  1349. CurrentNameLength = RtlStringLength(Context->SourceFile.Path);
  1350. NameCrc32 = RtlComputeCrc32(0,
  1351. Context->SourceFile.Path,
  1352. CurrentNameLength);
  1353. //
  1354. // If this data refers the same file as the client was
  1355. // expecting, load it.
  1356. //
  1357. if (NameCrc32 == SourceData->FileNameCrc32) {
  1358. assert(Context->SourceFile.Contents == NULL);
  1359. Context->SourceFile.Contents = SourceFile;
  1360. Context->SourceFile.Size = SourceFileLength;
  1361. SourceFile = NULL;
  1362. Result = UiLoadSourceFile(Context->SourceFile.Path,
  1363. Context->SourceFile.Contents,
  1364. Context->SourceFile.Size);
  1365. if (Result != FALSE) {
  1366. SourceLine = Context->SourceFile.LineNumber;
  1367. Context->SourceFile.LineNumber = 0;
  1368. DbgrpHighlightExecutingLine(Context, SourceLine);
  1369. }
  1370. }
  1371. }
  1372. ReleaseDebuggerLock(Context->StandardOut.Lock);
  1373. if (SourceFile != NULL) {
  1374. free(SourceFile);
  1375. }
  1376. break;
  1377. default:
  1378. DbgOut("Received unknown remote server command %d.\n",
  1379. Header->Command);
  1380. break;
  1381. }
  1382. free(Header);
  1383. }
  1384. DbgrSocketClose(Context->Client.Socket);
  1385. Context->Client.ShutDown = 1;
  1386. return;
  1387. }
  1388. INT
  1389. DbgrpClientSendInformation (
  1390. PDEBUGGER_CONTEXT Context,
  1391. INT Socket
  1392. )
  1393. /*++
  1394. Routine Description:
  1395. This routine sends sends client information to the remote server, and
  1396. collects the server information.
  1397. Arguments:
  1398. Context - Supplies the application context.
  1399. Socket - Supplies the connected socket.
  1400. Return Value:
  1401. 0 on success.
  1402. Returns an error code on failure.
  1403. --*/
  1404. {
  1405. PSTR Host;
  1406. DEBUG_REMOTE_CLIENT_INFORMATION Information;
  1407. INT Result;
  1408. PDEBUG_REMOTE_SERVER_INFORMATION ServerInformation;
  1409. PSTR User;
  1410. memset(&Information, 0, sizeof(DEBUG_REMOTE_CLIENT_INFORMATION));
  1411. Information.Header.Command = DebugRemoteClientInformation;
  1412. Information.Header.Length = sizeof(DEBUG_REMOTE_CLIENT_INFORMATION) -
  1413. FIELD_OFFSET(DEBUG_REMOTE_CLIENT_INFORMATION,
  1414. ProtocolVersion);
  1415. Information.ProtocolVersion = DEBUG_REMOTE_PROTOCOL_VERSION;
  1416. User = DbgrOsGetUserName();
  1417. if (User != NULL) {
  1418. strncpy(Information.User, User, sizeof(Information.User));
  1419. Information.User[DEBUG_REMOTE_USER_SIZE - 1] = '\0';
  1420. }
  1421. Host = DbgrOsGetHostName();
  1422. if (Host != NULL) {
  1423. strncpy(Information.Host, Host, sizeof(Information.Host));
  1424. Information.Host[DEBUG_REMOTE_HOST_SIZE - 1] = '\0';
  1425. free(Host);
  1426. }
  1427. Result = DbgrpRemoteSendCommand(Socket, &(Information.Header));
  1428. if (Result != 0) {
  1429. DbgOut("Failed to send client information.\n");
  1430. return Result;
  1431. }
  1432. Result = DbgrpRemoteReceiveCommand(
  1433. Socket,
  1434. (PDEBUG_REMOTE_HEADER *)&ServerInformation);
  1435. if (Result != 0) {
  1436. return Result;
  1437. }
  1438. if (ServerInformation->Header.Command != DebugRemoteServerInformation) {
  1439. DbgOut("Got something other than server information.\n");
  1440. free(ServerInformation);
  1441. return EINVAL;
  1442. }
  1443. DbgOut("Connected to server version %d.%d\n",
  1444. DEBUG_REMOTE_PROTOCOL_MAJOR(ServerInformation->ProtocolVersion),
  1445. DEBUG_REMOTE_PROTOCOL_MINOR(ServerInformation->ProtocolVersion));
  1446. if (DEBUG_REMOTE_PROTOCOL_MAJOR(ServerInformation->ProtocolVersion) >
  1447. DEBUG_REMOTE_PROTOCOL_MAJOR(DEBUG_REMOTE_PROTOCOL_VERSION)) {
  1448. DbgOut("This debug client must be upgraded from it's current version "
  1449. "(%d.%d) to connect to the server, which runs remote protocol "
  1450. "version %d.%d.\n",
  1451. DEBUG_REMOTE_PROTOCOL_MAJOR(DEBUG_REMOTE_PROTOCOL_VERSION),
  1452. DEBUG_REMOTE_PROTOCOL_MINOR(DEBUG_REMOTE_PROTOCOL_VERSION),
  1453. DEBUG_REMOTE_PROTOCOL_MAJOR(ServerInformation->ProtocolVersion),
  1454. DEBUG_REMOTE_PROTOCOL_MINOR(ServerInformation->ProtocolVersion));
  1455. free(ServerInformation);
  1456. return EINVAL;
  1457. }
  1458. free(ServerInformation);
  1459. return 0;
  1460. }
  1461. INT
  1462. DbgrpRemoteSendCommand (
  1463. int Socket,
  1464. PDEBUG_REMOTE_HEADER Header
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. This routine sends a command to the remote client or server.
  1469. Arguments:
  1470. Socket - Supplies the socket to send the data on.
  1471. Header - Supplies a pointer to the command to send. The data should be
  1472. immediately after the command. The command type, length, and payload
  1473. should already be filled in. The remainder of the header is filled in
  1474. by this routine.
  1475. Return Value:
  1476. 0 on success.
  1477. Returns an error code on failure.
  1478. --*/
  1479. {
  1480. INT Result;
  1481. Header->Magic = DEBUG_REMOTE_HEADER_MAGIC;
  1482. Header->DataCrc32 = RtlComputeCrc32(0, Header + 1, Header->Length);
  1483. Header->HeaderCrc32 = 0;
  1484. Header->HeaderCrc32 = RtlComputeCrc32(0,
  1485. Header,
  1486. sizeof(DEBUG_REMOTE_HEADER));
  1487. Result = DbgrpRemoteSendData(Socket,
  1488. Header,
  1489. Header->Length + sizeof(DEBUG_REMOTE_HEADER));
  1490. return Result;
  1491. }
  1492. INT
  1493. DbgrpRemoteReceiveCommand (
  1494. int Socket,
  1495. PDEBUG_REMOTE_HEADER *Header
  1496. )
  1497. /*++
  1498. Routine Description:
  1499. This routine receives a command from the remote client or server.
  1500. Arguments:
  1501. Socket - Supplies the socket to receive the data from.
  1502. Header - Supplies a pointer where a pointer to the command will be returned
  1503. on success. The caller is responsible for freeing this memory.
  1504. Return Value:
  1505. 0 on success.
  1506. Returns an error code on failure.
  1507. --*/
  1508. {
  1509. PDEBUG_REMOTE_HEADER Buffer;
  1510. ULONG FoundCrc;
  1511. DEBUG_REMOTE_HEADER LocalHeader;
  1512. INT Result;
  1513. *Header = NULL;
  1514. Result = DbgrpRemoteReceiveData(Socket,
  1515. &LocalHeader,
  1516. sizeof(DEBUG_REMOTE_HEADER));
  1517. if (Result != 0) {
  1518. return Result;
  1519. }
  1520. if (LocalHeader.Magic != DEBUG_REMOTE_HEADER_MAGIC) {
  1521. DbgOut("Received remote packet with bad magic.\n");
  1522. return EINVAL;
  1523. }
  1524. FoundCrc = LocalHeader.HeaderCrc32;
  1525. LocalHeader.HeaderCrc32 = 0;
  1526. if (RtlComputeCrc32(0, &LocalHeader, sizeof(DEBUG_REMOTE_HEADER)) !=
  1527. FoundCrc) {
  1528. DbgOut("Received remote packet with bad CRC.\n");
  1529. return EINVAL;
  1530. }
  1531. LocalHeader.HeaderCrc32 = 0;
  1532. Buffer = malloc(sizeof(DEBUG_REMOTE_HEADER) + LocalHeader.Length);
  1533. if (Buffer == NULL) {
  1534. DbgOut("Failed to allocate 0x%I64x bytes for remote packet.\n",
  1535. sizeof(DEBUG_REMOTE_HEADER) + LocalHeader.Length);
  1536. return ENOMEM;
  1537. }
  1538. memcpy(Buffer, &LocalHeader, sizeof(DEBUG_REMOTE_HEADER));
  1539. Result = DbgrpRemoteReceiveData(Socket, Buffer + 1, LocalHeader.Length);
  1540. if (Result != 0) {
  1541. DbgOut("Failed to receive 0x%I64x bytes: %s.\n",
  1542. LocalHeader.Length,
  1543. strerror(errno));
  1544. free(Buffer);
  1545. return errno;
  1546. }
  1547. if (RtlComputeCrc32(0, Buffer + 1, LocalHeader.Length) !=
  1548. LocalHeader.DataCrc32) {
  1549. free(Buffer);
  1550. return EINVAL;
  1551. }
  1552. *Header = Buffer;
  1553. return Result;
  1554. }
  1555. INT
  1556. DbgrpRemoteSendData (
  1557. int Socket,
  1558. PVOID Data,
  1559. ULONGLONG DataSize
  1560. )
  1561. /*++
  1562. Routine Description:
  1563. This routine sends data across a socket.
  1564. Arguments:
  1565. Socket - Supplies the socket to send to.
  1566. Data - Supplies a pointer to the buffer containing the data to send.
  1567. DataSize - Supplies the size of the data in bytes.
  1568. Return Value:
  1569. 0 on success.
  1570. -1 on failure.
  1571. --*/
  1572. {
  1573. ssize_t BytesSent;
  1574. size_t BytesThisRound;
  1575. while (DataSize != 0) {
  1576. BytesThisRound = DataSize;
  1577. if (BytesThisRound != DataSize) {
  1578. BytesThisRound = 0x100000;
  1579. }
  1580. BytesSent = DbgrSocketSend(Socket, Data, BytesThisRound);
  1581. if (BytesSent < 0) {
  1582. return -1;
  1583. }
  1584. Data += BytesSent;
  1585. DataSize -= BytesSent;
  1586. }
  1587. return 0;
  1588. }
  1589. INT
  1590. DbgrpRemoteReceiveData (
  1591. int Socket,
  1592. PVOID Data,
  1593. ULONGLONG DataSize
  1594. )
  1595. /*++
  1596. Routine Description:
  1597. This routine sends data across a socket.
  1598. Arguments:
  1599. Socket - Supplies the socket to send to.
  1600. Data - Supplies a pointer to the buffer where the data will be returned.
  1601. DataSize - Supplies the size of the data in bytes.
  1602. Return Value:
  1603. 0 on success.
  1604. -1 on failure.
  1605. --*/
  1606. {
  1607. ssize_t BytesSent;
  1608. size_t BytesThisRound;
  1609. while (DataSize != 0) {
  1610. BytesThisRound = DataSize;
  1611. if (BytesThisRound != DataSize) {
  1612. BytesThisRound = 0x100000;
  1613. }
  1614. BytesSent = DbgrSocketReceive(Socket, Data, BytesThisRound);
  1615. if (BytesSent < 0) {
  1616. return -1;
  1617. }
  1618. Data += BytesSent;
  1619. DataSize -= BytesSent;
  1620. }
  1621. return 0;
  1622. }
  1623. INT
  1624. DbgrpServerCreateClient (
  1625. PDEBUGGER_CONTEXT Context,
  1626. INT ClientSocket,
  1627. PSTR ClientHost,
  1628. INT ClientPort
  1629. )
  1630. /*++
  1631. Routine Description:
  1632. This routine creates, initializes, and inserts a client connection.
  1633. Arguments:
  1634. Context - Supplies a pointer to the application context.
  1635. ClientSocket - Supplies the socket containing the new connection with the
  1636. client.
  1637. ClientHost - Supplies a pointer to an allocated string containing the
  1638. name of the remote client. This will be freed when the client
  1639. connection is destroyed.
  1640. ClientPort - Supplies the port of the client connection.
  1641. Return Value:
  1642. 0 on success.
  1643. Non-zero on failure.
  1644. --*/
  1645. {
  1646. PDEBUGGER_SERVER_CLIENT ClientConnection;
  1647. INT Result;
  1648. ClientConnection = malloc(sizeof(DEBUGGER_SERVER_CLIENT));
  1649. if (ClientConnection == NULL) {
  1650. return ENOMEM;
  1651. }
  1652. memset(ClientConnection, 0, sizeof(DEBUGGER_SERVER_CLIENT));
  1653. ClientConnection->Pipe[0] = -1;
  1654. ClientConnection->Pipe[1] = -1;
  1655. ClientConnection->Socket = ClientSocket;
  1656. ClientConnection->Host = ClientHost;
  1657. ClientConnection->Port = ClientPort;
  1658. ClientConnection->Context = Context;
  1659. Result = DbgrOsCreatePipe(ClientConnection->Pipe);
  1660. if (Result != 0) {
  1661. goto ServerCreateClientEnd;
  1662. }
  1663. //
  1664. // Add this client connection officially to the list.
  1665. //
  1666. DbgrpServerAcquireLock(Context);
  1667. if (Context->Server.ShutDown != 0) {
  1668. Result = -1;
  1669. DbgrpServerReleaseLock(Context);
  1670. goto ServerCreateClientEnd;
  1671. }
  1672. INSERT_BEFORE(&(ClientConnection->ListEntry),
  1673. &(Context->Server.ClientList));
  1674. Result = DbgrOsCreateThread(DbgrpServerConnectionThread,
  1675. ClientConnection);
  1676. if (Result != 0) {
  1677. //
  1678. // The client can be destroyed officially, but don't free the host,
  1679. // as the caller will do that on failure of this function.
  1680. //
  1681. ClientConnection->Host = NULL;
  1682. ClientConnection->Socket = -1;
  1683. DbgrpServerDestroyClient(ClientConnection);
  1684. ClientConnection = NULL;
  1685. }
  1686. DbgrpServerReleaseLock(Context);
  1687. ServerCreateClientEnd:
  1688. if (Result != 0) {
  1689. if (ClientConnection != NULL) {
  1690. if (ClientConnection->Pipe[0] != -1) {
  1691. close(ClientConnection->Pipe[0]);
  1692. }
  1693. if (ClientConnection->Pipe[1] != -1) {
  1694. close(ClientConnection->Pipe[1]);
  1695. }
  1696. free(ClientConnection);
  1697. }
  1698. }
  1699. return Result;
  1700. }
  1701. VOID
  1702. DbgrpServerDestroyClient (
  1703. PDEBUGGER_SERVER_CLIENT Client
  1704. )
  1705. /*++
  1706. Routine Description:
  1707. This routine destroys a debug server client connection.
  1708. Arguments:
  1709. Client - Supplies a pointer to the client to destroy.
  1710. Return Value:
  1711. None.
  1712. --*/
  1713. {
  1714. if (Client->ListEntry.Next != NULL) {
  1715. LIST_REMOVE(&(Client->ListEntry));
  1716. }
  1717. if (Client->Socket != -1) {
  1718. DbgrSocketClose(Client->Socket);
  1719. Client->Socket = -1;
  1720. }
  1721. if (Client->Pipe[0] != -1) {
  1722. close(Client->Pipe[0]);
  1723. Client->Pipe[0] = -1;
  1724. }
  1725. if (Client->Pipe[1] != -1) {
  1726. close(Client->Pipe[1]);
  1727. Client->Pipe[1] = -1;
  1728. }
  1729. if (Client->Host != NULL) {
  1730. free(Client->Host);
  1731. }
  1732. if (Client->HostName != NULL) {
  1733. free(Client->HostName);
  1734. }
  1735. if (Client->UserName != NULL) {
  1736. free(Client->UserName);
  1737. }
  1738. if (Client->Prompt != NULL) {
  1739. free(Client->Prompt);
  1740. }
  1741. free(Client);
  1742. return;
  1743. }
  1744. VOID
  1745. DbgrpServerAcquireLock (
  1746. PDEBUGGER_CONTEXT Context
  1747. )
  1748. /*++
  1749. Routine Description:
  1750. This routine acquires the global debug server lock.
  1751. Arguments:
  1752. Context - Supplies a pointer to the debugger context.
  1753. Return Value:
  1754. None.
  1755. --*/
  1756. {
  1757. AcquireDebuggerLock(Context->StandardOut.Lock);
  1758. return;
  1759. }
  1760. VOID
  1761. DbgrpServerReleaseLock (
  1762. PDEBUGGER_CONTEXT Context
  1763. )
  1764. /*++
  1765. Routine Description:
  1766. This routine releases the global debug server lock.
  1767. Arguments:
  1768. Context - Supplies a pointer to the debugger context.
  1769. Return Value:
  1770. None.
  1771. --*/
  1772. {
  1773. ReleaseDebuggerLock(Context->StandardOut.Lock);
  1774. return;
  1775. }
  1776. INT
  1777. DbgrpClientConvertRemoteAddressString (
  1778. PSTR RemoteString,
  1779. PSTR *HostString,
  1780. PINT Port
  1781. )
  1782. /*++
  1783. Routine Description:
  1784. This routine converts a remote string in the form address:port into an
  1785. address string and a port number.
  1786. Arguments:
  1787. RemoteString - Supplies a pointer to the remote string to convert.
  1788. HostString - Supplies a pointer where a pointer to the host portion will be
  1789. returned. This newly allocated string must be freed by the caller.
  1790. Port - Supplies a pointer where the port number will be returned, or 0 if
  1791. no port was specified.
  1792. Return Value:
  1793. 0 on success.
  1794. Non-zero on failure.
  1795. --*/
  1796. {
  1797. PSTR AfterScan;
  1798. PSTR Host;
  1799. PSTR Ip6Copy;
  1800. PSTR LastColon;
  1801. INT PortNumber;
  1802. *HostString = NULL;
  1803. *Port = 0;
  1804. PortNumber = 0;
  1805. Host = strdup(RemoteString);
  1806. if (Host == NULL) {
  1807. return ENOMEM;
  1808. }
  1809. LastColon = strrchr(Host, ':');
  1810. if (LastColon == NULL) {
  1811. *HostString = Host;
  1812. return 0;
  1813. }
  1814. //
  1815. // Look for other colons, and skip the port thing if there are some.
  1816. //
  1817. if (strchr(Host, ':') != LastColon) {
  1818. //
  1819. // If it's an IPv6 address, chop off the [] and get the port.
  1820. //
  1821. if ((Host[0] == '[') && (LastColon != Host) &&
  1822. (*(LastColon - 1) == ']')) {
  1823. PortNumber = strtoul(LastColon + 1, &AfterScan, 10);
  1824. if (AfterScan == LastColon + 1) {
  1825. return EINVAL;
  1826. }
  1827. *(LastColon - 1) = '\0';
  1828. Ip6Copy = strdup(Host + 1);
  1829. free(Host);
  1830. if (Ip6Copy == NULL) {
  1831. return ENOMEM;
  1832. }
  1833. Host = Ip6Copy;
  1834. }
  1835. //
  1836. // There's only one colon, it's 255.255.255.255:1234.
  1837. //
  1838. } else {
  1839. *LastColon = '\0';
  1840. PortNumber = strtoul(LastColon + 1, &AfterScan, 10);
  1841. if (AfterScan == LastColon + 1) {
  1842. return EINVAL;
  1843. }
  1844. }
  1845. *HostString = Host;
  1846. *Port = PortNumber;
  1847. return 0;
  1848. }