gameserver.cpp

Go to the documentation of this file.
00001 /*
00002 #########################################################################
00003 #
00004 #  This file is part of trustyRC.
00005 #
00006 #  trustyRC, fully modular IRC robot 
00007 #  Copyright (C) 2006-2008 Nicoleau Fabien 
00008 #
00009 #  trustyRC is free software: you can redistribute it and/or modify
00010 #  it under the terms of the GNU General Public License as published by
00011 #  the Free Software Foundation, either version 3 of the License, or
00012 #  (at your option) any later version.
00013 #
00014 #  trustyRC is distributed in the hope that it will be useful,
00015 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 #  GNU General Public License for more details.
00018 #
00019 #  You should have received a copy of the GNU General Public License
00020 #  along with trustyRC.  If not, see <http://www.gnu.org/licenses/>.
00021 #
00022 #########################################################################
00023 */
00024 
00029 #include "gameserver.h"
00030 
00034 GameServer::GameServer(BotKernel*b)
00035 {
00036         this->author = "eponyme";
00037         this->description = "Provides tools to query game servers";
00038         this->version = VERSION;
00039         this->name = "gameserver";
00040         this->bindFunction("q3",IN_COMMAND_HANDLER,"q3",0,10);
00041         this->bindFunction("warsow",IN_COMMAND_HANDLER,"warsow",0,10);
00042         this->bindFunction("wsw",IN_COMMAND_HANDLER,"warsow",0,10);
00043         this->bindFunction("hl",IN_COMMAND_HANDLER,"hl",0,10);
00044         this->bindFunction("cs",IN_COMMAND_HANDLER,"hl",0,10);
00045 }
00046 
00053 long GameServer::strToLong(string str) 
00054 {
00055    char buffer[4];
00056    long result;
00057    for(unsigned int i = 0 ; i < 4 ; i ++ )
00058    {
00059       buffer[i] = str[i] ;
00060    }
00061    result= strtoll(buffer,NULL,10);
00062    return result;
00063 }
00064 
00073 string GameServer::getHLstring(unsigned int * index,char*datas) {
00074    string buffer = "";
00075    while(datas[*index] != '\x00')
00076    {
00077       buffer += datas[(*index)];
00078       (*index)++;
00079    }
00080    (*index)++;
00081    return buffer;
00082 }
00083 
00092 char GameServer::getHLbyte(unsigned int*index,char*datas) {
00093    (*index)++;
00094    return datas[(*index)-1];
00095 }
00096 
00104 string GameServer::getHLlong(unsigned int*index,char*datas) {
00105    string buffer = "";
00106    for(unsigned int i = 0 ; i < 4 ; i ++ ) {
00107       buffer[i] = datas[(*index)+i];
00108    }
00109    (*index)+=4;
00110    return buffer;
00111 }
00112 
00120 bool GameServer::getHL1Players(vector<string>*players,char*datas) {
00121    players->clear();
00122    unsigned int index = 4 ;
00123    if ( getHLbyte(&index,datas) != '\x44' )
00124       return false;
00125    int nbPlayers = (int)getHLbyte(&index,datas) ;
00126    for(int i = 0 ; i < nbPlayers ; i ++ ) {
00127       index++;
00128       players->push_back("\""+getHLstring(&index,datas)+"\"");   
00129       index += 8;
00130    }
00131    return true;
00132 }
00133 
00141 bool GameServer::getHL1Challenge(string*challenge,char*datas) {
00142    unsigned int index=4;
00143    if ( getHLbyte(&index,datas) != '\x41' )
00144       return false;
00145    *challenge = getHLlong(&index,datas) ;
00146    return true;
00147 }
00148 
00156 bool GameServer::getHL1Infos(map<string,string>* settings,char*datas) {
00157    unsigned int index = 5;
00158    if(datas[4] == '\x6d') { // HL1 support
00159       (*settings)["ip"] = getHLstring(&index,datas);
00160       (*settings)["hostname"] = getHLstring(&index,datas);
00161       (*settings)["map"] = getHLstring(&index,datas);
00162       (*settings)["gamedir"] = getHLstring(&index,datas);
00163       (*settings)["gamedesc"] = getHLstring(&index,datas);
00164       (*settings)["players"] = getHLbyte(&index,datas);
00165       (*settings)["maxplayers"] = getHLbyte(&index,datas);
00166       (*settings)["version"] = getHLbyte(&index,datas);
00167       (*settings)["dedicated"] = getHLbyte(&index,datas);
00168       (*settings)["os"] = getHLbyte(&index,datas);
00169       (*settings)["pass"] = getHLbyte(&index,datas);
00170       (*settings)["ismod"] = getHLbyte(&index,datas);
00171       (*settings)["urlinfo"] = getHLstring(&index,datas);
00172       (*settings)["urldl"] = getHLstring(&index,datas);
00173       (*settings)["unused"] = getHLstring(&index,datas);
00174       (*settings)["modversion"] = getHLlong(&index,datas);
00175       (*settings)["modsize"] = getHLlong(&index,datas);
00176       (*settings)["svonly"] = getHLbyte(&index,datas);
00177       (*settings)["cidll"] = getHLbyte(&index,datas);
00178       (*settings)["secure"] = getHLbyte(&index,datas);
00179       (*settings)["numbots"] = getHLbyte(&index,datas);
00180       return true;
00181    }
00182    else {
00183       return false;
00184    }
00185 }
00186 
00192 string GameServer::getQ3GameType(string number)
00193 {
00194    if ( number == "0" )
00195       return "FFA";
00196    else if ( number == "1" )
00197       return "1v1";
00198    else if ( number == "2" )
00199       return "CB TDM";
00200    else if ( number == "3" )
00201       return "TDM";
00202    else if ( number == "4" )
00203       return "CTF" ;
00204    else if ( number == "5" )
00205       return "CA" ;
00206    else if ( number == "6" )
00207       return "FF TDM" ;
00208    else
00209       return "unknown";
00210 }
00211 
00220 bool GameServer::parseWSWinfos(map<string,string>* settings,vector<string>* players,char* datas)
00221 {
00222    unsigned int index,rindex;
00223    vector<string> split = Tools::stringToVector(datas,"\x0a",1);
00224    if(split.size()>= 1 )
00225    {
00226       vector<string>sets = Tools::stringToVector(split[0],"\\",0);
00227       for ( unsigned int i = 1 ; i < sets.size() ; i +=2 ) {
00228          (*settings)[sets[i]] = sets[i+1]  ;
00229       }
00230       for (unsigned int i = 1 ; i < (split.size() -1); i ++ )  {
00231          index = split[i].find("\"") ;
00232          rindex = split[i].rfind("\"");
00233          (*players).push_back(Tools::parseQ3Colors(split[i].substr(index,rindex-index+1)));
00234       }
00235       return true;
00236    }
00237    return false;
00238 }
00239 
00248 bool GameServer::parseQ3infos(map<string,string>* settings,vector<string>* players,char* datas)
00249 {
00250    vector<string> split = Tools::stringToVector(datas,"\x0a",1);
00251    if(split.size()>= 1 )
00252    {
00253       vector<string>sets = Tools::stringToVector(split[0],"\\",0);
00254       for ( unsigned int i = 1 ; i < sets.size() ; i +=2 ) {
00255          (*settings)[sets[i]] = sets[i+1]  ;
00256       }
00257       for (unsigned int i = 1 ; i < split.size() ; i ++ )  {
00258          (*players).push_back(Tools::parseQ3Colors(split[i].substr(split[i].find("\""))));
00259       }
00260       return true;
00261    }
00262    return false;
00263 }
00264 
00274 bool GameServer::sendQuery(string ip,string port,int* sock,string query) 
00275 {
00276    sockaddr_in sockname;
00277    sockname.sin_family=AF_INET; 
00278         sockname.sin_addr.s_addr=inet_addr(ip.c_str());
00279    sockname.sin_port=htons(Tools::strToInt(port.c_str()));
00280    (*sock) = socket(AF_INET,SOCK_DGRAM,0);
00281    if ( (*sock) <0 ) {
00282       return false;
00283    }
00284    else {
00285       if (sendto((*sock),query.c_str(),strlen(query.c_str()),0,(struct sockaddr*)&sockname,sizeof(sockname))<0) {
00286          return false;
00287       } 
00288       else {
00289          return true;
00290       }
00291    }
00292 }
00293 
00301 string GameServer::getResult(int sock,char*buffer) 
00302 {
00303    int nbChars;
00304    fd_set readfds;
00305    struct timeval tv;
00306    tv.tv_sec = 3;
00307    tv.tv_usec = 0;
00308    FD_ZERO(&readfds);
00309    FD_SET(sock, &readfds);
00310    if (select(sock+1, &readfds, NULL, NULL, &tv) >=0 ) {
00311       if (FD_ISSET(sock, &readfds)) { 
00312               nbChars=recv(sock,buffer,MAX_CHARS,0);
00313          if ((nbChars > -1) && (nbChars <= MAX_CHARS) ) {
00314             buffer[nbChars] = '\0';
00315             return "0";
00316          }
00317          else {
00318             return "Read error" ;
00319          }
00320       }
00321       else {
00322          return "No response" ;
00323       }
00324    }
00325    else {   
00326       return "Socket down" ;
00327    }
00328 }
00329 
00330 extern "C"
00331 {
00332         Plugin *contruct_gameserver(BotKernel*b)
00333         {
00334                 return new GameServer(b);
00335         }
00336         void destroy_gameserver(Plugin*p)
00337         {
00338                 delete p;
00339         }
00340         bool q3 (Message*m,Plugin*p,BotKernel*b)
00341         {
00342       GameServer * gs = (GameServer*) p;
00343       char buffer[MAX_CHARS];
00344       map<string,string> settings;
00345       vector<string> players,split;   
00346       string result,query,message;
00347       int sock;
00348       if ( m->isPublic() && (m->nbParts() == 5) ) {
00349          split = Tools::stringToVector(m->getPart(4),":",0);
00350                    if ( split.size() == 2 ) {
00351             query = "\xff\xff\xff\xffgetstatus";
00352             if (gs->sendQuery(split[0],split[1],&sock,query)) {
00353                result = gs->getResult(sock,buffer);
00354                if ( result == "0" ) {
00355                   if (gs->parseQ3infos(&settings,&players,buffer) ) {
00356                      message =  ""+Tools::parseQ3Colors(settings["sv_hostname"]) + " => Q3 " + gs->getQ3GameType(settings["g_gametype"]) + " (" + settings["gameversion"] +") on " +settings["mapname"] +" Players:"+Tools::intToStr(players.size())+ "/"+settings["sv_maxclients"] + " ("+Tools::vectorToString(players,",",0)+") blue:" + settings["Score_Blue"]+" red:"+settings["Score_Red"]+ " Time Left:"+settings["Score_Time"]+ " pb:"+settings["sv_punkbuster"]+ " pv:"+settings["g_needpass"]+"";
00357                   }
00358                   else {
00359                      message = "* Parse error *" ;
00360                   }  
00361                }
00362                else {
00363                   message = result ;
00364                } 
00365             }
00366             else {
00367                message = "* Error, unable to send querry *";
00368             }
00369             b->send( IRCProtocol::sendMsg(m->getSource(),message) ) ;
00370             close(sock);           
00371          }
00372       }
00373       return true;
00374         }
00375         bool warsow (Message*m,Plugin*p,BotKernel*b)
00376         {
00377       GameServer * gs = (GameServer*) p;
00378       char buffer[MAX_CHARS];
00379       map<string,string> settings;
00380       vector<string> players,split;   
00381       string result,query,message;
00382       int sock;
00383       if ( m->isPublic() && (m->nbParts() == 5) ) {
00384          split = Tools::stringToVector(m->getPart(4),":",0);
00385                    if ( split.size() == 2 ) {
00386             query = "\xff\xff\xff\xffgetinfo";
00387             if (gs->sendQuery(split[0],split[1],&sock,query)) {
00388                result = gs->getResult(sock,buffer);
00389                if ( result == "0" ) {
00390                   if (gs->parseWSWinfos(&settings,&players,buffer) ) {
00391                      message =  ""+Tools::parseQ3Colors(settings["sv_hostname"]) + " => WSW " + settings["g_gametype"] + " (" + settings["version"] +") on " +settings["mapname"] +" Players:"+Tools::intToStr(players.size())+ "/"+settings["sv_maxclients"] + " ("+Tools::vectorToString(players,",",0)+") " + settings["g_match_score"]+ " Time Left:"+settings["g_match_time"]+ " pure:"+settings["sv_pure"]+ " pv:"+settings["g_needpass"]+"";
00392                   }
00393                   else {
00394                      message = "* Parse error *" ;
00395                   }  
00396                }
00397                else {
00398                   message = result ;
00399                } 
00400             }
00401             else {
00402                message = "* Error, unable to send querry *";
00403             }
00404             b->send( IRCProtocol::sendMsg(m->getSource(),message) ) ;
00405             close(sock);           
00406          }
00407       }
00408       return true;
00409         }
00410         bool hl (Message*m,Plugin*p,BotKernel*b)
00411         {
00412       GameServer * gs = (GameServer*) p;
00413       char buffer[MAX_CHARS];
00414       map<string,string> settings;
00415       vector<string> players,split;   
00416       string result,query,message,challenge;
00417       int sock;
00418       if ( m->isPublic() && (m->nbParts() == 5) ) {
00419          split = Tools::stringToVector(m->getPart(4),":",0);
00420                    if ( split.size() == 2 ) {
00421             query = "\xFF\xFF\xFF\xFF\x54\x53\x6F\x75\x72\x63\x65\x20\x45\x6E\x67\x69\x6E\x65\x20\x51\x75\x65\x72\x79\x00";
00422             if (gs->sendQuery(split[0],split[1],&sock,query)) {
00423                result = gs->getResult(sock,buffer);
00424                if ( result == "0" ) {
00425                   if (!gs->getHL1Infos(&settings,buffer) ) {
00426                      message = "Error, only HL1 servers are supported" ;
00427                   }  
00428                   else {
00429                      query = "\xFF\xFF\xFF\xFF\x57";
00430                      if (gs->sendQuery(split[0],split[1],&sock,query)) {
00431                         result = gs->getResult(sock,buffer);
00432                         if ( result == "0" ) {
00433                            if ( !gs->getHL1Challenge(&challenge,buffer) ) {
00434                               message =  "* Parse error *" ;
00435                            }
00436                            else {
00437                               query = "\xFF\xFF\xFF\xFF\x55";
00438                               for (unsigned int i = 0 ; i < 4 ; i ++ ) {
00439                                  query += challenge[i] ;
00440                               }
00441                               if (gs->sendQuery(split[0],split[1],&sock,query)) {
00442                                  result = gs->getResult(sock,buffer);
00443                                  if ( result == "0" ) {
00444                                     if (gs->getHL1Players(&players,buffer)) {            
00445                                        message =  ""+settings["hostname"]+ " => HL1 " + settings["gamedesc"] + " on " +settings["map"] +" Players:"+Tools::intToStr((int)settings["players"][0])+ "/"+Tools::intToStr((int)settings["maxplayers"][0])+ " ("+Tools::vectorToString(players,",",0)+")  pure:"+Tools::intToStr((int)settings["secure"][0])+ " pv:"+Tools::intToStr((int)settings["pass"][0])+"";
00446                                     }
00447                                     else {
00448                                        message =  "* Parse error *";
00449                                     }
00450                                  }
00451                                  else {
00452                                     message = result ;
00453                                  } 
00454                               }
00455                               else {
00456                                  message = "* Unable to send query *";
00457                               }
00458                            }
00459                         }
00460                         else {
00461                            message = result ;
00462                         } 
00463                      }
00464                      else {
00465                         message = "* Error, unable to send querry *";
00466                      }
00467                   }
00468                }
00469                else {
00470                   message = result ;
00471                } 
00472             }
00473             else {
00474                message = "* Error, unable to send querry *";
00475             }
00476             b->send( IRCProtocol::sendMsg(m->getSource(),message) ) ;
00477             close(sock);           
00478          }
00479       }
00480       return true;
00481         }
00482 }

Generated on Sun Aug 16 15:28:27 2009 for trustyRC by  doxygen 1.5.8