tt

A terminal-based typing game
git clone git://pcardenasb.com/tt
Log | Files | Refs | README | LICENSE

ttsrv.c (3893B)


      1 #include "tt.h"
      2 #include <json.h>
      3 #include <netinet/in.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <sys/socket.h>
      8 #include <unistd.h>
      9 
     10 int change_quote(
     11 	int quote_idx,
     12 	struct json_object *quotes,
     13 	struct state states[FD_SETSIZE],
     14 	int sockfd,
     15 	fd_set set)
     16 {
     17 	json_object *quote = json_object_array_get_idx(quotes, quote_idx);
     18 	json_object_object_get_ex(quote, "text", &quote);
     19 	const char *str_quote = json_object_get_string(quote);
     20 	short length = strlen(str_quote);
     21 	for (int i = 0; i < FD_SETSIZE; i++) {
     22 		states[i].pos = 0;
     23 		if (!(i != 0 && i != sockfd && FD_ISSET(i, &set))) {
     24 			continue;
     25 		}
     26 		send(i, "\x00", 1, 0);
     27 		send(i, &length, sizeof length, 0);
     28 		send(i, str_quote, length, 0);
     29 	}
     30 }
     31 
     32 int main(int argc, const char *argv[])
     33 {
     34 	if (argc != 3) {
     35 		fprintf(stderr, "Usage: %s <port> <quotes.json>\n", argv[0]);
     36 		return 1;
     37 	}
     38 
     39 	char *endptr;
     40 	long port = strtol(argv[1], &endptr, 10);
     41 	if (!(*argv[1] != '\0' && *endptr == '\0' && port < 65536)) {
     42 		fprintf(stderr, "ERROR: '%s' is not a valid port.\n", argv[1]);
     43 		return 1;
     44 	}
     45 
     46 	struct json_object *root = json_object_from_file(argv[2]);
     47 	if (!root) {
     48 		fprintf(stderr, "Failed to parse JSON file.\n");
     49 		return 1;
     50 	}
     51 	struct json_object *quotes;
     52 	json_object_object_get_ex(root, "quotes", &quotes);
     53 	int num_quotes = json_object_array_length(quotes);
     54 
     55 	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
     56 	if (sockfd == -1) {
     57 		perror("socket");
     58 		return 1;
     59 	}
     60 
     61 	struct sockaddr_in address = {
     62 		.sin_family = AF_INET,
     63 		.sin_port = htons(port),
     64 		.sin_addr.s_addr = INADDR_ANY};
     65 	if (bind(sockfd, (struct sockaddr *)&address, sizeof address) == -1) {
     66 		perror("bind");
     67 		return 1;
     68 	}
     69 	if (listen(sockfd, 5) == -1) {
     70 		perror("listen");
     71 		return 1;
     72 	}
     73 
     74 	fd_set set;
     75 	FD_ZERO(&set);
     76 	FD_SET(0, &set);
     77 	FD_SET(sockfd, &set);
     78 
     79 	struct state states[FD_SETSIZE];
     80 
     81 	while (1) {
     82 		fd_set readfds = set;
     83 		if (select(FD_SETSIZE, &readfds, NULL, NULL, NULL) == -1) {
     84 			perror("select");
     85 			return 1;
     86 		}
     87 
     88 		if (FD_ISSET(0, &readfds)) {
     89 			char buffer[4096];
     90 			read(0, buffer, 4096);
     91 			long quote_idx = strtol(buffer, &endptr, 10);
     92 			if (!((*buffer != '\n' && *buffer != '\0') &&
     93 			      (*endptr == '\0' || *endptr == '\n'))) {
     94 				fprintf(stderr, "Error parsing quote index.\n");
     95 			} else if (!(0 <= quote_idx &&
     96 				     quote_idx < num_quotes)) {
     97 				fprintf(stderr,
     98 					"0 <= quote_index < %d.\n",
     99 					num_quotes);
    100 			} else {
    101 				change_quote(
    102 					quote_idx, quotes, states, sockfd, set);
    103 			}
    104 		}
    105 
    106 		if (FD_ISSET(sockfd, &readfds)) {
    107 			int fd = accept(sockfd, NULL, NULL);
    108 			FD_SET(fd, &set);
    109 			states[fd].pos = 0;
    110 			printf("player %d connected\n", fd);
    111 		}
    112 
    113 		for (int fd = 0; fd < FD_SETSIZE; fd++) {
    114 			if (!(fd != 0 && fd != sockfd &&
    115 			      FD_ISSET(fd, &readfds))) {
    116 				continue;
    117 			}
    118 
    119 			struct {
    120 				char type;
    121 				unsigned int number;
    122 			} message;
    123 
    124 			int length = recv(fd, &message, 1 + sizeof(int), 0);
    125 
    126 			if (length == 0) {
    127 				states[fd].pos = 0;
    128 				printf("Disconnected\n");
    129 				FD_CLR(fd, &set);
    130 				continue;
    131 			}
    132 
    133 			if (message.type == 0) {
    134 				states[fd].pos = message.number;
    135 				for (int dest = 0; dest < FD_SETSIZE; dest++) {
    136 					if (!(dest != 0 && dest != fd &&
    137 					      dest != sockfd &&
    138 					      FD_ISSET(dest, &set))) {
    139 						continue;
    140 					}
    141 					struct state buffer[FD_SETSIZE];
    142 					unsigned short buffer_size = 0;
    143 					for (int i = 0; i < FD_SETSIZE; i++) {
    144 						if (!(i != 0 && i != dest &&
    145 						      i != sockfd &&
    146 						      FD_ISSET(i, &set))) {
    147 							continue;
    148 						}
    149 						buffer[buffer_size++] =
    150 							states[i];
    151 					}
    152 					buffer_size *= sizeof(struct state);
    153 
    154 					send(dest, "\x01", 1, 0);
    155 					send(dest, &buffer_size, 2, 0);
    156 					send(dest, buffer, buffer_size, 0);
    157 				}
    158 			}
    159 
    160 			if (message.type == 1) {
    161 				int quote_idx = message.number;
    162 				change_quote(
    163 					quote_idx, quotes, states, sockfd, set);
    164 			}
    165 		}
    166 	}
    167 	return 0;
    168 }