📄 ncbi_namedpipe.cpp
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbi_namedpipe.cpp,v $ * PRODUCTION Revision 1000.5 2004/06/01 18:45:01 gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.26 * PRODUCTION * =========================================================================== *//* $Id: ncbi_namedpipe.cpp,v 1000.5 2004/06/01 18:45:01 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Anton Lavrentiev, Mike DiCuccio, Vladimir Ivanov * * File Description: * Portable interprocess named pipe API for: UNIX, MS-Win * */#include <ncbi_pch.hpp>#include <connect/ncbi_namedpipe.hpp>#include <corelib/ncbi_system.hpp>#if defined(NCBI_OS_MSWIN)#elif defined(NCBI_OS_UNIX)# include <unistd.h># include <errno.h># include <fcntl.h># include <errno.h># include <sys/socket.h># include <sys/stat.h># include <sys/time.h># include <sys/un.h># include <connect/ncbi_socket.h>#else# error "Class CNamedPipe is supported only on Windows and Unix"#endifBEGIN_NCBI_SCOPE#if !defined(HAVE_SOCKLEN_T)typedef int socklen_t;#endif// Predefined timeoutsconst size_t kDefaultPipeBufSize = (size_t)CNamedPipe::eDefaultBufSize;////////////////////////////////////////////////////////////////////////////////// Auxiliary functions//static STimeout* s_SetTimeout(const STimeout* from, STimeout* to){ if ( !from ) { return const_cast<STimeout*> (kInfiniteTimeout); } to->sec = from->usec / 1000000 + from->sec; to->usec = from->usec % 1000000; return to;}static string s_FormatErrorMessage(const string& where, const string& what){ return "[NamedPipe::" + where + "] " + what + ".";}inline void s_AdjustPipeBufSize(size_t* bufsize) { if (*bufsize == 0) *bufsize = kDefaultPipeBufSize; else if (*bufsize == (size_t)kMax_Int) *bufsize = 0 /* use system default buffer size */;}////////////////////////////////////////////////////////////////////////////////// Class CNamedPipeHandle handles forwarded requests from CNamedPipe.// This class is reimplemented in a platform-specific fashion where needed.//#if defined(NCBI_OS_MSWIN)const DWORD kSleepTime = 100; // sleep time for timeouts////////////////////////////////////////////////////////////////////////////////// CNamedPipeHandle -- MS Windows version//class CNamedPipeHandle{public: CNamedPipeHandle(void); ~CNamedPipeHandle(void); // client-side EIO_Status Open(const string& pipename, const STimeout* timeout, size_t pipebufsize); // server-side EIO_Status Create(const string& pipename, size_t pipebufsize); EIO_Status Listen(const STimeout* timeout); EIO_Status Disconnect(void); // common EIO_Status Close(void); EIO_Status Read(void* buf, size_t count, size_t* n_read, const STimeout* timeout); EIO_Status Write(const void* buf, size_t count, size_t* n_written, const STimeout* timeout); EIO_Status Wait(EIO_Event event, const STimeout* timeout); EIO_Status Status(EIO_Event direction) const;private: long TimeoutToMSec(const STimeout* timeout) const;private: HANDLE m_Pipe; // pipe I/O handle string m_PipeName; // pipe name size_t m_PipeBufSize; // pipe buffer size EIO_Status m_ReadStatus; // last read status EIO_Status m_WriteStatus; // last write status};CNamedPipeHandle::CNamedPipeHandle(void) : m_Pipe(INVALID_HANDLE_VALUE), m_PipeName(kEmptyStr), m_PipeBufSize(0), m_ReadStatus(eIO_Closed), m_WriteStatus(eIO_Closed){ return;}CNamedPipeHandle::~CNamedPipeHandle(void){ Close();}EIO_Status CNamedPipeHandle::Open(const string& pipename, const STimeout* timeout, size_t /* pipebufsize */){ try { if (m_Pipe != INVALID_HANDLE_VALUE) { throw string("Pipe is already open"); } // Save parameters m_PipeName = pipename; m_PipeBufSize = 0 /* pipebufsize is not used on client side */; // Set the base security attributes SECURITY_ATTRIBUTES attr; attr.nLength = sizeof(attr); attr.bInheritHandle = TRUE; attr.lpSecurityDescriptor = NULL; // Waits until either a time-out interval elapses or an instance of // the specified named pipe is available for connection (that is, the // pipe's server process has a pending Listen() operation on the pipe). // NOTE: We do not use here a WaitNamedPipe() because it works // incorrect in some cases. DWORD x_timeout = TimeoutToMSec(timeout); do { // Open existing pipe m_Pipe = CreateFile(pipename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &attr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (m_Pipe != INVALID_HANDLE_VALUE) { m_ReadStatus = eIO_Success; m_WriteStatus = eIO_Success; return eIO_Success; } DWORD x_sleep = kSleepTime; if (x_timeout != INFINITE) { if (x_timeout < kSleepTime) { x_sleep = x_timeout; } x_timeout -= x_sleep; } SleepMilliSec(x_sleep); } while (x_timeout == INFINITE || x_timeout); return eIO_Timeout; } catch (string& what) { Close(); ERR_POST(s_FormatErrorMessage("Open", what)); return eIO_Unknown; }}EIO_Status CNamedPipeHandle::Create(const string& pipename, size_t pipebufsize){ try { if (m_Pipe != INVALID_HANDLE_VALUE) { throw string("Pipe is already open"); } // Save parameters m_PipeName = pipename; m_PipeBufSize = pipebufsize; // Set the base security attributes SECURITY_ATTRIBUTES attr; attr.nLength = sizeof(attr); attr.bInheritHandle = TRUE; attr.lpSecurityDescriptor = NULL; // Create pipe m_Pipe = CreateNamedPipe( pipename.c_str(), // pipe name PIPE_ACCESS_DUPLEX, // read/write access PIPE_TYPE_BYTE | PIPE_NOWAIT, // byte-type, nonblocking mode 1, // one instance only pipebufsize, // output buffer size pipebufsize, // input buffer size INFINITE, // client time-out by default &attr); // security attributes if (m_Pipe == INVALID_HANDLE_VALUE) { throw "Create named pipe \"" + pipename + "\" failed"; } m_ReadStatus = eIO_Success; m_WriteStatus = eIO_Success; return eIO_Success; } catch (string& what) { Close(); ERR_POST(s_FormatErrorMessage("Create", what)); return eIO_Unknown; }}EIO_Status CNamedPipeHandle::Listen(const STimeout* timeout){ EIO_Status status = eIO_Unknown; // Wait for the client to connect, or time out. // NOTE: The function WaitForSingleObject() do not work with pipes. DWORD x_timeout = TimeoutToMSec(timeout); try { if (m_Pipe == INVALID_HANDLE_VALUE) { status = eIO_Closed; throw string("Pipe is closed"); } do { BOOL connected = ConnectNamedPipe(m_Pipe, NULL); if ( !connected ) { DWORD error = GetLastError(); connected = (error == ERROR_PIPE_CONNECTED); // If client closed connection before we serve it if (error == ERROR_NO_DATA) { if (Disconnect() != eIO_Success) { throw string("Listening pipe: failed to close broken " "client session"); } } } if ( connected ) { return eIO_Success; } DWORD x_sleep = kSleepTime; if (x_timeout != INFINITE) { if (x_timeout < kSleepTime) { x_sleep = x_timeout; } x_timeout -= x_sleep; } SleepMilliSec(x_sleep); } while (x_timeout == INFINITE || x_timeout); return eIO_Timeout; } catch (string& what) { ERR_POST(s_FormatErrorMessage("Listen", what)); return status; }}EIO_Status CNamedPipeHandle::Disconnect(void){ EIO_Status status = eIO_Unknown; try { if (m_Pipe == INVALID_HANDLE_VALUE) { status = eIO_Closed; throw string("Pipe is already closed"); } FlushFileBuffers(m_Pipe); if (!DisconnectNamedPipe(m_Pipe)) { throw string("DisconnectNamedPipe() failed"); } Close(); return Create(m_PipeName, m_PipeBufSize); } catch (string& what) { ERR_POST(s_FormatErrorMessage("Disconnect", what)); return status; }}EIO_Status CNamedPipeHandle::Close(void){ if (m_Pipe == INVALID_HANDLE_VALUE) { return eIO_Closed; } FlushFileBuffers(m_Pipe); CloseHandle(m_Pipe); m_Pipe = INVALID_HANDLE_VALUE; m_ReadStatus = eIO_Closed; m_WriteStatus = eIO_Closed; return eIO_Success;}EIO_Status CNamedPipeHandle::Read(void* buf, size_t count, size_t* n_read, const STimeout* timeout){ EIO_Status status = eIO_Unknown; try { if (m_Pipe == INVALID_HANDLE_VALUE) { status = eIO_Closed; throw string("Pipe is closed"); } if ( !count ) { m_ReadStatus = eIO_Success; return m_ReadStatus; } DWORD x_timeout = TimeoutToMSec(timeout); DWORD bytes_avail = 0; // Wait a data from the pipe with timeout. // NOTE: The function WaitForSingleObject() do not work with pipe. do { if ( !PeekNamedPipe(m_Pipe, NULL, 0, NULL, &bytes_avail, NULL) ) { // Peer has been closed the connection? if (GetLastError() == ERROR_BROKEN_PIPE) { m_ReadStatus = eIO_Closed; return m_ReadStatus; } throw string("Cannot peek data from the named pipe"); } if ( bytes_avail ) { break; } DWORD x_sleep = kSleepTime; if (x_timeout != INFINITE) { if (x_timeout < kSleepTime) { x_sleep = x_timeout; } x_timeout -= x_sleep; } SleepMilliSec(x_sleep); } while (x_timeout == INFINITE || x_timeout); // Data is available to read or time out if ( !bytes_avail ) { m_ReadStatus = eIO_Timeout; return m_ReadStatus; } // We must read only "count" bytes of data regardless of the number // available to read if (bytes_avail > count) { bytes_avail = count; } if (!ReadFile(m_Pipe, buf, count, &bytes_avail, NULL)) { throw string("Failed to read data from the named pipe"); } if ( n_read ) { *n_read = bytes_avail; } status = eIO_Success; } catch (string& what) { ERR_POST(s_FormatErrorMessage("Read", what)); } m_ReadStatus = status; return status;}EIO_Status CNamedPipeHandle::Write(const void* buf, size_t count, size_t* n_written, const STimeout* timeout){ EIO_Status status = eIO_Unknown; try { if (m_Pipe == INVALID_HANDLE_VALUE) { status = eIO_Closed; throw string("Pipe is closed"); } if ( !count ) { return eIO_Success; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -