Drizzled Public API Documentation

network_ms.cc
00001 /* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
00002  *
00003  * PrimeBase Media Stream for MySQL
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00018  *
00019  * Original author: Paul McCullagh
00020  * Continued development: Barry Leslie
00021  *
00022  * 2007-05-25
00023  *
00024  * H&G2JCtL
00025  *
00026  * Network interface.
00027  *
00028  */
00029 #include "cslib/CSConfig.h"
00030 
00031 #include "defs_ms.h"
00032 
00033 #include "cslib/CSGlobal.h"
00034 #include "cslib/CSLog.h"
00035 
00036 #include "network_ms.h"
00037 #include "connection_handler_ms.h"
00038 
00039 MSSystemThread    *MSNetwork::gSystemThread;
00040 time_t        MSNetwork::gCurrentTime;
00041 time_t        MSNetwork::gLastService;
00042 CSThreadList    *MSNetwork::gHandlerList;
00043 CSSync        MSNetwork::gListenerLock;
00044 CSSocket      *MSNetwork::gListenerSocket;
00045 MSConnectionHandler *MSNetwork::gListenerThread;
00046 uint32_t        MSNetwork::gWaitingToListen;
00047 int         MSNetwork::handlerCount;
00048 
00049 /*
00050  * -------------------------------------------------------------------------
00051  * SYSTEM THREAD
00052  */
00053 
00054 bool MSSystemThread::doWork()
00055 {
00056   bool  killed = true;
00057 
00058   enter_();
00059   MSNetwork::gCurrentTime = time(NULL);
00060   if ((MSNetwork::gCurrentTime - MSNetwork::gLastService) >= (MS_IDLE_THREAD_TIMEOUT/2)) {
00061     MSNetwork::gLastService = MSNetwork::gCurrentTime;
00062     while (!myMustQuit && killed) {
00063       killed = MSNetwork::killListener();
00064       MSNetwork::gCurrentTime = time(NULL);
00065     }
00066   }
00067   return_(true);
00068 }
00069 
00070 /*
00071  * -------------------------------------------------------------------------
00072  * NETWORK FUNCTIONS
00073  */
00074 
00075 void MSNetwork::startUp(int port)
00076 {
00077   enter_();
00078   gCurrentTime = time(NULL);
00079   gLastService = gCurrentTime;
00080   gListenerSocket = NULL;
00081   handlerCount = 0;
00082   
00083   CSL.lock();
00084   CSL.log(self, CSLog::Protocol, "Media Stream Daemon ");
00085   if (port) {
00086   CSL.log(self, CSLog::Protocol, " listening on port ");
00087   CSL.log(self, CSLog::Protocol, port);
00088   } else
00089     CSL.log(self, CSLog::Protocol, " not published ");
00090   CSL.log(self, CSLog::Protocol, "\n");
00091   CSL.unlock();
00092 
00093   new_(gHandlerList, CSThreadList());
00094   if (port) {
00095   gListenerSocket = CSSocket::newSocket();
00096   gListenerSocket->publish(NULL, port);
00097   } else 
00098     gListenerSocket = NULL;
00099 
00100   new_(gSystemThread, MSSystemThread(1000 /* 1 sec */, NULL));
00101   gSystemThread->start();
00102   exit_();
00103 }
00104 
00105 void MSNetwork::shutDown()
00106 {
00107   enter_();
00108 
00109   if (gSystemThread) {
00110     gSystemThread->stop();
00111     gSystemThread->release();
00112     gSystemThread = NULL;
00113   }
00114 
00115   /* This will set all threads to quiting: */
00116   if (gHandlerList)
00117     gHandlerList->quitAllThreads();
00118 
00119   /* Close the socket: */
00120   if (gListenerThread)
00121     gListenerThread->shuttingDown = true; // Block error messages as a result of the listener being killed
00122   
00123   lock_(&gListenerLock);
00124   if (gListenerSocket) {
00125     try_(a) {
00126       gListenerSocket->release();
00127     }
00128     catch_(a) {
00129       self->logException();
00130     }
00131     cont_(a);
00132   }
00133   gListenerSocket = NULL;
00134   unlock_(&gListenerLock);
00135 
00136   if (gHandlerList) {
00137     try_(b) {
00138       /* This will stop any threads remaining: */
00139       gHandlerList->release();
00140     }
00141     catch_(b) {
00142       self->logException();
00143     }
00144     cont_(b);
00145   }
00146 
00147   CSL.log(self, CSLog::Protocol, "PrimeBase Media Stream Daemon no longer published\n");
00148   exit_();
00149 }
00150 
00151 void MSNetwork::startConnectionHandler()
00152 {
00153   char        buffer[120];
00154   MSConnectionHandler *thread;
00155 
00156   enter_();
00157   handlerCount++;
00158   snprintf(buffer, 120, "NetworkHandler%d", handlerCount);
00159   lock_(gHandlerList);
00160   thread = MSConnectionHandler::newHandler(MSNetwork::gHandlerList);
00161   unlock_(gHandlerList);
00162   push_(thread);
00163   thread->threadName = CSString::newString(buffer);
00164   thread->start();
00165   release_(thread);
00166   exit_();
00167 }
00168 
00169 /*
00170  * Return NULL of a connection cannot be openned, and the
00171  * thread must quit.
00172  */
00173 class OpenConnectioCleanUp : public CSRefObject {
00174   bool do_cleanup;
00175 
00176   public:
00177   
00178   OpenConnectioCleanUp(): CSRefObject(),
00179     do_cleanup(false){}
00180     
00181   ~OpenConnectioCleanUp() 
00182   {
00183     if (do_cleanup) {
00184       MSNetwork::unlockListenerSocket();
00185     }
00186   }
00187   
00188   void setCleanUp()
00189   {
00190     do_cleanup = true;
00191   }
00192   
00193   void cancelCleanUp()
00194   {
00195     do_cleanup = false;
00196   }
00197   
00198 };
00199 
00200 /*
00201  * Return NULL if a connection cannot be openned, and the
00202  * thread must quit.
00203  */
00204 CSSocket *MSNetwork::openConnection(MSConnectionHandler *handler)
00205 {
00206   CSSocket *sock = NULL;
00207   OpenConnectioCleanUp *cleanup;
00208 
00209   enter_();
00210   
00211   if(!MSNetwork::gListenerSocket) {
00212     return_(NULL);
00213   }
00214   
00215   sock = CSSocket::newSocket();
00216   push_(sock);
00217 
00218   /* Wait for a connection: */
00219   if (!lockListenerSocket(handler)) {
00220     release_(sock);
00221     return_(NULL);
00222   }
00223 
00224   new_(cleanup, OpenConnectioCleanUp());
00225   push_(cleanup);
00226   
00227   cleanup->setCleanUp();
00228   sock->open(MSNetwork::gListenerSocket);
00229   cleanup->cancelCleanUp();
00230 
00231   handler->lastUse = gCurrentTime;
00232 
00233   unlockListenerSocket();
00234 
00235   release_(cleanup);
00236   pop_(sock);
00237   return_(sock);
00238 }
00239 
00240 void MSNetwork::startNetwork()
00241 {
00242   enter_();
00243   startConnectionHandler();
00244   exit_();
00245 }
00246 
00247 bool MSNetwork::lockListenerSocket(MSConnectionHandler *handler)
00248 {
00249   bool socket_locked = false;
00250 
00251   enter_();
00252   if (handler->myMustQuit)
00253     return false;
00254   lock_(&gListenerLock);
00255   if (gListenerSocket) {
00256     /* Wait for the listen socket to be freed: */
00257     if (gListenerThread) {
00258       gWaitingToListen++;
00259       handler->amWaitingToListen = true;
00260       while (gListenerThread) {
00261         if (handler->myMustQuit)
00262           break;
00263         try_(a) {
00264           gListenerLock.wait(2000);
00265         }
00266         catch_(a) {
00267           /* Catch any error */;
00268         }
00269         cont_(a);
00270       }
00271       gWaitingToListen--;
00272       handler->amWaitingToListen = false;
00273     }
00274     if (!handler->myMustQuit) {
00275       gListenerThread = handler;
00276       socket_locked = true;
00277     }
00278   }
00279   unlock_(&gListenerLock);
00280   return_(socket_locked);
00281 }
00282 
00283 void MSNetwork::unlockListenerSocket()
00284 {
00285   enter_();
00286   lock_(&gListenerLock);
00287   gListenerThread = NULL;
00288   gListenerLock.wakeup();
00289   unlock_(&gListenerLock);
00290   exit_();
00291 }
00292 
00293 /* Kill a listener if possible!
00294  * Return true if a thread was killed.
00295  */
00296 bool MSNetwork::killListener()
00297 {
00298   MSConnectionHandler *ptr = NULL;
00299 
00300   enter_();
00301   lock_(&gListenerLock);
00302   if (gListenerThread && gWaitingToListen > 0) {
00303     /* Kill one: */
00304     lock_(gHandlerList);
00305     ptr = (MSConnectionHandler *) gHandlerList->getBack();
00306     while (ptr) {
00307       if (ptr->amWaitingToListen) {
00308         if (gCurrentTime > ptr->lastUse && (gCurrentTime - ptr->lastUse) > MS_IDLE_THREAD_TIMEOUT) {
00309           ptr->myMustQuit = true;
00310           ptr->wakeup();
00311           break;
00312         }
00313       }
00314       ptr = (MSConnectionHandler *) ptr->getNextLink();
00315     }
00316     unlock_(gHandlerList);
00317   }
00318   unlock_(&gListenerLock);
00319   if (ptr) {
00320     ptr->join();
00321     return_(true);
00322   }
00323   return_(false);
00324 }
00325 
00326