Message* Message::deserialize(const char* bytes, unsigned len) { if (len == 0) return nullptr; uint8_t TYPE = *bytes; bytes++, len--; switch (TYPE) { case GAME_CREATE: return GameCreateMessage::deserialize(bytes, len); case GAME_JOIN: return GameJoinMessage::deserialize(bytes, len); case GAME_LEAVE: return GameLeaveMessage::deserialize(bytes, len); case ACCOUNT_REGISTER: return AccountRegisterMessage::deserialize(bytes, len); case ACCOUNT_LOGIN: return AccountLoginMessage::deserialize(bytes, len); case GET_GAME_LISTING: return new EmptyMessage(GET_GAME_LISTING); case GET_GAME_STATE: return GetGameMessage::deserialize(bytes, len); case PLAYER_DIED: return PlayerDeathMessage::deserialize(bytes, len); case GAME_FINISHED: return GameEndMessage::deserialize(bytes, len); case PLANE_LOCATIONS: return PlaneLocationsMessage::deserialize(bytes, len); case ATTACK_CELL: return AttackCellMessage::deserialize(bytes, len); case EVENT_PLAYER_JOINED_GAME: return PlayerJoinedMessage::deserialize(bytes, len); case SERVER_RESPONSE: return ResponseMessage::deserialize(bytes, len); default: throw ProtocolViolationException("Message type has no associated class." "Sent wrong type, or forgot to define a class?"); } }
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; }