home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Inne / Gry / Atomic_Tanks / Atomic-Tanks-5.1.exe / src / network.cpp < prev    next >
C/C++ Source or Header  |  2009-11-15  |  12KB  |  510 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #ifdef NETWORK
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <sys/select.h>
  9. #include <netdb.h>
  10. #include <errno.h>
  11. #include <unistd.h>
  12. #include <pthread.h>
  13. #endif
  14.  
  15. #include "network.h"
  16. #include "player.h"
  17. #include "globaldata.h"
  18.  
  19.  
  20. // init the object
  21. MESSAGE_QUEUE::MESSAGE_QUEUE()
  22. {
  23.    first_message = last_message = NULL;
  24. }
  25.  
  26.  
  27.  
  28. // do clean up on all messages
  29. MESSAGE_QUEUE::~MESSAGE_QUEUE()
  30. {
  31.    Erase_All();
  32. }
  33.  
  34.  
  35.  
  36. // add a new message to the queue
  37. // Returns true on success and false is an error occures
  38. bool MESSAGE_QUEUE::Add(char *some_text, int to)
  39. {
  40.     MESSAGE *new_message;
  41.  
  42.     if (! some_text)
  43.       return false;
  44.  
  45.     new_message = (MESSAGE *) calloc(1, sizeof(MESSAGE));
  46.     if (! new_message)
  47.         return false;
  48.     new_message->text = (char *) calloc( strlen(some_text), sizeof(char) );
  49.     if (! new_message->text)
  50.     {
  51.        free(new_message);
  52.        return false;
  53.     }
  54.  
  55.     // fill the message structure
  56.     strcpy(new_message->text, some_text);
  57.     new_message->to = to;
  58.     // next is already cleared by calloc
  59.  
  60.     // empty line, create new line
  61.     if (! first_message)
  62.     {
  63.        first_message = new_message;
  64.        last_message = new_message;
  65.     }
  66.  
  67.     else // we have a line, add it to the end
  68.     {
  69.        last_message->next = new_message;
  70.        last_message = new_message;
  71.     }
  72.     return true;
  73. }
  74.  
  75.  
  76.  
  77. // retreive a message and erase it from the queue
  78. // returns a message on success and NULL on failure
  79. MESSAGE *MESSAGE_QUEUE::Read()
  80. {
  81.    MESSAGE *my_message;
  82.  
  83.    my_message = Peek();       // grab next message
  84.    if (my_message)
  85.       Erase();            // clear it from the queue
  86.  
  87.    return my_message;
  88. }
  89.  
  90.  
  91.  
  92. // returns a message from the queue without removing it from the line
  93. // Returns a message on success or a NULL on failure
  94. MESSAGE *MESSAGE_QUEUE::Peek()
  95. {
  96.    MESSAGE *my_message;
  97.  
  98.    // see if there is a message to get
  99.    if ( (! first_message) || (! first_message->text) )
  100.       return NULL;
  101.  
  102.    // we want to make a copy of the message, not just pass back a pointer
  103.    my_message = (MESSAGE *) calloc( 1, sizeof(MESSAGE) );
  104.    if (! my_message)
  105.       return NULL;
  106.    my_message->text = (char *) calloc( strlen(first_message->text), sizeof(char) );
  107.    if (! my_message->text)
  108.    {
  109.       free(my_message);
  110.       return NULL;
  111.    }
  112.  
  113.    // we have an empty message. Now fill it
  114.    strcpy(my_message->text, first_message->text);
  115.    my_message->to = first_message->to;
  116.    
  117.    return my_message;
  118. }
  119.  
  120.  
  121.  
  122. // Finds the next message destined "to" a given player
  123. // This function returns the first message it finds and
  124. // erases it. The message is returned on success or a
  125. // NULL is returned if no message is found.
  126. MESSAGE *MESSAGE_QUEUE::Read_To(int my_to)
  127. {
  128.     MESSAGE *current, *previous = NULL, *my_message = NULL;
  129.     bool found = false;
  130.  
  131.     // search for matching to field
  132.     current = first_message;
  133.     while ( (current) && (! found) )
  134.     {
  135.        if ( current->to == my_to )
  136.           found = true;
  137.        else
  138.        {
  139.           previous = current;
  140.           current = (MESSAGE *) current->next;
  141.        }
  142.     }
  143.  
  144.     if (! found)
  145.         return NULL;
  146.  
  147.     // found match, create a copy and erase the original
  148.     my_message = (MESSAGE *) calloc( 1, sizeof(MESSAGE));
  149.     if (! my_message)
  150.         return NULL;
  151.  
  152.     my_message->text = (char *) calloc( strlen(current->text), sizeof(char));
  153.     if (! my_message->text)
  154.     {
  155.         free(my_message);
  156.         return NULL;
  157.     }
  158.  
  159.     my_message->to = current->to;
  160.     strcpy(my_message->text, current->text);
  161.     if (previous)
  162.        previous->next = current->next;
  163.     else
  164.        first_message = (MESSAGE *) current->next;
  165.  
  166.     if (last_message == current)
  167.         last_message = previous;
  168.  
  169.     free(current->text);
  170.     free(current);
  171.     return my_message;
  172. }
  173.  
  174.  
  175. // Erases the next message in the line without returning anything
  176. void MESSAGE_QUEUE::Erase()
  177. {
  178.    MESSAGE *next_in_line;
  179.  
  180.    if (first_message)
  181.    {
  182.       next_in_line = (MESSAGE *) first_message->next;
  183.       // clean up
  184.       if (first_message->text)
  185.       {
  186.          free(first_message->text);
  187.          first_message->text = NULL;
  188.       }
  189.       free(first_message);
  190.  
  191.       // see if we are at the end of the list
  192.       if (last_message == first_message)
  193.         last_message = next_in_line;
  194.  
  195.       first_message = next_in_line;
  196.    }
  197.  
  198. }
  199.  
  200.  
  201.  
  202. // This function erases all messages in the queue.
  203. void MESSAGE_QUEUE::Erase_All()
  204. {
  205.    MESSAGE *current, *coming_up;
  206.  
  207.    current = first_message;
  208.    while (current)
  209.    {
  210.        coming_up = (MESSAGE *) current->next;
  211.        if (current->text)
  212.           free(current->text);
  213.        free(current);
  214.        current = coming_up;
  215.    }
  216.  
  217.    first_message = last_message = NULL;
  218. }
  219.  
  220.  
  221.  
  222.  
  223.  
  224. //
  225. // Past this point we have socket functions.
  226. //
  227. //
  228. #ifdef NETWORK
  229.  
  230.  
  231. // Create a socket for listening. Returns a listening socket
  232. // on success or -1 on failure.
  233. int Setup_Server_Socket(int port)
  234. {
  235.    int listensocket;
  236.    struct sockaddr_in myaddr;
  237.    
  238.    listensocket = socket(AF_INET, SOCK_STREAM, 0);
  239.    myaddr.sin_port = htons(port);
  240.    myaddr.sin_addr.s_addr = INADDR_ANY;
  241.    if (bind(listensocket, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) 
  242.    {
  243.        printf("Bind failed: %s\n", strerror(errno));
  244.        return -1;
  245.    }
  246.    if (listen(listensocket, 5)) 
  247.    {
  248.        printf("Listen failed: %s\n", strerror(errno));
  249.        return -1;
  250.    }
  251.  
  252.    return listensocket;
  253. }
  254.  
  255.  
  256.  
  257.  
  258. // Connect to a remote server. Returns -1 on failure or
  259. // a socket (int) on success.
  260. int Setup_Client_Socket(char *server_name, char *port)
  261. {
  262.    int socket_num, port_number;
  263.    struct sockaddr_in server_address;
  264.    struct hostent *server;
  265.  
  266.    sscanf(port, "%d", &port_number);
  267.    socket_num = socket(AF_INET, SOCK_STREAM, 0);
  268.    if (socket_num < 0)
  269.       return -1;
  270.    server = gethostbyname(server_name);
  271.    if (! server)
  272.       return -1;
  273.    bzero((char *) &server_address, sizeof(server_address));
  274.    server_address.sin_family = AF_INET;
  275.    bcopy((char *) server->h_addr,
  276.          (char *) &server_address.sin_addr.s_addr,
  277.          server->h_length);
  278.    server_address.sin_port = htons(port_number);
  279.  
  280.    // try to connect
  281.    if ( connect(socket_num, (sockaddr *)&server_address, sizeof(server_address)) < 0)
  282.        return -1;
  283.  
  284.    return socket_num;
  285. }
  286.  
  287.  
  288.  
  289. // Accepts an incoming connection request. Returns the
  290. // new socket connection on success or -1 on failure.
  291. int Accept_Incoming_Connection(int my_socket)
  292. {
  293.    int new_connection;
  294.    socklen_t my_length;
  295.    struct sockaddr new_address;
  296.  
  297.    my_length = sizeof(new_address);
  298.    new_connection = accept(my_socket, (struct sockaddr *) &new_address, &my_length);
  299.    return new_connection;
  300. }
  301.  
  302.  
  303.  
  304. // Take whatever is in the message and send it
  305. // to a socket.
  306. // Returns a negative number on failure. Zero and
  307. // positive numbers indicate success.
  308. int Send_Message(MESSAGE *mess, int to_socket)
  309. {
  310.     int status;
  311.     char buffer[MAX_MESSAGE_LENGTH];
  312.  
  313.     strncpy(buffer, mess->text, MAX_MESSAGE_LENGTH);
  314.     buffer[MAX_MESSAGE_LENGTH - 1] = '\0';
  315.     status = write(to_socket, buffer, strlen(buffer) );
  316.     return status;
  317. }
  318.  
  319.  
  320.  
  321. // Read data from a socket and put it in a message
  322. // Returns the message on success and NULL on failure.
  323. // Note: the "to" field of the message is not set.
  324. MESSAGE *Receive_Message(int from_socket)
  325. {
  326.   MESSAGE *my_message;
  327.   int bytes_read;
  328.   char buffer[MAX_MESSAGE_LENGTH];
  329.  
  330.   my_message = (MESSAGE *) calloc( 1, sizeof(MESSAGE) );
  331.   if (! my_message)
  332.      return NULL;
  333.  
  334.   memset(buffer, '\0', MAX_MESSAGE_LENGTH);
  335.   bytes_read = read(from_socket, buffer, MAX_MESSAGE_LENGTH);
  336.   if (bytes_read > 0)
  337.   {
  338.      buffer[MAX_MESSAGE_LENGTH - 1] = '\0';
  339.      my_message->text = (char *) calloc( strlen(buffer), sizeof(char) );
  340.      if (! my_message->text)
  341.      {
  342.          free(my_message);
  343.          return NULL;
  344.      }
  345.      strcpy(my_message->text, buffer);
  346.      return my_message;
  347.   }
  348.   else   // error while reading
  349.   {
  350.       free(my_message);
  351.       return NULL;
  352.   }
  353.  
  354. }
  355.  
  356.  
  357.  
  358. void Clean_Up_Server_Socket(int my_socket)
  359. {
  360.    close(my_socket);
  361. }
  362.  
  363.  
  364. void Clean_Up_Client_Socket(int my_socket)
  365. {
  366.    close(my_socket);
  367. }
  368.  
  369.  
  370.  
  371. // This function checks the socket to see if there is data ready to
  372. // be read. If there is data ready, then the function returns TRUE. If
  373. // an error occures, the function returns -1. If there is no data
  374. // and no error, the function returns FALSE.
  375. int Check_For_Incoming_Data(int socket_number)
  376. {
  377.    fd_set rfds;
  378.    struct timeval tv;
  379.    int retval;
  380.  
  381.    FD_ZERO(&rfds);
  382.    FD_SET(socket_number, &rfds);
  383.  
  384.    tv.tv_sec = 0;
  385.    tv.tv_usec = 0;
  386.  
  387.    retval = select(socket_number + 1, &rfds, NULL, NULL, &tv);
  388.  
  389.    if (retval == -1)
  390.        return -1;
  391.  
  392.    else if (retval)
  393.        return TRUE;
  394.  
  395.    else
  396.        return FALSE;
  397.  
  398.     return TRUE;
  399. }
  400.  
  401.  
  402.  
  403.  
  404. // This function checks the passed socket for errors. If the socket
  405. // is error-free, the function returns FALSE. If an exception
  406. // has occured, the function returns TRUE.
  407. int Check_For_Errors(int socket_number)
  408. {
  409.     fd_set exds;
  410.     struct timeval tv;
  411.     int expval;
  412.  
  413.     FD_ZERO(&exds);
  414.     FD_SET(socket_number, &exds);
  415.     tv.tv_sec = 0;
  416.     tv.tv_usec = 0;
  417.  
  418.     expval = select(socket_number + 1, NULL, NULL, &exds, &tv);
  419.  
  420.     if (expval == -1)
  421.        return TRUE;
  422.     else if (expval)
  423.        return TRUE;
  424.     else
  425.        return FALSE;
  426. }
  427.  
  428.  
  429.  
  430.  
  431. // This function will probably be called as a separate thread at the
  432. // start of the game. It will set up a listening port, accept
  433. // incoming connections and manage them. That is, they will be
  434. // passed on to AI players. 
  435. void *Send_And_Receive(void *all_the_data)
  436. {
  437.    SEND_RECEIVE_TYPE *send_receive_data = (SEND_RECEIVE_TYPE *) all_the_data;
  438.    int server_socket, new_socket;
  439.    int status, counter;
  440.    GLOBALDATA *global = (GLOBALDATA *) send_receive_data->global;
  441.    bool found;
  442.  
  443.    // set up listening socket
  444.    server_socket = Setup_Server_Socket(send_receive_data->listening_port);
  445.    if (server_socket == -1)
  446.    {
  447.       printf("Error creating listening socket.\n");
  448.       pthread_exit(NULL);
  449.    }
  450.  
  451.    while (! send_receive_data->shut_down)
  452.    {
  453.       // check for incoming connections
  454.       status = Check_For_Incoming_Data(server_socket);
  455.       if (status)
  456.       {
  457.          new_socket = Accept_Incoming_Connection(server_socket);
  458.          printf("Accepted connection.\n");
  459.          // give connection to AI player
  460.          found = false;
  461.          while ( (! found) && (counter < global->numPlayers) )
  462.          {
  463.               if ( ( global->players[counter]->type >= USELESS_PLAYER) &&
  464.                    ( global->players[counter]->type <= DEADLY_PLAYER) )
  465.               {
  466.                   found = true;
  467.                   global->players[counter]->server_socket = new_socket;
  468.                   global->players[counter]->previous_type = global->players[counter]->type;
  469.                   global->players[counter]->type = NETWORK_CLIENT;
  470.                   printf("Assigned connection to %s\n", global->players[counter]->getName() );
  471.               }
  472.               else
  473.                  counter++;
  474.          }
  475.          // in case we did not find a match
  476.          if (! found)
  477.          {
  478.             printf("Unable to assign new connection to player.\n");
  479.             write(new_socket, "NOROOM", strlen("NOROOM") );
  480.             close(new_socket);
  481.          }
  482.       }
  483.      
  484.       // consider resting for a moment?
  485.       usleep(10000);
  486.    }
  487.  
  488.    // clean up everything
  489.    printf("Cleaning up networking\n");
  490.    Clean_Up_Server_Socket(server_socket);
  491.    counter = 0;
  492.    while (counter < global->numPlayers)
  493.    {
  494.       if (global->players[counter]->type == NETWORK_CLIENT)
  495.       {
  496.           write(global->players[counter]->server_socket, "CLOSE", strlen("CLOSE") );
  497.           close(global->players[counter]->server_socket);
  498.       }
  499.       counter++;
  500.    }
  501.  
  502.    pthread_exit(NULL);
  503. }
  504.  
  505.  
  506. #endif
  507.  
  508.  
  509.  
  510.