/** ****************************************************************************** @file /net/server.cpp @brief Trida server @author Vta @version 1.0 ******************************************************************************/ #include "net/server.h" #include "common/utils.h" #include "common/rm/rmconfi.h" #include "common/rm/rmmapi.h" #include "common/compatibility.h" #include using namespace rm; namespace net { int TServer::sendMessage(TXMLdata * data) { this->lock(); // printf("\n"); // printf(content); // int contentlen=datostr(&content, xml_in_da,0); // nejdriv to hodim do sveho charu int to = data->getDataInt("to_",0,NULL); int from = data->getDataInt("from_",0,NULL); int ofrom = data->getDataInt("ofrom_",0,NULL); int i=-1; if (to>=1) // 1) pokud je to zprava jen primo jednomu klientovi { int /*clientid=-1,*/ j=1; // JEN V PRIPADE, ZE [to]!=CLIENTID /* while (j<(this->maxClients-1) ) { if ((*this->clients)[j]==NULL) j++; else if ((*this->clients)[j]->clientid!=to) j++; else break; } */ j=to; if (((*this->clients)[j])!=NULL) // pak musi ten klient existovat { if ((*this->clients)[j]->localConnection==1) // pokud je to localni pripojeni. tj. komunikace server->lokalni klient { this->xml_in_da->reset(); data->toXML(xml_in_da); char * content=NULL; content=this->xml_in_da->getData(); i=this->queue->addMessage(content,0); // nula symbolizuje lokalni pripojeni } else { if ((*this->clients)[j]->fd!=0) // pokud dany klient existuje a neni-li docasne odpojen { this->xml_in_da->reset(); data->toXML(xml_in_da); char * content=NULL; content=this->xml_in_da->getData(); i=this->queue->addMessage(content,(*this->clients)[j]->fd); } else { GLOBALLOGID(PRIORITY_FATAL, "Server - Client %i is not connected yet",to); // THROW(E_8K_NET,"Server - Can not send a message to unconnected client"); } } } else { GLOBALLOGID(PRIORITY_WARNING, "Server - Non existing addressee clientid = %i",j); //problem!! } } else if (to==TO_SERVER) // 2) server nemuze odeslat zpravu s adresatem server { // printf("SEM SE NELZE DOSTAT"); GLOBALLOGID(PRIORITY_FATAL, "Server - Bad addressee of message"); THROW(E_8K_NET,"Server - Bad addressee of message"); } else if ((to==TO_CLIENTS) || (to==TO_EVERYBODY) || (to==TO_NET_CLIENTS)) // 3) vsem { int k; int local=0; for (k=1;k<(this->maxClients);k++) { if ((k!=from) && (k!=ofrom)) // abych neposilal stejnou zpravu nazpet klientovi, ktery broadcast posal. Server je ok, jelikoz jeho id je <0 { if ((*this->clients)[k]!=NULL) { if ((*this->clients)[k]->profileName[0]!=0) // pripojovaci procedura jeste neskoncila { if (((*this->clients)[k]->localConnection==1) || ((*this->clients)[k]->fd!=0)) // pokud dany klient existuje a neni-li docasne odpojen { if ((local==0) || ((to!=TO_NET_CLIENTS) || ((*this->clients)[k]->localConnection==0)) ) { if ((*this->clients)[k]->localConnection==1) // uz to bylo odeslano i pro lokalni hrace local=1; this->xml_in_da->reset(); data->setDataInt(k,"to_",0,NULL); data->toXML(xml_in_da); char * content=NULL; content=this->xml_in_da->getData(); i=this->queue->addMessage(content,(*this->clients)[k]->fd); } } } } } }//for } this->unlock(); return i; } int TServer::FreeExtraClient(int clientid) { this->lock(); if ((*this->clients)[clientid]!=NULL) { MyCloseSocket((*this->clients)[clientid]->fd); // zavru socket this->clientsConnected--; if ((*this->clients)[clientid]->recvbuff!=NULL) delete((*this->clients)[clientid]->recvbuff); if ((*this->clients)[clientid]->decompressbuff!=NULL) delete((*this->clients)[clientid]->decompressbuff); KMemFree((*this->clients)[clientid]); // uvolnim } this->unlock(); return 1; } int TServer::getFreeClientCount() { this->lock(); int i; i=this->maxClients - this->clientsConnected-1; this->unlock(); return (i); } TNodeInfo ** TServer::getFreeClient() { this->lock(); int i; for (i=1;imaxClients;i++) { if ((*this->clients)[i]==NULL) // prvni ktery je volny { this->clientsConnected++; this->unlock(); return &((*this->clients)[i]); } } // tj. nic to nenaslo - vse je plne, tato vetev pokud se pouziva "extra" klient by nemela nastat this->unlock(); GLOBALLOGID(PRIORITY_FATAL, "Server - Fatal error"); THROW(E_8K_NET,"Server - Fatal error"); // return NULL; } int TServer::getFreeClientId() { this->lock(); int i; for (i=1;imaxClients;i++) { if ((*this->clients)[i]==NULL) // prvni ktery je volny { this->unlock(); return i; } } // tj. nic to nenaslo - vse je plne, tato vetev pokud se pouziva "extra" klient by nemela nastat this->unlock(); GLOBALLOGID(PRIORITY_FATAL, "Server - Fatal error"); THROW(E_8K_NET,"Server - Fatal error"); // return NULL; } int TServer::install() { if(MyListen(this->fd,this->maxClients) == -1) { GLOBALLOGID(PRIORITY_FATAL, "Server - listen error"); THROW(E_8K_NET,"Server - listen error"); // return 0; } else { return 1; } } void TServer::clientDisconnected(int id) { this->lock(); if ((*this->clients)[id]!=NULL) { if ((*this->clients)[id]->fd!=0) MyCloseSocket((*this->clients)[id]->fd); (*this->clients)[id]->fd=0; if ((*this->clients)[id]->IP==0) // odstran celeho klienta, hra jeste nezacala { if ((*this->clients)[id]->recvbuff!=NULL) delete((*this->clients)[id]->recvbuff); if ((*this->clients)[id]->decompressbuff!=NULL) delete((*this->clients)[id]->decompressbuff); KMemFree((*this->clients)[id]); (*this->clients)[id]=NULL; this->clientsConnected--; } else // Nech strukturu tak jak je - aby se mohl pripojit { // NIC // But inform about free slot, if reconnect if (this->reconnection==1) { this->announce_right_now=1; // if the thread was already running inform it to send new info if ((this->announceold==1) && (this->announce!=1)) { this->announce=1; this->sem=SDL_CreateSemaphore(0); this->announceThread=SDL_CreateThread(announceGame_thread, (void*)this); SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); // No!! Its running already! this->status=STATUS_PREPARE; this->sem=SDL_CreateSemaphore(0); this->announceThread=SDL_CreateThread(announceGameLAN_thread, (void*)this); SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); } } } this->unlock(); // In case in profile is set to announce and is not currently announcing KSendMessage(RQUEUE,MSG_CLIENT_DISCONNECTION_ACCEPTED,MOD_NET,MOD_NET,*((void**)(&id))); } else { this->unlock(); } } int recvServer_thread(void * data) { TServer* that=(TServer*) data; try { SDL_SemPost(that->sem); fd_set readfds; GLOBALLOGID(PRIORITY_THREAD, "Server - recvServer_thread is running"); timeval timeout; timeout.tv_sec=0; timeout.tv_usec=0; // int sin_size = sizeof(struct sockaddr_in); int i; int s; mysocket sck; int sz; DA * bfr; DA * dbfr; int num,len; mysocket maxDescriptor; while (1) { FD_ZERO(&(readfds)); // vynuluji // if (that->fd!=0) num=1; // pocet pripojenych klientu maxDescriptor=0; for (i=1;imaxClients;i++) { if (((*that->clients)[i]!=NULL) && ((*that->clients)[i]->fd!=0)) { FD_SET((*that->clients)[i]->fd, &(readfds)); if (maxDescriptor<((*that->clients)[i]->fd)) maxDescriptor=(*that->clients)[i]->fd; num++; } } if (that->status==STATUS_ENDING) // pokud server jiz konci, ukonci vlakno { GLOBALLOGID(PRIORITY_THREAD, "Server - recvServer_thread is ending"); return 0; } if (num>0) // je pripojen alespon jeden klient { that->lock(); #ifdef WIN32 s=MySelect (0, &(readfds), NULL,NULL, &timeout); #else s=MySelect (maxDescriptor+1, &(readfds), NULL,NULL, &timeout); #endif that->unlock(); if (that->status==STATUS_ENDING) { GLOBALLOGID(PRIORITY_THREAD, "Server - recvServer_thread is ending"); return 0; } for (i=1;imaxClients;i++) // ktery klient to poslal { if (((*that->clients)[i]!=NULL) && ((*that->clients)[i]->fd!=0)) { if (FD_ISSET((*that->clients)[i]->fd,&(readfds))) { // nactu zpravu nebo jeji cast sck=(*that->clients)[i]->fd; bfr=(*that->clients)[i]->recvbuff; dbfr=(*that->clients)[i]->decompressbuff; sz=(*that->clients)[i]->size_of_next_message; if (that->status!=STATUS_ENDING) len=that->recvFrom(sck,bfr,dbfr,i,sz); else return 0; if (len<=0) // pokud nic neprijmu, musel nastat closesocket() { // mysocket sock=readfds.fd_array[s-1]; GLOBALLOGID(PRIORITY_NEW_CONNECTION, "Server - connection to Client id %i was closed",i); // printf("Socket se zavrel - klient %i\n",i); if (that->status!=STATUS_ENDING) { KSendMessage(RQUEUE,MSG_CLIENT_HAS_DISCONNECTED,MOD_NET,BROADCAST,*((void**)(&i))); that->clientDisconnected(i); } } else { that->setPing(i); // neco jsem prijal - klient zije } if ((*that->clients)[i]!=NULL) // pokud nebyl po prijmuti zpravy klient zabit { (*that->clients)[i]->size_of_next_message=sz; // zapisu novou hodnotu // printf("RECEIVED %i",(*that->clients)[i]->fd); if ((*that->clients)[i]->profileName[0]==0) // jeste neni proveren - musim hlidat, co prichazi { if ( ((*that->clients)[i]->size_of_next_message>MAX_LENGHT_UNAUTHORIZED_MESSAGE) || ((*that->clients)[i]->size_of_next_message<=0)) // prichozi zprava je moc dlouha { // printf("X"); printf("%i\n",(*that->clients)[i]->size_of_next_message); that->clientDisconnected(i); } } } break; } } } SDL_Delay(COMM_WAIT_AFTER_SELECT); // printf("New SELECT"); } else // nejsou pripojeni zadni klienti { SDL_Delay(COMM_WAIT_NO_CLIENTS); } } GLOBALLOGID(PRIORITY_THREAD, "Server - recvServer_thread is ending"); } catch (E_8K &e) { GLOBALLOGID(PRIORITY_EXCETION_IN_THREAD, "Exception in recvServer_thread"); char err[1000]; snprintf(err,999,"%s:%i:%s",e.getFileName(),e.getLineNumber(),e.getDescription()); err[999]=0; GLOBALLOGID(PRIORITY_EXCETION_IN_THREAD, err); if (that->status!=STATUS_ENDING) KSendMessage(RQUEUE,MSG_EXCEPTION_IN_THREAD,MOD_NET,BROADCAST,&e); } return 0; } int accept_thread(void * data) { TServer* that=(TServer*) data; try { fd_set readfds; SDL_SemPost(that->sem); GLOBALLOGID(PRIORITY_THREAD, "Server - accept_thread is running"); timeval timeout; timeout.tv_sec=0; timeout.tv_usec=0; TNodeInfo ** client; mysocket maxDescriptor = that->fd; #ifdef WIN32 int sin_size = sizeof(struct sockaddr_in); // Windows chteji do accept int #else socklen_t sin_size = sizeof(struct sockaddr_in); #endif int s; while (1) { FD_ZERO(&(readfds)); // if (that->fd!=0) FD_SET(that->fd, &(readfds)); // hlida jen fd - na accept that->lock(); #ifdef WIN32 s=MySelect (0, &(readfds), NULL,NULL, &timeout); #else s=MySelect (maxDescriptor+1, &(readfds), NULL,NULL, &timeout); #endif that->unlock(); // pokud server konci, nebo se ma ukoncit jen toto vlakno if ( (that->status==STATUS_ENDING) || (that->reconnection==2) ) { GLOBALLOGID(PRIORITY_THREAD, "Server - accept_thread is ending"); // printf("Ending accept thread"); return 0; } if (FD_ISSET(that->fd,&(readfds))) // nic jineho nemuze ani nastat { that->lock(); if (that->getFreeClientCount()>0) // pokud je nejake misto volne na pripojeni klienta { client=that->getFreeClient(); int clientidtemp=that->getFreeClientId(); (*client)=(TNodeInfo*)KMemAlloc(sizeof(TNodeInfo)); (*client)->recvbuff=new DA(MAX_SIZE_OF_MESSAGE); (*client)->decompressbuff=new DA(MAX_SIZE_OF_MESSAGE); (*client)->IP=0; (*client)->size_of_next_message=0; (*client)->level=0; (*client)->ping=0; (*client)->profileName[0]=0; (*client)->clientid=clientidtemp; (*client)->fd=0; (*client)->localConnection=0; // printf("CEKAM\n"); if ( ((*client)->fd=accept(that->fd,(struct sockaddr *)&((*client)->client),&sin_size)) ==-1) { GLOBALLOGID(PRIORITY_NEW_CONNECTION,"Server - Accept error"); // printf("Accept Error"); if ((*client)->recvbuff!=NULL) delete((*client)->recvbuff); if ((*client)->decompressbuff!=NULL) delete((*client)->decompressbuff); KMemFree(*client); (*client)=NULL; that->clientsConnected--; } else { if ((*client)!=NULL) // odpoji se velmi rychle { if (/* (that->status!=STATUS_GAME_STARTED) && */(that->getFreeClientCount()==0) )// volne misto na pripojeni az ve hre { GLOBALLOGID(PRIORITY_NEW_CONNECTION, "Server - can not accept any more connections"); if (that->status!=STATUS_ENDING) that->clientDisconnected((*client)->clientid); } else { // printf( "Server - Klient s id %i se pripojil z %S %i, volne: %i, jmeno: %s",(*client)->clientid,inet_ntoa((*client)->client.sin_addr),(*client)->fd,that->getFreeClientCount(),(*client)->profileName); GLOBALLOGID(PRIORITY_NEW_CONNECTION, "Server - Client having id %i has connected from %S %i, volne: %i",(*client)->clientid,inet_ntoa((*client)->client.sin_addr),(*client)->fd,that->getFreeClientCount()); if (that->status!=STATUS_ENDING) KSendMessage(RQUEUE,MSG_NEW_CONNECTION_SYNCHRO1,MOD_NET,MOD_NET,(void*)(*client)); } } } } else // neni misto kam klienta pripojit { GLOBALLOGID(PRIORITY_NEW_CONNECTION, "Server - can not accept any more connections"); // printf("No more space for another client"); SDL_Delay(1000); } that->unlock(); } SDL_Delay(COMM_WAIT_AFTER_SELECT); } GLOBALLOGID(PRIORITY_THREAD, "Server - accept_thread is ending"); } catch (E_8K &e) { GLOBALLOGID(PRIORITY_EXCETION_IN_THREAD, "Exception in accept_thread"); char err[1000]; snprintf(err,999,"%s:%i:%s",e.getFileName(),e.getLineNumber(),e.getDescription()); err[999]=0; GLOBALLOGID(PRIORITY_EXCETION_IN_THREAD, err); if (that->status!=STATUS_ENDING) KSendMessage(RQUEUE,MSG_EXCEPTION_IN_THREAD,MOD_NET,BROADCAST,&e); } return 0; } int TServer::reconnectClient(int id,char * name) { int i; int found=0; TNodeInfo * client; for (i=clients->getNext(-1);i!=-1;i=clients->getNext(i)) { client=(*this->clients)[i]; // Local client cannot reconnect if ((strcmp((*this->clients)[i]->profileName,name)==0) && ((*this->clients)[i]->localConnection==0)) { found=i; break; } } if (found<=0) { this->clientDisconnected(id); return 0; } else { if ((*this->clients)[found]->fd==0) // only if the client was really disconnected - to prevent 2 clients connected with the same name { // poznamenam si jmeno profilu do noveho pripojeni if ((*this->clients)[id]!=NULL) { // strncpy((*this->clients)[id]->profileName,name,K8_MAX_NAME_LEN); // Local client cannot reconnect if ((*this->clients)[id]->localConnection!=1) { (*this->clients)[found]->IP=inet_addr (inet_ntoa((*this->clients)[id]->client.sin_addr)); } else { // therefore it should not get here (*this->clients)[found]->IP=1; } } (*this->clients)[found]->fd=(*this->clients)[id]->fd; // zrusim puvodni zaznam uplne if ((*this->clients)[id]->recvbuff!=NULL) delete((*this->clients)[id]->recvbuff); if ((*this->clients)[id]->decompressbuff!=NULL) delete((*this->clients)[id]->decompressbuff); KMemFree((*this->clients)[id]); (*this->clients)[id]=NULL; this->clientsConnected--; // prenastavim aby mel puvodni clientid /* (*this->clients)[found]=(*this->clients)[id]; (*this->clients)[found]->clientid=found; (*this->clients)[id]=NULL; return found; */ this->announce_right_now=1; // Someone has connected, remove him from the list on the web return found; } else // same client connected 2x { return 0; } } } int TServer::noteClientProfileName(int id,char * name) { int i; int found=0; for (i=clients->getNext(-1);i!=-1;i=clients->getNext(i)) { if (strcmp((*this->clients)[i]->profileName,name)==0) { found=i; break; } } if (found==0) // takovy profil ve hre jeste neni { if ((*this->clients)[id]!=NULL) { strncpy((*this->clients)[id]->profileName,name,K8_MAX_NAME_LEN); } return 0; } else { return i; } } int TServer::isLocal(int id) { return (*this->clients)[id]->localConnection; } int TServer::allocatePort() { if(MyBind(this->fd,(struct sockaddr*)&(this->server),sizeof(struct sockaddr)) == -1) { GLOBALLOGID(PRIORITY_FATAL, "Server - bind error"); THROW(E_8K_NET,"Server - bind error"); // return 0; } else { return 1; } } int TServer::addLocalClient(char profilename[K8_MAX_NAME_LEN]) { this->lock(); // I pri sitove hre! - pro klienta ktery hraje u serveru if (this->getFreeClientCount()>1) // pokud je nejake misto volne na pripojeni klienta (tito nepouzivaji 1 extra na accept) { TNodeInfo ** client; client=this->getFreeClient(); int tempclientid=this->getFreeClientId(); (*client)=(TNodeInfo*)KMemAlloc(sizeof(TNodeInfo)); (*client)->IP=0; (*client)->size_of_next_message=0; (*client)->recvbuff=NULL; // lokalni hrac, buffer neni treba (*client)->decompressbuff=NULL; // lokalni hrac, buffer neni treba (*client)->level=0; (*client)->ping=0; strncpy((*client)->profileName,profilename,K8_MAX_NAME_LEN); (*client)->profileName[K8_MAX_NAME_LEN-1]=0; int a=this->getFreeClientCount(); (*client)->clientid=tempclientid; (*client)->fd=0; (*client)->localConnection=1; // je localni GLOBALLOGID(PRIORITY_NEW_CONNECTION, "Server - A local client having id %i has connected, free space: %i",(*client)->clientid,this->getFreeClientCount()); // printf("\nKlient se pripojil id %i, port %i, volne: %i",(*client)->clientid,(*client)->fd,this->getFreeClientCount()); KSendMessage(RQUEUE,MSG_LOCAL_CLIENT_ADDED,MOD_NET,MOD_NET,*((void**)(&((*client)->clientid)))); KSendMessage(RQUEUE,MSG_NEW_CONNECTION_ACCEPTED,MOD_NET,MOD_NET,*((void**)(&((*client)->clientid)))); this->unlock(); return 1; } else { GLOBALLOGID(PRIORITY_NEW_CONNECTION, "No more space for another client"); // printf("No more space for another client"); this->unlock(); return 0; } } void TServer::endGame() { this->lock(); this->status=STATUS_ENDING; this->unlock(); } void TServer::stopAnnouncingMissingPlayers() { int set=0; for (int i=this->clients->getNext(-1);i!=-1;i=this->clients->getNext(i)) { // client=(*this->clients)[i]; if ( ((*this->clients)[i]->fd==0) && ((*this->clients)[i]->localConnection==0)) { set=1; break; } } if (set==0) if (this->announce==1) this->announce=2; // prestat oznamovat } int TServer::startGame() { // int ok=1; int i; this->lock(); if (this->status==STATUS_RUNNING) // pouze kdyz je pripraven a pouze jednou { for (i=1;imaxClients;i++) { if ((*this->clients)[i]!=NULL) { if ((*this->clients)[i]->localConnection!=1) { (*this->clients)[i]->IP=inet_addr (inet_ntoa((*this->clients)[i]->client.sin_addr)); } else { (*this->clients)[i]->IP=1; // zapamatuji si IP - toto ze je local } } } if (this->announce==1) this->announce=2; // prestat oznamovat if (this->reconnection==0) { this->reconnection=2; // prestat prijimat klienty if (this->localGame==0) { if (this->fd!=0) { MyCloseSocket(this->fd); this->fd=0; } } } this->status=STATUS_GAME_STARTED; this->unlock(); return 1; } else { this->unlock(); return 0; } } int announceGame_thread(void * data) { int j=0,i=ANNOUNCE_TIME-1,ret; // TXMLdata * players; char buff[1024]; TServer* that=(TServer*) data; SDL_SemPost(that->sem); struct hostent *he; he = gethostbyname("kralovstvi.sourceforge.net"); if (he==NULL) // nelze najit, pripojit { return 0; } // priprava zpravy, ktera se posle TRM_map_i * rmmi = (TRM_map_i *)KSendMessage(RQUEUE,MSG_GET_RM_MAP_I,MOD_NET,MOD_RM,NULL); // printf("Map loaded %i, id of map %i",rmmi->isMapLoaded(),rmmi->idOfLoadedMap()); char message[1024]; char message3[1024]; if (rmmi->idOfLoadedMap()>=0) { TMapInfo * info; rmmi->getMapInfo(&info,rmmi->idOfLoadedMap()); j=0; snprintf(message,1024,"GET /maps/main.php?ip=y&p=%d&mn=",info->players); size_t msglen=strlen(message); while (msglen<950) // musi byt mensi, skaci i o vic znaku { if (info->name[j]!=' ') // mezera se musi nahradit, aby to apache prijmul cele { message[msglen]=info->name[j]; msglen++; j++; if (info->name[j]==0) // nic nasledovat stejne uz nemuze break; } else { message[msglen]='%'; message[msglen+1]='2'; message[msglen+2]='0'; msglen=msglen+3; j++; } } message[msglen]=0; } else { strncpy(message,"GET /maps/main.php?ip=y&mn=none&p=0",1024); } delete(rmmi); char * message2="GET /maps/stop.php?ip=y HTTP/1.1\nHost: kralovstvi.sourceforge.net\n\n"; // ukoncovaci zprava size_t msglen=strlen(message); size_t msg2len=strlen(message2); /*******/ struct sockaddr_in server; mysocket fd; j=0; int set=0; int msglen3; server.sin_family = AF_INET; server.sin_port = htons(80); server.sin_addr = *((struct in_addr *)he->h_addr); while (1) { if ((that->status==STATUS_ENDING) && (that->announce!=2)) // pokud server konci break; i++; if ((i==ANNOUNCE_TIME) || (that->announce==2) || (that->announce_right_now==1)) { that->announce_right_now=0; if ((fd = MySocket()) != MY_INVALID_SOCKET ) { if (MyConnect(fd,(struct sockaddr *)&(server),sizeof(struct sockaddr))==0) { TNodeInfo * client; set=0; for (i=that->clients->getNext(-1);i!=-1;i=that->clients->getNext(i)) { client=(*that->clients)[i]; if ( ((*that->clients)[i]->fd==0) && (client->localConnection==0)) { if (set==0) { for (set=0;set<1023;set++) message3[set]=0; set=1; strcpy(message3,message); strcat(message3,"&desc=Join%20as%20"); strcat(message3,client->profileName); } else { strcat(message3,"%20or%20"); strcat(message3,client->profileName); } } } if (set==0) // no client is missing now (none has disconnected yet) { for (set=0;set<1023;set++) message3[set]=0; if (that->description[0]==0) { strcpy(message3,message); strcat(message3,"&desc=Welcome"); } else { strcpy(message3,message); strcat(message3,"&desc="); msglen=strlen(message3); j=0; while (msglen<950) // musi byt mensi, skaci i o vic znaku { if (that->description[j]!=' ') // mezera se musi nahradit, aby to apache prijmul cele { message3[msglen]=that->description[j]; msglen++; j++; if (that->description[j]==0) // nic nasledovat stejne uz nemuze break; } else { message3[msglen]='%'; message3[msglen+1]='2'; message3[msglen+2]='0'; msglen=msglen+3; j++; } } } } strcat(message3," HTTP/1.1\nHost: kralovstvi.sourceforge.net\n\n"); message3[1023]=0; msglen3=strlen(message3); if (that->announce==2) // mam prestat oznamovat { // printf("Koncim s oznamovanim na webu\n"); ret=MySend(fd,message2,msg2len+1); ret=MyRecv(fd,buff,1023); buff[ret]=0; MyCloseSocket(fd); break; } else // poslu zpravu znovu { // printf("Oznamuju na web\n"); ret=MySend(fd,message3,msglen3+1); ret=MyRecv(fd,buff,1023); buff[ret]=0; // printf(buff); MyCloseSocket(fd); } } else { // printf("break"); MyCloseSocket(fd); break; } i=1; } else { // printf("sock"); break; } } SDL_Delay(1000); } return 0; } int announceGameLAN_thread(void * data) { int i=ANNOUNCE_LAN_TIME-1; // TXMLdata * players; TServer* that=(TServer*) data; SDL_SemPost(that->sem); /*******/ // vytvoreni zpravy, ktera se bude posilat (se jmenem mapy a poctem roli) TRM_map_i * rmmi = (TRM_map_i *)KSendMessage(RQUEUE,MSG_GET_RM_MAP_I,MOD_NET,MOD_RM,NULL); // printf("Map loaded %i, id of map %i",rmmi->isMapLoaded(),rmmi->idOfLoadedMap()); char message2[1024]; char descr[1024]; char * message3="

-1

"; TMapInfo * info=NULL; TXMLdata message; if (rmmi->idOfLoadedMap()>=0) { rmmi->getMapInfo(&info,rmmi->idOfLoadedMap()); // j=0; message.setData(info->name,"host",0,"mn",0,NULL); message.setDataInt(info->players,"host",0,"p",0,NULL); message.setData(" ","host",0,"desc",0,NULL); } else { message.setData("none","host",0,"mn",0,NULL); message.setDataInt(0,"host",0,"p",0,NULL); } delete(rmmi); if (that->reconnection==1) { TNodeInfo * client; int set=0; for (i=that->clients->getNext(-1);i!=-1;i=that->clients->getNext(i)) { client=(*that->clients)[i]; if ( ((*that->clients)[i]->fd==0) && (client->localConnection==0)) { if (set==0) { strcpy(descr,"Join as "); strcat(descr,client->profileName); set++; } else { strcat(descr," or "); strcat(descr,client->profileName); set++; } } } if (set!=0) message.setData(descr,"host",0,"desc",0,NULL); else message.setData("x","host",0,"desc",0,NULL); } else { message.setData("x","host",0,"desc",0,NULL); } message.toXML(message2,1024); size_t msglen2=strlen(message2); size_t msglen3=strlen(message3); /*******/ sockaddr_in udp_announce; udp_announce.sin_family = AF_INET; udp_announce.sin_addr.s_addr = htonl(INADDR_ANY); udp_announce.sin_port = htons( DEFAULT_UDP_PORT ); mysocket fd = MyUDPSocket(); int on=1; // broadcast if ( setsockopt(fd, SOL_SOCKET ,SO_REUSEADDR,(char *) &on,sizeof(on) ) == -1) { // printf("Prob1"); MyCloseSocket(fd); return 0; } if ( setsockopt(fd, SOL_SOCKET ,SO_BROADCAST,(char *) &on,sizeof(on) ) == -1) { // printf("Prob1"); MyCloseSocket(fd); return 0; } // alokace portu if ( MyBind( fd, (sockaddr*) &udp_announce, sizeof(udp_announce) ) == -1 ) { // printf("Prob2"); MyCloseSocket(fd); return 0; } sockaddr_in announce_message; announce_message.sin_family =AF_INET; announce_message.sin_port = htons( DEFAULT_UDP_PORT ); announce_message.sin_addr.s_addr = INADDR_BROADCAST; /********/ mysocklen_t size_am=sizeof(announce_message); while (1) { if ((that->status==STATUS_ENDING) && (that->announce!=2)) // pokud server konci break; i++; if ((i==(ANNOUNCE_LAN_TIME)) || (that->announce==2)) // uz mam odeslat, nebo prestat vysilat { if (that->announce==1) // opakuju zpravu { // printf("Odesilam informace o moji hre\n"); int ret; if ( (ret=MySendto(fd,message2,(int)msglen2+1,0,(sockaddr*) &announce_message,size_am)) == -1) { MyCloseSocket(fd); return 0; }; i=0; } else // jinak mam prestat vysilat, oznamim okoli, ze sem se uz pripojit neda { // printf("Odesilam informace o zruseni moji hry\n"); if ( MySendto(fd,message3,(int)msglen3+1,0,(sockaddr*) &announce_message,size_am) == -1) { MyCloseSocket(fd); return 0; }; i=0; // MyRecvfrom(fd,buff,1024,0,(sockaddr*) &announce_message2,&size_am2); // printf("Server: %s IP:%s \n",buff,inet_ntoa(announce_message2.sin_addr) ); MyCloseSocket(fd); return 0; } // MyRecvfrom(fd,buff,1024,0,(sockaddr*) &announce_message2,&size_am2); // printf("Server: %s IP:%s \n",buff, inet_ntoa(announce_message2.sin_addr) ); } SDL_Delay(1000); } MyCloseSocket(fd); return 0; } int TServer::prepare() { if (this->localGame==0) // pokud je to sitova hra pro vice pocitacu { // this->start(); // spustim sit KSendMessage(RQUEUE,MSG_NET_START_NETWORK,MOD_NET,MOD_NET,NULL); this->createMySocket(); // vytvorim socket this->server.sin_addr.s_addr = htonl(INADDR_ANY); // nasloucham vsemu this->server.sin_family = AF_INET; this->server.sin_port = htons(this->port); this->allocatePort(); // bind() this->install(); // listen() this->sem=SDL_CreateSemaphore(0); this->acceptThread=SDL_CreateThread(accept_thread, (void*)this); SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); // while (this->status!=STATUS_THREAD_IS_RUNNING) { } this->status=STATUS_PREPARE; // priprava this->sem=SDL_CreateSemaphore(0); this->recvThread=SDL_CreateThread(recvServer_thread, (void*)this); SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); #if (PING_ENABLED==1) this->status=STATUS_PREPARE; // priprava this->sem=SDL_CreateSemaphore(0); this->pingThread=SDL_CreateThread(pingServer_thread, (void*)this); SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); #endif TRM_conf_i * rmci = (TRM_conf_i *)KSendMessage(RQUEUE,MSG_GET_RM_CONF_I,MOD_NET,MOD_RM,NULL); int lup=rmci->getLastUsedProfile(); if (lup>0) { DA * profiles; rmci->getProfiles(&profiles); this->announce=(*profiles)[lup]->announce; // Announce has to be set at least to 1 even for LAN announcing! this->announceold=(*profiles)[lup]->announce; // Announce has to be set at least to 1 even for LAN announcing! delete (rmci); if (this->announce==1) // po netu jen kdyz je zaskrtnuto { this->status=STATUS_PREPARE; // priprava this->sem=SDL_CreateSemaphore(0); this->announceThread=SDL_CreateThread(announceGame_thread, (void*)this); SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); this->status=STATUS_PREPARE; // priprava this->sem=SDL_CreateSemaphore(0); this->announceThread=SDL_CreateThread(announceGameLAN_thread, (void*)this); SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); } } } // vlakna musi bezet vzdy this->status=STATUS_PREPARE; // priprava this->sem=SDL_CreateSemaphore(0); this->sendThread=SDL_CreateThread(sendInThread, (void*)this); SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); // while (this->status!=STATUS_THREAD_IS_RUNNING) { } this->status=STATUS_RUNNING; // spusteno return 1; } void TServer::showMeClientsInfo(DA**clients) { (*clients)=this->clients; } void TServer::setPing(int cid) { #if (PING_ENABLED==1) this->lock(); if ((*this->clients)[cid]!=NULL) (*this->clients)[cid]->ping=SDL_GetTicks(); this->unlock(); #endif } int pingServer_thread(void * data) { TServer * that=(TServer *) data; try { timeval timeout; timeout.tv_sec=0; timeout.tv_usec=0; int i; SDL_SemPost(that->sem); TPackage ping(MSG_NET_PING); while (1) { for (i=0;i<2;i++) { if (that->status==STATUS_ENDING) // pokud server konci { GLOBALLOGID(PRIORITY_THREAD, "Client - recvClient_thread is ending"); // printf("Ending recv thread"); return 0; } SDL_Delay(that->ping_time*1000); } that->lock(); for (i=1;imaxClients;i++) { if (((*that->clients)[i]!=NULL) && ((*that->clients)[i]->fd!=0) && ((*that->clients)[i]->ping!=0)) { if (SDL_GetTicks()>((*that->clients)[i]->ping+that->max_timeout*1000)) { that->unlock(); if (that->status!=STATUS_ENDING) KSendMessage(RQUEUE,MSG_CLIENT_HAS_DISCONNECTED,MOD_NET,BROADCAST,*((void**)(&i))); else return 0; that->lock(); // printf("Ping - Timeout"); that->clientDisconnected(i); } } } that->unlock(); ping.send(TO_SERVER,TO_NET_CLIENTS,MOD_NET); } } catch (E_8K &e) { GLOBALLOGID(PRIORITY_EXCETION_IN_THREAD, "Exception in pingClient_thread"); char err[1000]; snprintf(err,999,"%s:%i:%s",e.getFileName(),e.getLineNumber(),e.getDescription()); err[999]=0; GLOBALLOGID(PRIORITY_EXCETION_IN_THREAD, err); if (that->status!=STATUS_ENDING) KSendMessage(RQUEUE,MSG_EXCEPTION_IN_THREAD,MOD_NET,BROADCAST,&e); } return 0; } void TServer::startPing(int cid) { #if (PING_ENABLED==1) this->lock(); (*this->clients)[cid]->ping=SDL_GetTicks(); this->unlock(); #endif } void TServer::changeDescription(char * description) { strncpy(this->description,description,49); this->description[49]=0; } TServer::TServer(int maxClients,int localGame,int port,int reconnect) { this->fd=0; this->announce_right_now=0; strcpy(this->description,"Welcome"); this->announce=0; this->reconnection=reconnect; this->port=port; this->localGame=localGame; this->status=STATUS_NOT_INICIALIZED; this->maxClients=maxClients+2; // od 1 do maxClients a jeden extra if (this->maxClients>=MAX_CLIENTS) this->maxClients=MAX_CLIENTS-1; this->clientsConnected=0; this->pingThread=NULL; this->clients=new DA(this->maxClients,1); for (int i=1;imaxClients;i++) (*this->clients)[i]=NULL; } TServer::~TServer() { if (this->announce==1) this->announce=2; // prestat oznamovat this->queue->shutdownQueue(); this->status=STATUS_ENDING; // pockat az vsechny vlakna skonci if (this->localGame==0) { if (this->pingThread!=NULL) SDL_WaitThread(this->pingThread,NULL); SDL_WaitThread(this->acceptThread,NULL); SDL_WaitThread(this->recvThread,NULL); if (announce>0) SDL_WaitThread(this->announceThread,NULL); } SDL_WaitThread(this->sendThread,NULL); if (this->localGame==0) { if (this->fd!=0) { MyCloseSocket(this->fd); this->fd=0; } } for (int i=0;imaxClients;i++) { if ((*this->clients)[i]!=NULL) { if((*this->clients)[i]->fd!=0) { MyCloseSocket((*this->clients)[i]->fd); (*this->clients)[i]->fd=0; } if ((*this->clients)[i]->recvbuff!=NULL) delete((*this->clients)[i]->recvbuff); if ((*this->clients)[i]->decompressbuff!=NULL) delete((*this->clients)[i]->decompressbuff); KMemFree((*this->clients)[i]); } } delete(this->clients); if (this->localGame==0) { // this->clean(); } } }