Exemplo n.º 1
0
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;
        }
    }
}
Exemplo n.º 2
0
bool
Timer::reset(unsigned long long us, bool fromNow)
{
    boost::mutex::scoped_lock lock(m_manager->m_mutex);
    if (!m_dg)
        return false;
    // No change
    if (us == m_us && !fromNow)
        return true;
    std::set<Timer::ptr, Timer::Comparator>::iterator it =
        m_manager->m_timers.find(shared_from_this());
    MORDOR_ASSERT(it != m_manager->m_timers.end());
    m_manager->m_timers.erase(it);
    unsigned long long start;
    if (fromNow)
        start = TimerManager::now();
    else
        start = m_next - m_us;
    m_us = us;
    m_next = start + m_us;
    it = m_manager->m_timers.insert(shared_from_this()).first;
    bool atFront = (it == m_manager->m_timers.begin()) && !m_manager->m_tickled;
    if (atFront)
        m_manager->m_tickled = true;
    lock.unlock();
    MORDOR_LOG_DEBUG(g_log) << this << " reset to " << m_us;
    if (atFront)
        m_manager->onTimerInsertedAtFront();
    return true;
}
Exemplo n.º 3
0
void
ZlibStream::flush(int flush)
{
    flushBuffer();
    while (true) {
        if (m_outBuffer.writeAvailable() == 0)
            m_outBuffer.reserve(m_bufferSize);
        struct iovec outbuf = m_outBuffer.writeBuffer(~0u, false);
        MORDOR_ASSERT(m_strm.avail_in == 0);
        m_strm.next_out = (Bytef*)outbuf.iov_base;
        m_strm.avail_out = outbuf.iov_len;
        int rc = deflate(&m_strm, flush);
        MORDOR_ASSERT(m_strm.avail_in == 0);
        MORDOR_LOG_DEBUG(g_log) << this << " deflate((0, " << outbuf.iov_len
            << "), " << flush << "): " << rc << " (0, " << m_strm.avail_out
            << ")";
        m_outBuffer.produce(outbuf.iov_len - m_strm.avail_out);
        MORDOR_ASSERT(flush == Z_FINISH || rc != Z_STREAM_END);
        switch (rc) {
            case Z_STREAM_END:
                m_closed = true;
                deflateEnd(&m_strm);
                flushBuffer();
                return;
            case Z_OK:
                break;
            case Z_BUF_ERROR:
                flushBuffer();
                return;
            default:
                MORDOR_NOTREACHED();
        }
    }
}
Exemplo n.º 4
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();
        }
    }
}
Exemplo n.º 5
0
void
EventLoop::idle()
{
    while (!stopping()) {
        MORDOR_LOG_DEBUG(g_log) << m_messageWindow << " Starting new message pump";
        schedule(boost::bind(&EventLoop::messagePump, this));
        Fiber::yield();
    }
}
Exemplo n.º 6
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";
}
Exemplo n.º 7
0
unsigned long long
TimerManager::nextTimer()
{
    boost::mutex::scoped_lock lock(m_mutex);
    m_tickled = false;
    if (m_timers.empty()) {
        MORDOR_LOG_DEBUG(g_log) << this << " nextTimer(): ~0ull";
        return ~0ull;
    }
    const Timer::ptr &next = *m_timers.begin();
    unsigned long long nowUs = now();
    unsigned long long result;
    if (nowUs >= next->m_next)
        result = 0;
    else
        result = next->m_next - nowUs;
    MORDOR_LOG_DEBUG(g_log) << this << " nextTimer(): " << result;
    return result;
}
Exemplo n.º 8
0
void
Scheduler::dispatch()
{
    MORDOR_LOG_DEBUG(g_log) << this << " dispatching";
    MORDOR_ASSERT(m_rootThread == gettid() && m_threadCount == 0);
    m_stopping = true;
    m_autoStop = true;
    yieldTo();
    m_autoStop = false;
}
Exemplo n.º 9
0
static void
stubOnTimer(
    boost::weak_ptr<void> weakCond, boost::function<void ()> dg)
{
    boost::shared_ptr<void> temp = weakCond.lock();
    if (temp) {
        dg();
    } else {
        MORDOR_LOG_DEBUG(g_log) << " Conditionally skip in stubOnTimer!";
    }
}
Exemplo n.º 10
0
int Logger::writeLog(std::string& msg, Mordor::Log::Level log_level)
{
    //show all g_logs
    Mordor::Log::visit(boost::bind(&printLogger, &(std::cout), _1));

    MORDOR_LOG_ERROR(g_app_log)<<msg;
    MORDOR_LOG_INFO(g_app_log)<<msg;

    MORDOR_LOG_DEBUG(g_app_log)<<msg; //can not see it by default. should provide some config?
    return 0;
}
Exemplo n.º 11
0
void
Scheduler::switchTo(tid_t thread)
{
    MORDOR_ASSERT(Scheduler::getThis() != NULL);
    if (Scheduler::getThis() == this) {
        if (thread == emptytid() || thread == gettid())
            return;
    }
    MORDOR_LOG_DEBUG(g_log) << this << " switching to thread " << thread;
    schedule(Fiber::getThis(), thread);
    Scheduler::yieldTo();
}
Exemplo n.º 12
0
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;
}
Exemplo n.º 13
0
bool
Scheduler::scheduleNoLock(boost::function<void ()> dg, tid_t thread)
{
    MORDOR_LOG_DEBUG(g_log) << this << " scheduling " << dg << " on thread "
        << thread;
    MORDOR_ASSERT(dg);
    // Not thread-targeted, or this scheduler owns the targetted thread
    MORDOR_ASSERT(thread == emptytid() || thread == m_rootThread ||
        contains(m_threads, thread));
    FiberAndThread ft = {Fiber::ptr(), dg, thread };
    bool tickleMe = m_fibers.empty();
    m_fibers.push_back(ft);
    return tickleMe;
}
Exemplo n.º 14
0
bool
Timer::cancel()
{
    MORDOR_LOG_DEBUG(g_log) << this << " cancel";
    boost::mutex::scoped_lock lock(m_manager->m_mutex);
    if (m_dg) {
        m_dg = NULL;
        std::set<Timer::ptr, Timer::Comparator>::iterator it =
            m_manager->m_timers.find(shared_from_this());
        MORDOR_ASSERT(it != m_manager->m_timers.end());
        m_manager->m_timers.erase(it);
        return true;
    }
    return false;
}
Exemplo n.º 15
0
void
Scheduler::yieldTo()
{
    Scheduler *self = Scheduler::getThis();
    MORDOR_ASSERT(self);
    MORDOR_LOG_DEBUG(g_log) << self << " yielding to scheduler";
    MORDOR_ASSERT(t_fiber.get());
    if (self->m_rootThread == gettid() &&
        (t_fiber->state() == Fiber::INIT || t_fiber->state() == Fiber::TERM)) {
        self->m_callingFiber = Fiber::getThis();
        self->yieldTo(true);
    } else {
        self->yieldTo(false);
    }
}
Exemplo n.º 16
0
bool
Timer::refresh()
{
    boost::mutex::scoped_lock lock(m_manager->m_mutex);
    if (!m_dg)
        return false;
    std::set<Timer::ptr, Timer::Comparator>::iterator it =
        m_manager->m_timers.find(shared_from_this());
    MORDOR_ASSERT(it != m_manager->m_timers.end());
    m_manager->m_timers.erase(it);
    m_next = TimerManager::now() + m_us;
    m_manager->m_timers.insert(shared_from_this());
    lock.unlock();
    MORDOR_LOG_DEBUG(g_log) << this << " refresh";
    return true;
}
Exemplo n.º 17
0
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;
}
Exemplo n.º 18
0
Timer::ptr
TimerManager::registerTimer(unsigned long long us, boost::function<void ()> dg,
        bool recurring)
{
    MORDOR_ASSERT(dg);
    Timer::ptr result(new Timer(us, dg, recurring, this));
    boost::mutex::scoped_lock lock(m_mutex);
    std::set<Timer::ptr, Timer::Comparator>::iterator it =
        m_timers.insert(result).first;
    bool atFront = (it == m_timers.begin()) && !m_tickled;
    if (atFront)
        m_tickled = true;
    lock.unlock();
    MORDOR_LOG_DEBUG(g_log) << result.get() << " registerTimer(" << us
        << ", " << recurring << "): " << atFront;
    if (atFront)
        onTimerInsertedAtFront();
    return result;
}
Exemplo n.º 19
0
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();
}
Exemplo n.º 20
0
size_t
ZlibStream::write(const Buffer &buffer, size_t length)
{
    MORDOR_ASSERT(!m_closed);
    flushBuffer();
    while (true) {
        if (m_outBuffer.writeAvailable() == 0)
            m_outBuffer.reserve(m_bufferSize);
        struct iovec inbuf = buffer.readBuffer(length, false);
        struct iovec outbuf = m_outBuffer.writeBuffer(~0u, false);
        m_strm.next_in = (Bytef*)inbuf.iov_base;
        m_strm.avail_in = inbuf.iov_len;
        m_strm.next_out = (Bytef*)outbuf.iov_base;
        m_strm.avail_out = outbuf.iov_len;
        int rc = deflate(&m_strm, Z_NO_FLUSH);
        MORDOR_LOG_DEBUG(g_log) << this << " deflate((" << inbuf.iov_len << ", "
            << outbuf.iov_len << "), Z_NO_FLUSH): " << rc << " ("
            << m_strm.avail_in << ", " << m_strm.avail_out << ")";
        // We are always providing both input and output
        MORDOR_ASSERT(rc != Z_BUF_ERROR);
        // We're not doing Z_FINISH, so we shouldn't get EOF
        MORDOR_ASSERT(rc != Z_STREAM_END);
        size_t result;
        switch(rc) {
            case Z_OK:
                result = inbuf.iov_len - m_strm.avail_in;
                if (result == 0)
                    continue;
                m_outBuffer.produce(outbuf.iov_len - m_strm.avail_out);
                try {
                    flushBuffer();
                } catch (std::runtime_error) {
                    // Swallow it
                }
                return result;
            default:
                MORDOR_NOTREACHED();
        }
    }
}
Exemplo n.º 21
0
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;
}
Exemplo n.º 22
0
void
Scheduler::stop()
{
    // Already stopped
    if (m_rootFiber &&
        m_threadCount == 0 &&
        (m_rootFiber->state() == Fiber::TERM || m_rootFiber->state() == Fiber::INIT)) {
        MORDOR_LOG_VERBOSE(g_log) << this << " stopped";
        m_stopping = true;
        // A derived class may inhibit stopping while it has things to do in
        // its idle loop, so we can't break early
        if (stopping())
            return;
    }

    bool exitOnThisFiber = false;
    if (m_rootThread != emptytid()) {
        // A thread-hijacking scheduler must be stopped
        // from within itself to return control to the
        // original thread
        MORDOR_ASSERT(Scheduler::getThis() == this);
        if (Fiber::getThis() == m_callingFiber) {
            exitOnThisFiber = true;
            // First switch to the correct thread
            MORDOR_LOG_DEBUG(g_log) << this
                << " switching to root thread to stop";
            switchTo(m_rootThread);
        }
        if (!m_callingFiber)
            exitOnThisFiber = true;
    } else {
        // A spawned-threads only scheduler cannot be stopped from within
        // itself... who would get control?
        MORDOR_ASSERT(Scheduler::getThis() != this);
    }
    m_stopping = true;
    for (size_t i = 0; i < m_threadCount; ++i)
        tickle();
    if (m_rootFiber && (m_threadCount != 0u || Scheduler::getThis() != this))
        tickle();
    // Wait for all work to stop on this thread
    if (exitOnThisFiber) {
        while (!stopping()) {
            // Give this thread's run fiber a chance to kill itself off
            MORDOR_LOG_DEBUG(g_log) << this
                << " yielding to this thread to stop";
            yieldTo(true);
        }
    }
    // Wait for other threads to stop
    if (exitOnThisFiber ||
        Scheduler::getThis() != this) {
        MORDOR_LOG_DEBUG(g_log) << this
            << " waiting for other threads to stop";
        std::vector<boost::shared_ptr<Thread> > threads;
        {
            boost::mutex::scoped_lock lock(m_mutex);
            threads.swap(m_threads);
        }
        for (std::vector<boost::shared_ptr<Thread> >::const_iterator it
            (threads.begin());
            it != threads.end();
            ++it) {
            (*it)->join();
        }
    }
    MORDOR_LOG_VERBOSE(g_log) << this << " stopped";
}
Exemplo n.º 23
0
void
Scheduler::run()
{
    t_scheduler = this;
    if (gettid() != m_rootThread) {
        // Running in own thread
        t_fiber = Fiber::getThis().get();
    } else {
        // Hijacked a thread
        MORDOR_ASSERT(t_fiber.get() == Fiber::getThis().get());
    }
    Fiber::ptr idleFiber(new Fiber(boost::bind(&Scheduler::idle, this)));
    MORDOR_LOG_VERBOSE(g_log) << this << " starting thread with idle fiber " << idleFiber;
    Fiber::ptr dgFiber;
    // use a vector for O(1) .size()
    std::vector<FiberAndThread> batch(m_batchSize);
    bool isActive = false;
    while (true) {
        batch.clear();
        bool dontIdle = false;
        bool tickleMe = false;
        {
            boost::mutex::scoped_lock lock(m_mutex);
            // Kill ourselves off if needed
            if (m_threads.size() > m_threadCount && gettid() != m_rootThread) {
                // Accounting
                if (isActive)
                    --m_activeThreadCount;
                // Kill off the idle fiber
                try {
                    throw boost::enable_current_exception(
                        OperationAbortedException());
                } catch(...) {
                    idleFiber->inject(boost::current_exception());
                }
                // Detach our thread
                for (std::vector<boost::shared_ptr<Thread> >
                    ::iterator it = m_threads.begin();
                    it != m_threads.end();
                    ++it)
                    if ((*it)->tid() == gettid()) {
                        m_threads.erase(it);
                        if (m_threads.size() > m_threadCount)
                            tickle();
                        return;
                    }
                MORDOR_NOTREACHED();
            }

            std::list<FiberAndThread>::iterator it(m_fibers.begin());
            while (it != m_fibers.end()) {
                // If we've met our batch size, and we're not checking to see
                // if we need to tickle another thread, then break
                if ( (tickleMe || m_activeThreadCount == threadCount()) &&
                    batch.size() == m_batchSize)
                    break;

                if (it->thread != emptytid() && it->thread != gettid()) {
                    MORDOR_LOG_DEBUG(g_log) << this
                        << " skipping item scheduled for thread "
                        << it->thread;

                    // Wake up another thread to hopefully service this
                    tickleMe = true;
                    dontIdle = true;
                    ++it;
                    continue;
                }
                MORDOR_ASSERT(it->fiber || it->dg);
                // This fiber is still executing; probably just some race
                // race condition that it needs to yield on one thread
                // before running on another thread
                if (it->fiber && it->fiber->state() == Fiber::EXEC) {
                    MORDOR_LOG_DEBUG(g_log) << this
                        << " skipping executing fiber " << it->fiber;
                    ++it;
                    dontIdle = true;
                    continue;
                }
                // We were just checking if there is more work; there is, so
                // set the flag and don't actually take this piece of work
                if (batch.size() == m_batchSize) {
                    tickleMe = true;
                    break;
                }
                batch.push_back(*it);
                it = m_fibers.erase(it);
                if (!isActive) {
                    ++m_activeThreadCount;
                    isActive = true;
                }
            }
            if (batch.empty() && isActive) {
                --m_activeThreadCount;
                isActive = false;
            }
        }
        if (tickleMe)
            tickle();
        MORDOR_LOG_DEBUG(g_log) << this
            << " got " << batch.size() << " fiber/dgs to process (max: "
            << m_batchSize << ", active: " << isActive << ")";
        MORDOR_ASSERT(isActive == !batch.empty());
        if (!batch.empty()) {
            std::vector<FiberAndThread>::iterator it;
            for (it = batch.begin(); it != batch.end(); ++it) {
                Fiber::ptr f = it->fiber;
                boost::function<void ()> dg = it->dg;

                try {
                    if (f && f->state() != Fiber::TERM) {
                        MORDOR_LOG_DEBUG(g_log) << this << " running " << f;
                        f->yieldTo();
                    } else if (dg) {
                        if (!dgFiber)
                            dgFiber.reset(new Fiber(dg));
                        dgFiber->reset(dg);
                        MORDOR_LOG_DEBUG(g_log) << this << " running " << dg;
                        dgFiber->yieldTo();
                        if (dgFiber->state() != Fiber::TERM)
                            dgFiber.reset();
                        else
                            dgFiber->reset(NULL);
                    }
                } catch (...) {
                    MORDOR_LOG_FATAL(Log::root())
                        << boost::current_exception_diagnostic_information();
                    throw;
                }
            }
            continue;
        }
        if (dontIdle)
            continue;

        if (idleFiber->state() == Fiber::TERM) {
            MORDOR_LOG_DEBUG(g_log) << this << " idle fiber terminated";
            if (gettid() == m_rootThread)
                m_callingFiber.reset();
            // Unblock the next thread
            if (threadCount() > 1)
                tickle();
            return;
        }
        MORDOR_LOG_DEBUG(g_log) << this << " idling";
        idleFiber->call();
    }
}
Exemplo n.º 24
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();
}
Exemplo n.º 25
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();
        }
    }
}
Exemplo n.º 26
0
size_t
ZlibStream::read(Buffer &buffer, size_t length)
{
    if (m_closed)
        return 0;
    struct iovec outbuf = buffer.writeBuffer(length, false);
    m_strm.next_out = (Bytef*)outbuf.iov_base;
    m_strm.avail_out = outbuf.iov_len;

    while (true) {
        std::vector<iovec> inbufs = m_inBuffer.readBuffers();
        size_t avail_in;
        if (!inbufs.empty()) {
            m_strm.next_in = (Bytef*)inbufs[0].iov_base;
            avail_in = inbufs[0].iov_len;
            m_strm.avail_in = inbufs[0].iov_len;
        } else {
            m_strm.next_in = NULL;
            m_strm.avail_in = 0;
        }
        int rc = inflate(&m_strm, Z_NO_FLUSH);
        MORDOR_LOG_DEBUG(g_log) << this << " inflate(("
            << (inbufs.empty() ? 0 : inbufs[0].iov_len) << ", "
            << outbuf.iov_len << ")): " << rc << " (" << m_strm.avail_in
            << ", " << m_strm.avail_out << ")";
        if (!inbufs.empty())
            m_inBuffer.consume(inbufs[0].iov_len - m_strm.avail_in);
        size_t result;
        switch (rc) {
            case Z_STREAM_END:
                // May have still produced output
                result = outbuf.iov_len - m_strm.avail_out;
                buffer.produce(result);
                inflateEnd(&m_strm);
                m_closed = true;
                return result;
            case Z_OK:
                result = outbuf.iov_len - m_strm.avail_out;
                // It consumed input, but produced no output... DON'T return eof
                if (result == 0)
                    continue;
                buffer.produce(result);
                return result;
            case Z_BUF_ERROR:
                // no progress... we need to provide more input (since we're
                // guaranteed to provide output)
                MORDOR_ASSERT(m_strm.avail_in == 0);
                MORDOR_ASSERT(inbufs.empty());
                result = parent()->read(m_inBuffer, m_bufferSize);
                if (result == 0)
                    MORDOR_THROW_EXCEPTION(UnexpectedEofException());
                break;
            case Z_MEM_ERROR:
                throw std::bad_alloc();
            case Z_NEED_DICT:
                MORDOR_THROW_EXCEPTION(NeedPresetDictionaryException());
            case Z_DATA_ERROR:
                MORDOR_THROW_EXCEPTION(CorruptedZlibStreamException());
            default:
                MORDOR_NOTREACHED();
        }
    }
}