소스 검색

Added hostname cache, filled with data from central's smart hostname
lookup.
Broadcasting messages within own network with resolved ip to host, hosts
coming from hostname cache.

Mihawk 12 년 전
부모
커밋
e0852fe0a8
9개의 변경된 파일211개의 추가작업 그리고 44개의 파일을 삭제
  1. 12 0
      ActiveClient.cpp
  2. 17 0
      ActiveClient.h
  3. 74 16
      App.cpp
  4. 37 2
      App.h
  5. 22 8
      Client.cpp
  6. 7 0
      Settings.cpp
  7. 1 0
      Settings.h
  8. 28 6
      SshClient.cpp
  9. 13 12
      SshClient.h

+ 12 - 0
ActiveClient.cpp

@@ -175,3 +175,15 @@ void ActiveClient::incrementReplyCounters(int userCount, int channelCount, int p
   myUniqueServerCount += serverCount;
   myUniquePlayerCount += playerCount;
 }
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void ActiveClient::setHostName(const QString &hostName)
+{
+  myHostName = hostName;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+const QString& ActiveClient::hostName() const
+{
+  return myHostName;
+}

+ 17 - 0
ActiveClient.h

@@ -124,6 +124,20 @@ public:
   */
   bool              isWaitingReply() const;
 
+  /**
+    Set hostname
+
+    @param hostName The hostname
+  */
+  void              setHostName(const QString& hostName);
+
+  /**
+    Get hostname
+
+    @return The hostname
+  */
+  const QString&    hostName() const;
+
 private slots:
   /**
     Called when a query gathering server information has just finished successfully.
@@ -158,6 +172,9 @@ private:
   QTimer*           myQueryTimer;
   quint32           myQueryInterval;
 
+  // Server HostName used on reply
+  QString           myHostName;
+
   // Reply counters
   int               myUniqueUserCount;
   int               myUniqueChannelCount;

+ 74 - 16
App.cpp

@@ -56,7 +56,7 @@ App::App(int &argc, char **argv) :
   QCoreApplication(argc, argv),
   myServer(new QTcpServer()),
   mySocketConnectedFlag(false),
-  myQWNETSshClient(new SshClient(this))
+  mySshClient(new SshClient(this))
 {
   if(!parseCommandLine())
   {
@@ -64,19 +64,21 @@ App::App(int &argc, char **argv) :
     return;
   }
 
-  print("CIMS Bot Service v0.101\n========================================================\n");
+  print("CIMS Bot Service v0.12\n========================================================\n");
 
   setApplicationName("CIMSBOT");
   setOrganizationDomain("http://redmine.b4r.org/projects/cimsqwbot/");
   setOrganizationName("CIMS");
-  setApplicationVersion("0.101");
+  setApplicationVersion("0.12");
 
   myClientsFrameTimerID = startTimer(0);
 
-  myQWNETSshClient->connectToHost(Settings::globalInstance()->sshUserName(), Settings::globalInstance()->sshHostName());
-
   loadServerList();
 
+  print("Connecting to central...\n");
+  connect(mySshClient, SIGNAL(connected()), SLOT(onCentralConnection()));
+  mySshClient->connectToHost(Settings::globalInstance()->sshUserName(), Settings::globalInstance()->sshHostName());
+
   Settings::globalInstance()->save();
 }
 
@@ -337,15 +339,15 @@ const QStringList& App::lastMessages() const
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 void App::help()
 {
-  print("connect server:port -> connects the bot on a server\n");
-  print("disconnect server:port -> removes the bot from a server\n");
-  print("say message -> says the message on all servers where the bot is connected\n");
-  print("servers -> lists all servers the bot is connected\n");
-  print("name nick -> changes the bot name to nick\n");
-  print("color x x -> changes the player color\n");
-  print("setping x -> sets the bot ping to x. ofc you can't lower your actual ping with this.\n");
-  print("team teamname -> sets the bot team\n");
-  print("help -> displays this message\n");
+//  print("connect server:port -> connects the bot on a server\n");
+//  print("disconnect server:port -> removes the bot from a server\n");
+//  print("say message -> says the message on all servers where the bot is connected\n");
+//  print("servers -> lists all servers the bot is connected\n");
+//  print("name nick -> changes the bot name to nick\n");
+//  print("color x x -> changes the player color\n");
+//  print("setping x -> sets the bot ping to x. ofc you can't lower your actual ping with this.\n");
+//  print("team teamname -> sets the bot team\n");
+//  print("help -> displays this message\n");
 }
 
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -516,6 +518,18 @@ void App::timerEvent(QTimerEvent *e)
     {
       ac->run();
     }
+
+    // HostNames scheduled daily refresh
+    int currentHour = QTime::currentTime().hour();
+    if(currentHour == 21 && !myHostNamesRequested)
+    {
+      requestCachedHostNames();
+      myHostNamesRequested = true;
+    }
+    else if(currentHour != 21 && myHostNamesRequested)
+    {
+      myHostNamesRequested = false;
+    }
   }
   Sleeper::msleep(1);
 }
@@ -524,9 +538,9 @@ void App::timerEvent(QTimerEvent *e)
 void App::requestBroadcast(const QString &type, const QString &user, const QString &server, const QString &message)
 {
   if(!Settings::globalInstance()->developerMode())
-    myQWNETSshClient->write("REQ_BC QWalt,-" + type + "-,qw://" + server + ",'" + user + "','" + message + "'\n");
+    mySshClient->write("REQ_BC QWalt,-" + type + "-,qw://" + server + ",'" + user + "','" + message + "'\n");
   else
-    myQWNETSshClient->write("REQ_BC QDEV,-dev-,qw://" + server + ",'" + user + "','" + message + "'\n");
+    mySshClient->write("REQ_BC QDEV,-dev-,qw://" + server + ",'" + user + "','" + message + "'\n");
 }
 
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -622,3 +636,47 @@ void App::incrementReplyCounters(const QString &hash, int userCount, int channel
     }
   }
 }
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void App::requestCachedHostNames() const
+{
+  ActiveClient* ac;
+  foreach(ac, myClients)
+    mySshClient->write("REQ_DNS " + ac->serverAddressString() + "\n");
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void App::setServerHostName(const QString &serverAddress, const QString &hostName)
+{
+  ActiveClient* ac;
+  foreach(ac, myClients)
+  {
+    if(ac->serverAddressString() == serverAddress)
+    {
+      qDebug() << serverAddress << hostName;
+      ac->setHostName(hostName);
+      return;
+    }
+  }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+QString App::serverHostName(const QString &serverAddress) const
+{
+  ActiveClient* ac;
+  foreach(ac, myClients)
+  {
+    if(ac->serverAddressString() == serverAddress)
+    {
+      return ac->hostName();
+    }
+  }
+  return QString();
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void App::onCentralConnection()
+{
+  print("Connected!\nRefreshing cached hostnames...\n");
+  requestCachedHostNames();
+}

+ 37 - 2
App.h

@@ -120,9 +120,27 @@ public:
   */
   const QStringList&    lastMessages() const;
 
+  /**
+    Sets monitored server HostName, this function should be called from SshClient (central)
+    in reply to REQ_DNS request (DNS_RE).
+
+    @param serverAddress The server address full string ip:port
+    @param hostName      The server hostname (obtained from REQ_DNS request to central)
+  */
+  void                  setServerHostName(const QString& serverAddress, const QString& hostName);
+
+  /**
+    Gets monitored server HostName, this function should be called from QWClient (BOT)
+    when broadcasting inside it's own network of bots.
+
+    @param serverAddress The server address full string ip:port
+    @return hostName     The server hostname
+  */
+  QString serverHostName(const QString& serverAddress) const;
+
 protected:
   /**
-    App Destructor.
+    App's MainLoop is here.
   */
   void									timerEvent(QTimerEvent *e);
 
@@ -134,7 +152,7 @@ private:
   bool                  mySocketConnectedFlag; // Indicates whether there is someone connected to the TelNet administration
 
   // SSH Client connected to central
-  SshClient*            myQWNETSshClient;
+  SshClient*            mySshClient;
 
   // List of Servers we are monitoring
   QList<ActiveClient*>  myClients;
@@ -145,6 +163,9 @@ private:
   // Last 5 messages list
   QStringList           myLastMessages;
 
+  // Indicates whether I've requested the hostnames, used to avoid requesting the entire scheduled hour
+  bool                  myHostNamesRequested;
+
   /**
     Loads the server list from the config file.
   */
@@ -190,6 +211,13 @@ private:
   */
   void                  removeClient(const QString& host, quint16 port);
 
+  /**
+    Requests the hostnames of all servers being monitored.
+    Those hostnames are obtained from central, that has a smart
+    hostname lookup system.
+  */
+  void                  requestCachedHostNames() const;
+
   /**
     The following functions sets the Team, Color, Nick and Ping
     for all the bots on all servers that we are monitoring.
@@ -251,6 +279,13 @@ private slots:
     Called everytime an user is disconnected from the TelNet interface.
   */
   void                  onDisconnection();
+
+  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  /**
+    Called everytime we are fully connected to central.
+  */
+  void                  onCentralConnection();
+
 };
 
 #endif // APP_H

+ 22 - 8
Client.cpp

@@ -236,18 +236,32 @@ void Client::parsePrintedLine()
       mySpamBroadcastFloodTimer->start(spamFloodProtTime*1000);
     }
 
-    QString server(QString(host()) + ":" + QString::number(port()) + " " + QString::number(playerCount()) + "/" + QString::number(myMaxClients));
-    QString message("-" + command + "- " + nick + " - " + server + " : " + args.trimmed());
+    // Prepare all strings to be broadcasted
+    QString server(QString(host()) + ":" + QString::number(port()));
 
-    /* Broadcast within QW servers */
-    myApp->broadcast(message, myActiveClient);
-
-    /* Broadcast outside QW */
-    nick = parseNameFun(nick); //for the irc message namefun must be removed.
+    // Tries to find the hostname for this ip in the cache
+    QString resolvedServer(myApp->serverHostName(server));
+    if(!resolvedServer.isEmpty())
+      resolvedServer.append(":" + QString::number(port()));
+    else
+      resolvedServer = server;
+
+    // Internal message to be broadcast within our network of bots (don't need to have namefun parsed)
+    // The internal message uses the resolvedServer, because this message doesn't pass tru central, thus
+    // the server ip isn't replaced by a hostname automatically
+    QString internalMessage("-" + command + "- " + nick + " - " + resolvedServer + " " + QString::number(playerCount()) + "/" + QString::number(myMaxClients) + " : " + args.trimmed());
+    myApp->broadcast(internalMessage, myActiveClient);
+
+    // Message that will be broadcast to other networks (needs namefun parsing)
+    // this message passes tru central, thus the server ip will be replaced by a hostname
+    // automatically
+    nick = parseNameFun(nick);
     QString parsedMsg = parseNameFun(args.trimmed());
 
+    server.append(" " + QString::number(playerCount()) + "/" + QString::number(myMaxClients)); // append player count to the server (central needs another parm for this!)
+
     if(!Settings::globalInstance()->developerMode())
-      myApp->requestBroadcast(command, nick, server, args.trimmed());
+      myApp->requestBroadcast(command, nick, server, parsedMsg);
     else
       myApp->requestBroadcast("dev", nick, server, parsedMsg);
 

+ 7 - 0
Settings.cpp

@@ -188,6 +188,12 @@ QString Settings::sshUserName() const
   return ourSettings->value("sshUserName", "stomp").toString();
 }
 
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+int Settings::refreshHostNamesHour() const
+{
+  return ourSettings->value("refreshHostNamesHour", 21).toInt();
+}
+
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 void Settings::save()
 {
@@ -206,6 +212,7 @@ void Settings::save()
   ourSettings->setValue("developerMode", developerMode());
   ourSettings->setValue("sshHostName", sshHostName());
   ourSettings->setValue("sshUserName", sshUserName());
+  ourSettings->setValue("refreshHostNamesHour", refreshHostNamesHour());
 
   ServerList list = serverList();
   setServerList(list);

+ 1 - 0
Settings.h

@@ -83,6 +83,7 @@ public:
   bool              developerMode() const;
   QString           sshUserName() const;
   QString           sshHostName() const;
+  int               refreshHostNamesHour() const;
 
   /**
     Save current settings to the file.

+ 28 - 6
SshClient.cpp

@@ -36,8 +36,7 @@ SshClient::SshClient(App* app, QObject *parent) :
   myConnectedFlag(false),
   myConnectionTimerID(0),
   myPingTimerID(0),
-  myPongTimerID(0),
-  myClients(new QStringList())
+  myPongTimerID(0)
 {
   connect(myProcess, SIGNAL(readyRead()), SLOT(read()));
   connect(myProcess, SIGNAL(finished(int)), SLOT(exited(int)));
@@ -47,7 +46,6 @@ SshClient::SshClient(App* app, QObject *parent) :
 SshClient::~SshClient()
 {
   delete myCommandRegex;
-  delete myClients;
 }
 
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -117,8 +115,8 @@ void SshClient::parse(const QDateTime &time, const QString &command, const QStri
     QRegExp a("^User '([a-zA-Z]+)'.+$");
     if(a.indexIn(commandData) != -1)
     {
-      if(!myClients->contains(a.capturedTexts().at(1)))
-        myClients->push_back(a.capturedTexts().at(1));
+      if(!myClients.contains(a.capturedTexts().at(1)))
+        myClients.push_back(a.capturedTexts().at(1));
     }
     return;
   }
@@ -128,7 +126,7 @@ void SshClient::parse(const QDateTime &time, const QString &command, const QStri
   {
     QRegExp a("^User '([a-zA-Z]+)'.+$");
     if(a.indexIn(commandData) != -1)
-      myClients->removeAll(a.capturedTexts().at(1));
+      myClients.removeAll(a.capturedTexts().at(1));
     return;
   }
 
@@ -237,6 +235,30 @@ void SshClient::parse(const QDateTime &time, const QString &command, const QStri
     return;
   }
 
+  /* DNS_RE - Reply from REQ_DNS, returns the HostName for the requested ip:port pair */
+  if(command == "DNS_RE")
+  {
+    QRegExp a("^([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+:[0-9]+) ([0-9A-Za-z][A-Za-z0-9\\-\\.]+)$");
+    if(a.indexIn(commandData) == -1)
+      return;
+    myApp->setServerHostName(a.cap(1), a.cap(2));
+    return;
+  }
+
+  /* COMMANDS - List of commands allowed for me */
+  if(command == "COMMANDS")
+  {
+    myCommands = commandData.split(", ", QString::SkipEmptyParts);
+    return;
+  }
+
+  /* ROLES - List of roles I exert */
+  if(command == "ROLES")
+  {
+    myRoles = commandData.split(", ", QString::SkipEmptyParts);
+    return;
+  }
+
   myApp->print("Unparsed cmd from central: " + time.toString() + " " + command + " " + commandData + "\n");
 }
 

+ 13 - 12
SshClient.h

@@ -21,11 +21,10 @@ along with this program.  If not, see < http://www.gnu.org/licenses/ >.
 #define SSHCLIENT_H
 
 #include <QObject>
-#include <QString>
+#include <QStringList>
 
 class QProcess;
 class QDateTime;
-class QStringList;
 class App;
 
 /**
@@ -119,16 +118,18 @@ private slots:
   void exited(int exitCode);
 
 private:
-  App*      myApp;
-  QProcess* myProcess;
-  QRegExp*  myCommandRegex;
-  bool      myConnectedFlag;
-  int       myConnectionTimerID;
-  int       myPingTimerID;
-  int       myPongTimerID;
-  QStringList* myClients;
-  QString   myUsername;
-  QString   myHostname;
+  App*        myApp;               // The app
+  QProcess*   myProcess;           // The ssh process
+  QRegExp*    myCommandRegex;      // Regex used on every command, so it was made persistent
+  bool        myConnectedFlag;     // Are we connected?
+  int         myConnectionTimerID; // Times out connection process
+  int         myPingTimerID;       // PING? PONG! Checks if the connection is still alive
+  int         myPongTimerID;       // PING? PONG! Checks if the connection is still alive
+  QStringList myClients;           // List of other clients connected to central
+  QString     myUsername;          // My username on central
+  QString     myHostname;          // Central's hostname
+  QStringList myRoles;             // My roles on central
+  QStringList myCommands;          // The list of commands that I can issue
 
   /**
     Parses all commands coming from the server and execute the appropriate