Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <net/if.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <pwd.h>
- #include <poll.h>
- #include <signal.h>
- //////////////// C++ //////////////////////
- #include "shared.h"
- #include "semaphore.h"
- ///////////////////////////////////////////
- #define SERVER_PORT 32030
- #define PKT_KEEPALIVE 0x00
- #define PKT_STARTGAME 0x01
- #define PKT_MAKEMOVE 0x02
- #define PKT_PLAYERQUIT 0x03
- #define PKT_GAMEOVER 0x04
- #define PKT_ERROR 0x05
- #define PKT_READY 0x06
- #define PKT_CREATEACCT 0x07
- #define PKT_RECORD 0x08
- #define GAME_WIN 0
- #define GAME_LOSE 1
- #define GAME_DRAW 2
- #define WIN_HORIZ 1
- #define WIN_VERT 2
- #define WIN_DIAGLR 3
- #define WIN_DIAGRL 4
- #define BOARD_SIZE 3
- #define MAX_NUM_GAMES 1
- #define MAX_NUM_PLAYERS (MAX_NUM_GAMES * 2)
- #define MAX_NUM_ACCOUNTS 10
- #define DEFAULT_VERBOSE_LEVEL 1
- #define SHKEY_NUM_ACCOUNTS 32030
- #define SHKEY_ACCOUNTS 32031
- struct _game;
- typedef struct _playerrec {
- uint32_t id;
- char fname[10];
- char lname[10];
- uint32_t wins;
- uint32_t losses;
- uint32_t ties;
- } PLAYERREC, *LPPLAYERREC;
- typedef struct _player {
- int sck;
- int id;
- struct _game *pgame;
- struct _player *opponent;
- } PLAYER, *LPPLAYER;
- typedef struct _game {
- LPPLAYER players[2];
- int turn;
- int marks;
- int board[BOARD_SIZE][BOARD_SIZE];
- } GAME, *LPGAME;
- int CreateListenSck();
- void ParseData(LPPLAYER plr, char *data, int len);
- void HandleGameStart(LPPLAYER plr, char *data, int len);
- void HandleGameMove(LPPLAYER plr, char *data, int len);
- void HandlePlayerQuit(LPPLAYER plr, char *data, int len);
- void HandleCreateAcct(LPPLAYER plr, char *data, int len);
- void HandleRecordReq(LPPLAYER plr, char *data, int len);
- void GameStart(LPPLAYER plr);
- void GameEnd(LPGAME game);
- int GameCheckWin(LPGAME game, int plrid, int x, int y);
- void UpdateRecords(int plrid1, int plrid2, int draw);
- void ParseCmdLine(int argc, char *argv[]);
- int GetUidFromUsername(const char *username);
- int verbose = DEFAULT_VERBOSE_LEVEL;
- int force_run_as_root;
- int is_child;
- unsigned short port = SERVER_PORT;
- int nfds;
- struct pollfd fds[MAX_NUM_PLAYERS + 1];
- struct pollfd *fdarr;
- int sck_listen;
- int nplrs;
- PLAYER plrs[MAX_NUM_PLAYERS];
- int ngames;
- GAME games[MAX_NUM_GAMES];
- //////////////// C++ //////////////////////
- Shared<int> num_accounts(1, SHKEY_NUM_ACCOUNTS);
- Shared<PLAYERREC> accounts(MAX_NUM_ACCOUNTS, SHKEY_ACCOUNTS);
- Semaphore mutex(1, 800);
- ///////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- void CleanExit() {
- num_accounts.remove();
- accounts.remove();
- }
- void CleanupShared(int status) {
- CleanExit();
- }
- void ReapTerminatedChild(int status) {
- int s;
- while (waitpid(-1, &s, WNOHANG) > 0);
- if (verbose)
- printf("child exited with status %d!\n", s);
- }
- int main(int argc, char *argv[]) {
- int sck;
- struct sockaddr addr;
- unsigned long on;
- int i, nready, recvlen, cpid;
- unsigned int addrlen;
- struct sigaction sa;
- char rxbuf[256];
- //weird? why does this terminate the parent when raised
- //signal(SIGCHLD, ReapTerminatedChild);
- signal(SIGINT, CleanupShared);
- memset(&sa.sa_mask, 0, sizeof(sa.sa_mask));
- sa.sa_handler = SIG_IGN;
- sa.sa_flags = 0;
- sa.sa_sigaction = NULL;
- sigaction(SIGPIPE, &sa, NULL);
- ParseCmdLine(argc, argv);
- if (getuid() == 0 && !force_run_as_root) {
- fprintf(stderr, "WARNING: should not be running as root!\n");
- setuid(GetUidFromUsername("nobody"));
- }
- srand(time(NULL));
- if (!CreateListenSck()) {
- CleanExit();
- return 1;
- }
- if (listen(sck_listen, SOMAXCONN) == -1) {
- if (verbose)
- fprintf(stderr, "ERROR: listen() failed!\n");
- CleanExit();
- return 1;
- }
- fds[0].fd = sck_listen;
- fds[0].events = POLLIN | POLLHUP;
- fds[0].revents = 0;
- nfds = 1;
- fdarr = fds;
- while ((nready = poll(fdarr, nfds - is_child, INFTIM)) > 0) {
- if (!is_child && fds[0].revents) {
- if (verbose)
- printf("accepting new connection, revents: 0x%x\n",
- fds[0].revents);
- addrlen = sizeof(addr);
- sck = accept(sck_listen, &addr, &addrlen);
- on = 1;
- ioctl(sck, FIONBIO, (u_long *)&on);
- fds[nfds].fd = sck;
- fds[nfds].events = POLLIN | POLLHUP;
- fds[nfds].revents = 0;
- nfds++;
- plrs[nplrs].sck = sck;
- plrs[nplrs].id = -1;
- plrs[nplrs].pgame = NULL;
- plrs[nplrs].opponent = NULL;
- nplrs++;
- if (nplrs == MAX_NUM_PLAYERS) {
- cpid = fork();
- if (cpid == 0) {
- if (verbose)
- printf("subserver created: pid %d\n", getpid());
- //this is necessary to have a enthropy
- //different from the parent's!
- srand(time(NULL));
- is_child = 1;
- fdarr++;
- } else if (cpid == -1) {
- fprintf(stderr,
- "ERROR: fork() returned -1! errno: %d\n", errno);
- CleanExit();
- return 1;
- } else {
- if (verbose)
- printf("forked subserver to pid %d\n", cpid);
- nfds = 1;
- nplrs = 0;
- ngames = 0;
- }
- }
- }
- for (i = 1; i != nfds; i++) {
- if (verbose > 1)
- printf("fds[%d].revents: 0x%08x\n", i, fds[i].revents);
- if (fds[i].revents & POLLHUP) {
- hup:
- if (verbose)
- printf("fd %d finished.\n", fds[i].fd);
- close(fds[i].fd);
- nfds--;
- fds[i].fd = fds[nfds].fd;
- fds[i].events = fds[nfds].events;
- fds[i].revents = fds[nfds].revents;
- GameEnd(plrs[i - 1].pgame);
- nplrs--;
- if (!nplrs && is_child) {
- if (verbose)
- printf("subserver %d exiting\n", getpid());
- CleanExit();
- _exit(0);
- }
- memcpy(&plrs[i - 1], &plrs[nplrs], sizeof(PLAYER));
- i--;
- } else if (fds[i].revents & POLLIN) {
- recvlen = recv(fds[i].fd, rxbuf, sizeof(rxbuf), 0);
- if (!recvlen || recvlen == -1) {
- if (verbose && recvlen == -1)
- fprintf(stderr, "error receiving\n");
- goto hup;
- }
- ParseData(&plrs[i - 1], rxbuf, recvlen);
- }
- }
- }
- CleanExit();
- return 0;
- }
- void ParseCmdLine(int argc, char *argv[]) {
- int i;
- if (!argc)
- return;
- for (i = 1; i != argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
- case 'd': //daemonize
- //TODO: implement this
- break;
- case 'p': //set port
- if (argv[i + 1]) {
- port = atoi(argv[i + 1]);
- i++;
- }
- break;
- case 'r': //force to run as root
- force_run_as_root = 1;
- break;
- case 'v': //verbosity
- verbose++;
- break;
- default:
- ;
- }
- }
- }
- int CreateListenSck() {
- struct sockaddr_in localname;
- unsigned long on;
- int blah;
- sck_listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sck_listen == -1) {
- if (verbose)
- fprintf(stderr, "ERROR: couldn't create listen socket\n");
- return 0;
- }
- blah = 1;
- if (setsockopt(sck_listen, SOL_SOCKET, SO_REUSEADDR,
- (const char *)&blah, sizeof(blah)) == -1) {
- if (verbose)
- fprintf(stderr, "ERROR: couldn't SO_RESUEADDR\n");
- return 0;
- }
- on = 1;
- ioctl(sck_listen, FIONBIO, (u_long *)&on);
- memset(&localname, 0, sizeof(localname));
- localname.sin_family = AF_INET;
- localname.sin_port = htons(port);
- localname.sin_addr.s_addr = INADDR_ANY;
- if (bind(sck_listen, (const struct sockaddr *)&localname,
- sizeof(localname)) == -1) {
- if (verbose)
- fprintf(stderr, "ERROR: couldn't bind to network interface\n");
- return 0;
- }
- return 1;
- }
- void GameStart(LPPLAYER plr) {
- LPPLAYER oplr;
- char buf[128];
- int i, j, k, starting;
- for (i = 0; i != nplrs; i++) {
- if (!plrs[i].pgame && plrs[i].id != -1 && plrs[i].id != plr->id) {
- oplr = &plrs[i];
- break;
- }
- }
- if (i == nplrs) {
- if (verbose)
- fprintf(stderr, "WARNING: could not pair player to start game\n");
- return;
- }
- starting = (rand() & 1);
- buf[0] = PKT_STARTGAME;
- buf[1] = starting;
- *(uint32_t *)(buf + 2) = htonl(oplr->id);
- send(plr->sck, buf, 6, 0);
- buf[1] = !starting;
- *(uint32_t *)(buf + 2) = htonl(plr->id);
- send(oplr->sck, buf, 6, 0);
- plr->opponent = oplr;
- oplr->opponent = plr;
- for (k = 0; k != MAX_NUM_GAMES && games[k].players[0]; k++);
- if (k == MAX_NUM_GAMES) {
- if (verbose)
- fprintf(stderr, "ERROR: no game slots available\n");
- return;
- }
- games[k].players[0] = plr;
- games[k].players[1] = oplr;
- games[k].turn = starting ? plr->id : oplr->id;
- games[k].marks = 0;
- for (i = 0; i != BOARD_SIZE; i++)
- for (j = 0; j != BOARD_SIZE; j++)
- games[k].board[i][j] = -1;
- plr->pgame = &games[k];
- oplr->pgame = &games[k];
- ngames++;
- }
- void GameEnd(LPGAME game) {
- if (!game)
- return;
- game->players[0]->pgame = NULL;
- game->players[1]->pgame = NULL;
- game->players[0] = NULL;
- game->players[1] = NULL;
- ngames--;
- }
- int GameCheckWin(LPGAME game, int plrid, int x, int y) {
- int i, nx;
- nx = 0; //horiz check
- for (i = 0; i != BOARD_SIZE; i++)
- if (game->board[i][y] == plrid)
- nx++;
- if (nx == BOARD_SIZE)
- return WIN_HORIZ;
- nx = 0; //vert check
- for (i = 0; i != BOARD_SIZE; i++)
- if (game->board[x][i] == plrid)
- nx++;
- if (nx == BOARD_SIZE)
- return WIN_VERT;
- nx = 0; //diag check
- for (i = 0; i != BOARD_SIZE; i++)
- if (game->board[i][i] == plrid)
- nx++;
- if (nx == BOARD_SIZE)
- return WIN_DIAGLR;
- nx = 0; //diag check
- for (i = 0; i != BOARD_SIZE; i++)
- if (game->board[(BOARD_SIZE - 1) - i][i] == plrid)
- nx++;
- if (nx == BOARD_SIZE)
- return WIN_DIAGRL;
- return 0;
- }
- void HandleGameStart(LPPLAYER plr, char *data, int len) {
- plr->id = ntohl(*(uint32_t *)(data + 1));
- if (verbose)
- printf("Player %d ready to start\n", plr->id);
- if (nplrs && !(nplrs & 1))
- GameStart(plr);
- }
- void HandleGameMove(LPPLAYER plr, char *data, int len) {
- LPGAME game;
- char buf[8];
- int x, y, win;
- x = (unsigned char)data[1];
- y = (unsigned char)data[2];
- game = plr->pgame;
- if (!game)
- return;
- if (x > (BOARD_SIZE - 1) || y > (BOARD_SIZE - 1) ||
- game->turn != plr->id || game->board[x][y] != -1) {
- buf[0] = PKT_ERROR;
- buf[1] = PKT_MAKEMOVE;
- send(plr->sck, buf, 2, 0);
- if (verbose)
- printf("Player %d sent erroneous packet.\n", plr->id);
- return;
- }
- if (verbose)
- printf("Player %d marked board position (%d, %d).\n", plr->id, x, y);
- send(plr->opponent->sck, data, 3, 0);
- game->board[x][y] = plr->id;
- win = GameCheckWin(game, plr->id, x, y);
- if (win) {
- UpdateRecords(plr->id, plr->opponent->id, 0);
- buf[0] = PKT_GAMEOVER;
- buf[2] = x;
- buf[3] = y;
- buf[4] = win;
- buf[1] = GAME_WIN;
- send(plr->sck, buf, 5, 0);
- buf[1] = GAME_LOSE;
- send(plr->opponent->sck, buf, 5, 0);
- if (verbose)
- printf("Player %d won.\n", plr->id);
- return;
- }
- game->marks++;
- if (game->marks == 9) {
- UpdateRecords(plr->id, plr->opponent->id, 1);
- buf[0] = PKT_GAMEOVER;
- buf[1] = GAME_DRAW;
- send(game->players[0]->sck, buf, 2, 0);
- send(game->players[1]->sck, buf, 2, 0);
- if (verbose)
- printf("Game ended in draw.\n");
- return;
- }
- game->turn = plr->opponent->id;
- }
- void HandlePlayerQuit(LPPLAYER plr, char *data, int len) {
- send(plr->opponent->sck, data, len, 0);
- shutdown(plr->sck, 2);
- }
- void HandleCreateAcct(LPPLAYER plr, char *data, int len) {
- char buf[8];
- uint32_t i;
- buf[0] = PKT_CREATEACCT;
- mutex.wait();
- i = num_accounts[0];
- if (i >= MAX_NUM_ACCOUNTS) {
- *(uint32_t *)(buf + 1) = 0xFFFFFFFF;
- } else {
- accounts[i].id = i;
- accounts[i].wins = 0;
- accounts[i].losses = 0;
- accounts[i].ties = 0;
- strncpy(accounts[i].fname, data + 1, sizeof(accounts[i].fname));
- accounts[i].fname[sizeof(accounts[i].fname) - 1] = 0;
- strncpy(accounts[i].lname, data + 2 + strlen(data + 1),
- sizeof(accounts[i].lname));
- accounts[i].lname[sizeof(accounts[i].lname) - 1] = 0;
- *(uint32_t *)(buf + 1) = htonl(i);
- if (verbose)
- printf("Created new account %d (%s %s)\n", i,
- accounts[i].fname, accounts[i].lname);
- num_accounts[0]++;
- }
- mutex.signal();
- send(plr->sck, buf, 5, 0);
- }
- void HandleRecordReq(LPPLAYER plr, char *data, int len) {
- char buf[64], *next;
- uint32_t lookupid;
- int i;
- lookupid = ntohl(*(uint32_t *)(data + 1));
- buf[0] = PKT_RECORD;
- mutex.wait();
- for (i = 0; i != num_accounts[0]; i++) {
- if (accounts[i].id == lookupid) {
- buf[1] = 1;
- *(uint32_t *)(buf + 2) = htonl(accounts[i].wins);
- *(uint32_t *)(buf + 6) = htonl(accounts[i].losses);
- *(uint32_t *)(buf + 10) = htonl(accounts[i].ties);
- next = stpcpy(buf + 14, accounts[i].fname);
- next = stpcpy(next + 1, accounts[i].lname);
- send(plr->sck, buf, next - buf + 1, 0);
- mutex.signal();
- return;
- }
- }
- mutex.signal();
- buf[1] = 0;
- *(uint32_t *)(buf + 2) = 0;
- *(uint32_t *)(buf + 6) = 0;
- *(uint32_t *)(buf + 10) = 0;
- buf[14] = 0;
- buf[15] = 0;
- send(plr->sck, buf, 16, 0);
- }
- void UpdateRecords(int plrid1, int plrid2, int draw) {
- int i, found = 0;
- mutex.wait();
- for (i = 0; i != num_accounts[0] && found != 2; i++) {
- if (accounts[i].id == (uint32_t)plrid1) {
- found++;
- if (draw)
- accounts[i].ties++;
- else
- accounts[i].wins++;
- } else if (accounts[i].id == (uint32_t)plrid2) {
- found++;
- if (draw)
- accounts[i].ties++;
- else
- accounts[i].losses++;
- }
- }
- mutex.signal();
- }
- void ParseData(LPPLAYER plr, char *data, int len) {
- if (verbose > 1)
- printf("[%02d] received 0x%02x\n", plr->id, (unsigned char)*data);
- int i;
- for (i = 0; i != len; i++)
- printf("%02x ", (unsigned char)data[i]);
- printf("\n");
- switch (*data) {
- case PKT_STARTGAME:
- //HandleGameStart(plr, data, len);
- break;
- case PKT_MAKEMOVE:
- HandleGameMove(plr, data, len);
- break;
- case PKT_PLAYERQUIT:
- HandlePlayerQuit(plr, data, len);
- break;
- case PKT_READY:
- HandleGameStart(plr, data, len);
- break;
- case PKT_CREATEACCT:
- HandleCreateAcct(plr, data, len);
- break;
- case PKT_RECORD:
- HandleRecordReq(plr, data, len);
- break;
- default:
- if (verbose)
- fprintf(stderr, "[%02d] received unhandled packet"
- "0x%02x, ignoring\n", plr->id, (unsigned char)*data);
- }
- }
- int GetUidFromUsername(const char *username) {
- struct passwd *pass;
- if (!username)
- return -1;
- while ((pass = getpwent())) {
- if (!strcmp(pass->pw_name, username)) {
- endpwent();
- return pass->pw_uid;
- }
- }
- endpwent();
- return -1;
- }
Add Comment
Please, Sign In to add comment