Guest User

Untitled

a guest
Mar 17th, 2018
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.49 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/socket.h>
  6. #include <sys/ioctl.h>
  7. #include <sys/types.h>
  8. #include <sys/wait.h>
  9. #include <net/if.h>
  10. #include <netinet/in.h>
  11. #include <arpa/inet.h>
  12. #include <pwd.h>
  13. #include <poll.h>
  14. #include <signal.h>
  15. //////////////// C++ //////////////////////
  16. #include "shared.h"
  17. #include "semaphore.h"
  18. ///////////////////////////////////////////
  19.  
  20. #define SERVER_PORT    32030
  21.  
  22. #define PKT_KEEPALIVE  0x00
  23. #define PKT_STARTGAME  0x01
  24. #define PKT_MAKEMOVE   0x02
  25. #define PKT_PLAYERQUIT 0x03
  26. #define PKT_GAMEOVER   0x04
  27. #define PKT_ERROR      0x05
  28. #define PKT_READY      0x06
  29. #define PKT_CREATEACCT 0x07
  30. #define PKT_RECORD     0x08
  31.  
  32. #define GAME_WIN  0
  33. #define GAME_LOSE 1
  34. #define GAME_DRAW 2
  35.  
  36. #define WIN_HORIZ  1
  37. #define WIN_VERT   2
  38. #define WIN_DIAGLR 3
  39. #define WIN_DIAGRL 4
  40.  
  41. #define BOARD_SIZE 3
  42.  
  43. #define MAX_NUM_GAMES  1
  44. #define MAX_NUM_PLAYERS (MAX_NUM_GAMES * 2)
  45. #define MAX_NUM_ACCOUNTS 10
  46.  
  47. #define DEFAULT_VERBOSE_LEVEL 1
  48.  
  49. #define SHKEY_NUM_ACCOUNTS 32030
  50. #define SHKEY_ACCOUNTS     32031
  51.  
  52.  
  53. struct _game;
  54.  
  55. typedef struct _playerrec {
  56.     uint32_t id;
  57.     char fname[10];
  58.     char lname[10];
  59.     uint32_t wins;
  60.     uint32_t losses;
  61.     uint32_t ties;
  62. } PLAYERREC, *LPPLAYERREC;
  63.  
  64. typedef struct _player {
  65.     int sck;
  66.     int id;
  67.     struct _game *pgame;
  68.     struct _player *opponent;
  69. } PLAYER, *LPPLAYER;
  70.  
  71. typedef struct _game {
  72.     LPPLAYER players[2];
  73.     int turn;
  74.     int marks;
  75.     int board[BOARD_SIZE][BOARD_SIZE];
  76. } GAME, *LPGAME;
  77.  
  78.  
  79. int CreateListenSck();
  80. void ParseData(LPPLAYER plr, char *data, int len);
  81. void HandleGameStart(LPPLAYER plr, char *data, int len);
  82. void HandleGameMove(LPPLAYER plr, char *data, int len);
  83. void HandlePlayerQuit(LPPLAYER plr, char *data, int len);
  84. void HandleCreateAcct(LPPLAYER plr, char *data, int len);
  85. void HandleRecordReq(LPPLAYER plr, char *data, int len);
  86.  
  87. void GameStart(LPPLAYER plr);
  88. void GameEnd(LPGAME game);
  89. int GameCheckWin(LPGAME game, int plrid, int x, int y);
  90. void UpdateRecords(int plrid1, int plrid2, int draw);
  91.  
  92. void ParseCmdLine(int argc, char *argv[]);
  93. int GetUidFromUsername(const char *username);
  94.  
  95.  
  96. int verbose = DEFAULT_VERBOSE_LEVEL;
  97. int force_run_as_root;
  98. int is_child;
  99. unsigned short port = SERVER_PORT;
  100.  
  101. int nfds;
  102. struct pollfd fds[MAX_NUM_PLAYERS + 1];
  103. struct pollfd *fdarr;
  104. int sck_listen;
  105.  
  106. int nplrs;
  107. PLAYER plrs[MAX_NUM_PLAYERS];
  108.  
  109. int ngames;
  110. GAME games[MAX_NUM_GAMES];
  111.  
  112.  
  113. //////////////// C++ //////////////////////
  114. Shared<int>       num_accounts(1, SHKEY_NUM_ACCOUNTS);
  115. Shared<PLAYERREC> accounts(MAX_NUM_ACCOUNTS, SHKEY_ACCOUNTS);
  116. Semaphore mutex(1, 800);
  117. ///////////////////////////////////////////
  118.  
  119. ///////////////////////////////////////////////////////////////////////////////
  120.  
  121.  
  122. void CleanExit() {
  123.     num_accounts.remove();
  124.     accounts.remove();
  125. }
  126.  
  127.  
  128. void CleanupShared(int status) {
  129.     CleanExit();
  130. }
  131.  
  132.  
  133. void ReapTerminatedChild(int status) {
  134.     int s;
  135.  
  136.     while (waitpid(-1, &s, WNOHANG) > 0);
  137.     if (verbose)
  138.         printf("child exited with status %d!\n", s);
  139. }
  140.  
  141.  
  142. int main(int argc, char *argv[]) {
  143.     int sck;
  144.     struct sockaddr addr;
  145.     unsigned long on;
  146.     int i, nready, recvlen, cpid;
  147.     unsigned int addrlen;
  148.     struct sigaction sa;
  149.     char rxbuf[256];
  150.  
  151.     //weird? why does this terminate the parent when raised
  152.     //signal(SIGCHLD, ReapTerminatedChild);
  153.  
  154.     signal(SIGINT, CleanupShared);
  155.     memset(&sa.sa_mask, 0, sizeof(sa.sa_mask));
  156.     sa.sa_handler   = SIG_IGN;
  157.     sa.sa_flags     = 0;
  158.     sa.sa_sigaction = NULL;
  159.     sigaction(SIGPIPE, &sa, NULL);
  160.  
  161.     ParseCmdLine(argc, argv);
  162.  
  163.     if (getuid() == 0 && !force_run_as_root) {
  164.         fprintf(stderr, "WARNING: should not be running as root!\n");
  165.         setuid(GetUidFromUsername("nobody"));
  166.     }
  167.     srand(time(NULL));
  168.  
  169.     if (!CreateListenSck()) {
  170.         CleanExit();
  171.         return 1;
  172.     }
  173.  
  174.     if (listen(sck_listen, SOMAXCONN) == -1) {
  175.         if (verbose)
  176.             fprintf(stderr, "ERROR: listen() failed!\n");
  177.         CleanExit();
  178.         return 1;
  179.     }
  180.  
  181.     fds[0].fd      = sck_listen;
  182.     fds[0].events  = POLLIN | POLLHUP;
  183.     fds[0].revents = 0;
  184.     nfds  = 1;
  185.     fdarr = fds;
  186.     while ((nready = poll(fdarr, nfds - is_child, INFTIM)) > 0) {
  187.         if (!is_child && fds[0].revents) {
  188.             if (verbose)
  189.                 printf("accepting new connection, revents: 0x%x\n",
  190.                     fds[0].revents);
  191.  
  192.             addrlen = sizeof(addr);
  193.             sck = accept(sck_listen, &addr, &addrlen);
  194.            
  195.             on = 1;
  196.             ioctl(sck, FIONBIO, (u_long *)&on);
  197.            
  198.             fds[nfds].fd      = sck;
  199.             fds[nfds].events  = POLLIN | POLLHUP;
  200.             fds[nfds].revents = 0;
  201.             nfds++;
  202.  
  203.             plrs[nplrs].sck      = sck;
  204.             plrs[nplrs].id       = -1;
  205.             plrs[nplrs].pgame    = NULL;
  206.             plrs[nplrs].opponent = NULL;
  207.             nplrs++;
  208.  
  209.             if (nplrs == MAX_NUM_PLAYERS) {
  210.  
  211.                 cpid = fork();
  212.                 if (cpid == 0) {
  213.                     if (verbose)
  214.                         printf("subserver created: pid %d\n", getpid());
  215.                    
  216.                     //this is necessary to have a enthropy
  217.                     //different from the parent's!
  218.                     srand(time(NULL));
  219.  
  220.                     is_child = 1;
  221.                     fdarr++;
  222.                 } else if (cpid == -1) {
  223.                     fprintf(stderr,
  224.                         "ERROR: fork() returned -1! errno: %d\n", errno);
  225.                     CleanExit();
  226.                     return 1;
  227.                 } else {
  228.                     if (verbose)
  229.                         printf("forked subserver to pid %d\n", cpid);
  230.                     nfds   = 1;
  231.                     nplrs  = 0;
  232.                     ngames = 0;
  233.                 }
  234.             }
  235.         }
  236.         for (i = 1; i != nfds; i++) {
  237.             if (verbose > 1)
  238.                 printf("fds[%d].revents: 0x%08x\n", i, fds[i].revents);
  239.             if (fds[i].revents & POLLHUP) {
  240.                 hup:
  241.  
  242.                 if (verbose)
  243.                     printf("fd %d finished.\n", fds[i].fd);
  244.  
  245.                 close(fds[i].fd);
  246.  
  247.                 nfds--;
  248.                 fds[i].fd      = fds[nfds].fd;
  249.                 fds[i].events  = fds[nfds].events;
  250.                 fds[i].revents = fds[nfds].revents;
  251.  
  252.                 GameEnd(plrs[i - 1].pgame);
  253.  
  254.                 nplrs--;
  255.  
  256.                 if (!nplrs && is_child) {
  257.                     if (verbose)
  258.                         printf("subserver %d exiting\n", getpid());
  259.                     CleanExit();
  260.                     _exit(0);
  261.                 }
  262.  
  263.                 memcpy(&plrs[i - 1], &plrs[nplrs], sizeof(PLAYER));
  264.  
  265.                 i--;
  266.             } else if (fds[i].revents & POLLIN) {
  267.                 recvlen = recv(fds[i].fd, rxbuf, sizeof(rxbuf), 0);
  268.                 if (!recvlen || recvlen == -1) {
  269.                     if (verbose && recvlen == -1)
  270.                         fprintf(stderr, "error receiving\n");
  271.                     goto hup;
  272.                 }
  273.                 ParseData(&plrs[i - 1], rxbuf, recvlen);
  274.             }
  275.         }
  276.     }
  277.     CleanExit();
  278.     return 0;
  279. }
  280.  
  281.  
  282. void ParseCmdLine(int argc, char *argv[]) {
  283.     int i;
  284.    
  285.     if (!argc)
  286.         return;
  287.  
  288.     for (i = 1; i != argc; i++) {
  289.         if (argv[i][0] != '-')
  290.             continue;
  291.  
  292.         switch (argv[i][1]) {
  293.             case 'd': //daemonize
  294.                 //TODO: implement this
  295.                 break;
  296.             case 'p': //set port
  297.                 if (argv[i + 1]) {
  298.                     port = atoi(argv[i + 1]);
  299.                     i++;
  300.                 }
  301.                 break;
  302.             case 'r': //force to run as root
  303.                 force_run_as_root = 1;
  304.                 break;
  305.             case 'v': //verbosity
  306.                 verbose++;
  307.                 break;
  308.             default:
  309.                 ;
  310.         }
  311.     }
  312.    
  313. }
  314.  
  315.  
  316. int CreateListenSck() {
  317.     struct sockaddr_in localname;
  318.     unsigned long on;
  319.     int blah;
  320.  
  321.     sck_listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  322.     if (sck_listen == -1) {
  323.         if (verbose)
  324.             fprintf(stderr, "ERROR: couldn't create listen socket\n");
  325.         return 0;
  326.     }
  327.  
  328.     blah = 1;
  329.     if (setsockopt(sck_listen, SOL_SOCKET, SO_REUSEADDR,
  330.         (const char *)&blah, sizeof(blah)) == -1) {
  331.         if (verbose)
  332.             fprintf(stderr, "ERROR: couldn't SO_RESUEADDR\n");
  333.         return 0;
  334.     }
  335.  
  336.     on = 1;
  337.     ioctl(sck_listen, FIONBIO, (u_long *)&on);
  338.  
  339.     memset(&localname, 0, sizeof(localname));
  340.     localname.sin_family      = AF_INET;
  341.     localname.sin_port        = htons(port);
  342.     localname.sin_addr.s_addr = INADDR_ANY;
  343.     if (bind(sck_listen, (const struct sockaddr *)&localname,
  344.         sizeof(localname)) == -1) {
  345.         if (verbose)
  346.             fprintf(stderr, "ERROR: couldn't bind to network interface\n");
  347.         return 0;
  348.     }
  349.  
  350.     return 1;
  351. }
  352.  
  353.  
  354. void GameStart(LPPLAYER plr) {
  355.     LPPLAYER oplr;
  356.     char buf[128];
  357.     int i, j, k, starting;
  358.  
  359.     for (i = 0; i != nplrs; i++) {
  360.         if (!plrs[i].pgame && plrs[i].id != -1 && plrs[i].id != plr->id) {
  361.             oplr = &plrs[i];
  362.             break;
  363.         }
  364.     }
  365.     if (i == nplrs) {
  366.         if (verbose)
  367.             fprintf(stderr, "WARNING: could not pair player to start game\n");
  368.         return;
  369.     }
  370.  
  371.     starting = (rand() & 1);
  372.  
  373.     buf[0] = PKT_STARTGAME;
  374.  
  375.     buf[1] = starting;
  376.     *(uint32_t *)(buf + 2) = htonl(oplr->id);
  377.     send(plr->sck, buf, 6, 0);
  378.  
  379.     buf[1] = !starting;
  380.     *(uint32_t *)(buf + 2) = htonl(plr->id);
  381.     send(oplr->sck, buf, 6, 0);
  382.  
  383.     plr->opponent  = oplr;
  384.     oplr->opponent = plr;
  385.  
  386.     for (k = 0; k != MAX_NUM_GAMES && games[k].players[0]; k++);
  387.     if (k == MAX_NUM_GAMES) {
  388.         if (verbose)
  389.             fprintf(stderr, "ERROR: no game slots available\n");
  390.         return;
  391.     }
  392.  
  393.     games[k].players[0] = plr;
  394.     games[k].players[1] = oplr;
  395.     games[k].turn       = starting ? plr->id : oplr->id;
  396.     games[k].marks      = 0;
  397.     for (i = 0; i != BOARD_SIZE; i++)
  398.         for (j = 0; j != BOARD_SIZE; j++)
  399.             games[k].board[i][j] = -1;
  400.     plr->pgame  = &games[k];
  401.     oplr->pgame = &games[k];
  402.     ngames++;
  403. }
  404.  
  405.  
  406. void GameEnd(LPGAME game) {
  407.     if (!game)
  408.         return;
  409.  
  410.     game->players[0]->pgame = NULL;
  411.     game->players[1]->pgame = NULL;
  412.     game->players[0] = NULL;
  413.     game->players[1] = NULL;
  414.     ngames--;
  415. }
  416.  
  417.  
  418. int GameCheckWin(LPGAME game, int plrid, int x, int y) {
  419.     int i, nx;
  420.  
  421.     nx = 0; //horiz check
  422.     for (i = 0; i != BOARD_SIZE; i++)
  423.         if (game->board[i][y] == plrid)
  424.             nx++;
  425.     if (nx == BOARD_SIZE)
  426.         return WIN_HORIZ;
  427.  
  428.     nx = 0; //vert check
  429.     for (i = 0; i != BOARD_SIZE; i++)
  430.         if (game->board[x][i] == plrid)
  431.             nx++;
  432.     if (nx == BOARD_SIZE)
  433.         return WIN_VERT;
  434.  
  435.     nx = 0; //diag check
  436.     for (i = 0; i != BOARD_SIZE; i++)
  437.         if (game->board[i][i] == plrid)
  438.             nx++;
  439.     if (nx == BOARD_SIZE)
  440.         return WIN_DIAGLR;
  441.  
  442.     nx = 0; //diag check
  443.     for (i = 0; i != BOARD_SIZE; i++)
  444.         if (game->board[(BOARD_SIZE - 1) - i][i] == plrid)
  445.             nx++;
  446.     if (nx == BOARD_SIZE)
  447.         return WIN_DIAGRL;
  448.  
  449.     return 0;
  450. }
  451.  
  452.  
  453. void HandleGameStart(LPPLAYER plr, char *data, int len) {
  454.  
  455.     plr->id = ntohl(*(uint32_t *)(data + 1));
  456.  
  457.     if (verbose)
  458.         printf("Player %d ready to start\n", plr->id);
  459.  
  460.     if (nplrs && !(nplrs & 1))
  461.         GameStart(plr);
  462. }
  463.  
  464.  
  465. void HandleGameMove(LPPLAYER plr, char *data, int len) {
  466.     LPGAME game;
  467.     char buf[8];
  468.     int x, y, win;
  469.  
  470.     x = (unsigned char)data[1];
  471.     y = (unsigned char)data[2];
  472.     game = plr->pgame;
  473.     if (!game)
  474.         return;
  475.  
  476.     if (x > (BOARD_SIZE - 1) || y > (BOARD_SIZE - 1) ||
  477.         game->turn != plr->id || game->board[x][y] != -1) {
  478.         buf[0] = PKT_ERROR;
  479.         buf[1] = PKT_MAKEMOVE;
  480.         send(plr->sck, buf, 2, 0);
  481.         if (verbose)
  482.             printf("Player %d sent erroneous packet.\n", plr->id);
  483.         return;
  484.     }
  485.  
  486.     if (verbose)
  487.         printf("Player %d marked board position (%d, %d).\n", plr->id, x, y);
  488.  
  489.     send(plr->opponent->sck, data, 3, 0);
  490.  
  491.     game->board[x][y] = plr->id;
  492.  
  493.     win = GameCheckWin(game, plr->id, x, y);
  494.     if (win) {
  495.         UpdateRecords(plr->id, plr->opponent->id, 0);
  496.  
  497.         buf[0] = PKT_GAMEOVER;
  498.         buf[2] = x;
  499.         buf[3] = y;
  500.         buf[4] = win;
  501.        
  502.         buf[1] = GAME_WIN;
  503.         send(plr->sck, buf, 5, 0);
  504.  
  505.         buf[1] = GAME_LOSE;
  506.         send(plr->opponent->sck, buf, 5, 0);
  507.  
  508.         if (verbose)
  509.             printf("Player %d won.\n", plr->id);
  510.         return;
  511.  
  512.     }
  513.  
  514.     game->marks++;
  515.     if (game->marks == 9) {
  516.         UpdateRecords(plr->id, plr->opponent->id, 1);
  517.  
  518.         buf[0] = PKT_GAMEOVER;
  519.         buf[1] = GAME_DRAW;
  520.         send(game->players[0]->sck, buf, 2, 0);
  521.         send(game->players[1]->sck, buf, 2, 0);
  522.  
  523.         if (verbose)
  524.             printf("Game ended in draw.\n");
  525.         return;
  526.     }
  527.  
  528.     game->turn = plr->opponent->id;
  529. }
  530.  
  531.  
  532. void HandlePlayerQuit(LPPLAYER plr, char *data, int len) {
  533.     send(plr->opponent->sck, data, len, 0);
  534.     shutdown(plr->sck, 2);
  535. }
  536.  
  537.  
  538. void HandleCreateAcct(LPPLAYER plr, char *data, int len) {
  539.     char buf[8];
  540.     uint32_t i;
  541.  
  542.     buf[0] = PKT_CREATEACCT;
  543.  
  544.     mutex.wait();
  545.     i = num_accounts[0];
  546.     if (i >= MAX_NUM_ACCOUNTS) {
  547.         *(uint32_t *)(buf + 1) = 0xFFFFFFFF;
  548.     } else {
  549.         accounts[i].id     = i;
  550.         accounts[i].wins   = 0;
  551.         accounts[i].losses = 0;
  552.         accounts[i].ties   = 0;
  553.  
  554.         strncpy(accounts[i].fname, data + 1, sizeof(accounts[i].fname));
  555.         accounts[i].fname[sizeof(accounts[i].fname) - 1] = 0;
  556.  
  557.         strncpy(accounts[i].lname, data + 2 + strlen(data + 1),
  558.             sizeof(accounts[i].lname));
  559.         accounts[i].lname[sizeof(accounts[i].lname) - 1] = 0;
  560.  
  561.         *(uint32_t *)(buf + 1) = htonl(i);
  562.  
  563.         if (verbose)
  564.             printf("Created new account %d (%s %s)\n", i,
  565.                 accounts[i].fname, accounts[i].lname);
  566.  
  567.         num_accounts[0]++;
  568.     }
  569.     mutex.signal();
  570.  
  571.     send(plr->sck, buf, 5, 0);
  572. }
  573.  
  574.  
  575. void HandleRecordReq(LPPLAYER plr, char *data, int len) {
  576.     char buf[64], *next;
  577.     uint32_t lookupid;
  578.     int i;
  579.  
  580.     lookupid = ntohl(*(uint32_t *)(data + 1));
  581.  
  582.     buf[0] = PKT_RECORD;
  583.  
  584.     mutex.wait();
  585.     for (i = 0; i != num_accounts[0]; i++) {
  586.         if (accounts[i].id == lookupid) {
  587.             buf[1] = 1;
  588.             *(uint32_t *)(buf + 2)  = htonl(accounts[i].wins);
  589.             *(uint32_t *)(buf + 6)  = htonl(accounts[i].losses);
  590.             *(uint32_t *)(buf + 10) = htonl(accounts[i].ties);
  591.             next = stpcpy(buf + 14, accounts[i].fname);
  592.             next = stpcpy(next + 1, accounts[i].lname);
  593.             send(plr->sck, buf, next - buf + 1, 0);
  594.             mutex.signal();
  595.             return;
  596.         }
  597.     }
  598.     mutex.signal();
  599.  
  600.     buf[1] = 0;
  601.     *(uint32_t *)(buf + 2)  = 0;
  602.     *(uint32_t *)(buf + 6)  = 0;
  603.     *(uint32_t *)(buf + 10) = 0;
  604.     buf[14] = 0;
  605.     buf[15] = 0;
  606.     send(plr->sck, buf, 16, 0);
  607. }
  608.  
  609.  
  610. void UpdateRecords(int plrid1, int plrid2, int draw) {
  611.     int i, found = 0;
  612.  
  613.     mutex.wait();
  614.     for (i = 0; i != num_accounts[0] && found != 2; i++) {
  615.         if (accounts[i].id == (uint32_t)plrid1) {
  616.             found++;
  617.             if (draw)
  618.                 accounts[i].ties++;
  619.             else
  620.                 accounts[i].wins++;
  621.         } else if (accounts[i].id == (uint32_t)plrid2) {
  622.             found++;
  623.             if (draw)
  624.                 accounts[i].ties++;
  625.             else
  626.                 accounts[i].losses++;
  627.         }
  628.     }
  629.     mutex.signal();
  630. }
  631.  
  632.  
  633. void ParseData(LPPLAYER plr, char *data, int len) {
  634.     if (verbose > 1)
  635.         printf("[%02d] received 0x%02x\n", plr->id, (unsigned char)*data);
  636.  
  637.     int i;
  638.     for (i = 0; i != len; i++)
  639.         printf("%02x ", (unsigned char)data[i]);
  640.     printf("\n");
  641.  
  642.     switch (*data) {
  643.         case PKT_STARTGAME:
  644.             //HandleGameStart(plr, data, len);
  645.             break;
  646.         case PKT_MAKEMOVE:
  647.             HandleGameMove(plr, data, len);
  648.             break;
  649.         case PKT_PLAYERQUIT:
  650.             HandlePlayerQuit(plr, data, len);
  651.             break;
  652.         case PKT_READY:
  653.             HandleGameStart(plr, data, len);
  654.             break;
  655.         case PKT_CREATEACCT:
  656.             HandleCreateAcct(plr, data, len);
  657.             break;
  658.         case PKT_RECORD:
  659.             HandleRecordReq(plr, data, len);
  660.             break;
  661.         default:
  662.             if (verbose)
  663.                 fprintf(stderr, "[%02d] received unhandled packet"
  664.                 "0x%02x, ignoring\n", plr->id, (unsigned char)*data);
  665.     }
  666. }
  667.  
  668.  
  669. int GetUidFromUsername(const char *username) {
  670.     struct passwd *pass;
  671.  
  672.     if (!username)
  673.         return -1;
  674.  
  675.     while ((pass = getpwent())) {
  676.         if (!strcmp(pass->pw_name, username)) {
  677.             endpwent();
  678.             return pass->pw_uid;
  679.         }
  680.     }
  681.     endpwent();
  682.     return -1;
  683. }
Add Comment
Please, Sign In to add comment