home *** CD-ROM | disk | FTP | other *** search
-
- /******************************************************************************\
- * 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:
-
- SrvMain.c
-
- Abstract:
-
- The server component of Remote. It spawns a child process
- and redirects the stdin/stdout/stderr of child to itself.
- Waits for connections from clients - passing the
- output of child process to client and the input from clients
- to child process.
-
- This version uses overlapped I/O to do in one thread what
- the original uses 9 for. Almost. Because there is no way to
- get overlapped stdin/stdout handles, two threads sit around
- doing blocking I/O on stdin and stdout. 3 is better than 9.
-
- Unfortunately there's no CreatePipe()
- or equivalent option to open an overlapped handle to an anonymous
- pipe, so I stole the source for NT CreatePipe and hacked it to
- accept flags indicating overlapped for one or both ends of the
- anonymous pipe. In our usage the child end handles are not
- overlapped but the server end handles are.
-
-
- Author:
-
- Dave Hart 30 May 1997 after Server.c by
- Rajivendra Nath 2-Jan-1992
-
- Environment:
-
- Console App. User mode.
-
- Revision History:
-
- --*/
-
- #include <windows.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <process.h>
- #include <io.h>
- #include <string.h>
- #if DBG
- #undef NDEBUG // so asserts work on chk builds
- #endif
- #include "Remote.h"
- #define SERVER_H_NOEXTERN
- #include "Server.h"
-
-
- DWORD cbRemoteClient = sizeof(REMOTE_CLIENT); // for debugging
-
-
-
- /*************************************************************/
- int
- OverlappedServer( //Main routine for server.
- char* pszChildCmd,
- char* pszPipeNameArg
- )
- {
- int i;
- BOOL b;
- DWORD cWait;
- DWORD dwWait;
- PREMOTE_CLIENT pClientRemove;
-
- #if DBG
- // Trace = -1; // all TR_ bits on (and then some)
- #endif
-
- //
- // Initialize globals
- //
-
- pszPipeName = pszPipeNameArg;
-
- dwNextClientID = 1; // local client will be 1
- cConnectIns = CONNECT_COUNT;
- cWait = MAX_WAIT_HANDLES;
-
- hHeap = HeapCreate(
- 0,
- 3 * sizeof(REMOTE_CLIENT), // initial size
- 3000 * sizeof(REMOTE_CLIENT) // max
- );
-
- OsVersionInfo.dwOSVersionInfoSize = sizeof OsVersionInfo;
- b = GetVersionEx(&OsVersionInfo);
- ASSERT( b );
-
- printf("**************************************\n");
- printf("*********** REMOTE ************\n");
- printf("*********** SERVER ************\n");
- printf("**************************************\n");
- fflush(stdout);
-
-
- //
- // Setup the ACLs we need, taking into account any /u switches
- //
-
- SetupSecurityDescriptors();
-
-
- printf("To Connect: Remote /C %s %s\n\n", HostName, pszPipeName);
- fflush(stdout);
-
-
- //
- // runtime link to NT-only kernel32 APIs so we can
- // load on Win95 for client use.
- //
-
- RuntimeLinkAPIs();
-
-
- //
- // Setup our three lists of clients: handshaking,
- // connected, and closing/closed.
- //
-
- InitializeClientLists();
-
-
- //
- // set _REMOTE environment variable to the pipe name (why?)
- //
-
- SetEnvironmentVariable("_REMOTE", pszPipeName);
-
-
- //
- // Create a tempfile for storing Child process output.
- //
-
- {
- char szTempDirectory[MAX_PATH + 1];
-
- GetTempPath(sizeof(szTempDirectory), szTempDirectory);
-
- //
- // Before we litter the temp directory with more REMnnn.TMP
- // files, let's delete all the orphaned ones we can. This
- // will fail for temp files open by other remote servers.
- //
-
- CleanupTempFiles(szTempDirectory);
-
- GetTempFileName(szTempDirectory, "REM", 0, SaveFileName);
- }
-
- if ( ! (hWriteTempFile =
- CreateFile(
- SaveFileName, /* name of the file */
- GENERIC_READ | GENERIC_WRITE, /* access (read/write) mode */
- FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
- NULL, /* security descriptor */
- CREATE_ALWAYS, /* how to create */
- FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL,
- NULL
- ))) {
-
- ErrorExit("Could not Create Temp File");
- }
-
-
- //
- // We don't want to have multiple IN pipes created and
- // awaiting connection simultaneously if there are
- // multiple remote server processes sharing different
- // sessions under the same pipe name. This would be
- // hairy for several reasons including breaking the
- // current round-robin behavior of connections, since
- // the oldest server pipe is connected first. So
- // we create/open a named event based on the pipe name and
- // set the event so that any other remote servers on the
- // same pipe will fall back to a single IN pipe listening.
- //
-
- {
- char szPerPipeEventName[1024];
-
- sprintf(
- szPerPipeEventName,
- "MSRemoteSrv%s",
- pszPipeName
- );
-
- rghWait[WAITIDX_PER_PIPE_EVENT] =
- CreateEvent(
- &saPublic, // security
- TRUE, // manual reset (synchronization)
- FALSE, // initially nonsignaled
- szPerPipeEventName
- );
-
- if (! rghWait[WAITIDX_PER_PIPE_EVENT]) {
-
- ErrorExit("Unable to create per-pipe event.");
- }
-
- if (ERROR_ALREADY_EXISTS == GetLastError()) {
-
- TRACE(CONNECT, ("Found previous server on '%s', using 1 listening pipe.\n", pszPipeName));
-
- SetEvent(rghWait[WAITIDX_PER_PIPE_EVENT]);
-
- for (i = 1; i < (int) cConnectIns; i++) {
-
- rghPipeIn[i] = INVALID_HANDLE_VALUE;
- }
-
- cWait = MAX_WAIT_HANDLES - cConnectIns + 1;
- cConnectIns = 1;
-
- //
- // We don't want to wait on the event handle, but it's easier
- // to have a handle in its slot, so dupe a handle to our own
- // process. Note we toss the value of the created event handle
- // without closing it -- we want it to stay around but we're
- // done with it.
- //
-
- DuplicateHandle(
- GetCurrentProcess(),
- GetCurrentProcess(),
- GetCurrentProcess(),
- &rghWait[WAITIDX_PER_PIPE_EVENT],
- 0,
- FALSE,
- DUPLICATE_SAME_ACCESS
- );
-
- }
- }
-
-
- //
- // Create the event for the OVERLAPPED structure
- // used by the main server thread for WriteFileSynch calls.
- //
-
- olMainThread.hEvent =
- CreateEvent(
- NULL, // security
- TRUE, // auto-reset
- FALSE, // initially nonsignaled
- NULL // unnamed
- );
-
-
- //
- // Create the events for the OVERLAPPED structures
- // used for ConnectNamedPipe operations.
- //
-
- olConnectOut.hEvent =
- rghWait[WAITIDX_CONNECT_OUT] =
- CreateEvent(
- NULL, // security
- TRUE, // manual reset as ConnectNamedPipe demands
- FALSE, // initially nonsignaled
- NULL
- );
-
- for (i = 0;
- i < (int) cConnectIns;
- i++) {
-
- rgolConnectIn[i].hEvent =
- rghWait[WAITIDX_CONNECT_IN_BASE + i] =
- CreateEvent(
- NULL, // security
- TRUE, // manual reset as ConnectNamedPipe demands
- FALSE, // initially nonsignaled
- NULL
- );
-
- }
-
-
- //
- // Create a timer we'll use to detect 2-pipe clients connected to
- // OUT without ever connecting to IN so we can recycle our single
- // OUT instance and allow other two-pipe clients in again.
- // NT 3.51 doesn't have waitable timers, so we don't do that
- // error handling on that OS. Same as old remote.exe.
- //
-
- if (pfnCreateWaitableTimer) {
- hConnectOutTimer =
- pfnCreateWaitableTimer(
- NULL, // security
- FALSE, // bManualReset, we want auto-reset
- NULL // unnamed
- );
- } else {
- hConnectOutTimer = INVALID_HANDLE_VALUE;
- }
-
-
- //
- // Start the command as a child process
- //
-
- if (hAttachedProcess != INVALID_HANDLE_VALUE) {
-
- ChldProc = hAttachedProcess;
- hWriteChildStdIn = hAttachedWriteChildStdIn;
- hReadChildOutput = hAttachedReadChildStdOut;
-
- } else {
-
- ChldProc =
- ForkChildProcess(
- ChildCmd,
- &hWriteChildStdIn,
- &hReadChildOutput
- );
- }
-
- rghWait[WAITIDX_CHILD_PROCESS] = ChldProc;
-
- //
- // Set ^c/^break handler. It will kill the child process on
- // ^break and pass ^c through to it.
- //
-
- SetConsoleCtrlHandler(SrvCtrlHand, TRUE);
-
-
- //
- // Setup local session and start first read against its input.
- // This starts a chain of completion routines that continues
- // until this server exits.
- //
-
- StartLocalSession();
-
-
- //
- // Start a read operation on the child output pipe.
- // This starts a chain of completion routines that continues
- // until the child terminates.
- //
-
- StartChildOutPipeRead();
-
-
- //
- // Start several async ConnectNamedPipe operations, to reduce the chance
- // of a client getting pipe busy errors. Since there is no
- // completion port version of ConnectNamedPipe, we'll wait on the
- // events in the main loop below that indicate completion.
- //
-
- CreatePipeAndIssueConnect(OUT_PIPE);
-
- for (i = 0;
- i < (int) cConnectIns;
- i++) {
-
- CreatePipeAndIssueConnect(i);
- }
-
-
- InitAd(IsAdvertise);
-
-
- //
- // We may need to service the query pipe for remote /q clients.
- //
-
- InitializeQueryServer();
-
-
- //
- // main loop of thread, waits for ConnectNamedPipe completions
- // and handles them while remaining alertable for completion
- // routines to get called.
- //
-
- while (1) {
-
- dwWait =
- WaitForMultipleObjectsEx(
- cWait,
- rghWait,
- FALSE, // wait on any handle, not all
- 30 * 1000, // ms
- TRUE // alertable (completion routines)
- );
-
-
- if (WAIT_IO_COMPLETION == dwWait) {
-
- //
- // A completion routine was called.
- //
-
- continue;
- }
-
-
- if (WAIT_TIMEOUT == dwWait) {
-
- //
- // Presumably since we've timed out for 30 seconds
- // with no IO completion, closing clients have
- // finished any pending IOs and the memory can be
- // released.
- //
-
- while (pClientRemove = RemoveFirstClientFromClosingList()) {
-
- HeapFree(hHeap, 0, pClientRemove);
- }
-
- continue;
- }
-
-
- if (WAITIDX_CONNECT_OUT == dwWait) {
-
- HandleOutPipeConnected();
- continue;
- }
-
-
- if (WAITIDX_CONNECT_IN_BASE <= dwWait &&
- (WAITIDX_CONNECT_IN_BASE + CONNECT_COUNT) > dwWait) {
-
- HandleInPipeConnected( dwWait - WAITIDX_CONNECT_IN_BASE );
- continue;
- }
-
-
- if (WAITIDX_QUERYSRV_WAIT == dwWait ||
- WAITIDX_QUERYSRV_WAIT + WAIT_ABANDONED_0 == dwWait ) {
-
- //
- // The remote server which was handling the query pipe
- // has gone away. We'll try to take over.
- //
-
- QueryWaitCompleted();
-
- continue;
- }
-
-
- if (WAITIDX_PER_PIPE_EVENT == dwWait) {
-
- //
- // Another server is starting on this same
- // pipename. To be most compatible we need
- // to fall back to listening on only one
- // IN pipe instance.
- //
-
- if (1 != cConnectIns) {
-
- TRACE(CONNECT,
- ("Another server starting on '%s', falling back to 1 IN listening pipe.\n",
- pszPipeName
- ));
-
- for (i = 1; i < (int) cConnectIns; i++) {
-
- CANCELIO( rghPipeIn[i] );
- DisconnectNamedPipe( rghPipeIn[i] );
- CloseHandle( rghPipeIn[i] );
- rghPipeIn[i] = INVALID_HANDLE_VALUE;
-
- }
-
- cWait = MAX_WAIT_HANDLES - cConnectIns + 1;
-
- cConnectIns = 1;
-
- //
- // We don't want to wait on the event handle, but it's easier
- // to have a handle in its slot, so dupe a handle to our own
- // process. We toss the event handle without closing it so
- // it will stay around for future remote servers on the same
- // pipe name.
- //
-
- DuplicateHandle(
- GetCurrentProcess(),
- GetCurrentProcess(),
- GetCurrentProcess(),
- &rghWait[WAITIDX_PER_PIPE_EVENT],
- 0,
- FALSE,
- DUPLICATE_SAME_ACCESS
- );
- }
-
- continue;
- }
-
- if (WAITIDX_CHILD_PROCESS == dwWait ||
- WAITIDX_READ_STDIN_DONE == dwWait) {
-
- if (INVALID_HANDLE_VALUE != hConnectOutTimer) {
-
- CloseHandle(hConnectOutTimer);
- hConnectOutTimer = INVALID_HANDLE_VALUE;
- }
-
- //
- // Cancel ConnectNamedPipe operations and close
- // the pipes
- //
-
- if (INVALID_HANDLE_VALUE != hPipeOut) {
-
- DisconnectNamedPipe( hPipeOut );
- CANCELIO( hPipeOut );
- CloseHandle( rghWait[WAITIDX_CONNECT_OUT] );
- rghWait[WAITIDX_CONNECT_OUT] = INVALID_HANDLE_VALUE;
- }
-
- for (i = 0;
- i < (int) cConnectIns;
- i++) {
-
- if (INVALID_HANDLE_VALUE != rghPipeIn[i]) {
-
- TRACE(CONNECT, ("Tearing down listening IN pipe #%d.\n", i + 1));
-
- DisconnectNamedPipe( rghPipeIn[i] );
- CANCELIO( rghPipeIn[i] );
- CloseHandle( rghPipeIn[i] );
- rghPipeIn[i] = INVALID_HANDLE_VALUE;
- }
-
- }
-
- //
- // Cancel read against child process in/out pipes
- //
-
- if (INVALID_HANDLE_VALUE != hWriteChildStdIn) {
-
- CANCELIO( hWriteChildStdIn );
- CloseHandle( hWriteChildStdIn );
- hWriteChildStdIn = INVALID_HANDLE_VALUE;
- }
-
- if (INVALID_HANDLE_VALUE != hReadChildOutput) {
-
- CANCELIO( hReadChildOutput );
- CloseHandle( hReadChildOutput );
- hReadChildOutput = INVALID_HANDLE_VALUE;
- }
-
- //
- // Cancel client I/Os
- //
-
- bShuttingDownServer = TRUE;
-
- //
- // Note that CloseClient will remove entries from this list,
- // so we walk it starting at the head at each step.
- //
-
- for (pClientRemove = (PREMOTE_CLIENT) ClientListHead.Flink;
- pClientRemove != (PREMOTE_CLIENT) &ClientListHead;
- pClientRemove = (PREMOTE_CLIENT) ClientListHead.Flink ) {
-
- CloseClient(pClientRemove);
- }
-
- //
- // on our way out...
- //
-
- break;
- }
-
- //
- // Unexpected WaitForMulipleObjectsEx return
- //
-
- printf("Remote: unknown wait return %d\n", dwWait);
- ErrorExit("fix srvmain.c");
-
- } // endless loop
-
-
- ShutAd(IsAdvertise);
-
- while (i = 0, GetExitCodeProcess(ChldProc, &i) &&
- STILL_ACTIVE == i) {
-
- printf("\nRemote: Waiting for child to exit.\n");
- WaitForSingleObjectEx(ChldProc, 10 * 1000, TRUE);
- }
-
- //
- // For some interesting reason when we're attached to
- // a debugger like ntsd and it exits, our printf
- // below comes out *after* the cmd.exe prompt, making
- // it look like we hung on exit even though cmd.exe is
- // patiently awaiting a command. So suppress it.
- //
-
- if (hAttachedProcess == INVALID_HANDLE_VALUE) {
- printf("\nRemote exiting. Child (%s) exit code was %d.\n", ChildCmd, i);
- }
-
- CANCELIO(hWriteTempFile);
- CloseHandle(hWriteTempFile);
- hWriteTempFile = INVALID_HANDLE_VALUE;
-
- //
- // Flush any pending completion routines.
- //
-
- while (WAIT_IO_COMPLETION == SleepEx(50, TRUE)) {
- ;
- }
-
- if (!DeleteFile(SaveFileName)) {
-
- printf("Remote: Temp File %s not deleted..\n",SaveFileName);
- }
-
- return i;
- }
-
-
-
- VOID
- FASTCALL
- StartLocalSession(
- VOID
- )
- {
- DWORD dwThreadId;
- char szHexAsciiId[9];
-
- pLocalClient = HeapAlloc(
- hHeap,
- HEAP_ZERO_MEMORY,
- sizeof(*pLocalClient)
- );
-
- if (!pLocalClient) {
-
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- ErrorExit("Unable to allocate local client.");
- }
-
- pLocalClient->dwID = dwNextClientID++;
- sprintf(szHexAsciiId, "%08x", pLocalClient->dwID);
- CopyMemory(pLocalClient->HexAsciiId, szHexAsciiId, sizeof(pLocalClient->HexAsciiId));
-
- strcpy(pLocalClient->Name, "Local");
- pLocalClient->ServerFlags = SFLG_LOCAL;
-
-
- //
- // we need overlapped handles to stdin/stdout,
- // and woefully DuplicateHandle can't do it.
- // So we'll create two anonymous pipes and two
- // threads to shuffle data between stdin/stdout
- // and the pipes. The server end of the pipes
- // is opened overlapped, the "client" end (used
- // by the threads) is not overlapped.
- //
-
-
- rgCopyPipe[0].hRead = GetStdHandle(STD_INPUT_HANDLE);
- if ( ! MyCreatePipeEx(&pLocalClient->PipeReadH, &rgCopyPipe[0].hWrite, NULL, 0, FILE_FLAG_OVERLAPPED, 0)) {
- ErrorExit("Cannot create local input pipe");
- }
-
- rgCopyPipe[1].hWrite = GetStdHandle(STD_OUTPUT_HANDLE);
- if ( ! MyCreatePipeEx(&rgCopyPipe[1].hRead, &pLocalClient->PipeWriteH, NULL, 0, 0, FILE_FLAG_OVERLAPPED)) {
- ErrorExit("Cannot create local output pipe");
- }
-
- rghWait[WAITIDX_READ_STDIN_DONE] = (HANDLE)
- _beginthreadex(
- NULL, // security
- 0, // default stack size
- CopyPipeToPipe, // proc
- (LPVOID) &rgCopyPipe[0], // parm
- 0, // flags
- &dwThreadId
- );
-
- CloseHandle( (HANDLE)
- _beginthreadex(
- NULL, // security
- 0, // default stack size
- CopyPipeToPipe, // proc
- (LPVOID) &rgCopyPipe[1], // parm
- 0, // flags
- &dwThreadId
- )
- );
-
-
- StartSession( pLocalClient );
- }
-
-
- //
- // Two of these threads to deal with non-overlapped stdin/stdout.
- // CRT is OK.
- //
-
- DWORD
- WINAPI
- CopyPipeToPipe(
- LPVOID lpCopyPipeData
- )
- {
- PCOPYPIPE psd = (PCOPYPIPE) lpCopyPipeData;
- DWORD cb;
- char achBuffer[BUFFSIZE];
-
- while (1) {
- if ( ! ReadFile(
- psd->hRead,
- achBuffer,
- sizeof(achBuffer),
- &cb,
- NULL
- )) {
-
- TRACE(COPYPIPE, ("CopyPipeToPipe ReadFile %s failed, exiting thread.\n",
- (psd == &rgCopyPipe[0])
- ? "stdin"
- : "local client output pipe"));
- break;
- }
-
- if ( ! WriteFile(
- psd->hWrite,
- achBuffer,
- cb,
- &cb,
- NULL
- )) {
-
- TRACE(COPYPIPE, ("CopyPipeToPipe WriteFile %s failed, exiting thread.\n",
- (psd == &rgCopyPipe[0])
- ? "local client input pipe"
- : "stdout"));
- break;
- }
- }
-
- return 0;
- }
-
-
- VOID
- FASTCALL
- StartSession(
- PREMOTE_CLIENT pClient
- )
- {
- pClient->rSaveFile =
- CreateFile(
- SaveFileName,
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- NULL
- );
-
- if ( ! pClient->rSaveFile) {
-
- printf("Remote:Cannot open ReadHandle to temp file:%d\n",GetLastError());
-
- } else {
-
- pClient->UserName[0] = 0;
-
- GetNamedPipeHandleState(
- pClient->PipeReadH,
- NULL,
- NULL,
- NULL,
- NULL,
- pClient->UserName,
- sizeof(pClient->UserName)
- );
-
- //
- // For every client except the local
- // stdin/stdout client, there's a copy of remote.exe
- // running in client mode on the other side. Do
- // handshaking with it to setup options and check
- // versions. HandshakeWithRemoteClient will start
- // the "normal" I/O cycle once the handshake cycle is
- // done. Note it returns as soon as the first handshake
- // I/O is submitted.
- //
-
- if (pClient->ServerFlags & SFLG_LOCAL) {
-
- AddClientToHandshakingList(pClient);
- MoveClientToNormalList(pClient);
-
- //
- // Start read operation against this client's input.
- //
-
- StartReadClientInput(pClient);
-
- //
- // Start write cycle for client output from the temp
- // file.
- //
-
- StartReadTempFile(pClient);
-
- } else {
-
- HandshakeWithRemoteClient(pClient);
- }
- }
- }
-
-
-
-
- VOID
- FASTCALL
- CreatePipeAndIssueConnect(
- int nIndex // IN pipe index or OUT_PIPE
- )
- {
- BOOL b;
- DWORD dwError;
- char szPipeName[BUFFSIZE];
-
-
- if (OUT_PIPE == nIndex) {
- TRACE(CONNECT, ("Creating listening OUT pipe.\n"));
- } else {
- TRACE(CONNECT, ("Creating listening IN pipe #%d.\n", nIndex + 1));
- }
-
- if (OUT_PIPE == nIndex) {
-
- sprintf(szPipeName, SERVER_WRITE_PIPE, ".", pszPipeName);
-
- hPipeOut =
- CreateNamedPipe(
- szPipeName,
- PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE,
- PIPE_UNLIMITED_INSTANCES,
- 0,
- 0,
- 0,
- &saPipe
- );
-
- if (INVALID_HANDLE_VALUE == hPipeOut) {
-
- ErrorExit("Unable to CreateNamedPipe OUT");
- }
-
- b = ConnectNamedPipe(hPipeOut, &olConnectOut);
-
-
- if ( ! b ) {
-
- dwError = GetLastError();
-
- if (ERROR_PIPE_CONNECTED == dwError) {
-
- b = TRUE;
- }
- }
-
- if ( b ) {
-
- TRACE(CONNECT, ("Quick connect on OUT pipe.\n"));
-
- HandleOutPipeConnected();
-
- } else {
-
- if (ERROR_IO_PENDING != dwError) {
-
- ErrorExit("ConnectNamedPipe out failed");
- }
- }
-
- } else {
-
- sprintf(szPipeName, SERVER_READ_PIPE, ".", pszPipeName);
-
- rghPipeIn[nIndex] =
- CreateNamedPipe(
- szPipeName,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE,
- PIPE_UNLIMITED_INSTANCES,
- 0,
- 0,
- 0,
- &saPipe
- );
-
- if (INVALID_HANDLE_VALUE == rghPipeIn[nIndex]) {
-
- if (ERROR_ACCESS_DENIED == GetLastError()) {
- if (DaclNameCount) {
- ErrorExit("Unable to CreateNamedPipe, are YOU in the list of permitted users?");
- } else {
- ErrorExit("Unable to CreateNamedPipe, maybe old remote server on same pipe name?");
- }
- } else {
- ErrorExit("Unable to CreateNamedPipe IN");
- }
- }
-
- b = ConnectNamedPipe(rghPipeIn[nIndex], &rgolConnectIn[nIndex]);
-
- if ( ! b ) {
-
- dwError = GetLastError();
-
- if (ERROR_PIPE_CONNECTED == dwError) {
- b = TRUE;
- }
- }
-
- if ( b ) {
-
- TRACE(CONNECT, ("Quick connect on IN pipe #%d.\n", nIndex));
-
- HandleInPipeConnected(nIndex);
-
- } else {
-
- if (ERROR_IO_PENDING != dwError) {
-
- ErrorExit("ConnectNamedPipe in failed");
- }
- }
-
- }
-
- if (OUT_PIPE == nIndex) {
- TRACE(CONNECT, ("Listening OUT pipe handle %x.\n", hPipeOut));
- } else {
- TRACE(CONNECT, ("Listening IN pipe #%d handle %x.\n", nIndex + 1, rghPipeIn[nIndex]));
- }
- }
-
-
- VOID
- FASTCALL
- HandleOutPipeConnected(
- VOID
- )
- {
- LARGE_INTEGER DueTime;
-
- ResetEvent(rghWait[WAITIDX_CONNECT_OUT]);
-
- bOutPipeConnected = TRUE;
-
- TRACE(CONNECT, ("Two-pipe caller connected to OUT pipe %x.\n",
- hPipeOut));
-
- //
- // Start a 1 minute timer in case we don't get a connection
- // on an IN pipe from this client, we'll recycle the OUT
- // pipe.
- //
-
- if (INVALID_HANDLE_VALUE != hConnectOutTimer) {
-
- DueTime.QuadPart = Int32x32To64(60 * 1000, -10000);
-
- pfnSetWaitableTimer(
- hConnectOutTimer,
- &DueTime,
- 0, // not periodic, single-fire
- ConnectOutTimerFired,
- 0, // arg to compl. rtn
- TRUE
- );
- }
- }
-
-
- VOID
- APIENTRY
- ConnectOutTimerFired(
- LPVOID pArg,
- DWORD dwTimerLo,
- DWORD dwTimerHi
- )
- {
- UNREFERENCED_PARAMETER( pArg );
- UNREFERENCED_PARAMETER( dwTimerLo );
- UNREFERENCED_PARAMETER( dwTimerHi );
-
- //
- // We've had a connected OUT pipe for a minute now,
- // only two-pipe clients connect to that and they
- // immediately connect to IN afterwards. Presumably
- // the client died between these two operations. Until
- // we recycle the OUT pipe all two-pipe clients are
- // unable to connect getting pipe busy errors.
- //
-
- if ( ! bOutPipeConnected ) {
-
- TRACE(CONNECT, ("ConnectOut timer fired but Out pipe not connected.\n"));
- return;
- }
-
- TRACE(CONNECT, ("Two-pipe caller hung for 1 minute, recycling OUT pipe %x.\n",
- hPipeOut));
-
- bOutPipeConnected = FALSE;
-
- CANCELIO(hPipeOut);
- DisconnectNamedPipe(hPipeOut);
- CloseHandle(hPipeOut);
- hPipeOut = INVALID_HANDLE_VALUE;
-
- CreatePipeAndIssueConnect(OUT_PIPE);
-
- //
- // 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 IN pipe and recreate it so
- // that the oldest listening OUT pipe will be from the same process
- // as the oldest listening IN pipe.
- //
-
- if (1 == cConnectIns) {
-
- TRACE(CONNECT, ("Recycling IN pipe %x as well for round-robin behavior.\n",
- rghPipeIn[0]));
-
- CANCELIO(rghPipeIn[0]);
- DisconnectNamedPipe(rghPipeIn[0]);
- CloseHandle(rghPipeIn[0]);
- rghPipeIn[0] = INVALID_HANDLE_VALUE;
-
- CreatePipeAndIssueConnect(0);
- }
- }
-
-
- VOID
- FASTCALL
- HandleInPipeConnected(
- int nIndex
- )
- {
- PREMOTE_CLIENT pClient;
- char szHexAsciiId[9];
-
- ResetEvent(rghWait[WAITIDX_CONNECT_IN_BASE + nIndex]);
-
- if (nIndex >= (int) cConnectIns) {
-
- //
- // The I/O was cancelled on the excess
- // listening pipes, causing the event to
- // fire.
- //
-
- ASSERT(INVALID_HANDLE_VALUE == rghPipeIn[nIndex]);
-
- TRACE(CONNECT, ("IN pipe #%d, handle %x listen cancelled.\n",
- nIndex + 1, rghPipeIn[nIndex]));
-
- return;
- }
-
-
- TRACE(CONNECT, ("Caller connected to IN pipe #%d, handle %x.\n",
- nIndex + 1, rghPipeIn[nIndex]));
-
- //
- // A client is fully connected, but we don't know if
- // it's a single-pipe or two-pipe client. Until
- // we do its PipeWriteH will be invalid. We'll figure
- // it out in ReadClientNameCompleted.
- //
-
- pClient = HeapAlloc(
- hHeap,
- HEAP_ZERO_MEMORY,
- sizeof(*pClient)
- );
-
- if ( ! pClient) {
-
- printf("Out of memory connecting client, hanging up.\n");
-
- CloseHandle( rghPipeIn[nIndex] );
- rghPipeIn[nIndex] = INVALID_HANDLE_VALUE;
- CreatePipeAndIssueConnect( nIndex );
-
-
- if (bOutPipeConnected) {
-
- //
- // Hang up on the two-pipe caller connected to the
- // OUT pipe as well -- it may be this client or it
- // may be another, no way to tell, and really no
- // great need to because if it's another caller
- // we probably wouldn't be able to allocate memory
- // for it either.
- //
- // Also if we're using a single IN pipe for
- // multiple-server round-robin behavior we
- // want to recycle both pipes at the same time.
- //
-
- TRACE(CONNECT, ("Also hanging up on connected two-pipe caller on OUT pipe %x.\n",
- hPipeOut));
-
- bOutPipeConnected = FALSE;
-
- if (INVALID_HANDLE_VALUE != hConnectOutTimer) {
- pfnCancelWaitableTimer(hConnectOutTimer);
- }
-
- DisconnectNamedPipe(hPipeOut);
- CloseHandle(hPipeOut);
- hPipeOut = INVALID_HANDLE_VALUE;
-
- CreatePipeAndIssueConnect( OUT_PIPE );
- }
-
- } else {
-
- //
- // Initialize the Client
- //
-
- pClient->dwID = dwNextClientID++;
- sprintf(szHexAsciiId, "%08x", pClient->dwID);
- CopyMemory(pClient->HexAsciiId, szHexAsciiId, sizeof(pClient->HexAsciiId));
-
- pClient->PipeReadH = rghPipeIn[nIndex];
- rghPipeIn[nIndex] = INVALID_HANDLE_VALUE;
-
- pClient->PipeWriteH = INVALID_HANDLE_VALUE;
-
- TRACE(CONNECT, ("Handshaking new client %d (%x) on IN pipe handle %x.\n",
- pClient->dwID, pClient, pClient->PipeReadH));
-
- //
- // Start another connect operation to replace this completed one.
- //
-
- CreatePipeAndIssueConnect( nIndex );
-
- //
- // Start session I/Os with the new client. This will link it
- // into the handshaking list.
- //
-
- StartSession( pClient );
-
- }
-
- }
-