game_server.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #define _GNU_SOURCE
  2. #ifndef PORT
  3. #define PORT 8087
  4. #endif
  5. #include "game_server.h"
  6. Player *player_list = NULL;
  7. Client *client_list = NULL;
  8. short port = -1;
  9. int board[16];
  10. char dice[16][6] = {
  11. {'R', 'I', 'F', 'O', 'B', 'X'},
  12. {'I', 'F', 'E', 'H', 'E', 'Y'},
  13. {'D', 'E', 'N', 'O', 'W', 'S'},
  14. {'U', 'T', 'O', 'K', 'N', 'D'},
  15. {'H', 'M', 'S', 'R', 'A', 'O'},
  16. {'L', 'U', 'P', 'E', 'T', 'S'},
  17. {'A', 'C', 'I', 'T', 'O', 'A'},
  18. {'Y', 'L', 'G', 'K', 'U', 'E'},
  19. {'Q', 'B', 'M', 'J', 'O', 'A'},
  20. {'E', 'H', 'I', 'S', 'P', 'N'},
  21. {'V', 'E', 'T', 'I', 'G', 'N'},
  22. {'B', 'A', 'L', 'I', 'Y', 'T'},
  23. {'E', 'Z', 'A', 'V', 'N', 'D'},
  24. {'R', 'A', 'L', 'E', 'S', 'C'},
  25. {'U', 'W', 'I', 'L', 'R', 'G'},
  26. {'P', 'A', 'C', 'E', 'M', 'D'}
  27. };
  28. int main(int argc, char* argv[]) {
  29. // struct client *p;
  30. if (argc > 1)
  31. port = (short)(atoi(argv[1]));
  32. else
  33. port = PORT;
  34. //get listen file descriptor
  35. int listenfd = setup();
  36. struct sigaction newact;
  37. newact.sa_handler = timer_handler;
  38. newact.sa_flags = 0;
  39. sigemptyset(&newact.sa_mask);
  40. sigaction(SIGALRM, &newact, NULL);
  41. //start timer
  42. alarm(TIMER_TICK);
  43. int max_fd;
  44. fd_set client_fds;
  45. Client * temp;
  46. while (1) {
  47. FD_ZERO(&client_fds);
  48. temp = client_list;
  49. max_fd = listenfd;
  50. while (temp) {
  51. FD_SET(temp->fd, &client_fds);
  52. if (temp->fd > max_fd) {
  53. max_fd = temp->fd;
  54. }
  55. temp = temp -> next;
  56. }
  57. FD_SET(listenfd, &client_fds);
  58. if (select(max_fd+1, &client_fds, NULL, NULL, NULL) == -1) {
  59. perror("select");
  60. exit(1);
  61. }
  62. temp = client_list;
  63. while (temp) {
  64. if (FD_ISSET(temp->fd, &client_fds)) {
  65. receiveclient(temp);
  66. }
  67. temp = temp -> next;
  68. }
  69. if (FD_ISSET(listenfd, &client_fds)) {
  70. new_connection(listenfd);
  71. }
  72. }
  73. return 0;
  74. }
  75. /*
  76. * Sets up server socket: bind and listen
  77. * Returns a file descriptor for listening and accepting new connections
  78. */
  79. int setup (void) {
  80. int on = 1, status;
  81. struct sockaddr_in self;
  82. int listenfd;
  83. if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  84. perror("socket");
  85. exit(1);
  86. }
  87. status = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
  88. (const char *) &on, sizeof(on));
  89. if(status == -1) {
  90. perror("setsockopt -- REUSEADDR");
  91. }
  92. memset(&self, '\0', sizeof(self));
  93. self.sin_family = AF_INET;
  94. self.sin_addr.s_addr = INADDR_ANY;
  95. self.sin_port = htons(port);
  96. printf("Listening on %d\n", port);
  97. if (bind(listenfd, (struct sockaddr *)&self, sizeof(self)) == -1) {
  98. perror("bind"); // probably means port is in use
  99. exit(1);
  100. }
  101. if (listen(listenfd, 5) == -1) {
  102. perror("listen");
  103. exit(1);
  104. }
  105. return listenfd;
  106. }
  107. void swap(int* i, int* j) {
  108. int temp = *i;
  109. *i = *j;
  110. *j = temp;
  111. }
  112. /* timer signal handler */
  113. void timer_handler(int sig) {
  114. //broadcast current game end to all connected clients
  115. Client *curr;
  116. for (curr = client_list; curr!=NULL; curr = curr->next) {
  117. sendclient(curr, "Game over\r\n");
  118. }
  119. srand(time(0));
  120. int order[16];
  121. int i;
  122. for (i = 0; i < 16; i++) {
  123. order[i] = i;
  124. }
  125. for (i = 0; i < 16; i++) {
  126. swap(order + i, order + (rand() % (16-i)) + i);
  127. }
  128. for (i = 0; i < 16; i++) {
  129. board[i] = dice[order[i]][rand() % 6];
  130. }
  131. //reset the timer so we get called again in 120 seconds
  132. alarm(TIMER_TICK);
  133. }
  134. /* accepts new connection and adds a client-specific fd */
  135. void new_connection (int listenfd) {
  136. int fd;
  137. struct sockaddr_in r;
  138. socklen_t socklen = sizeof(r);
  139. if ((fd = accept(listenfd, (struct sockaddr *)&r, &socklen)) < 0) {
  140. perror("accept");
  141. return;
  142. }
  143. printf("connection from %s\n", inet_ntoa(r.sin_addr));
  144. add_client(fd, r.sin_addr);
  145. }
  146. /* creates a new client struct and
  147. adds it to the list of clients */
  148. void add_client(int fd, struct in_addr addr){
  149. struct client *p = malloc(sizeof(struct client));
  150. if (!p) {
  151. perror("malloc failure");
  152. exit(1);
  153. }
  154. printf("Adding client %s\n", inet_ntoa(addr));
  155. fflush(stdout);
  156. p->fd = fd;
  157. p->state = NAME; //needs yet to identify new client by name
  158. p->inbuf = 0;
  159. p->next = client_list;
  160. client_list = p;
  161. sendclient(p, "What is your player name?\n");
  162. }
  163. void remove_client(int c_fd){
  164. if (client_list->fd == c_fd) {
  165. client_list = client_list -> next;
  166. }
  167. else {
  168. Client *prev = client_list;
  169. Client *temp = prev->next;
  170. while (temp && temp->fd!=c_fd) {
  171. prev = temp;
  172. temp = temp -> next;
  173. }
  174. if (temp) {
  175. prev->next = temp -> next;
  176. free(temp);
  177. }
  178. }
  179. }
  180. void receiveclient(struct client *p) {
  181. char *after = p->buf + p->inbuf;
  182. int room = BUFFER_SIZE - p->inbuf;
  183. int nbytes;
  184. if ((nbytes = read(p->fd, after, room)) > 0) {
  185. p->inbuf += nbytes;
  186. int where = find_network_newline(p->buf, p->inbuf);
  187. if (where >= 0) {
  188. p->buf[where] = '\0';
  189. p->buf[where+1] = '\0';
  190. interpret_message(p);
  191. where+=2; // skip over \r\n
  192. p->inbuf -= where;
  193. memmove(p->buf, p->buf + where, p->inbuf);
  194. }
  195. room = sizeof(p->buf) - p->inbuf;
  196. after = p->buf + p->inbuf;
  197. } else {
  198. remove_client(p->fd);
  199. }
  200. }
  201. /*
  202. * Acts according to the client state
  203. */
  204. void interpret_message(Client *p) {
  205. char *buf;
  206. if (p->state == NAME) {
  207. strcpy(p->name, p->buf);
  208. switch (create_player(p->name, &player_list)) {
  209. case 1:
  210. sendclient(p, "Welcome back.\r\n");
  211. break;
  212. case 2:
  213. asprintf(&buf, "Username too long, truncated to %d chars.\r\n", (MAX_NAME-1));
  214. sendclient(p, buf);
  215. break;
  216. case 0:
  217. sendclient(p, "Welcome, new player\r\n");
  218. break;
  219. }
  220. printf("Added %s to the client list\n",p->name);
  221. p->state = COMMAND;
  222. sendclient(p, "Go ahead and enter player commands>\r\n");
  223. } else if (!strcmp(p->buf, "q")) {
  224. remove_client(p->fd);
  225. } else {
  226. parse_line(p);
  227. }
  228. }
  229. int parse_line(Client *p) {
  230. char * input = p->buf;
  231. // cmd_argv will held arguments to individual commands passed to sub-procedure
  232. char *cmd_argv[INPUT_ARG_MAX_NUM];
  233. int cmd_argc;
  234. // tokenize arguments
  235. char *next_token = strtok(input, DELIM);
  236. cmd_argc = 0;
  237. while (next_token != NULL) {
  238. cmd_argv[cmd_argc] = next_token;
  239. cmd_argc++;
  240. next_token = strtok(NULL, DELIM);
  241. }
  242. return (cmd_argc > 0 && do_command(p, cmd_argc, cmd_argv));
  243. }
  244. /*
  245. * Process player commands
  246. * Return: -1 for quit command
  247. * 0 otherwise
  248. */
  249. int do_command(struct client * p, int cmd_argc, char **cmd_argv) {
  250. if (cmd_argc <= 0) {
  251. return 0;
  252. } else if (strcmp(cmd_argv[0], "q") == 0 && cmd_argc == 1) {
  253. return -1;
  254. } else if (strcmp(cmd_argv[0], "all_players") == 0 && cmd_argc == 1) {
  255. char str [BUFFER_SIZE-10];
  256. char str2[BUFFER_SIZE-10];
  257. Player *temp = player_list;
  258. sprintf(str, "Name | Max Score | Total Games | Total Score\r\n");
  259. while (temp) {
  260. sprintf(str2, "%s, %d, %d, %d\r\n", temp->name, temp->max_score, temp->total_games, temp->total_score);
  261. strcat(str, str2);
  262. temp = temp->next;
  263. }
  264. sendclient(p, str);
  265. } else if (strcmp(cmd_argv[0], "top_3") == 0 && cmd_argc == 1) {
  266. Player* first = NULL;
  267. Player* second = NULL;
  268. Player* third = NULL;
  269. Player* temp = player_list;
  270. int s;
  271. while (temp) {
  272. s = temp->total_score;
  273. if (!first || s > first->total_score) {
  274. third=second;
  275. second=first;
  276. first=temp;
  277. }
  278. else if (!second || s > second->total_score) {
  279. third=second;
  280. second=temp;
  281. }
  282. else if (!third || s > third->total_score) {
  283. third=temp;
  284. }
  285. temp = temp->next;
  286. }
  287. char str [BUFFER_SIZE - 10];
  288. char str2 [BUFFER_SIZE - 10];
  289. if (first) {
  290. sprintf(str, "1: %s, %d points\r\n", first->name, first->total_score);
  291. if (second) {
  292. sprintf(str2, "2: %s, %d points\r\n", second->name, second->total_score);
  293. strcat(str, str2);
  294. if (third) {
  295. sprintf(str2, "3: %s, %d points\r\n", third->name, third->total_score);
  296. strcat(str, str2);
  297. }
  298. }
  299. }
  300. else {
  301. sprintf(str, "No players ever\r\n");
  302. }
  303. sendclient(p, str);
  304. } else if (strcmp(cmd_argv[0], "add_score") == 0 && cmd_argc == 2) {
  305. char str [BUFFER_SIZE - 10];
  306. int score =atoi(cmd_argv[1]);
  307. Player *player = find_player(p->name, player_list);
  308. player->total_score+=score;
  309. if (score > player->max_score)
  310. player->max_score = score;
  311. sprintf (str, "added score %d for player %s\r\n", score, p->name);
  312. sendclient(p, str);
  313. } else if (strcmp(cmd_argv[0], "new_game") == 0 && cmd_argc == 1) {
  314. char str [BUFFER_SIZE - 10];
  315. char str2 [BUFFER_SIZE-10];
  316. sprintf(str, "");
  317. for (int i = 0; i < 4; i++) {
  318. for (int j = 0; j < 4; j++) {
  319. sprintf(str2, "%c ", board[4*i+j]);
  320. strcat(str, str2);
  321. }
  322. strcat(str, "\r\n");
  323. }
  324. sendclient(p, str);
  325. }else {
  326. sendclient(p, "Incorrect syntax\r\n");
  327. }
  328. return 0;
  329. }
  330. void sendclient(struct client *p, char *msg) {
  331. write(p->fd, msg, strlen(msg));
  332. }
  333. /*
  334. * Search the first inbuf characters of buf for a network newline.
  335. * Return the location of the '\r' if the network newline is found, or -1 otherwise.
  336. */
  337. int find_network_newline(char *buf, int inbuf) {
  338. int i;
  339. for (i = 0; i < inbuf - 1; i++)
  340. if ((buf[i] == '\r') && (buf[i + 1] == '\n'))
  341. return i;
  342. return -1;
  343. }