Example #1
0
File: net.c Project: faf0/sws
/**
 * Determines the client's IP address, waits for a request,
 * and handles it.
 *
 * @param client_sock the client socket
 * @param client client socket information
 * @param client_length length of client structure
 * @param flag user-provided flags
 */
static void
handle_client(int client_sock, struct sockaddr_storage * client,
    socklen_t client_length, struct flags * flag)
{
  char client_ip[INET6_ADDRSTRLEN];
  int determined_client_addr;

  /* determine client IP address */
  determined_client_addr = 0;
  /* client IP is empty by default */
  bzero(client_ip, sizeof(client_ip));
  if (client->ss_family == AF_INET6) {
    if (inet_ntop(AF_INET6, &((struct sockaddr_in6*) client)->sin6_addr,
        client_ip, sizeof(client_ip)) == NULL) {
      perror("inet_ntop for client address");
    } else {
      determined_client_addr = 1;
    }
  } else if (client->ss_family == AF_INET) {
    if (inet_ntop(AF_INET, &((struct sockaddr_in *) client)->sin_addr.s_addr,
        client_ip, sizeof(client_ip)) == NULL) {
      perror("inet_ntop for client address");
    } else {
      determined_client_addr = 1;
    }
  }
  if (!determined_client_addr) {
    strncpy(client_ip, UNKNOWN_IP, sizeof(client_ip) - 1);
  }
  /* child process handles client and exits when done */
  /* TODO only reads a line from client in this framework */
  communicate_client(flag, client_sock, client_ip);
  (void) close(client_sock);
}
Example #2
0
/*
 * Function: handle_client()
 * 
 * Descripton:
 *  Accept a connection from a client, then fork to communicate the client
 *
 * Argument:
 *  info_p:	pointer to a server infomation
 *
 * Return value:
 *  0:	    success
 *  other:  fail
 */
int
handle_client(struct server_info *info_p)
{
    int ret = EXIT_SUCCESS;	/* return value of this function */
    int do_accept = 1;		/* if non-zero, accept connection */
    fd_set read_fds;		/* list of file descriptor for reading */
    int max_read_fd = 0;	/* maximum number in the read fds */

    info_p->current_connection = 0;
    FD_ZERO(&read_fds);
    FD_SET(info_p->listen_sd, &read_fds);
    max_read_fd = info_p->listen_sd;

    /* Catch SIGHUP */
    handler.sa_handler = set_signal_flag;
    if (sigaction(SIGHUP, &handler, NULL) < 0)
	fatal_error("sigaction()");

    /* Loop to wait a new connection */
    for(;;) {
	if (do_accept) {
	    int data_sd;	/* socket descriptor for send/recv data */
	    socklen_t client_addr_len;	/* length of `client_addr' */
	    struct sockaddr_storage client_addr;    /* address of a client */
	    int select_ret;	/* return value of select() */
	    fd_set  active_fds;	/* list of the active file descriptor */
	    struct timeval select_timeout;	/* timeout for select() */

	    /* When catch SIGHUP, no more connection is acceptted. */
	    if (catch_sighup) {
		do_accept = 0;
		if (close(info_p->listen_sd))
		    fatal_error("close()");
		continue;
	    }

	    /* Check a connection is requested */
	    active_fds = read_fds;
	    select_timeout.tv_sec = 0;	    /* 0.5 sec */
	    select_timeout.tv_usec = 500000;

	    select_ret = select(max_read_fd + 1,
		    &active_fds, NULL, NULL, &select_timeout);
	    if (select_ret < 0) {
		do_accept = 0;
		if (!catch_sighup) {
		    perror("select()");
		    ret = EXIT_FAILURE;
		}
		if (close(info_p->listen_sd))
		    fatal_error("close()");
		continue;
	    } else if (select_ret == 0) {	    /* select() is timeout */
		if (info_p->concurrent)
		    delete_zombies(info_p);
		continue;
	    }

	    /* Accetpt a client connection */
	    if (FD_ISSET(info_p->listen_sd, &active_fds)) {
		client_addr_len = sizeof(struct sockaddr_storage);
		data_sd = accept(info_p->listen_sd,
			(struct sockaddr *)&client_addr, &client_addr_len);
		if (data_sd < 0) {
		    do_accept = 0;
		    if (!catch_sighup) {
			perror("accept()");
			ret = EXIT_FAILURE;
		    }
		    if (close(info_p->listen_sd))
			fatal_error("close()");
		    continue;
		}
		if (debug)
		    fprintf(stderr, "called accept(). data_sd=%d\n", data_sd);

		/* Handle clients */
		if (info_p->concurrent) {	/* concurrent server. */
		    pid_t child_pid;
		    child_pid = fork();
		    if (child_pid < 0) {	/* fork() is failed. */
			perror("fork()");
			if (close(data_sd))
			    fatal_error("close()");
			if (close(info_p->listen_sd))
			    fatal_error("close()");
			do_accept = 0;
			continue;
		    } else if (child_pid == 0) {	/* case of a child */
			int exit_value;
			if (close(info_p->listen_sd))
			    fatal_error("close()");
			exit_value = communicate_client(info_p, data_sd);
			if (debug)
			    fprintf(stderr, "child(%d) exits. value is %d\n",
				    getpid(), exit_value);
			exit(exit_value);
		    } else {				/* case of the parent */
			if (close(data_sd))
			    fatal_error("close()");
			
			++info_p->current_connection;
			if (info_p->max_connection < info_p->current_connection) {
			    info_p->max_connection = info_p->current_connection;
			    if (debug)
				fprintf (stderr, "The maximum connection is updated. The number is %zu.\n", info_p->max_connection);
			}
			delete_zombies(info_p);
		    }
		} else {			/* repeat server */
		    ret = communicate_client(info_p, data_sd);
		    if (ret != EXIT_SUCCESS) 
		      if (close(info_p->listen_sd))
			fatal_error("close()");
		    break;
		}
	    }
	} else {
	    /* case where new connection isn't accepted. */
	    if (info_p->concurrent)
		delete_zombies(info_p);
	    if (info_p->current_connection == 0) 
		break;
	}
    }
    return ret;
}