Exemple #1
0
CJsonNode CReadJsonFromSocket::ReadMessage(CSocket& sock)
{
    try {
        char read_buffer[READ_BUFFER_SIZE];

        size_t bytes_read;

        do {
            s_ReadSocket(sock, read_buffer, READ_BUFFER_SIZE, &bytes_read);

            m_UTTPReader.SetNewBuffer(read_buffer, bytes_read);

        } while (!m_JSONReader.ReadMessage(m_UTTPReader));
    }
    catch (...) {
        sock.Close();
        throw;
    }

    if (m_UTTPReader.GetNextEvent() != CUTTPReader::eEndOfBuffer) {
        string server_address(sock.GetPeerAddress());
        sock.Close();
        NCBI_THROW_FMT(CNetStorageException, eIOError,
                "Extra bytes past message end while reading from " <<
                        server_address << " after receiving " <<
                        m_JSONReader.GetMessage().Repr() << '.');
    }

    return m_JSONReader.GetMessage();
}
Exemple #2
0
void SNetStorageObjectRPC::ReadConfirmation()
{
    CSocket& sock = m_Connection->m_Socket;

    CJsonOverUTTPReader json_reader;
    try {
        size_t bytes_read;

        while (!json_reader.ReadMessage(m_UTTPReader)) {
            s_ReadSocket(sock, m_ReadBuffer,
                    READ_BUFFER_SIZE, &bytes_read);

            m_UTTPReader.SetNewBuffer(m_ReadBuffer, bytes_read);
        }

        if (m_UTTPReader.GetNextEvent() != CUTTPReader::eEndOfBuffer) {
            NCBI_THROW_FMT(CNetStorageException, eIOError,
                    "Extra bytes past confirmation message "
                    "while reading " << m_Locator << " from " <<
                    sock.GetPeerAddress() << '.');
        }
    }
    catch (...) {
        m_UTTPReader.Reset();
        m_Connection->Close();
        throw;
    }

    s_TrapErrors(m_OriginalRequest, json_reader.GetMessage(), sock,
            m_NetStorageRPC->m_Config.err_mode);
}
Exemple #3
0
void SNetStorageObjectRPC::Close()
{
    if (m_State == eReady)
        return;

    CNetServerConnection conn_copy(m_Connection);
    m_Connection = NULL;

    if (m_State == eReading) {
        m_State = eReady;

        if (!m_EOF) {
            m_UTTPReader.Reset();
            conn_copy->Close();
        }
    } else { /* m_State == eWriting */
        m_State = eReady;

        CSocket& sock = conn_copy->m_Socket;

        s_SendEndOfData(sock);

        CReadJsonFromSocket message_reader;

        s_TrapErrors(m_OriginalRequest,
                message_reader.ReadMessage(sock), sock,
                m_NetStorageRPC->m_Config.err_mode);
    }
}
Exemple #4
0
bool CJsonOverUTTPReader::ReadMessage(CUTTPReader& reader)
{
    for (;;)
        switch (reader.GetNextEvent()) {
        case CUTTPReader::eChunkPart:
            switch (m_State) {
            case eExpectNextToken:
                m_State = eReadingString;
                m_CurrentChunk.assign(reader.GetChunkPart(),
                        reader.GetChunkPartSize());
                break;
            case eReadingString:
                m_CurrentChunk.append(reader.GetChunkPart(),
                        reader.GetChunkPartSize());
                break;
            case eReadingDouble:
                // The underlying transport protocol guarantees
                // that m_Double boundaries will not be exceeded.
                memcpy(m_DoublePtr, reader.GetChunkPart(),
                        reader.GetChunkPartSize());
                m_DoublePtr += reader.GetChunkPartSize();
                break;
            default: /* case eMessageComplete: */
                goto ThrowUnexpectedTrailingToken;
            }
            break;

        case CUTTPReader::eChunk:
            switch (m_State) {
            case eExpectNextToken:
                m_CurrentChunk.assign(reader.GetChunkPart(),
                        reader.GetChunkPartSize());
                break;
            case eReadingString:
                m_State = eExpectNextToken;
                m_CurrentChunk.append(reader.GetChunkPart(),
                        reader.GetChunkPartSize());
                break;
            case eReadingDouble:
                m_State = eExpectNextToken;
                memcpy(m_DoublePtr, reader.GetChunkPart(),
                        reader.GetChunkPartSize());
                if (m_DoubleEndianness != DOUBLE_PREFIX)
                    reverse(reinterpret_cast<char*>(&m_Double),
                            reinterpret_cast<char*>(&m_Double + 1));
                if (!x_AddNewNode(CJsonNode::NewDoubleNode(m_Double)))
                    m_State = eMessageComplete;
                continue;
            default: /* case eMessageComplete: */
                goto ThrowUnexpectedTrailingToken;
            }
            if (!m_CurrentNode) {
                m_CurrentNode = CJsonNode::NewStringNode(m_CurrentChunk);
                m_State = eMessageComplete;
            } else if (m_HashValueIsExpected) {
                m_HashValueIsExpected = false;
                m_CurrentNode.SetString(m_HashKey, m_CurrentChunk);
            } else
                // The current node is either a JSON object or an array,
                // because if it was a non-container node, m_State would
                // be eMessageComplete.
                if (m_CurrentNode.IsArray())
                    m_CurrentNode.AppendString(m_CurrentChunk);
                else {
                    m_HashKey = m_CurrentChunk;
                    m_HashValueIsExpected = true;
                }
            break;

        case CUTTPReader::eControlSymbol:
            {
                char control_symbol = reader.GetControlSymbol();

                if (control_symbol == '\n') {
                    if (m_State != eMessageComplete) {
                        NCBI_THROW(CJsonOverUTTPException, eUnexpectedEOM,
                                "JSON-over-UTTP: Unexpected end of message");
                    }
                    return true;
                }

                if (m_State != eExpectNextToken)
                    goto ThrowChunkContinuationExpected;

                switch (control_symbol) {
                case '[':
                case '{':
                    {
                        CJsonNode new_node(control_symbol == '[' ?
                            CJsonNode::NewArrayNode() :
                            CJsonNode::NewObjectNode());
                        if (x_AddNewNode(new_node)) {
                            m_NodeStack.push_back(m_CurrentNode);
                            m_CurrentNode = new_node;
                        }
                    }
                    break;

                case ']':
                case '}':
                    if (!m_CurrentNode ||
                            (control_symbol == ']') ^ m_CurrentNode.IsArray()) {
                        NCBI_THROW(CJsonOverUTTPException, eUnexpectedClosingBracket,
                                "JSON-over-UTTP: Unexpected closing bracket");
                    }
                    if (m_NodeStack.empty())
                        m_State = eMessageComplete;
                    else {
                        m_CurrentNode = m_NodeStack.back();
                        m_NodeStack.pop_back();
                    }
                    break;

                case 'D':
                case 'd':
                    switch (reader.ReadRawData(sizeof(double))) {
                    default: /* case CUTTPReader::eEndOfBuffer: */
                        m_State = eReadingDouble;
                        m_DoubleEndianness = control_symbol;
                        m_DoublePtr = reinterpret_cast<char*>(&m_Double);
                        return false;
                    case CUTTPReader::eChunkPart:
                        m_State = eReadingDouble;
                        m_DoubleEndianness = control_symbol;
                        memcpy(&m_Double, reader.GetChunkPart(),
                                reader.GetChunkPartSize());
                        m_DoublePtr = reinterpret_cast<char*>(&m_Double) +
                                reader.GetChunkPartSize();
                        break;
                    case CUTTPReader::eChunk:
                        _ASSERT(reader.GetChunkPartSize() == sizeof(double));

                        if (control_symbol == DOUBLE_PREFIX)
                            memcpy(&m_Double, reader.GetChunkPart(),
                                    sizeof(double));
                        else {
                            // Copy the entire chunk to
                            // m_Double in reverse order.
                            const char* src = reader.GetChunkPart();
                            char* dst = reinterpret_cast<char*>(&m_Double + 1);
                            int count = sizeof(double);

                            do
                                *--dst = *src++;
                            while (--count > 0);
                        }

                        if (!x_AddNewNode(CJsonNode::NewDoubleNode(m_Double)))
                            m_State = eMessageComplete;
                    }
                    break;

                case 'Y':
                    if (!x_AddNewNode(CJsonNode::NewBooleanNode(true)))
                        m_State = eMessageComplete;
                    break;

                case 'N':
                    if (!x_AddNewNode(CJsonNode::NewBooleanNode(false)))
                        m_State = eMessageComplete;
                    break;

                case 'U':
                    if (!x_AddNewNode(CJsonNode::NewNullNode()))
                        m_State = eMessageComplete;
                    break;

                default:
                    NCBI_THROW_FMT(CJsonOverUTTPException,
                            eUnknownControlSymbol,
                            "JSON-over-UTTP: Unknown control symbol '" <<
                            NStr::PrintableString(CTempString(&control_symbol,
                                    1)) << '\'');
                }
            }
            break;

        case CUTTPReader::eNumber:
            switch (m_State) {
            case eExpectNextToken:
                if (!x_AddNewNode(CJsonNode::NewIntegerNode(reader.GetNumber())))
                    m_State = eMessageComplete;
                break;
            case eMessageComplete:
                goto ThrowUnexpectedTrailingToken;
            default:
                goto ThrowChunkContinuationExpected;
            }
            break;

        case CUTTPReader::eEndOfBuffer:
            return false;

        default: /* case CUTTPReader::eFormatError: */
            NCBI_THROW(CJsonOverUTTPException, eUTTPFormatError,
                    "JSON-over-UTTP: UTTP format error");
        }

ThrowUnexpectedTrailingToken:
    NCBI_THROW(CJsonOverUTTPException, eUnexpectedTrailingToken,
            "JSON-over-UTTP: Received a token while expected EOM");

ThrowChunkContinuationExpected:
    NCBI_THROW(CJsonOverUTTPException, eChunkContinuationExpected,
            "JSON-over-UTTP: Chunk continuation expected");
}
CJsonOverUTTPReader::EParsingEvent
    CJsonOverUTTPReader::ProcessParsingEvents(CUTTPReader& reader)
{
    for (;;)
        switch (reader.GetNextEvent()) {
        case CUTTPReader::eChunkPart:
            if (m_ReadingChunk)
                m_CurrentChunk.append(reader.GetChunkPart(),
                    reader.GetChunkPartSize());
            else {
                m_ReadingChunk = true;
                m_CurrentChunk.assign(reader.GetChunkPart(),
                    reader.GetChunkPartSize());
            }
            break;

        case CUTTPReader::eChunk:
            if (m_ReadingChunk) {
                m_ReadingChunk = false;
                m_CurrentChunk.append(reader.GetChunkPart(),
                    reader.GetChunkPartSize());
            } else
                m_CurrentChunk.assign(reader.GetChunkPart(),
                    reader.GetChunkPartSize());
            if (m_CurrentNode.IsArray())
                m_CurrentNode.PushString(m_CurrentChunk);
            else // The current node is eObject.
                if (m_HashValueIsExpected) {
                    m_HashValueIsExpected = false;
                    m_CurrentNode.SetString(m_HashKey, m_CurrentChunk);
                } else {
                    m_HashValueIsExpected = true;
                    m_HashKey = m_CurrentChunk;
                }
            break;

        case CUTTPReader::eControlSymbol:
            {
                if (m_ReadingChunk)
                    return eChunkContinuationExpected;

                char control_symbol = reader.GetControlSymbol();

                switch (control_symbol) {
                case '\n':
                    if (m_NodeStack.size() != 0)
                        return eUnexpectedEOM;
                    if (reader.GetNextEvent() != CUTTPReader::eEndOfBuffer)
                        return eExtraCharsPastEOM;
                    return eEndOfMessage;

                case '[':
                case '{':
                    {
                        CJsonNode new_node(control_symbol == '[' ?
                            CJsonNode::NewArrayNode() :
                            CJsonNode::NewObjectNode());
                        if (m_CurrentNode.IsArray())
                            m_CurrentNode.PushNode(new_node);
                        else // The current node is eObject.
                            if (m_HashValueIsExpected) {
                                m_HashValueIsExpected = false;
                                m_CurrentNode.SetNode(m_HashKey, new_node);
                            } else
                                return eHashKeyMustBeString;
                        m_NodeStack.push_back(m_CurrentNode);
                        m_CurrentNode = new_node;
                    }
                    break;

                case ']':
                case '}':
                    if (m_NodeStack.size() == 0 || (control_symbol == ']') ^
                            m_CurrentNode.IsArray())
                        return eUnexpectedClosingBracket;
                    m_CurrentNode = m_NodeStack.back();
                    m_NodeStack.pop_back();
                    break;

                case 'Y':
                case 'N':
                    {
                        bool boolean = control_symbol == 'Y';

                        if (m_CurrentNode.IsArray())
                            m_CurrentNode.PushBoolean(boolean);
                        else // The current node is eObject.
                            if (m_HashValueIsExpected) {
                                m_HashValueIsExpected = false;
                                m_CurrentNode.SetBoolean(m_HashKey, boolean);
                            } else
                                return eHashKeyMustBeString;
                    }
                    break;

                case 'U':
                    if (m_CurrentNode.IsArray())
                        m_CurrentNode.PushNull();
                    else // The current node is eObject.
                        if (m_HashValueIsExpected) {
                            m_HashValueIsExpected = false;
                            m_CurrentNode.SetNull(m_HashKey);
                        } else
                            return eHashKeyMustBeString;
                    break;

                default:
                    return eUnknownControlSymbol;
                }
            }
            break;

        case CUTTPReader::eNumber:
            if (m_ReadingChunk)
                return eChunkContinuationExpected;
            if (m_CurrentNode.IsArray())
                m_CurrentNode.PushNumber(reader.GetNumber());
            else // The current node is eObject.
                if (m_HashValueIsExpected) {
                    m_HashValueIsExpected = false;
                    m_CurrentNode.SetNumber(m_HashKey, reader.GetNumber());
                } else
                    return eHashKeyMustBeString;
            break;

        case CUTTPReader::eEndOfBuffer:
            return eNextBuffer;

        default: // case CUTTPReader::eFormatError:
            return eUTTPFormatError;
        }
}
Exemple #6
0
ERW_Result SNetStorageObjectRPC::Read(void* buffer, size_t buf_size,
        size_t* bytes_read)
{
    if (m_State == eWriting) {
        NCBI_THROW_FMT(CNetStorageException, eInvalidArg,
                "Cannot read a NetStorage file while writing to it");
    }

    size_t bytes_read_local;

    if (m_State == eReady) {
        m_OriginalRequest = x_MkRequest("READ");

        if (m_ReadBuffer == NULL)
            m_ReadBuffer = new char[READ_BUFFER_SIZE];

        CNetServer server(*m_OwnService.Iterate(CNetService::eRandomize));

        CJsonOverUTTPExecHandler json_over_uttp_sender(m_OriginalRequest);

        server->TryExec(json_over_uttp_sender);

        CSocket& sock = json_over_uttp_sender.GetConnection()->m_Socket;

        CJsonOverUTTPReader json_reader;

        try {
            do {
                s_ReadSocket(sock, m_ReadBuffer, READ_BUFFER_SIZE,
                        &bytes_read_local);

                m_UTTPReader.SetNewBuffer(m_ReadBuffer, bytes_read_local);

            } while (!json_reader.ReadMessage(m_UTTPReader));
        }
        catch (...) {
            m_UTTPReader.Reset();
            sock.Close();
            throw;
        }

        s_TrapErrors(m_OriginalRequest, json_reader.GetMessage(), sock,
            m_NetStorageRPC->m_Config.err_mode);

        m_Connection = json_over_uttp_sender.GetConnection();

        m_CurrentChunkSize = 0;

        m_State = eReading;
        m_EOF = false;
    }

    char* buf_pos = reinterpret_cast<char*>(buffer);

    if (m_CurrentChunkSize >= buf_size) {
        if (buf_size > 0) {
            memcpy(buf_pos, m_CurrentChunk, buf_size);
            m_CurrentChunk += buf_size;
            m_CurrentChunkSize -= buf_size;
        }
        if (bytes_read != NULL)
            *bytes_read = buf_size;
        return eRW_Success;
    }

    if (m_CurrentChunkSize > 0) {
        memcpy(buf_pos, m_CurrentChunk, m_CurrentChunkSize);
        buf_pos += m_CurrentChunkSize;
        buf_size -= m_CurrentChunkSize;
    }

    size_t bytes_copied = m_CurrentChunkSize;

    m_CurrentChunkSize = 0;

    if (m_EOF) {
        if (bytes_read != NULL)
            *bytes_read = bytes_copied;
        return bytes_copied ? eRW_Success : eRW_Eof;
    }

    try {
        while (buf_size > 0) {
            switch (m_UTTPReader.GetNextEvent()) {
            case CUTTPReader::eChunkPart:
            case CUTTPReader::eChunk:
                m_CurrentChunk = m_UTTPReader.GetChunkPart();
                m_CurrentChunkSize = m_UTTPReader.GetChunkPartSize();

                if (m_CurrentChunkSize >= buf_size) {
                    memcpy(buf_pos, m_CurrentChunk, buf_size);
                    m_CurrentChunk += buf_size;
                    m_CurrentChunkSize -= buf_size;
                    if (bytes_read != NULL)
                        *bytes_read = bytes_copied + buf_size;
                    return eRW_Success;
                }

                memcpy(buf_pos, m_CurrentChunk, m_CurrentChunkSize);
                buf_pos += m_CurrentChunkSize;
                buf_size -= m_CurrentChunkSize;
                bytes_copied += m_CurrentChunkSize;
                m_CurrentChunkSize = 0;
                break;

            case CUTTPReader::eControlSymbol:
                if (m_UTTPReader.GetControlSymbol() != END_OF_DATA_MARKER) {
                    NCBI_THROW_FMT(CNetStorageException, eIOError,
                            "NetStorage API: invalid end-of-data-stream "
                            "terminator: " <<
                                    (int) m_UTTPReader.GetControlSymbol());
                }
                m_EOF = true;
                ReadConfirmation();
                if (bytes_read != NULL)
                    *bytes_read = bytes_copied;
                return bytes_copied ? eRW_Success : eRW_Eof;

            case CUTTPReader::eEndOfBuffer:
                s_ReadSocket(m_Connection->m_Socket, m_ReadBuffer,
                        READ_BUFFER_SIZE, &bytes_read_local);

                m_UTTPReader.SetNewBuffer(m_ReadBuffer, bytes_read_local);
                break;

            default:
                NCBI_THROW_FMT(CNetStorageException, eIOError,
                        "NetStorage API: invalid UTTP status "
                        "while reading " << m_Locator);
            }
        }

        if (bytes_read != NULL)
            *bytes_read = bytes_copied;
        return eRW_Success;
    }
    catch (...) {
        m_State = eReady;
        m_UTTPReader.Reset();
        m_Connection->Close();
        m_Connection = NULL;
        throw;
    }
}