Esempio n. 1
0
int chitcpd_server_stop(serverinfo_t *si)
{
    int rc;

    chilog(DEBUG, "Stopping the chiTCP daemon.");

    /* To stop the server, all we need to do is shutdown the server's
     * TCP and UNIX sockets. Once the server is running, its two
     * threads (server and network) are blocking on accept() on
     * each of these two sockets. Shutting down the sockets forces
     * a return from those calls which, combined with the change
     * in the state of the server, will result in an orderly shutdown. */

    pthread_mutex_lock(&si->lock_state);
    si->state = CHITCPD_STATE_STOPPING;
    pthread_cond_broadcast(&si->cv_state);
    pthread_mutex_unlock(&si->lock_state);

    rc = shutdown(si->network_socket, SHUT_RDWR);
    if(rc != 0)
        return CHITCP_ESOCKET;

    rc = shutdown(si->server_socket, SHUT_RDWR);
    if(rc != 0)
        return CHITCP_ESOCKET;

    chilog(DEBUG, "chiTCP daemon is now in STOPPING state.");

    return CHITCP_OK;
}
Esempio n. 2
0
/*
 * chitcpd_server_wait - Wait for chiTCP daemon to exit
 *
 * si: Server info
 *
 * Returns:
 *  - CHITCP_OK: chiTCP daemon has exited correctly
 *
 */
int chitcpd_server_wait(serverinfo_t *si)
{
    chilog(DEBUG, "Waiting for chiTCP daemon to stop.");

    while(si->state != CHITCPD_STATE_STOPPED)
        pthread_cond_wait(&si->cv_state, &si->lock_state);
    pthread_mutex_unlock(&si->lock_state);

    chilog(DEBUG, "chiTCP daemon has fully stopped.");

    return CHITCP_OK;
}
Esempio n. 3
0
void chilog_chitcp(loglevel_t level, uint8_t *packet, char prefix)
{
    if(level > loglevel)
        return;

    chitcphdr_t *header = (chitcphdr_t*) packet;

    flockfile(stdout);
    chilog(level, "   ======================================================================");
    chilog(level, "%c  Payload length: %i", prefix, chitcp_ntohs(header->payload_len));
    chilog(level, "%c  Protocol: %i", prefix, header->proto);
    chilog(level, "   ======================================================================");
    funlockfile(stdout);
}
Esempio n. 4
0
// Based on http://stackoverflow.com/questions/7775991/how-to-get-hexdump-of-a-structure-data
void chilog_hex (loglevel_t level, void *data, int len)
{
    int i;
    char buf[8];
    char ascii[17];
    char line[74];
    uint8_t *pc = data;

    line[0] = '\0';
    // Process every byte in the data.
    for (i = 0; i < len; i++)
    {
        // Multiple of 16 means new line (with line offset).

        if ((i % 16) == 0)
        {
            // Just don't print ASCII for the zeroth line.
            if (i != 0)
            {
                chilog(level, "%s  %s", line, ascii);
                line[0] = '\0';
            }

            // Output the offset.
            sprintf(buf, "  %04x ", i);
            strcat(line, buf);
        }

        // Now the hex code for the specific character.
        sprintf(buf, " %02x", pc[i]);
        strcat(line, buf);

        // And store a printable ASCII character for later.
        if ((pc[i] < 0x20) || (pc[i] > 0x7e))
            ascii[i % 16] = '.';
        else
            ascii[i % 16] = pc[i];
        ascii[(i % 16) + 1] = '\0';
    }

    // Pad out last line if not exactly 16 characters.
    while ((i % 16) != 0)
    {
        strcat(line, "   ");
        i++;
    }

    // And print the final ASCII bit.
    chilog(level, "%s  %s", line, ascii);
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
/*
 * chitcpd_server_wait - Wait for chiTCP daemon to exit
 *
 * si: Server info
 *
 * Returns:
 *  - CHITCP_OK: chiTCP daemon has exited correctly
 *
 */
int chitcpd_server_wait(serverinfo_t *si)
{
    chilog(DEBUG, "Waiting for chiTCP daemon to stop.");

    /* TODO: Retrieve return values */
    pthread_join(si->server_thread, NULL);
    pthread_join(si->network_thread, NULL);

    pthread_mutex_lock(&si->lock_state);
    si->state = CHITCPD_STATE_STOPPED;
    pthread_cond_broadcast(&si->cv_state);
    pthread_mutex_unlock(&si->lock_state);

    chilog(DEBUG, "chiTCP daemon has fully stopped.");

    return CHITCP_OK;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
void chilog_tcp(loglevel_t level, tcp_packet_t *packet, char prefix)
{
    if(level > loglevel)
        return;

    tcphdr_t *header = (tcphdr_t*) packet->raw;
    uint8_t *payload = TCP_PAYLOAD_START(packet);
    uint16_t payload_len = TCP_PAYLOAD_LEN(packet);

    flockfile(stdout);
    chilog(level, "   ######################################################################");

    chilog(level, "%c  Src: %i  Dest: %i  Seq: %i  Ack: %i  Doff: %i  Win: %i",
           prefix,
           chitcp_ntohs(header->source),
           chitcp_ntohs(header->dest),
           chitcp_ntohl(header->seq),
           chitcp_ntohl(header->ack_seq),
           header->doff,
           chitcp_ntohs(header->win));
    chilog(level, "%c  CWR: %i  ECE: %i  URG: %i  ACK: %i  PSH: %i  RST: %i  SYN: %i  FIN: %i",
           prefix,
           header->cwr,
           header->ece,
           header->urg,
           header->ack,
           header->psh,
           header->rst,
           header->syn,
           header->fin);

    if(payload_len > 0)
    {
        chilog(level, "%c  Payload (%i bytes):", prefix, payload_len);
        chilog_hex(level, payload, payload_len);
    }
    else
    {
        chilog(level, "%c  No Payload", prefix);
    }
    chilog(level, "   ######################################################################");
    funlockfile(stdout);
}
Esempio n. 14
0
/*
 * chitcpd_server_network_thread_func - Server thread function
 *
 * This function will spawn a connection thread (see connection.c)
 * for each new connection on the UNIX socket.
 *
 * args: arguments (a serverinfo_t variable in network_thread_args_t)
 *
 * Returns: Nothing.
 *
 */
void* chitcpd_server_network_thread_func(void *args)
{
    socklen_t sunSize;
    network_thread_args_t *nta;
    socket_t realsocket;
    serverinfo_t *si;
    tcpconnentry_t* connection;
    char addr_str[100];

    pthread_setname_np(pthread_self(), "network_server");

    /* Unpack arguments */
    nta = (network_thread_args_t *) args;
    si = nta->si;

    struct sockaddr_storage client_addr;

    /* Accept connections on the TCP socket */
    for(;;)
    {
        /* Accept a connection */
        sunSize = sizeof(client_addr);
        if ((realsocket = accept(si->network_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 network socket");
            continue;
        }

        chitcp_addr_str((struct sockaddr *) &client_addr, addr_str, sizeof(addr_str));
        chilog(INFO, "TCP connection received from %s", addr_str);

        /* Check whether the connection already exists. */
        connection = chitcpd_get_connection(si, (struct sockaddr *) &client_addr);
        if (connection != NULL)
        {
            /* If this is a loopback connection, there is already an entry in
             * the connection table, but we need to update its receive socket
             * and create its connection thread. */
           if(chitcp_addr_is_loopback((struct sockaddr *) &client_addr))
           {
               connection->realsocket_recv = realsocket;

               if(chitcpd_create_connection_thread(si, connection) != CHITCP_OK)
               {
                   perror("Could not create connection thread.");
                   // TODO: Perform orderly shutdown
                   pthread_exit(NULL);
               }

               continue;
           }
           else
           /* Otherwise, this is an error. The peer chiTCP daemon tried to create
            * a second connection, which shouldn't happen. */
            {
                perror("Peer chiTCP daemon tried to establish more than one connection.");
                close(realsocket);
                close(si->server_socket);
                // TODO: Perform orderly shutdown instead of just exiting
                pthread_exit(NULL);
            }
        }

        /* If this is not a loopback connection, we need to add an entry
         * for this connection */
        connection = chitcpd_add_connection(si, realsocket, realsocket, (struct sockaddr*) &client_addr);

        if (!connection)
        {
            perror("Could not create a connection to a peer chiTCP daemon");
            // TODO: Perform orderly shutdown
            pthread_exit(NULL);
        }

        if(chitcpd_create_connection_thread(si, connection) != CHITCP_OK)
        {
            perror("Could not create connection thread.");
            // TODO: Perform orderly shutdown
            pthread_exit(NULL);
        }
    }

    /* Close all TCP connections. This will force an exit of the
     * corresponding connection threads. */
    for(int i=0; i < si->connection_table_size; i++)
    {
        connection = &si->connection_table[i];
        if(!connection->available)
        {
            shutdown(connection->realsocket_recv, SHUT_RDWR);
            if (connection->realsocket_recv != connection->realsocket_send)
                shutdown(connection->realsocket_send, SHUT_RDWR);
            pthread_join(connection->thread, NULL);
        }
    }

    chilog(DEBUG, "Network thread is exiting.");

    pthread_exit(NULL);
}
Esempio n. 15
0
/*
 * 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);
}
Esempio n. 16
0
/*
 * chitcpd_server_init - Starts the chiTCP daemon
 *
 * si: Server info
 *
 * Returns:
 *  - CHITCP_OK: Daemon (including server thread and network thread)
 *               has started correctly.
 *  - CHITCP_ENOMEM: Could not allocate memory for daemon
 *  - CHITCP_ESOCKET: Could not create a socket needed by daemon
 *  - CHITCP_ETHREAD: Could not create a thread needed by daemon
 *
 */
int chitcpd_server_init(serverinfo_t *si)
{
    /* TODO: Make this configurable */
    si->chisocket_table_size = DEFAULT_MAX_SOCKETS;
    si->port_table_size = DEFAULT_MAX_PORTS;
    si->connection_table_size = DEFAULT_MAX_CONNECTIONS;
    si->ephemeral_port_start = DEFAULT_EPHEMERAL_PORT_START;

    si->latency = 0.0;

    /* Initialize chisocket table */
    pthread_mutex_init(&si->lock_chisocket_table, NULL);
    si->chisocket_table = calloc(si->chisocket_table_size, sizeof(chisocketentry_t));

    if(si->chisocket_table == NULL)
    {
        perror("Could not initialize chisocket table");
        return CHITCP_ENOMEM;
    }

    for(int i=0; i< si->chisocket_table_size; i++)
    {
        pthread_mutex_init(&si->chisocket_table[i].lock_debug_monitor, NULL);
        si->chisocket_table[i].available = TRUE;
    }


    /* Initialize connection table */
    pthread_mutex_init(&si->lock_connection_table, NULL);
    si->connection_table = calloc(si->connection_table_size, sizeof(tcpconnentry_t));

    if(si->connection_table == NULL)
    {
        perror("Could not initialize connection table");
        return CHITCP_ENOMEM;
    }

    for(int i=0; i< si->connection_table_size; i++)
        si->connection_table[i].available = TRUE;

    /* Initialize port table */
    /* This is an array of pointers, and they are all set to NULL */
    si->port_table = calloc(si->port_table_size, sizeof(chisocketentry_t*));

    if(si->port_table == NULL)
    {
        perror("Could not initialize port table");
        return CHITCP_ENOMEM;
    }

    /* Daemon state lock and condvar */
    pthread_mutex_init(&si->lock_state, NULL);
    pthread_cond_init(&si->cv_state, NULL);

    /* Delivery list (+ lock and condvar) */
    list_init(&si->delivery_queue);
    pthread_mutex_init(&si->lock_delivery, NULL);
    pthread_cond_init(&si->cv_delivery, NULL);

    /* Open libpcap file if a name is provided. Will overwrite any data currentlly
       in said file. */
    if (si->libpcap_file_name != NULL)
    {
        si->libpcap_file = fopen(si->libpcap_file_name, "wb");
        if (si->libpcap_file == NULL)
        {
            perror("Could not open libpcap file for writing");
            return CHITCP_ENOMEM;
        }

        chilog(INFO, "Logging to libpcap file %s", si->libpcap_file_name);
        /* Write the libpcap header */
        pcap_hdr_t pcap_header;
        pcap_header.magic_number = 0xa1b23c4d;
        pcap_header.version_major = 2;
        pcap_header.version_minor = 4;
        pcap_header.thiszone = 0;
        pcap_header.sigfigs = 0;
        pcap_header.snaplen = 65535;
        pcap_header.network = 101;
        fwrite(&pcap_header, sizeof(pcap_hdr_t), 1, si->libpcap_file);
    }
    else
    {
        si->libpcap_file = NULL;
    }

    si->state = CHITCPD_STATE_READY;

    return CHITCP_OK;
}
Esempio n. 17
0
/*
 * 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;
}
Esempio n. 18
0
int chitcpd_tcp_state_handle_TIME_WAIT(serverinfo_t *si, chisocketentry_t *entry, tcp_event_type_t event) {
  chilog(WARNING, "Running handler for TIME_WAIT. This should not happen.");

  return CHITCP_OK;
}