Windows-Server-2003/sdktools/remote/client.c

789 lines
17 KiB
C

/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1992 - 1997 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/
/*++
Copyright 1992 - 1997 Microsoft Corporation
Module Name:
Client.c
Abstract:
The Client component of Remote. Connects to the remote
server using named pipes. It sends its stdin to
the server and output everything from server to
its stdout.
Author:
Rajivendra Nath 2-Jan-1992
Dave Hart Summer 1997 single-pipe operation
Environment:
Console App. User mode.
Revision History:
--*/
#include <precomp.h>
#include "Remote.h"
BOOL fAsyncPipe = TRUE; // need this so server has it TRUE
HANDLE*
EstablishSession(
char *server,
char *pipe
);
DWORD
WINAPI
SendServerInp(
LPVOID pvParam
);
BOOL
FilterClientInp(
char *buff,
int count
);
BOOL
Mych(
DWORD ctrlT
);
VOID
SendMyInfo(
PHANDLE Pipes
);
#define ZERO_LENGTH_READ_LIMIT 200
HANDLE MyStdInp;
HANDLE MyStdOut;
//
// ReadPipe and WritePipe are referenced by multiple
// threads so need to be volatile.
//
volatile HANDLE ReadPipe;
volatile HANDLE WritePipe;
CONSOLE_SCREEN_BUFFER_INFO csbi;
char MyEchoStr[30];
BOOL CmdSent;
DWORD LinesToSend=LINESTOSEND;
int
Client(
char* Server,
char* Pipe
)
{
HANDLE *Connection;
DWORD dwThreadID;
HANDLE hThread;
DWORD cb;
OVERLAPPED ol;
char rgchBuf[1024];
DWORD dwZeroCount = 0;
CWCDATA cwcData = {NULL};
int rc = 0;
MyStdInp=GetStdHandle(STD_INPUT_HANDLE);
MyStdOut=GetStdHandle(STD_OUTPUT_HANDLE);
fputs("**************************************\n"
"*********** REMOTE ************\n"
"*********** CLIENT ************\n"
"**************************************\n",
stdout);
if ((Connection=EstablishSession(Server,Pipe))==NULL)
return 1;
ReadPipe=Connection[0];
WritePipe=Connection[1];
SetConsoleCtrlHandler((PHANDLER_ROUTINE)Mych,TRUE);
// Start Thread For Client --> Server Flow
hThread = (HANDLE)
_beginthreadex(
NULL, // security
0, // default stack size
SendServerInp, // thread proc
NULL, // parm
0, // not suspended
&dwThreadID
);
if ( !hThread)
{
Errormsg("REMOTE /C Could Not Create Thread.");
return 1;
}
// We don't need the thread handle - it lives to the process exits
CloseHandle(hThread);
ZeroMemory(&ol, sizeof(ol));
ol.hEvent =
CreateEvent(
NULL, // security
TRUE, // auto-reset
FALSE, // initially nonsignaled
NULL // unnamed
);
while (ReadFileSynch(ReadPipe, rgchBuf, sizeof rgchBuf, &cb, 0, &ol)) {
if (cb) {
// If we are interested in colors, do special output
if ( pWantColorLines() )
{
if ( !WriteConsoleWithColor( MyStdOut,
rgchBuf,
cb,
&cwcData ) )
{
rc = 1;
break;
}
}
else
{
if ( ! WriteFile(MyStdOut, rgchBuf, cb, &cb, NULL)) {
rc = 1;
break;
}
}
dwZeroCount = 0;
} else {
if (++dwZeroCount > ZERO_LENGTH_READ_LIMIT) {
//
// If we get a bunch of zero length reads in a row,
// something's broken, don't loop forever.
// (bug #115866).
//
fputs("\nREMOTE: bailing out, server must have gone away.\n", stdout);
rc = 1;
break;
}
}
}
CloseHandle(ol.hEvent);
fputs("*** SESSION OVER ***", stdout);
fflush(stdout);
CloseClientPipes();
fputs("\n", stdout);
fflush(stdout);
return rc;
}
DWORD
WINAPI
SendServerInp(
LPVOID pvParam
)
{
DWORD dread,dwrote;
OVERLAPPED ol;
char buff[512];
UNREFERENCED_PARAMETER(pvParam);
ZeroMemory(&ol, sizeof(ol));
ol.hEvent =
CreateEvent(
NULL, // security
TRUE, // auto-reset
FALSE, // initially nonsignaled
NULL // unnamed
);
while(ReadFile(MyStdInp,buff,sizeof buff,&dread,NULL))
{
if (FilterClientInp(buff,dread))
continue;
if (!WriteFileSynch(WritePipe,buff,dread,&dwrote,0,&ol))
break;
}
CloseClientPipes();
return 0;
}
BOOL
FilterClientInp(
char *buff,
int count
)
{
if (count==0)
return(TRUE);
if (buff[0]==2) // Adhoc screening of ^B so that i386kd/mipskd
return(TRUE); // do not terminate.
if (buff[0]==COMMANDCHAR)
{
switch (buff[1])
{
case 'k':
case 'K':
case 'q':
case 'Q':
CloseClientPipes();
return(FALSE);
case 'h':
case 'H':
printf("%cM : Send Message\n",COMMANDCHAR);
printf("%cP : Show Popup on Server\n",COMMANDCHAR);
printf("%cS : Status of Server\n",COMMANDCHAR);
printf("%cQ : Quit client\n",COMMANDCHAR);
printf("%cH : This Help\n",COMMANDCHAR);
return(TRUE);
default:
return(FALSE);
}
}
return(FALSE);
}
BOOL
Mych(
DWORD ctrlT
)
{
char c[2];
DWORD tmp;
OVERLAPPED ol;
c[0]=CTRLC;
if (ctrlT==CTRL_C_EVENT)
{
ZeroMemory(&ol, sizeof(ol));
ol.hEvent =
CreateEvent(
NULL, // security
TRUE, // auto-reset
FALSE, // initially nonsignaled
NULL // unnamed
);
if (INVALID_HANDLE_VALUE != WritePipe &&
!WriteFileSynch(WritePipe,c,1,&tmp,0,&ol))
{
CloseHandle(ol.hEvent);
Errormsg("Error Sending ^c");
return(FALSE);
}
CloseHandle(ol.hEvent);
return(TRUE);
}
if ((ctrlT==CTRL_BREAK_EVENT)||
(ctrlT==CTRL_CLOSE_EVENT)||
(ctrlT==CTRL_LOGOFF_EVENT)||
(ctrlT==CTRL_SHUTDOWN_EVENT)
) {
CloseClientPipes();
}
return(FALSE);
}
VOID
CloseClientPipes(
VOID
)
{
HANDLE WriteHandle, ReadHandle;
WriteHandle = (HANDLE) InterlockedExchangePointer(
(PVOID *) &WritePipe,
INVALID_HANDLE_VALUE
);
if (INVALID_HANDLE_VALUE != WriteHandle) {
CloseHandle(WriteHandle);
ReadHandle = (HANDLE) InterlockedExchangePointer(
(PVOID *) &ReadPipe,
INVALID_HANDLE_VALUE
);
if (INVALID_HANDLE_VALUE != ReadHandle &&
WriteHandle != ReadHandle) {
CloseHandle(ReadHandle);
}
}
}
VOID
HandleConnectError(
char *server,
char *srvpipename
)
{
DWORD Err = GetLastError();
char msg[128];
Errormsg("*** Unable to Connect ***");
//
// Print a helpful message
//
switch(Err)
{
case ERROR_FILE_NOT_FOUND:
sprintf(msg,"invalid pipe name \"%s\"", srvpipename);
break;
case ERROR_BAD_NETPATH:
sprintf(msg,"\\\\%s not found", server);
break;
default:
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, Err, 0, msg, sizeof(msg), NULL);
break;
}
printf("Diagnosis: %s\n",msg);
//
// If the machine exists but the pipe doesn't do an
// automatic remote /q to list pipes available on
// that machine.
//
if (ERROR_FILE_NOT_FOUND == Err) {
printf("\nREMOTE /Q %s\n", server);
fflush(stdout);
QueryRemotePipes(server);
}
}
HANDLE*
EstablishSession(
char *server,
char *srvpipename
)
{
extern BOOL bForceTwoPipes;
static HANDLE PipeH[2];
char pipenameSrvIn[200];
char pipenameSrvOut[200];
BOOL fOldServer;
DWORD dwError;
DWORD RetryCount = 0;
//
// Since in single-pipe operation we'll be using the same
// pipe in two threads, we have to open the handles for
// overlapped operation, even though we always want
// synchronous operation.
//
sprintf(pipenameSrvIn ,SERVER_READ_PIPE ,server,srvpipename);
sprintf(pipenameSrvOut,SERVER_WRITE_PIPE,server,srvpipename);
if (bForceTwoPipes) {
dwError = ERROR_NOT_SUPPORTED;
} else {
RetrySrvBidi:
if (INVALID_HANDLE_VALUE ==
(PipeH[1] =
CreateFile(
pipenameSrvIn,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
))) {
dwError = GetLastError();
if (ERROR_PIPE_BUSY == dwError) {
fputs( "All pipe instances busy, waiting for another...\n", stdout);
WaitNamedPipe(
pipenameSrvIn,
15000
);
if (RetryCount++ < 6) {
goto RetrySrvBidi;
}
}
if (ERROR_ACCESS_DENIED != dwError &&
ERROR_NOT_SUPPORTED != dwError) {
HandleConnectError(server, srvpipename);
return NULL;
}
} else {
PipeH[0] = PipeH[1];
fAsyncPipe = TRUE;
fputs("Connected...\n\n", stdout);
SendMyInfo(PipeH);
return PipeH;
}
}
//
// Old remote servers don't allow you to open the
// server IN pipe for READ access, so go down the
// old path, notably opening OUT first so the
// server knows we'll be using both pipes. We'll
// also come down this path on Win95 because
// it doesn't allow you to open an overlapped
// pipe handle. Or if remote /c mach pipe /2 is used.
//
fOldServer = (ERROR_ACCESS_DENIED == dwError);
RetrySrvOut:
if (INVALID_HANDLE_VALUE ==
(PipeH[0] =
CreateFile(
pipenameSrvOut,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL
))) {
if (ERROR_PIPE_BUSY == GetLastError()) {
fputs( "All OUT pipe instances busy, waiting for another...\n", stdout);
WaitNamedPipe(
pipenameSrvOut,
32000 // server recycles abandoned
); // OUT pipe after two minutes
if (RetryCount++ < 6) {
goto RetrySrvOut;
}
}
HandleConnectError(server, srvpipename);
return NULL;
}
RetrySrvIn:
if (INVALID_HANDLE_VALUE ==
(PipeH[1] =
CreateFile(
pipenameSrvIn,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL
))) {
dwError = GetLastError();
if (ERROR_PIPE_BUSY == dwError) {
fputs( "All IN pipe instances busy, waiting for another...\n", stdout);
WaitNamedPipe(
pipenameSrvIn,
15000
);
if (RetryCount++ < 6) {
goto RetrySrvIn;
}
}
HandleConnectError(server, srvpipename);
return NULL;
}
fAsyncPipe = FALSE;
printf("Connected... %s\n\n",
fOldServer
? "to two-pipe remote server."
: "using two pipes."
);
SendMyInfo(PipeH);
return PipeH;
}
VOID
SendMyInfo(
PHANDLE pipeH
)
{
HANDLE rPipe=pipeH[0];
HANDLE wPipe=pipeH[1];
DWORD hostlen;
WORD BytesToSend=sizeof(SESSION_STARTUPINFO);
DWORD tmp;
OVERLAPPED ol;
SESSION_STARTUPINFO ssi;
SESSION_STARTREPLY ssr;
ol.hEvent =
CreateEvent(
NULL, // security
TRUE, // auto-reset
FALSE, // initially nonsignaled
NULL // unnamed
);
ssi.Size=BytesToSend;
ssi.Version=VERSION;
hostlen = sizeof(ssi.ClientName) / sizeof(ssi.ClientName[0]);
GetComputerName(ssi.ClientName, &hostlen);
ssi.LinesToSend=LinesToSend;
ssi.Flag=ClientToServerFlag;
{
DWORD NewCode=MAGICNUMBER;
char Name[MAX_COMPUTERNAME_LENGTH+1];
strcpy(Name,(char *)ssi.ClientName);
memcpy(&Name[11],(char *)&NewCode,sizeof(NewCode));
//
// The server needs to know if we're doing single-pipe
// operation so it can complete the connection properly.
// So if we are, change the first byte of the first
// send (the computername, which is later superceded
// by the one in the SESSION_STARTUPINFO structure)
// to an illegal computername character, question mark.
//
if (wPipe == rPipe) {
Name[0] = '?';
}
WriteFileSynch(wPipe,(char *)Name,HOSTNAMELEN-1,&tmp,0,&ol);
ReadFileSynch(rPipe ,(char *)&ssr.MagicNumber,sizeof(ssr.MagicNumber),&tmp,0,&ol);
if (ssr.MagicNumber!=MAGICNUMBER)
{
SetLastError(ERROR_INVALID_PARAMETER);
ErrorExit("Pipe connected but server not recognized.\n");
}
//Get Rest of the info-its not the old server
ReadFileSynch(
rPipe,
(char *)&ssr + sizeof(ssr.MagicNumber),
sizeof(ssr)-sizeof(ssr.MagicNumber),
&tmp,
0,
&ol
);
}
if (!WriteFileSynch(wPipe,(char *)&ssi,BytesToSend,&tmp,0,&ol))
{
Errormsg("INFO Send Error");
}
CloseHandle(ol.hEvent);
}
VOID
QueryRemotePipes(
char* pszServer
)
{
HANDLE hQPipe;
DWORD dwRead;
DWORD dwError;
char fullname[400] = {0};
char* msg;
int msgLen;
if (pszServer[0] == '\\' && pszServer[1] == '\\') {
pszServer += 2;
}
printf("Querying server \\\\%s\n", pszServer);
_snprintf(fullname, sizeof(fullname)-1, QUERY_DEBUGGERS_PIPE, pszServer);
//
// Send request and display the query result
//
hQPipe = CreateFile(fullname,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hQPipe == INVALID_HANDLE_VALUE) {
dwError = GetLastError();
if (ERROR_FILE_NOT_FOUND == dwError) {
printf("No Remote servers running on \\\\%s\n", pszServer);
} else if (ERROR_BAD_NETPATH == dwError) {
printf("\\\\%s not found on the network\n", pszServer);
} else {
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwError, 0,
fullname, sizeof(fullname), NULL);
printf("Can't query server %s: %s\n", pszServer, fullname);
}
return;
}
// Send Query Command
if(!WriteFile(hQPipe, "q", 1, &dwRead, NULL) || (dwRead != 1))
{
fputs("\nError: Can't send command\n", stdout);
goto failure;
}
// read msg dimension
if(!ReadFile(hQPipe, &msgLen, sizeof(int), &dwRead, NULL) || (dwRead != sizeof(int)))
{
fputs("\nError: Can't read message\n", stdout);
goto failure;
}
if(!msgLen)
{
printf("\nNo visible sessions on server %s", pszServer);
goto failure;
}
if(msgLen > 65535) // error
{
printf("Error querying server %s, got %d for msg length, 65535 max.\n",
pszServer,
msgLen
);
goto failure;
}
// +1 for null terminator
if((msg = (char*)malloc( (msgLen +1) *sizeof(char))) == NULL)
{
fputs("\nOut of memory\n", stdout);
goto failure;
}
if (!ReadFile(hQPipe, msg, msgLen * sizeof(char), &dwRead, NULL)) {
fputs("\nUnable to read from pipe\n", stdout);
goto failure;
}
// Make sure the string is terminated
msg[dwRead] = 0;
printf("\nVisible sessions on server %s:\n\n", pszServer);
fputs(msg, stdout);
fputs("\n",stdout);
free(msg);
failure:
CloseHandle(hQPipe);
}