/** * Plays an in-game message. * * @param msg_idx Message index * @param delay Delay between the message can be repeated. * @param queue True will allow the message to queue, * false will play it immediately or never. * @return Gives true if the message was prepared to play or queued. * If the message couldn't be played nor queued, returns false. */ TbBool output_message(long msg_idx, long delay, TbBool queue) { struct SMessage *smsg; long i; SYNCDBG(5,"Message %ld, delay %ld, queue %s",msg_idx, delay, queue?"on":"off"); smsg = &messages[msg_idx]; if (!message_can_be_played(msg_idx)) { SYNCDBG(8,"Delay to turn %ld didn't passed, skipping",(long)smsg->end_time); return false; } if (!speech_sample_playing()) { i = get_phrase_sample(get_phrase_for_message(msg_idx)); if (i == 0) { SYNCDBG(8,"No phrase %d sample, skipping",(int)msg_idx); return false; } if (play_speech_sample(i)) { message_playing = msg_idx; smsg->end_time = (long)game.play_gameturn + delay; SYNCDBG(8,"Playing prepared"); return true; } } if ( (msg_idx == message_playing) || (message_already_in_queue(msg_idx)) ) { SYNCDBG(8,"Message %ld is already in queue",msg_idx); return false; } if (queue) { if (add_message_to_queue(msg_idx, delay)) { SYNCDBG(8,"Playing queued"); return true; } } WARNDBG(8,"Playing message %ld failed",msg_idx); return false; }
int packet_assembly_thread(void * data) { struct client_params * cur; struct pcap_packet * packets, *local_list, *cur_packet_list, *prev, *cur2; _packet_assembly_thread_stopped = 0; local_list = NULL; uint32_t fcs; char * temp_str; int bad_frame; #ifdef DEBUG add_message_to_queue(MESSAGE_TYPE_REG_LOG, NULL, 1, "Packet assembly thread started", 1); #endif while (!_stop_threads && !_stop_packet_assembly_thread) { // Check that the server is initialized if (_sensor_server_params == NULL) { usleep(5000); continue; } // Check if it has clients if (_sensor_server_params->client_list == NULL) { usleep(10000); continue; } // TODO: Check the client isn't dead and thus being removed/free (there is probably a mutex next to the dead check function) // 1. Search in all connected clients (rpcap) ... for (cur = _sensor_server_params->client_list; cur != NULL; cur = cur->next) { if (!(cur->rpcap_server && cur->rpcap_server->client_list && /*&& cur->rpcap_server->client_list->client->connected*/ cur->rpcap_server->client_list->received_packets && cur->rpcap_server->client_list->received_packets->nb_packet && cur->rpcap_server->client_list->received_packets->pcap_header)) { continue; } // Is there any packet in the structure // ... RPCAP is connected, we probably have some packets (take all) ... packets = get_packets(INT_MAX, &(cur->rpcap_server->client_list->received_packets)); if (packets == NULL) { continue; } // Tag all packets with socket id (TODO: Use sensor login) for (cur_packet_list = packets; cur_packet_list != NULL; cur_packet_list = cur_packet_list->next) { cur_packet_list->source = cur->rpcap_server->client_list->client->sock; cur_packet_list->linktype = cur->rpcap_server->client_list->received_packets->pcap_header->linktype; } // ... and add them to our local list if (local_list == NULL) { local_list = packets; } else { for (cur_packet_list = local_list; cur_packet_list->next != NULL; cur_packet_list = cur_packet_list->next); cur_packet_list->next = packets; } packets = NULL; } if (!local_list) { usleep(100); continue; } // 2. Remove bad CRC/FCS prev = NULL; cur_packet_list = local_list; while (cur_packet_list != NULL) { bad_frame = 1; if (cur_packet_list->header.cap_len < MIN_PACKET_SIZE + FCS_SIZE) { temp_str = (char *)calloc(1, 200 * sizeof(char)); sprintf(temp_str, "Received invalid packet - frame too short to be analyzed. Expected %d bytes, received %u.", MIN_PACKET_SIZE + FCS_SIZE, cur_packet_list->header.cap_len); add_message_to_queue(MESSAGE_TYPE_ANOMALY, NULL, 1, temp_str, 0); } else { // Get packet information cur_packet_list->info = parse_packet_basic_info(cur_packet_list); if (cur_packet_list->info != NULL) { // If FCS is bad, discard the frame and log it. if (cur_packet_list->info->bad_fcs) { #ifdef EXTRA_DEBUG add_message_to_queue(MESSAGE_TYPE_DEBUG, NULL, 1, "Invalid FCS flags set. Ignoring frame", 1); #endif } else if (_force_fcs_check && cur_packet_list->info->fcs_present) { // Check FCS before processing frame (ignore if invalid but log it in DB). fcs = crc32(0L, cur_packet_list->info->frame_start, cur_packet_list->header.cap_len - FCS_SIZE - cur_packet_list->info->packet_header_len); if (fcs != cur_packet_list->info->fcs) { #ifdef EXTRA_DEBUG temp_str = (char *)calloc(1, 80); fprintf(stderr, "Invalid FCS: Got 0x%x, expected 0x%x. Ignoring frame", cur_packet_list->info->fcs, fcs); add_message_to_queue(MESSAGE_TYPE_DEBUG, NULL, 1, temp_str, 0); #endif } else bad_frame = 0; } else bad_frame = 0; } } if (!bad_frame) { prev = cur_packet_list; cur_packet_list = cur_packet_list->next; continue; } // Remove frame from list if (prev == NULL) { // First frame of the list local_list = cur_packet_list->next; free_pcap_packet(&cur_packet_list, 0); // Free cur_packet_list = local_list; } else { cur2 = cur_packet_list; prev->next = cur_packet_list->next; cur_packet_list = cur_packet_list->next; free_pcap_packet(&cur2, 0); // Free } } // 3. TODO: Remove duplicates (within 1 second of the last received packet) within several sources // Easy in most cases thanks to the Sequence Number (or FCS if it present) // More problematic with Control packets (can use FCS if present) but also need to check time difference more accurately) // 4. TODO: Re-order (if needed) // 5. Put it on the list add_multiple_packets_to_list(local_list, &_receive_packet_list, 1); local_list = NULL; // Make sure the CPU won't get overloaded usleep(250); } _packet_assembly_thread_stopped = 1; return EXIT_SUCCESS; }