12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- remsrv.c
- Abstract:
- This module implements remote debug server functionality.
- Author:
- Evan Green 27-Aug-2014
- Environment:
- Debug Client
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "dbgrtl.h"
- #include <minoca/debug/spproto.h>
- #include <minoca/lib/im.h>
- #include <minoca/debug/dbgext.h>
- #include "symbols.h"
- #include "dbgapi.h"
- #include "dbgrprof.h"
- #include "console.h"
- #include "userdbg.h"
- #include "dbgrcomm.h"
- #include "extsp.h"
- #include "consio.h"
- #include "remsrv.h"
- #include "sock.h"
- #include <assert.h>
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <getopt.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define DEBUGGER_SERVER_USAGE \
- "Usage: server [-r] <host> <port>\n" \
- " server <port>\n" \
- " server help\n" \
- " server status\n" \
- " server stop\n" \
- "This command opens up a debug server that others can connect to. \n" \
- "If -r is specified, then the server will connect in reverse mode, \n" \
- "reaching out to a single client directly. This is useful in situations \n"\
- "where the server cannot accept incoming connections.\n"
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- DbgrpServerThread (
- PVOID Parameter
- );
- VOID
- DbgrpServerConnectionThread (
- PVOID Parameter
- );
- VOID
- DbgrpServerConnectionReceiveThread (
- PVOID Parameter
- );
- VOID
- DbgrpClientNetworkThread (
- PVOID Parameter
- );
- INT
- DbgrpClientSendInformation (
- PDEBUGGER_CONTEXT Context,
- INT Socket
- );
- INT
- DbgrpRemoteSendCommand (
- int Socket,
- PDEBUG_REMOTE_HEADER Header
- );
- INT
- DbgrpRemoteReceiveCommand (
- int Socket,
- PDEBUG_REMOTE_HEADER *Header
- );
- INT
- DbgrpRemoteSendData (
- int Socket,
- PVOID Data,
- ULONGLONG DataSize
- );
- INT
- DbgrpRemoteReceiveData (
- int Socket,
- PVOID Data,
- ULONGLONG DataSize
- );
- INT
- DbgrpServerCreateClient (
- PDEBUGGER_CONTEXT Context,
- INT ClientSocket,
- PSTR ClientHost,
- INT ClientPort
- );
- VOID
- DbgrpServerDestroyClient (
- PDEBUGGER_SERVER_CLIENT Client
- );
- VOID
- DbgrpServerAcquireLock (
- PDEBUGGER_CONTEXT Context
- );
- VOID
- DbgrpServerReleaseLock (
- PDEBUGGER_CONTEXT Context
- );
- INT
- DbgrpClientConvertRemoteAddressString (
- PSTR RemoteString,
- PSTR *HostString,
- PINT Port
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Define the set of commands that affect the local debugger, even when it's
- // acting as a remote client.
- //
- PSTR DbgrLocalOnlyCommands[] = {
- "q",
- "srcpath",
- "srcpath+",
- NULL
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- DbgrServerCommand (
- PDEBUGGER_CONTEXT Context,
- PSTR *Arguments,
- ULONG ArgumentCount
- )
- /*++
- Routine Description:
- This routine starts or stops a remote server interface.
- Arguments:
- Context - Supplies a pointer to the application context.
- Arguments - Supplies an array of strings containing the arguments. The
- first argument is the command itself.
- ArgumentCount - Supplies the count of arguments. This is always at least
- one.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- char *AfterScan;
- char *Host;
- char *HostCopy;
- BOOL LockHeld;
- int Port;
- BOOL Reverse;
- int Socket;
- int Status;
- Host = NULL;
- LockHeld = FALSE;
- Port = 0;
- Reverse = FALSE;
- Socket = -1;
- if (ArgumentCount == 2) {
- if (strstr(Arguments[1], "help") == 0) {
- DbgOut(DEBUGGER_SERVER_USAGE);
- Status = 0;
- goto ServerCommandEnd;
- } else if (strcasecmp(Arguments[1], "status") == 0) {
- if (Context->Server.Socket == -1) {
- DbgOut("Debug server not connected.\n");
- } else {
- if (Context->Server.Host != NULL) {
- DbgOut("Debug server listening at address %s, port %d.\n",
- Context->Server.Host,
- Context->Server.Port);
- } else {
- DbgOut("Debug server listening on port %d.\n",
- Context->Server.Port);
- }
- }
- Status = 0;
- goto ServerCommandEnd;
- } else if (strcasecmp(Arguments[1], "stop") == 0) {
- if (Context->Server.Socket == -1) {
- DbgOut("Debug server not connected.\n");
- } else {
- DbgrpServerDestroy(Context);
- }
- Status = 0;
- goto ServerCommandEnd;
- }
- Port = strtoul(Arguments[1], &AfterScan, 0);
- if ((AfterScan == Arguments[1]) || (*AfterScan != '\0')) {
- DbgOut("Invalid port number '%s'.\n", Arguments[1]);
- Status = EINVAL;
- goto ServerCommandEnd;
- }
- } else if (ArgumentCount == 3) {
- Host = Arguments[1];
- Port = strtoul(Arguments[2], &AfterScan, 0);
- if ((AfterScan == Arguments[2]) || (*AfterScan != '\0')) {
- DbgOut("Invalid port number '%s'.\n", Arguments[1]);
- Status = EINVAL;
- goto ServerCommandEnd;
- }
- } else if (ArgumentCount == 4) {
- if (strcasecmp(Arguments[1], "-r") != 0) {
- DbgOut("Unknown argument %s.\n", Arguments[1]);
- Status = EINVAL;
- goto ServerCommandEnd;
- }
- Reverse = TRUE;
- Host = Arguments[2];
- Port = strtoul(Arguments[3], &AfterScan, 0);
- if ((AfterScan == Arguments[3]) || (*AfterScan != '\0')) {
- DbgOut("Invalid port number '%s'.\n", Arguments[1]);
- Status = EINVAL;
- goto ServerCommandEnd;
- }
- } else if (ArgumentCount > 4) {
- DbgOut("Too many arguments. Try --help for usage.\n");
- Status = EINVAL;
- goto ServerCommandEnd;
- }
- if (Context->Server.Socket != -1) {
- DbgOut("Debug server already listening. Run server stop to kill it.\n");
- Status = EINVAL;
- goto ServerCommandEnd;
- }
- DbgrSocketInitializeLibrary();
- Socket = DbgrSocketCreateStreamSocket();
- if (Socket == -1) {
- DbgOut("Failed to create socket.\n");
- Status = EINVAL;
- goto ServerCommandEnd;
- }
- //
- // Do an ugly conversion until someone can be bothered to use
- // getnameinfo.
- //
- if ((Host != NULL) && (strcmp(Host, "localhost") == 0)) {
- Host = NULL;
- }
- //
- // In reverse mode, reach out to the client directly.
- //
- if (Reverse != FALSE) {
- if (Host == NULL) {
- Host = "127.0.0.1";
- }
- Status = DbgrSocketConnect(Socket, Host, Port);
- if (Status != 0) {
- DbgOut("Failed to connect to %s on port %d: %s\n",
- Host,
- Port,
- strerror(errno));
- Status = errno;
- goto ServerCommandEnd;
- }
- HostCopy = strdup(Host);
- Status = DbgrpServerCreateClient(Context, Socket, HostCopy, Port);
- if (Status != 0) {
- DbgOut("Failed to create client: %s\n", strerror(Status));
- DbgrSocketClose(Socket);
- Socket = -1;
- if (HostCopy != NULL) {
- free(HostCopy);
- }
- goto ServerCommandEnd;
- }
- Socket = -1;
- } else {
- Status = DbgrSocketBind(Socket, Host, Port);
- if (Status != 0) {
- DbgOut("Failed to bind to port %d.\n", Port);
- goto ServerCommandEnd;
- }
- Status = DbgrSocketListen(Socket);
- if (Status != 0) {
- DbgOut("Failed to listen: %s\n", strerror(errno));
- goto ServerCommandEnd;
- }
- DbgrpServerAcquireLock(Context);
- LockHeld = TRUE;
- Context->Server.ShutDown = 1;
- Status = DbgrOsCreateThread(DbgrpServerThread, Context);
- if (Status != 0) {
- goto ServerCommandEnd;
- }
- Context->Server.Socket = Socket;
- Context->Server.Host = NULL;
- Context->Server.Port = 0;
- Status = DbgrSocketGetName(Socket, &Host, &Port);
- if (Status == 0) {
- Context->Server.Host = Host;
- Context->Server.Port = Port;
- }
- Socket = -1;
- //
- // Wait for the server thread to come online before continuing.
- //
- while (Context->Server.ShutDown != 0) {
- CommStall(10);
- }
- DbgrpServerReleaseLock(Context);
- LockHeld = FALSE;
- DbgOut("Server listening on %s:%d\n",
- Context->Server.Host,
- Context->Server.Port);
- }
- Status = 0;
- ServerCommandEnd:
- if (Socket != -1) {
- DbgrSocketClose(Socket);
- }
- if (LockHeld != FALSE) {
- DbgrpServerReleaseLock(Context);
- }
- return Status;
- }
- INT
- DbgrClientMainLoop (
- PDEBUGGER_CONTEXT Context,
- PSTR RemoteString,
- BOOL ReverseRemote
- )
- /*++
- Routine Description:
- This routine implements the main loop of the debugger when connected to a
- remote server.
- Arguments:
- Context - Supplies a pointer to the debugger context.
- RemoteString - Supplies a pointer to the remote host to connect to.
- ReverseRemote - Supplies a boolean indicating whether or not the client
- should act in "reverse": opening up a port and waiting for the server
- to connect. This is useful in situations where the server cannot
- accept incoming connections.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PDEBUG_REMOTE_HEADER Command;
- ULONG CommandArgumentCount;
- PSTR CommandArguments[DEBUGGER_MAX_COMMAND_ARGUMENTS];
- PDEBUGGER_COMMAND_ENTRY CommandEntry;
- UINTN CommandIndex;
- INT Length;
- PSTR LocalHost;
- INT LocalPort;
- INT Match;
- INT Port;
- PSTR RemoteHost;
- PSTR RemoteServer;
- INT RemoteServerPort;
- INT RemoteServerSocket;
- INT Result;
- int Socket;
- RemoteHost = NULL;
- Socket = -1;
- Result = DbgrpClientConvertRemoteAddressString(RemoteString,
- &RemoteHost,
- &Port);
- if (Result != 0) {
- DbgOut("Invalid host string: '%s'.\n", RemoteString);
- goto ClientMainLoopEnd;
- }
- DbgrSocketInitializeLibrary();
- Socket = DbgrSocketCreateStreamSocket();
- if (Socket < 0) {
- DbgOut("Failed to create socket.\n");
- goto ClientMainLoopEnd;
- }
- Context->Client.Socket = Socket;
- //
- // If running in reverse, bind to the given host/port, and wait for an
- // incoming connection.
- //
- if (ReverseRemote != FALSE) {
- Result = DbgrSocketBind(Socket, RemoteHost, Port);
- if (Result != 0) {
- DbgOut("Failed to bind to %s:%d: %s.\n",
- RemoteHost,
- Port,
- strerror(errno));
- goto ClientMainLoopEnd;
- }
- Result = DbgrSocketListen(Socket);
- if (Result != 0) {
- DbgOut("Failed to listen.\n");
- goto ClientMainLoopEnd;
- }
- Result = DbgrSocketGetName(Socket, &LocalHost, &LocalPort);
- if (Result == 0) {
- DbgOut("Waiting for connection on %s:%d...\n",
- LocalHost,
- LocalPort);
- if (LocalHost != NULL) {
- free(LocalHost);
- }
- } else {
- DbgOut("Waiting for connection...\n");
- }
- RemoteServerSocket = DbgrSocketAccept(Socket,
- &RemoteServer,
- &RemoteServerPort);
- if (RemoteServerSocket < 0) {
- DbgOut("Failed to accept incoming connection.\n");
- goto ClientMainLoopEnd;
- }
- DbgOut("Connected to %s:%d\n", RemoteServer, RemoteServerPort);
- if (RemoteServer != NULL) {
- free(RemoteServer);
- }
- //
- // Replace the main socket with the newly accepted connection.
- //
- DbgrSocketClose(Socket);
- Socket = RemoteServerSocket;
- Context->Client.Socket = Socket;
- } else {
- DbgOut("Connecting to %s:%d...\n", RemoteHost, Port);
- Result = DbgrSocketConnect(Socket, RemoteHost, Port);
- if (Result != 0) {
- DbgOut("Failed to connect to %s.\n", RemoteHost);
- goto ClientMainLoopEnd;
- }
- }
- Result = DbgrpClientSendInformation(Context, Socket);
- if (Result != 0) {
- DbgOut("Failed to send client information.\n");
- goto ClientMainLoopEnd;
- }
- UiSetCommandText("");
- Result = DbgrOsCreateThread(DbgrpClientNetworkThread, Context);
- if (Result != 0) {
- DbgOut("Failed to create client network thread.\n");
- Context->Client.Socket = -1;
- goto ClientMainLoopEnd;
- }
- //
- // Don't echo commands, as the server does that.
- //
- Context->Flags &= ~DEBUGGER_FLAG_ECHO_COMMANDS;
- //
- // Loop breaking in and waiting for the target.
- //
- while ((Context->Flags & DEBUGGER_FLAG_EXITING) == 0) {
- //
- // Process a command from the user.
- //
- Result = DbgrGetCommand(Context);
- if (Result == FALSE) {
- Result = EINVAL;
- goto ClientMainLoopEnd;
- }
- if (Context->CommandBuffer[0] == '\0') {
- continue;
- }
- //
- // Determine if this command should be acted on locally.
- //
- CommandIndex = 0;
- Match = 1;
- while (DbgrLocalOnlyCommands[CommandIndex] != NULL) {
- Length = strlen(DbgrLocalOnlyCommands[CommandIndex]);
- Match = strncasecmp(Context->CommandBuffer,
- DbgrLocalOnlyCommands[CommandIndex],
- Length);
- if ((Match == 0) &&
- ((isspace(Context->CommandBuffer[Length]) != 0) ||
- (Context->CommandBuffer[Length] == '\0'))) {
- Result = DbgrpSplitCommandArguments(Context->CommandBuffer,
- CommandArguments,
- &CommandArgumentCount);
- if (Result == FALSE) {
- Result = EINVAL;
- goto ClientMainLoopEnd;
- }
- CommandEntry = DbgrLookupCommand(CommandArguments[0]);
- assert(CommandEntry != NULL);
- DbgOut("\n");
- CommandEntry->CommandRoutine(Context,
- CommandArguments,
- CommandArgumentCount);
- DbgOut("%s", Context->StandardOut.Prompt);
- break;
- }
- CommandIndex += 1;
- }
- if (Match == 0) {
- continue;
- }
- //
- // Send the command to the remote server.
- //
- Length = strlen(Context->CommandBuffer);
- Command = malloc(Length + sizeof(DEBUG_REMOTE_HEADER));
- if (Command == NULL) {
- DbgOut("Allocation failure.\n");
- continue;
- }
- Command->Command = DebugRemoteInput;
- Command->Length = Length;
- memcpy(Command + 1, Context->CommandBuffer, Length);
- Result = DbgrpRemoteSendCommand(Socket, Command);
- if (Result != 0) {
- DbgOut("Failed to send command.\n");
- break;
- }
- }
- //
- // Wait for the client thread to stop.
- //
- if (Context->Client.Socket != -1) {
- DbgrSocketShutdown(Socket);
- while (Context->Client.ShutDown == 0) {
- CommStall(10);
- }
- }
- ClientMainLoopEnd:
- if (Socket != -1) {
- DbgrSocketClose(Socket);
- Context->Client.Socket = -1;
- }
- if (RemoteHost != NULL) {
- free(RemoteHost);
- }
- DbgrSocketDestroyLibrary();
- return Result;
- }
- INT
- DbgrpClientRequestBreakIn (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine sends a break request across to the debug server.
- Arguments:
- Context - Supplies a pointer to the debugger context.
- Return Value:
- 0 on success.
- Non-zero on error.
- --*/
- {
- DEBUG_REMOTE_HEADER Header;
- INT Result;
- Header.Command = DebugRemoteBreakRequest;
- Header.Length = 0;
- Result = DbgrpRemoteSendCommand(Context->Client.Socket, &Header);
- return Result;
- }
- VOID
- DbgrpServerNotifyClients (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine notifies all debug clients connected to the given server that
- there is new activity to send off to the clients. This routine assumes the
- standard output lock is already held.
- Arguments:
- Context - Supplies a pointer to the debugger context.
- Return Value:
- None.
- --*/
- {
- PDEBUGGER_SERVER_CLIENT Client;
- PLIST_ENTRY CurrentEntry;
- char OutputCharacter;
- //
- // Note that if the server is ever changed to synchronize on something
- // other than the standard output lock, then it would need to be acquired
- // here. All callers of this function are holding the standard output lock.
- //
- OutputCharacter = 'o';
- CurrentEntry = Context->Server.ClientList.Next;
- while (CurrentEntry != &(Context->Server.ClientList)) {
- Client = LIST_VALUE(CurrentEntry, DEBUGGER_SERVER_CLIENT, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- assert(Client->Context == Context);
- //
- // Wake up the client by writing to its pipe.
- //
- if ((Client->Pipe[1] != -1) && (Client->Update == 0)) {
- Client->Update = 1;
- write(Client->Pipe[1], &OutputCharacter, 1);
- }
- }
- return;
- }
- VOID
- DbgrpServerDestroy (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine tears down the debug server and all its connections.
- Arguments:
- Context - Supplies a pointer to the debugger context.
- Return Value:
- None.
- --*/
- {
- PDEBUGGER_SERVER_CLIENT Client;
- PLIST_ENTRY CurrentEntry;
- DbgrpServerAcquireLock(Context);
- if (Context->Server.Socket != -1) {
- Context->Server.ShutDown = 1;
- DbgrSocketClose(Context->Server.Socket);
- Context->Server.Socket = -1;
- }
- if (Context->Client.Socket != -1) {
- DbgrSocketShutdown(Context->Client.Socket);
- }
- if (Context->Server.Host != NULL) {
- free(Context->Server.Host);
- Context->Server.Host = NULL;
- }
- Context->Server.Port = 0;
- CurrentEntry = Context->Server.ClientList.Next;
- while (CurrentEntry != &(Context->Server.ClientList)) {
- Client = LIST_VALUE(CurrentEntry, DEBUGGER_SERVER_CLIENT, ListEntry);
- if (Client->Socket != -1) {
- DbgrSocketShutdown(Client->Socket);
- }
- //
- // Close the write end of the pipe to unblock the connection thread
- // trying to read it.
- //
- if (Client->Pipe[1] != -1) {
- close(Client->Pipe[1]);
- Client->Pipe[1] = -1;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- DbgrpServerReleaseLock(Context);
- while ((LIST_EMPTY(&(Context->Server.ClientList)) == FALSE) ||
- (Context->Server.ShutDown != 0)) {
- CommStall(10);
- DbgrpServerAcquireLock(Context);
- DbgrpServerReleaseLock(Context);
- }
- //
- // Acquire and release the lock one more time as a barrier.
- //
- DbgrpServerAcquireLock(Context);
- DbgrpServerReleaseLock(Context);
- DbgrSocketDestroyLibrary();
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- DbgrpServerThread (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine is the entry point for the debug server thread that simply
- accepts new connections and spawns worker threads to handle them.
- Arguments:
- Parameter - Supplies a pointer supplied by the creator of the thread. In
- this case, the debugger application context.
- Return Value:
- None.
- --*/
- {
- char *ClientHost;
- int ClientPort;
- int ClientSocket;
- PDEBUGGER_CONTEXT Context;
- int Result;
- int Socket;
- Context = Parameter;
- //
- // Mark that the server thread has fired up.
- //
- Context->Server.ShutDown = 0;
- //
- // Loop accepting connections.
- //
- while (TRUE) {
- Socket = Context->Server.Socket;
- if (Context->Server.ShutDown != 0) {
- break;
- }
- ClientHost = NULL;
- ClientSocket = DbgrSocketAccept(Socket, &ClientHost, &ClientPort);
- if (ClientSocket < 0) {
- continue;
- }
- Result = DbgrpServerCreateClient(Context,
- ClientSocket,
- ClientHost,
- ClientPort);
- if (Result != 0) {
- DbgrSocketClose(ClientSocket);
- if (ClientHost != NULL) {
- free(ClientHost);
- }
- }
- }
- //
- // Mark that the server thread is done.
- //
- Context->Server.ShutDown = 0;
- return;
- }
- VOID
- DbgrpServerConnectionThread (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine is the entry point for the thread that manages an individual
- connection with a client for the debug server.
- Arguments:
- Parameter - Supplies a pointer supplied by the creator of the thread. In
- this case, a pointer to the debugger server client connection.
- Return Value:
- None.
- --*/
- {
- PDEBUGGER_SERVER_CLIENT Client;
- PDEBUG_REMOTE_CLIENT_INFORMATION ClientInformation;
- PDEBUGGER_CONTEXT Context;
- PDEBUG_REMOTE_HEADER Header;
- BOOL LockHeld;
- void *Output;
- ULONGLONG OutputIndex;
- char PipeCharacter;
- PSTR Prompt;
- int Result;
- DEBUG_REMOTE_SERVER_INFORMATION ServerInformation;
- int Size;
- BOOL SourceAvailable;
- PSTR SourceFile;
- ULONG SourceFileLength;
- PDEBUG_REMOTE_SOURCE_INFORMATION SourceInformation;
- ULONGLONG SourceLine;
- Client = Parameter;
- Context = Client->Context;
- LockHeld = FALSE;
- Output = NULL;
- OutputIndex = 0;
- Prompt = NULL;
- SourceFile = NULL;
- SourceInformation = NULL;
- memset(&ServerInformation, 0, sizeof(DEBUG_REMOTE_SERVER_INFORMATION));
- ServerInformation.Header.Command = DebugRemoteServerInformation;
- ServerInformation.Header.Length =
- sizeof(DEBUG_REMOTE_SERVER_INFORMATION) -
- FIELD_OFFSET(DEBUG_REMOTE_SERVER_INFORMATION, ProtocolVersion);
- ServerInformation.ProtocolVersion = DEBUG_REMOTE_PROTOCOL_VERSION;
- Result = DbgrpRemoteSendCommand(Client->Socket,
- &(ServerInformation.Header));
- if (Result != 0) {
- DbgOut("Failed to send server information to client.\n");
- goto ServerConnectionThreadEnd;
- }
- Result = DbgrpRemoteReceiveCommand(
- Client->Socket,
- (PDEBUG_REMOTE_HEADER *)&ClientInformation);
- if (Result != 0) {
- DbgOut("Failed to receive client information.\n");
- goto ServerConnectionThreadEnd;
- }
- if (ClientInformation->Header.Command != DebugRemoteClientInformation) {
- DbgOut("Received something other than remote client information.\n");
- free(ClientInformation);
- goto ServerConnectionThreadEnd;
- }
- ClientInformation->User[DEBUG_REMOTE_USER_SIZE - 1] = '\0';
- ClientInformation->Host[DEBUG_REMOTE_HOST_SIZE - 1] = '\0';
- Client->HostName = strdup(ClientInformation->Host);
- Client->UserName = strdup(ClientInformation->User);
- free(ClientInformation);
- DbgOut("\nUser %s on %s connected at %s:%d.\n",
- Client->UserName,
- Client->HostName,
- Client->Host,
- Client->Port);
- //
- // Make sure the user name is something readable. Replace the user name
- // with the host name or the host address if it started empty.
- //
- if ((Client->UserName == NULL) || (strlen(Client->UserName) == 0)) {
- if (Client->UserName != NULL) {
- free(Client->UserName);
- Client->UserName = NULL;
- }
- if ((Client->HostName != NULL) && (strlen(Client->HostName) != 0)) {
- Client->UserName = strdup(Client->HostName);
- } else {
- Client->UserName = strdup(Client->Host);
- }
- }
- //
- // Start the receive thread.
- //
- assert(Client->ReceiveState == DebuggerServerReceiveNotStarted);
- Client->ReceiveState = DebuggerServerReceiveRunning;
- Result = DbgrOsCreateThread(DbgrpServerConnectionReceiveThread, Client);
- if (Result != 0) {
- Client->ReceiveState = DebuggerServerReceiveNotStarted;
- goto ServerConnectionThreadEnd;
- }
- while (TRUE) {
- //
- // Clear the update flag before going through and doing the update.
- //
- Client->Update = 0;
- //
- // Loop writing output to the client.
- //
- Result = 0;
- while (OutputIndex != Context->StandardOut.ConsoleBufferSize) {
- DbgrpServerAcquireLock(Context);
- LockHeld = TRUE;
- //
- // The check in the while loop was not synchronized, so take a look
- // again now that the lock is held.
- //
- if (OutputIndex == Context->StandardOut.ConsoleBufferSize) {
- break;
- }
- //
- // Allocate and initialize buffer containing the output that has
- // not yet been sent.
- //
- Size = Context->StandardOut.ConsoleBufferSize - OutputIndex;
- assert(Size ==
- Context->StandardOut.ConsoleBufferSize - OutputIndex);
- Output = malloc(Size + sizeof(DEBUG_REMOTE_HEADER));
- if (Output == NULL) {
- break;
- }
- memcpy(Output + sizeof(DEBUG_REMOTE_HEADER),
- Context->StandardOut.ConsoleBuffer + OutputIndex,
- Size);
- Header = Output;
- Header->Command = DebugRemoteOutput;
- Header->Length = Size;
- //
- // Drop the lock so the UI thread can continue, and then work on
- // sending the data.
- //
- DbgrpServerReleaseLock(Context);
- LockHeld = FALSE;
- Result = DbgrpRemoteSendCommand(Client->Socket, Header);
- if (Result != 0) {
- break;
- }
- OutputIndex += Size;
- }
- if (LockHeld != FALSE) {
- DbgrpServerReleaseLock(Context);
- LockHeld = FALSE;
- }
- if (Output != NULL) {
- free(Output);
- Output = NULL;
- }
- if (Result != 0) {
- break;
- }
- //
- // Check to see if the prompt has changed, and send the updated prompt
- // if so. Grab the source information while the lock is held.
- //
- assert((Prompt == NULL) && (SourceFile == NULL));
- SourceAvailable = FALSE;
- DbgrpServerAcquireLock(Context);
- if (Context->StandardOut.Prompt != NULL) {
- Prompt = strdup(Context->StandardOut.Prompt);
- }
- if (Context->SourceFile.Path != NULL) {
- SourceFile = strdup(Context->SourceFile.Path);
- }
- SourceLine = Context->SourceFile.LineNumber;
- if (Context->SourceFile.Contents != NULL) {
- SourceAvailable = TRUE;
- }
- DbgrpServerReleaseLock(Context);
- if (((Prompt == NULL) && (Client->Prompt != NULL)) ||
- ((Prompt != NULL) && (Client->Prompt == NULL)) ||
- ((Prompt != NULL) && (strcmp(Prompt, Client->Prompt) != 0))) {
- if (Client->Prompt != NULL) {
- free(Client->Prompt);
- }
- Client->Prompt = Prompt;
- Prompt = NULL;
- Size = 0;
- if (Client->Prompt != NULL) {
- Size = strlen(Client->Prompt);
- }
- Output = malloc(Size + sizeof(DEBUG_REMOTE_HEADER));
- if (Output == NULL) {
- break;
- }
- if (Size != 0) {
- memcpy(Output + sizeof(DEBUG_REMOTE_HEADER),
- Client->Prompt,
- Size);
- }
- Header = Output;
- Header->Command = DebugRemotePrompt;
- Header->Length = Size;
- Result = DbgrpRemoteSendCommand(Client->Socket, Header);
- if (Result != 0) {
- break;
- }
- }
- if (Prompt != NULL) {
- free(Prompt);
- Prompt = NULL;
- }
- if (Output != NULL) {
- free(Output);
- Output = NULL;
- }
- //
- // Send the updated source file and line if different.
- //
- if (((Client->SourceFile == NULL) && (SourceFile != NULL)) ||
- ((Client->SourceFile != NULL) && (SourceFile == NULL)) ||
- (Client->SourceLine != SourceLine) ||
- ((SourceFile != NULL) &&
- (strcmp(Client->SourceFile, SourceFile) != 0))) {
- if (Client->SourceFile != NULL) {
- free(Client->SourceFile);
- Client->SourceFile = NULL;
- }
- SourceFileLength = 0;
- if (SourceFile != NULL) {
- SourceFileLength = strlen(SourceFile);
- }
- SourceInformation = malloc(
- sizeof(DEBUG_REMOTE_SOURCE_INFORMATION) + SourceFileLength);
- if (SourceInformation != NULL) {
- SourceInformation->Header.Command =
- DebugRemoteSourceInformation;
- SourceInformation->Header.Length =
- SourceFileLength +
- (sizeof(DEBUG_REMOTE_SOURCE_INFORMATION) -
- FIELD_OFFSET(DEBUG_REMOTE_SOURCE_INFORMATION, LineNumber));
- if (SourceFileLength != 0) {
- memcpy(SourceInformation + 1,
- SourceFile,
- SourceFileLength);
- }
- SourceInformation->LineNumber = SourceLine;
- SourceInformation->SourceAvailable = SourceAvailable;
- Result = DbgrpRemoteSendCommand(Client->Socket,
- &(SourceInformation->Header));
- if (Result != 0) {
- break;
- }
- }
- Client->SourceFile = SourceFile;
- SourceFile = NULL;
- Client->SourceLine = SourceLine;
- }
- if (SourceFile != NULL) {
- free(SourceFile);
- SourceFile = NULL;
- }
- if (SourceInformation != NULL) {
- free(SourceInformation);
- SourceInformation = NULL;
- }
- //
- // If there's still another update to do, go back and do it.
- //
- if (Client->Update != 0) {
- continue;
- }
- //
- // Block on the pipe, which will be written to when there's something
- // to do.
- //
- Result = read(Client->Pipe[0], &PipeCharacter, 1);
- if (Result <= 0) {
- if (errno == EINTR) {
- continue;
- }
- break;
- }
- }
- ServerConnectionThreadEnd:
- assert(LockHeld == FALSE);
- if (Output != NULL) {
- free(Output);
- }
- if (Prompt != NULL) {
- free(Prompt);
- }
- if (SourceFile != NULL) {
- free(SourceFile);
- }
- if (SourceInformation != NULL) {
- free(SourceInformation);
- }
- //
- // Stop the receive thread if needed.
- //
- if (Client->ReceiveState == DebuggerServerReceiveRunning) {
- Client->ReceiveState = DebuggerServerReceiveShutDownRequested;
- DbgrSocketShutdown(Client->Socket);
- while (Client->ReceiveState != DebuggerServerReceiveShutDown) {
- CommStall(10);
- }
- }
- DbgOut("\nDisconnected from %s:%d.\n", Client->Host, Client->Port);
- DbgrpServerAcquireLock(Context);
- DbgrpServerDestroyClient(Client);
- DbgrpServerReleaseLock(Context);
- return;
- }
- VOID
- DbgrpServerConnectionReceiveThread (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine is the entry point for the thread that receives requests and
- input from a remote client.
- Arguments:
- Parameter - Supplies a pointer supplied by the creator of the thread. In
- this case, a pointer to the debugger context.
- Return Value:
- None.
- --*/
- {
- PDEBUGGER_SERVER_CLIENT Client;
- PDEBUGGER_CONTEXT Context;
- PDEBUG_REMOTE_HEADER Header;
- PDEBUGGER_REMOTE_COMMAND RemoteCommand;
- INT Result;
- INT Retries;
- PDEBUG_REMOTE_SOURCE_DATA SourceData;
- Client = Parameter;
- Context = Client->Context;
- Header = NULL;
- Retries = 10;
- while (Client->ReceiveState == DebuggerServerReceiveRunning) {
- Result = DbgrpRemoteReceiveCommand(Client->Socket, &Header);
- if (Result != 0) {
- Retries -= 1;
- if (Retries == 0) {
- break;
- }
- continue;
- }
- Retries = 10;
- switch (Header->Command) {
- //
- // Add a remote input command.
- //
- case DebugRemoteInput:
- RemoteCommand = malloc(sizeof(DEBUGGER_REMOTE_COMMAND));
- if (RemoteCommand == NULL) {
- break;
- }
- memset(RemoteCommand, 0, sizeof(DEBUGGER_REMOTE_COMMAND));
- RemoteCommand->Command = malloc(Header->Length + 1);
- if (RemoteCommand->Command == NULL) {
- free(RemoteCommand);
- break;
- }
- memcpy(RemoteCommand->Command, Header + 1, Header->Length);
- RemoteCommand->Command[Header->Length] = '\0';
- if (Client->UserName != NULL) {
- RemoteCommand->User = strdup(Client->UserName);
- }
- if (Client->HostName != NULL) {
- RemoteCommand->Host = strdup(Client->HostName);
- }
- AcquireDebuggerLock(Context->StandardIn.Lock);
- INSERT_BEFORE(&(RemoteCommand->ListEntry),
- &(Context->StandardIn.RemoteCommandList));
- ReleaseDebuggerLock(Context->StandardIn.Lock);
- DbgrOsRemoteInputAdded();
- break;
- case DebugRemoteBreakRequest:
- DbgOut("Requesting break in...\t\t[%s@%s]\n",
- Client->UserName,
- Client->HostName);
- DbgRequestBreakIn(Context);
- break;
- case DebugRemoteSourceDataRequest:
- //
- // Send the current source data. The source file is protected by
- // the standard out lock, which is the same physically but not
- // conceptually as the server lock.
- //
- AcquireDebuggerLock(Context->StandardOut.Lock);
- SourceData = malloc(sizeof(DEBUG_REMOTE_SOURCE_DATA) +
- Context->SourceFile.Size);
- if (SourceData != NULL) {
- SourceData->Header.Command = DebugRemoteSourceData;
- SourceData->Header.Length =
- sizeof(DEBUG_REMOTE_SOURCE_DATA) -
- (FIELD_OFFSET(DEBUG_REMOTE_SOURCE_DATA, FileNameCrc32)) +
- Context->SourceFile.Size;
- SourceData->FileNameCrc32 = 0;
- if (Context->SourceFile.Path != NULL) {
- SourceData->FileNameCrc32 = RtlComputeCrc32(
- 0,
- Context->SourceFile.Path,
- RtlStringLength(Context->SourceFile.Path));
- }
- memcpy(SourceData + 1,
- Context->SourceFile.Contents,
- Context->SourceFile.Size);
- }
- ReleaseDebuggerLock(Context->StandardOut.Lock);
- if (SourceData != NULL) {
- DbgrpRemoteSendCommand(Client->Socket, &(SourceData->Header));
- free(SourceData);
- }
- break;
- default:
- DbgOut("Unknown remote command 0x%x received.\n", Header->Command);
- break;
- }
- }
- Client->ReceiveState = DebuggerServerReceiveShutDown;
- return;
- }
- VOID
- DbgrpClientNetworkThread (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine is the entry point for the thread that manages network traffic
- from a remote client.
- Arguments:
- Parameter - Supplies a pointer supplied by the creator of the thread. In
- this case, a pointer to the debugger context.
- Return Value:
- None.
- --*/
- {
- PDEBUGGER_CONTEXT Context;
- ULONG CurrentNameLength;
- PDEBUG_REMOTE_HEADER Header;
- ULONG NameCrc32;
- PSTR Output;
- INT Result;
- PDEBUG_REMOTE_SOURCE_DATA SourceData;
- PSTR SourceFile;
- PSTR SourceFileBuffer;
- ULONGLONG SourceFileLength;
- PDEBUG_REMOTE_SOURCE_INFORMATION SourceInformation;
- ULONGLONG SourceLine;
- Context = Parameter;
- Context->Client.ShutDown = 0;
- while (TRUE) {
- Result = DbgrpRemoteReceiveCommand(Context->Client.Socket, &Header);
- if (Result != 0) {
- break;
- }
- assert(Header != NULL);
- switch (Header->Command) {
- case DebugRemoteOutput:
- case DebugRemotePrompt:
- if ((Header->Command == DebugRemotePrompt) &&
- (Header->Length == 0)) {
- DbgrpSetPromptText(Context, NULL);
- UiEnableCommands(FALSE);
- break;
- }
- Output = malloc(Header->Length + 1);
- if (Output != NULL) {
- memcpy(Output, Header + 1, Header->Length);
- Output[Header->Length] = '\0';
- if (Header->Command == DebugRemoteOutput) {
- DbgOut("%s", Output);
- } else {
- assert(Header->Command == DebugRemotePrompt);
- DbgrpSetPromptText(Context, Output);
- UiEnableCommands(TRUE);
- }
- free(Output);
- }
- break;
- case DebugRemoteSourceInformation:
- //
- // The source file name comes after the structure, so the source
- // file size is the whole payload minus the fields in the source
- // information (the header doesn't count in the length).
- //
- SourceInformation = (PDEBUG_REMOTE_SOURCE_INFORMATION)Header;
- //
- // Skip bogus lengths.
- //
- if (Header->Length <
- (sizeof(DEBUG_REMOTE_SOURCE_INFORMATION) -
- FIELD_OFFSET(DEBUG_REMOTE_SOURCE_INFORMATION, LineNumber))) {
- break;
- }
- SourceFileLength =
- Header->Length -
- (sizeof(DEBUG_REMOTE_SOURCE_INFORMATION) -
- FIELD_OFFSET(DEBUG_REMOTE_SOURCE_INFORMATION, LineNumber));
- SourceFileBuffer = (PSTR)(SourceInformation + 1);
- SourceFile = NULL;
- if (SourceFileLength != 0) {
- SourceFile = malloc(SourceFileLength + 1);
- if (SourceFile != NULL) {
- memcpy(SourceFile, SourceFileBuffer, SourceFileLength);
- SourceFile[SourceFileLength] = '\0';
- }
- }
- SourceLine = SourceInformation->LineNumber;
- //
- // The standard out lock protects the source file (which is the
- // same physically but not conceptually as the debug server lock).
- //
- AcquireDebuggerLock(Context->StandardOut.Lock);
- //
- // If the line number is zero, just unhighlight the line.
- //
- if (SourceInformation->LineNumber == 0) {
- DbgrpHighlightExecutingLine(Context, 0);
- } else {
- assert(SourceFile != NULL);
- //
- // If the file is the same, just move the line number.
- //
- if ((Context->SourceFile.Path != NULL) &&
- (strcmp(Context->SourceFile.Path, SourceFile) == 0)) {
- DbgrpHighlightExecutingLine(Context, SourceLine);
- //
- // The file needs to be loaded.
- //
- } else {
- if (Context->SourceFile.Path != NULL) {
- free(Context->SourceFile.Path);
- Context->SourceFile.Path = NULL;
- }
- if (Context->SourceFile.ActualPath != NULL) {
- free(Context->SourceFile.ActualPath);
- Context->SourceFile.ActualPath = NULL;
- }
- if (Context->SourceFile.Contents != NULL) {
- free(Context->SourceFile.Contents);
- Context->SourceFile.Contents = NULL;
- }
- Context->SourceFile.LineNumber = 0;
- Context->SourceFile.Path = SourceFile;
- //
- // First try to load the source locally.
- //
- Result = DbgrpLoadSourceFile(
- Context,
- SourceFile,
- &(Context->SourceFile.ActualPath),
- &(Context->SourceFile.Contents),
- &(Context->SourceFile.Size));
- if (Result == 0) {
- Result = UiLoadSourceFile(
- Context->SourceFile.ActualPath,
- Context->SourceFile.Contents,
- Context->SourceFile.Size);
- if (Result != FALSE) {
- DbgrpHighlightExecutingLine(Context, SourceLine);
- }
- //
- // Source could not be loaded locally, try to request it
- // from the server.
- //
- } else if (SourceInformation->SourceAvailable != 0) {
- //
- // Reuse the header to request the source data.
- //
- SourceInformation = NULL;
- Header->Command = DebugRemoteSourceDataRequest;
- Header->Length = 0;
- Result = DbgrpRemoteSendCommand(Context->Client.Socket,
- Header);
- //
- // If sending the request failed, blank out the screen.
- //
- if (Result != 0) {
- UiLoadSourceFile(SourceFile, NULL, 0);
- }
- //
- // Save the source line in the context for now.
- //
- Context->SourceFile.LineNumber = SourceLine;
- }
- SourceFile = NULL;
- }
- }
- ReleaseDebuggerLock(Context->StandardOut.Lock);
- if (SourceFile != NULL) {
- free(SourceFile);
- }
- break;
- case DebugRemoteSourceData:
- //
- // A response to a previous request to source data has come in.
- // Load the file finally.
- //
- SourceData = (PDEBUG_REMOTE_SOURCE_DATA)Header;
- //
- // Skip bogus lengths.
- //
- if (Header->Length <
- (sizeof(DEBUG_REMOTE_SOURCE_DATA) -
- FIELD_OFFSET(DEBUG_REMOTE_SOURCE_DATA, FileNameCrc32))) {
- break;
- }
- SourceFileLength =
- Header->Length -
- (sizeof(DEBUG_REMOTE_SOURCE_DATA) -
- FIELD_OFFSET(DEBUG_REMOTE_SOURCE_DATA, FileNameCrc32));
- SourceFileBuffer = (PSTR)(SourceData + 1);
- SourceFile = NULL;
- if (SourceFileLength != 0) {
- SourceFile = malloc(SourceFileLength + 1);
- if (SourceFile != NULL) {
- memcpy(SourceFile, SourceFileBuffer, SourceFileLength);
- SourceFile[SourceFileLength] = '\0';
- }
- }
- //
- // The standard out lock protects the source file (which is the
- // same physically but not conceptually as the debug server lock).
- //
- AcquireDebuggerLock(Context->StandardOut.Lock);
- if (Context->SourceFile.Path != NULL) {
- CurrentNameLength = RtlStringLength(Context->SourceFile.Path);
- NameCrc32 = RtlComputeCrc32(0,
- Context->SourceFile.Path,
- CurrentNameLength);
- //
- // If this data refers the same file as the client was
- // expecting, load it.
- //
- if (NameCrc32 == SourceData->FileNameCrc32) {
- assert(Context->SourceFile.Contents == NULL);
- Context->SourceFile.Contents = SourceFile;
- Context->SourceFile.Size = SourceFileLength;
- SourceFile = NULL;
- Result = UiLoadSourceFile(Context->SourceFile.Path,
- Context->SourceFile.Contents,
- Context->SourceFile.Size);
- if (Result != FALSE) {
- SourceLine = Context->SourceFile.LineNumber;
- Context->SourceFile.LineNumber = 0;
- DbgrpHighlightExecutingLine(Context, SourceLine);
- }
- }
- }
- ReleaseDebuggerLock(Context->StandardOut.Lock);
- if (SourceFile != NULL) {
- free(SourceFile);
- }
- break;
- default:
- DbgOut("Received unknown remote server command %d.\n",
- Header->Command);
- break;
- }
- free(Header);
- }
- DbgrSocketClose(Context->Client.Socket);
- Context->Client.ShutDown = 1;
- return;
- }
- INT
- DbgrpClientSendInformation (
- PDEBUGGER_CONTEXT Context,
- INT Socket
- )
- /*++
- Routine Description:
- This routine sends sends client information to the remote server, and
- collects the server information.
- Arguments:
- Context - Supplies the application context.
- Socket - Supplies the connected socket.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PSTR Host;
- DEBUG_REMOTE_CLIENT_INFORMATION Information;
- INT Result;
- PDEBUG_REMOTE_SERVER_INFORMATION ServerInformation;
- PSTR User;
- memset(&Information, 0, sizeof(DEBUG_REMOTE_CLIENT_INFORMATION));
- Information.Header.Command = DebugRemoteClientInformation;
- Information.Header.Length = sizeof(DEBUG_REMOTE_CLIENT_INFORMATION) -
- FIELD_OFFSET(DEBUG_REMOTE_CLIENT_INFORMATION,
- ProtocolVersion);
- Information.ProtocolVersion = DEBUG_REMOTE_PROTOCOL_VERSION;
- User = DbgrOsGetUserName();
- if (User != NULL) {
- strncpy(Information.User, User, sizeof(Information.User));
- Information.User[DEBUG_REMOTE_USER_SIZE - 1] = '\0';
- }
- Host = DbgrOsGetHostName();
- if (Host != NULL) {
- strncpy(Information.Host, Host, sizeof(Information.Host));
- Information.Host[DEBUG_REMOTE_HOST_SIZE - 1] = '\0';
- free(Host);
- }
- Result = DbgrpRemoteSendCommand(Socket, &(Information.Header));
- if (Result != 0) {
- DbgOut("Failed to send client information.\n");
- return Result;
- }
- Result = DbgrpRemoteReceiveCommand(
- Socket,
- (PDEBUG_REMOTE_HEADER *)&ServerInformation);
- if (Result != 0) {
- return Result;
- }
- if (ServerInformation->Header.Command != DebugRemoteServerInformation) {
- DbgOut("Got something other than server information.\n");
- free(ServerInformation);
- return EINVAL;
- }
- DbgOut("Connected to server version %d.%d\n",
- DEBUG_REMOTE_PROTOCOL_MAJOR(ServerInformation->ProtocolVersion),
- DEBUG_REMOTE_PROTOCOL_MINOR(ServerInformation->ProtocolVersion));
- if (DEBUG_REMOTE_PROTOCOL_MAJOR(ServerInformation->ProtocolVersion) >
- DEBUG_REMOTE_PROTOCOL_MAJOR(DEBUG_REMOTE_PROTOCOL_VERSION)) {
- DbgOut("This debug client must be upgraded from it's current version "
- "(%d.%d) to connect to the server, which runs remote protocol "
- "version %d.%d.\n",
- DEBUG_REMOTE_PROTOCOL_MAJOR(DEBUG_REMOTE_PROTOCOL_VERSION),
- DEBUG_REMOTE_PROTOCOL_MINOR(DEBUG_REMOTE_PROTOCOL_VERSION),
- DEBUG_REMOTE_PROTOCOL_MAJOR(ServerInformation->ProtocolVersion),
- DEBUG_REMOTE_PROTOCOL_MINOR(ServerInformation->ProtocolVersion));
- free(ServerInformation);
- return EINVAL;
- }
- free(ServerInformation);
- return 0;
- }
- INT
- DbgrpRemoteSendCommand (
- int Socket,
- PDEBUG_REMOTE_HEADER Header
- )
- /*++
- Routine Description:
- This routine sends a command to the remote client or server.
- Arguments:
- Socket - Supplies the socket to send the data on.
- Header - Supplies a pointer to the command to send. The data should be
- immediately after the command. The command type, length, and payload
- should already be filled in. The remainder of the header is filled in
- by this routine.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- INT Result;
- Header->Magic = DEBUG_REMOTE_HEADER_MAGIC;
- Header->DataCrc32 = RtlComputeCrc32(0, Header + 1, Header->Length);
- Header->HeaderCrc32 = 0;
- Header->HeaderCrc32 = RtlComputeCrc32(0,
- Header,
- sizeof(DEBUG_REMOTE_HEADER));
- Result = DbgrpRemoteSendData(Socket,
- Header,
- Header->Length + sizeof(DEBUG_REMOTE_HEADER));
- return Result;
- }
- INT
- DbgrpRemoteReceiveCommand (
- int Socket,
- PDEBUG_REMOTE_HEADER *Header
- )
- /*++
- Routine Description:
- This routine receives a command from the remote client or server.
- Arguments:
- Socket - Supplies the socket to receive the data from.
- Header - Supplies a pointer where a pointer to the command will be returned
- on success. The caller is responsible for freeing this memory.
- Return Value:
- 0 on success.
- Returns an error code on failure.
- --*/
- {
- PDEBUG_REMOTE_HEADER Buffer;
- ULONG FoundCrc;
- DEBUG_REMOTE_HEADER LocalHeader;
- INT Result;
- *Header = NULL;
- Result = DbgrpRemoteReceiveData(Socket,
- &LocalHeader,
- sizeof(DEBUG_REMOTE_HEADER));
- if (Result != 0) {
- return Result;
- }
- if (LocalHeader.Magic != DEBUG_REMOTE_HEADER_MAGIC) {
- DbgOut("Received remote packet with bad magic.\n");
- return EINVAL;
- }
- FoundCrc = LocalHeader.HeaderCrc32;
- LocalHeader.HeaderCrc32 = 0;
- if (RtlComputeCrc32(0, &LocalHeader, sizeof(DEBUG_REMOTE_HEADER)) !=
- FoundCrc) {
- DbgOut("Received remote packet with bad CRC.\n");
- return EINVAL;
- }
- LocalHeader.HeaderCrc32 = 0;
- Buffer = malloc(sizeof(DEBUG_REMOTE_HEADER) + LocalHeader.Length);
- if (Buffer == NULL) {
- DbgOut("Failed to allocate 0x%I64x bytes for remote packet.\n",
- sizeof(DEBUG_REMOTE_HEADER) + LocalHeader.Length);
- return ENOMEM;
- }
- memcpy(Buffer, &LocalHeader, sizeof(DEBUG_REMOTE_HEADER));
- Result = DbgrpRemoteReceiveData(Socket, Buffer + 1, LocalHeader.Length);
- if (Result != 0) {
- DbgOut("Failed to receive 0x%I64x bytes: %s.\n",
- LocalHeader.Length,
- strerror(errno));
- free(Buffer);
- return errno;
- }
- if (RtlComputeCrc32(0, Buffer + 1, LocalHeader.Length) !=
- LocalHeader.DataCrc32) {
- free(Buffer);
- return EINVAL;
- }
- *Header = Buffer;
- return Result;
- }
- INT
- DbgrpRemoteSendData (
- int Socket,
- PVOID Data,
- ULONGLONG DataSize
- )
- /*++
- Routine Description:
- This routine sends data across a socket.
- Arguments:
- Socket - Supplies the socket to send to.
- Data - Supplies a pointer to the buffer containing the data to send.
- DataSize - Supplies the size of the data in bytes.
- Return Value:
- 0 on success.
- -1 on failure.
- --*/
- {
- ssize_t BytesSent;
- size_t BytesThisRound;
- while (DataSize != 0) {
- BytesThisRound = DataSize;
- if (BytesThisRound != DataSize) {
- BytesThisRound = 0x100000;
- }
- BytesSent = DbgrSocketSend(Socket, Data, BytesThisRound);
- if (BytesSent < 0) {
- return -1;
- }
- Data += BytesSent;
- DataSize -= BytesSent;
- }
- return 0;
- }
- INT
- DbgrpRemoteReceiveData (
- int Socket,
- PVOID Data,
- ULONGLONG DataSize
- )
- /*++
- Routine Description:
- This routine sends data across a socket.
- Arguments:
- Socket - Supplies the socket to send to.
- Data - Supplies a pointer to the buffer where the data will be returned.
- DataSize - Supplies the size of the data in bytes.
- Return Value:
- 0 on success.
- -1 on failure.
- --*/
- {
- ssize_t BytesSent;
- size_t BytesThisRound;
- while (DataSize != 0) {
- BytesThisRound = DataSize;
- if (BytesThisRound != DataSize) {
- BytesThisRound = 0x100000;
- }
- BytesSent = DbgrSocketReceive(Socket, Data, BytesThisRound);
- if (BytesSent < 0) {
- return -1;
- }
- Data += BytesSent;
- DataSize -= BytesSent;
- }
- return 0;
- }
- INT
- DbgrpServerCreateClient (
- PDEBUGGER_CONTEXT Context,
- INT ClientSocket,
- PSTR ClientHost,
- INT ClientPort
- )
- /*++
- Routine Description:
- This routine creates, initializes, and inserts a client connection.
- Arguments:
- Context - Supplies a pointer to the application context.
- ClientSocket - Supplies the socket containing the new connection with the
- client.
- ClientHost - Supplies a pointer to an allocated string containing the
- name of the remote client. This will be freed when the client
- connection is destroyed.
- ClientPort - Supplies the port of the client connection.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PDEBUGGER_SERVER_CLIENT ClientConnection;
- INT Result;
- ClientConnection = malloc(sizeof(DEBUGGER_SERVER_CLIENT));
- if (ClientConnection == NULL) {
- return ENOMEM;
- }
- memset(ClientConnection, 0, sizeof(DEBUGGER_SERVER_CLIENT));
- ClientConnection->Pipe[0] = -1;
- ClientConnection->Pipe[1] = -1;
- ClientConnection->Socket = ClientSocket;
- ClientConnection->Host = ClientHost;
- ClientConnection->Port = ClientPort;
- ClientConnection->Context = Context;
- Result = DbgrOsCreatePipe(ClientConnection->Pipe);
- if (Result != 0) {
- goto ServerCreateClientEnd;
- }
- //
- // Add this client connection officially to the list.
- //
- DbgrpServerAcquireLock(Context);
- if (Context->Server.ShutDown != 0) {
- Result = -1;
- DbgrpServerReleaseLock(Context);
- goto ServerCreateClientEnd;
- }
- INSERT_BEFORE(&(ClientConnection->ListEntry),
- &(Context->Server.ClientList));
- Result = DbgrOsCreateThread(DbgrpServerConnectionThread,
- ClientConnection);
- if (Result != 0) {
- //
- // The client can be destroyed officially, but don't free the host,
- // as the caller will do that on failure of this function.
- //
- ClientConnection->Host = NULL;
- ClientConnection->Socket = -1;
- DbgrpServerDestroyClient(ClientConnection);
- ClientConnection = NULL;
- }
- DbgrpServerReleaseLock(Context);
- ServerCreateClientEnd:
- if (Result != 0) {
- if (ClientConnection != NULL) {
- if (ClientConnection->Pipe[0] != -1) {
- close(ClientConnection->Pipe[0]);
- }
- if (ClientConnection->Pipe[1] != -1) {
- close(ClientConnection->Pipe[1]);
- }
- free(ClientConnection);
- }
- }
- return Result;
- }
- VOID
- DbgrpServerDestroyClient (
- PDEBUGGER_SERVER_CLIENT Client
- )
- /*++
- Routine Description:
- This routine destroys a debug server client connection.
- Arguments:
- Client - Supplies a pointer to the client to destroy.
- Return Value:
- None.
- --*/
- {
- if (Client->ListEntry.Next != NULL) {
- LIST_REMOVE(&(Client->ListEntry));
- }
- if (Client->Socket != -1) {
- DbgrSocketClose(Client->Socket);
- Client->Socket = -1;
- }
- if (Client->Pipe[0] != -1) {
- close(Client->Pipe[0]);
- Client->Pipe[0] = -1;
- }
- if (Client->Pipe[1] != -1) {
- close(Client->Pipe[1]);
- Client->Pipe[1] = -1;
- }
- if (Client->Host != NULL) {
- free(Client->Host);
- }
- if (Client->HostName != NULL) {
- free(Client->HostName);
- }
- if (Client->UserName != NULL) {
- free(Client->UserName);
- }
- if (Client->Prompt != NULL) {
- free(Client->Prompt);
- }
- free(Client);
- return;
- }
- VOID
- DbgrpServerAcquireLock (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine acquires the global debug server lock.
- Arguments:
- Context - Supplies a pointer to the debugger context.
- Return Value:
- None.
- --*/
- {
- AcquireDebuggerLock(Context->StandardOut.Lock);
- return;
- }
- VOID
- DbgrpServerReleaseLock (
- PDEBUGGER_CONTEXT Context
- )
- /*++
- Routine Description:
- This routine releases the global debug server lock.
- Arguments:
- Context - Supplies a pointer to the debugger context.
- Return Value:
- None.
- --*/
- {
- ReleaseDebuggerLock(Context->StandardOut.Lock);
- return;
- }
- INT
- DbgrpClientConvertRemoteAddressString (
- PSTR RemoteString,
- PSTR *HostString,
- PINT Port
- )
- /*++
- Routine Description:
- This routine converts a remote string in the form address:port into an
- address string and a port number.
- Arguments:
- RemoteString - Supplies a pointer to the remote string to convert.
- HostString - Supplies a pointer where a pointer to the host portion will be
- returned. This newly allocated string must be freed by the caller.
- Port - Supplies a pointer where the port number will be returned, or 0 if
- no port was specified.
- Return Value:
- 0 on success.
- Non-zero on failure.
- --*/
- {
- PSTR AfterScan;
- PSTR Host;
- PSTR Ip6Copy;
- PSTR LastColon;
- INT PortNumber;
- *HostString = NULL;
- *Port = 0;
- PortNumber = 0;
- Host = strdup(RemoteString);
- if (Host == NULL) {
- return ENOMEM;
- }
- LastColon = strrchr(Host, ':');
- if (LastColon == NULL) {
- *HostString = Host;
- return 0;
- }
- //
- // Look for other colons, and skip the port thing if there are some.
- //
- if (strchr(Host, ':') != LastColon) {
- //
- // If it's an IPv6 address, chop off the [] and get the port.
- //
- if ((Host[0] == '[') && (LastColon != Host) &&
- (*(LastColon - 1) == ']')) {
- PortNumber = strtoul(LastColon + 1, &AfterScan, 10);
- if (AfterScan == LastColon + 1) {
- return EINVAL;
- }
- *(LastColon - 1) = '\0';
- Ip6Copy = strdup(Host + 1);
- free(Host);
- if (Ip6Copy == NULL) {
- return ENOMEM;
- }
- Host = Ip6Copy;
- }
- //
- // There's only one colon, it's 255.255.255.255:1234.
- //
- } else {
- *LastColon = '\0';
- PortNumber = strtoul(LastColon + 1, &AfterScan, 10);
- if (AfterScan == LastColon + 1) {
- return EINVAL;
- }
- }
- *HostString = Host;
- *Port = PortNumber;
- return 0;
- }
|