Comments about this communication module

/*
Ol?.

There goes my complete communication module source code. ( ping.c )

It is my first work of this genre, and I’m not sure about the best
practices on it.
So, I would like to know the opinions about my way of SDL_Net use.

Any comment is welcome, even about style or logic. Anything! :wink:

Thank you

Obviously, if you like this code, you’re free to use.

Miguel Pragier
*/

#define PING_MAXSTRLEN 127 /* MaxLen for the messagens. Usually, the
messages have up to 10 characters. */

static struct _Ping
{
TCPsocket sckGeneral; /*
GenericUse Socket. /
SDLNet_SocketSet SocketSet; /
GenericUse SocketSet. */

   char Msg[PING_MAXSTRLEN+1];             /* StaticBuffer for

incoming data. /
char LogErrors;
/
(1) recording error messages or (0) Ignoring
error messages. */
} Ping;

static int Ping_Connect( void );
static void Ping_Say( const char* msg );
static void Ping_Listen( char* answer );
static void Ping_Clear( void );
static int Ping_ValidateConnection( void );
static void Ping_CorrectString( char* str, const int receivedBytes );
static void Ping_Disconnect( void );
static void Ping_Concat( char* destiny, const char* origin );

//////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/

/**
Prepare basic Ping structure and connect the server.
*/
void Ping_Load()
{
memset(&Ping, 0, sizeof Ping);

   if( !Ping_Connect() )
   {
           const Uint32 interval = 1000;   /* interval between

reconnection trials.*/
Uint32 nextTry = ( SDL_GetTicks() + interval );
SDL_Event event;

           LOG_WriteStr("%s", "Ping_Load(Turning auto-try on.)");

           MsgBox_Show(MSGBOX_NOCONNECTION);

           Ping.LogErrors = 0;

           for(;;)
           {
                   SDL_Delay(25);

                   if( SDL_PollEvent(&event) )
                   {
                           if( ( ( event.type == SDL_KEYDOWN ) &&

( event.key.keysym.sym ==
SDLK_ESCAPE ) ) || ( event.type == SDL_QUIT ) )
exit(0);
}

                   if( nextTry < SDL_GetTicks() )
                   {
                           if( Ping_Connect() )
                                   break;

                           nextTry = ( SDL_GetTicks() + interval );
                   }
           }

           LOG_WriteStr("%s", "Ping_Load(Connection Stablished).");

           Ping.LogErrors = 1;

           MsgBox_Hide(MSGBOX_NOCONNECTION);
   }

}

/**
Send a “question” to the server, wait a little moment and
receive the “answer”.
\param msg the question to send to the server.
\param answer the message received from the server.
/
void Ping_Ask( const char
msg, char* answer )
{
if( Ping_ValidateConnection() )
{
Ping_Clear();

           Ping_Say(msg);

           SDL_Delay(10);

           Ping_Listen(answer);
   }

   /* If there is no valid answer from server, */
   if( !answer || strlen(answer) == 0 )
   {
           SDL_Event event;

           /* Block the game with a MsgBox. */
           MsgBox_Show(MSGBOX_NOCONNECTION);

           Ping.LogErrors = 0;

           /* And send again the question, untill receive a valid answer. */
           do
           {
                   Ping_Disconnect();

                   while( !Ping_Connect() )
                   {
                           if( SDL_PollEvent(&event) )
                           {
                                   if( ( ( event.type ==

SDL_KEYDOWN ) && ( event.key.keysym.sym ==
SDLK_ESCAPE ) ) || ( event.type == SDL_QUIT ) )
exit(0);
}

                           SDL_Delay(25);
                   }

                   if( SDL_PollEvent(&event) )
                   {
                           if( ( ( event.type == SDL_KEYDOWN ) &&

( event.key.keysym.sym ==
SDLK_ESCAPE ) ) || ( event.type == SDL_QUIT ) )
exit(0);
}

                   Ping_Clear();
                   Ping_Say(msg);
                   Ping_Listen(answer);
                   SDL_Delay(10);
           }
           while( !answer || ( strlen(answer) == 0 ) );

           Ping.LogErrors = 1;

           MsgBox_Hide(MSGBOX_NOCONNECTION);
   }

}

/**
Send a “question” to the server, wait a little moment and
receive the “answer”.
\ Then compares the message received with the message desired, and
returns the result.
\param ask the question to send to the server.
\param desiredAnswer the message received from the server.
\param verbose if a different answer than the desired must be
registered in the LOG.
\return The comparsion result.
\sa Ping_Ask()
/
int Ping_Confirm( const char
ask, const char* desiredAnswer, const
int verbose )
{
char answer[PING_MAXSTRLEN+1];

   memset(answer, 0, sizeof answer);

   Ping_Ask(ask, answer);

   if( strncmp(desiredAnswer, answer, strlen(desiredAnswer)) == 0 )
           return 1;
   else
   {
           if( verbose == 1 )
           {
                   LOG_WriteStr("%s",

“#######################################################”);
LOG_WriteStr(“Ping_Confirm(Ask: %s);”, ask);
LOG_WriteStr(“Ping_Confirm(DesiredAnswer:
%s);”, desiredAnswer);
LOG_WriteStr(“Ping_Confirm(ReceivedAnswer:
%s);”, answer);
LOG_WriteStr("%s",
"#######################################################");
}

           return 0;
   }

}

/**
Send a message to the server, wait a little moment and clean the
socket, ignoring the received answer.
\param msg the message to send to the server.
/
void Ping_Tell( const char
msg )
{
if( Ping_ValidateConnection() )
{
Ping_Clear();
Ping_Say(msg);
SDL_Delay(100);
Ping_Clear();
return;
}

   LOG_WriteStr("Ping_Tell(%s)::Connection Lost.", msg);
   MsgBox_Show(MSGBOX_NOCONNECTION);
   Ping_Disconnect();
   Ping.LogErrors = 0;

   while( !Ping_Connect() )
           SDL_Delay(25);

   Ping.LogErrors = 1;
   Ping_Clear();
   Ping_Say(msg);
   SDL_Delay(100);
   Ping_Clear();
   MsgBox_Hide(MSGBOX_NOCONNECTION);

}

/**
Stablish a persistent connection with the server.
\return If the connection was successfuly maded.
*/
static int Ping_Connect()
{
IPaddress ip;

   if( SDLNet_ResolveHost(&ip, Config_Ping_IP(),

(Uint16)Config_Ping_Porta()) == 0 )
{
Ping.sckGeneral = SDLNet_TCP_Open(&ip);

           if( Ping.sckGeneral )
           {
                   Ping.SocketSet = SDLNet_AllocSocketSet(1);

                   if( Ping.SocketSet )
                   {
                           SDLNet_TCP_AddSocket(Ping.SocketSet,

Ping.sckGeneral);

                           SDL_Delay(500);

                           return 1;
                   }
                   else
                   {
                           SDLNet_TCP_Close(Ping.sckGeneral);

                           if( Ping.LogErrors )

LOG_WriteStr(“Ping_Connect(SDLNet_AllocSocketSet(%s))”,
SDLNet_GetError());
}
}
else
{
if( Ping.LogErrors )

LOG_WriteStr(“Ping_Connect(SDLNet_TCP_Open(%s))”, SDLNet_GetError());
}
}
else
{
if( Ping.LogErrors )

LOG_WriteStr(“Ping_Connect(SDLNet_ResolveHost(%s))”,
SDLNet_GetError());
}

   return 0;

}

/**
Send a message to the server.
\param msg the message to send to the server.
/
static void Ping_Say( const char
msg )
{
const int tam = (int)strlen(msg);
int i;

   memset(Ping.Msg, 0, sizeof Ping.Msg);

   sprintf(Ping.Msg, "%s\n", msg);

   for(i=0; i<tam; i++ )
           Ping.Msg[i] = (char)toupper(Ping.Msg[i]);

   SDLNet_TCP_Send(Ping.sckGeneral, Ping.Msg, (tam+1));

}

/**
Receive a message from the server.
\param answer the buffer to write the received message.
/
static void Ping_Listen( char
answer )
{
int r;
Uint32 tempo = ( SDL_GetTicks() + 1000 );

   memset(answer, 0, (PING_MAXSTRLEN+1));

   r = SDLNet_CheckSockets(Ping.SocketSet, 2000);

   if( r > 0 )
   {
           char str[PING_MAXSTRLEN+1];
           int receivedBytes;

           while( SDLNet_SocketReady(Ping.sckGeneral) )
           {
                   memset(str, 0, sizeof str);
                   receivedBytes =

SDLNet_TCP_Recv(Ping.sckGeneral, str, PING_MAXSTRLEN);
Ping_CorrectString(str, receivedBytes);
Ping_Concat(answer, str);

                   if( tempo < SDL_GetTicks() )
                   {
                           /* Something was wrong. Try immediatly

reconnect. */
LOG_WriteStr("%s",
“Ping_Listen(Reconnecting…)”);
Ping_Refresh();
return;
}
}
}
}

/**
Clean the socket, if there’s garbage.
*/
static void Ping_Clear()
{
if( !SDLNet_CheckSockets(Ping.SocketSet,0) )
return;
else
{
int vezes = 0;
char lixo[PING_MAXSTRLEN+1];

           while( (int)SDLNet_SocketReady( Ping.sckGeneral ) > 0 )
           {
                   memset(lixo, 0, sizeof lixo);
                   SDLNet_TCP_Recv(Ping.sckGeneral, lixo, PING_MAXSTRLEN);

                   if( (++vezes) == 3 )
                   {
                           /* Something was wrong. Try immediatly

reconnect. */
LOG_WriteStr("%s",
“Ping_Clear(SDLNet_TCP_Recv(ERRO: Reconnecting.))”);
Ping_Refresh();
return;
}
}
}
}

/**
Check the connection components.
\return The test results.
*/
static int Ping_ValidateConnection()
{
if( !Ping.SocketSet )
{
LOG_WriteStr("%s", “Ping_ValidateConnection(SocketSet
Invalido.”);
return 0;
}
else
{
int r = SDLNet_CheckSockets(Ping.SocketSet, 0);

           if( r < 0 )
           {

LOG_WriteStr(“Ping_ValidateConnection(SDLNet_CheckSockets(%s))”,
SDLNet_GetError());
return 0;
}

           r = SDLNet_SocketReady(Ping.sckGeneral);

           if( r < 0 )
           {

LOG_WriteStr(“Ping_ValidateConnection(SDLNet_SocketReady(%s))”,
SDLNet_GetError());
return 0;
}
else if( r > 0 ) /* In case we’ve found garbage data in
the socket. */
{
int vezes = 0;

                   do
                   {
                           r = SDLNet_TCP_Recv(Ping.sckGeneral,

Ping.Msg, PING_MAXSTRLEN);

                           if( r <= 0 )
                           {

LOG_WriteStr(“Ping_ValidateConnection(SDLNet_TCP_Recv(%s))”,
SDLNet_GetError());
return 0;
}

                           SDL_Delay(25);
                           r = SDLNet_SocketReady(Ping.sckGeneral);

LOG_WriteStr(“Ping_ValidateConnection(SDLNet_TCP_Recv(%s))”,
Ping.Msg);

                           if( (++vezes) == 3 )
                           {
                                   /* Something was wrong. Try

immediatly reconnect. */
LOG_WriteStr("%s",
“Ping_ValidateConnection(SDLNet_TCP_Recv(ERRO:
Reconnecting.))”);
Ping_Refresh();
return 1;
}
}
while( r > 0 ) ;
}
}

   return 1;

}

/**
Disconnect and reconnect, to refresh all the socket components.
*/
void Ping_Refresh()
{
Ping_Disconnect();
Ping_Connect();
}

/**
Takes a string and validate each character.
\param str destination buffer for the sane string.
\param receivedBytes data to be checked and filtered.
/
static void Ping_CorrectString( char
str, const int receivedBytes )
{
int i;

   if( receivedBytes > PING_MAXSTRLEN )
           str[PING_MAXSTRLEN] = '\0';

   for( i=0; i<receivedBytes; i++ )
   {
           if( !Between(str[i], 9, 125) )
                   str[i] = '\0';
   }

}

/**
Close the connection and free the components.
*/
static void Ping_Disconnect()
{
SDLNet_TCP_DelSocket(Ping.SocketSet, Ping.sckGeneral);
SDLNet_FreeSocketSet(Ping.SocketSet);
SDLNet_TCP_Close(Ping.sckGeneral);
}

/**
Concatenate two strings. It’s used to join the just arrived
characters with the previously received ones.
\param destiny destination buffer.
\param origin previously received characters string.
/
static void Ping_Concat( char
destiny, const char* origin )
{
const int ocupado = (int)strlen(destino);
const int livre = ( PING_MAXSTRLEN - ocupado );

   if( livre > 0 )
           strncat(destino, origem, livre);

}

/**
Send the “ask” message and convert the result to an integer.
\param message the request data to send to the server.
\return The converted answer or ZERO in case of error.
/
int Ping_GetInt( const char
message )
{
Ping_Ask(message, Ping.Msg);

   return Util_StrToInt(Ping.Msg, 0);

}