コード例 #1
0
ファイル: ssl.cpp プロジェクト: zalemwoo/mordor-base
void
SSLStream::flush(bool flushParent)
{
    static const int WRITE_BUF_LENGTH = 4096;
    char writeBuf[WRITE_BUF_LENGTH];
    int toWrite = 0;
    do {
        toWrite = BIO_read(m_writeBio, (void *)writeBuf, WRITE_BUF_LENGTH);
        if (toWrite > 0) {
            m_writeBuffer.copyIn((const void *)writeBuf, toWrite);
        }
    } while (toWrite > 0);

    if (m_writeBuffer.readAvailable() == 0)
        return;

    while (m_writeBuffer.readAvailable()) {
        MORDOR_LOG_TRACE(g_log) << this << " parent()->write("
            << m_writeBuffer.readAvailable() << ")";
        size_t written = parent()->write(m_writeBuffer,
            m_writeBuffer.readAvailable());
        MORDOR_LOG_TRACE(g_log) << this << " parent()->write("
            << m_writeBuffer.readAvailable() << "): " << written;
        m_writeBuffer.consume(written);
    }

    if (flushParent)
        parent()->flush(flushParent);
}
コード例 #2
0
ファイル: buffered.cpp プロジェクト: adfin/mordor
ptrdiff_t
BufferedStream::find(const std::string &str, size_t sanitySize, bool throwIfNotFound)
{
    if (supportsSeek())
        flush(false);
    if (sanitySize == (size_t)~0)
        sanitySize = 2 * m_bufferSize;
    sanitySize += str.size();
    while (true) {
        size_t readAvailable = m_readBuffer.readAvailable();
        if (readAvailable > 0) {
            ptrdiff_t result = m_readBuffer.find(str, std::min(sanitySize, readAvailable));
            if (result != -1) {
                return result;
            }
        }
        if (readAvailable >= sanitySize) {
            if (throwIfNotFound)
                MORDOR_THROW_EXCEPTION(BufferOverflowException());
            return -(ptrdiff_t)m_readBuffer.readAvailable() - 1;
        }

        MORDOR_LOG_TRACE(g_log) << this << " parent()->read(" << m_bufferSize
            << ")";
        size_t result = parent()->read(m_readBuffer, m_bufferSize);
        MORDOR_LOG_DEBUG(g_log) << this << " parent()->read(" << m_bufferSize
            << "): " << result;
        if (result == 0) {
            // EOF
            if (throwIfNotFound)
                MORDOR_THROW_EXCEPTION(UnexpectedEofException());
            return -(ptrdiff_t)m_readBuffer.readAvailable() - 1;
        }
    }
}
コード例 #3
0
ファイル: eventloop.cpp プロジェクト: Abioy/mordor
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");
}
コード例 #4
0
ファイル: iomanager_epoll.cpp プロジェクト: adfin/mordor
IOManagerEPoll::~IOManagerEPoll()
{
    stop();
    close(m_epfd);
    MORDOR_LOG_TRACE(g_log) << this << " close(" << m_epfd << ")";
    close(m_tickleFds[0]);
    MORDOR_LOG_VERBOSE(g_log) << this << " close(" << m_tickleFds[0] << ")";
    close(m_tickleFds[1]);
}
コード例 #5
0
ファイル: timer.cpp プロジェクト: fathomdb/mordor
std::vector<boost::function<void ()> >
TimerManager::processTimers()
{
    std::vector<Timer::ptr> expired;
    std::vector<boost::function<void ()> > result;
    unsigned long long nowUs = now();
    {
        boost::mutex::scoped_lock lock(m_mutex);
        if (m_timers.empty())
            return result;
        bool rollover = detectClockRollover(nowUs);
        if (!rollover && (*m_timers.begin())->m_next > nowUs)
            return result;
        Timer nowTimer(nowUs);
        Timer::ptr nowTimerPtr(&nowTimer, &nop<Timer *>);
        // Find all timers that are expired
        std::set<Timer::ptr, Timer::Comparator>::iterator it =
            rollover ? m_timers.end() : m_timers.lower_bound(nowTimerPtr);
        while (it != m_timers.end() && (*it)->m_next == nowUs ) ++it;
        // Copy to expired, remove from m_timers;
        expired.insert(expired.begin(), m_timers.begin(), it);
        m_timers.erase(m_timers.begin(), it);
        result.reserve(expired.size());
        // Look at expired timers and re-register recurring timers
        // (while under the same lock)
        for (std::vector<Timer::ptr>::iterator it2(expired.begin());
            it2 != expired.end();
            ++it2) {
            Timer::ptr &timer = *it2;
            MORDOR_ASSERT(timer->m_dg);
            result.push_back(timer->m_dg);
            if (timer->m_recurring) {
                MORDOR_LOG_TRACE(g_log) << timer << " expired and refreshed";
                timer->m_next = nowUs + timer->m_us;
                m_timers.insert(timer);
            } else {
                MORDOR_LOG_TRACE(g_log) << timer << " expired";
                timer->m_dg = NULL;
            }
        }
    }
    return result;
}
コード例 #6
0
ファイル: eventloop.cpp プロジェクト: Abioy/mordor
LRESULT CALLBACK
EventLoop::foregroundIdleProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    EventLoop *self = (EventLoop *)Scheduler::getThis();

    MORDOR_LOG_TRACE(g_log) << self->m_messageWindow << " message pump idle";
    if (self->hasWorkToDo())
        self->tickle();

    return CallNextHookEx(self->m_idleHook, nCode, wParam, lParam);
}
コード例 #7
0
ファイル: ssl.cpp プロジェクト: zalemwoo/mordor-base
void
SSLStream::wantRead()
{
    if (m_readBuffer.readAvailable() == 0) {
        MORDOR_LOG_TRACE(g_log) << this << " parent()->read(32768)";
        const size_t result = parent()->read(m_readBuffer, 32768);
        MORDOR_LOG_TRACE(g_log) << this << " parent()->read(32768): " << result;
        if (result == 0) {
            BIO_set_mem_eof_return(m_readBio, 0);
            return;
        }
    }
    MORDOR_ASSERT(m_readBuffer.readAvailable());
    const iovec iov = m_readBuffer.readBuffer(~0, false);
    MORDOR_ASSERT(iov.iov_len > 0);
    const int written = BIO_write(m_readBio, (char *)iov.iov_base, iov.iov_len);
    MORDOR_ASSERT(written > 0);
    if (written > 0) {
        m_readBuffer.consume(written);
    }
    MORDOR_LOG_DEBUG(g_log) << this << " wantRead(): " << written;
}
コード例 #8
0
ファイル: eventloop.cpp プロジェクト: Abioy/mordor
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);
    }
}
コード例 #9
0
ファイル: buffered.cpp プロジェクト: adfin/mordor
size_t
BufferedStream::readInternal(T &buffer, size_t length)
{
    if (supportsSeek())
        flush(false);
    size_t remaining = length;

    size_t buffered = std::min(m_readBuffer.readAvailable(), remaining);
    m_readBuffer.copyOut(buffer, buffered);
    m_readBuffer.consume(buffered);
    remaining -= buffered;

    MORDOR_LOG_VERBOSE(g_log) << this << " read(" << length << "): "
        << buffered << " read from buffer";

    if (remaining == 0)
        return length;

    if (buffered == 0 || !m_allowPartialReads) {
        size_t result;
        do {
            // Read enough to satisfy this request, plus up to a multiple of
            // the buffer size
            size_t todo = ((remaining - 1) / m_bufferSize + 1) * m_bufferSize;
            try {
                MORDOR_LOG_TRACE(g_log) << this << " parent()->read(" << todo
                    << ")";
                result = parent()->read(m_readBuffer, todo);
                MORDOR_LOG_DEBUG(g_log) << this << " parent()->read(" << todo
                    << "): " << result;
            } catch (...) {
                if (remaining == length) {
                    MORDOR_LOG_VERBOSE(g_log) << this << " forwarding exception";
                    throw;
                } else {
                    MORDOR_LOG_VERBOSE(g_log) << this << " swallowing exception";
                    // Swallow the exception
                    return length - remaining;
                }
            }

            buffered = std::min(m_readBuffer.readAvailable(), remaining);
            m_readBuffer.copyOut(buffer, buffered);
            m_readBuffer.consume(buffered);
            advance(buffer, buffered);
            remaining -= buffered;
        } while (remaining > 0 && !m_allowPartialReads && result != 0);
    }

    return length - remaining;
}
コード例 #10
0
ファイル: buffered.cpp プロジェクト: adfin/mordor
size_t
BufferedStream::flushWrite(size_t length)
{
    while (m_writeBuffer.readAvailable() >= m_bufferSize)
    {
        size_t result;
        try {
            if (m_readBuffer.readAvailable() && supportsSeek()) {
                parent()->seek(-(long long)m_readBuffer.readAvailable(), CURRENT);
                m_readBuffer.clear();
            }
            size_t toWrite = m_writeBuffer.readAvailable();
            if (m_flushMultiplesOfBuffer)
                toWrite = toWrite / m_bufferSize * m_bufferSize;
            MORDOR_LOG_TRACE(g_log) << this << " parent()->write("
                << m_writeBuffer.readAvailable() << ")";
            result = parent()->write(m_writeBuffer, toWrite);
            MORDOR_LOG_DEBUG(g_log) << this << " parent()->write("
                << m_writeBuffer.readAvailable() << "): " << result;
            m_writeBuffer.consume(result);
        } catch (...) {
            // If this entire write is still in our buffer,
            // back it out and report the error
            if (m_writeBuffer.readAvailable() >= length) {
                MORDOR_LOG_VERBOSE(g_log) << this << " forwarding exception";
                Buffer tempBuffer;
                tempBuffer.copyIn(m_writeBuffer, m_writeBuffer.readAvailable()
                    - length);
                m_writeBuffer.clear();
                m_writeBuffer.copyIn(tempBuffer);
                throw;
            } else {
                // Otherwise we have to say we succeeded,
                // because we're not allowed to have a partial
                // write, and we can't report an error because
                // the caller will think he needs to repeat
                // the entire write
                MORDOR_LOG_VERBOSE(g_log) << this << " swallowing exception";
                return length;
            }
        }
    }
    return length;
}
コード例 #11
0
ファイル: buffered.cpp プロジェクト: adfin/mordor
void
BufferedStream::flush(bool flushParent)
{
    while (m_writeBuffer.readAvailable()) {
        if (m_readBuffer.readAvailable() && supportsSeek()) {
            parent()->seek(-(long long)m_readBuffer.readAvailable(), CURRENT);
            m_readBuffer.clear();
        }
        MORDOR_LOG_TRACE(g_log) << this << " parent()->write("
            << m_writeBuffer.readAvailable() << ")";
        size_t result = parent()->write(m_writeBuffer, m_writeBuffer.readAvailable());
        MORDOR_LOG_DEBUG(g_log) << this << " parent()->write("
            << m_writeBuffer.readAvailable() << "): " << result;
        MORDOR_ASSERT(result > 0);
        m_writeBuffer.consume(result);
    }
    if (flushParent)
        parent()->flush();
}
コード例 #12
0
ファイル: negotiate.cpp プロジェクト: Abioy/mordor
bool
NegotiateAuth::authorize(const AuthParams &challenge, AuthParams &authorization,
    const URI &uri)
{
    SECURITY_STATUS status;
    std::wstring packageW = toUtf16(challenge.scheme);
    std::string param = challenge.base64;

    std::string outboundBuffer;
    SecBufferDesc outboundBufferDesc;
    SecBuffer outboundSecBuffer;
    TimeStamp lifetime;
    ULONG contextAttributes;

    outboundBuffer.resize(4096);
    outboundBufferDesc.ulVersion = 0;
    outboundBufferDesc.cBuffers = 1;
    outboundBufferDesc.pBuffers = &outboundSecBuffer;
    outboundSecBuffer.BufferType = SECBUFFER_TOKEN;
    outboundSecBuffer.pvBuffer = &outboundBuffer[0];
    outboundSecBuffer.cbBuffer = (unsigned long)outboundBuffer.size();

    if (param.empty()) {
        // No response from server; we're starting a new session
        if (SecIsValidHandle(&m_creds))
            return false;

        SEC_WINNT_AUTH_IDENTITY_W id;
        id.User = (unsigned short *)m_username.c_str();
        id.UserLength = (unsigned long)m_username.size();
        id.Domain = (unsigned short *)m_domain.c_str();
        id.DomainLength = (unsigned long)m_domain.size();
        id.Password = (unsigned short *)m_password.c_str();
        id.PasswordLength = (unsigned long)m_password.size();
        id.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
        status = AcquireCredentialsHandleW(NULL,
            (wchar_t *)packageW.c_str(),
            SECPKG_CRED_OUTBOUND,
            NULL,
            m_username.empty() ? NULL : &id,
            NULL,
            NULL,
            &m_creds,
            &lifetime);
        MORDOR_LOG_TRACE(g_log) << "AcquireCredentialsHandleW("
            << challenge.scheme << ", " << toUtf8(m_username) << "): ("
            << status << ")";
        if (!SUCCEEDED(status))
            MORDOR_THROW_EXCEPTION_FROM_ERROR_API(status, "AcquireCredentialsHandleW");

        status = InitializeSecurityContextW(
            &m_creds,
            NULL,
            (wchar_t *)toUtf16(uri.toString()).c_str(),
            ISC_REQ_CONFIDENTIALITY,
            0,
            SECURITY_NATIVE_DREP,
            NULL,
            0,
            &m_secCtx,
            &outboundBufferDesc,
            &contextAttributes,
            &lifetime);
        MORDOR_LOG_TRACE(g_log) << "InitializeSecurityContextW("
            << uri << ", {0}):  {" << outboundSecBuffer.cbBuffer << "} ("
            << status << ")";
    } else {
        // Prepare the response from the server
        std::string inboundBuffer = base64decode(param);
        SecBufferDesc inboundBufferDesc;
        SecBuffer inboundSecBuffer;

        inboundBufferDesc.ulVersion = 0;
        inboundBufferDesc.cBuffers = 1;
        inboundBufferDesc.pBuffers = &inboundSecBuffer;
        inboundSecBuffer.BufferType = SECBUFFER_TOKEN;
        inboundSecBuffer.pvBuffer = &inboundBuffer[0];
        inboundSecBuffer.cbBuffer = (unsigned long)inboundBuffer.size();

        status = InitializeSecurityContextW(
            &m_creds,
            &m_secCtx,
            (wchar_t *)toUtf16(uri.toString()).c_str(),
            ISC_REQ_CONFIDENTIALITY,
            0,
            SECURITY_NATIVE_DREP,
            &inboundBufferDesc,
            0,
            &m_secCtx,
            &outboundBufferDesc,
            &contextAttributes,
            &lifetime);
        MORDOR_LOG_TRACE(g_log) << "InitializeSecurityContextW("
            << uri << ", {" << inboundSecBuffer.cbBuffer << "}):  {"
            << outboundSecBuffer.cbBuffer << "} (" << status << ")";
    }

    if (status == SEC_I_COMPLETE_NEEDED ||
        status == SEC_I_COMPLETE_AND_CONTINUE) {
        status = CompleteAuthToken(&m_secCtx, &outboundBufferDesc);
        MORDOR_LOG_TRACE(g_log) << "CompleteAuthToken(): {"
            << outboundSecBuffer.cbBuffer << "} (" << status << ")";
    }

    if (!SUCCEEDED(status))
        MORDOR_THROW_EXCEPTION_FROM_ERROR(status);

    outboundBuffer.resize(outboundSecBuffer.cbBuffer);
    authorization.scheme = challenge.scheme;
    authorization.base64 = base64encode(outboundBuffer);
    authorization.parameters.clear();
    return true;
}
コード例 #13
0
ファイル: iomanager_epoll.cpp プロジェクト: adfin/mordor
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();
    }
}