Example #1
0
TempStream::TempStream(const std::string &prefix, bool deleteOnClose,
                       IOManager *ioManager, Scheduler *scheduler)
{
    std::string tempdir;
    bool absolutePath =
#ifdef WINDOWS
        (prefix.size() >= 2 && (prefix[1] == ':' || prefix[1] == '\\')) ||
        (!prefix.empty() && prefix[0] == '\\');
#else
        !prefix.empty() && prefix[0] == '/';
#endif
    if (!absolutePath)
        tempdir = g_tempDir->val();
#ifdef WINDOWS
    std::wstring wtempdir = toUtf16(tempdir);
    if (!absolutePath && wtempdir.empty()) {
        wtempdir.resize(MAX_PATH);
        DWORD len = GetTempPathW(MAX_PATH, &wtempdir[0]);
        if (len == 0)
            wtempdir = L".";
        else
            wtempdir.resize(len);
    }
    std::wstring prefixW = toUtf16(prefix);
    size_t backslash = prefixW.rfind(L'\\');
    if (backslash != std::wstring::npos) {
        wtempdir += prefixW.substr(0, backslash);
        prefixW = prefixW.substr(backslash + 1);
    }
    std::wstring tempfile;
    tempfile.resize(MAX_PATH);
    UINT len = GetTempFileNameW(wtempdir.c_str(),
        prefixW.c_str(),
        0,
        &tempfile[0]);
    if (len == 0)
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("GetTempFileNameW");
    init(tempfile, FileStream::READWRITE,
        (FileStream::CreateFlags)(FileStream::OPEN |
            (deleteOnClose ? FileStream::DELETE_ON_CLOSE : 0)),
        ioManager, scheduler);
#else
    if (!absolutePath && tempdir.empty())
        tempdir = "/tmp/" + prefix + "XXXXXX";
    else if (!absolutePath)
        tempdir += prefix + "XXXXXX";
    else
        tempdir = prefix + "XXXXXX";
    int fd = mkstemp(&tempdir[0]);
    if (fd < 0)
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("mkstemp");
    init(fd, ioManager, scheduler);
    if (deleteOnClose) {
        int rc = unlink(tempdir.c_str());
        if (rc != 0)
            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("unlink");
    }
    m_path = tempdir;
#endif
}
Example #2
0
unsigned long long
TimerManager::now()
{
    if (ms_clockDg)
        return ms_clockDg();

#ifdef WINDOWS
    LARGE_INTEGER count;
    if (!QueryPerformanceCounter(&count))
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("QueryPerformanceCounter");
    unsigned long long countUll = (unsigned long long)count.QuadPart;
    if (g_frequency == 0)
        g_frequency = queryFrequency();
    return muldiv64(countUll, 1000000, g_frequency);
#elif defined(OSX)
    unsigned long long absoluteTime = mach_absolute_time();
    if (g_timebase.denom == 0)
        g_timebase = queryTimebase();
    return muldiv64(absoluteTime, g_timebase.numer, (uint64_t)g_timebase.denom * 1000);
#else
    struct timespec ts;

    if (clock_gettime(CLOCK_MONOTONIC, &ts))
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("clock_gettime");
    return ts.tv_sec * 1000000ull + ts.tv_nsec / 1000;
#endif
}
Example #3
0
EventLoop::EventLoop()
    : Scheduler(1, true, 1)
{
    m_messageWindow = NULL;
    m_messageWindow = CreateWindowW(L"MordorEventLoop",
        L"Mordor Event Loop",
        0,
        0, 0,
        0, 0,
        HWND_MESSAGE,
        NULL,
        GetModuleHandleW(NULL),
        this);
    if (!m_messageWindow)
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("CreateWindowW");
    m_idleHook = SetWindowsHookExW(WH_FOREGROUNDIDLE,
        &EventLoop::foregroundIdleProc,
        NULL,
        GetCurrentThreadId());
    if (!m_idleHook) {
        DestroyWindow(m_messageWindow);
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SetWindowsHookEx");
    }
    start();
}
Example #4
0
IOManagerEPoll::IOManagerEPoll(int threads, bool useCaller)
    : Scheduler(threads, useCaller)
{
    m_epfd = epoll_create(5000);
    MORDOR_LOG_LEVEL(g_log, m_epfd <= 0 ? Log::ERROR : Log::TRACE) << this
        << " epoll_create(5000): " << m_epfd;
    if (m_epfd <= 0)
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_create");
    int rc = pipe(m_tickleFds);
    MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this << " pipe(): "
        << rc << " (" << errno << ")";
    if (rc) {
        close(m_epfd);
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("pipe");
    }
    MORDOR_ASSERT(m_tickleFds[0] > 0);
    MORDOR_ASSERT(m_tickleFds[1] > 0);
    epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = m_tickleFds[0];
    rc = epoll_ctl(m_epfd, EPOLL_CTL_ADD, m_tickleFds[0], &event);
    MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this
        << " epoll_ctl(" << m_epfd << ", EPOLL_CTL_ADD, " << m_tickleFds[0]
        << ", EPOLLIN): " << rc << " (" << errno << ")";
    if (rc) {
        close(m_tickleFds[0]);
        close(m_tickleFds[1]);
        close(m_epfd);
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_ctl");
    }
}
Example #5
0
void
EventLoop::tickle()
{
    MORDOR_LOG_TRACE(g_log) << m_messageWindow << " tickling";
    if (!PostMessage(m_messageWindow, g_tickleMessage, 0, 0))
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("PostMessage");
}
Example #6
0
size_t
SSLStream::read(void *buffer, size_t length)
{
    const int toRead = (int)std::min<size_t>(0x0fffffff, length);
    while (true) {
        unsigned long error = SSL_ERROR_NONE;
        const int result = sslCallWithLock(std::bind(SSL_read, m_ssl.get(), buffer, toRead), &error);
        if (result > 0) {
            return result;
        }
        MORDOR_LOG_DEBUG(g_log) << this << " SSL_read(" << m_ssl.get() << ", "
            << toRead << "): " << result << " (" << error << ")";
        switch (error) {
            case SSL_ERROR_NONE:
                return result;
            case SSL_ERROR_ZERO_RETURN:
                // Received close_notify message
                MORDOR_ASSERT(result == 0);
                return 0;
            case SSL_ERROR_WANT_READ:
                wantRead();
                continue;
            case SSL_ERROR_WANT_WRITE:
            case SSL_ERROR_WANT_CONNECT:
            case SSL_ERROR_WANT_ACCEPT:
            case SSL_ERROR_WANT_X509_LOOKUP:
                MORDOR_NOTREACHED();
            case SSL_ERROR_SYSCALL:
                if (hasOpenSSLError()) {
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_read("
                        << m_ssl.get() << ", " << toRead << "): " << result
                        << " (" << error << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                       // << boost::errinfo_api_function("SSL_read");
                    ;
                }
                MORDOR_LOG_WARNING(g_log) << this << " SSL_read("
                    << m_ssl.get() << ", " << toRead << "): " << result
                    << " (" << error << ")";
                if (result == 0) {
                    return 0;
                }
                MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_read");
            case SSL_ERROR_SSL:
                {
                    MORDOR_ASSERT(hasOpenSSLError());
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_read("
                        << m_ssl.get() << ", " << toRead << "): " << result
                        << " (" << error << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                      //  << boost::errinfo_api_function("SSL_read");
                    ;
                }
            default:
                MORDOR_NOTREACHED();
        }
    }
}
Example #7
0
EventLoop::Initializer::Initializer()
{
    WNDCLASSW wndClass;
    memset(&wndClass, 0, sizeof(wndClass));
    wndClass.lpfnWndProc = &EventLoop::wndProc;
    wndClass.hInstance = GetModuleHandleW(NULL);
    wndClass.lpszClassName = L"MordorEventLoop";
    if (!RegisterClassW(&wndClass))
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("RegisterClassW");
}
Example #8
0
void
HandleStream::cancelRead()
{
    m_cancelRead = true;
    if (m_ioManager) {
        m_ioManager->cancelEvent(m_hFile, &m_readEvent);
    } else {
        if (!pCancelIoEx(m_hFile, NULL))
            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("CancelIoEx");
    }
}
Example #9
0
void
EventLoop::onTimerInsertedAtFront()
{
    unsigned long long next = nextTimer();
    MORDOR_ASSERT(next != ~0ull);
    UINT uElapse = (UINT)((next / 1000) + 1);
    uElapse = std::max<UINT>(USER_TIMER_MINIMUM, uElapse);
    uElapse = std::min<UINT>(USER_TIMER_MAXIMUM, uElapse);
    if (!SetTimer(m_messageWindow, 1, uElapse, NULL))
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SetTimer");
}
Example #10
0
size_t
HandleStream::write(const void *buffer, size_t length)
{
    if (m_cancelWrite)
        MORDOR_THROW_EXCEPTION(OperationAbortedException());
    SchedulerSwitcher switcher(m_ioManager ? NULL : m_scheduler);
    DWORD written;
    OVERLAPPED *overlapped = NULL;
    if (m_ioManager) {
        MORDOR_ASSERT(Scheduler::getThis());
        m_ioManager->registerEvent(&m_writeEvent);
        overlapped = &m_writeEvent.overlapped;
        if (supportsSeek()) {
            overlapped->Offset = (DWORD)m_pos;
            overlapped->OffsetHigh = (DWORD)(m_pos >> 32);
        }
    }
    length = (std::min)(length, m_maxOpSize);
    BOOL ret = WriteFile(m_hFile, buffer, (DWORD)length, &written, overlapped);
    Log::Level level = Log::DEBUG;
    if (!ret) {
        if (m_ioManager && GetLastError() == ERROR_IO_PENDING)
            level = Log::TRACE;
        else
            level = Log::ERROR;
    }
    DWORD error = GetLastError();
    MORDOR_LOG_LEVEL(g_log, level) << this << " WriteFile(" << m_hFile << ", "
        << length << "): " << ret << " - " << written << " (" << error << ")";
    if (m_ioManager) {
        if (!ret && error != ERROR_IO_PENDING) {
            m_ioManager->unregisterEvent(&m_writeEvent);
            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("WriteFile");
        }
        if (m_skipCompletionPortOnSuccess && ret)
            m_ioManager->unregisterEvent(&m_writeEvent);
        else
            Scheduler::yieldTo();
        DWORD error = pRtlNtStatusToDosError((NTSTATUS)m_writeEvent.overlapped.Internal);
        MORDOR_LOG_LEVEL(g_log, error ? Log::ERROR : Log::VERBOSE) << this
            << " WriteFile(" << m_hFile << ", " << length << "): "
            << m_writeEvent.overlapped.InternalHigh << " (" << error << ")";
        if (error)
            MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "WriteFile");
        if (supportsSeek()) {
            m_pos = ((long long)overlapped->Offset | ((long long)overlapped->OffsetHigh << 32)) +
                m_writeEvent.overlapped.InternalHigh;
        }
        return m_writeEvent.overlapped.InternalHigh;
    }
    if (!ret)
        MORDOR_THROW_EXCEPTION_FROM_ERROR_API(error, "WriteFile");
    return written;
}
Example #11
0
void
HandleStream::cancelWrite()
{
    m_cancelWrite = true;
    if (m_ioManager) {
        m_ioManager->cancelEvent(m_hFile, &m_writeEvent);
    } else {
        MORDOR_ASSERT(supportsCancel());
        if (!pCancelIoEx(m_hFile, NULL))
            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("CancelIoEx");
    }
}
Example #12
0
LRESULT CALLBACK
EventLoop::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    EventLoop *self = (EventLoop *)Scheduler::getThis();
    MORDOR_ASSERT(self->m_messageWindow == hWnd ||
        self->m_messageWindow == NULL);

    if (uMsg == g_tickleMessage) {
        MORDOR_LOG_TRACE(g_log) << hWnd << " received tickle";
        Scheduler::yield();
        return 0;
    }

    switch (uMsg) {
        case WM_TIMER:
        {
            MORDOR_LOG_TRACE(g_log) << hWnd << " processing timers";
            std::vector<boost::function<void ()> > expired = self->processTimers();
            if (!expired.empty())
                self->schedule(expired.begin(), expired.end());

            unsigned long long nextTimer = self->nextTimer();
            if (nextTimer != ~0ull) {
                UINT uElapse = (UINT)((nextTimer / 1000) + 1);
                uElapse = std::max<UINT>(USER_TIMER_MINIMUM, uElapse);
                uElapse = std::min<UINT>(USER_TIMER_MAXIMUM, uElapse);
                if (!SetTimer(hWnd, 1, uElapse, NULL))
                    MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SetTimer");
            } else {
                if (!KillTimer(hWnd, 1))
                    MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("KillTimer");
            }

            return 0;
        }
        default:
            return DefWindowProcW(hWnd, uMsg, wParam, lParam);
    }
}
Example #13
0
void
IOManagerEPoll::cancelEvent(int fd, Event events)
{
    boost::mutex::scoped_lock lock(m_mutex);
    std::map<int, AsyncEvent>::iterator it = m_pendingEvents.find(fd);
    if (it == m_pendingEvents.end())
        return;
    AsyncEvent &e = it->second;
    if ((events & EPOLLIN) && (e.event.events & EPOLLIN)) {
        if (e.m_dgIn)
            e.m_schedulerIn->schedule(e.m_dgIn);
        else
            e.m_schedulerIn->schedule(e.m_fiberIn);
        e.m_dgIn = NULL;
        e.m_fiberIn.reset();
    }
    if ((events & EPOLLOUT) && (e.event.events & EPOLLOUT)) {
        if (e.m_dgOut)
            e.m_schedulerOut->schedule(e.m_dgOut);
        else
            e.m_schedulerOut->schedule(e.m_fiberOut);
        e.m_dgOut = NULL;
        e.m_fiberOut.reset();
    }
    if ((events & EPOLLHUP) && (e.event.events & EPOLLHUP)) {
        if (e.m_dgClose)
            e.m_schedulerClose->schedule(e.m_dgClose);
        else
            e.m_schedulerClose->schedule(e.m_fiberClose);
        e.m_dgClose = NULL;
        e.m_fiberClose.reset();
    }
    if ((events & EPOLLERR) && (e.event.events & EPOLLERR)) {
        if (e.m_dgError)
            e.m_schedulerError->schedule(e.m_dgError);
        else
            e.m_schedulerError->schedule(e.m_fiberError);
        e.m_dgError = NULL;
        e.m_fiberError.reset();
    }
    e.event.events &= ~events;
    int op = e.event.events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
    int rc = epoll_ctl(m_epfd, op, fd, &e.event);
    MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this
        << " epoll_ctl(" << m_epfd << ", " << (epoll_ctl_op_t)op << ", " << fd
        << ", " << (epoll_events_t)e.event.events << "): " << rc << " (" << errno << ")";
    if (op == EPOLL_CTL_DEL)
        m_pendingEvents.erase(it);
    if (rc)
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_ctl");
}
Example #14
0
void
EventLoop::messagePump()
{
    MORDOR_LOG_DEBUG(g_log) << m_messageWindow << " starting message pump";
    while (!hasWorkToDo() && !stopping()) {
        MSG msg;
        BOOL bRet = GetMessageW(&msg, NULL, 0, 0);
        if (bRet < 0)
            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("GetMessageW");
        if (bRet == 0) {
            stop();
            return;
        }
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
    MORDOR_LOG_DEBUG(g_log) << m_messageWindow << " exiting message pump";
}
Example #15
0
void
sleep(unsigned long long us)
{
#ifdef WINDOWS
    Sleep((DWORD)(us / 1000));
#else
    struct timespec ts;
    ts.tv_sec = us / 1000000;
    ts.tv_nsec = (us % 1000) * 1000;
    while (true) {
        if (nanosleep(&ts, &ts) == -1) {
            if (errno == EINTR)
                continue;
            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("nanosleep");
        }
        break;
    }
#endif
}
Example #16
0
void
IOManagerEPoll::registerEvent(int fd, Event events, boost::function<void ()> dg)
{
    MORDOR_ASSERT(fd > 0);
    MORDOR_ASSERT(Scheduler::getThis());
    MORDOR_ASSERT(Fiber::getThis());

    int epollevents = (int)events & (EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR);
    MORDOR_ASSERT(epollevents != 0);
    boost::mutex::scoped_lock lock(m_mutex);
    int op;
    std::map<int, AsyncEvent>::iterator it = m_pendingEvents.find(fd);
    AsyncEvent *event;
    if (it == m_pendingEvents.end()) {
        op = EPOLL_CTL_ADD;
        event = &m_pendingEvents[fd];
        event->event.data.fd = fd;
        event->event.events = epollevents;
    } else {
        op = EPOLL_CTL_MOD;
        event = &it->second;
        // OR == XOR means that none of the same bits were set
        MORDOR_ASSERT((event->event.events | epollevents)
            == (event->event.events ^ epollevents));
        event->event.events |= epollevents;
    }
    if (epollevents & EPOLLIN) {
        event->m_schedulerIn = Scheduler::getThis();
        if (dg) {
            event->m_dgIn = dg;
            event->m_fiberIn.reset();
        } else {
            event->m_dgIn = NULL;
            event->m_fiberIn = Fiber::getThis();
        }
    }
    if (epollevents & EPOLLOUT) {
        event->m_schedulerOut = Scheduler::getThis();
        if (dg) {
            event->m_dgOut = dg;
            event->m_fiberOut.reset();
        } else {
            event->m_dgOut = NULL;
            event->m_fiberOut = Fiber::getThis();
        }
    }
    if (epollevents & EPOLLHUP) {
        event->m_schedulerClose = Scheduler::getThis();
        if (dg) {
            event->m_dgClose = dg;
            event->m_fiberClose.reset();
        } else {
            event->m_dgClose = NULL;
            event->m_fiberClose = Fiber::getThis();
        }
    }
    if (epollevents & EPOLLERR) {
        event->m_schedulerError = Scheduler::getThis();
        if (dg) {
            event->m_dgError = dg;
            event->m_fiberError.reset();
        } else {
            event->m_dgError = NULL;
            event->m_fiberError = Fiber::getThis();
        }
    }
    int rc = epoll_ctl(m_epfd, op, event->event.data.fd, &event->event);
    MORDOR_LOG_LEVEL(g_log, rc ? Log::ERROR : Log::VERBOSE) << this
        << " epoll_ctl(" << m_epfd << ", " << (epoll_ctl_op_t)op << ", "
        << event->event.data.fd << ", " << (epoll_events_t)event->event.events << "): " << rc
        << " (" << errno << ")";
    if (rc)
        MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_ctl");
}
Example #17
0
void
IOManagerEPoll::idle()
{
    epoll_event events[64];
    while (true) {
        unsigned long long nextTimeout;
        if (stopping(nextTimeout))
            return;
        int rc = -1;
        errno = EINTR;
        while (rc < 0 && errno == EINTR) {
            int timeout = -1;
            if (nextTimeout != ~0ull)
                timeout = (int)(nextTimeout / 1000) + 1;
            rc = epoll_wait(m_epfd, events, 64, timeout);
            if (rc < 0 && errno == EINTR)
                nextTimeout = nextTimer();
        }
        MORDOR_LOG_LEVEL(g_log, rc < 0 ? Log::ERROR : Log::VERBOSE) << this
            << " epoll_wait(" << m_epfd << "): " << rc << " (" << errno << ")";
        if (rc < 0)
            MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_wait");
        std::vector<boost::function<void ()> > expired = processTimers();
        schedule(expired.begin(), expired.end());

        for(int i = 0; i < rc; ++i) {
            epoll_event &event = events[i];
            if (event.data.fd == m_tickleFds[0]) {
                unsigned char dummy;
                int rc2 = read(m_tickleFds[0], &dummy, 1);
                MORDOR_VERIFY(rc2 == 1);
                MORDOR_LOG_VERBOSE(g_log) << this << " received tickle";
                continue;
            }
            bool err = event.events & (EPOLLERR | EPOLLHUP);
            boost::mutex::scoped_lock lock(m_mutex);
            std::map<int, AsyncEvent>::iterator it =
m_pendingEvents.find(event.data.fd);
            if (it == m_pendingEvents.end())
                continue;
            AsyncEvent &e = it->second;
            MORDOR_LOG_TRACE(g_log) << " epoll_event {"
                << (epoll_events_t)event.events << ", " << event.data.fd
                << "}, registered for " << (epoll_events_t)e.event.events;
            if ((event.events & EPOLLERR) && (e.event.events & EPOLLERR)) {
                if (e.m_dgError)
                    e.m_schedulerError->schedule(e.m_dgError);
                else
                    e.m_schedulerError->schedule(e.m_fiberError);
                // Block other events from firing
                e.m_dgError = NULL;
                e.m_fiberError.reset();
                e.m_dgIn = NULL;
                e.m_fiberIn.reset();
                e.m_dgOut = NULL;
                e.m_fiberOut.reset();
                event.events = 0;
                e.event.events = 0;
            }
            if ((event.events & EPOLLHUP) && (e.event.events & EPOLLHUP)) {
                if (e.m_dgClose)
                    e.m_schedulerError->schedule(e.m_dgClose);
                else
                    e.m_schedulerError->schedule(e.m_fiberClose);
                // Block write event from firing
                e.m_dgOut = NULL;
                e.m_fiberOut.reset();
                e.m_dgClose = NULL;
                e.m_fiberClose.reset();
                event.events &= EPOLLOUT;
                e.event.events &= EPOLLOUT;
                err = false;
            }

            if (((event.events & EPOLLIN) ||
                err) && (e.event.events & EPOLLIN)) {
                if (e.m_dgIn)
                    e.m_schedulerIn->schedule(e.m_dgIn);
                else
                    e.m_schedulerIn->schedule(e.m_fiberIn);
                e.m_dgIn = NULL;
                e.m_fiberIn.reset();
                event.events |= EPOLLIN;
            }
            if (((event.events & EPOLLOUT) ||
                err) && (e.event.events & EPOLLOUT)) {
                if (e.m_dgOut)
                    e.m_schedulerOut->schedule(e.m_dgOut);
                else
                    e.m_schedulerOut->schedule(e.m_fiberOut);
                e.m_dgOut = NULL;
                e.m_fiberOut.reset();
                event.events |= EPOLLOUT;
            }
            e.event.events &= ~event.events;

            int op = e.event.events == 0 ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
            int rc2 = epoll_ctl(m_epfd, op, event.data.fd,
                &e.event);
            MORDOR_LOG_LEVEL(g_log, rc2 ? Log::ERROR : Log::VERBOSE) << this
                << " epoll_ctl(" << m_epfd << ", " << (epoll_ctl_op_t)op << ", "
                << event.data.fd << ", " << (epoll_events_t)e.event.events << "): " << rc2
                << " (" << errno << ")";
            if (rc2)
                MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("epoll_ctl");
            if (op == EPOLL_CTL_DEL)
                m_pendingEvents.erase(it);
        }
        Fiber::yield();
    }
}
Example #18
0
void
SSLStream::connect()
{
    while (true) {
        unsigned long error = SSL_ERROR_NONE;
        const int result = sslCallWithLock(std::bind(SSL_connect, m_ssl.get()), &error);
        MORDOR_LOG_DEBUG(g_log) << this << " SSL_connect(" << m_ssl.get()
            << "): " << result << " (" << error << ")";
        if (result > 0) {
            flush(false);
            return;
        }
        switch (error) {
            case SSL_ERROR_NONE:
                flush(false);
                return;
            case SSL_ERROR_ZERO_RETURN:
                // Received close_notify message
                return;
            case SSL_ERROR_WANT_READ:
                flush();
                wantRead();
                continue;
            case SSL_ERROR_WANT_WRITE:
            case SSL_ERROR_WANT_CONNECT:
            case SSL_ERROR_WANT_ACCEPT:
            case SSL_ERROR_WANT_X509_LOOKUP:
                MORDOR_NOTREACHED();
            case SSL_ERROR_SYSCALL:
                if (hasOpenSSLError()) {
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_connect("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                       // << boost::errinfo_api_function("SSL_connect");
                    ;
                }
                MORDOR_LOG_ERROR(g_log) << this << " SSL_connect("
                    << m_ssl.get() << "): " << result << " (" << error
                    << ")";
                if (result == 0) {
                    MORDOR_THROW_EXCEPTION(UnexpectedEofException());
                }
                MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_connect");
            case SSL_ERROR_SSL:
                {
                    MORDOR_ASSERT(hasOpenSSLError());
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_connect("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                      //  << boost::errinfo_api_function("SSL_connect");
                    ;
                }
            default:
                MORDOR_NOTREACHED();
        }
    }
}
Example #19
0
void
SSLStream::close(CloseType type)
{
    MORDOR_ASSERT(type == BOTH);
    if (!(sslCallWithLock(std::bind(SSL_get_shutdown, m_ssl.get()), NULL) & SSL_SENT_SHUTDOWN)) {
        unsigned long error = SSL_ERROR_NONE;
        const int result = sslCallWithLock(std::bind(SSL_shutdown, m_ssl.get()), &error);
        if (result <= 0) {
            MORDOR_LOG_DEBUG(g_log) << this << " SSL_shutdown(" << m_ssl.get()
                << "): " << result << " (" << error << ")";
            switch (error) {
                case SSL_ERROR_NONE:
                case SSL_ERROR_ZERO_RETURN:
                    break;
                case SSL_ERROR_WANT_READ:
                case SSL_ERROR_WANT_WRITE:
                case SSL_ERROR_WANT_CONNECT:
                case SSL_ERROR_WANT_ACCEPT:
                case SSL_ERROR_WANT_X509_LOOKUP:
                    MORDOR_NOTREACHED();
                case SSL_ERROR_SYSCALL:
                    if (hasOpenSSLError()) {
                        std::string message = getOpenSSLErrorMessage();
                        MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                            << m_ssl.get() << "): " << result << " (" << error
                            << ", " << message << ")";
                        MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                           // << boost::errinfo_api_function("SSL_shutdown");
                        ;
                    }
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ")";
                    if (result == 0)
                        break;
                    MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_shutdown");
                case SSL_ERROR_SSL:
                    {
                        MORDOR_ASSERT(hasOpenSSLError());
                        std::string message = getOpenSSLErrorMessage();
                        MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                            << m_ssl.get() << "): " << result << " (" << error
                            << ", " << message << ")";
                        MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                          //  << boost::errinfo_api_function("SSL_shutdown");
                        ;
                    }
                default:
                    MORDOR_NOTREACHED();
            }
        }
        flush(false);
    }

    while (!(sslCallWithLock(std::bind(SSL_get_shutdown, m_ssl.get()), NULL) & SSL_RECEIVED_SHUTDOWN)) {
        unsigned long error = SSL_ERROR_NONE;
        const int result = sslCallWithLock(std::bind(SSL_shutdown, m_ssl.get()), &error);
        MORDOR_LOG_DEBUG(g_log) << this << " SSL_shutdown(" << m_ssl.get()
            << "): " << result << " (" << error << ")";
        if (result > 0) {
            break;
        }
        switch (error) {
            case SSL_ERROR_NONE:
            case SSL_ERROR_ZERO_RETURN:
                break;
            case SSL_ERROR_WANT_READ:
                flush();
                wantRead();
                continue;
            case SSL_ERROR_WANT_WRITE:
            case SSL_ERROR_WANT_CONNECT:
            case SSL_ERROR_WANT_ACCEPT:
            case SSL_ERROR_WANT_X509_LOOKUP:
                MORDOR_NOTREACHED();
            case SSL_ERROR_SYSCALL:
                if (hasOpenSSLError()) {
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                       // << boost::errinfo_api_function("SSL_shutdown");
                    ;
                }
                MORDOR_LOG_WARNING(g_log) << this << " SSL_shutdown(" << m_ssl.get()
                    << "): " << result << " (" << error << ")";
                if (result == 0) {
                    break;
                }
                MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_shutdown");
            case SSL_ERROR_SSL:
                {
                    MORDOR_ASSERT(hasOpenSSLError());
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_shutdown("
                        << m_ssl.get() << "): " << result << " (" << error
                        << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                      //  << boost::errinfo_api_function("SSL_shutdown");
                    ;
                }
            default:
                MORDOR_NOTREACHED();
        }
        break;
    }
    parent()->close();
}