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 "CeylanSocket.h"
00028
00029 #include "CeylanLogPlug.h"
00030 #include "CeylanOperators.h"
00031 #include "CeylanStringUtils.h"
00032 #include "CeylanNetwork.h"
00033
00034
00035
00036 #include "CeylanSystemSpecificSocketAddress.h"
00037
00038
00039
00040
00041 #ifdef CEYLAN_USES_CONFIG_H
00042 #include "CeylanConfig.h"
00043 #endif // CEYLAN_USES_CONFIG_H
00044
00045
00046
00047
00048
00049 extern "C"
00050 {
00051
00052
00053 #ifdef CEYLAN_USES_SYS_TIME_H
00054 #include <sys/time.h>
00055 #endif // CEYLAN_USES_SYS_TIME_H
00056
00057
00058 #ifdef CEYLAN_USES_STRING_H
00059 #include <string.h>
00060 #endif // CEYLAN_USES_STRING_H
00061
00062
00063 #ifdef CEYLAN_USES_SYS_TYPES_H
00064 #include <sys/types.h>
00065 #endif // CEYLAN_USES_SYS_TYPES_H
00066
00067
00068 #ifdef CEYLAN_USES_SYS_SOCKET_H
00069 #include <sys/socket.h>
00070 #endif // CEYLAN_USES_SYS_SOCKET_H
00071
00072
00073 #ifdef CEYLAN_USES_UNISTD_H
00074 #include <unistd.h>
00075 #endif // CEYLAN_USES_UNISTD_H
00076
00077
00078 #ifdef CEYLAN_USES_STRING_H
00079 #include <string.h>
00080 #endif // CEYLAN_USES_STRING_H
00081
00082
00083 #ifdef CEYLAN_USES_FCNTL_H
00084 #include <fcntl.h>
00085 #endif // CEYLAN_USES_STRINGS_H
00086
00087
00088 #ifdef CEYLAN_USES_SYS_SELECT_H
00089 #include <sys/select.h>
00090 #endif // CEYLAN_USES_SYS_SELECT_H
00091
00092 #ifdef CEYLAN_USES_WINSOCK2_H
00093 #include <winsock2.h>
00094 #endif // CEYLAN_USES_WINSOCK2_H
00095
00096
00097 #pragma comment (lib , "ws2_32.lib")
00098
00099 }
00100
00101
00102
00103
00104 using namespace Ceylan ;
00105 using namespace Ceylan::Network ;
00106 using namespace Ceylan::System ;
00107 using namespace Ceylan::Log ;
00108
00109
00110 using std::string ;
00111
00112
00113
00114
00115 Socket::SocketException::SocketException( const std::string & reason ) :
00116 SystemException( reason )
00117 {
00118
00119 }
00120
00121
00122
00123 Socket::SocketException::~SocketException() throw()
00124 {
00125
00126 }
00127
00128
00129
00130
00131
00132 Socket::Socket( bool blocking ) :
00133 InputOutputStream( true ),
00134 _port( 0 ),
00135 _address( 0 ),
00136 _originalFD( 0 )
00137 {
00138
00139 #if CEYLAN_USES_NETWORK
00140
00141 _address = new SystemSpecificSocketAddress ;
00142
00143
00144
00145
00146
00147
00148
00149
00150 if ( ! blocking )
00151 setBlocking( false ) ;
00152
00153
00154 #else // CEYLAN_USES_NETWORK
00155
00156 throw SocketException( "Socket empty constructor failed: "
00157 "network support not available." ) ;
00158
00159 #endif // CEYLAN_USES_NETWORK
00160
00161 }
00162
00163
00164
00165 Socket::Socket( Port port, bool blocking ) :
00166 InputOutputStream( blocking ),
00167 _port( port ) ,
00168 _address( 0 ),
00169 _originalFD( 0 )
00170 {
00171
00172 #if CEYLAN_USES_NETWORK
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 _address = new SystemSpecificSocketAddress ;
00187
00188 if ( ! blocking )
00189 setBlocking( false ) ;
00190
00191 #else // CEYLAN_USES_NETWORK
00192
00193 throw SocketException( "Socket port-based constructor failed: "
00194 "network support not available." ) ;
00195
00196 #endif // CEYLAN_USES_NETWORK
00197
00198 }
00199
00200
00201
00202 Socket::~Socket() throw()
00203 {
00204
00205 #if CEYLAN_USES_NETWORK
00206
00207
00208 try
00209 {
00210 close() ;
00211 }
00212 catch( const Stream::CloseException & e )
00213 {
00214 LogPlug::error( "Socket destructor failed: " + e.toString() ) ;
00215 }
00216
00217 if ( _address != 0 )
00218 delete _address ;
00219
00220 #endif // CEYLAN_USES_NETWORK
00221
00222 }
00223
00224
00225
00226 bool Socket::hasAvailableData() const
00227 {
00228
00229 #if CEYLAN_USES_NETWORK
00230
00231 try
00232 {
00233 return System::HasAvailableData( getFileDescriptorForTransport() ) ;
00234 }
00235 catch( const Ceylan::Exception & e )
00236 {
00237
00238 LogPlug::error( "Socket::hasAvailableData failed: "
00239 + e.toString() ) ;
00240
00241 return false ;
00242
00243 }
00244
00245 #else // CEYLAN_USES_NETWORK
00246
00247 LogPlug::error( "Socket::hasAvailableData failed: "
00248 "network support not available." ) ;
00249
00250 return false ;
00251
00252 #endif // CEYLAN_USES_NETWORK
00253
00254 }
00255
00256
00257
00258 Size Socket::read( char * buffer, Size maxLength )
00259 {
00260
00261 #if CEYLAN_USES_NETWORK
00262
00263 try
00264 {
00265
00266 setSelected( false ) ;
00267
00268 #if CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00269 LogPlug::debug( "Socket::read: using file descriptor "
00270 + Ceylan::toString( getFileDescriptorForTransport() ) ) ;
00271 #endif // CEYLAN_DEBUG_LOW_LEVEL_STREAMS
00272
00273
00274 return System::FDRead( getFileDescriptorForTransport(),
00275 buffer, maxLength ) ;
00276
00277 }
00278 catch( const Ceylan::Exception & e )
00279 {
00280 throw ReadFailedException( "Socket::read failed: " + e.toString() ) ;
00281 }
00282
00283 #else // CEYLAN_USES_NETWORK
00284
00285 throw ReadFailedException(
00286 "Socket::read failed: network support not available." ) ;
00287
00288 #endif // CEYLAN_USES_NETWORK
00289
00290 }
00291
00292
00293
00294 Size Socket::write( const string & message )
00295 {
00296
00297 #if CEYLAN_USES_NETWORK
00298
00299 Size n ;
00300
00301 StringSize messageSize = message.size() ;
00302
00303 try
00304 {
00305
00306 n = System::FDWrite( getFileDescriptorForTransport(),
00307 message.c_str(), messageSize ) ;
00308 }
00309 catch( const Ceylan::Exception & e )
00310 {
00311 throw WriteFailedException( "Socket::write (std::string) failed: "
00312 + e.toString() ) ;
00313 }
00314
00315
00316
00317 if ( n < messageSize )
00318 throw WriteFailedException( "Socket::write (std::string) failed: "
00319 + System::explainError() ) ;
00320
00321 return n ;
00322
00323 #else // if CEYLAN_USES_NETWORK
00324
00325 throw WriteFailedException( "Socket::write (std::string) failed: "
00326 "network support not available." ) ;
00327
00328 #endif // if CEYLAN_USES_NETWORK
00329
00330 }
00331
00332
00333
00334 Size Socket::write( const char * buffer, Size maxLength )
00335 {
00336
00337 #if CEYLAN_USES_NETWORK
00338
00339 Size n ;
00340
00341 try
00342 {
00343 n = System::FDWrite( getFileDescriptorForTransport(),
00344 buffer, maxLength ) ;
00345 }
00346 catch( const Ceylan::Exception & e )
00347 {
00348 throw WriteFailedException( "Socket::write (char *) failed: "
00349 + e.toString() ) ;
00350 }
00351
00352
00353
00354 if ( n < maxLength )
00355 throw WriteFailedException( "Socket::write (char *) failed: "
00356 + System::explainError() ) ;
00357
00358 return n ;
00359
00360 #else // CEYLAN_USES_NETWORK
00361
00362 throw WriteFailedException( "Socket::write (char *) failed: "
00363 "network support not available." ) ;
00364
00365 #endif // CEYLAN_USES_NETWORK
00366
00367 }
00368
00369
00370
00371 FileDescriptor Socket::getOriginalFileDescriptor() const
00372 {
00373
00374 #if CEYLAN_USES_NETWORK
00375
00376 return _originalFD ;
00377
00378 #else // CEYLAN_USES_NETWORK
00379
00380 throw Features::FeatureNotAvailableException(
00381 "Socket::getOriginalFileDescriptor: network support not available." ) ;
00382
00383 #endif // CEYLAN_USES_NETWORK
00384
00385 }
00386
00387
00388
00389 FileDescriptor Socket::getFileDescriptorForTransport() const
00390 {
00391
00392 #if CEYLAN_USES_NETWORK
00393
00394
00395 return _originalFD ;
00396
00397 #else // CEYLAN_USES_NETWORK
00398
00399 throw Features::FeatureNotAvailableException(
00400 "Socket::getOriginalFileDescriptor: network support not available." ) ;
00401
00402 #endif // CEYLAN_USES_NETWORK
00403
00404 }
00405
00406
00407
00408 Port Socket::getLocalPort() const
00409 {
00410
00411 throw SocketException( "Socket::getLocalPort: not implemented yet." ) ;
00412
00413 }
00414
00415
00416
00417 Port Socket::getPeerPort() const
00418 {
00419
00420 throw SocketException( "Socket::getPeerPort: not implemented yet." ) ;
00421
00422 }
00423
00424
00425
00426 IPAddress * Socket::getLocalIPAddress() const
00427 {
00428
00429 throw SocketException(
00430 "Socket::getLocalIPAddress: not implemented yet." ) ;
00431
00432 }
00433
00434
00435
00436 IPAddress * Socket::getPeerIPAddress() const
00437 {
00438
00439 throw SocketException(
00440 "Socket::getPeerIPAddress: not implemented yet." ) ;
00441
00442 }
00443
00444
00445
00446 StreamID Socket::getInputStreamID() const
00447 {
00448
00449 #if CEYLAN_USES_NETWORK
00450
00451 try
00452 {
00453 return static_cast<StreamID>( getFileDescriptorForTransport() ) ;
00454 }
00455 catch( const Ceylan::Exception & e )
00456 {
00457 throw InputStreamException( "Socket::getInputStreamID failed: "
00458 + e.toString() ) ;
00459 }
00460
00461
00462 #else // CEYLAN_USES_NETWORK
00463
00464 throw SocketException( "Socket::getInputStreamID failed: "
00465 "network feature not available." ) ;
00466
00467 #endif // CEYLAN_USES_NETWORK
00468
00469 }
00470
00471
00472
00473 StreamID Socket::getOutputStreamID() const
00474 {
00475
00476 #if CEYLAN_USES_NETWORK
00477
00478 try
00479 {
00480 return static_cast<StreamID>( getFileDescriptorForTransport() ) ;
00481 }
00482 catch( const Ceylan::Exception & e )
00483 {
00484 throw OutputStreamException( "Socket::getOutputStreamID failed: "
00485 + e.toString() ) ;
00486 }
00487
00488
00489 #else // CEYLAN_USES_NETWORK
00490
00491 throw SocketException( "Socket::getOutputStreamID failed: "
00492 "network feature not available." ) ;
00493
00494 #endif // CEYLAN_USES_NETWORK
00495
00496 }
00497
00498
00499
00500 const std::string Socket::toString( Ceylan::VerbosityLevels level ) const
00501 {
00502
00503 string res ;
00504
00505
00506 try
00507 {
00508
00509 res = "Socket associated to local port "
00510 + Ceylan::toString( getLocalPort() )
00511 + ", with original file descriptor being "
00512 + Ceylan::toString( getOriginalFileDescriptor() ) ;
00513
00514 if ( isConnected() )
00515 res += ". This Socket is currently connected, "
00516 "and the file descriptor for transport is "
00517 + Ceylan::toString( getFileDescriptorForTransport() ) ;
00518 else
00519 res += ". This Socket is currently not connected" ;
00520
00521 }
00522 catch( const Ceylan::Exception & e )
00523 {
00524 return "Socket::toString failed (abnormal)" ;
00525 }
00526
00527 if ( level == Ceylan::low )
00528 return res ;
00529
00530 if ( isBlocking() )
00531 res += ". This is a blocking socket" ;
00532 else
00533 res += ". This is a non-blocking socket" ;
00534
00535
00536
00537 return res ;
00538
00539 }
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553 bool Socket::close()
00554 {
00555
00556 #if CEYLAN_USES_NETWORK
00557
00558
00559
00560 #if CEYLAN_ARCH_WINDOWS
00561
00562 if ( _originalFD == 0 )
00563 return false ;
00564
00565 if ( ::closesocket( _originalFD ) == SOCKET_ERROR )
00566 throw Stream::CloseException( "Socket::close failed: "
00567 + Network::explainSocketError() ) ;
00568
00569 _originalFD = 0 ;
00570
00571 return true ;
00572
00573 #else // CEYLAN_ARCH_WINDOWS
00574
00575 bool res = Stream::Close( _originalFD ) ;
00576
00577 _originalFD = 0 ;
00578
00579 return res ;
00580
00581 #endif // CEYLAN_ARCH_WINDOWS
00582
00583
00584 #else // CEYLAN_USES_NETWORK
00585
00586 LogPlug::error( "Socket::close failed: network support not available." ) ;
00587
00588 return false ;
00589
00590 #endif // CEYLAN_USES_NETWORK
00591
00592 }
00593
00594
00595
00596 void Socket::setBlocking( bool newStatus )
00597 {
00598
00599
00600 _isBlocking = newStatus ;
00601
00602
00603
00604
00605
00606
00607
00608 }
00609