summaryrefslogtreecommitdiff
path: root/lib/server
diff options
context:
space:
mode:
authorChris Wilson <chris+github@qwirx.com>2008-10-03 22:39:59 +0000
committerChris Wilson <chris+github@qwirx.com>2008-10-03 22:39:59 +0000
commit962fe34e1d033dab5c8049b0d01dbcf0466c5386 (patch)
tree7621288e6bf597120deed7037dc1088b13ee4d7f /lib/server
parent86f379db8587547addb050663aa86ca8d87d0c5f (diff)
Utility classes to be used by new Windows named pipe framework.
Diffstat (limited to 'lib/server')
-rw-r--r--lib/server/OverlappedIO.h42
-rw-r--r--lib/server/WinNamedPipeListener.h232
2 files changed, 274 insertions, 0 deletions
diff --git a/lib/server/OverlappedIO.h b/lib/server/OverlappedIO.h
new file mode 100644
index 00000000..12495053
--- /dev/null
+++ b/lib/server/OverlappedIO.h
@@ -0,0 +1,42 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: OverlappedIO.h
+// Purpose: Windows overlapped IO handle guard
+// Created: 2008/09/30
+//
+// --------------------------------------------------------------------------
+
+#ifndef OVERLAPPEDIO__H
+#define OVERLAPPEDIO__H
+
+class OverlappedIO
+{
+public:
+ OVERLAPPED mOverlapped;
+
+ OverlappedIO()
+ {
+ ZeroMemory(&mOverlapped, sizeof(mOverlapped));
+ mOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE,
+ NULL);
+ if (mOverlapped.hEvent == INVALID_HANDLE_VALUE)
+ {
+ BOX_LOG_WIN_ERROR("Failed to create event for "
+ "overlapped I/O");
+ THROW_EXCEPTION(ServerException, BadSocketHandle);
+ }
+ }
+
+ ~OverlappedIO()
+ {
+ if (CloseHandle(mOverlapped.hEvent) != TRUE)
+ {
+ BOX_LOG_WIN_ERROR("Failed to delete event for "
+ "overlapped I/O");
+ THROW_EXCEPTION(ServerException, BadSocketHandle);
+ }
+ }
+};
+
+#endif // !OVERLAPPEDIO__H
diff --git a/lib/server/WinNamedPipeListener.h b/lib/server/WinNamedPipeListener.h
new file mode 100644
index 00000000..26e76e3d
--- /dev/null
+++ b/lib/server/WinNamedPipeListener.h
@@ -0,0 +1,232 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: WinNamedPipeListener.h
+// Purpose: Windows named pipe socket connection listener
+// for server
+// Created: 2008/09/30
+//
+// --------------------------------------------------------------------------
+
+#ifndef WINNAMEDPIPELISTENER__H
+#define WINNAMEDPIPELISTENER__H
+
+#include <OverlappedIO.h>
+#include <WinNamedPipeStream.h>
+
+#include "ServerException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: WinNamedPipeListener
+// Purpose:
+// Created: 2008/09/30
+//
+// --------------------------------------------------------------------------
+template<int ListenBacklog = 128>
+class WinNamedPipeListener
+{
+private:
+ std::auto_ptr<std::string> mapPipeName;
+ std::auto_ptr<OverlappedIO> mapOverlapConnect;
+ HANDLE mPipeHandle;
+
+public:
+ // Initialise
+ WinNamedPipeListener()
+ : mPipeHandle(INVALID_HANDLE_VALUE)
+ { }
+
+private:
+ WinNamedPipeListener(const WinNamedPipeListener &rToCopy)
+ { /* forbidden */ }
+
+ HANDLE CreatePipeHandle(const std::string& rName)
+ {
+ std::string socket = WinNamedPipeStream::sPipeNamePrefix +
+ rName;
+
+ HANDLE handle = CreateNamedPipeA(
+ socket.c_str(), // pipe name
+ PIPE_ACCESS_DUPLEX | // read/write access
+ FILE_FLAG_OVERLAPPED, // enabled overlapped I/O
+ PIPE_TYPE_BYTE | // message type pipe
+ PIPE_READMODE_BYTE | // message-read mode
+ PIPE_WAIT, // blocking mode
+ ListenBacklog + 1, // max. instances
+ 4096, // output buffer size
+ 4096, // input buffer size
+ NMPWAIT_USE_DEFAULT_WAIT, // client time-out
+ NULL); // default security attribute
+
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ BOX_LOG_WIN_ERROR("Failed to create named pipe " <<
+ socket);
+ THROW_EXCEPTION(ServerException, SocketOpenError)
+ }
+
+ return handle;
+ }
+
+public:
+ ~WinNamedPipeListener()
+ {
+ Close();
+ }
+
+ void Close()
+ {
+ if (mPipeHandle != INVALID_HANDLE_VALUE)
+ {
+ if (mapOverlapConnect.get())
+ {
+ // outstanding connect in progress
+ if (CancelIo(mPipeHandle) != TRUE)
+ {
+ BOX_LOG_WIN_ERROR("Failed to cancel "
+ "outstanding connect request "
+ "on named pipe");
+ }
+
+ mapOverlapConnect.reset();
+ }
+
+ if (CloseHandle(mPipeHandle) != TRUE)
+ {
+ BOX_LOG_WIN_ERROR("Failed to close named pipe "
+ "handle");
+ }
+
+ mPipeHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ // ------------------------------------------------------------------
+ //
+ // Function
+ // Name: WinNamedPipeListener::Listen(std::string name)
+ // Purpose: Initialises socket name
+ // Created: 2003/07/31
+ //
+ // ------------------------------------------------------------------
+ void Listen(const std::string& rName)
+ {
+ Close();
+ mapPipeName.reset(new std::string(rName));
+ mPipeHandle = CreatePipeHandle(rName);
+ }
+
+ // ------------------------------------------------------------------
+ //
+ // Function
+ // Name: WinNamedPipeListener::Accept(int)
+ // Purpose: Accepts a connection, returning a pointer to
+ // a class of the specified type. May return a
+ // null pointer if a signal happens, or there's
+ // a timeout. Timeout specified in
+ // milliseconds, defaults to infinite time.
+ // Created: 2003/07/31
+ //
+ // ------------------------------------------------------------------
+ std::auto_ptr<WinNamedPipeStream> Accept(int Timeout = INFTIM,
+ const char* pLogMsgOut = NULL)
+ {
+ if(!mapPipeName.get())
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle);
+ }
+
+ BOOL connected = FALSE;
+ std::auto_ptr<WinNamedPipeStream> mapStream;
+
+ if (!mapOverlapConnect.get())
+ {
+ // start a new connect operation
+ mapOverlapConnect.reset(new OverlappedIO());
+ connected = ConnectNamedPipe(mPipeHandle,
+ &mapOverlapConnect->mOverlapped);
+
+ if (connected == FALSE)
+ {
+ if (GetLastError() == ERROR_PIPE_CONNECTED)
+ {
+ connected = TRUE;
+ }
+ else if (GetLastError() != ERROR_IO_PENDING)
+ {
+ BOX_LOG_WIN_ERROR("Failed to connect "
+ "named pipe");
+ THROW_EXCEPTION(ServerException,
+ SocketAcceptError);
+ }
+ }
+ }
+
+ if (connected == FALSE)
+ {
+ // wait for connection
+ DWORD result = WaitForSingleObject(
+ mapOverlapConnect->mOverlapped.hEvent,
+ (Timeout == INFTIM) ? INFINITE : Timeout);
+
+ if (result == WAIT_OBJECT_0)
+ {
+ DWORD dummy;
+
+ if (!GetOverlappedResult(mPipeHandle,
+ &mapOverlapConnect->mOverlapped,
+ &dummy, TRUE))
+ {
+ BOX_LOG_WIN_ERROR("Failed to get "
+ "overlapped connect result");
+ THROW_EXCEPTION(ServerException,
+ SocketAcceptError);
+ }
+
+ connected = TRUE;
+ }
+ else if (result == WAIT_TIMEOUT)
+ {
+ return mapStream; // contains NULL
+ }
+ else if (result == WAIT_ABANDONED)
+ {
+ BOX_ERROR("Wait for named pipe connection "
+ "was abandoned by the system");
+ THROW_EXCEPTION(ServerException,
+ SocketAcceptError);
+ }
+ else if (result == WAIT_FAILED)
+ {
+ BOX_LOG_WIN_ERROR("Failed to wait for named "
+ "pipe connection");
+ THROW_EXCEPTION(ServerException,
+ SocketAcceptError);
+ }
+ else
+ {
+ BOX_ERROR("Failed to wait for named pipe "
+ "connection: unknown return code " <<
+ result);
+ THROW_EXCEPTION(ServerException,
+ SocketAcceptError);
+ }
+ }
+
+ ASSERT(connected == TRUE);
+
+ mapStream.reset(new WinNamedPipeStream(mPipeHandle));
+ mPipeHandle = CreatePipeHandle(*mapPipeName);
+ mapOverlapConnect.reset();
+
+ return mapStream;
+ }
+};
+
+#include "MemLeakFindOff.h"
+
+#endif // WINNAMEDPIPELISTENER__H