uint8_t Codec12::readHeader( Transport& transport, const HeaderParams& params) const { uint8_t magic = transport.readByte(); if (magic != HotRodConstants::RESPONSE_MAGIC) { std::ostringstream message; message << "Invalid magic number. Expected " << HotRodConstants::RESPONSE_MAGIC << " and received " << magic; throw InvalidResponseException(message.str()); } uint64_t receivedMessageId = transport.readVLong(); // TODO: java comment, to be checked // If received id is 0, it could be that a failure was noted before the // message id was detected, so don't consider it to a message id error if (receivedMessageId != params.messageId && receivedMessageId != 0) { std::ostringstream message; message << "Invalid message id. Expected " << params.messageId << " and received " << receivedMessageId; throw InvalidResponseException(message.str()); } uint8_t receivedOpCode = transport.readByte(); // Read both the status and new topology (if present), // before deciding how to react to error situations. uint8_t status = transport.readByte(); readNewTopologyIfPresent(transport, params); // Now that all headers values have been read, check the error responses. // This avoids situations where an exceptional return ends up with // the socket containing data from previous request responses. if (receivedOpCode != params.opRespCode) { if (receivedOpCode == HotRodConstants::ERROR_RESPONSE) { checkForErrorsInResponseStatus(transport, params, status); } std::ostringstream message; message << "Invalid response operation. Expected " << std::hex << (int) params.opRespCode << " and received " << std::hex << (int) receivedOpCode; throw InvalidResponseException(message.str()); } return status; }
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; }