int chitcpd_tcp_state_handle_SYN_SENT(serverinfo_t *si, chisocketentry_t *entry, tcp_event_type_t event){ tcp_data_t *data = &entry->socket_state.active.tcp_data; if (event == PACKET_ARRIVAL){ 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); /* This condition checks if there is an ack that it is acceptable and there is a syn*/ if (((head->ack && ((data->SND_UNA <= SEG_ACK(pack)) && (SEG_ACK(pack) <= data->SND_NXT))) || !head->ack) && head->syn){ data->RCV_NXT = SEG_SEQ(pack)+1; data->IRS = SEG_SEQ(pack); if (head->ack){ //only if its an ack data->SND_WND = SEG_WND(pack); data->SND_UNA = SEG_ACK(pack); } if (data->SND_UNA > data->ISS){ send_ACK(si, entry, data); data->SND_UNA = data->SND_NXT; chitcpd_update_tcp_state(si,entry,ESTABLISHED); chitcp_tcp_packet_free(pack); return CHITCP_OK; } else { tcp_packet_t *new_pack = (tcp_packet_t*)malloc(sizeof(tcp_packet_t)); chitcpd_tcp_packet_create(entry,new_pack,NULL,0); tcphdr_t *SYN_ACK = TCP_PACKET_HEADER(new_pack); SYN_ACK->seq = chitcp_htonl(data->ISS); SYN_ACK->ack_seq = chitcp_htonl(data->RCV_NXT); SYN_ACK->syn = 1; SYN_ACK->ack = 1; SYN_ACK->win = chitcp_htons(data->RCV_WND); chilog_tcp(CRITICAL,new_pack,LOG_OUTBOUND); chitcpd_send_tcp_packet(si,entry,new_pack); chitcpd_update_tcp_state(si,entry,SYN_RCVD); chitcp_tcp_packet_free(pack); chitcp_tcp_packet_free(new_pack); return CHITCP_OK; } } } else chilog(WARNING, "In SYN_SENT state, received unexpected event."); return CHITCP_OK; }
int chitcpd_tcp_state_handle_CLOSING(serverinfo_t *si, chisocketentry_t *entry, tcp_event_type_t event) { tcp_data_t *data = &entry->socket_state.active.tcp_data; if (event == PACKET_ARRIVAL) { while (!list_empty(&data->pending_packets)) { 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->ack) { if (inside_window(data, pack)) { update_WND_and_UNA(data, pack); chitcpd_update_tcp_state(si, entry, TIME_WAIT); } if (head->fin) always_on_fb(si, entry, data, pack); } chitcp_tcp_packet_free(pack); } } else chilog(WARNING, "In CLOSING state, received unexpected event (%i).", event); return CHITCP_OK; }
int chitcpd_tcp_state_handle_SYN_RCVD(serverinfo_t *si, chisocketentry_t *entry, tcp_event_type_t event){ tcp_data_t *data = &entry->socket_state.active.tcp_data; if (event == PACKET_ARRIVAL){ 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)){ //Its acceptable, but is this true in all cases or just receiving information if (head->ack && ((data->SND_UNA <= SEG_ACK(pack)) && (SEG_ACK(pack) <= data->SND_NXT))){ data->SND_UNA = data->SND_NXT; data->SND_WND = SEG_WND(pack); chitcpd_update_tcp_state(si,entry,ESTABLISHED); } else { send_ACK(si, entry, data); data->SND_WND = SEG_WND(pack); } } chitcp_tcp_packet_free(pack); } else chilog(WARNING, "In SYN_RCVD state, received unexpected event."); return CHITCP_OK; }
int chitcpd_tcp_state_handle_CLOSE_WAIT(serverinfo_t *si, chisocketentry_t *entry, tcp_event_type_t event) { tcp_data_t *data = &entry->socket_state.active.tcp_data; if (event == APPLICATION_CLOSE) { 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); send_all(si, entry, data); 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,LAST_ACK); chitcp_tcp_packet_free(new_pack); } else if (event == PACKET_ARRIVAL) { while (!list_empty(&data->pending_packets)) { 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->ack) { if (inside_window(data, pack)) update_WND_and_UNA(data, pack); if (head->fin){ always_on_fb(si, entry, data, pack); } } chitcp_tcp_packet_free(pack); } } else chilog(WARNING, "In CLOSE_WAIT state, received unexpected event (%i).", event); return CHITCP_OK; }
int chitcpd_tcp_state_handle_LISTEN(serverinfo_t *si, chisocketentry_t *entry, tcp_event_type_t event){ tcp_data_t *data = &entry->socket_state.active.tcp_data; if (event == PACKET_ARRIVAL) { 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 (head->syn) { data->RCV_NXT = SEG_SEQ(pack) + 1; data->IRS = SEG_SEQ(pack); data->ISS = rand() % 1000 + 1; data->RCV_WND = circular_buffer_available(&data->recv); tcp_packet_t *new_pack = (tcp_packet_t*)malloc(sizeof(tcp_packet_t)); chitcpd_tcp_packet_create(entry,new_pack,NULL,0); tcphdr_t *SYN_ACK = TCP_PACKET_HEADER(new_pack); SYN_ACK->seq = chitcp_htonl(data->ISS); SYN_ACK->ack_seq = chitcp_htonl(data->RCV_NXT); SYN_ACK->syn = 1; SYN_ACK->ack = 1; SYN_ACK->win = chitcp_htons(data->RCV_WND); chilog_tcp(CRITICAL,new_pack,LOG_OUTBOUND); chitcpd_send_tcp_packet(si,entry,new_pack); data->SND_WND = SEG_WND(pack); data->SND_NXT = data->ISS + 1; data->SND_UNA = data->ISS; chitcpd_update_tcp_state(si,entry,SYN_RCVD); chitcp_tcp_packet_free(pack); chitcp_tcp_packet_free(new_pack); return CHITCP_OK; } } else chilog(WARNING, "In LISTEN state, received unexpected event."); return CHITCP_OK; }
int chitcpd_tcp_state_handle_CLOSED(serverinfo_t *si, chisocketentry_t *entry, tcp_event_type_t event){ tcp_data_t *data = &entry->socket_state.active.tcp_data; if (event == APPLICATION_CONNECT) { /* Initializes the data */ data->ISS = rand() % 1000 + 1; data->SND_UNA = data->ISS; data->SND_NXT = data->ISS + 1; data->RCV_WND = circular_buffer_available(&data->recv); tcp_packet_t *pack = (tcp_packet_t*)malloc(sizeof(tcp_packet_t)); chitcpd_tcp_packet_create(entry,pack,NULL,0); tcphdr_t *SYN = TCP_PACKET_HEADER(pack); SYN->seq = chitcp_htonl(data->ISS); SYN->ack_seq = chitcp_htonl(data->ISS + 1); SYN->syn = 1; SYN->win = chitcp_htons(data->RCV_WND); chilog_tcp(CRITICAL,pack,LOG_OUTBOUND); chitcpd_send_tcp_packet(si,entry,pack); chitcpd_update_tcp_state(si,entry,SYN_SENT); chitcp_tcp_packet_free(pack); } else if (event == CLEANUP) { chitcpd_free_socket_entry(si, entry); pthread_exit(NULL); /* Any additional cleanup goes here */ } else chilog(WARNING, "In CLOSED state, received unexpected event."); return CHITCP_OK; }
int chitcpd_tcp_state_handle_LAST_ACK(serverinfo_t *si, chisocketentry_t *entry, tcp_event_type_t event) { tcp_data_t *data = &entry->socket_state.active.tcp_data; if (event == PACKET_ARRIVAL) { while (!list_empty(&data->pending_packets)){ 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->ack) { if (inside_window(data, pack)) { circular_buffer_free(&data->recv); circular_buffer_free(&data->send); list_destroy(&data->pending_packets); pthread_mutex_destroy(&data->lock_pending_packets); pthread_mutex_destroy(&data->lock_withheld_packets); list_destroy(&data->withheld_packets); free(data); chitcpd_update_tcp_state(si, entry, CLOSED); } } chitcp_tcp_packet_free(pack); } } else chilog(WARNING, "In LAST_ACK state, received unexpected event (%i).", event); return CHITCP_OK; }
/* * chitcpd_handler_dispatch - Handler thread function * * Handles a connection on chitcpd's UNIX socket, and dispatches * incoming requests to the appropriate function, using the * dispatch table defined above. * * args: arguments (in handler_thread_args_t) * * Returns: Nothing. * */ void* chitcpd_handler_dispatch(void *args) { handler_thread_args_t *ha = (handler_thread_args_t *) args; serverinfo_t *si = ha->si; socket_t client_socket = ha->client_socket; pthread_mutex_t *handler_lock = ha->handler_lock; pthread_setname_np(pthread_self(), ha->thread_name); ChitcpdMsg *req; ChitcpdMsg resp_outer = CHITCPD_MSG__INIT; ChitcpdResp resp_inner = CHITCPD_RESP__INIT; bool_t done = FALSE; /* Should we keep looping? */ int rc; resp_outer.code = CHITCPD_MSG_CODE__RESP; resp_outer.resp = &resp_inner; do { rc = chitcpd_recv_msg(client_socket, &req); if (rc < 0) break; chilog(TRACE, "Received request (code=%s)", handler_code_string(req->code)); /* We have received a request, so we grab the handler lock to * prevent a race condition when the server is shutting down */ pthread_mutex_lock(handler_lock); /* Call handler function using dispatch table */ rc = handlers[req->code](si, req, &resp_inner); chitcpd_msg__free_unpacked(req, NULL); if(rc != CHITCP_OK) { chilog(ERROR, "Error when handling request."); /* We don't need to bail out just because one request failed */ } /* Send response */ rc = chitcpd_send_msg(client_socket, &resp_outer); if (resp_inner.has_buf) { /* This buffer was allocated in RECV. */ free(resp_inner.buf.data); resp_inner.has_buf = FALSE; } if (resp_inner.socket_state != NULL) { /* This submessage was allocated in GET_SOCKET_STATE. */ free(resp_inner.socket_state); resp_inner.socket_state = NULL; } if (resp_inner.socket_buffer_contents != NULL) { /* This submessage was allocated in GET_SOCKET_BUFFER_CONTENTS. */ if (resp_inner.socket_buffer_contents->snd.data != NULL) free(resp_inner.socket_buffer_contents->snd.data); if (resp_inner.socket_buffer_contents->rcv.data != NULL) free(resp_inner.socket_buffer_contents->rcv.data); free(resp_inner.socket_buffer_contents); resp_inner.socket_buffer_contents = NULL; } /* We're done processing the request (we've run the handler and * we've returned a response). We can release the handler lock and, * if a shutdown is in progress, it will make sure it can proceed * safely */ pthread_mutex_unlock(handler_lock); if (rc < 0) break; } while (!done); /* TODO: Be more discerning about what kind of shutdown this is */ if(si->state == CHITCPD_STATE_STOPPING) chilog(DEBUG, "chiTCP daemon is stopping. Freeing open sockets for this handler..."); else chilog(DEBUG, "Daemon client has disconnected. Freeing open sockets for this handler..."); int freed_sockets = 0; for(int i=0; i < si->chisocket_table_size; i++) { chisocketentry_t *entry = &si->chisocket_table[i]; if(!entry->available && entry->creator_thread == pthread_self()) { chilog(DEBUG, "Freeing socket %i", i); /* TODO: The connection should be aborted (not closed) here. * However, we do not currently support the ABORT call or * RST's so we simply "force close" each socket. */ if(entry->actpas_type == SOCKET_ACTIVE) { /* Any transition to CLOSED will force a termination of the TCP thread */ chitcpd_update_tcp_state(si, entry, CLOSED); pthread_join(entry->socket_state.active.tcp_thread, NULL); } else if(entry->actpas_type == SOCKET_PASSIVE) chitcpd_free_socket_entry(si, entry); freed_sockets++; /* TODO: Close the connection */ } } if (freed_sockets) chilog(DEBUG, "Done freeing open sockets."); else chilog(DEBUG, "This handler had no sockets to free."); chilog(DEBUG, "Handler is exiting."); free(args); return NULL; }