Example #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;
        }
    }
}
Example #2
0
std::string
Buffer::getDelimited(char delimiter, bool eofIsDelimiter, bool includeDelimiter)
{
    ptrdiff_t offset = find(delimiter, ~0);
    MORDOR_ASSERT(offset >= -1);
    if (offset == -1 && !eofIsDelimiter)
        MORDOR_THROW_EXCEPTION(UnexpectedEofException());
    eofIsDelimiter = offset == -1;
    if (offset == -1)
        offset = readAvailable();;
    std::string result;
    result.resize(offset + (eofIsDelimiter ? 0 : (includeDelimiter ? 1 : 0)));
    copyOut(&result[0], result.size());
    consume(result.size());
    if (!eofIsDelimiter && !includeDelimiter)
        consume(1u);
    return result;
}
Example #3
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();
        }
    }
}
Example #4
0
Stream::ptr tunnel(HTTP::StreamBroker::ptr streamBroker, const URI &proxy,
    IPAddress::ptr targetIP, const std::string &targetDomain,
    unsigned short targetPort, unsigned char version)
{
    MORDOR_ASSERT(version == 4 || version == 5);
    MORDOR_ASSERT(version == 5 || !targetIP ||
        targetIP->family() == AF_INET);

    MORDOR_ASSERT(streamBroker);
    MORDOR_ASSERT(targetIP || !targetDomain.empty());
    std::string buffer;
    buffer.resize(std::max<size_t>(targetDomain.size() + 1u, 16u) + 9);

    Stream::ptr stream = streamBroker->getStream(proxy);
    if (version == 5) {
        buffer[0] = version;
        buffer[1] = 1;
        buffer[2] = 0;
        size_t written = 0;
        while (written < 3)
            written += stream->write(buffer.data() + written, 3 - written);
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if (buffer[0] != 5)
            MORDOR_THROW_EXCEPTION(ProtocolViolationException());
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if ((unsigned char)buffer[0] == 0xff)
            MORDOR_THROW_EXCEPTION(NoAcceptableAuthenticationMethodException());
        if (buffer[0] != 0)
            MORDOR_THROW_EXCEPTION(ProtocolViolationException());
    }
    buffer[0] = version;
    buffer[1] = 1;
    size_t size;
    if (version == 4) {
        if (targetIP)
            *(unsigned short *)&buffer[2] = htons(targetIP->port());
        else
            *(unsigned short *)&buffer[2] = htons(targetPort);
        if (targetIP)
            *(unsigned int *)&buffer[4] = htonl((unsigned int)(((sockaddr_in *)targetIP->name())->sin_addr.s_addr));
        else
            *(unsigned int *)&buffer[4] = htonl(0x00000001);
        buffer[8] = 0;
        if (!targetIP) {
            memcpy(&buffer[9], targetDomain.c_str(), targetDomain.size());
            buffer[9 + targetDomain.size()] = 0;
        }
        size = 9 + targetDomain.size() + (targetDomain.empty() ? 0 : 1);
    } else {
        buffer[2] = 0;
        if (targetIP) {
            if (targetIP->family() == AF_INET) {
                buffer[3] = 1;
                *(unsigned int *)&buffer[4] = htonl((unsigned int)(((sockaddr_in *)targetIP->name())->sin_addr.s_addr));
                size = 7;
            } else {
                buffer[3] = 4;
                memcpy(&buffer[4], &((sockaddr_in6 *)targetIP->name())->sin6_addr, 16);
                size = 19;
            }
        } else {
            buffer[3] = 3;
            buffer[4] = (unsigned char)targetDomain.size();
            memcpy(&buffer[5], targetDomain.c_str(), targetDomain.size());
            size = 5 + targetDomain.size();
        }
        if (targetIP)
            *(unsigned short *)&buffer[size] = htons(targetIP->port());
        else
            *(unsigned short *)&buffer[size] = htons(targetPort);
        size += 2;
    }
    size_t written = 0;
    while (written < size)
        written += stream->write(buffer.data() + written, size - written);
    if (stream->read(&buffer[0], 1) == 0)
        MORDOR_THROW_EXCEPTION(UnexpectedEofException());
    if ((version == 4 && buffer[0] != 0) || (version == 5 && buffer[0] != 5))
        MORDOR_THROW_EXCEPTION(ProtocolViolationException());
    if (stream->read(&buffer[0], 1) == 0)
        MORDOR_THROW_EXCEPTION(UnexpectedEofException());
    if ((version == 4 && buffer[0] != 0x5a) || (version == 5 && buffer[0] != 0))
        MORDOR_THROW_EXCEPTION(InvalidResponseException(buffer[0]));
    if (version == 4) {
        size = 0;
        while (size < 6) {
            written = stream->read(&buffer[0], 6 - size);
            if (written == 0)
                MORDOR_THROW_EXCEPTION(UnexpectedEofException());
            size += written;
        }
    } else {
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if (buffer[0] != 0)
            MORDOR_THROW_EXCEPTION(InvalidResponseException(buffer[0]));
        if (stream->read(&buffer[0], 1) == 0)
            MORDOR_THROW_EXCEPTION(UnexpectedEofException());
        if (buffer[1] == 3) {
            if (buffer[0] != 0)
                MORDOR_THROW_EXCEPTION(ProtocolViolationException());
            size = buffer[1] + 2;
        } else if (buffer[1] == 1) {
            size = 6;
        } else if (buffer[1] == 4) {
            size = 18;
        } else {
            MORDOR_THROW_EXCEPTION(ProtocolViolationException());
        }
        while (size > 0) {
            written = stream->read(&buffer[0], size);
            if (written == 0)
                MORDOR_THROW_EXCEPTION(UnexpectedEofException());
            size -= written;
        }
    }
    return stream;
}
Example #5
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 #6
0
size_t
SSLStream::write(const void *buffer, size_t length)
{
    flush(false);
    if (length == 0)
        return 0;

    const int toWrite = (int)std::min<size_t>(0x7fffffff, length);
    while (true) {
        unsigned long error = SSL_ERROR_NONE;
        const int result = sslCallWithLock(std::bind(SSL_write, m_ssl.get(), buffer, toWrite), &error);
        if (result > 0) {
            return result;
        }

        MORDOR_LOG_DEBUG(g_log) << this << " SSL_write(" << m_ssl.get() << ", "
            << toWrite << "): " << result << " (" << error << ")";
        switch (error) {
            case SSL_ERROR_NONE:
                return result;
            case SSL_ERROR_ZERO_RETURN:
                // Received close_notify message
                MORDOR_ASSERT(result != 0);
                return result;
            case SSL_ERROR_WANT_READ:
                MORDOR_THROW_EXCEPTION(OpenSSLException("SSL_write generated 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_write("
                            << m_ssl.get() << ", " << toWrite << "): "
                            << result << " (" << error << ", " << message
                            << ")";
                        MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                          //  << boost::errinfo_api_function("SSL_write");
                        ;
                }
                MORDOR_LOG_ERROR(g_log) << this << " SSL_write("
                    << m_ssl.get() << ", " << toWrite << "): " << result
                    << " (" << error << ")";
                if (result == 0) {
                    MORDOR_THROW_EXCEPTION(UnexpectedEofException());
                }
                MORDOR_THROW_EXCEPTION_FROM_LAST_ERROR_API("SSL_write");
            case SSL_ERROR_SSL:
                {
                    MORDOR_ASSERT(hasOpenSSLError());
                    std::string message = getOpenSSLErrorMessage();
                    MORDOR_LOG_ERROR(g_log) << this << " SSL_write("
                        << m_ssl.get() << ", " << toWrite << "): " << result
                        << " (" << error << ", " << message << ")";
                    MORDOR_THROW_EXCEPTION(OpenSSLException(message))
                      //  << boost::errinfo_api_function("SSL_write");
                    ;
                }
            default:
                MORDOR_NOTREACHED();
        }
    }
}