/********************************************************************/ /* */ /* L I QQ U U I DD W W A RR 555 */ /* L I Q Q U U I D D W W A A R R 5 */ /* L I Q Q U U I D D W W W AAA RR 55 */ /* L I Q Q U U I D D WW WW A A R R 5 */ /* LLL I Q Q U I DD W W A A R R 55 */ /* */ /* b */ /* bb y y */ /* b b yyy */ /* bb y */ /* yy */ /* */ /* U U FFF O O TTT */ /* U U F O O O O T */ /* U U TIRET FF O O O O T */ /* U U F O O O O T */ /* U F O O T */ /* */ /********************************************************************/ /*****************************************************************************/ /* Liquid War is a multiplayer wargame */ /* Copyright (C) 1998-2007 Christian Mauduit */ /* */ /* This program 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* */ /* Liquid War homepage : http://www.ufoot.org/liquidwar/v5 */ /* Contact author : ufoot@ufoot.org */ /*****************************************************************************/ /********************************************************************/ /* name : srvchan.c */ /* content : handles a server network channel */ /* date de modif : 3 mai 98 */ /********************************************************************/ /*==================================================================*/ /* includes */ /*==================================================================*/ #include #include #include #include "srvchan.h" #include "netmess.h" #include "log.h" #include "netmap.h" #include "netconf.h" #include "sock2gen.h" #include "macro.h" /*==================================================================*/ /* Constants */ /*==================================================================*/ /*==================================================================*/ /* static functions */ /*==================================================================*/ static void reset (LW_SRVCHAN * chan); static int handle_team (LW_SRVCHAN * chan, LW_NETMESS * mess, int *free_teams); static int handle_ready (LW_SRVCHAN * chan, LW_NETMESS * mess); static int handle_start (LW_SRVCHAN * chan, LW_NETMESS * mess); static int handle_waiting (LW_SRVCHAN * chan, LW_NETMESS * mess, int free_teams); static int handle_next (LW_SRVCHAN * chan, LW_NETMESS * mess, int *next); static int handle_teamstartinfo (LW_SRVCHAN * chan, LW_NETMESS * mess, LW_TEAMSTARTINFO * team_start_info); static int handle_chattalk (LW_SRVCHAN * chan, LW_NETMESS * mess, LW_CHAT_HISTORY * chat); static int handle_chatlisten (LW_SRVCHAN * chan, LW_NETMESS * mess); static int handle_who (LW_SRVCHAN * chan, LW_NETMESS * mess); static int handle_sendmap (LW_SRVCHAN * chan, LW_NETMESS * mess, void **map); static int handle_recvmap (LW_SRVCHAN * chan, LW_NETMESS * mess, void *map); static int handle_sendconfig (LW_SRVCHAN * chan, LW_NETMESS * mess, LW_NETCONF * config); static int handle_recvconfig (LW_SRVCHAN * chan, LW_NETMESS * mess, LW_NETCONF * config); /*------------------------------------------------------------------*/ /* * Resets the LW_SRVCHAN struct */ static void reset (LW_SRVCHAN * chan) { int i; memset (chan, 0, sizeof (LW_SRVCHAN)); chan->sock = -1; chan->ip[0] = '\0'; chan->port = 0; chan->program_ok = 0; chan->version_ok = 0; chan->password_ok = 0; chan->ready_ok = 0; chan->start = 0; chan->map = NULL; memset (&(chan->config), 0, sizeof (LW_NETCONF)); for (i = 0; i < NB_TEAMS; ++i) { lw_srvteam_reset (&(chan->team[i])); } lw_chat_reset (&(chan->chat)); chan->checksum_recv = 0; chan->checksum_send = 0; chan->normal_quit = 0; } /*------------------------------------------------------------------*/ /* * handles the "PING" message */ int lw_srvchan_handle_ping (int sock, LW_NETMESS * mess) { int result = 0; LW_MACRO_NOP (mess); /* * It's a ping, we answer OK everytime */ lw_sock_send_str (&sock, LW_NETMESS_TEXT_OK); result = 1; return result; } /*------------------------------------------------------------------*/ /* * handles the "ECHO" message */ int lw_srvchan_handle_echo (int sock, LW_NETMESS * mess) { int result = 0; char answer[LW_SOCK_MESSAGE_SIZE]; int i; /* * echo, we rebuild the original message * from the information we have in the LW_NETMESS * struct, and resend it to the client */ LW_MACRO_STRCPY (answer, LW_NETMESS_TEXT_ECHO); i = 0; while (i < mess->argc) { if (i == 0) { LW_MACRO_STRCAT (answer, " "); } else { LW_MACRO_STRCAT (answer, ","); } LW_MACRO_STRCAT (answer, mess->argv[i]); i++; } lw_sock_send_str (&sock, answer); result = 1; return result; } /*------------------------------------------------------------------*/ /* * handles the "PROGRAM" message */ int lw_srvchan_handle_program (int sock, LW_NETMESS * mess, int *ok) { int result = 0; if (mess->argc == 1) { /* * OK, there's an argument, we check if it's the good prog name. * This prevents form accepting random connections: if the client * is not really a liquidwar client, it will be thrown away */ if (strcmp (mess->argv[0], LW_PROGRAM) == 0) { (*ok) = 1; result = 1; } } /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&sock, LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&sock, LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "VERSION" message */ int lw_srvchan_handle_version (int sock, LW_NETMESS * mess, int *ok) { int result = 0; if (mess->argc == 1) { /* * OK, there's an argument, we check if it's the good version. * This prevents form accepting random connections: if the client * is not a liquidwar client with the right version number, it will * be thrown away... */ if (strcmp (mess->argv[0], LW_VERSION) == 0) { (*ok) = 1; result = 1; } } /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&sock, LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&sock, LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "PASSWORD" message */ int lw_srvchan_handle_password (int sock, LW_NETMESS * mess, int *ok, char *password) { int result = 0; switch (mess->argc) { case 1: /* * OK, there's an argument, we check if it's the good password. */ if (strncmp (mess->argv[0], password, PASSWORD_SIZE) == 0) { (*ok) = 1; result = 1; } break; } if (!strcmp (password, "")) { /* * OK, now the server's password is "", so we consider any * that any password from the client is OK. */ (*ok) = 1; result = 1; } /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&sock, LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&sock, LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "FREE" message */ int lw_srvchan_handle_free (int sock, LW_NETMESS * mess, int free_teams, int *ok) { int result = 0; char answer[LW_SOCK_MESSAGE_SIZE]; LW_MACRO_NOP (mess); LW_MACRO_SPRINTF2 (answer, "%s %d", LW_NETMESS_TEXT_OK, free_teams); lw_sock_send_str (&sock, answer); (*ok) = 1; result = 1; return result; } /*------------------------------------------------------------------*/ /* * handles the "TEAM" message */ static int handle_team (LW_SRVCHAN * chan, LW_NETMESS * mess, int *free_teams) { int result = 0; int i; if (mess->argc == 3) { /* * OK, there are 3 arguments * - arg 1 is the team index * - arg 2 is the "control_type" parameter * - arg 3 is the team name */ i = atoi (mess->argv[0]); if (i >= 0 && i < NB_TEAMS) { if (!chan->team[i].active) { /* * The message from the client makes sense, we * return OK */ result = 1; /* * Now we activate the team only if there's still * room. If not we still return OK but the "WHO" * message will later inform the client that some * of his requests have been cancelled... */ if ((*free_teams) > 0) { (*free_teams)--; chan->team[i].active = 1; chan->team[i].control_type = atoi (mess->argv[1]); strncpy (chan->team[i].name, mess->argv[2], NAME_SIZE); chan->team[i].name[NAME_SIZE] = '\0'; log_print_str ("Team \""); log_print_str (mess->argv[2]); log_print_str ("\" on client \""); log_print_str (chan->ip); log_print_str (":"); log_print_int (chan->port); log_println_str ("\" accepted"); } else { log_print_str ("Team \""); log_print_str (mess->argv[2]); log_print_str ("\" on client \""); log_print_str (chan->ip); log_print_str (":"); log_print_int (chan->port); log_println_str ("\" refused!"); } } } } /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "WHO" message */ static int handle_who (LW_SRVCHAN * chan, LW_NETMESS * mess) { int result = 0; int i; char answer[LW_SOCK_MESSAGE_SIZE]; if (mess->argc == 1) { /* * OK, there's an argument, we interpret it as a number */ i = atoi (mess->argv[0]); if (i >= 0 && i < NB_TEAMS) { LW_MACRO_SPRINTF1 (answer, "%s", LW_NETMESS_TEXT_ERR); if (chan->team[i].active) { if (chan->team[i].network) { LW_MACRO_SPRINTF4 (answer, "%s %d,%d,'%s'", LW_NETMESS_TEXT_NETWORK, chan->team[i].server_id, chan->team[i].control_type, chan->team[i].name); } else { LW_MACRO_SPRINTF4 (answer, "%s %d,%d,'%s'", LW_NETMESS_TEXT_LOCAL, chan->team[i].server_id, chan->team[i].control_type, chan->team[i].name); } } else { LW_MACRO_SPRINTF1 (answer, "%s", LW_NETMESS_TEXT_NOBODY); } lw_sock_send_str (&(chan->sock), answer); result = 1; } } /* * Now we send feedback on the network */ if (!result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "READY" message */ static int handle_ready (LW_SRVCHAN * chan, LW_NETMESS * mess) { int result = 0; LW_MACRO_NOP (mess); /* * Here we do not return "OK" yet. In fact we will return * "OK" on the network later, when all the clients will be * connected, this way the "OK" answer to the "READY" message * is the signal for game start */ chan->ready_ok = 1; result = 1; return result; } /*------------------------------------------------------------------*/ /* * handles the "START" message */ static int handle_start (LW_SRVCHAN * chan, LW_NETMESS * mess) { int result = 0; LW_MACRO_NOP (mess); /* * Here we just acknowledge the fact that the client required * the game to start right away */ chan->start = 1; result = 1; /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "WAITING" message */ static int handle_waiting (LW_SRVCHAN * chan, LW_NETMESS * mess, int free_teams) { int result = 0; char answer[LW_SOCK_MESSAGE_SIZE]; LW_MACRO_NOP (mess); /* * Here we answer the client the number of free teams */ result = 1; LW_MACRO_SPRINTF2 (answer, "%s %d", LW_NETMESS_TEXT_OK, free_teams); /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&(chan->sock), answer); } else { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "NEXT" message */ static int handle_next (LW_SRVCHAN * chan, LW_NETMESS * mess, int *next) { int result = 0; LW_MACRO_NOP (chan); LW_MACRO_NOP (mess); /* * Here we do not return "OK" yet. * The point is that the "NEXT" message is like the "READY" * message, it gets an answer when the server decides to * talk to the client again. */ (*next) = 1; result = 1; return result; } /*------------------------------------------------------------------*/ /* * handles the "TEAMSTARTINFO" message */ static int handle_teamstartinfo (LW_SRVCHAN * chan, LW_NETMESS * mess, LW_TEAMSTARTINFO * team_start_info) { int result = 0; int i; char answer[LW_SOCK_MESSAGE_SIZE]; if (mess->argc == 1) { /* * OK, there's an argument, we interpret it as a number */ i = atoi (mess->argv[0]); if (i >= 0 && i < NB_TEAMS) { LW_MACRO_SPRINTF4 (answer, "%s %d,%d,'%s'", LW_NETMESS_TEXT_OK, team_start_info[i].active, team_start_info[i].start, team_start_info[i].name); lw_sock_send_str (&(chan->sock), answer); result = 1; } } /* * Now we send feedback on the network */ if (!result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "CHATTALK" message */ static int handle_chattalk (LW_SRVCHAN * chan, LW_NETMESS * mess, LW_CHAT_HISTORY * chat) { int result = 0; if (mess->argc == 1) { /* * OK, there's an argument, we interpret it as a message. * Note that we push the message in a common chat history * struct, to share it with others. */ log_print_str ("Client \""); log_print_str (chan->ip); log_print_str (":"); log_print_int (chan->port); log_print_str ("\" says \""); log_print_str (mess->argv[0]); log_println_str ("\""); lw_chat_push (chat, chan->team[0].name, mess->argv[0]); result = 1; } /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "CHATLISTEN" message */ static int handle_chatlisten (LW_SRVCHAN * chan, LW_NETMESS * mess) { int result = 0; char answer[LW_SOCK_MESSAGE_SIZE]; LW_CHAT_MESSAGE message; if (mess->argc == 0) { if (lw_chat_pop (&(chan->chat), &message)) { /* * OK, there's a message in the queue, we send it */ LW_MACRO_SPRINTF3 (answer, "%s '%s','%s'", LW_NETMESS_TEXT_OK, message.author, message.content); } else { LW_MACRO_SPRINTF0 (answer, LW_NETMESS_TEXT_OK); } lw_sock_send_str (&(chan->sock), answer); result = 1; } /* * Send error message if needed */ if (!result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "SENDMAP" message */ static int handle_sendmap (LW_SRVCHAN * chan, LW_NETMESS * mess, void **map) { int result = 0; LW_MACRO_NOP (mess); result = lw_netmap_recv (&(chan->sock), map); /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "RECVMAP" message */ static int handle_recvmap (LW_SRVCHAN * chan, LW_NETMESS * mess, void *map) { int result = 0; LW_MACRO_NOP (mess); result = lw_netmap_send (&(chan->sock), map); /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "SENDCONFIG" message */ static int handle_sendconfig (LW_SRVCHAN * chan, LW_NETMESS * mess, LW_NETCONF * config) { int result = 0; LW_MACRO_NOP (mess); result = lw_netconf_recv (&(chan->sock), config); /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "RECVCONFIG" message */ static int handle_recvconfig (LW_SRVCHAN * chan, LW_NETMESS * mess, LW_NETCONF * config) { int result = 0; LW_MACRO_NOP (mess); result = lw_netconf_send (&(chan->sock), config); /* * Now we send feedback on the network */ if (result) { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK); } else { lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } return result; } /*------------------------------------------------------------------*/ /* * handles the "QUIT" message */ int lw_srvchan_handle_quit (int sock, LW_NETMESS * mess, int *normal_quit) { int result = 0; LW_MACRO_NOP (sock); LW_MACRO_NOP (mess); /* * We flag the client as having quitted the server "normally". * This allow calling functions to make the difference between * a client that decided to leave on purpose from a client * that was disconnected because of lag or something. */ (*normal_quit) = 1; /* * Here we do nothing and simply return an error, this will * cause the system to close the socket automatically... */ result = -1; return result; } /*------------------------------------------------------------------*/ /* * handles an unknown message */ int lw_srvchan_handle_unknown (int sock, LW_NETMESS * mess) { int result = 0; LW_MACRO_NOP (mess); /* * We answer ERR all the time */ lw_sock_send_str (&sock, LW_NETMESS_TEXT_ERR); /* * Since we return 0, the connection will be closed... */ return result; } /*==================================================================*/ /* global functions */ /*==================================================================*/ /*------------------------------------------------------------------*/ /* * Waits for a client to connect, returns 1 if successfull, 0 if not */ int lw_srvchan_wait_teams (LW_SRVCHAN * chan, int *free_teams, int sock, void **map, LW_NETCONF * config, char *password) { int result = 0; int ret; int ret_mess = 1; char message[LW_SOCK_MESSAGE_SIZE]; LW_NETMESS *mess; int free_received = 0; reset (chan); if (lw_sock_accept (&(chan->sock), chan->ip, &(chan->port), sock, 1)) { log_print_str ("Connection from \""); log_print_str (chan->ip); log_print_str (":"); log_print_int (chan->port); log_print_str ("\""); log_println (); log_flush (); while ((!chan->ready_ok) && ret_mess && ((ret = lw_sock_recv_str (&(chan->sock), message)) >= 0)) { if (ret > 0) { mess = lw_netmess_read (message); if (mess != NULL) { /* * switch to handle the different possible messages */ switch (mess->code) { case LW_NETMESS_CODE_PING: ret_mess = lw_srvchan_handle_ping (chan->sock, mess); break; case LW_NETMESS_CODE_ECHO: ret_mess = lw_srvchan_handle_echo (chan->sock, mess); break; case LW_NETMESS_CODE_PROGRAM: ret_mess = lw_srvchan_handle_program (chan->sock, mess, &(chan-> program_ok)); break; case LW_NETMESS_CODE_VERSION: ret_mess = lw_srvchan_handle_version (chan->sock, mess, &(chan-> version_ok)); break; case LW_NETMESS_CODE_PASSWORD: ret_mess = lw_srvchan_handle_password (chan->sock, mess, &(chan-> password_ok), password); break; case LW_NETMESS_CODE_FREE: ret_mess = lw_srvchan_handle_free (chan->sock, mess, *free_teams, &free_received); break; case LW_NETMESS_CODE_TEAM: ret_mess = handle_team (chan, mess, free_teams); break; case LW_NETMESS_CODE_READY: ret_mess = handle_ready (chan, mess); break; case LW_NETMESS_CODE_SENDMAP: ret_mess = handle_sendmap (chan, mess, map); break; case LW_NETMESS_CODE_SENDCONFIG: ret_mess = handle_sendconfig (chan, mess, config); break; case LW_NETMESS_CODE_QUIT: ret_mess = lw_srvchan_handle_quit (chan->sock, mess, &(chan-> normal_quit)); break; default: ret_mess = lw_srvchan_handle_unknown (sock, mess); break; } /* * lw_netmess_free must *not* be forgetted */ lw_netmess_free (mess); if (!ret_mess) { log_print_str ("Error processing \""); log_print_str (message); log_print_str ("\""); log_println (); } } else { log_println_str ("Serious memory problem 8-("); ret_mess = 0; } } } if (chan->program_ok && chan->version_ok && chan->password_ok && chan->ready_ok && ret_mess) { result = 1; log_print_str ("Client \""); log_print_str (chan->ip); log_print_str (":"); log_print_int (chan->port); log_println_str ("\" accepted"); /* * We play a little sound for people who have the server * opened on a console and want it to beep when someone * connects */ log_beep (); } else { if (chan->ready_ok) { /* * Now if we are here it means we have received a "READY" * message, but still the client did not send the correct * messages before => we send an "ERR" messageon the * network for consistency, since the client did not receive * any message to his "READY" query yet. */ lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } lw_sock_close (&(chan->sock)); log_print_str ("Client \""); log_print_str (chan->ip); log_print_str (":"); log_print_int (chan->port); if (chan->normal_quit) { log_println_str ("\" disconnected (probably a ping)"); } else { log_println_str ("\" rejected!"); } } } return result; } /*------------------------------------------------------------------*/ /* * Sends informations to the client on a regular basis, once it's * connected and waiting for the game to start */ int lw_srvchan_keepalive (LW_SRVCHAN * chan, int waited_teams, LW_TEAMSTARTINFO * team_start_info, LW_CHAT_HISTORY * chat) { int result = 0; int ret; int ret_mess = 1; char message[LW_SOCK_MESSAGE_SIZE]; LW_NETMESS *mess; int next = 0; /* * we set ready_ok back to false since we will wait for * another ready message */ chan->ready_ok = 0; /* * We first answer the "READY" message which had been sent by the * client a possibly long time ago. */ if (lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK)) { while ((!chan->ready_ok) && (!next) && ret_mess && ((ret = lw_sock_recv_str (&(chan->sock), message)) >= 0)) { if (ret > 0) { mess = lw_netmess_read (message); if (mess != NULL) { /* * switch to handle the different possible messages */ switch (mess->code) { case LW_NETMESS_CODE_PING: ret_mess = lw_srvchan_handle_ping (chan->sock, mess); break; case LW_NETMESS_CODE_ECHO: ret_mess = lw_srvchan_handle_echo (chan->sock, mess); break; case LW_NETMESS_CODE_START: ret_mess = handle_start (chan, mess); break; case LW_NETMESS_CODE_WAITING: ret_mess = handle_waiting (chan, mess, waited_teams); break; case LW_NETMESS_CODE_NEXT: ret_mess = handle_next (chan, mess, &next); break; case LW_NETMESS_CODE_TEAMSTARTINFO: ret_mess = handle_teamstartinfo (chan, mess, team_start_info); break; case LW_NETMESS_CODE_CHATTALK: ret_mess = handle_chattalk (chan, mess, chat); break; case LW_NETMESS_CODE_CHATLISTEN: ret_mess = handle_chatlisten (chan, mess); break; case LW_NETMESS_CODE_READY: ret_mess = handle_ready (chan, mess); break; case LW_NETMESS_CODE_QUIT: ret_mess = lw_srvchan_handle_quit (chan->sock, mess, &(chan-> normal_quit)); break; default: ret_mess = lw_srvchan_handle_unknown (chan->sock, mess); break; } /* * lw_netmess_free must *not* be forgetted */ lw_netmess_free (mess); if (!ret_mess) { log_print_str ("Error processing \""); log_print_str (message); log_print_str ("\""); log_println (); } } else { log_println_str ("Serious memory problem 8-("); ret_mess = 0; } } } if ((chan->ready_ok || next) && ret_mess) { result = 1; if (chan->ready_ok) { log_print_str ("Client \""); log_print_str (chan->ip); log_print_str (":"); log_print_int (chan->port); log_println_str ("\" ready"); } } else { if (chan->ready_ok || next) { /* * Now if we are here it means we have received a "READY" * message, but still the client did not send the correct * messages before => we send an "ERR" messageon the * network for consistency, since the client did not receive * any message to his "READY" query yet. */ lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } lw_sock_close (&(chan->sock)); //log_println_str("Player KO"); } } return result; } /*------------------------------------------------------------------*/ /* * Answers OK to a client, and waits for the "WHO" message */ int lw_srvchan_tell_who (LW_SRVCHAN * chan, void *map, LW_NETCONF * config) { int result = 0; int ret; int ret_mess = 1; char message[LW_SOCK_MESSAGE_SIZE]; LW_NETMESS *mess; log_print_str ("Sending info to \""); log_print_str (chan->ip); log_print_str (":"); log_print_int (chan->port); log_print_str ("\""); log_println (); /* * we set ready_ok back to false since we will wait for * another ready message */ chan->ready_ok = 0; /* * We first answer the "READY" message which had been sent by the * client a possibly long time ago. */ if (lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK)) { while ((!chan->ready_ok) && ret_mess && ((ret = lw_sock_recv_str (&(chan->sock), message)) >= 0)) { if (ret > 0) { mess = lw_netmess_read (message); if (mess != NULL) { /* * switch to handle the different possible messages */ switch (mess->code) { case LW_NETMESS_CODE_PING: ret_mess = lw_srvchan_handle_ping (chan->sock, mess); break; case LW_NETMESS_CODE_ECHO: ret_mess = lw_srvchan_handle_echo (chan->sock, mess); break; case LW_NETMESS_CODE_WHO: ret_mess = handle_who (chan, mess); break; case LW_NETMESS_CODE_READY: ret_mess = handle_ready (chan, mess); break; case LW_NETMESS_CODE_RECVMAP: ret_mess = handle_recvmap (chan, mess, map); break; case LW_NETMESS_CODE_RECVCONFIG: ret_mess = handle_recvconfig (chan, mess, config); break; default: ret_mess = lw_srvchan_handle_unknown (chan->sock, mess); break; } /* * lw_netmess_free must *not* be forgetted */ lw_netmess_free (mess); if (!ret_mess) { log_print_str ("Error processing \""); log_print_str (message); log_print_str ("\""); log_println (); } } else { log_println_str ("Serious memory problem 8-("); ret_mess = 0; } } } if (chan->ready_ok && ret_mess) { result = 1; // log_println_str("Player OK"); } else { if (chan->ready_ok) { /* * Now if we are here it means we have received a "READY" * message, but still the client did not send the correct * messages before => we send an "ERR" messageon the * network for consistency, since the client did not receive * any message to his "READY" query yet. */ lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_ERR); } lw_sock_close (&(chan->sock)); //log_println_str("Player KO"); } } return result; } /*------------------------------------------------------------------*/ /* * Sends the final "OK" message before streaming */ int lw_srvchan_final_ok (LW_SRVCHAN * chan) { int result = 0; if (lw_sock_send_str (&(chan->sock), LW_NETMESS_TEXT_OK)) { result = 1; } else { lw_sock_close (&(chan->sock)); } return result; } /*------------------------------------------------------------------*/ /* * Returns the index of the team associated to a given server team id */ int lw_srvchan_find_team_by_server_id (LW_SRVCHAN * chan, int server_id) { int result = -1; int i; for (i = 0; i < NB_TEAMS && result < 0; ++i) { if (chan->team[i].active && chan->team[i].server_id == server_id) { result = i; } } return result; } /*------------------------------------------------------------------*/ /* * Returns the index of the first inactive team */ int lw_srvchan_find_first_free_team (LW_SRVCHAN * chan) { int result = -1; int i; for (i = 0; i < NB_TEAMS && result < 0; ++i) { if (!(chan->team[i].active)) { result = i; } } return result; } /*------------------------------------------------------------------*/ /* * Closes everything and frees the resources */ void lw_srvchan_close (LW_SRVCHAN * chan) { lw_sock_close (&(chan->sock)); if (chan->map != NULL) { free (chan->map); chan->map = NULL; } reset (chan); } /*------------------------------------------------------------------*/ /* * Receives key presses from a computer. * The keys come in the "computer's order" ie one still has to * sort them by server id. */ int lw_srvchan_recv_keys (LW_SRVCHAN * chan, LW_NETKEY * netkey) { int result = 0; int i; LW_NETKEY chan_netkey; lw_netkey_reset (&chan_netkey); result = lw_netkey_recv (&(chan->sock), &chan_netkey); for (i = 0; i < NB_TEAMS; ++i) { if (chan->team[i].active && !chan->team[i].network) { netkey->key_states[chan->team[i].server_id] = chan_netkey.key_states[i]; } } netkey->cmd = chan_netkey.cmd; netkey->arg = chan_netkey.arg; chan->checksum_recv = chan_netkey.checksum; return result; } /*------------------------------------------------------------------*/ /* * Sends key presses to a computer. * The keys must be send in the "computer's order" ie they must * be sorted first. */ int lw_srvchan_send_keys (LW_SRVCHAN * chan, LW_NETKEY * netkey) { int result = 0; int i; LW_NETKEY chan_netkey; lw_netkey_reset (&chan_netkey); for (i = 0; i < NB_TEAMS; ++i) { if (chan->team[i].active) { chan_netkey.key_states[i] = netkey->key_states[chan->team[i].server_id]; } } chan_netkey.cmd = netkey->cmd; chan_netkey.arg = netkey->arg; chan_netkey.checksum = chan->checksum_send; result = lw_netkey_send (&(chan->sock), &chan_netkey); return result; }