/* * 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 #include #include #include #include #include #include #include #include #include #include #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); }