00001 /* 00002 * Copyright (C) 2003-2009 Olivier Boudeville 00003 * 00004 * This file is part of the Ceylan library. 00005 * 00006 * The Ceylan library is free software: you can redistribute it and/or modify 00007 * it under the terms of either the GNU Lesser General Public License or 00008 * the GNU General Public License, as they are published by the Free Software 00009 * Foundation, either version 3 of these Licenses, or (at your option) 00010 * any later version. 00011 * 00012 * The Ceylan library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU Lesser General Public License and the GNU General Public License 00016 * for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License and the GNU General Public License along with the Ceylan library. 00020 * If not, see <http://www.gnu.org/licenses/>. 00021 * 00022 * Author: Olivier Boudeville (olivier.boudeville@esperide.com) 00023 * 00024 */ 00025 00026 00027 #include "CeylanMultiplexedProtocolBasedStreamServer.h" 00028 00029 00030 #include "CeylanLogPlug.h" // for LogPlug 00031 #include "CeylanStringUtils.h" // for formatStringList 00032 #include "CeylanOperators.h" // for toString 00033 #include "CeylanAnonymousProtocolAwareStreamSocket.h" // for this class 00034 #include "CeylanProtocolServer.h" // for ProtocolServer 00035 #include "CeylanProtocolEndpoint.h" // for ProtocolException 00036 00037 00038 #ifdef CEYLAN_USES_CONFIG_H 00039 #include "CeylanConfig.h" // for configure-time feature settings 00040 #endif // CEYLAN_USES_CONFIG_H 00041 00042 00043 00044 using namespace Ceylan::System ; 00045 using namespace Ceylan::Network ; 00046 using namespace Ceylan::Log ; 00047 00048 00049 using std::string ; 00050 using std::list ; 00051 using std::set ; 00052 00053 00054 00055 00056 00057 MultiplexedProtocolBasedStreamServer::MultiplexedProtocolBasedStreamServer( 00058 Port listeningPort, bool reuse ) : 00059 MultiplexedServerStreamSocket( listeningPort, reuse ) 00060 { 00061 00062 // Not anything special to do here. 00063 00064 } 00065 00066 00067 00068 MultiplexedProtocolBasedStreamServer::~MultiplexedProtocolBasedStreamServer() 00069 throw() 00070 { 00071 00072 // Not anything special to do here. 00073 00074 } 00075 00076 00077 00078 AnonymousStreamSocket * MultiplexedProtocolBasedStreamServer::accept() 00079 { 00080 00081 #if CEYLAN_USES_NETWORK 00082 00083 if ( ! _bound ) 00084 prepareToAccept() ; 00085 00086 00087 #if CEYLAN_DEBUG_NETWORK_SERVERS 00088 LogPlug::trace( "MultiplexedProtocolBasedStreamServer::accept: " 00089 "will accept now connections, state is: " + toString() ) ; 00090 #endif // CEYLAN_DEBUG_NETWORK_SERVERS 00091 00092 00093 AnonymousProtocolAwareStreamSocket * protocolSocket ; 00094 00095 try 00096 { 00097 00098 /* 00099 * Accepts the connection, by passing the listening file descriptor: 00100 * 00101 * No particular protocol server can be set here, see 00102 * the customizeProtocolFor method. 00103 * 00104 */ 00105 protocolSocket = new AnonymousProtocolAwareStreamSocket( 00106 getOriginalFileDescriptor() ) ; 00107 00108 } 00109 catch( const AnonymousStreamSocket::NonBlockingAcceptException & e ) 00110 { 00111 00112 LogPlug::warning( "MultiplexedProtocolBasedStreamServer::accept " 00113 "cancelled: " + e.toString() ) ; 00114 00115 return 0 ; 00116 00117 } 00118 catch( const SocketException & e ) 00119 { 00120 throw MultiplexedServerStreamSocketException( 00121 "MultiplexedProtocolBasedStreamServer::accept failed: " 00122 + e.toString() ) ; 00123 } 00124 00125 _currentConnections.insert( protocolSocket ) ; 00126 00127 00128 #if CEYLAN_DEBUG_NETWORK_SERVERS 00129 LogPlug::trace( "MultiplexedProtocolBasedStreamServer::accept: " 00130 "new connection accepted by the anonymous socket." ) ; 00131 #endif // CEYLAN_DEBUG_NETWORK_SERVERS 00132 00133 00134 /* 00135 * The user-supplied accepted method must link a protocol server to the 00136 * newly created AnonymousProtocolAwareStreamSocket: 00137 * 00138 */ 00139 accepted( *protocolSocket ) ; 00140 00141 if ( ! protocolSocket->hasProtocolServer() ) 00142 throw MultiplexedServerStreamSocketException( 00143 "MultiplexedProtocolBasedStreamServer::accept: " 00144 "the user-overriden accepted() method did not set " 00145 "a protocol server to: " + protocolSocket->toString() ) ; 00146 00147 00148 #if CEYLAN_DEBUG_NETWORK_SERVERS 00149 LogPlug::trace( "MultiplexedProtocolBasedStreamServer::accept: " 00150 "connection registered" ) ; 00151 #endif // CEYLAN_DEBUG_NETWORK_SERVERS 00152 00153 00154 // No cleanAfterAccept() called, since connections are still alive here. 00155 00156 return protocolSocket ; 00157 00158 00159 #else // CEYLAN_USES_NETWORK 00160 00161 00162 throw ServerStreamSocketException( 00163 "MultiplexedProtocolBasedStreamServer::accept: " 00164 "network feature not available." ) ; 00165 00166 00167 #endif // CEYLAN_USES_NETWORK 00168 00169 } 00170 00171 00172 00173 void MultiplexedProtocolBasedStreamServer::accepted( 00174 AnonymousStreamSocket & newConnection ) 00175 { 00176 00177 throw ServerStreamSocketException( 00178 "MultiplexedProtocolBasedStreamServer::accepted: " 00179 "this method must be overriden by the user " 00180 "(and it must set a protocol server of the new connection socket)." ) ; 00181 00182 } 00183 00184 00185 00186 bool MultiplexedProtocolBasedStreamServer::handleConnection( 00187 AnonymousStreamSocket & connection ) 00188 { 00189 00190 #if CEYLAN_DEBUG_NETWORK_SERVERS 00191 LogPlug::trace( "MultiplexedProtocolBasedStreamServer::handleConnection " 00192 "for " + connection.toString( Ceylan::low ) ) ; 00193 #endif // CEYLAN_DEBUG_NETWORK_SERVERS 00194 00195 00196 AnonymousProtocolAwareStreamSocket * realSocket = 00197 dynamic_cast<AnonymousProtocolAwareStreamSocket *>( & connection ) ; 00198 00199 /* 00200 * No test needed, it is really a protocol-aware socket, and it has 00201 * a protocol server attached indeed. 00202 * 00203 */ 00204 00205 try 00206 { 00207 00208 return realSocket->getProtocolServer().notifyDataAvailability() ; 00209 00210 } 00211 catch( const AnonymousStreamSocket::AnonymousStreamSocketException & e ) 00212 { 00213 00214 throw MultiplexedServerStreamSocketException( 00215 "MultiplexedProtocolBasedStreamServer::handleConnection: " 00216 + e.toString() ) ; 00217 00218 } 00219 catch( const Middleware::ProtocolException & e ) 00220 { 00221 00222 // Do not kill the server for a connection-level error: 00223 LogPlug::error( 00224 "MultiplexedProtocolBasedStreamServer::handleConnection: " 00225 + e.toString() + ". Killing the connection." ) ; 00226 00227 // .. but kill the connection: 00228 return false ; 00229 00230 } 00231 00232 } 00233 00234 00235 00236 void MultiplexedProtocolBasedStreamServer::closeConnection( 00237 AnonymousStreamSocket & connection ) 00238 { 00239 00240 if ( _currentConnections.find( &connection ) != _currentConnections.end() ) 00241 { 00242 00243 AnonymousProtocolAwareStreamSocket * realSocket = 00244 dynamic_cast<AnonymousProtocolAwareStreamSocket *>( & connection ) ; 00245 00246 /* 00247 * No test needed, it is really a protocol-aware socket, and it has 00248 * a protocol server attached indeed. 00249 * 00250 */ 00251 if ( realSocket->getProtocolServer().isShutdownRequested() ) 00252 requestToStop() ; 00253 00254 delete &connection ; 00255 _currentConnections.erase( &connection ) ; 00256 00257 } 00258 else 00259 throw MultiplexedServerStreamSocketException( 00260 "MultiplexedServerStreamSocket::closeConnection: " 00261 "unable to find following connection: " + connection.toString() ) ; 00262 00263 } 00264 00265 00266 00267 const std::string MultiplexedProtocolBasedStreamServer::toString( 00268 Ceylan::VerbosityLevels level ) const 00269 { 00270 00271 #if CEYLAN_USES_NETWORK 00272 00273 string res = "MultiplexedProtocolBasedStreamServer" ; 00274 00275 if ( _currentConnections.empty() ) 00276 { 00277 res += " currently not managing any connection" ; 00278 } 00279 else 00280 { 00281 00282 list<string> connectionDescriptions ; 00283 00284 for ( set<AnonymousStreamSocket *>::const_iterator it = 00285 _currentConnections.begin(); it != _currentConnections.end(); 00286 it++ ) 00287 connectionDescriptions.push_back( (*it)->toString( level ) ) ; 00288 00289 res += " managing currently following connection(s): " 00290 + Ceylan::formatStringList( connectionDescriptions ) ; 00291 00292 } 00293 00294 if ( level == Ceylan::medium ) 00295 return res ; 00296 00297 return res + ". " + StreamSocket::toString( level ) ; 00298 00299 #else // CEYLAN_USES_NETWORK 00300 00301 return "MultiplexedProtocolBasedStreamServer " 00302 "(no network support not available)" ; 00303 00304 #endif // CEYLAN_USES_NETWORK 00305 00306 } 00307