Переглянути джерело

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