From d36cf5c650533abc3d940dde160ee1a0c529876d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 18:36:54 +0000 Subject: * lib/win32/WinNamedPipeStream.h * lib/win32/WinNamedPipeStream.cpp * lib/server/WinNamedPipeStream.h * lib/server/WinNamedPipeStream.cpp - Moved WinNamedPipeStream class from lib/win32 to lib/server, to resolve circular dependency between lib/common and lib/win32. --- lib/server/WinNamedPipeStream.cpp | 312 ++++++++++++++++++++++++++++++++++++++ lib/server/WinNamedPipeStream.h | 60 ++++++++ 2 files changed, 372 insertions(+) create mode 100644 lib/server/WinNamedPipeStream.cpp create mode 100644 lib/server/WinNamedPipeStream.h (limited to 'lib/server') diff --git a/lib/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp new file mode 100644 index 00000000..c5b7eaa5 --- /dev/null +++ b/lib/server/WinNamedPipeStream.cpp @@ -0,0 +1,312 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: WinNamedPipeStream.cpp +// Purpose: I/O stream interface for Win32 named pipes +// Created: 2005/12/07 +// +// -------------------------------------------------------------------------- + +#include "Box.h" + +#ifdef WIN32 + +#ifdef HAVE_UNISTD_H + #include +#endif + +#include +#include +#include + +#include "WinNamedPipeStream.h" +#include "ServerException.h" +#include "CommonException.h" +#include "Socket.h" + +#include "MemLeakFindOn.h" + +// -------------------------------------------------------------------------- +// +// Function +// Name: WinNamedPipeStream::WinNamedPipeStream() +// Purpose: Constructor (create stream ready for Open() call) +// Created: 2005/12/07 +// +// -------------------------------------------------------------------------- +WinNamedPipeStream::WinNamedPipeStream() + : mSocketHandle(NULL), + mReadClosed(false), + mWriteClosed(false), + mIsServer(false), + mIsConnected(false) +{ +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: WinNamedPipeStream::~WinNamedPipeStream() +// Purpose: Destructor, closes stream if open +// Created: 2005/12/07 +// +// -------------------------------------------------------------------------- +WinNamedPipeStream::~WinNamedPipeStream() +{ + if (mSocketHandle != NULL) + { + Close(); + } +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: WinNamedPipeStream::Accept(const char* Name) +// Purpose: Creates a new named pipe with the given name, +// and wait for a connection on it +// Created: 2005/12/07 +// +// -------------------------------------------------------------------------- +void WinNamedPipeStream::Accept(const wchar_t* pName) +{ + if (mSocketHandle != NULL || mIsConnected) + { + THROW_EXCEPTION(ServerException, SocketAlreadyOpen) + } + + mSocketHandle = CreateNamedPipeW( + pName, // pipe name + PIPE_ACCESS_DUPLEX, // read/write access + PIPE_TYPE_MESSAGE | // message type pipe + PIPE_READMODE_MESSAGE | // message-read mode + PIPE_WAIT, // blocking mode + 1, // max. instances + 4096, // output buffer size + 4096, // input buffer size + NMPWAIT_USE_DEFAULT_WAIT, // client time-out + NULL); // default security attribute + + if (mSocketHandle == NULL) + { + ::syslog(LOG_ERR, "CreateNamedPipeW failed: %d", + GetLastError()); + THROW_EXCEPTION(ServerException, SocketOpenError) + } + + bool connected = ConnectNamedPipe(mSocketHandle, (LPOVERLAPPED) NULL); + + if (!connected) + { + ::syslog(LOG_ERR, "ConnectNamedPipe failed: %d", + GetLastError()); + Close(); + THROW_EXCEPTION(ServerException, SocketOpenError) + } + + mReadClosed = false; + mWriteClosed = false; + mIsServer = true; // must flush and disconnect before closing + mIsConnected = true; +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: WinNamedPipeStream::Connect(const char* Name) +// Purpose: Opens a connection to a listening named pipe +// Created: 2005/12/07 +// +// -------------------------------------------------------------------------- +void WinNamedPipeStream::Connect(const wchar_t* pName) +{ + if (mSocketHandle != NULL || mIsConnected) + { + THROW_EXCEPTION(ServerException, SocketAlreadyOpen) + } + + mSocketHandle = CreateFileW( + pName, // pipe name + GENERIC_READ | // read and write access + GENERIC_WRITE, + 0, // no sharing + NULL, // default security attributes + OPEN_EXISTING, + 0, // default attributes + NULL); // no template file + + if (mSocketHandle == INVALID_HANDLE_VALUE) + { + ::syslog(LOG_ERR, "Failed to connect to server's named pipe: " + "error %d", GetLastError()); + THROW_EXCEPTION(ServerException, SocketOpenError) + } + + mReadClosed = false; + mWriteClosed = false; + mIsServer = false; // just close the socket + mIsConnected = true; +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: WinNamedPipeStream::Read(void *pBuffer, int NBytes) +// Purpose: Reads data from stream. Maybe returns less than asked for. +// Created: 2003/07/31 +// +// -------------------------------------------------------------------------- +int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) +{ + // TODO no support for timeouts yet + ASSERT(Timeout == IOStream::TimeOutInfinite) + + if (mSocketHandle == NULL || !mIsConnected) + { + THROW_EXCEPTION(ServerException, BadSocketHandle) + } + + DWORD NumBytesRead; + + bool Success = ReadFile( + mSocketHandle, // pipe handle + pBuffer, // buffer to receive reply + NBytes, // size of buffer + &NumBytesRead, // number of bytes read + NULL); // not overlapped + + if (!Success) + { + THROW_EXCEPTION(ConnectionException, Conn_SocketReadError) + } + + // Closed for reading at EOF? + if (NumBytesRead == 0) + { + mReadClosed = true; + } + + return NumBytesRead; +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: WinNamedPipeStream::Write(void *pBuffer, int NBytes) +// Purpose: Writes data, blocking until it's all done. +// Created: 2003/07/31 +// +// -------------------------------------------------------------------------- +void WinNamedPipeStream::Write(const void *pBuffer, int NBytes) +{ + if (mSocketHandle == NULL || !mIsConnected) + { + THROW_EXCEPTION(ServerException, BadSocketHandle) + } + + // Buffer in byte sized type. + ASSERT(sizeof(char) == 1); + const char *pByteBuffer = (char *)pBuffer; + + int NumBytesWrittenTotal = 0; + + while (NumBytesWrittenTotal < NBytes) + { + DWORD NumBytesWrittenThisTime = 0; + + bool Success = WriteFile( + mSocketHandle, // pipe handle + pByteBuffer + NumBytesWrittenTotal, // message + NBytes - NumBytesWrittenTotal, // message length + &NumBytesWrittenThisTime, // bytes written this time + NULL); // not overlapped + + if (!Success) + { + mWriteClosed = true; // assume can't write again + THROW_EXCEPTION(ConnectionException, + Conn_SocketWriteError) + } + + NumBytesWrittenTotal += NumBytesWrittenThisTime; + } +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: WinNamedPipeStream::Close() +// Purpose: Closes connection to remote socket +// Created: 2003/07/31 +// +// -------------------------------------------------------------------------- +void WinNamedPipeStream::Close() +{ + if (mSocketHandle == NULL && mIsConnected) + { + fprintf(stderr, "Inconsistent connected state\n"); + ::syslog(LOG_ERR, "Inconsistent connected state"); + mIsConnected = false; + } + + if (mSocketHandle == NULL) + { + THROW_EXCEPTION(ServerException, BadSocketHandle) + } + + if (mIsServer) + { + if (!FlushFileBuffers(mSocketHandle)) + { + ::syslog(LOG_INFO, "FlushFileBuffers failed: %d", + GetLastError()); + } + + if (!DisconnectNamedPipe(mSocketHandle)) + { + ::syslog(LOG_ERR, "DisconnectNamedPipe failed: %d", + GetLastError()); + } + + mIsServer = false; + } + + bool result = CloseHandle(mSocketHandle); + + mSocketHandle = NULL; + mIsConnected = false; + + if (!result) + { + ::syslog(LOG_ERR, "CloseHandle failed: %d", GetLastError()); + THROW_EXCEPTION(ServerException, SocketCloseError) + } +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: WinNamedPipeStream::StreamDataLeft() +// Purpose: Still capable of reading data? +// Created: 2003/08/02 +// +// -------------------------------------------------------------------------- +bool WinNamedPipeStream::StreamDataLeft() +{ + return !mReadClosed; +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: WinNamedPipeStream::StreamClosed() +// Purpose: Connection been closed? +// Created: 2003/08/02 +// +// -------------------------------------------------------------------------- +bool WinNamedPipeStream::StreamClosed() +{ + return mWriteClosed; +} + +#endif // WIN32 diff --git a/lib/server/WinNamedPipeStream.h b/lib/server/WinNamedPipeStream.h new file mode 100644 index 00000000..5a800371 --- /dev/null +++ b/lib/server/WinNamedPipeStream.h @@ -0,0 +1,60 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: WinNamedPipeStream.h +// Purpose: I/O stream interface for Win32 named pipes +// Created: 2005/12/07 +// +// -------------------------------------------------------------------------- + +#if ! defined WINNAMEDPIPESTREAM__H && defined WIN32 +#define WINNAMEDPIPESTREAM__H + +#include "IOStream.h" + +// -------------------------------------------------------------------------- +// +// Class +// Name: WinNamedPipeStream +// Purpose: I/O stream interface for Win32 named pipes +// Created: 2003/07/31 +// +// -------------------------------------------------------------------------- +class WinNamedPipeStream : public IOStream +{ +public: + WinNamedPipeStream(); + ~WinNamedPipeStream(); + + // server side - create the named pipe and listen for connections + void Accept(const wchar_t* Name); + + // client side - connect to a waiting server + void Connect(const wchar_t* Name); + + // both sides + virtual int Read(void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); + virtual void Write(const void *pBuffer, int NBytes); + virtual void Close(); + virtual bool StreamDataLeft(); + virtual bool StreamClosed(); + bool IsConnected() { return mIsConnected; } + +protected: + HANDLE GetSocketHandle(); + void MarkAsReadClosed() {mReadClosed = true;} + void MarkAsWriteClosed() {mWriteClosed = true;} + +private: + WinNamedPipeStream(const WinNamedPipeStream &rToCopy) + { /* do not call */ } + + HANDLE mSocketHandle; + bool mReadClosed; + bool mWriteClosed; + bool mIsServer; + bool mIsConnected; +}; + +#endif // WINNAMEDPIPESTREAM__H -- cgit v1.2.3