bool KartUpdateProtocol::notifyEventAsynchronous(Event* event) { if (event->type != EVENT_TYPE_MESSAGE) return true; NetworkString ns = event->data(); if (ns.size() < 36) { Log::info("KartUpdateProtocol", "Message too short."); return true; } ns.removeFront(4); while(ns.size() >= 16) { uint32_t kart_id = ns.getUInt32(0); float a,b,c; a = ns.getFloat(4); b = ns.getFloat(8); c = ns.getFloat(12); float d,e,f,g; d = ns.getFloat(16); e = ns.getFloat(20); f = ns.getFloat(24); g = ns.getFloat(28); pthread_mutex_trylock(&m_positions_updates_mutex); m_next_positions.push_back(Vec3(a,b,c)); m_next_quaternions.push_back(btQuaternion(d,e,f,g)); m_karts_ids.push_back(kart_id); pthread_mutex_unlock(&m_positions_updates_mutex); ns.removeFront(32); } return true; }
/** Sends a packet to this host. * \param data The data to send. * \param reliable If the data is sent reliable or not. */ void STKPeer::sendPacket(NetworkString const& data, bool reliable) { TransportAddress a(m_enet_peer->address); Log::verbose("STKPeer", "sending packet of size %d to %s", data.size(), a.toString().c_str()); ENetPacket* packet = enet_packet_create(data.getBytes(), data.size() + 1, (reliable ? ENET_PACKET_FLAG_RELIABLE : ENET_PACKET_FLAG_UNSEQUENCED)); enet_peer_send(m_enet_peer, 0, packet); } // sendPacket
/** \brief Broadcasts a packet to all peers. * \param data : Data to send. */ void Network::broadcastPacket(const NetworkString& data, bool reliable) { ENetPacket* packet = enet_packet_create(data.getBytes(), data.size() + 1, reliable ? ENET_PACKET_FLAG_RELIABLE : ENET_PACKET_FLAG_UNSEQUENCED); enet_host_broadcast(m_host, 0, packet); } // broadcastPacket
/** Saves a state on the client. Used to save an initial state at t=0 for each * client in case that we receive an event from another client (which will * trigger a rewind) before a state from the server. */ void RewindManager::saveLocalState() { int ticks = World::getWorld()->getTimeTicks(); saveState(/*local_state*/true); NetworkString *state = GameProtocol::lock()->getState(); // Copy the data to a new string, making the buffer in // GameProtocol availble for again. BareNetworkString *bns = new BareNetworkString(state->getCurrentData(), state->size() ); m_rewind_queue.addLocalState(bns, /*confirmed*/true, ticks); } // saveLocalState
/** \brief Log packets into a file * \param ns : The data in the packet * \param incoming : True if the packet comes from a peer. * False if it's sent to a peer. */ void Network::logPacket(const NetworkString &ns, bool incoming) { if (m_log_file.getData() == NULL) // read only access, no need to lock return; const char *arrow = incoming ? "<--" : "-->"; m_log_file.lock(); fprintf(m_log_file.getData(), "[%d\t] %s ", (int)(StkTime::getRealTime()), arrow); for (int i = 0; i < ns.size(); i++) { fprintf(m_log_file.getData(), "%d.", ns[i]); } fprintf(m_log_file.getData(), "\n"); m_log_file.unlock(); } // logPacket
/** This function is called on a client when it receives a kartFinishedRace * event from the server. It updates the game with this information. * \param ns The message from the server. */ void GameEventsProtocol::kartFinishedRace(const NetworkString &ns) { if (ns.size() < 5) { Log::warn("GameEventsProtocol", "kartFinisheRace: Too short message."); return; } uint8_t kart_id = ns.getUInt8(); float time = ns.getFloat(); if (race_manager->modeHasLaps()) { World::getWorld()->getKart(kart_id) ->setPosition(m_last_finished_position++); } World::getWorld()->getKart(kart_id)->finishedRace(time, /*from_server*/true); } // kartFinishedRace
void STKPeer::sendPacket(NetworkString const& data, bool reliable) { TransportAddress a(m_peer->address); Log::verbose("STKPeer", "sending packet of size %d to %s", a.toString().c_str()); ENetPacket* packet = enet_packet_create(data.getBytes(), data.size() + 1, (reliable ? ENET_PACKET_FLAG_RELIABLE : ENET_PACKET_FLAG_UNSEQUENCED)); /* to debug the packet output printf("STKPeer: "); for (unsigned int i = 0; i < data.size(); i++) { printf("%d ", (uint8_t)(data[i])); } printf("\n"); */ enet_peer_send(m_peer, 0, packet); }
bool StartGameProtocol::notifyEventAsynchronous(Event* event) { NetworkString data = event->data(); if (data.size() < 5) { Log::error("StartGameProtocol", "Too short message."); return true; } uint32_t token = data.gui32(); uint8_t ready = data.gui8(4); STKPeer* peer = (*(event->peer)); if (peer->getClientServerToken() != token) { Log::error("StartGameProtocol", "Bad token received."); return true; } if (m_listener->isServer() && ready) // on server, player is ready { Log::info("StartGameProtocol", "One of the players is ready."); m_player_states[peer->getPlayerProfile()] = READY; m_ready_count++; if (m_ready_count == m_game_setup->getPlayerCount()) { // everybody ready, synchronize SynchronizationProtocol* protocol = static_cast<SynchronizationProtocol*>(m_listener->getProtocol(PROTOCOL_SYNCHRONIZATION)); if (protocol) { protocol->startCountdown(5000); // 5 seconds countdown Log::info("StartGameProtocol", "All players ready, starting countdown."); m_ready = true; return true; } else Log::error("StartGameProtocol", "The Synchronization protocol hasn't been started."); } } else // on the client, we shouldn't even receive messages. { Log::error("StartGameProtocol", "Received a message with bad format."); } return true; }
// ---------------------------------------------------------------------------- void STKHost::handleLANRequests() { const int LEN=2048; char buffer[LEN]; TransportAddress sender; int len = m_lan_network->receiveRawPacket(buffer, LEN, &sender, 1); if(len<=0) return; if (std::string(buffer, len) == "stk-server") { Log::verbose("STKHost", "Received LAN server query"); std::string name = StringUtils::wideToUtf8(NetworkConfig::get()->getServerName()); // Avoid buffer overflows if (name.size() > 255) name = name.substr(0, 255); // Send the answer, consisting of server name, max players, // current players, and the client's ip address and port // number (which solves the problem which network interface // might be the right one if there is more than one). NetworkString s; s.encodeString(name); s.addUInt8(NetworkConfig::get()->getMaxPlayers()); s.addUInt8(0); // FIXME: current number of connected players s.addUInt32(sender.getIP()); s.addUInt16(sender.getPort()); m_lan_network->sendRawPacket(s.getBytes(), s.size(), sender); } // if message is server-requested else if (std::string(buffer, len) == "connection-request") { Protocol *c = new ConnectToPeer(sender); c->requestStart(); } else Log::info("STKHost", "Received unknown command '%s'", std::string(buffer, len).c_str()); } // handleLANRequests
bool ServerLobbyRoomProtocol::notifyEventAsynchronous(Event* event) { assert(m_setup); // assert that the setup exists if (event->type == EVENT_TYPE_MESSAGE) { NetworkString data = event->data(); assert(data.size()); // message not empty uint8_t message_type; message_type = data[0]; event->removeFront(1); Log::info("ServerLobbyRoomProtocol", "Message received with type %d.", message_type); if (message_type == 0x01) // player requesting connection connectionRequested(event); else if (message_type == 0x02) // player requesting kart selection kartSelectionRequested(event); else if (message_type == 0xc0) // vote for major mode playerMajorVote(event); else if (message_type == 0xc1) // vote for race count playerRaceCountVote(event); else if (message_type == 0xc2) // vote for minor mode playerMinorVote(event); else if (message_type == 0xc3) // vote for track playerTrackVote(event); else if (message_type == 0xc4) // vote for reversed mode playerReversedVote(event); else if (message_type == 0xc5) // vote for laps playerLapsVote(event); } // if (event->type == EVENT_TYPE_MESSAGE) else if (event->type == EVENT_TYPE_CONNECTED) { } // if (event->type == EVENT_TYPE_CONNECTED) else if (event->type == EVENT_TYPE_DISCONNECTED) { kartDisconnected(event); } // if (event->type == EVENT_TYPE_DISCONNECTED) return true; }
bool SynchronizationProtocol::notifyEventAsynchronous(Event* event) { if (event->type != EVENT_TYPE_MESSAGE) return true; NetworkString data = event->data(); if (data.size() < 10) { Log::warn("SynchronizationProtocol", "Received a message too short."); return true; } uint8_t talk_id = data.gui8(); uint32_t token = data.gui32(1); uint32_t request = data.gui8(5); uint32_t sequence = data.gui32(6); std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers(); assert(peers.size() > 0); if (m_listener->isServer()) { if (talk_id > peers.size()) { Log::warn("SynchronizationProtocol", "The ID isn't known."); return true; } } uint8_t peer_id = 0; for (unsigned int i = 0; i < peers.size(); i++) { if (peers[i]->isSamePeer(*event->peer)) { peer_id = i; } } if (peers[peer_id]->getClientServerToken() != token) { Log::warn("SynchronizationProtocol", "Bad token from peer %d", talk_id); return true; } if (request) { NetworkString response; response.ai8(data.gui8(talk_id)).ai32(token).ai8(0).ai32(sequence); m_listener->sendMessage(this, peers[peer_id], response, false); Log::verbose("SynchronizationProtocol", "Answering sequence %u", sequence); if (data.size() == 14 && !m_listener->isServer()) // countdown time in the message { uint32_t time_to_start = data.gui32(10); Log::debug("SynchronizationProtocol", "Request to start game in %d.", time_to_start); if (!m_countdown_activated) startCountdown(time_to_start); else m_countdown = (double)(time_to_start/1000.0); } else Log::verbose("SynchronizationProtocol", "No countdown for now."); } else // response { if (sequence >= m_pings[peer_id].size()) { Log::warn("SynchronizationProtocol", "The sequence# %u isn't known.", sequence); return true; } double current_time = StkTime::getRealTime(); m_total_diff[peer_id] += current_time - m_pings[peer_id][sequence]; Log::verbose("SynchronizationProtocol", "InstantPing is %u", (unsigned int)((current_time - m_pings[peer_id][sequence])*1000)); m_successed_pings[peer_id]++; m_average_ping[peer_id] = (int)((m_total_diff[peer_id]/m_successed_pings[peer_id])*1000.0); Log::debug("SynchronizationProtocol", "Ping is %u", m_average_ping[peer_id]); } return true; }
/*! \brief Called when a player asks for a connection. * \param event : Event providing the information. * * Format of the data : * Byte 0 1 5 * ------------------------ * Size | 1 | 4 | * Data | 4 | global player id | * ------------------------ */ void ServerLobbyRoomProtocol::connectionRequested(Event* event) { STKPeer* peer = *(event->peer); NetworkString data = event->data(); if (data.size() != 5 || data[0] != 4) { Log::warn("ServerLobbyRoomProtocol", "Receiving badly formated message. Size is %d and first byte %d", data.size(), data[0]); return; } uint32_t player_id = 0; player_id = data.getUInt32(1); // can we add the player ? if (m_setup->getPlayerCount() < ServerNetworkManager::getInstance()->getMaxPlayers()) //accept { // add the player to the game setup m_next_id = m_setup->getPlayerCount(); // notify everybody that there is a new player NetworkString message; // new player (1) -- size of id -- id -- size of local id -- local id; message.ai8(1).ai8(4).ai32(player_id).ai8(1).ai8(m_next_id); m_listener->sendMessageExcept(this, peer, message); /// now answer to the peer that just connected RandomGenerator token_generator; // use 4 random numbers because rand_max is probably 2^15-1. uint32_t token = (uint32_t)(((token_generator.get(RAND_MAX)<<24) & 0xff) + ((token_generator.get(RAND_MAX)<<16) & 0xff) + ((token_generator.get(RAND_MAX)<<8) & 0xff) + ((token_generator.get(RAND_MAX) & 0xff))); // send a message to the one that asked to connect NetworkString message_ack; // connection success (129) -- size of token -- token message_ack.ai8(0x81).ai8(1).ai8(m_next_id).ai8(4).ai32(token).ai8(4).ai32(player_id); // add all players so that this user knows std::vector<NetworkPlayerProfile*> players = m_setup->getPlayers(); for (unsigned int i = 0; i < players.size(); i++) { // do not duplicate the player into the message if (players[i]->race_id != m_next_id && players[i]->user_profile->getID() != player_id) message_ack.ai8(1).ai8(players[i]->race_id).ai8(4).ai32(players[i]->user_profile->getID()); } m_listener->sendMessage(this, peer, message_ack); peer->setClientServerToken(token); NetworkPlayerProfile* profile = new NetworkPlayerProfile(); profile->race_id = m_next_id; profile->kart_name = ""; profile->user_profile = new Online::OnlineProfile(player_id, ""); m_setup->addPlayer(profile); peer->setPlayerProfile(profile); Log::verbose("ServerLobbyRoomProtocol", "New player."); } // accept player else // refuse the connection with code 0 (too much players) { NetworkString message; message.ai8(0x80); // 128 means connection refused message.ai8(1); // 1 bytes for the error code message.ai8(0); // 0 = too much players // send only to the peer that made the request m_listener->sendMessage(this, peer, message); Log::verbose("ServerLobbyRoomProtocol", "Player refused"); } }