|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 9988 (0x2704) Types: TextFile Names: »dist.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Hearts/dist.c«
/* * hearts_dist - distributor for hearts * * Keeps track of games in progress and allows new players to select which * game to join or start a new game. * * * Commands to hearts player: * tn Following info regards table n (n is unique identifier). * hn Now playing hand n. * rn Now playing round n. * pn<name> Player n is <name>. * * xn Table n has exited (game over). * g Get table number to join. * cn Connect to dealer on port n. * * Commands from hearts player: * jn Join table n. * n Start new game. * * Commands to dealer: * none yet?!? * * Commands from dealer: * hn Now playing hand n. * rn Now playing round n. * pn<name> Player n is <name>. * */ #include "misc.h" #include "defs.h" #include "local.h" typedef struct table *table_ptr; struct table { table_ptr next_table; /* Points to next table entry */ int table_id; /* Unique identifier */ char player_name[4][9]; /* Name of players at table */ int hand; /* Current dealer hand (1..4) */ int round; /* Current round (1..13) */ int port_num; /* Port # assigned */ int socket; /* File descriptor for dealer */ int pid; /* Process id for dealer */ }; typedef struct empty_table *empty_ptr; struct empty_table { empty_ptr next_empty; int port_num; /* Available port # */ }; typedef struct new_comer *new_ptr; struct new_comer { new_ptr next_new_comer; int socket; /* File descriptor */ }; table_ptr first_table; empty_ptr first_empty; new_ptr first_new_comer; int main_sock, next_port, /* Next port to assign */ unique_id; /* * clear_table - dealer went away; drop that table. */ clear_table(tbl_ptr) table_ptr tbl_ptr; { table_ptr prev_ptr = NULL; table_ptr cur_ptr; empty_ptr temp_empty, cur_empty; new_ptr cur_new_comer; char buf[16]; char *malloc(); while (wait(0) != tbl_ptr->pid) /* Wait for process to die */ ; (void) close(tbl_ptr->socket); /* * Inform new-comers */ (void) sprintf(buf, "x%d", tbl_ptr->table_id); for (cur_new_comer = first_new_comer; cur_new_comer; cur_new_comer = cur_new_comer->next_new_comer) write_socket(cur_new_comer->socket, buf); for (cur_ptr = first_table; cur_ptr != tbl_ptr; cur_ptr = cur_ptr->next_table) prev_ptr = cur_ptr; if (prev_ptr) prev_ptr->next_table = tbl_ptr->next_table; else if ((first_table = tbl_ptr->next_table) == NULL) exit(0); /* No more dealers */ temp_empty = (empty_ptr) malloc(sizeof(struct empty_table)); temp_empty->next_empty = NULL; temp_empty->port_num = tbl_ptr->port_num; free((char *) tbl_ptr); if (first_empty) { for (cur_empty = first_empty; cur_empty->next_empty; cur_empty = cur_empty->next_empty) ; cur_empty->next_empty = temp_empty; } else first_empty = temp_empty; } /* * drop_new_comer - New comer exited */ drop_new_comer(dead_new_comer) new_ptr dead_new_comer; { new_ptr cur_new_comer, prev_new_comer = NULL; (void) close(dead_new_comer->socket); for (cur_new_comer = first_new_comer; cur_new_comer != dead_new_comer; cur_new_comer = cur_new_comer->next_new_comer) prev_new_comer = cur_new_comer; if (prev_new_comer) prev_new_comer->next_new_comer = dead_new_comer->next_new_comer; else first_new_comer = dead_new_comer->next_new_comer; free((char *) dead_new_comer); if ((first_table == NULL) && (first_new_comer == NULL)) exit(0); /* Nobody connected */ } /* * new_player - New player has connected. Inform of games in progress and * request game to be joined. */ new_player() { int new_socket; /* new file descriptor */ char buf[64]; struct sockaddr_in sockad; int ssize; /* makes accept happy */ int i; new_ptr cur_new_comer, temp_new_comer; table_ptr cur_ptr; char *malloc(); /* * add whoever's waiting */ ssize = sizeof (sockad); if ((new_socket = accept(main_sock, &sockad, &ssize)) == -1) { perror("accept"); exit(-1); } /* * add to list of new_comers */ temp_new_comer = (new_ptr) malloc(sizeof(struct new_comer)); temp_new_comer->next_new_comer = NULL; temp_new_comer->socket = new_socket; if (first_new_comer) { for (cur_new_comer = first_new_comer; cur_new_comer->next_new_comer; cur_new_comer = cur_new_comer->next_new_comer) ; cur_new_comer->next_new_comer = temp_new_comer; } else first_new_comer = temp_new_comer; /* * send info on games in progress */ for (cur_ptr = first_table; cur_ptr; cur_ptr = cur_ptr->next_table) { (void) sprintf(buf, "t%d", cur_ptr->table_id); write_socket(new_socket, buf); (void) sprintf(buf, "h%d", cur_ptr->hand); write_socket(new_socket, buf); (void) sprintf(buf, "r%d", cur_ptr->round); write_socket(new_socket, buf); for (i = 0; i < 4; i++) { (void) sprintf(buf, "p%d%s", i, cur_ptr->player_name[i]); write_socket(new_socket, buf); } } write_socket(new_socket, "g"); } tell_new_comers(buf) char *buf; { new_ptr cur_new; for (cur_new = first_new_comer; cur_new; cur_new = cur_new->next_new_comer) write_socket(cur_new->socket, buf); } /* * join - join an existing table. table_num is unique identifier for table. */ join(table_num, socket) int table_num, socket; { table_ptr cur_ptr; char buf[16]; for (cur_ptr = first_table; cur_ptr && cur_ptr->table_id != table_num; cur_ptr = cur_ptr->next_table) ; if (cur_ptr) { (void) sprintf(buf, "c%d", cur_ptr->port_num); write_socket(socket, buf); } else write_socket(socket, "g"); /* Table doesn't exist?!? */ } /* * new_table - start new hearts game. */ new_table(cur_new_comer) new_ptr cur_new_comer; { table_ptr cur_table, new_tbl_ptr; empty_ptr tmp_empty; int i, socks[2]; int dealer_port, dealer_socket, retry; char buf[16]; char *malloc(); new_tbl_ptr = (table_ptr) malloc(sizeof(struct table)); new_tbl_ptr->next_table = NULL; new_tbl_ptr->table_id = ++unique_id; for (i = 0; i < 4; i++) (void) strcpy(new_tbl_ptr->player_name[i], "<empty>"); /* * Assign a port. Reassign a used port if available. */ do { if (first_empty) { dealer_port = first_empty->port_num; tmp_empty = first_empty; first_empty = first_empty->next_empty; free((char *) tmp_empty); } else dealer_port = next_port++; /* * Make sure port is ok before assigning. */ if ((dealer_socket = open_socket(dealer_port)) == 0) if (++ retry == 20) { fputs("Can't open a dealer port!\n", stderr); exit(1); } } while (dealer_socket == 0); new_tbl_ptr->port_num = dealer_port; /* * Open a socket pair to talk to dealer on. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1) { perror("socketpair"); exit(1); } switch (new_tbl_ptr->pid = fork()) { case 0: (void) setpgrp (0, getpid()); (void) close(socks[0]); if (socks[1] != 3) (void) dup2(socks[1], 3); /* Remap to fd 3 */ if (dealer_socket != 4) (void) dup2(dealer_socket, 4); /* Remap to fd 4 */ execl (HEARTSD, "heartsd", 0); exit(1); case -1: perror("fork"); exit(1); } (void) close(socks[1]); (void) close(dealer_socket); new_tbl_ptr->socket = socks[0]; if (first_table) { for (cur_table = first_table; cur_table->next_table; cur_table = cur_table->next_table) ; cur_table->next_table = new_tbl_ptr; } else first_table = new_tbl_ptr; /* * Inform hearts player of port # to connect on. */ (void) sprintf(buf, "c%d", dealer_port); write_socket(cur_new_comer->socket, buf); } main(argc, argv) char **argv; { fd_type read_fd; table_ptr cur_table; new_ptr cur_new_comer; char buf[64], tmp_buf[64]; int ret; int table_num; char debug; while (*++argv) { if (**argv == '-') { while (*++*argv) { switch (**argv) { case 'd': debug = TRUE; break; default: fprintf (stderr, "usage: hearts_dist [-d]\n"); exit (1); break; } } } } first_table = NULL; first_empty = NULL; first_new_comer = NULL; next_port = DIST_PORT; unique_id = 0; if ((main_sock = open_socket(PORT)) == 0) { fputs("Distributor port in use!\n", stderr); exit(1); } if (!debug) { /* * Fork off and die. Thus hearts invoker wait() returns. * This signals ready to connect. */ if (fork()) exit (0); } for (;;) { fd_init(main_sock, &read_fd); /* * Build mask for dealers */ for (cur_table = first_table; cur_table; cur_table = cur_table->next_table) fd_set(cur_table->socket, &read_fd); /* * Build mask for new_comers */ for (cur_new_comer = first_new_comer; cur_new_comer; cur_new_comer = cur_new_comer->next_new_comer) fd_set(cur_new_comer->socket, &read_fd); /* * Wait for something to happen */ if (select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0, (struct timeval *) 0)) { if (fd_isset(main_sock, read_fd)) new_player(); for (cur_table = first_table; cur_table; cur_table = cur_table->next_table) if (fd_isset(cur_table->socket, read_fd)) { /* * Message from dealer */ ret = read_socket(cur_table->socket, buf); if (!ret) clear_table(cur_table); else { switch (buf[0]) { case 'h' : (void) sscanf(buf + 1, "%d", &cur_table->hand); break; case 'r' : (void) sscanf(buf + 1, "%d", &cur_table->round); break; case 'p' : (void) strcpy(cur_table->player_name[buf[1] - '0'], buf + 2); } (void) sprintf(tmp_buf, "t%d", cur_table->table_id); tell_new_comers(tmp_buf); tell_new_comers(buf); } } for (cur_new_comer = first_new_comer; cur_new_comer; cur_new_comer = cur_new_comer->next_new_comer) if (fd_isset(cur_new_comer->socket, read_fd)) { /* * Message from newcomer */ ret = read_socket(cur_new_comer->socket, buf); if (ret) switch (buf[0]) { case 'j' : (void) sscanf(buf + 1, "%d", &table_num); join(table_num, cur_new_comer->socket); break; case 'n' : new_table(cur_new_comer); } else drop_new_comer(cur_new_comer); } } } }