Logo Search packages:      
Sourcecode: gtkatlantic version File versions  Download package

client.c

/*
 *     gtkatlantic - the gtk+ monopd client, enjoy network monopoly games
 *
 *
 *  Copyright (C) 2002-2004 Rochet Sylvain
 *
 *  gtkatlantic is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* ** functions for connect/disconnect server, receive/send data to/from server */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <netinet/in.h>

#include "config.h"
#include "xmlparse.h"
#include "global.h"
#include "client.h"
#include "game.h"


/* -- connect to server
     >
     > return false if:
     >   - max number of connection reached
     >   - can't resolve host
     >   - can't open port or socket
*/
gboolean client_connect(guint16 *idconnect, gchar* host, guint32 port)  {

      struct sockaddr_in addr;
      struct hostent *ent;
      struct in_addr in;
      gint32 addr_len, test;
      gpointer errormsg;
      gchar *text;
      guint16 idcon;
      guint32 sock;


      if( !connect_get_valid_id(&idcon) )  {

            errormsg = g_strdup("[ERROR] Max number of connections reached");
            text_insert_message(errormsg, strlen(errormsg));
            g_free(errormsg);
            return(FALSE);
      }

      /** resolve an address */
      if (!inet_aton(host, &in) ) {

            if (! (ent = gethostbyname(host)) )  {

                  errormsg = g_strdup_printf("[ERROR] Can't resolve host \"%s\"", host);
                  text_insert_message(errormsg, strlen(errormsg));
                  g_free(errormsg);
                  return(FALSE);

            }  else  {

                  in = *(struct in_addr *)ent->h_addr;
                  addr.sin_family = ent->h_addrtype;
            }
      }
      else  addr.sin_family = AF_INET;

      addr.sin_addr = in;
      addr.sin_port = htons(port);
      addr_len = sizeof(addr);

      /* -- now host is resolved, continue connection */
      sock = socket(addr.sin_family, SOCK_STREAM, IPPROTO_IP);
            // see /usr/include/netinet/in.h for IPPROTO_x

      test = connect(sock, (struct sockaddr*) &addr, addr_len);

      if(test < 0) {

            errormsg = g_strdup_printf("[ERROR] Host \"%s\" resolved but can't open port \"%d\" or socket", host, port);
            text_insert_message(errormsg, strlen(errormsg));
            g_free(errormsg);
            return(FALSE);
      }

      /* -- connection established :), finishing it */
      connection[idcon] = g_malloc0(sizeof (_connect) );
      connection_is_open[idcon] = TRUE;

      connection[idcon]->socket = sock;
      connection[idcon]->host = g_strdup(host);
      connection[idcon]->port = port;
      connection[idcon]->connected = TRUE;
      *idconnect = idcon;

      text = g_strdup_printf("[CONNECT %d] connected on \"%s:%d\", use socket %d", idcon, host, port, sock);
      text_insert_message(text, strlen(text));
      g_free(text);

      return(TRUE);
}


/* -- close the connection */
gboolean client_disconnect(guint32 idconnect)  {

      gpointer errormsg;
      gchar *text;

      if(!connection_is_open[idconnect])   return(FALSE);
      if(!connection[idconnect]->connected)   return(FALSE);

      shutdown (connection[idconnect]->socket, 2);

      if(close(connection[idconnect]->socket))  {

            errormsg = g_strdup_printf("[ERROR] Connection \"%d\" : can't close socket", idconnect);
            text_insert_message(errormsg, strlen(errormsg));
            g_free(errormsg);
            return(FALSE);
      }

      text = g_strdup_printf("[CONNECT %d] socket %d closed", idconnect, connection[idconnect]->socket);
      text_insert_message(text, strlen(text));
      g_free(text);

      if(connection[idconnect]->buffer_in)
            g_free(connection[idconnect]->buffer_in);

      g_free(connection[idconnect]->host);
      g_free(connection[idconnect]->server_version);

      g_free( connection[idconnect] );
      connection_is_open[idconnect] = FALSE;

      return(TRUE);
}


/* -- exec all client fonctions, for all games */
gboolean client_fonct()  {

      gint32 i, max_desc = 0;
      fd_set readfs;
      struct timeval tv;

      tv.tv_sec = 0;
      tv.tv_usec = 0;

      FD_ZERO(&readfs);

      for(i = 0 ; i < MAX_CONNECTION ; i++) {

            if(!connection_is_open[i])  continue;
            if(!connection[i]->connected)  continue;

            FD_SET(connection[i]->socket, &readfs);

            if(connection[i]->socket > max_desc)
                  max_desc = connection[i]->socket;
      }

      if(select(max_desc+1, &readfs, NULL, NULL, &tv) == 0)
            return TRUE;

      else {

            for(i = 0 ; i < MAX_CONNECTION ; i++)   {

                  if(!connection_is_open[i])  continue;
                  if(!connection[i]->connected)  continue;

                  if(FD_ISSET(connection[i]->socket, &readfs)) {

                        if(! client_recv(i) )
                              client_disconnect(i);
                  }
            }
      }

      return TRUE;
}


/* -- receive data from server */
gint32 client_recv(gint32 id)
{
      guchar *data, *buffer = 0, *buffer2, *tmp;
      gint32 len, sock, i;

      if(!connection_is_open[id])  return(FALSE);
      if(!connection[id]->connected)  return(FALSE);

      sock = connection[id]->socket;

      /* get data from server */
      data = g_malloc0(GETDATA_STEP +SECURITY_SIZE);
      do  {

            len = read(sock, data, GETDATA_STEP);

            data[len] = '\0';

            if(len <= 0)  {
                  g_free(data);
                  return 0;
            }

            /* concatenate with previous data */
            if(!buffer)  buffer = g_strdup(data);
            else  {
                  tmp = buffer;
                  buffer = g_strconcat(buffer, data, NULL);
                  g_free(tmp);
            }

      }  while(len == GETDATA_STEP);
      g_free(data);

      /* improve string */
      for(i = 0, len = strlen(buffer); i < len ; i++)  {

            /* remove nasty CR */
            if(buffer[i] == 13)  buffer[i] = ' ';
      }

      /* concatenate data */
      if(connection[id]->buffer_in)  {

            tmp = buffer;
            buffer = g_strconcat(connection[id]->buffer_in, tmp, NULL);
            g_free(connection[id]->buffer_in);
            g_free(tmp);
            connection[id]->buffer_in = 0;
      }

      /* parse data */
      for(i = 0, buffer2 = buffer, len = strlen(buffer2); i < len; i++)  {

            if( buffer2[i] == '\n' )  {

                  i++;

                  tmp = g_strndup(buffer2, i);
#if DEBUG
                  fprintf(stdout, "\033[32mID(%.2d): GET(%.4d): [%s]\033[m\n", id, strlen(tmp), tmp);
#endif

                  switch(connection[id]->type)  {

                        case CONNECT_TYPE_MONOPD_GETGAME:
                              xmlparse_getgamelist_plugger(id, tmp);
                              break;
                        case CONNECT_TYPE_MONOPD_GAME:
                              xmlparse_game_plugger(id, tmp);
                              break;

                        case CONNECT_TYPE_META_GETLIST:
                        case CONNECT_TYPE_META_GETGAME:
                              xmlparse_metaserver(id, tmp);
                              break;
                  }

                  g_free(tmp);

                  buffer2 += i;
                  len = strlen(buffer2);
                  i = 0;
            }
      }

      /* store string can't be parsed (no LF) */
      if(strlen(buffer2) > 0)  connection[id]->buffer_in = g_strdup(buffer2);

      g_free(buffer);

      return 1;
}


/* -- send data to server
      >> get from send_tmp buffer
      >> flush send_tmp buffer */
gboolean client_send(guint32 id, gchar *data, guint32 lenght_data)  {

      guint32 t;
      gpointer errormsg;

      if(!connection_is_open[id])  return(TRUE);
      if(!connection[id]->connected)  return(TRUE);

      t = write(connection[id]->socket, data, lenght_data);

      if(t != lenght_data) {

            errormsg = g_strdup("[ERROR] Can't send data to server");
            text_insert_message(errormsg, strlen(errormsg));
            g_free(errormsg);
            return(FALSE);
      }

#if DEBUG
      fprintf(stdout, "\033[31mID(%.2d): SEND(%.4d): [%s]\033[m\n", id, lenght_data, data);
#endif

      return(TRUE);
}

Generated by  Doxygen 1.6.0   Back to index