00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "CeylanServerStreamSocket.h"
00028
00029
00030 #include "CeylanLogPlug.h"
00031 #include "CeylanOperators.h"
00032 #include "CeylanThread.h"
00033 #include "CeylanAnonymousStreamSocket.h"
00034
00035
00036
00037
00038 #include "CeylanSystemSpecificSocketAddress.h"
00039
00040
00041 #ifdef CEYLAN_USES_CONFIG_H
00042 #include "CeylanConfig.h"
00043 #endif // CEYLAN_USES_CONFIG_H
00044
00045
00046
00047 extern "C"
00048 {
00049
00050 #ifdef CEYLAN_USES_UNISTD_H
00051
00052 #endif // CEYLAN_USES_UNISTD_H
00053
00054 #ifdef CEYLAN_USES_SYS_TYPES_H
00055 #include <sys/types.h>
00056 #endif // CEYLAN_USES_SYS_TYPES_H
00057
00058 #ifdef CEYLAN_USES_SYS_SOCKET_H
00059 #include <sys/socket.h>
00060 #endif // CEYLAN_USES_SYS_SOCKET_H
00061
00062 #ifdef CEYLAN_USES_ARPA_INET_H
00063 #include <arpa/inet.h>
00064 #endif // CEYLAN_USES_ARPA_INET_H
00065
00066 #ifdef CEYLAN_USES_NETINET_IN_H
00067 #include <netinet/in.h>
00068 #endif // CEYLAN_USES_NETINET_IN_H
00069
00070 }
00071
00072
00073 using namespace Ceylan::System ;
00074 using namespace Ceylan::Network ;
00075 using namespace Ceylan::Log ;
00076
00077
00078 using std::string ;
00079
00080
00081 #ifdef DEBUG_NETWORK_SERVERS
00082
00083 #define DISPLAY_NET_DEBUG(message) LogPlug::trace(message )
00084
00085 #else // DEBUG_NETWORK_SERVERS
00086
00087 #define DISPLAY_NET_DEBUG(message)
00088
00089 #endif // DEBUG_NETWORK_SERVERS
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 ServerStreamSocket::ServerStreamSocketException::ServerStreamSocketException(
00105 const std::string & reason ) :
00106 StreamSocketException( reason )
00107 {
00108
00109 }
00110
00111
00112
00113 ServerStreamSocket::ServerStreamSocketException::~ServerStreamSocketException()
00114 throw()
00115 {
00116
00117 }
00118
00119
00120
00121
00122 ServerStreamSocket::ServerStreamSocket( Port serverPort, bool reuse,
00123 bool blocking ) :
00124 StreamSocket( serverPort, blocking ),
00125 _bound( false ),
00126 _stopRequested( false ),
00127 _maximumPendingConnectionsCount( DefaultMaximumPendingConnectionsCount )
00128 {
00129
00130 #if CEYLAN_USES_NETWORK
00131
00132 if ( reuse )
00133 {
00134
00135
00136 int reuseOption = 1 ;
00137
00138
00139
00140
00141
00142
00143
00144
00145 if ( ::setsockopt( getOriginalFileDescriptor(),
00146 SOL_SOCKET,
00147 SO_REUSEADDR,
00148 reinterpret_cast<char *>( &reuseOption ),
00149 sizeof( reuseOption ) ) != 0 )
00150 throw ServerStreamSocketException(
00151 "ServerStreamSocket constructor: "
00152 "could not set reuse option on listening socket: "
00153 + System::explainError() ) ;
00154 }
00155
00156 #else // CEYLAN_USES_NETWORK
00157
00158 throw ServerStreamSocketException(
00159 "ServerStreamSocket constructor failed: "
00160 "network support not available." ) ;
00161
00162 #endif // CEYLAN_USES_NETWORK
00163
00164 }
00165
00166
00167
00168 ServerStreamSocket::~ServerStreamSocket() throw()
00169 {
00170
00171
00172
00173 }
00174
00175
00176
00177 void ServerStreamSocket::run()
00178 {
00179
00180 DISPLAY_NET_DEBUG( "Entering in ServerStreamSocket::run" ) ;
00181
00182
00183 Ceylan::Uint32 connectionCount = 0 ;
00184
00185 while ( ! isRequestedToStop() )
00186 {
00187
00188 connectionCount++ ;
00189
00190 DISPLAY_NET_DEBUG( "ServerStreamSocket::run: waiting for connection #"
00191 + Ceylan::toString( connectionCount ) ) ;
00192
00193 accept() ;
00194
00195 }
00196
00197 DISPLAY_NET_DEBUG( "Exiting from ServerStreamSocket::run" ) ;
00198
00199 }
00200
00201
00202
00203 Port ServerStreamSocket::getLocalPort() const
00204 {
00205
00206 return _port ;
00207
00208 }
00209
00210
00211
00212 ServerStreamSocket::ConnectionCount
00213 ServerStreamSocket::getMaximumPendingConnectionsCount() const
00214 {
00215
00216 return _maximumPendingConnectionsCount ;
00217
00218 }
00219
00220
00221
00222 void ServerStreamSocket::setMaximumPendingConnectionsCount(
00223 ConnectionCount newMax )
00224 {
00225 _maximumPendingConnectionsCount = newMax ;
00226 }
00227
00228
00229
00230 const std::string ServerStreamSocket::toString( Ceylan::VerbosityLevels level )
00231 const
00232 {
00233
00234 #if CEYLAN_USES_NETWORK
00235
00236 string res ;
00237
00238
00239 if ( _bound )
00240 res = "ServerStreamSocket bound and listening for new connections" ;
00241 else
00242 res = "ServerStreamSocket not ready to accept new connections" ;
00243
00244 res += ". " ;
00245
00246 if ( _stopRequested )
00247 res = "ServerStreamSocket is requested to stop" ;
00248 else
00249 res = "ServerStreamSocket is not requested to stop" ;
00250
00251 if ( level == Ceylan::low )
00252 return res ;
00253
00254 res += ". The current maximum number of pending connections "
00255 "for this server stream socket is "
00256 + Ceylan::toString( getMaximumPendingConnectionsCount() ) ;
00257
00258 if ( level == Ceylan::medium )
00259 return res ;
00260
00261 return res + ". " + StreamSocket::toString( level ) ;
00262
00263 #else // CEYLAN_USES_NETWORK
00264
00265 return "ServerStreamSocket (no network support not available)" ;
00266
00267 #endif // CEYLAN_USES_NETWORK
00268
00269 }
00270
00271
00272
00273 void ServerStreamSocket::prepareToAccept()
00274 {
00275
00276
00277 #if CEYLAN_USES_NETWORK
00278
00279
00280
00281
00282
00283
00284
00285
00286 DISPLAY_NET_DEBUG( "Entering ServerStreamSocket::prepareToAccept" ) ;
00287
00288 if ( _bound )
00289 throw ServerStreamSocketException(
00290 "ServerStreamSocket::prepareToAccept: socket already bound" ) ;
00291
00292 _address->_socketAddress.sin_addr.s_addr = htonl(
00293 INADDR_ANY ) ;
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 Ceylan::Uint8 bindAttemptCount = 0 ;
00306 const Ceylan::Uint8 maxBindAttemptCount = 5 ;
00307
00308 for ( ; bindAttemptCount < maxBindAttemptCount; bindAttemptCount++ )
00309 {
00310
00311 DISPLAY_NET_DEBUG( "ServerStreamSocket::prepareToAccept: "
00312 "bind attempt #" + Ceylan::toString( bindAttemptCount + 1 ) ) ;
00313
00314 if ( ::bind( getOriginalFileDescriptor(),
00315 reinterpret_cast<sockaddr *>(
00316 & _address->_socketAddress ),
00317 sizeof( sockaddr_in ) ) == 0 )
00318 break ;
00319
00320
00321 Thread::Sleep( 0 , 500000 ) ;
00322
00323 }
00324
00325 if ( bindAttemptCount == maxBindAttemptCount )
00326 throw ServerStreamSocketException(
00327 "ServerStreamSocket::prepareToAccept: bind attempts failed: "
00328 + System::explainError() ) ;
00329
00330 if ( _nagleAlgorithmDeactivated )
00331 setNagleAlgorithmTo( false ) ;
00332
00333 _bound = true ;
00334
00335 DISPLAY_NET_DEBUG( "ServerStreamSocket::prepareToAccept: bind succeeded." );
00336
00337 if ( ::listen( getOriginalFileDescriptor(),
00338 _maximumPendingConnectionsCount ) != 0 )
00339 throw ServerStreamSocketException(
00340 "ServerStreamSocket::prepareToAccept: listen failed: "
00341 + System::explainError() ) ;
00342
00343 DISPLAY_NET_DEBUG( "ServerStreamSocket::prepareToAccept: "
00344 "listen succeeded." ) ;
00345
00346
00347 #else // CEYLAN_USES_NETWORK
00348
00349 throw ServerStreamSocketException( "ServerStreamSocket::prepareToAccept: "
00350 "no network support available." ) ;
00351
00352 #endif // CEYLAN_USES_NETWORK
00353
00354 }
00355
00356
00357
00358 void ServerStreamSocket::cleanAfterAccept()
00359 {
00360
00361
00362 #if CEYLAN_USES_NETWORK
00363
00364 DISPLAY_NET_DEBUG( "Entering ServerStreamSocket::cleanAfterAccept" ) ;
00365
00366 closeAcceptedConnections() ;
00367
00368 #else // CEYLAN_USES_NETWORK
00369
00370 throw ServerStreamSocketException( "ServerStreamSocket::cleanAfterAccept: "
00371 "no network support available." ) ;
00372
00373 #endif // CEYLAN_USES_NETWORK
00374
00375 }
00376
00377
00378
00379 void ServerStreamSocket::accepted( AnonymousStreamSocket & newConnection )
00380 {
00381
00382
00383
00384 DISPLAY_NET_DEBUG( "ServerStreamSocket::accepted: "
00385 "connection up and running: " + newConnection.toString() ) ;
00386
00387 }
00388
00389
00390
00391 bool ServerStreamSocket::isRequestedToStop() const
00392 {
00393
00394 return _stopRequested ;
00395
00396 }
00397
00398
00399
00400 void ServerStreamSocket::requestToStop()
00401 {
00402
00403 DISPLAY_NET_DEBUG( "ServerStreamSocket::requestToStop" ) ;
00404
00405 _stopRequested = true ;
00406
00407 }
00408