void PipeConnectionCreator::create_connection_for( std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket) { auto const messenger = std::make_shared<network::LocalSocketMessenger>(socket); const auto type = identify_client(messenger); auto const processor = create_processor(type, messenger); if (!processor) BOOST_THROW_EXCEPTION(std::runtime_error("Unhandled client type")); auto const &connection = std::make_shared<network::SocketConnection>( messenger, messenger, next_id(), connections_, processor); connection->set_name(client_type_to_string(type)); connections_->add(connection); connection->read_next_message(); }
std::string peer_alert::message() const { error_code ec; return torrent_alert::message() + " peer (" + ip.address().to_string(ec) + ", " + identify_client(pid) + ")"; }
std::string peer_alert::message() const { error_code ec; return torrent_alert::message() + " peer (" + print_endpoint(ip) + ", " + identify_client(pid) + ")"; }
/*! * main loop. Accept contribution from clients and dispatch digest of * the frame to all clients */ void serve_dispatch (global_option_type * global_option) { global_status_type global_status; int client_index; /* * Initialize global_status fields */ global_status.frame_number = 1; global_status.number_identified_players = 0; global_status.number_allocation_request = 0; #if defined(GTK) gtk_stop_asked = 0; #endif for (client_index = 0; client_index < MAX_NUMBER_PLAYER; client_index++) { global_status.player_status[client_index] = UNIDENTIFIED; } global_status.server_socket = SDLNet_UDP_Open (global_option->server_port); if (global_status.server_socket == NULL) { printf_screen ("Couldn't open UDP socket on port %d.\nCheck privileges and availability.\n", global_option->server_port); return; } /* global_status.server_socket is ready to serve our needs :) */ global_status.current_packet = SDLNet_AllocPacket (CLIENT_PACKET_SIZE); if (global_status.current_packet == NULL) { SDLNet_UDP_Close (global_status.server_socket); printf_screen ("Failed to allocate a buffer for receiving client packets (size: %d bytes) (Not enough memory ?)", CLIENT_PACKET_SIZE); return; } global_status.digest_packet = SDLNet_AllocPacket (SERVER_PACKET_SIZE); if (global_status.digest_packet == NULL) { SDLNet_UDP_Close (global_status.server_socket); SDLNet_FreePacket (global_status.digest_packet); printf_screen ("Failed to allocate a buffer for sending packets (size: %d bytes) (Not enough memory ?)", SERVER_PACKET_SIZE); return; } /* Allocate enough space for a single socket */ global_status.server_socket_set = SDLNet_AllocSocketSet (1); if (global_status.server_socket_set == NULL) { SDLNet_UDP_Close (global_status.server_socket); SDLNet_FreePacket (global_status.current_packet); SDLNet_FreePacket (global_status.digest_packet); printf_screen ("Couldn't allocate a socket set (not enough memory ?).\n"); return; } if (SDLNet_UDP_AddSocket (global_status.server_socket_set, global_status.server_socket) != 1) { SDLNet_UDP_Close (global_status.server_socket); SDLNet_FreePacket (global_status.current_packet); SDLNet_FreePacket (global_status.digest_packet); SDLNet_FreeSocketSet (global_status.server_socket_set); printf_screen ("Error when adding socket to socket set.\n"); return; } /* Identification loop */ /* * We're expecting identification packets until we've filled all slots, then * we can proceed to the real meat */ for (;;) { int number_ready_socket; #if defined(DEBUG) printf_screen ("Waiting for identification\n"); #endif if (read_incoming_server_packet (&global_status)) { identify_client (&global_status, global_option); if (count_remaining_slot (&global_status, global_option) == 0) { /* Perfect, we've finished the identification of all slots */ break; } printf_screen("%d slots open.\n", count_remaining_slot (&global_status, global_option)); /* Going back to the identification loop */ continue; } #if defined(GTK) gtk_iteration = GTK_SERVER_SOCKET_RATIO; do { number_ready_socket = SDLNet_CheckSockets (global_status.server_socket_set, SERVER_SOCKET_TIMEOUT / GTK_SERVER_SOCKET_RATIO); while (gtk_events_pending()) { if (gtk_main_iteration()) { gtk_stop_asked = 1; } } } while ( (number_ready_socket == 0) && (--gtk_iteration != 0) && !gtk_stop_asked); #else number_ready_socket = SDLNet_CheckSockets (global_status.server_socket_set, SERVER_SOCKET_TIMEOUT); #endif if (gtk_stop_asked) { break; } if (number_ready_socket == -1) { printf_screen ("Error in socket waiting (disconnection ?).\n"); break; } if (number_ready_socket == 1) { #if defined(DEBUG) printf_screen ("Got a packet\n"); #endif /* We're awaiting a packet in the server socket */ if (read_incoming_server_packet (&global_status)) { /* * If we haven't identified all clients yet, we're trying to use the current packet * to improve our knowledge of the typography */ identify_client (&global_status, global_option); if (count_remaining_slot (&global_status, global_option) == 0) { /* Perfect, we've finished the identification of all slots */ break; } printf_screen("%d slots open.\n", count_remaining_slot (&global_status, global_option)); } } } if (!gtk_stop_asked) { printf_screen ("Identification finished\n"); #if defined(DEBUG) for (client_index = 0; client_index < MAX_NUMBER_PLAYER; client_index++) { printf_screen ("Mapping[%d] = { { 0x%08X, %d }, %d }\n", client_index, global_status.input_mapping[client_index].address.host, global_status.input_mapping[client_index].address.port, global_status.input_mapping[client_index].remote_input_device); } #endif switch (global_option->type_server) { case LAN_PROTOCOL_TYPE: serve_clients_lan_protocol(&global_status, global_option); break; case INTERNET_PROTOCOL_TYPE: serve_clients_internet_protocol(&global_status, global_option); break; default: printf_screen("Internal error, unknown internal server type : %d\n", global_option->type_server); break; } } // gtk_stop_asked /* * Free resources */ SDLNet_FreePacket (global_status.current_packet); SDLNet_FreePacket (global_status.digest_packet); SDLNet_FreeSocketSet (global_status.server_socket_set); SDLNet_UDP_Close (global_status.server_socket); global_status.server_socket = NULL; }
/*! * Store a packet information and updates the current status as well as the next frame asked by the client */ void store_remote_status_internet (global_status_type * global_status, global_option_type * global_option) { int input_index; if (global_status->current_packet->len != PACKET_STATUS_LENGTH) { /* Discarding invalid packet */ #if defined(DEBUG) fprintf (stderr, "Invalid packet received when in status receiving phase (received length: %d, expected length: %d)\n", global_status->current_packet->len, PACKET_STATUS_LENGTH); #endif /* If may be an identification packet which was lost at some point */ identify_client (global_status, global_option); return; } if (global_status->current_packet->data[PACKET_IDENTIFIER] != PACKET_STATUS_ID) { /* Discarding invalid packet */ #if defined(DEBUG) fprintf (stderr, "Invalid packet received when in status receiving phase (received ID: 0x%02x, expected ID: 0x%02x)\n", global_status->current_packet->data[PACKET_IDENTIFIER], PACKET_STATUS_ID); #endif return; } /* TODO : add checksum testing */ for (input_index = 0; input_index < MAX_NUMBER_PLAYER; input_index++) { if (equals_address (global_status->current_packet->address, global_status->input_mapping[input_index].address)) { /* Update the status with the client status */ store_individual_status (global_status, input_index, global_status->current_packet-> data[PACKET_STATUS_INPUT_DEVICE_INDEX + global_status-> input_mapping[input_index]. remote_input_device]); if (SDLNet_Read32 (global_status->current_packet->data + PACKET_STATUS_FRAME_NUMBER) != 0) { /* The client requested a given frame */ /* Update the next frame to send to this player */ global_status->next_frame_asked[input_index] = SDLNet_Read32 (global_status->current_packet->data + PACKET_STATUS_FRAME_NUMBER); #if defined(DEBUG) if (global_status->next_frame_asked[input_index] == global_status->frame_number) { fprintf (stderr, "Great, player is waiting for the current frame, lag is less than a frame delay (player %d).\n", input_index); } if (global_status->next_frame_asked[input_index] == global_status->next_frame_to_send[input_index]) { fprintf (stderr, "Half great, we don't have packets loss, the game should be smooth (player %d).\n", input_index); } #endif if (global_status->next_frame_asked[input_index] > global_status->frame_number) { fprintf (stderr, "Error, player asked a frame which hasn't been reached yet! (asked: %d, maximum: %d)\n", global_status->next_frame_asked[input_index], global_status->frame_number); global_status->next_frame_asked[input_index] = global_status->frame_number; } if ((global_status->frame_number > AUTO_OUTDATE) && (global_status->next_frame_asked[input_index] <= global_status->frame_number - AUTO_OUTDATE)) { fprintf (stderr, "FATAL ERROR !! Player requested an outdated frame, we can't provide it! (requested : %d, available range : %d - %d)\n", global_status->next_frame_asked[input_index], global_status->frame_number - AUTO_OUTDATE, global_status->frame_number); /* TODO: think about actions which should be performed in this case. */ } /* Update the counter for sending frames */ global_status->next_frame_to_send[input_index] = global_status->next_frame_asked[input_index]; } else { #if defined(DEBUG) fprintf (stderr, "Client sends a status without requesting a specific frame.\n"); #endif } } } }
/*! * Process a status packet and updates global input status and client status */ void store_remote_status_lan (global_status_type * global_status, global_option_type * global_option) { int input_index; if (global_status->current_packet->len != PACKET_STATUS_LENGTH) { /* Discarding invalid packet */ #if defined(DEBUG) fprintf (stderr, "Invalid packet received when in status receiving phase (received length: %d, expected length: %d)\n", global_status->current_packet->len, PACKET_STATUS_LENGTH); #endif /* If may be an identification packet which was lost at some point */ identify_client (global_status, global_option); return; } if (global_status->current_packet->data[PACKET_IDENTIFIER] != PACKET_STATUS_ID) { /* Discarding invalid packet */ #if defined(DEBUG) fprintf (stderr, "Invalid packet received when in status receiving phase (received ID: 0x%02x, expected ID: 0x%02x)\n", global_status->current_packet->data[PACKET_IDENTIFIER], PACKET_STATUS_ID); #endif return; } if (global_status->frame_number != SDLNet_Read32 (global_status->current_packet->data + PACKET_STATUS_FRAME_NUMBER)) { if (global_status->frame_number == SDLNet_Read32 (global_status->current_packet->data + PACKET_STATUS_FRAME_NUMBER) + 1) { /* * This a request for the previous frame, i.e. a client lost his digest, we resend it to him */ send_previous_digest_packet (global_status, global_option, global_status->current_packet-> address); return; } /* Discarding status not corresponding to this frame */ #if defined(DEBUG) fprintf (stderr, "Invalid packet received when in status receiving phase (status for frame %d, awaiting for frame %d)\n", SDLNet_Read32 (global_status->current_packet->data + PACKET_STATUS_FRAME_NUMBER), global_status->frame_number); #endif return; } for (input_index = 0; input_index < MAX_NUMBER_PLAYER; input_index++) { if (equals_address (global_status->current_packet->address, global_status->input_mapping[input_index].address)) { if (global_status->player_status[input_index] == READY) { #if defined(DEBUG) fprintf (stderr, "We have another status for the same frame, same origin."); #endif /* TODO : check if it's the same status we already have stored */ } /* Global input number input_index will be filled by this packet status */ global_status->input_value[input_index] = global_status->current_packet-> data[PACKET_STATUS_INPUT_DEVICE_INDEX + global_status->input_mapping[input_index]. remote_input_device]; #if defined(DEBUG) fprintf (stderr, "input value[%d] = 0x%02x (data[%d])\n", input_index, global_status->current_packet-> data[PACKET_STATUS_INPUT_DEVICE_INDEX + global_status->input_mapping[input_index]. remote_input_device], PACKET_STATUS_INPUT_DEVICE_INDEX + global_status->input_mapping[input_index]. remote_input_device); #endif /* Slot is now filled */ global_status->player_status[input_index] = READY; } } }