connection_dispatcher.cpp

00001 
00002 /***************************************************************************
00003  *  connection_dispatcher.cpp - Network connection listener and dispatcher
00004  *
00005  *  Created: Mon Oct 20 15:06:28 2008
00006  *  Copyright  2008  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 <gui_utils/connection_dispatcher.h>
00025 #include <netcomm/fawkes/client.h>
00026 
00027 #include <cstring>
00028 #include <cstdlib>
00029 
00030 namespace fawkes {
00031 
00032 /** @class ConnectionDispatcher <gui_utils/connection_dispatcher.h>
00033  * Watches network client events and dispatches them as signals.
00034  * @author Tim Niemueller
00035  */
00036 
00037 /** Constructor.
00038  * @param cid component ID to register this dispatcher for. This is relevant if
00039  * you want to use the message received signal!
00040  */
00041 ConnectionDispatcher::ConnectionDispatcher(unsigned int cid)
00042 {
00043   __cid = cid;
00044   __client = new FawkesNetworkClient();
00045   __client->register_handler(this, __cid);
00046   __client_owned = true;
00047 
00048   connect_signals();
00049 }
00050 
00051 
00052 /** Constructor.
00053  * @param cid component ID to register this dispatcher for. This is relevant if
00054  * you want to use the message received signal!
00055  * @param hostname hostname to connect to
00056  * @param port port to connect to
00057  */
00058   ConnectionDispatcher::ConnectionDispatcher(const char *hostname,
00059                                              unsigned short int port,
00060                                              unsigned int cid)
00061 {
00062   __cid = cid;
00063   __client = new FawkesNetworkClient(hostname, port);
00064   __client->register_handler(this, __cid);
00065   __client_owned = true;
00066 
00067   connect_signals();
00068 }
00069 
00070 /** Destructor. */
00071 ConnectionDispatcher::~ConnectionDispatcher()
00072 {
00073   set_client(NULL);
00074 }
00075 
00076 
00077 void
00078 ConnectionDispatcher::connect_signals()
00079 {
00080   __dispatcher_connected.connect(sigc::mem_fun(*this, &ConnectionDispatcher::on_connection_established));
00081   __dispatcher_disconnected.connect(sigc::mem_fun(*this, &ConnectionDispatcher::on_connection_died));
00082   __dispatcher_message_received.connect(sigc::mem_fun(*this, &ConnectionDispatcher::on_message_received));
00083 }
00084 
00085 /** Set component ID.
00086  * Set the component ID you want to register this connection dispatcher on. By
00087  * default the connection dispatcher uses the observer mode to only provide
00088  * connection status signals. If you want to use the dispatcher to be signaled
00089  * for incoming messages you have to set the appropriate component ID.
00090  * @param cid component ID
00091  */
00092 void
00093 ConnectionDispatcher::set_cid(unsigned int cid)
00094 {
00095   if ( __client ) {
00096     __client->deregister_handler(__cid);
00097     __client->register_handler(this, cid);
00098   }
00099   __cid = cid;
00100 }
00101 
00102 
00103 /** Set Fawkes network client.
00104  * The instance you set is not owned by the ConnectionDispatcher, it's only
00105  * used. You have to delete it when finished. Similarly you have to make sure that
00106  * the client is valid as long as it is set on the dispatcher.
00107  * @param client Fawkes network client to set.
00108  */
00109 void
00110 ConnectionDispatcher::set_client(FawkesNetworkClient *client)
00111 {
00112   if ( __client )  __client->deregister_handler(__cid);
00113   if ( __client_owned ) {
00114     delete __client;
00115   }
00116   __client_owned = false;
00117   __client = client;
00118   if ( __client )  __client->register_handler(this, __cid);
00119 }
00120 
00121 
00122 /** Get client.
00123  * @return associated Fawkes network client.
00124  */
00125 FawkesNetworkClient *
00126 ConnectionDispatcher::get_client()
00127 {
00128   return __client;
00129 }
00130 
00131 
00132 /** Check if client is set and connection has been established.
00133  * @return true if a client exists and a connection is established, false
00134  * otherwise.
00135  */
00136 ConnectionDispatcher::operator bool()
00137 {
00138   return (__client && __client->connected());
00139 }
00140 
00141 
00142 /** Internal event handler.
00143  * Called by dispatcher to emit signal.
00144  */
00145 void
00146 ConnectionDispatcher::on_connection_established()
00147 {
00148   __signal_connected.emit();
00149 }
00150 
00151 
00152 /** Internal event handler.
00153  * Called by dispatcher to emit signal.
00154  */
00155 void
00156 ConnectionDispatcher::on_connection_died()
00157 {
00158   __signal_disconnected.emit();
00159 }
00160 
00161 
00162 /** Internal event handler.
00163  * Called by dispatcher to emit signal.
00164  */
00165 void
00166 ConnectionDispatcher::on_message_received()
00167 {
00168   __queue_message_received.lock();
00169   while (! __queue_message_received.empty()) {
00170     FawkesNetworkMessage *msg = __queue_message_received.front();
00171     __signal_message_received.emit(msg);
00172     msg->unref();
00173     __queue_message_received.pop();
00174   }
00175   __queue_message_received.unlock();
00176 }
00177 
00178 
00179 void
00180 ConnectionDispatcher::deregistered(unsigned int id) throw()
00181 {
00182   // ignored
00183 }
00184 
00185 
00186 void
00187 ConnectionDispatcher::inbound_received(FawkesNetworkMessage *m, unsigned int id) throw()
00188 {
00189   m->ref();
00190   __queue_message_received.push_locked(m);
00191   __dispatcher_message_received();
00192 }
00193 
00194 
00195 void
00196 ConnectionDispatcher::connection_died(unsigned int id) throw()
00197 {
00198   __dispatcher_disconnected();
00199 }
00200 
00201 
00202 void
00203 ConnectionDispatcher::connection_established(unsigned int id) throw()
00204 {
00205   __dispatcher_connected();
00206 }
00207 
00208 
00209 /** Get "message received" signal.
00210  * The "message received" signal is emitted whenever a FawkesNetworkMessage has
00211  * been received.
00212  * @return "message received" signal
00213  */
00214   sigc::signal<void, FawkesNetworkMessage *>
00215 ConnectionDispatcher::signal_message_received()
00216 {
00217   return __signal_message_received;
00218 }
00219 
00220 
00221 /** Get "connected" signal.
00222  * The "connected" signal is emitted when the connection has been established.
00223  * @return "connected" signal
00224  */
00225 sigc::signal<void>
00226 ConnectionDispatcher::signal_connected()
00227 {
00228   return __signal_connected;
00229 }
00230 
00231 
00232 /** Get "disconnected" signal.
00233  * The "disconnected" signal is emitted when the connection has died, for example
00234  * because the other peer closed the connection.
00235  * @return "disconnected" signal
00236  */
00237 sigc::signal<void>
00238 ConnectionDispatcher::signal_disconnected()
00239 {
00240   return __signal_disconnected;
00241 }
00242 
00243 } // end of namespace fawkes