int chitcpd_tcp_state_handle_ESTABLISHED(serverinfo_t *si, chisocketentry_t *entry, tcp_event_type_t event){ tcp_data_t *data = &entry->socket_state.active.tcp_data; if (event == APPLICATION_SEND) { send_all(si,entry,data); } else if (event == PACKET_ARRIVAL) { while (!list_empty(&data->pending_packets) && circular_buffer_available(&data->recv)){ pthread_mutex_lock(&data->lock_pending_packets); tcp_packet_t *pack = list_fetch(&(data->pending_packets)); pthread_mutex_unlock(&data->lock_pending_packets); tcphdr_t * head = TCP_PACKET_HEADER(pack); if (!acceptability_test(data, pack)) { send_ACK(si, entry, data); chitcp_tcp_packet_free(pack); return CHITCP_OK; } if (!head->syn && head->ack) { if (inside_window(data, pack)) update_WND_and_UNA(data, pack); if (TCP_PAYLOAD_LEN(pack)) use_data(si, entry, data, pack); if (head->fin){ always_on_fb(si, entry, data, pack); chitcpd_update_tcp_state(si, entry, CLOSE_WAIT); } } chitcp_tcp_packet_free(pack); } } else if (event == APPLICATION_RECEIVE){ data->RCV_WND = circular_buffer_available(&data->recv); } else if (event == APPLICATION_CLOSE){ send_all(si,entry,data); tcp_packet_t *new_pack = (tcp_packet_t*)malloc(sizeof(tcp_packet_t)); chitcpd_tcp_packet_create(entry,new_pack,NULL,0); tcphdr_t *FIN = TCP_PACKET_HEADER(new_pack); FIN->seq = chitcp_htonl(data->SND_NXT); FIN->ack_seq = chitcp_htonl(data->RCV_NXT); FIN->fin = 1; FIN->win = chitcp_htons(data->RCV_WND); chilog_tcp(CRITICAL,new_pack,LOG_OUTBOUND); chitcpd_send_tcp_packet(si,entry,new_pack); circular_buffer_close(&data->recv); circular_buffer_close(&data->send); chitcpd_update_tcp_state(si,entry,FIN_WAIT_1); chitcp_tcp_packet_free(new_pack); } else chilog(WARNING, "In ESTABLISHED state, received unexpected event (%i).", event); return CHITCP_OK; }
/* * chitcpd_server_thread_func - Server thread function * * This function will spawn a handler thread (see handler.c) for each * new connection on the UNIX socket. * * args: arguments (a serverinfo_t variable in server_threads_args_t) * * Returns: Nothing. * */ void* chitcpd_server_thread_func(void *args) { socklen_t sunSize; handler_thread_t *handler_thread; server_thread_args_t *sta; serverinfo_t *si; handler_thread_args_t *ha; list_t handler_thread_list; int rc; ChitcpdMsg *req; ChitcpdInitArgs *init_args; ChitcpdConnectionType conntype; ChitcpdMsg resp_outer = CHITCPD_MSG__INIT; ChitcpdResp resp_inner = CHITCPD_RESP__INIT; resp_outer.code = CHITCPD_MSG_CODE__RESP; resp_outer.resp = &resp_inner; /* For naming the handler threads we create (for debugging/logging) */ int next_thread_id = 0; pthread_setname_np(pthread_self(), "unix_server"); /* Unpack arguments */ sta = (server_thread_args_t *) args; si = sta->si; list_init(&handler_thread_list); struct sockaddr_un client_addr; /* Accept connections on the UNIX socket */ for(;;) { socket_t client_socket; /* Accept a connection */ sunSize = sizeof(client_addr); if ((client_socket = accept(si->server_socket, (struct sockaddr *)&client_addr, &sunSize)) == -1) { /* If accept() returns in the CHITCPD_STATE_STOPPING, we don't * care what the error is. We just break out of the loop and * initiate an orderly shutdown. */ if(si->state == CHITCPD_STATE_STOPPING) break; /* If this particular connection fails, no need to kill the entire thread. */ perror("Could not accept() connection on UNIX socket"); continue; } /* We receive a single message, which has to be an INIT message */ rc = chitcpd_recv_msg(client_socket, &req); if (rc < 0) { if(si->state == CHITCPD_STATE_STOPPING) break; else { chilog(ERROR, "Error when receiving lead message through UNIX socket"); shutdown(client_socket, SHUT_RDWR); continue; } } if(req->code != CHITCPD_MSG_CODE__INIT) { chilog(ERROR, "Expected INIT message, instead got message code %i", req->code); chitcpd_msg__free_unpacked(req, NULL); shutdown(client_socket, SHUT_RDWR); continue; } /* Unpack INIT request */ assert(req->init_args != NULL); init_args = req->init_args; conntype = init_args->connection_type; /* There are two types of connections: command connections and debug * connections. * * When a command connection is created, a new thread is created to * handle the incoming chisocket commands on that connection (socket, * send, recv, etc.) * * When a debug connection is created, no additional thread is necessary. * The connection on the UNIX socket is simply "handed off" to a * debug monitor that will be associated with a chiTCP socket. * That UNIX socket is then used to send back debug messages. */ if (conntype == CHITCPD_CONNECTION_TYPE__COMMAND_CONNECTION) { /* Create arguments for handler thread */ ha = malloc(sizeof(handler_thread_args_t)); ha->si = si; handler_thread = malloc(sizeof(handler_thread_t)); handler_thread->handler_socket = client_socket; pthread_mutex_init(&handler_thread->handler_lock, NULL); /* Create handler thread to handle this connection */ ha->client_socket = handler_thread->handler_socket; ha->handler_lock = &handler_thread->handler_lock; snprintf(ha->thread_name, 16, "socket-layer-%d", next_thread_id++); if (pthread_create(&handler_thread->thread, NULL, chitcpd_handler_dispatch, ha) != 0) { perror("Could not create a worker thread"); resp_outer.resp->ret = CHITCP_ETHREAD; resp_outer.resp->error_code = 0; rc = chitcpd_send_msg(client_socket, &resp_outer); free(ha); close(ha->client_socket); close(si->server_socket); // TODO: Perform an orderly shutdown instead of exiting pthread_exit(NULL); } resp_outer.resp->ret = CHITCP_OK; resp_outer.resp->error_code = 0; rc = chitcpd_send_msg(client_socket, &resp_outer); list_append(&handler_thread_list, handler_thread); } else if(conntype == CHITCPD_CONNECTION_TYPE__DEBUG_CONNECTION) { int debug_sockfd, debug_event_flags; ChitcpdDebugArgs *debug_args; /* Unpack debug parameter */ assert(init_args->debug != NULL); debug_args = init_args->debug; debug_sockfd = debug_args->sockfd; debug_event_flags = debug_args->event_flags; rc = chitcpd_init_debug_connection(si, debug_sockfd, debug_event_flags, client_socket); if(rc == CHITCP_OK) { resp_outer.resp->ret = CHITCP_OK; resp_outer.resp->error_code = 0; rc = chitcpd_send_msg(client_socket, &resp_outer); } else { chilog(ERROR, "Error when creating debug connection for socket %i", debug_sockfd); resp_outer.resp->ret = CHITCP_EINIT; resp_outer.resp->error_code = rc; rc = chitcpd_send_msg(client_socket, &resp_outer); shutdown(client_socket, SHUT_RDWR); } } else { chilog(ERROR, "Received INIT message with unknown connection type %i", conntype); resp_outer.resp->ret = CHITCP_EINVAL; resp_outer.resp->error_code = 0; rc = chitcpd_send_msg(client_socket, &resp_outer); shutdown(client_socket, SHUT_RDWR); } chitcpd_msg__free_unpacked(req, NULL); } while(!list_empty(&handler_thread_list)) { /* For each handler thread we spawned, we close its socket, which * will force the thread to exit (and we then join it). * * Note that closing a handler thread will also free up all chiTCP * sockets created through that thread, and will also terminate * all associated TCP threads. * * TODO: We should simply detach those threads, since they can exit * before an orderly shutdown and would be left lingering until * we call join here. */ handler_thread_t *ht = list_fetch(&handler_thread_list); /* We don't want to shutdown the handler's socket if an operation is * in progress. The handler thread may have read a command, but * not sent a response back yet */ pthread_mutex_lock(&ht->handler_lock); shutdown(ht->handler_socket, SHUT_RDWR); pthread_mutex_unlock(&ht->handler_lock); pthread_join(ht->thread, NULL); pthread_mutex_destroy(&ht->handler_lock); free(ht); } list_destroy(&handler_thread_list); chilog(DEBUG, "Server thread is exiting."); pthread_exit(NULL); }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Update the csv context with the latest contents from the * Falcon. For each buffer that has at least on hour worth of * data, compress and write the data to the diskloop. */ void csv_poll( csv_context_t* csv_buffer_list, buffer_t* url_str, st_info_t* st_info, time_t initial_time ) { list_t* file_list = NULL; buffer_t* buf = NULL; buffer_t* url = NULL; char* file_name = NULL; const char* path = "/data/minute"; csv_buffer_t csv_tmp; csv_buffer_t* csv_buffer; int location = 0; uint64_t file_hash = 0LL; uint8_t buffer_found = 0; int tally = 0; // Build the CSV directory URL url = buffer_init(); buffer_write(url, url_str->content, url_str->length); buffer_write(url, (uint8_t*)path, strlen(path)); buffer_terminate(url); // Initialize the CSV file list file_list = (list_t*)malloc(sizeof(list_t)); if (!file_list) goto clean; list_init(file_list); list_attributes_seeker( file_list, _file_list_seeker ); list_attributes_comparator( file_list, _file_list_comparator ); // Get the html page listing the available CSV files buf = buffer_init(); get_page((char*)url->content, buf); // Generate a list of files from the page if (!csv_get_file_list(file_list, buf)) goto clean; buffer_reset(buf); buffer_reset(url); // Step through each CSV file and update its csv_buffer // in the csv_buffer_list while (!list_empty(file_list)) { tally++; file_name = (char*)list_fetch(file_list); memset(&csv_tmp, 0, sizeof(csv_tmp)); csv_tmp.file_name = file_name; // If there is not a csv buffer for this csv file, create a // new buffer and add it to the list if ((location = list_locate(csv_buffer_list, &csv_tmp)) < 0) { csv_buffer = csv_buffer_init(); csv_buffer->file_name = file_name; list_append(csv_buffer_list, csv_buffer); buffer_found = 0; // Otherwise re-use the old csv buffer } else { csv_buffer = (csv_buffer_t*)list_get_at(csv_buffer_list, location); buffer_found = 1; } // Process the contents of this CSV file // Generate the URL for retrieving the file buffer_write(url, url_str->content, url_str->length); buffer_write(url, (uint8_t*)csv_buffer->file_name, strlen(csv_buffer->file_name)); buffer_terminate(url); if (gDebug) { printf("getting page %s\n", url->content); } // Download the file get_page((char*)url->content, buf); file_hash = murmur_64_b( buf->content, buf->length, HASH_SEED_64 ); if (gDebug) { fprintf(stderr, "file '%s' [0x%016llx] uncompressed size is %lu bytes\n", csv_buffer->file_name, (unsigned long long)file_hash, (unsigned long)buf->length); if (strcmp("/data/minute/logm1.csv", csv_buffer->file_name) == 0) fprintf(stderr, "'%s'\n", buf->content); } // Populate a csv_buffer with the contents of the file csv_parse_file(csv_buffer, buf, initial_time); if (gDebug) { fprintf(stderr, "The CSV buffer contains %u rows\n", csv_buffer->list->numels); } // Empty our temporary buffers buffer_reset(buf); buffer_reset(url); if (buffer_found) { free(file_name); } file_name = NULL; csv_buffer = NULL; } // Clean up all temporary resources clean: buf = buffer_destroy(buf); url = buffer_destroy(url); if (file_list) { while(!list_empty(file_list)) { file_name = list_fetch(file_list); if (file_name) { free(file_name); } } list_destroy(file_list); free(file_list); } } // csv_poll()