fuse_server.cpp

00001
00002 /***************************************************************************
00003  *  fuse_server.tcp - network image transport server interface
00004  *
00005  *  Generated: Mon Mar 19 15:56:22 2007
00006  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <fvutils/net/fuse_server.h>
00025 #include <fvutils/net/fuse_server_client_thread.h>
00026
00027 #include <core/threading/thread_collector.h>
00028 #include <netcomm/utils/acceptor_thread.h>
00029
00030 #include <algorithm>
00031
00032 using namespace fawkes;
00033 
00034 /** @class FuseServer <fvutils/net/fuse_server.h>
00035  * FireVision FUSE protocol server.
00036  * The FuseServer will open a StreamSocket and listen on it for incoming
00037  * connections. For each connection a client thread is started that will process
00038  * all requests issued by the client.
00039  *
00040  * @ingroup FUSE
00041  * @ingroup FireVision
00042  * @author Tim Niemueller
00043  */
00044 
00045 /** Constructor.
00046  * @param port Port to listen on for incoming connections
00047  * @param collector optional thread collector
00048  */
00049 FuseServer::FuseServer(unsigned short int port, ThreadCollector *collector)
00050   : Thread("FuseServer", Thread::OPMODE_WAITFORWAKEUP)
00051 {
00052   __thread_collector = collector;
00053
00054   __acceptor_thread = new NetworkAcceptorThread(this, port, "FuseNetworkAcceptorThread");
00055   if (__thread_collector) {
00056     __thread_collector->add(__acceptor_thread);
00057   } else {
00058     __acceptor_thread->start();
00059   }
00060 }
00061
00062 
00063 /** Destructor. */
00064 FuseServer::~FuseServer()
00065 {
00066   if ( __thread_collector ) {
00067     __thread_collector->remove(__acceptor_thread);
00068   } else {
00069     __acceptor_thread->cancel();
00070     __acceptor_thread->join();
00071   }
00072
00073   for (__cit = __clients.begin(); __cit != __clients.end(); ++__cit) {
00074     if ( __thread_collector ) {
00075       // ThreadCollector::remove also stops the threads!
00076       __thread_collector->remove(*__cit);
00077     } else {
00078       (*__cit)->cancel();
00079       (*__cit)->join();
00080     }
00081     delete *__cit;
00082   }
00083   __clients.clear();
00084
00085   delete __acceptor_thread;
00086 }
00087
00088
00089 void
00090 FuseServer::add_connection(StreamSocket *s) throw()
00091 {
00092   FuseServerClientThread *client = new FuseServerClientThread(this, s);
00093   if ( __thread_collector) {
00094     __thread_collector->add(client);
00095   } else {
00096     client->start();
00097   }
00098   __clients.push_back_locked(client);
00099 }
00100
00101 
00102 /** Connection died.
00103  * @param client client whose connection died
00104  */
00105 void
00106 FuseServer::connection_died(FuseServerClientThread *client) throw()
00107 {
00108   __dead_clients.push_back_locked(client);
00109   wakeup();
00110 }
00111
00112
00113 void
00114 FuseServer::loop()
00115 {
00116   // Check for dead clients, cancel and join if there are any
00117   __dead_clients.lock();
00118   __clients.lock();
00119
00120   LockList<FuseServerClientThread *>::iterator  dcit;
00121
00122   while ( ! __dead_clients.empty() ) {
00123     dcit = __dead_clients.begin();
00124
00125     if ( __thread_collector ) {
00126       // ThreadCollector::remove also stops the threads!
00127       __thread_collector->remove(*dcit);
00128     } else {
00129       (*dcit)->cancel();
00130       (*dcit)->join();
00131     }
00132     if ( (__cit = find(__clients.begin(), __clients.end(), *dcit)) != __clients.end() ) {
00133       __clients.erase(__cit);
00134     }
00135
00136     FuseServerClientThread *tc = *dcit;
00137     __dead_clients.erase(dcit);
00138     delete tc;
00139   }
00140
00141   __clients.unlock();
00142   __dead_clients.unlock();
00143 }