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 "CeylanSequentialServerStreamSocket.h" 00028 00029 00030 #include "CeylanLogPlug.h" // for LogPlug 00031 #include "CeylanOperators.h" // for toString 00032 #include "CeylanThread.h" // for Sleep 00033 #include "CeylanAnonymousStreamSocket.h" // for AnonymousStreamSocket 00034 00035 00036 00037 #ifdef CEYLAN_USES_CONFIG_H 00038 #include "CeylanConfig.h" // for configure-time feature settings 00039 #endif // CEYLAN_USES_CONFIG_H 00040 00041 00042 using namespace Ceylan ; 00043 using namespace Ceylan::System ; 00044 using namespace Ceylan::Network ; 00045 using namespace Ceylan::Log ; 00046 00047 00048 using std::string ; 00049 00050 00051 00052 #ifdef DEBUG_NETWORK_SERVERS 00053 00054 #define DISPLAY_NET_DEBUG(message) LogPlug::trace(message ) 00055 00056 #else // DEBUG_NETWORK_SERVERS 00057 00058 #define DISPLAY_NET_DEBUG(message) 00059 00060 #endif // DEBUG_NETWORK_SERVERS 00061 00062 00063 00064 00065 SequentialServerStreamSocket::SequentialServerStreamSocketException::SequentialServerStreamSocketException( const std::string & reason ) : 00066 ServerStreamSocketException( reason ) 00067 { 00068 00069 } 00070 00071 00072 SequentialServerStreamSocket::SequentialServerStreamSocketException::~SequentialServerStreamSocketException() throw() 00073 { 00074 00075 } 00076 00077 00078 00079 00080 00081 // SequentialServerStreamSocket class. 00082 00083 00084 00085 SequentialServerStreamSocket::SequentialServerStreamSocket( Port listeningPort, 00086 bool reuse ) : 00087 ServerStreamSocket( listeningPort, reuse, /* blocking */ true ), 00088 _currentConnection( 0 ) 00089 { 00090 00091 #if CEYLAN_USES_NETWORK 00092 00093 00094 #else // CEYLAN_USES_NETWORK 00095 00096 throw SequentialServerStreamSocketException( 00097 "SequentialServerStreamSocket constructor failed: " 00098 "network support not available." ) ; 00099 00100 #endif // CEYLAN_USES_NETWORK 00101 00102 } 00103 00104 00105 00106 SequentialServerStreamSocket::~SequentialServerStreamSocket() throw() 00107 { 00108 00109 #if CEYLAN_USES_NETWORK 00110 00111 // The main listening socket is taken care of in mother classes. 00112 00113 // No destructor should throw exception: 00114 try 00115 { 00116 00117 closeAcceptedConnections() ; 00118 00119 } 00120 catch( const Stream::CloseException & e ) 00121 { 00122 LogPlug::error( "SequentialServerStreamSocket destructor failed: " 00123 + e.toString() ) ; 00124 } 00125 00126 #endif // CEYLAN_USES_NETWORK 00127 00128 } 00129 00130 00131 00132 bool SequentialServerStreamSocket::isConnected() const 00133 { 00134 00135 return _currentConnection != 0 ; 00136 00137 } 00138 00139 00140 00141 AnonymousStreamSocket * SequentialServerStreamSocket::accept() 00142 { 00143 00144 #if CEYLAN_USES_NETWORK 00145 00146 if ( _currentConnection != 0 ) 00147 throw SequentialServerStreamSocketException( 00148 "SequentialServerStreamSocket::accept: " 00149 "a connection is still active" ) ; 00150 00151 if ( ! _bound ) 00152 prepareToAccept() ; 00153 00154 00155 DISPLAY_NET_DEBUG( "SequentialServerStreamSocket::accept: " 00156 "will accept now connections, state is: " + toString() ) ; 00157 00158 /* 00159 * One can notice that constructing next AnonymousStreamSocket implies 00160 * that the accept is blocking, i.e. the listening socket is created 00161 * as a blocking one. Otherwise a Select operating on this socket would 00162 * have to be used here. 00163 * 00164 */ 00165 00166 try 00167 { 00168 00169 // Accepts the connection, by passing the listening file descriptor: 00170 _currentConnection = new AnonymousStreamSocket( 00171 getOriginalFileDescriptor() ) ; 00172 00173 } 00174 catch( const SocketException & e ) 00175 { 00176 throw SequentialServerStreamSocketException( 00177 "SequentialServerStreamSocket::accept failed: " 00178 + e.toString() ) ; 00179 } 00180 00181 DISPLAY_NET_DEBUG( "SequentialServerStreamSocket::accept: " 00182 "new connection accepted, will be taken care of now: " 00183 + _currentConnection->toString() ) ; 00184 00185 accepted( *_currentConnection ) ; 00186 00187 DISPLAY_NET_DEBUG( "SequentialServerStreamSocket::accept: " 00188 "connection terminated, cleaning up afterwards" ) ; 00189 00190 cleanAfterAccept() ; 00191 00192 return 0 ; 00193 00194 #else // CEYLAN_USES_NETWORK 00195 00196 00197 throw ServerStreamSocketException( 00198 "SequentialServerStreamSocket::accept: " 00199 "network feature not available." ) ; 00200 00201 00202 #endif // CEYLAN_USES_NETWORK 00203 00204 } 00205 00206 00207 00208 FileDescriptor SequentialServerStreamSocket::getFileDescriptorForTransport() 00209 const 00210 { 00211 00212 #if CEYLAN_USES_NETWORK 00213 00214 if ( _currentConnection != 0 ) 00215 return _currentConnection->getOriginalFileDescriptor() ; 00216 else 00217 throw SequentialServerStreamSocketException( 00218 "SequentialServerStreamSocket::getFileDescriptorForTransport: " 00219 "no available connection." ) ; 00220 00221 00222 #else // CEYLAN_USES_NETWORK 00223 00224 throw Features::FeatureNotAvailableException( 00225 "SequentialServerStreamSocket::getFileDescriptorForTransport: " 00226 "network support not available." ) ; 00227 00228 #endif // CEYLAN_USES_NETWORK 00229 00230 } 00231 00232 00233 00234 const std::string SequentialServerStreamSocket::toString( 00235 Ceylan::VerbosityLevels level ) const 00236 { 00237 00238 string res = "SequentialServerStreamSocket " ; 00239 00240 #if CEYLAN_USES_NETWORK 00241 00242 00243 if ( _currentConnection != 0 ) 00244 res += "with a running connection: " 00245 + _currentConnection->toString( level ) ; 00246 else 00247 res += "not connected to any peer" ; 00248 00249 if ( level == Ceylan::low ) 00250 return res ; 00251 00252 return res + ". " + ServerStreamSocket::toString( level ) ; 00253 00254 00255 #else // CEYLAN_USES_NETWORK 00256 00257 return res + "(no network support not available)" ; 00258 00259 #endif // CEYLAN_USES_NETWORK 00260 00261 } 00262 00263 00264 00265 bool SequentialServerStreamSocket::closeAcceptedConnections() 00266 { 00267 00268 if ( _currentConnection != 0 ) 00269 { 00270 delete _currentConnection ; 00271 _currentConnection = 0 ; 00272 return true ; 00273 00274 } 00275 00276 return false ; 00277 00278 } 00279 00280