You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
408 lines
9.8 KiB
408 lines
9.8 KiB
/******************************************************************************\
|
|
* This is a part of the Microsoft Source Code Samples.
|
|
* Copyright 1995 - 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 (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
SrvHShak.c
|
|
|
|
Abstract:
|
|
|
|
The server component of Remote. Handshake with
|
|
client at start of session.
|
|
|
|
|
|
Author:
|
|
|
|
Dave Hart 30 May 1997
|
|
|
|
Environment:
|
|
|
|
Console App. User mode.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#include "Remote.h"
|
|
#include "Server.h"
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
HandshakeWithRemoteClient(
|
|
PREMOTE_CLIENT pClient
|
|
)
|
|
{
|
|
pClient->ServerFlags |= SFLG_HANDSHAKING;
|
|
|
|
AddClientToHandshakingList(pClient);
|
|
|
|
//
|
|
// Read hostname from client
|
|
//
|
|
|
|
ZeroMemory(
|
|
&pClient->ReadOverlapped,
|
|
sizeof(pClient->ReadOverlapped)
|
|
);
|
|
|
|
if ( ! ReadFileEx(
|
|
pClient->PipeReadH,
|
|
pClient->Name,
|
|
HOSTNAMELEN - 1,
|
|
&pClient->ReadOverlapped,
|
|
ReadClientNameCompleted
|
|
)) {
|
|
|
|
CloseClient(pClient);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
ReadClientNameCompleted(
|
|
DWORD dwError,
|
|
DWORD cbRead,
|
|
LPOVERLAPPED lpO
|
|
)
|
|
{
|
|
PREMOTE_CLIENT pClient;
|
|
SESSION_STARTREPLY ssr;
|
|
|
|
pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, ReadOverlapped);
|
|
|
|
if (pClient->ServerFlags & SFLG_CLOSING) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (dwError) {
|
|
CloseClient(pClient);
|
|
return;
|
|
}
|
|
|
|
if ((HOSTNAMELEN - 1) != cbRead) {
|
|
printf("ReadClientNameCompleted read %d s/b %d.\n", cbRead, (HOSTNAMELEN - 1));
|
|
CloseClient(pClient);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The client name read is 15 bytes always. The last four
|
|
// should match MAGICNUMBER, which conveniently has the
|
|
// low byte zeroed to terminate the client name after 11
|
|
// characters.
|
|
//
|
|
|
|
if (MAGICNUMBER != *(DWORD UNALIGNED *)&pClient->Name[11]) {
|
|
|
|
pClient->Name[11] = 0;
|
|
CloseClient(pClient);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Now we can tell if this is a single-pipe or two-pipe
|
|
// client, because single-pipe clients replace the
|
|
// first byte of the computername with the illegal
|
|
// character '?'.
|
|
//
|
|
|
|
if ('?' == pClient->Name[0]) {
|
|
|
|
pClient->PipeWriteH = pClient->PipeReadH;
|
|
|
|
TRACE(CONNECT, ("Client %d pipe %p is single-pipe.\n", pClient->dwID, pClient->PipeWriteH));
|
|
|
|
//
|
|
// In order for things to work reliably for 2-pipe clients
|
|
// when there are multiple remote servers on the same pipename,
|
|
// we need to tear down the listening OUT pipe and recreate it so
|
|
// that the oldest listening IN pipe will be from the same process
|
|
// as the oldest listening OUT pipe.
|
|
//
|
|
|
|
if (1 == cConnectIns) {
|
|
|
|
TRACE(CONNECT, ("Recycling OUT pipe %p as well for round-robin behavior.\n",
|
|
hPipeOut));
|
|
|
|
CancelIo(hPipeOut);
|
|
DisconnectNamedPipe(hPipeOut);
|
|
CloseHandle(hPipeOut);
|
|
hPipeOut = INVALID_HANDLE_VALUE;
|
|
bOutPipeConnected = FALSE;
|
|
|
|
CreatePipeAndIssueConnect(OUT_PIPE);
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( ! bOutPipeConnected ) {
|
|
|
|
printf("Remote: %p two-pipe client connected to IN pipe but not OUT?\n", pClient);
|
|
CloseClient(pClient);
|
|
return;
|
|
}
|
|
|
|
bOutPipeConnected = FALSE;
|
|
|
|
if (INVALID_HANDLE_VALUE != hConnectOutTimer) {
|
|
CancelWaitableTimer(hConnectOutTimer);
|
|
}
|
|
|
|
pClient->PipeWriteH = hPipeOut;
|
|
hPipeOut = INVALID_HANDLE_VALUE;
|
|
|
|
TRACE(CONNECT, ("Client %d is dual-pipe IN %p OUT %p.\n", pClient->dwID, pClient->PipeReadH, pClient->PipeWriteH));
|
|
|
|
CreatePipeAndIssueConnect(OUT_PIPE);
|
|
}
|
|
|
|
TRACE(SHAKE, ("Read client name %s\n", pClient->Name));
|
|
|
|
//
|
|
// Send our little pile of goodies to the client
|
|
//
|
|
|
|
ssr.MagicNumber = MAGICNUMBER;
|
|
ssr.Size = sizeof(ssr);
|
|
ssr.FileSize = dwWriteFilePointer;
|
|
|
|
//
|
|
// Copy ssr structure to a buffer that will be around
|
|
// for the entire I/O.
|
|
//
|
|
|
|
CopyMemory(pClient->WriteBuffer, &ssr, sizeof(ssr));
|
|
|
|
if ( ! WriteFileEx(
|
|
pClient->PipeWriteH,
|
|
pClient->WriteBuffer,
|
|
sizeof(ssr),
|
|
&pClient->WriteOverlapped,
|
|
WriteServerReplyCompleted
|
|
)) {
|
|
|
|
CloseClient(pClient);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
WriteServerReplyCompleted(
|
|
DWORD dwError,
|
|
DWORD cbWritten,
|
|
LPOVERLAPPED lpO
|
|
)
|
|
{
|
|
PREMOTE_CLIENT pClient;
|
|
|
|
pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, WriteOverlapped);
|
|
|
|
if (pClient->ServerFlags & SFLG_CLOSING) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (HandleSessionError(pClient, dwError)) {
|
|
return;
|
|
}
|
|
|
|
TRACE(SHAKE, ("Wrote server reply\n"));
|
|
|
|
//
|
|
// Read the size of the SESSION_STARTUPINFO the client is
|
|
// sending us, to deal gracefully with different versions
|
|
// on client and server.
|
|
//
|
|
|
|
if ( ! ReadFileEx(
|
|
pClient->PipeReadH,
|
|
pClient->ReadBuffer,
|
|
sizeof(DWORD),
|
|
&pClient->ReadOverlapped,
|
|
ReadClientStartupInfoSizeCompleted
|
|
)) {
|
|
|
|
CloseClient(pClient);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
ReadClientStartupInfoSizeCompleted(
|
|
DWORD dwError,
|
|
DWORD cbRead,
|
|
LPOVERLAPPED lpO
|
|
)
|
|
{
|
|
PREMOTE_CLIENT pClient;
|
|
DWORD dwSize;
|
|
|
|
pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, ReadOverlapped);
|
|
|
|
if (HandleSessionError(pClient, dwError)) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (cbRead != sizeof(DWORD)) {
|
|
|
|
CloseClient(pClient);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Sanity check the size
|
|
//
|
|
|
|
dwSize = *(DWORD *)pClient->ReadBuffer;
|
|
|
|
if (dwSize > 1024) {
|
|
CloseClient(pClient);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Squirrel away the size in the write buffer,
|
|
// since during handshaking we never have both a
|
|
// read and write pending this is OK.
|
|
//
|
|
|
|
*(DWORD *)pClient->WriteBuffer = dwSize;
|
|
|
|
TRACE(SHAKE, ("Read client reply size %d\n", dwSize));
|
|
|
|
//
|
|
// Read the rest of the SESSION_STARTUPINFO into the read buffer
|
|
// after the size.
|
|
//
|
|
|
|
RtlZeroMemory(
|
|
&pClient->ReadOverlapped,
|
|
sizeof(pClient->ReadOverlapped)
|
|
);
|
|
|
|
if ( ! ReadFileEx(
|
|
pClient->PipeReadH,
|
|
pClient->ReadBuffer + sizeof(DWORD),
|
|
dwSize - sizeof(DWORD),
|
|
&pClient->ReadOverlapped,
|
|
ReadClientStartupInfoCompleted
|
|
)) {
|
|
|
|
CloseClient(pClient);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
ReadClientStartupInfoCompleted(
|
|
DWORD dwError,
|
|
DWORD cbRead,
|
|
LPOVERLAPPED lpO
|
|
)
|
|
{
|
|
PREMOTE_CLIENT pClient;
|
|
DWORD dwSize;
|
|
SESSION_STARTUPINFO ssi;
|
|
char Buf[256];
|
|
|
|
pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, ReadOverlapped);
|
|
|
|
if (HandleSessionError(pClient, dwError)) {
|
|
|
|
return;
|
|
}
|
|
|
|
dwSize = *(DWORD *)pClient->WriteBuffer;
|
|
|
|
if (cbRead != (dwSize - sizeof(ssi.Size))) {
|
|
|
|
CloseClient(pClient);
|
|
return;
|
|
}
|
|
|
|
CopyMemory(&ssi, pClient->ReadBuffer, min(dwSize, sizeof(ssi)));
|
|
|
|
CopyMemory(pClient->Name, ssi.ClientName, sizeof(pClient->Name));
|
|
pClient->Flag = ssi.Flag;
|
|
|
|
if (ssi.Version != VERSION) {
|
|
|
|
printf("Remote Warning: Server Version=%d Client Version=%d for %s\n", VERSION, ssi.Version, pClient->Name);
|
|
}
|
|
|
|
TRACE(SHAKE, ("Read client info, new name %s, %d lines\n", pClient->Name, ssi.LinesToSend));
|
|
|
|
|
|
//
|
|
// Set temp file position according to the client's
|
|
// requested lines to send. The heuristic of 45 chars
|
|
// per average line is used by the client. However since old clients
|
|
// hardcode this knowledge and sit and spin trying to read that many
|
|
// bytes before completing initialization, and because we might not send
|
|
// that many due to stripping BEGINMARK and ENDMARK characters, we
|
|
// use 50 chars per line to calculate the temp file position in hopes
|
|
// the extra bytes will overcome the missing MARK characters.
|
|
//
|
|
|
|
pClient->dwFilePos = dwWriteFilePointer > (ssi.LinesToSend * 50)
|
|
? dwWriteFilePointer - (ssi.LinesToSend * 50)
|
|
: 0;
|
|
|
|
//
|
|
// This client's ready to roll.
|
|
//
|
|
|
|
pClient->ServerFlags &= ~SFLG_HANDSHAKING;
|
|
|
|
MoveClientToNormalList(pClient);
|
|
|
|
//
|
|
// Start read operation against this client's input.
|
|
//
|
|
|
|
StartReadClientInput(pClient);
|
|
|
|
//
|
|
// Announce the connection.
|
|
//
|
|
|
|
sprintf(Buf,
|
|
"\n**Remote: Connected to %s %s%s [%s]\n",
|
|
pClient->Name,
|
|
pClient->UserName,
|
|
(pClient->PipeReadH != pClient->PipeWriteH)
|
|
? " (two pipes)"
|
|
: "",
|
|
GetFormattedTime(TRUE));
|
|
|
|
if (WriteFileSynch(hWriteTempFile,Buf,strlen(Buf),&dwSize,dwWriteFilePointer,&olMainThread)) {
|
|
dwWriteFilePointer += dwSize;
|
|
StartServerToClientFlow();
|
|
}
|
|
|
|
//
|
|
// Start write cycle for client output from the temp
|
|
// file.
|
|
// not needed because of StartServerToClientFlow() just above
|
|
// StartReadTempFile(pClient);
|
|
|
|
}
|