Advertisement
Guest User

Untitled

a guest
Nov 17th, 2019
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.36 KB | None | 0 0
  1. #define _POSIX_C_SOURCE 200809L
  2. #define _DEFAULT_SOURCE
  3.  
  4. #include <stdio.h>
  5. #include <errno.h>
  6. #include <stdlib.h>
  7. #include <time.h>
  8. #include <unistd.h>
  9. #include <syslog.h>
  10. #include <string.h>
  11. #include <time.h>
  12. #include <signal.h>
  13.  
  14. #include <sys/types.h>
  15. #include <sys/socket.h>
  16. #include <sys/select.h>
  17. #include <netdb.h>
  18.  
  19. #include "tcp.h"
  20. #include <event2/event.h>
  21.  
  22. #define CORRECT 0
  23. #define INCORRECT 1
  24. #define QUIT 2
  25. #define CHALLENGE 3
  26. #define UNKNOWN 4
  27.  
  28. typedef struct state {
  29. int num_guesses;
  30. int correct;
  31. char fortune[33];
  32. char missing[33];
  33. } state_t;
  34.  
  35. typedef struct node {
  36. int cfd;
  37. state_t *state;
  38. struct event *cev;
  39. struct node *next;
  40. } conn_node;
  41.  
  42. int remove_conn_node(conn_node **head, int cfd);
  43. conn_node* add_new_conn_node(conn_node **head, int cfd);
  44.  
  45.  
  46. conn_node* add_new_conn_node(conn_node **head, int cfd){
  47. conn_node *curr_node = NULL;
  48. state_t *curr_state = NULL;
  49.  
  50. if(*head == NULL){
  51. *head = (conn_node*) malloc(sizeof(conn_node));
  52. if(*head == NULL){
  53. fprintf(stderr, "error creating new connection: %s", strerror(errno));
  54. exit(EXIT_FAILURE);
  55. }
  56. curr_node = *head;
  57. } else {
  58. curr_node = *head;
  59. while(curr_node->next != NULL){
  60. curr_node = curr_node->next;
  61. }
  62. curr_node->next = (conn_node*) malloc(sizeof(conn_node));
  63. curr_node = curr_node->next;
  64. curr_node->next = NULL;
  65. }
  66. curr_node->cfd = cfd;
  67. curr_node->cev = NULL;
  68. curr_node->state = (state_t*) malloc(sizeof(state_t));
  69.  
  70. curr_state = curr_node->state;
  71. curr_state->num_guesses = 0;
  72. curr_state->correct = 0;
  73. curr_state->fortune[0] = '\0';
  74. curr_state->missing[0] = '\0';
  75.  
  76. return curr_node;
  77. }
  78.  
  79. int remove_conn_node(conn_node **head, int cfd){
  80. conn_node *curr_node = NULL;
  81. if(*head == NULL){
  82. fprintf(stderr, "the connection list is empty\n");
  83. return EXIT_FAILURE;
  84. }
  85.  
  86. curr_node = *head;
  87. if(curr_node->cfd == cfd){
  88. *head = ((*head)->next) ? (*head)->next : NULL;
  89. event_free(curr_node->cev);
  90. free(curr_node);
  91. return EXIT_SUCCESS;
  92. }
  93.  
  94. while(curr_node->next != NULL){
  95. if(curr_node->next->cfd == cfd){
  96. conn_node* tmp = curr_node->next;
  97. curr_node->next = (curr_node->next->next) ? curr_node->next->next : NULL;
  98. event_free(tmp->cev);
  99. free(tmp);
  100. break;
  101. }
  102. curr_node = curr_node->next;
  103. }
  104.  
  105. return EXIT_SUCCESS;
  106. }
  107.  
  108.  
  109.  
  110.  
  111. static const char* MESSAGES[] = {
  112. "O: Congratulation - challenge passed!\n",
  113. "F: Wrong guess - expected: %s\n",
  114. "M: You mastered %d/%d challenges. Good bye!\n",
  115. "C: %s",
  116. "Unknown command or format\n"
  117. };
  118.  
  119. static const char *progname = "guess-server";
  120. static struct event_base *evb;
  121. static conn_node *connections = NULL;
  122. static char chars_POSIX[] = " \t\r\n\v\f.,;!~`_-"; /* POSIX whitespace and punctuation chars */
  123.  
  124.  
  125. static void read_fortune(evutil_socket_t evfd, short evwhat, void *evarg);
  126. static void get_fortune(conn_node* connection);
  127. static void send_client(conn_node* connection, int type);
  128. static void read_client(evutil_socket_t evfd, short evwhat, void *evarg);
  129. static void set_connection(evutil_socket_t evfd, short evwhat, void *evarg);
  130.  
  131. int main(int argc, char* argv[]){
  132.  
  133. int fds;
  134. struct event *tev;
  135. /* In case "localhost" does not work, NULL should work */
  136. const char* interfaces[] = {"localhost", NULL, "0.0.0.0", "::"};
  137.  
  138. if(argc != 2){
  139. fprintf(stderr, "Not enough arguments. Usage: %s [port]\n", progname);
  140. exit(EXIT_FAILURE);
  141. }
  142.  
  143. // this if for avoiding zombie processes
  144. if(signal(SIGCHLD, SIG_IGN) == SIG_ERR){
  145. fprintf(stderr, "%s: signal() %s\n", progname, strerror(errno));
  146. exit(EXIT_FAILURE);
  147. }
  148.  
  149. (void) daemon(0, 0);
  150. openlog(progname, LOG_PID, LOG_DAEMON);
  151. evb = event_base_new();
  152. if(!evb){
  153. syslog(LOG_ERR, "creating event base failed");
  154. exit(EXIT_FAILURE);
  155. }
  156.  
  157. for(int i = 0; interfaces[i]; i++){
  158. fds = tcp_listen(interfaces[i], argv[1]);
  159. if(fds < 0){
  160. fprintf(stderr, "error %s %s: could listen to connection\n", strerror(errno), progname);
  161. continue;
  162. }
  163. tev = event_new(evb, fds, EV_READ | EV_PERSIST, set_connection, NULL);
  164. event_add(tev, NULL);
  165. }
  166.  
  167. if(event_base_loop(evb, 0) == -1){
  168. syslog(LOG_ERR, "event loop failed");
  169. event_base_free(evb);
  170. exit(EXIT_FAILURE);
  171. }
  172.  
  173. closelog();
  174. event_base_free(evb);
  175.  
  176. return EXIT_SUCCESS;
  177. }
  178.  
  179. static void hide_word(state_t* curr_state){
  180. char *pos;
  181. char *token = NULL;
  182. int n;
  183. int word_pos;
  184. char tmp[64];
  185.  
  186. pos = curr_state->fortune;
  187. while((pos = strpbrk(pos, chars_POSIX)) != NULL){
  188. pos++;
  189. n++;
  190. }
  191.  
  192. while(token == NULL){
  193.  
  194. srand(time(NULL));
  195. word_pos = rand()%n;
  196. n = 0;
  197.  
  198. strcpy(tmp, curr_state->fortune);
  199. token = strtok(tmp, chars_POSIX);
  200. while(token){
  201. if(n == word_pos){
  202. pos = strstr(curr_state->fortune, token);
  203. if(!pos){
  204. break;
  205. }
  206. memset(pos, '_', strlen(token));
  207. strcpy(curr_state->missing, token);
  208. break;
  209. }
  210. n++;
  211. token = strtok(NULL, chars_POSIX);
  212. }
  213. }
  214. }
  215.  
  216. static void read_fortune(evutil_socket_t evfd, short evwhat, void *evarg){
  217. int pfd = evfd;
  218. int nbytes;
  219. conn_node *curr_conn = (conn_node*) evarg;
  220. char buf[64];
  221.  
  222. nbytes = read(pfd, buf, 32);
  223. if(nbytes < 0){
  224. fprintf(stderr, "%s: read failed %s\n", progname, strerror(errno));
  225. exit(EXIT_FAILURE);
  226. } else {
  227. buf[nbytes] = '\0';
  228. strcpy(curr_conn->state->fortune, buf);
  229. }
  230.  
  231. hide_word(curr_conn->state);
  232. send_client(curr_conn, CHALLENGE);
  233. }
  234.  
  235. static void get_fortune(conn_node* connection){
  236. int pfd[2];
  237. pid_t pid;
  238. struct event *fev;
  239.  
  240. (void) pipe(pfd);
  241. fev = event_new(evb, pfd[0], EV_READ, read_fortune, connection);
  242. event_add(fev, NULL);
  243.  
  244. pid = fork();
  245. if(pid == -1){
  246. /* Failed forking */
  247. syslog(LOG_ERR, "failed to fork process\n");
  248. connection->state->fortune[0] = '\0';
  249. } else if(pid == 0){
  250. /* Child process */
  251. close(pfd[0]);
  252. dup2(pfd[1], STDOUT_FILENO);
  253. close(pfd[1]);
  254.  
  255. execlp("fortune", "fortune", "-n", "32", "-s", NULL);
  256. /* If it comes here then execution has failed */
  257. syslog(LOG_ERR, "failed to execute fortune\n");
  258. exit(EXIT_FAILURE);
  259. } else {
  260. /* We only need the read endpoint so we close the write */
  261. close(pfd[1]);
  262. }
  263. }
  264.  
  265. static void send_client(conn_node* connection, int type){
  266. char buf[256];
  267. int nbytes;
  268. if(type == QUIT){
  269. sprintf(buf, MESSAGES[QUIT], connection->state->correct, connection->state->num_guesses);
  270. } else if(type == CORRECT){
  271. strcpy(buf, MESSAGES[CORRECT]);
  272. } else if(type == INCORRECT){
  273. sprintf(buf, MESSAGES[INCORRECT], connection->state->missing);
  274. } else if(type == CHALLENGE){
  275. sprintf(buf, MESSAGES[CHALLENGE], connection->state->fortune);
  276. } else {
  277. strcpy(buf, MESSAGES[UNKNOWN]);
  278. }
  279.  
  280. nbytes = tcp_write(connection->cfd, buf, strlen(buf));
  281. if(nbytes < 0){
  282. fprintf(stderr, "%s: write failed %s\n", progname, strerror(errno));
  283. exit(EXIT_FAILURE);
  284. }
  285. }
  286.  
  287. static void read_client(evutil_socket_t evfd, short evwhat, void *evarg){
  288. int nbytes;
  289. int cfd = evfd;
  290. conn_node *curr_conn = (conn_node*) evarg;
  291. char buf[256];
  292. char *guess;
  293.  
  294. nbytes = read(cfd, buf, sizeof(buf));
  295. if(nbytes < 0){
  296. fprintf(stderr, "%s: read failed: %s\n", progname, strerror(errno));
  297. exit(EXIT_FAILURE);
  298. }
  299.  
  300. if(strstr(buf, "Q:") == buf){
  301. /* In case the user wants to quit */
  302. send_client(curr_conn, QUIT);
  303. event_free(curr_conn->cev);
  304. tcp_close(cfd);
  305. remove_conn_node(&connections, cfd);
  306. } else {
  307. if(strstr(buf, "R:") == buf){
  308. /* Response from the user */
  309. curr_conn->state->num_guesses++;
  310. memmove(buf, buf+2, strlen(buf)-2);
  311. guess = strtok(buf, chars_POSIX);
  312. if(guess == NULL || strcmp(guess, curr_conn->state->missing) != 0){
  313. send_client(curr_conn, INCORRECT);
  314. } else {
  315. curr_conn->state->correct++;
  316. send_client(curr_conn, CORRECT);
  317. }
  318. get_fortune(curr_conn);
  319. } else {
  320. /* Unrecognized command */
  321. send_client(curr_conn, UNKNOWN);
  322. }
  323. }
  324. }
  325.  
  326. static void set_connection(evutil_socket_t evfd, short evwhat, void *evarg){
  327. size_t n;
  328. int cfd;
  329. char welcome[256];
  330. conn_node *new_conn;
  331.  
  332. cfd = tcp_accept((int)evfd);
  333. if(cfd < 0){
  334. fprintf(stderr, "%s: could not connect: %s\n", progname, strerror(errno));
  335. exit(EXIT_FAILURE);
  336. }
  337.  
  338. strcpy(welcome, "M: Guess the missing ____!\n");
  339. strcat(welcome, "M: Send your guess in the for 'R: word\\r\\n'.\n");
  340.  
  341. n = tcp_write(cfd, welcome, strlen(welcome));
  342. if(n < 0){
  343. fprintf(stderr, "%s: %s writing failed\n", progname, welcome);
  344. tcp_close(cfd);
  345. exit(EXIT_FAILURE);
  346. }
  347.  
  348. new_conn = add_new_conn_node(&connections, cfd);
  349. new_conn->cev = event_new(evb, cfd, EV_READ | EV_PERSIST, read_client, new_conn);
  350. event_add(new_conn->cev, NULL);
  351.  
  352. get_fortune(new_conn);
  353. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement