/** ****************************************************************************** @file /net/locator.cpp @brief Trida hledajici okolni hry @author Vta @version 1.0 ******************************************************************************/ #include "net/locator.h" #ifndef WIN32 #include #endif namespace net { int TLocator::start() { if (this->net_running==0) { this->net_running=1; return MyStartNetwork(); } return 0; } int TLocator::clean() { return MyStopNetwork(); } void TLocator::stopSearching() { this->lock(); if (this->was_searched==2) { this->was_searched=1; // prestanu hledat } if (this->was_searched==1) { // this->searchLANThread=SDL_CreateThread(searchGameLAN_thread, (void*)this); } this->unlock(); } void TLocator::seachGames() { this->lock(); if (was_searched>0) // uz byla sit sputena { if (this->fdweb!=0) MyCloseSocket(this->fdweb); // osetreni blokujicich socketu this->status=STATUS_PREPARE; this->unlock(); // aby vlakno dobehlo SDL_WaitThread(this->searchThread,NULL); // kdyby nahodou jeste vlakno nedobehlo this->lock(); this->status=STATUS_RUNNING; this->fdweb=0; } else { KSendMessage(RQUEUE,MSG_NET_START_NETWORK,MOD_NET,MOD_NET,NULL); // prvni spousteni site } this->sem=SDL_CreateSemaphore(0); this->searchThread=SDL_CreateThread(searchGame_thread, (void*)this); // search 8KWW SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); if (was_searched<2) // tzn. ze uz vlakno nebezi, jinak by se poustelo 2x { if (was_searched==1) SDL_WaitThread(this->searchLANThread,NULL); // vlakno uz nekdy bezelo, pro jistotu int i; //smazu predchozi zaznamy, pozdeji se vyplni znovu (aby tam nezustavalo "smeti") for (i=this->LANgames->getNext(-1);i!=-1;i=this->LANgames->getNext(i)) { KMemFree((*this->LANgames)[i]); (*this->LANgames)[i]=NULL; } this->sem=SDL_CreateSemaphore(0); this->searchLANThread=SDL_CreateThread(searchGameLAN_thread, (void*)this); SDL_SemWait(this->sem); SDL_DestroySemaphore(this->sem); } was_searched=2; // uz se vlakno pustilo this->unlock(); } int searchGame_thread(void * data) { TLocator* that=(TLocator*) data; try { SDL_SemPost(that->sem); int j=0,ret; int games; TXMLdata * players; char * message="GET /maps/search.php HTTP/1.1\nHost: kralovstvi.sourceforge.net\n\n"; // zprava na zjisteni her char buff[1024]; struct sockaddr_in server; if ((that->fdweb = MySocket()) != MY_INVALID_SOCKET ) { struct hostent *he; he = gethostbyname("kralovstvi.sourceforge.net"); // adresa weboveho serveru if (he==NULL) // nelze najit { if (that->status!=STATUS_ENDING) // napr. pri padu, pro jistotu, tim se nic nezkazi { KSendMessage(RQUEUE,MSG_NET_OTHER_GAMES_INFO,MOD_NET,BROADCAST,that->games); } return 0; } server.sin_family = AF_INET; server.sin_port = htons(80); server.sin_addr = *((struct in_addr *)he->h_addr); #ifdef WIN32 ULONG NonBlock = 1; // !=0 je spusteno if (ioctlsocket(that->fdweb, FIONBIO, &NonBlock) == -1) #else if (fcntl(that->fdweb, F_SETFD, O_NONBLOCK)==-1) #endif { return 0; } fd_set conn; fd_set readfds; fd_set writefds; FD_ZERO(&(conn)); FD_ZERO(&(readfds)); FD_ZERO(&(writefds)); FD_SET(that->fdweb, &conn); FD_SET(that->fdweb, &readfds); FD_SET(that->fdweb, &writefds); timeval timeout; timeout.tv_sec=10; timeout.tv_usec=0; that->lock(); MyConnect(that->fdweb,(struct sockaddr *)&(server),sizeof(struct sockaddr)); // non blocking! that->unlock(); // if (MyConnect(that->fdweb,(struct sockaddr *)&(server),sizeof(struct sockaddr))==0) { #ifdef WIN32 MySelect (0, NULL, &conn,NULL, &timeout); // Windows ignoruje a chce int #else MySelect (that->fdweb+1, NULL, &conn,NULL, &timeout); #endif if (FD_ISSET(that->fdweb,&conn)) { if (that->status==STATUS_RUNNING) { timeout.tv_sec=5; #ifdef WIN32 MySelect (0, NULL,&writefds,NULL, &timeout); // Windows ignoruje a chce int #else MySelect (that->fdweb+1, NULL,&writefds,NULL, &timeout); #endif if (FD_ISSET(that->fdweb,&writefds)) { that->lock(); ret=MySend(that->fdweb,message,strlen(message)+1); // odeslu pozadavek that->unlock(); #ifdef WIN32 MySelect (0, &readfds, NULL,NULL, &timeout); // Windows ignoruje a chce int #else MySelect (that->fdweb+1, &readfds, NULL,NULL, &timeout); #endif if (FD_ISSET(that->fdweb,&readfds)) { that->lock(); ret=MyRecv(that->fdweb,buff,1023); // nactu // printf("Ret: %i, buff: %s",ret,buff); if (ret>=0) buff[ret]=0; else buff[0]=0; while ((buff[j]!=0) && (buff[j]!='<')) // preskocim hlavicku j++; players=new(TXMLdata); players->readChar(buff+j); // nactu XML games=players->getNumId(); // pocet oznamovanych her for (j=1;j<=games;j++) // prekopiruju novy obsah { if ((*that->games)[j]==NULL) (*that->games)[j]=(TGames*)KMemAlloc(sizeof(TGames)*80); players->getData((*that->games)[j]->ip,16,"host",j,"ip",0,NULL); players->getData((*that->games)[j]->mapname,36,"host",j,"mn",0,NULL); players->getData((*that->games)[j]->description,50,"host",j,"desc",0,NULL); (*that->games)[j]->players=players->getDataInt("host",j,"p",0,NULL); } j++; if (games==0) j--; while ((*that->games)[j]!=NULL) // vynuluju zbytek { KMemFree((*that->games)[j]); (*that->games)[j]=NULL; j++; } // printf(buff); MyCloseSocket(that->fdweb); that->fdweb=0; delete(players); if (that->status!=STATUS_ENDING) // napr. pri padu, pro jistotu, tim se nic nezkazi { // printf("Odesilam data %s",(*that->games)[1]->ip); that->unlock(); KSendMessage(RQUEUE,MSG_NET_OTHER_GAMES_INFO,MOD_NET,BROADCAST,that->games); } else { that->unlock(); } } else // nedoslo k prijmuti { int j=1; while ((*that->games)[j]!=NULL) // vynuluju zbytek { KMemFree((*that->games)[j]); (*that->games)[j]=NULL; j++; } KSendMessage(RQUEUE,MSG_NET_OTHER_GAMES_INFO,MOD_NET,BROADCAST,that->games); } } else // nedoslo k odeslani { int j=1; while ((*that->games)[j]!=NULL) // vynuluju zbytek { KMemFree((*that->games)[j]); (*that->games)[j]=NULL; j++; } KSendMessage(RQUEUE,MSG_NET_OTHER_GAMES_INFO,MOD_NET,BROADCAST,that->games); } } else { // that->fdweb=0; } } } that->lock(); if (that->fdweb!=0) { MyCloseSocket(that->fdweb); that->fdweb=0; } that->unlock(); } else { that->lock(); that->fdweb=0; that->unlock(); } } catch (E_8K &e) { if (that->status!=STATUS_ENDING) KSendMessage(RQUEUE,MSG_EXCEPTION_IN_THREAD,MOD_NET,BROADCAST,&e); } return 0; } int searchGameLAN_thread(void * data) { TLocator* that=(TLocator*) data; try { SDL_SemPost(that->sem); sockaddr_in announce_message; // zjisteni adresy odesilatele mysocklen_t size_am=sizeof(announce_message); sockaddr_in udp_announce; // otevreni portu 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(); if ( setsockopt(fd, SOL_SOCKET ,SO_REUSEADDR,(char *) &udp_announce,sizeof(udp_announce) ) == -1) { // printf("Prob1"); that->was_searched=1; // search bylo jiz zapnuto, ale toto vlakno uz skoncilo MyCloseSocket(fd); return 0; } if ( MyBind( fd, (sockaddr*) &udp_announce, sizeof(udp_announce) ) == -1 ) { MyCloseSocket(fd); // printf("Prob2"); that->was_searched=1; // search bylo jiz zapnuto, ale toto vlakno uz skoncilo return 0; } char buff[1024]; fd_set readfds; // select int s; // select int i,found; // pomocna mysocket maxDescriptor=fd; // socket na select timeval timeout; timeout.tv_sec=0; timeout.tv_usec=0; TXMLdata found_game; // prijem XML zparvy int players; // nova hra char * server_ip=NULL; // prevedeni IP adresy while (1) { if ( (that->status==STATUS_ENDING) || (that->was_searched<2) ) { break; } FD_ZERO(&(readfds)); // vynuluji FD_SET(fd, &(readfds)); // hlida jen fd - na accept #ifdef WIN32 s=MySelect (0, &(readfds), NULL,NULL, &timeout); #else s=MySelect (maxDescriptor+1, &(readfds), NULL,NULL, &timeout); #endif if (s!=0) { if (FD_ISSET(fd,&(readfds))) { if (MyRecvfrom(fd,buff,1024,0,(sockaddr*) &announce_message,&size_am)<0) { break; // while } else { // printf(buff); found_game.readChar(buff); players=found_game.getDataInt("host",0,"p",0,NULL); server_ip=inet_ntoa(announce_message.sin_addr); if (players>=0) // hra je oznamovnana { found=0; for (i=that->LANgames->getNext(-1);i!=-1;i=that->LANgames->getNext(i)) { if (strcmp((*that->LANgames)[i]->ip,server_ip)==0) { found=1; break; // for } } if (found==0) { i=1; while ((*that->LANgames)[i]!=NULL) { i++; } (*that->LANgames)[i]=(TGames*)KMemAlloc(sizeof(TGames)*1); strcpy((*that->LANgames)[i]->ip,server_ip); (*that->LANgames)[i]->players=players; found_game.getData((*that->LANgames)[i]->mapname,36,"host",0,"mn",0,NULL); found_game.getData((*that->LANgames)[i]->description,36,"host",0,"desc",0,NULL); // printf("Zprava o novem serveru z %s \n",server_ip); KSendMessage(RQUEUE,MSG_NET_LAN_GAMES_INFO,MOD_NET,BROADCAST,that->LANgames); // printf("Client sent me (NEW!): %s, its IP: %s\n",buff, server_ip); } else { // printf("Client sent me (OLD): %s, its IP: %s\n",buff, server_ip); } } else // hra je stahovana z oznamovani { found=0; for (i=that->LANgames->getNext(-1);i!=-1;i=that->LANgames->getNext(i)) { if (strcmp((*that->LANgames)[i]->ip,server_ip)==0) { found=i; break; // for } } if (found>0) // pouze pokud ji nasel { KMemFree((*that->LANgames)[found]); (*that->LANgames)[found]=NULL; // printf("Client sent me (NEW!): %s, its IP: %s\n",buff, server_ip); // printf("Zprava o zruseni serveru z %s \n",server_ip); KSendMessage(RQUEUE,MSG_NET_LAN_GAMES_INFO,MOD_NET,BROADCAST,that->LANgames); } else { // printf("Client sent me (OLD): %s, its IP: %s\n",buff, server_ip); } } } } } SDL_Delay(1000); } that->was_searched=1; // search bylo jiz zapnuto, ale toto vlakno uz skoncilo MyCloseSocket(fd); } catch (E_8K &e) { if (that->status!=STATUS_ENDING) KSendMessage(RQUEUE,MSG_EXCEPTION_IN_THREAD,MOD_NET,BROADCAST,&e); } return 0; } TLocator::TLocator() { this->status=STATUS_RUNNING; this->net_running=0; this->games=new (DA)(20,1); this->LANgames=new (DA)(20,1); if ( (this->mutex=SDL_CreateMutex()) == NULL ) { GLOBALLOGID(PRIORITY_FATAL,"Can not create a mutext"); THROW(E_8K_NET,"Can not create a mutext"); } was_searched=0; } TLocator::~TLocator() { this->status=STATUS_ENDING; this->lock(); if (this->fdweb!=0) { MyCloseSocket(this->fdweb); // aby to odpadlo rovnou a aby se to doopravdy uzavrelo } this->unlock(); if (was_searched>0) { SDL_WaitThread(this->searchThread,NULL); SDL_WaitThread(this->searchLANThread,NULL); } SDL_DestroyMutex(mutex); if (net_running==1) this->clean(); int i; if (this->games!=NULL) { for (i=this->games->getNext(-1);i!=-1;i=this->games->getNext(i)) KMemFree((*this->games)[i]); delete (this->games); } if (this->LANgames!=NULL) { for (i=this->LANgames->getNext(-1);i!=-1;i=this->LANgames->getNext(i)) KMemFree((*this->LANgames)[i]); delete (this->LANgames); } } void TLocator::lock(void) { if ( SDL_mutexP(this->mutex) < 0 ) { GLOBALLOGID(PRIORITY_FATAL, "Can not lock the mutext"); THROW(E_8K_NET,"Can not lock the mutext"); } GLOBALLOGID(PRIORITY_MUTEX,"Lock %i\n",SDL_ThreadID()); // printf("<"); } void TLocator::unlock(void) { if ( SDL_mutexV(this->mutex) < 0 ) { GLOBALLOGID(PRIORITY_FATAL, "Can not unlock the mutext"); THROW(E_8K_NET,"Can not unlock the mutext"); } GLOBALLOGID(PRIORITY_MUTEX,"Unlock %i\n",SDL_ThreadID()); // printf(">"); } }