/******************************************************************************\ * 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 #include #include #include #include #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) { pfnCancelWaitableTimer(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); }