/** ******************************************************************************* @file /net/netinit.cpp @brief Inicializace pro sitovou komunikaci @author Vta @version 1.0 ******************************************************************************/ #include "net/netinit.h" #include "net/server.h" #include "net/client.h" #include "net/locator.h" #include "common/xml/package.h" //#include "world/world_messages.h" namespace net { /////////////////////////////////////////////////////////////////////////////// // globalni staticke data /////////////////////////////////////////////////////////////////////////////// /// Globalni objekt server TServer * net_server = NULL; /// Globalni objekt klient TClient * net_client = NULL; /// Transceiver pro sitovou vrstvu TLocator * net_locator = NULL; static struct TMessageTransceiver Trans_net; /////////////////////////////////////////////////////////////////////////////// // handler /////////////////////////////////////////////////////////////////////////////// /// Makro na zjisteni, zda je pusten server #define IAMSERVER (net_server!=NULL) /// Makro na zjisteni, zda je pusten klient #define IAMCLIENT (net_client!=NULL) /// Makro na zjisteni, zda je pusten locator #define IAMLOCATOR (net_locator!=NULL) /// Funce transceiveru RVAL msgnet (MESSAGE_ID msgId,SENDER who,PARAM data) { switch (msgId) { case MSG_EXCEPTION_IN_THREAD: { printf("Fatal error in thread"); // KSendMessage(RQUEUE,MSG_NET_STOP,MOD_NET,MOD_NET,NULL); // zastaveni serveru // exit(0); } break; case MSG_GAME_START: { if (IAMLOCATOR) { net_locator->stopSearching(); } if (IAMSERVER) { net_server->startGame(); } } break; case MSG_NET_DISCONNECT: { if (IAMSERVER) { int who=*((int*)(&data)); net_server->clientDisconnected(who); if (IAMCLIENT) // hlavni lokalni hrac by vsak nemel jit odpojit { if (net_client->getMyClientId()==who) { net_client->setMyClientId(-1); // pro jistotu, aby tam nebyl ukazatel na nekoho, kdo neexistuje } } } } break; case MSG_NET_STARTSERVER: { TNetStartServer* s = (TNetStartServer*)data; if (!IAMSERVER) { net_server=new(TServer)(s->maxPlayers, s->localGame, s->port, s->reconnect); net_server->prepare(); } else { GLOBALLOGID(PRIORITY_WARNING,"Can not initialize Server more than once"); THROW(E_8K_NET,"Can not initialize Server more than once"); //problem!! } } break; case MSG_NET_STOP: { if (IAMSERVER) { delete(net_server); net_server=NULL; } if (IAMCLIENT) { if (IAMLOCATOR) { net_locator->stopSearching(); } delete(net_client); net_client=NULL; } } break; case MSG_NET_STARTCLIENT: { TNetStartClient* c = (TNetStartClient*)data; if (!IAMCLIENT) { if ( (!IAMCLIENT) || (c->localGame==1) ) // bud neexituje server a nebo je to lokalni TClient { net_client=new(TClient)(c->localGame,c->port,c->profile_name); net_client->prepare(c->connectto); } else { GLOBALLOGID(PRIORITY_WARNING,"Can not initialize Client"); THROW(E_8K_NET,"Can not initialize Client"); } } else { GLOBALLOGID(PRIORITY_WARNING,"Can not initialize Client more than once"); THROW(E_8K_NET,"Can not initialize Client more than once"); //problem!! } } break; case MSG_NET_STOPCLIENT: { if ((IAMCLIENT) && (net_client->amILocal()==0)) // zrusit jde pouze sitovy klient { if (IAMLOCATOR) { net_locator->stopSearching(); } delete(net_client); net_client=NULL; } } break; case MSG_NET_STOP_SEARCHING_LAN: { if (IAMLOCATOR) { net_locator->stopSearching(); } }; break; case MSG_SEARCH_GAMES: { if (IAMLOCATOR) { net_locator->seachGames(); } } break; case MSG_NET_TEST: { TPackage * ret = (TPackage *) data; char string[10000]; ret->getXML()->toXML(string,10000); delete(ret); } break; case MSG_MESSAGE_RECEIVED: // sitova vrstva zachytila zpravu { TPackage * ret = (TPackage *) data; int from = ret->msgFrom(); int ofrom = ret->msgOrigFrom(); int to = ret->msgTo(); int structid = ret->getInt("_id_struct",0,NULL); int trans = ret->getTransceiver(); if (structid!=MSG_MESSAGE_RECEIVED) // zabraneni aspon nejtrivialnejsimu zacykleni { if ((IAMCLIENT) && (from==TO_SERVER)) // zprava od serveru, zde konci // zde se zachyti vsechny zpravy smerujici pro klienta - pri odesilani ze serveru // dostanou vsechny zpravy odesilatele TO_SERVER, ale v orig_from mam puvodniho { // net_client->setPing(); - tady je to zbytecne ret->setOrigSender(); // pouze tady to mohlo byt preposilano pres server from=ofrom; // printf("\nKlientovi prisla zprava od %i pro %i",from,to); GLOBALLOGID(PRIORITY_NEW_MESSAGE,"Client - new message has arrived, sender %i, addresse %i", from, to); KSendMessage(RQUEUE,structid,MOD_NET,trans,(void*)ret); } else if ((IAMSERVER) && (from>=0)) // zprava od klienta { // net_server->setPing(from); - tady je to zbytecne GLOBALLOGID(PRIORITY_NEW_MESSAGE,"The Server has received a message from %i, for %i ", ofrom, to); DA*clients; net_server->showMeClientsInfo(&clients); if (((*clients)[from]->profileName[0]==0) && (structid!=MSG_NEW_CONNECTION_SYNCHRO3)) // jeste client nebyl autorizovan { // printf("Klient %i jeste nebyl autorizovan, presto prisla zprava.", ofrom); // printf("The client having id %i has not been authorized yet. There can not be any broadcast yet.", ofrom); GLOBALLOGID(PRIORITY_NEW_MESSAGE,"The client having id %i has not been authorized yet. There can not be any broadcast yet.", ofrom); net_server->clientDisconnected(from); break; } if (to==TO_SERVER) // server je inicializovan a je to zprava serveru { // printf("\nNa server prisla zprava od %i pro %i",from,to); GLOBALLOGID(PRIORITY_NEW_MESSAGE,"Server - a message was received, sender %i, addresse %i.", from,to); KSendMessage(RQUEUE,structid,MOD_NET,trans,(void*)ret); // preposlani na tomto pocitaci } else if (to>=0) // adresat nejaky klient { // printf("\nNa server prisla zprava pro klienta od %i pro %i ",from,to); GLOBALLOGID(PRIORITY_NEW_MESSAGE,"Server - a message from client id %i to client id %i was received.", from,to); if (net_server->isLocal(to)) // je to lokalni klient { KSendMessage(RQUEUE,structid,MOD_NET,trans,(void*)ret); // preposlani na cilovy transceiver // jelikoz toto volani ale prislo z vlakna, nebude to delat problem s cyklenim zprav } else // jen preposila zpravu klientovi { ret->send(TO_SERVER,to); // prekopiruje se do fronty delete(ret); // a smazu data } } else if (to==TO_CLIENTS) // vsem klientum od klienta { // printf("Na server prisla zprava pro vsechny klienty od %i ",from,to); GLOBALLOGID(PRIORITY_NEW_MESSAGE,"Server - a message for all clients was received from client %i.", from); ret->send(TO_SERVER,to); delete(ret); // a smazu data } /* else if (to==TO_NET_CLIENTS) // vsem sitovym klientum od klienta - nelze { printf("Na server prisla zprava pro vsechny sitove klienty od %i ",from,to); ret->send(TO_SERVER,to); delete(ret); // a smazu data }*/ else if (to==TO_EVERYBODY) // vsem klientum i serveru od klienta { // printf("Na server prisla zprava pro klienty %i server od %i ",from,to); GLOBALLOGID(PRIORITY_NEW_MESSAGE,"Server - a message for both server and all clients was received from client id.", from); ret->send(TO_SERVER,to); // preposlu vsem a navic zde poslu zpravu pro server KSendMessage(RQUEUE,structid,MOD_NET,trans,(void*)ret); // preposlani worldu protoze to jde i serveru. Zde se to maze, proto az 2. } else { GLOBALLOGID(PRIORITY_WRONG_MESSAGE,"A message with bad addressee was delivered"); //problem!! } } else //WHOAMI? { GLOBALLOGID(PRIORITY_NET_NOT_INICIALIZED,"The network has not been initialized yet"); //problem!! } } } break; case MSG_NEW_CONNECTION_SYNCHRO1: // server posila clientovi jeho clientid { if (IAMSERVER) { TNodeInfo * infoc = (TNodeInfo *) data; TPackage * new_connetion_info; new_connetion_info=new TPackage(MSG_NEW_CONNECTION_SYNCHRO2); new_connetion_info->setInt(infoc->clientid,"clientid",0,NULL); // printf("Odchazi na %i \n",infoc->clientid); new_connetion_info->send(TO_SERVER,infoc->clientid,MOD_NET); delete(new_connetion_info); } } break; case MSG_NEW_CONNECTION_SYNCHRO2: // client posila serveru zpet jeho jmeno profilu { if (IAMCLIENT) { TPackage * new_connetion_info=(TPackage*) data; TPackage * new_connetion_info2; new_connetion_info2=new TPackage(MSG_NEW_CONNECTION_SYNCHRO3); char profile_name[K8_MAX_NAME_LEN]; net_client->getMyProfileName(profile_name); new_connetion_info2->setChar(profile_name,"profile",0,NULL); int cid=new_connetion_info->getInt("clientid",0,NULL); // printf("Prislo mi oznameni o mem clientid: %i\n",cid); net_client->setMyClientId(cid); new_connetion_info2->send(cid,TO_SERVER,MOD_NET); delete(new_connetion_info); delete(new_connetion_info2); net_client->startPing(); } } break; case MSG_NEW_CONNECTION_SYNCHRO3: // server si zaznamena klientovo jmeno { // neni tady problem, ze klient zmeni jmeno nekomu cizimu? // neni, pokud si vezmu clientid primo z adresy - z odesilatele if (IAMSERVER) { TPackage * new_connection_info=(TPackage*) data; int from = new_connection_info->msgFrom(); char profile_name[K8_MAX_NAME_LEN]; new_connection_info->getChar(profile_name,K8_MAX_NAME_LEN,"profile",0,NULL); delete(new_connection_info); // printf("\n%s",profile_name); if (net_server->getStatus()==STATUS_RUNNING) // stav, kdy server muze normalne pribirat klienty { int freeprofilename=net_server->noteClientProfileName(from,profile_name); // printf("Zapsal jsem si jmeno profilu : %s\n",profile_name); // A uz muzu informovat vsechny o novem pripojeni if (freeprofilename==0) // pokud takovy profil neni uz pripojen { net_server->startPing(from); KSendMessage(RQUEUE,MSG_NEW_CONNECTION_ACCEPTED,MOD_NET,MOD_NET,*((void**)(&from))); } else { net_server->clientDisconnected(from); // uz je, tak ho odpojim } } else { if (net_server->getStatus()==STATUS_GAME_STARTED) // stav, kdy se mohou pripojit jen klienti, kteri uz byly ve hre { int accepted=net_server->reconnectClient(from,profile_name); if (accepted!=0) { TPackage * new_connetion_info2; new_connetion_info2=new TPackage(MSG_NEW_CONNECTION_SYNCHRO4); new_connetion_info2->setInt(accepted,"trueclientid",0,NULL); new_connetion_info2->send(TO_SERVER,accepted,MOD_NET); delete(new_connetion_info2); } // net_server->clientDisconnected(from); // v pripade, ze nepovolime } } } } break; case MSG_NEW_CONNECTION_SYNCHRO4: // clientID was set to previous one... updating { if (IAMCLIENT) { TPackage * new_connetion_info=(TPackage*) data; TPackage * new_connetion_info2; new_connetion_info2=new TPackage(MSG_NEW_CONNECTION_SYNCHRO5); char profile_name[K8_MAX_NAME_LEN]; net_client->getMyProfileName(profile_name); int cid=new_connetion_info->getInt("trueclientid",0,NULL); // printf("Prislo mi oznameni o mem clientid: %i\n",cid); // printf("Hurrraaa .. moje id je %i\n\n",cid); net_client->setMyClientId(cid); new_connetion_info2->send(cid,TO_SERVER,MOD_NET); delete(new_connetion_info); delete(new_connetion_info2); net_client->startPing(); } } break; case MSG_NEW_CONNECTION_SYNCHRO5: // client updated his new client ID .. lets inform others { if (IAMSERVER) { TPackage * new_connection_info=(TPackage*) data; int from = new_connection_info->msgFrom(); net_server->stopAnnouncingMissingPlayers(); net_server->startPing(from); KSendMessage(RQUEUE,MSG_CLIENT_HAS_RECONNECTED,MOD_NET,BROADCAST,*((void**)(&from))); KSendMessage(RQUEUE,MSG_CLIENT_RECONNECTION_ACCEPTED,MOD_NET,MOD_NET,*((void**)(&from))); } } case MSG_LOCAL_CLIENT_ADDED: { if (IAMCLIENT) { int cid=*((int*)(&data)); if (net_client->getMyClientId()==-1) net_client->setMyClientId(cid); } } break; case MSG_CLIENT_RECONNECTION_ACCEPTED: case MSG_NEW_CONNECTION_ACCEPTED: { if (IAMSERVER) { int from=*((int*)(&data)); DA * clients; net_server->showMeClientsInfo(&clients); TPackage * new_connetion_info; if (msgId==MSG_CLIENT_RECONNECTION_ACCEPTED) new_connetion_info=new TPackage(MSG_CLIENT_RECONNECTION_INFO); else new_connetion_info=new TPackage(MSG_NEW_CONNECTION_INFO); new_connetion_info->setInt((*clients)[from]->clientid,"clientid",0,NULL); new_connetion_info->setInt((*clients)[from]->level,"level",0,NULL); new_connetion_info->setInt((*clients)[from]->localConnection,"local",0,NULL); new_connetion_info->setChar((*clients)[from]->profileName,"nickname",0,NULL); new_connetion_info->send(TO_SERVER,TO_NET_CLIENTS,MOD_NET); delete(new_connetion_info); } } break; case MSG_CLIENT_RECONNECTION_INFO: case MSG_NEW_CONNECTION_INFO: { TPackage * new_connetion_info=(TPackage*) data; TNodeInfo * ni = (TNodeInfo*)KMemAlloc (sizeof(TNodeInfo)); ni->clientid=new_connetion_info->getInt("clientid",0,NULL); ni->decompressbuff=NULL; ni->fd=0; ni->IP=0; ni->level=new_connetion_info->getInt("level",0,NULL);; ni->localConnection=new_connetion_info->getInt("local",0,NULL); new_connetion_info->getChar(ni->profileName,NICKNAME_LEN,"nickname",0,NULL); ni->ping=0; ni->recvbuff=NULL; if (IAMCLIENT) { net_client->addClientInfo(ni); } if (msgId==MSG_CLIENT_RECONNECTION_INFO) KSendMessage(RQUEUE,MSG_CLIENT_RECONNECTION_REPORT,MOD_NET,BROADCAST,*((void**)(&(ni->clientid)))); else KSendMessage(RQUEUE,MSG_NEW_CONNECTION_REPORT,MOD_NET,BROADCAST,*((void**)(&(ni->clientid)))); delete(new_connetion_info); KMemFree(ni); } break; /* case MSG_NEW_CONNECTION_REPORT: { int infoc = (int) data; // printf("\nInformace pro klienta novem pripojeni Clientid :%i\n",infoc); } break; case MSG_CLIENT_RECONNECTION_REPORT: { int infoc = (int) data; // printf("\nReconnection: clientid :%i\n",infoc); } break; */ case MSG_GET_NETWORK_PARTICIPANTS: { if (IAMCLIENT) { TClientsInfo * ci= (TClientsInfo*)data; net_client->copyClientsInfo(ci); } } break; // **** DISCONNECT case MSG_CLIENT_DISCONNECTION_ACCEPTED: { if (IAMSERVER) { int who=*((int*)(&data)); TPackage * message=new TPackage(MSG_CLIENT_DISCONNECTION_INFO); message->setInt(who,"clientid",0,NULL); message->send(TO_SERVER,TO_NET_CLIENTS,MOD_NET); delete(message); } } break; case MSG_CLIENT_DISCONNECTION_INFO: { TPackage * message=(TPackage*) data; int who=message->getInt("clientid",0,NULL);; if (IAMCLIENT) { net_client->removeClientInfo(who); } KSendMessage(RQUEUE,MSG_CLIENT_DISCONNECTION_REPORT,MOD_NET,BROADCAST,*((void**)(&who))); delete(message); } break; // **** case MSG_ADD_LOCAL_CLIENT: { if (IAMSERVER) { if (data!=NULL) { char profilename[K8_MAX_NAME_LEN]; strncpy(profilename,(char*)data,K8_MAX_NAME_LEN); net_server->addLocalClient(profilename); } else { GLOBALLOGID(PRIORITY_WARNING,"The local client can not be added without a name"); } } else { //problem!! GLOBALLOGID(PRIORITY_WARNING,"Can not add a local client unless the Server is running"); } } break; case MSG_NET_START_NETWORK: { if (IAMLOCATOR) { net_locator->start(); } } break; case MSG_NET_PING: { TPackage * ret = (TPackage *) data; if (IAMSERVER) // nejdriv server, loklani klienti zpravu nedostavaji { int from=ret->msgFrom(); if (from>0) { net_server->setPing(from); // printf("ping"); } } else if (IAMCLIENT) // pak pripadne klient { net_client->setPing(); // printf("pong"); } } break; case MSG_NET: // sem se to dostane ve chvili kdy server nebo client neco odesila { if (data) { // printf("X"); TXMLdata * tosend=(TXMLdata*) data; int from=tosend->getDataInt("from_",0,NULL); // int to=tosend->getDataInt("to_",0,NULL); // int howmany; if ((IAMSERVER) && (from==TO_SERVER)) // server posila { /*howmany=*/net_server->sendMessage(tosend); // zarazeni do fronty odesilanych zprav } else if ((IAMCLIENT) && (from>=0)) // klient posila { /*howmany=*/net_client->sendMessage(tosend); // zarazeni do fronty odesilanych zprav // printf("@%i@",howmany); } else { //problem!! GLOBALLOGID(PRIORITY_NET_NOT_INICIALIZED,"The network has not been initialized yet"); // THROW(E_8K_NET,"Sit nebyla inicializovana"); } } else { //problem!! GLOBALLOGID(PRIORITY_EMPTY_DATA,"No data were sent"); // THROW(E_8K_NET,"Pres sit nebyly poslany zadne data"); } } break; } return NULL; } /////////////////////////////////////////////////////////////////////////////// // init & destroy /////////////////////////////////////////////////////////////////////////////// int NETdestroy() { KUnregisterTransceiver(RQUEUE,MOD_NET); // nejdriv odregistrovat, pak uz se nebudou dat poslat zpravy if (net_server!=NULL) { delete(net_server); net_server=NULL; } if (net_client!=NULL) { delete(net_client); net_client=NULL; } if (net_locator!=NULL) { delete(net_locator); net_locator=NULL; } return 0; } int NETinit() { // registrace MSG Transceiveru Trans_net.fnc = msgnet; Trans_net.iActived = 1; Trans_net.iPriority = 5; Trans_net.PrimaryID = MOD_NET; KRegisterGlobalTransceiver(&Trans_net, MOD_NET); net_locator=new(TLocator); return 0; } }