PageRenderTime 148ms CodeModel.GetById 85ms app.highlight 17ms RepoModel.GetById 44ms app.codeStats 0ms

/mordor/streams/namedpipe.cpp

http://github.com/mozy/mordor
C++ | 139 lines | 124 code | 13 blank | 2 comment | 36 complexity | 2561454902be8bd28f3b9e7bdad6cba0 MD5 | raw file
  1// Copyright (c) 2009 - Mozy, Inc.
  2
  3#include "namedpipe.h"
  4
  5#include "mordor/assert.h"
  6#include "mordor/exception.h"
  7#include "mordor/log.h"
  8#include "mordor/runtime_linking.h"
  9#include "mordor/string.h"
 10
 11namespace Mordor {
 12
 13static Logger::ptr g_log = Log::lookup("mordor:streams::namedpipe");
 14
 15NamedPipeStream::NamedPipeStream(const std::string &name, Flags flags, IOManager *ioManager, Scheduler *scheduler, DWORD pipeModeFlags)
 16{
 17    init(toUtf16(name), flags, pipeModeFlags,ioManager, scheduler);
 18}
 19
 20NamedPipeStream::NamedPipeStream(const std::wstring &name, Flags flags, IOManager *ioManager, Scheduler *scheduler, DWORD pipeModeFlags)
 21{
 22    init(name, flags, pipeModeFlags, ioManager, scheduler);
 23}
 24
 25void NamedPipeStream::init(const std::wstring &name, Flags flags, DWORD pipeModeFlags, IOManager *ioManager, Scheduler *scheduler)
 26{
 27    if (pipeModeFlags == (DWORD)-1) {
 28        pipeModeFlags = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
 29    }
 30
 31    HANDLE hPipe = CreateNamedPipeW(name.c_str(),
 32        (DWORD)flags | (ioManager ? FILE_FLAG_OVERLAPPED : 0),
 33        pipeModeFlags,
 34        PIPE_UNLIMITED_INSTANCES,
 35        0, 0, 0, NULL);
 36    error_t error = lastError();
 37    MORDOR_LOG_LEVEL(g_log, hPipe == INVALID_HANDLE_VALUE ? Log::ERROR : Log::VERBOSE)
 38        << this << " CreateNamedPipeW(" << toUtf8(name) << ", " << flags
 39        << "): " << hPipe << " (" << error << ")";
 40    if (hPipe == INVALID_HANDLE_VALUE)
 41        MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "CreateNamedPipeW");
 42    HandleStream::init(hPipe, ioManager, scheduler);
 43    m_supportsRead = !!(flags & READ);
 44    m_supportsWrite = !!(flags & WRITE);
 45}
 46
 47void
 48NamedPipeStream::close(CloseType type)
 49{
 50    if (m_hFile != INVALID_HANDLE_VALUE) {
 51        SchedulerSwitcher switcher(m_scheduler);
 52        BOOL ret = DisconnectNamedPipe(m_hFile);
 53        error_t error = lastError();
 54        MORDOR_LOG_VERBOSE(g_log) << this << " DisconnectNamedPipe(" << m_hFile
 55            << "): " << ret << " (" << error << ")";
 56        if (!ret)
 57            MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "DisconnectNamedPipe");
 58    }
 59    HandleStream::close(type);
 60}
 61
 62void
 63NamedPipeStream::accept()
 64{
 65    if (m_cancelRead)
 66        MORDOR_THROW_EXCEPTION(OperationAbortedException());
 67    SchedulerSwitcher switcher(m_ioManager ? NULL : m_scheduler);
 68    OVERLAPPED *overlapped = NULL;
 69    if (m_ioManager) {
 70        MORDOR_ASSERT(Scheduler::getThis());
 71        m_ioManager->registerEvent(&m_readEvent);
 72        overlapped = &m_readEvent.overlapped;
 73    }
 74    BOOL ret = ConnectNamedPipe(m_hFile, overlapped);
 75    Log::Level level = Log::DEBUG;
 76    if (!ret) {
 77        if (lastError() == ERROR_PIPE_CONNECTED) {
 78        } else if (m_ioManager) {
 79            if (lastError() == ERROR_IO_PENDING)
 80                level = Log::TRACE;
 81            else
 82                level = Log::ERROR;
 83        } else {
 84            level = Log::ERROR;
 85        }
 86    }
 87    error_t error = lastError();
 88    MORDOR_LOG_LEVEL(g_log, level) << this
 89        << " ConnectNamedPipe(" << m_hFile << "): " << ret << " ("
 90        << error << ")";
 91    if (m_ioManager) {
 92        if (!ret && error == ERROR_PIPE_CONNECTED) {
 93            m_ioManager->unregisterEvent(&m_readEvent);
 94            return;
 95        }
 96        if (!ret && error != ERROR_IO_PENDING) {
 97            m_ioManager->unregisterEvent(&m_readEvent);
 98            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("ConnectNamedPipe");
 99        }
100        if (ret && m_skipCompletionPortOnSuccess)
101            m_ioManager->unregisterEvent(&m_readEvent);
102        else
103            Scheduler::yieldTo();
104        error_t error = pRtlNtStatusToDosError((NTSTATUS)m_readEvent.overlapped.Internal);
105        MORDOR_LOG_LEVEL(g_log, error ? Log::ERROR : Log::DEBUG) << this
106            << " ConnectNamedPipe(" << m_hFile << "): (" << error
107            << ")";
108        if (error)
109            MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "ConnectNamedPipe");
110    } else {
111        if (!ret && error == ERROR_PIPE_CONNECTED)
112            return;
113        if (!ret)
114            MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "ConnectNamedPipe");
115    }
116}
117
118void
119NamedPipeStream::cancelAccept()
120{
121    m_cancelRead = true;
122    if (m_ioManager) {
123        m_ioManager->cancelEvent(m_hFile, &m_readEvent);
124    } else {
125        MORDOR_ASSERT(supportsCancel());
126        if (!pCancelIoEx(m_hFile, NULL))
127            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("CancelIoEx");
128    }
129}
130
131void
132NamedPipeStream::disconnectClient()
133{
134    // Prepare for reuse of the named pipe handle
135    FlushFileBuffers(m_hFile);
136    DisconnectNamedPipe(m_hFile);
137}
138
139}