]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/extra/m_pgsql.cpp
Fix a bunch of weird indentation and spacing issues.
[user/henk/code/inspircd.git] / src / modules / extra / m_pgsql.cpp
index b0f0b4597eba45367a256e7d7801158ebd0eb3cf..e1db996c896d918867bd8677b6190a174df03daa 100644 (file)
@@ -1,12 +1,18 @@
 /*
  * InspIRCd -- Internet Relay Chat Daemon
  *
+ *   Copyright (C) 2016 Adam <Adam@anope.org>
+ *   Copyright (C) 2015 Daniel Vassdal <shutter@canternet.org>
+ *   Copyright (C) 2013, 2016-2020 Sadie Powell <sadie@witchery.services>
+ *   Copyright (C) 2012-2015 Attila Molnar <attilamolnar@hush.com>
+ *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- *   Copyright (C) 2006-2007, 2009 Dennis Friis <peavey@inspircd.org>
- *   Copyright (C) 2006-2007, 2009 Craig Edwards <craigedwards@brainbox.cc>
- *   Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
- *   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
+ *   Copyright (C) 2007, 2009-2010 Craig Edwards <brain@inspircd.org>
+ *   Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
+ *   Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2006 Oliver Lupton <om@inspircd.org>
  *
  * This file is part of InspIRCd.  InspIRCd is free software: you can
  * redistribute it and/or modify it under the terms of the GNU General Public
@@ -49,14 +55,23 @@ class ModulePgSQL;
 
 typedef insp::flat_map<std::string, SQLConn*> ConnMap;
 
-/* CREAD,      Connecting and wants read event
- * CWRITE,     Connecting and wants write event
- * WREAD,      Connected/Working and wants read event
- * WWRITE,     Connected/Working and wants write event
- * RREAD,      Resetting and wants read event
- * RWRITE,     Resetting and wants write event
- */
-enum SQLstatus { CREAD, CWRITE, WREAD, WWRITE, RREAD, RWRITE };
+enum SQLstatus
+{
+       // The connection has died.
+       DEAD,
+
+       // Connecting and wants read event.
+       CREAD,
+
+       // Connecting and wants write event.
+       CWRITE,
+
+       // Connected/working and wants read event.
+       WREAD,
+
+       // Connected/working and wants write event.
+       WWRITE
+};
 
 class ReconnectTimer : public Timer
 {
@@ -171,7 +186,7 @@ class SQLConn : public SQL::Provider, public EventHandler
  public:
        reference<ConfigTag> conf;      /* The <database> entry */
        std::deque<QueueItem> queue;
-       PGconn*                 sql;            /* PgSQL database connection handle */
+       PGconn*                 sql;            /* PgSQL database connection handle */
        SQLstatus               status;         /* PgSQL database connection status */
        QueueItem               qinprog;        /* If there is currently a query in progress */
 
@@ -183,10 +198,7 @@ class SQLConn : public SQL::Provider, public EventHandler
                , qinprog(NULL, "")
        {
                if (!DoConnect())
-               {
-                       ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not connect to database " + tag->getString("id"));
                        DelayReconnect();
-               }
        }
 
        CullResult cull() CXX11_OVERRIDE
@@ -210,6 +222,7 @@ class SQLConn : public SQL::Provider, public EventHandler
                        q->OnError(err);
                        delete q;
                }
+               Close();
        }
 
        void OnEventHandlerRead() CXX11_OVERRIDE
@@ -255,34 +268,40 @@ class SQLConn : public SQL::Provider, public EventHandler
                return conninfo.str();
        }
 
+       bool HandleConnectError(const char* reason)
+       {
+               ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Could not connect to the \"%s\" database: %s",
+                       GetId().c_str(), reason);
+               return false;
+       }
+
        bool DoConnect()
        {
                sql = PQconnectStart(GetDSN().c_str());
                if (!sql)
-                       return false;
+                       return HandleConnectError("PQconnectStart returned NULL");
 
                if(PQstatus(sql) == CONNECTION_BAD)
-                       return false;
+                       return HandleConnectError("connection status is bad");
 
                if(PQsetnonblocking(sql, 1) == -1)
-                       return false;
+                       return HandleConnectError("unable to mark fd as non-blocking");
 
-               /* OK, we've initalised the connection, now to get it hooked into the socket engine
+               /* OK, we've initialised the connection, now to get it hooked into the socket engine
                * and then start polling it.
                */
-               this->fd = PQsocket(sql);
-
-               if(this->fd <= -1)
-                       return false;
+               SetFd(PQsocket(sql));
+               if(!HasFd())
+                       return HandleConnectError("PQsocket returned an invalid fd");
 
                if (!SocketEngine::AddFd(this, FD_WANT_NO_WRITE | FD_WANT_NO_READ))
-               {
-                       ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Couldn't add pgsql socket to socket engine");
-                       return false;
-               }
+                       return HandleConnectError("could not add the pgsql socket to the socket engine");
 
                /* Socket all hooked into the engine, now to tell PgSQL to start connecting */
-               return DoPoll();
+               if (!DoPoll())
+                       return HandleConnectError("could not poll the connection state");
+
+               return true;
        }
 
        bool DoPoll()
@@ -298,6 +317,8 @@ class SQLConn : public SQL::Provider, public EventHandler
                                status = CREAD;
                                return true;
                        case PGRES_POLLING_FAILED:
+                               SocketEngine::ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE);
+                               status = DEAD;
                                return false;
                        case PGRES_POLLING_OK:
                                SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
@@ -379,30 +400,6 @@ restart:
                }
        }
 
-       bool DoResetPoll()
-       {
-               switch(PQresetPoll(sql))
-               {
-                       case PGRES_POLLING_WRITING:
-                               SocketEngine::ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ);
-                               status = CWRITE;
-                               return DoPoll();
-                       case PGRES_POLLING_READING:
-                               SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
-                               status = CREAD;
-                               return true;
-                       case PGRES_POLLING_FAILED:
-                               return false;
-                       case PGRES_POLLING_OK:
-                               SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
-                               status = WWRITE;
-                               DoConnectedPoll();
-                               return true;
-                       default:
-                               return true;
-               }
-       }
-
        void DelayReconnect();
 
        void DoEvent()
@@ -411,11 +408,7 @@ restart:
                {
                        DoPoll();
                }
-               else if((status == RREAD) || (status == RWRITE))
-               {
-                       DoResetPoll();
-               }
-               else
+               else if (status == WREAD || status == WWRITE)
                {
                        DoConnectedPoll();
                }
@@ -516,7 +509,10 @@ restart:
 
        void Close()
        {
-               SocketEngine::DelFd(this);
+               status = DEAD;
+
+               if (HasFd() && SocketEngine::HasFd(GetFd()))
+                       SocketEngine::DelFd(this);
 
                if(sql)
                {
@@ -561,8 +557,13 @@ class ModulePgSQL : public Module
                        if (curr == connections.end())
                        {
                                SQLConn* conn = new SQLConn(this, i->second);
-                               conns.insert(std::make_pair(id, conn));
-                               ServerInstance->Modules->AddService(*conn);
+                               if (conn->status != DEAD)
+                               {
+                                       conns.insert(std::make_pair(id, conn));
+                                       ServerInstance->Modules->AddService(*conn);
+                               }
+                               // If the connection is dead it has already been queued for culling
+                               // at the end of the main loop so we don't need to delete it here.
                        }
                        else
                        {
@@ -614,7 +615,7 @@ class ModulePgSQL : public Module
 
        Version GetVersion() CXX11_OVERRIDE
        {
-               return Version("PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API", VF_VENDOR);
+               return Version("Provides the ability for SQL modules to query a PostgreSQL database.", VF_VENDOR);
        }
 };
 
@@ -628,17 +629,17 @@ bool ReconnectTimer::Tick(time_t time)
 
 void SQLConn::DelayReconnect()
 {
+       status = DEAD;
        ModulePgSQL* mod = (ModulePgSQL*)(Module*)creator;
+
        ConnMap::iterator it = mod->connections.find(conf->getString("id"));
        if (it != mod->connections.end())
-       {
                mod->connections.erase(it);
-               ServerInstance->GlobalCulls.AddItem((EventHandler*)this);
-               if (!mod->retimer)
-               {
-                       mod->retimer = new ReconnectTimer(mod);
-                       ServerInstance->Timers.AddTimer(mod->retimer);
-               }
+       ServerInstance->GlobalCulls.AddItem((EventHandler*)this);
+       if (!mod->retimer)
+       {
+               mod->retimer = new ReconnectTimer(mod);
+               ServerInstance->Timers.AddTimer(mod->retimer);
        }
 }