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(); }
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); }
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); } }
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; } }
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; } }