Example11_NetChat2.cpp


/*--------------------------------------------
   Examples - CRM32Pro SDK - Roberto Prieto
   Copyright (C) 2001-2011 MegaStorm Systems
  --------------------------------------------

  Example 11: using INetwork on Authoritative mode
  ------------------------------------------------
  - Initialize CRM32Pro and SDL.
  - Printing help on console.
  - Use of log system.
  - Initializing network system.
  - Using Authoritative Server Mode.
  - Each instance run as server or as client.
  - Simple chat with a little words filter: "hello" and "bye"
    will be denied by CoreServer function.
  - Exiting using the right way ;)

  This example is totally free and can be used without 
any restriction but there is not any warranty for its usage.
Please, do not forget to include a copy of all the library licenses
located at /licenses directory if you distribute or share it.

Roberto Prieto
megastorm@ono.com
http://www.megastormsystems.com
*/

// ---Includes---
#include "CRM32Pro.h" 

// ---Defines---
#define EXAMPLE_VERSION "Example 11: INetwork on Authoritative mode"

// ---Prototypes---
void ExecuteClient(char *server,char *myname);
void ExecuteServer();
int ReadLine(void *);
void PrintHelp(char *sErrMsg = NULL);
int myCoreServer(void *data,int size);

// ---Global vars---
int done;                      // Used by "ReadLine()" thread to finalize

// -------------MAIN FUNCTION----------------
int main(int argc,char **argv)
{          
   Uint8       bMode = 0;

   // -Print help without any arguments-
   if(argc < 2) 
   {
              PrintHelp();
              return 1;
   }

   // -Get arguments from command line-
   if(!strcmp(argv[1],"-s")) 
   {
              // Run as server
              bMode = 1;  
              // Log system initialize
              ILogSystem.Init("NetChat2Server.log",LOG_CONSOLE | LOG_FILE,LOG_NORMAL,EXAMPLE_VERSION);
   }
   else if(!strcmp(argv[1],"-c"))
   {
             if(argc > 2) 
             {
                        // Run as client
                        bMode = 2; 
                        // Log system initialize
                        ILogSystem.Init("NetChat2Client.log",LOG_CONSOLE | LOG_FILE,LOG_NORMAL,EXAMPLE_VERSION);
             }
   }

   // -Are the arguments OK?-
   if(bMode == 0) 
   {
              PrintHelp("\n Error: invalid arguments\n");
              return 1;
   }
   
   // -CRM32Pro and SDL initialize- 
   if(CRM32Pro.Init(0) < 0)
   {
      ILogSystem.Msg(LOG_NORMAL," · [LOG] - Could not initialize CRM32Pro: %s\n",SDL_GetError());
      return 1;
   }

   // -Interfaz network initialize-         
   if(!INetwork->Init(LOG_CONSOLE | LOG_FILE))
   {
      ILogSystem.Msg(LOG_NORMAL," · [LOG] - Could not initialize INetworkSystem\n");
      CRM32Pro.Quit();
             return 1;
   }

   // -Execute a server or a client-
   if(bMode == 1) ExecuteServer();
   else 
   {
              // Look for a client name
       if(argc > 3) ExecuteClient(argv[2],argv[3]);
              // Or use a default one
              else ExecuteClient(argv[2],"Anonymous");
   }

   // -Exiting..-   
   INetwork->Quit();
   CRM32Pro.Quit();
   return 0;
}

// -------------------CLIENT STUFF-----------------------
// -Execution of a client-
void ExecuteClient(char *server,char *myname)
{
   char       *buff = NULL; 
   Uint32 size = 0, result = 0;   
   SDL_Thread *ReadLineT = NULL;  

   // -Trying to connect to server on port 2220 with password 1001-
   if(!INetwork->ConnectTo(server,2220,myname,1001)) return;
           
   // -Using a thread, we can send/receive data at the same "time"-
   // We have a little chat ;)
   ReadLineT = SDL_CreateThread(ReadLine,NULL);                   

   // -Main Loop-
   done = 0;
   
   while(!done)
   {       
      // Have we received data?
      result = INetwork->ReceiveData(&buff,&size);                
      switch(result)
      {
         case INETWORK_ERROR:
                                 puts("Error detected!");
         case INETWORK_CLOSE:
                                 puts("Closing application. Press ENTER to finish");
                                 // With done = 1, the reading thread should finish by itself
                                 done = 1; 
                                 // Waiting for the end of our reading thread                                 
                                 SDL_WaitThread(ReadLineT,NULL);
                                 ReadLineT = NULL;
                                 break;
         case INETWORK_NEWCLIENT:
                                 ILogSystem.Msg(LOG_NORMAL,"[New client '%s' connected]\n",buff);
            break;
         case INETWORK_QUITCLIENT:
                                 ILogSystem.Msg(LOG_NORMAL,"['%s' client has quitted]\n",buff);
            break;
         case INETWORK_PING:
            break;
                       case INETWORK_CLIENTSINFO:
                                 ILogSystem.Msg(LOG_NORMAL,"[Clients information updated]\n");
            break;
         case INETWORK_DATA:
            ILogSystem.Msg(LOG_NORMAL,":%s(%dbytes)\n",buff,size);
                                 break;
                       case INETWORK_DATAVALIDATED:
                          ILogSystem.Msg(LOG_NORMAL,"[Validated data]\n");
                                 break;
                       case INETWORK_DATADENIED:
                                 ILogSystem.Msg(LOG_NORMAL,"[Denied data]\n");
                                 break;
      }
      // Delete received data (if any)
      INetwork->FreeData(buff);
      // Your code...we only wait 250ms
      SDL_Delay(250);
   }  
   // It's not necessary to kill our thread because it finishes by itself with done=1   
}

// -Our thread to read a line and send it-
#define MAXLEN (1*1024) // 1 KB - adequate for text!
int ReadLine(void *data)
{          
   char     message[MAXLEN];
   Uint32   len = 0, nc, i;
   char    *str;
   sClientInfo *cInfo;
   strcpy(message,"");

   // ---Main loop---
   while(!done)
   {
      strcpy(message,"");        
             // As we are not using a non blocking read method, quite probably we will have to press ENTER
             // to finish this thread, but the user will be informed on that case
      fgets(message,1024,stdin);   
      len = (int)strlen(message);      
      SDL_Delay(250);
      if((len) && (!done))
      {
                       message[len - 1] = '\0';

         // -With '1', query to close this client-
         if(message[0] == '1') INetwork->QueryKillClient();
                                 
         // -With '2', query to close the server (and all clients)
         else if(message[0] == '2') INetwork->QueryKillServer();

         // -With '3', query a list of current clients with updated information
         else if(message[0] == '3') INetwork->QueryClientsInfo();
                                 
         // -With '4', send raw data to server-
         #define HOW_KB 32*1024
         else if(message[0] == '4')
         {
            len = HOW_KB;
            str = new char[len]; 
                                 memset(str,0,len);
            ILogSystem.Msg(LOG_NORMAL,"[Sending a block of %dKb raw data]\n",len / 1024);                                                                                                  
            INetwork->SendData(str,len);
            delete str;                                                      
         }

                       // -With '5', show our local clients information table-
                       else if(message[0] == '5')
                       {
                                  nc = INetwork->GetClientsInfo(&cInfo);
                                  ILogSystem.Msg(LOG_NORMAL," Number of clients: %d\n",nc);
                                  for(i = 0; i < nc; i++)
                                  {
                                             ILogSystem.Msg(LOG_NORMAL,"Client '%s' - IP '%d.%d.%d.%d' - Current %dms - Average %dms.\n",
                                                        cInfo[i].szName,cInfo[i].IP >> 24,(cInfo[i].IP >> 16) & 0xff, (cInfo[i].IP >> 8) & 0xff,
                                                        cInfo[i].IP & 0xff, cInfo[i].iLatency, cInfo[i].iLatencyAvg);
                                  }

                       }

                       // -With '6', show current statistic-
                       else if(message[0] == '6')
                       {
                                  INetwork->Info();
                       }
                                                       
         // -Send a text line (to be evaluated by the CoreServer)-
         else
         {                                  
            ILogSystem.Msg(LOG_NORMAL,"[Sending a text line of %d bytes]\n",len);                                                                                               
            INetwork->SendData(message,len,1);
         }
      }    
   }
   return 1;
}


// -------------------Server STUFF-----------------------
// -Execution of a server-
void ExecuteServer()
{
   // Set a CoreServer callback to switch to Authoritative Mode
   INetwork->SetCoreServerCallback(myCoreServer);
   // Create a dedicatedserver listening on port 2220 and with 1001 as password
   if(!INetwork->CreateServer(2220,1001,1)) return;
}

// -My CoreServer function to evaluate the data-
int myCoreServer(void *data,int size)
{
           // With "hello" and "bye" we return 0
           if(!strcmp((const char*)data,"hello")) return 0;
           if(!strcmp((const char*)data,"bye")) return 0;

           // Any other word, is a valid one
           return 1;
}

// --------------------Help STUFF------------------------
// -Print help-
void PrintHelp(char *sErrMsg)
{
           printf("-----------------------------------------------------------\n");
           printf("                 CRM32Pro SDK - HelpScreen\n      %s\n",EXAMPLE_VERSION);
    printf("-----------------------------------------------------------\n\n");
           printf(" Use:\n");
           printf("   -  'NetChat2 -s' to run as server\n");
           printf("   -  'NetChat2 -c ServerIP [my_name]' to connect to a server\n\n");
           printf(" Once you are connected to a server, you can press [ENTER]\n");
           printf(" key to send any text to others clients.\n");
           printf(" There are a few words that are reserved internally:\n");
           printf("  > '1' the client wants to exit\n");
           printf("  > '2' the client wants to close the server\n");
           printf("  > '3' the client has asked for info about others clients(including itself)\n");
           printf("  > '4' the client sends a raw block data of %dKB\n",HOW_KB/1024);
           printf("  > '5' the client dumps the local clients information\n");
           printf("  > '6' the client shows the current statistics\n");
           if(sErrMsg != NULL) printf("%s",sErrMsg);
           else printf("\n");
           puts("Press [ENTER] key to continue");
           getchar();
}
 All Classes Functions Variables