/*! * 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; }
/*! * Process an identification request from a client, filling the interesting * fields in the global_status structure to find later the client */ void identify_client (global_status_type * global_status, global_option_type * global_option) { int requested_slots; int allocated_slots; int slot_index; int already_allocated_slot_by_client; if (global_status->current_packet->len != PACKET_IDENTIFICATION_LENGTH) { /* Discarding invalid packet */ #if defined(DEBUG) fprintf (stderr, "Invalid packet received when in identification phase (received length: %d, expected length: %d)\n", global_status->current_packet->len, PACKET_IDENTIFICATION_LENGTH); #endif return; } if (global_status->current_packet->data[PACKET_IDENTIFIER] != PACKET_IDENTIFICATION_ID) { /* Discarding invalid packet */ #if defined(DEBUG) fprintf (stderr, "Invalid packet received when in identification phase (received ID: 0x%02x, expected ID: 0x%02x)\n", global_status->current_packet->data[PACKET_IDENTIFIER], PACKET_IDENTIFICATION_ID); #endif return; } if (global_status->current_packet->data[PACKET_IDENTIFICATION_CHECKSUM] != compute_checksum (global_status->current_packet->data, PACKET_IDENTIFIER, PACKET_IDENTIFICATION_CHECKSUM)) { /* Discarding invalid packet */ #if defined(DEBUG) fprintf (stderr, "Packet checksum received when in identification phase (received checksum: 0x%02x, expected checksum: 0x%02x)\n", global_status->current_packet-> data[PACKET_IDENTIFICATION_CHECKSUM], compute_checksum (global_status->current_packet->data, PACKET_IDENTIFIER, PACKET_IDENTIFICATION_CHECKSUM)); #endif return; } requested_slots = global_status->current_packet-> data[PACKET_IDENTIFICATION_NUMBER_REQUESTED_SLOTS]; allocated_slots = min (requested_slots, count_remaining_slot (global_status, global_option)); /* Check if it's a new request or a re-request (happens when the client didn't get the acknowledgement) */ already_allocated_slot_by_client = compare_request_to_previous (global_status, global_status->current_packet->address); if (already_allocated_slot_by_client != -1) { /* We already answered this client, we'll reacknowledge */ send_identification_acknowledge_packet (global_status, already_allocated_slot_by_client); return; } for (slot_index = global_status->number_identified_players; slot_index < global_status->number_identified_players + allocated_slots; slot_index++) { /* Set the address for identified player */ global_status->input_mapping[slot_index].address.port = global_status->current_packet->address.port; global_status->input_mapping[slot_index].address.host = global_status->current_packet->address.host; /* Set the remote input device number */ global_status->input_mapping[slot_index].remote_input_device = global_status->current_packet-> data[PACKET_IDENTIFICATION_INPUT_DEVICE_INDEX + slot_index - global_status->number_identified_players]; /* Change status from UNIDENTIFIED */ global_status->player_status[slot_index] = WAITING; } global_status->allocation_request[global_status->number_allocation_request]. address.port = global_status->current_packet->address.port; global_status->allocation_request[global_status->number_allocation_request]. address.host = global_status->current_packet->address.host; global_status->allocation_request[global_status->number_allocation_request]. allocated_slots = allocated_slots; global_status->number_allocation_request++; global_status->number_identified_players += allocated_slots; send_identification_acknowledge_packet (global_status, allocated_slots); }