Beispiel #1
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();
        }
    }
}
Beispiel #2
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();
        }
    }
}
Beispiel #3
0
long long
CatStream::seek(long long offset, Anchor anchor)
{
    if (offset == 0 && anchor == CURRENT)
        return m_pos;
    MORDOR_ASSERT(m_seekable);
    std::vector<Stream::ptr>::iterator it = m_it;
    long long itOffset = 0;
    switch (anchor) {
        case BEGIN:
            it = m_streams.begin();
            if (it != m_streams.end())
                itOffset = (*it)->tell();
            break;
        case CURRENT:
            break;
        case END:
            it = m_streams.end();
            break;
        default:
            MORDOR_NOTREACHED();
    }
    long long pos = m_pos;
    while (offset != 0) {
        if (offset < 0) {
            if (itOffset == 0) {
                if (it == m_streams.begin())
                    throw std::invalid_argument("Can't seek below 0");
                --it;
                itOffset = (*it)->size();
            }
            long long toChange = std::min(-offset, itOffset);
            itOffset -= toChange;
            pos -= toChange;
            offset += toChange;
        } else {
            long long toChange = offset;
            if (it != m_streams.end())
                toChange = std::min(offset, (*it)->size() - itOffset);
            itOffset += toChange;
            pos += toChange;
            offset -= toChange;
            if (it != m_streams.end() && itOffset == (*it)->size()) {
                ++it;
                itOffset = 0;
            }
        }
    }
    if (it != m_streams.end() && it != m_it)
        (*it)->seek(itOffset);
    m_it = it;
    if (it == m_streams.end())
        pos = m_size + itOffset;
    return m_pos = pos;
}
Beispiel #4
0
long long
BufferedStream::seek(long long offset, Anchor anchor)
{
    MORDOR_ASSERT(parent()->supportsTell());
    long long parentPos = parent()->tell();
    long long bufferedPos = parentPos - m_readBuffer.readAvailable()
        + m_writeBuffer.readAvailable();
    long long parentSize = parent()->supportsSize() ? -1ll : parent()->size();
    // Check for no change in position
    if ((offset == 0 && anchor == CURRENT) ||
        (offset == bufferedPos && anchor == BEGIN) ||
        (parentSize != -1ll && offset + parentSize == bufferedPos &&
        anchor == END))
        return bufferedPos;

    MORDOR_ASSERT(supportsSeek());
    flush(false);
    MORDOR_ASSERT(m_writeBuffer.readAvailable() == 0u);
    switch (anchor) {
        case BEGIN:
            MORDOR_ASSERT(offset >= 0);
            if (offset >= bufferedPos && offset <= parentPos) {
                m_readBuffer.consume((size_t)(offset - bufferedPos));
                return offset;
            }
            m_readBuffer.clear();
            break;
        case CURRENT:
            if (offset > 0 && offset <= (long long)m_readBuffer.readAvailable()) {
                m_readBuffer.consume((size_t)offset);
                return bufferedPos + offset;
            }
            offset -= m_readBuffer.readAvailable();
            m_readBuffer.clear();
            break;
        case END:
            if (parentSize == -1ll)
                throw std::invalid_argument("Can't seek from end without known size");
            if (parentSize + offset >= bufferedPos && parentSize + offset <= parentPos) {
                m_readBuffer.consume((size_t)(parentSize + offset - bufferedPos));
                return parentSize + offset;
            }
            m_readBuffer.clear();
            break;
        default:
            MORDOR_NOTREACHED();
    }
    return parent()->seek(offset, anchor);
}
Beispiel #5
0
static void convertNode(JSON::Value &value, yaml_node_t *node,
    yaml_document_t &document)
{
    switch (node->type) {
        case YAML_SCALAR_NODE:
            value = std::string((char *)node->data.scalar.value,
                node->data.scalar.length);
            break;
        case YAML_SEQUENCE_NODE:
        {
            value = JSON::Array();
            JSON::Array &array = value.get<JSON::Array>();
            yaml_node_item_t *item = node->data.sequence.items.start;
            array.resize(node->data.sequence.items.top - item);
            JSON::Array::iterator it = array.begin();
            while (item < node->data.sequence.items.top) {
                convertNode(*it, yaml_document_get_node(&document, *item),
                    document);
                ++it; ++item;
            }
            break;
        }
        case YAML_MAPPING_NODE:
        {
            value = JSON::Object();
            JSON::Object &object = value.get<JSON::Object>();
            yaml_node_pair_t *pair = node->data.mapping.pairs.start;
            while (pair < node->data.mapping.pairs.top) {
                yaml_node_t *keyNode = yaml_document_get_node(&document,
                    pair->key);
                yaml_node_t *valueNode = yaml_document_get_node(&document,
                    pair->value);
                if (keyNode->type != YAML_SCALAR_NODE)
                    MORDOR_THROW_EXCEPTION(std::runtime_error("Can't use a non-string as a key"));
                std::string key((char *)keyNode->data.scalar.value,
                    keyNode->data.scalar.length);
                convertNode(object.insert(std::make_pair(key,
                    JSON::Value()))->second, valueNode, document);
                ++pair;
            }
            break;
        }
        default:
            MORDOR_NOTREACHED();
    }
}
Beispiel #6
0
void
ZlibStream::reset()
{
    m_inBuffer.clear();
    m_outBuffer.clear(false);
    if (!m_closed) {
        if (supportsRead()) {
            inflateEnd(&m_strm);
        } else {
            deflateEnd(&m_strm);
        }
        m_closed = true;
    }
    int rc;
    memset(&m_strm, 0, sizeof(z_stream));
    if (supportsRead()) {
        rc = inflateInit2(&m_strm, m_windowBits);
    } else {
        rc = deflateInit2(&m_strm, m_level, Z_DEFLATED, m_windowBits, m_memlevel,
            (int)m_strategy);
    }
    switch (rc) {
        case Z_OK:
            m_closed = false;
            break;
        case Z_MEM_ERROR:
            throw std::bad_alloc();
        case Z_STREAM_ERROR:
        {
            std::string message(m_strm.msg ? m_strm.msg : "");
            if (supportsRead()) {
                inflateEnd(&m_strm);
            } else {
                deflateEnd(&m_strm);
            }
            throw std::runtime_error(message);
        }
        default:
            MORDOR_NOTREACHED();
    }
}
Beispiel #7
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();
        }
    }
}
Beispiel #8
0
void Config::request(ServerRequest::ptr request, Access access)
{
    const std::string &method = request->request().requestLine.method;
    if (method == POST) {
        if (access != READWRITE) {
            respondError(request, FORBIDDEN);
            return;
        }
        if (request->request().entity.contentType.type != "application" ||
            request->request().entity.contentType.subtype != "x-www-form-urlencoded") {
            respondError(request, UNSUPPORTED_MEDIA_TYPE);
            return;
        }
        Stream::ptr requestStream = request->requestStream();
        requestStream.reset(new LimitedStream(requestStream, 65536));
        MemoryStream requestBody;
        transferStream(requestStream, requestBody);
        std::string queryString;
        queryString.resize(requestBody.buffer().readAvailable());
        requestBody.buffer().copyOut(&queryString[0], requestBody.buffer().readAvailable());

        bool failed = false;
        URI::QueryString qs(queryString);
        for (URI::QueryString::const_iterator it = qs.begin();
            it != qs.end();
            ++it) {
            ConfigVarBase::ptr var = Mordor::Config::lookup(it->first);
            if (var && !var->fromString(it->second))
                failed = true;
        }
        if (failed) {
            respondError(request, HTTP::FORBIDDEN,
                "One or more new values were not accepted");
            return;
        }
        // Fall through
    }
    if (method == GET || method == HEAD || method == POST) {
        Format format = HTML;
        URI::QueryString qs;
        if (request->request().requestLine.uri.queryDefined())
            qs = request->request().requestLine.uri.queryString();
        URI::QueryString::const_iterator it = qs.find("alt");
        if (it != qs.end() && it->second == "json")
            format = JSON;
        // TODO: use Accept to indicate JSON
        switch (format) {
            case HTML:
            {
                request->response().status.status = OK;
                request->response().entity.contentType = MediaType("text", "html");
                if (method == HEAD) {
                    if (request->request().requestLine.ver == Version(1, 1) &&
                        isAcceptable(request->request().request.te, "chunked", true)) {
                        request->response().general.transferEncoding.push_back("chunked");
                    }
                    return;
                }
                Stream::ptr response = request->responseStream();
                response.reset(new BufferedStream(response));
                response->write("<html><body><table>\n", 20);
                Mordor::Config::visit(boost::bind(access == READWRITE ?
                    &eachConfigVarHTMLWrite : &eachConfigVarHTML, _1,
                    response));
                response->write("</table></body></html>", 22);
                response->close();
                break;
            }
            case JSON:
            {
                JSON::Object root;
                Mordor::Config::visit(boost::bind(&eachConfigVarJSON, _1, boost::ref(root)));
                std::ostringstream os;
                os << root;
                std::string str = os.str();
                request->response().status.status = OK;
                request->response().entity.contentType = MediaType("application", "json");
                request->response().entity.contentLength = str.size();
                if (method != HEAD) {
                    request->responseStream()->write(str.c_str(), str.size());
                    request->responseStream()->close();
                }
                break;
            }
            default:
                MORDOR_NOTREACHED();
        }
    } else {
        respondError(request, METHOD_NOT_ALLOWED);
    }
}
Beispiel #9
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();
    }
}
Beispiel #10
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();
        }
    }
}
Beispiel #11
0
bool getCredentialsFromKeychain(const URI &uri, ClientRequest::ptr priorRequest,
    std::string &scheme, std::string &realm, std::string &username,
    std::string &password, size_t attempts)
{
    if (attempts != 1)
        return false;
    bool proxy =
       priorRequest->response().status.status == PROXY_AUTHENTICATION_REQUIRED;
    const ChallengeList &challengeList = proxy ?
        priorRequest->response().response.proxyAuthenticate :
        priorRequest->response().response.wwwAuthenticate;
    if (isAcceptable(challengeList, "Basic"))
        scheme = "Basic";
    else if (isAcceptable(challengeList, "Digest"))
        scheme = "Digest";
    else
        return false;

    std::vector<SecKeychainAttribute> attrVector;
    std::string host = uri.authority.host();
    attrVector.push_back((SecKeychainAttribute){kSecServerItemAttr, host.size(),
       (void *)host.c_str()});

    UInt32 port = 0;
    if (uri.authority.portDefined()) {
        port = uri.authority.port();
        attrVector.push_back((SecKeychainAttribute){kSecPortItemAttr,
           sizeof(UInt32), &port});
    }
    SecProtocolType protocol;
    if (proxy && priorRequest->request().requestLine.method == CONNECT)
        protocol = kSecProtocolTypeHTTPSProxy;
    else if (proxy)
        protocol = kSecProtocolTypeHTTPProxy;
    else if (uri.scheme() == "https")
        protocol = kSecProtocolTypeHTTPS;
    else if (uri.scheme() == "http")
        protocol = kSecProtocolTypeHTTP;
    else
        MORDOR_NOTREACHED();
    attrVector.push_back((SecKeychainAttribute){kSecProtocolItemAttr,
        sizeof(SecProtocolType), &protocol});

    ScopedCFRef<SecKeychainSearchRef> search;
    SecKeychainAttributeList attrList;
    attrList.count = (UInt32)attrVector.size();
    attrList.attr = &attrVector[0];

    OSStatus status = SecKeychainSearchCreateFromAttributes(NULL,
        kSecInternetPasswordItemClass, &attrList, &search);
    if (status != 0)
        return false;
    ScopedCFRef<SecKeychainItemRef> item;
    status = SecKeychainSearchCopyNext(search, &item);
    if (status != 0)
        return false;
    SecKeychainAttributeInfo info;
    SecKeychainAttrType tag = kSecAccountItemAttr;
    CSSM_DB_ATTRIBUTE_FORMAT format = CSSM_DB_ATTRIBUTE_FORMAT_STRING;
    info.count = 1;
    info.tag = (UInt32 *)&tag;
    info.format = (UInt32 *)&format;
    
    SecKeychainAttributeList *attrs;
    UInt32 passwordLength = 0;
    void *passwordBytes = NULL;

    status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attrs,
        &passwordLength, &passwordBytes);
    if (status != 0)
        return false;

    try {
        username.assign((const char *)attrs->attr[0].data, attrs->attr[0].length);
        password.assign((const char *)passwordBytes, passwordLength);
    } catch (...) {
        SecKeychainItemFreeContent(attrs, passwordBytes);
        throw;
    }
    SecKeychainItemFreeContent(attrs, passwordBytes);
    return true;
}
Beispiel #12
0
Result
PreparedStatement::execute()
{
    PGconn *conn = m_conn.lock().get();
    boost::shared_ptr<PGresult> result, next;
    int nParams = (int)m_params.size();
    Oid *paramTypes = NULL;
    int *paramLengths = NULL, *paramFormats = NULL;
    const char **params = NULL;
    if (nParams) {
        if (m_name.empty())
            paramTypes = &m_paramTypes[0];
        params = &m_params[0];
        paramLengths = &m_paramLengths[0];
        paramFormats = &m_paramFormats[0];
    }
    const char *api = NULL;
#ifndef WINDOWS
    SchedulerSwitcher switcher(m_scheduler);
#endif
    if (m_name.empty()) {
#ifndef WINDOWS
        if (m_scheduler) {
            api = "PQsendQueryParams";
            if (!PQsendQueryParams(conn, m_command.c_str(),
                nParams, paramTypes, params, paramLengths, paramFormats, m_resultFormat))
                throwException(conn);
            flush(conn, m_scheduler);
            next.reset(nextResult(conn, m_scheduler), &PQclear);
            while (next) {
                result = next;
                next.reset(nextResult(conn, m_scheduler), &PQclear);
                if (next) {
                    ExecStatusType status = PQresultStatus(next.get());
                    MORDOR_LOG_VERBOSE(g_log) << conn << "PQresultStatus(" <<
                        next.get() << "): " << PQresStatus(status);
                    switch (status) {
                        case PGRES_COMMAND_OK:
                        case PGRES_TUPLES_OK:
                            break;
                        default:
                            throwException(next.get());
                            MORDOR_NOTREACHED();
                    }
                }
            }
        } else
#endif
        {
            api = "PQexecParams";
            result.reset(PQexecParams(conn, m_command.c_str(),
                nParams, paramTypes, params, paramLengths, paramFormats, m_resultFormat),
                &PQclear);
        }
    } else {
#ifndef WINDOWS
        if (m_scheduler) {
            api = "PQsendQueryPrepared";
            if (!PQsendQueryPrepared(conn, m_name.c_str(),
                nParams, params, paramLengths, paramFormats, 1))
                throwException(conn);
            flush(conn, m_scheduler);
            next.reset(nextResult(conn, m_scheduler), &PQclear);
            while (next) {
                result = next;
                next.reset(nextResult(conn, m_scheduler), &PQclear);
                if (next) {
                    ExecStatusType status = PQresultStatus(next.get());
                    MORDOR_LOG_VERBOSE(g_log) << conn << "PQresultStatus(" <<
                        next.get() << "): " << PQresStatus(status);
                    switch (status) {
                        case PGRES_COMMAND_OK:
                        case PGRES_TUPLES_OK:
                            break;
                        default:
                            throwException(next.get());
                            MORDOR_NOTREACHED();
                    }
                }
            }
        } else
#endif
        {
            api = "PQexecPrepared";
            result.reset(PQexecPrepared(conn, m_name.c_str(),
                nParams, params, paramLengths, paramFormats, m_resultFormat),
                &PQclear);
        }
    }
    if (!result)
        throwException(conn);
    ExecStatusType status = PQresultStatus(result.get());
    MORDOR_ASSERT(api);
    MORDOR_LOG_VERBOSE(g_log) << conn << " " << api << "(\"" << m_command
        << m_name << "\", " << nParams << "), PQresultStatus(" << result.get()
        << "): " << PQresStatus(status);
    switch (status) {
        case PGRES_COMMAND_OK:
        case PGRES_TUPLES_OK:
            return Result(result);
        default:
            throwException(result.get());
            MORDOR_NOTREACHED();
    }
}
Beispiel #13
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();
        }
    }
}
Beispiel #14
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();
}