CRM32Pro SDK  v5.22
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
contact@megastormsystems.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)
{
puts("Error detected!");
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;
ILogSystem.Msg(LOG_NORMAL,"[New client '%s' connected]\n",buff);
break;
ILogSystem.Msg(LOG_NORMAL,"['%s' client has quitted]\n",buff);
break;
break;
ILogSystem.Msg(LOG_NORMAL,"[Clients information updated]\n");
break;
ILogSystem.Msg(LOG_NORMAL,":%s(%dbytes)\n",buff,size);
break;
ILogSystem.Msg(LOG_NORMAL,"[Validated data]\n");
break;
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();
}
// -With '7', send a text line (bypassing the CoreServer)
else if(message[0] == '7')
{
ILogSystem.Msg(LOG_NORMAL,"[Sending a text line of %d bytes bypassing the CoreServer]\n",len);
INetwork->SendData(message+1,len-1,0);
}
// -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();
}