Пример #1
0
/*
 * This is the start of the client handling code.
 * The server process has accepted a connection and authenticated it. Data from
 * the client will arrive here via infd and data that should be sent back goes
 * through outfd.
 * An instance of NitroHack will run in this process under the control of the
 * remote player. 
 */
void client_main(int userid, int _infd, int _outfd)
{
    char **gamepaths;
    int i;
    
    infd = _infd;
    outfd = _outfd;
    gamefd = -1;
    
    init_database();
    if (!db_get_user_info(userid, &user_info)) {
	log_msg("get_user_info error for uid %d!", userid);
	exit_client("database error");
    }
    
    gamepaths = init_game_paths();
    nh_lib_init(&server_windowprocs, gamepaths);
    for (i = 0; i < PREFIX_COUNT; i++)
	free(gamepaths[i]);
    free(gamepaths);

    db_restore_options(userid);
    
    client_main_loop();
    
    exit_client(NULL);
    /*NOTREACHED*/
    
    return;
}
Пример #2
0
/*
 * A new game process is needed.
 * Create the communication pipes, register them with epoll and fork the new
 * process.
 */
static int
fork_client(struct client_data *client, int epfd)
{
    int ret1, ret2, userid;
    int pipe_out_fd[2];
    int pipe_in_fd[2];
    struct epoll_event ev;

    ret1 = pipe2(pipe_out_fd, O_NONBLOCK);
    ret2 = pipe2(pipe_in_fd, O_NONBLOCK);
    if (ret1 == -1 || ret2 == -1) {
        if (!ret1) {
            close(pipe_out_fd[0]);
            close(pipe_out_fd[1]);
        }
        /* it's safe to use errno here, even though the second pipe2 call will
           erase the status from the first, because the second one will always
           fail with the same status as the first if the first call fails. */
        log_msg("Failed to create communication pipes for new connection: %s",
                strerror(errno));
        cleanup_game_process(client, epfd);
        return FALSE;
    }

    /* pipe[0] read side - pipe[1] write side */
    fcntl(pipe_in_fd[0], F_SETFD, FD_CLOEXEC);
    fcntl(pipe_out_fd[1], F_SETFD, FD_CLOEXEC); /* client does not need to
                                                   inherit this */

    client->pipe_out = pipe_out_fd[1];
    client->pipe_in = pipe_in_fd[0];
    map_fd_to_client(client->pipe_out, client);
    map_fd_to_client(client->pipe_in, client);

    client->pid = fork();
    if (client->pid > 0) {      /* parent */
    } else if (client->pid == 0) {      /* child */
        struct user_info info;

        userid = client->userid;
        db_get_user_info(userid, &info);
        setenv("NH4SERVERUSER", info.username, 1);
        post_fork_cleanup();
        client_main(userid, pipe_out_fd[0], pipe_in_fd[1]);
        exit(0);        /* shouldn't get here... client is done. */
    } else if (client->pid == -1) {     /* error */
        /* can't proceed, so clean up. The client side of the pipes needs to be
           closed here, this end gets handled in cleanup_game_process */
        close(pipe_out_fd[0]);
        close(pipe_in_fd[1]);
        cleanup_game_process(client, epfd);
        log_msg("Failed to fork a client process: %s", strerror(errno));
        return FALSE;
    }

    client->state = CLIENT_CONNECTED;
    unlink_client_data(client);
    link_client_data(client, &connected_list_head);

    /* register the pipe fds for monitoring by epoll */
    ev.data.ptr = NULL;
    ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
    ev.data.fd = client->pipe_out;
    epoll_ctl(epfd, EPOLL_CTL_ADD, client->pipe_out, &ev);
    ev.data.fd = client->pipe_in;
    epoll_ctl(epfd, EPOLL_CTL_ADD, client->pipe_in, &ev);

    /* close the client side of the pipes */
    close(pipe_out_fd[0]);
    close(pipe_in_fd[1]);

    return TRUE;
}