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 "CeylanAnonymousStreamSocket.h" 00028 00029 00030 #include "CeylanLogPlug.h" // for LogPlug 00031 #include "CeylanOperators.h" // for toString 00032 #include "CeylanNetwork.h" // for getSocketError 00033 00034 00035 // for SystemSpecificSocketAddress: 00036 #include "CeylanSystemSpecificSocketAddress.h" 00037 00038 00039 #ifdef CEYLAN_USES_CONFIG_H 00040 #include "CeylanConfig.h" // for configure-time feature settings 00041 #endif // CEYLAN_USES_CONFIG_H 00042 00043 00044 00045 extern "C" 00046 { 00047 00048 #ifdef CEYLAN_USES_UNISTD_H 00049 //#include <unistd.h> // for FIXME 00050 #endif // CEYLAN_USES_UNISTD_H 00051 00052 #ifdef CEYLAN_USES_SYS_TYPES_H 00053 #include <sys/types.h> // for bind, accept 00054 #endif // CEYLAN_USES_SYS_TYPES_H 00055 00056 #ifdef CEYLAN_USES_SYS_SOCKET_H 00057 #include <sys/socket.h> // for bind, listen, accept 00058 #endif // CEYLAN_USES_SYS_SOCKET_H 00059 00060 #ifdef CEYLAN_USES_ARPA_INET_H 00061 #include <arpa/inet.h> // for htonl, sockaddr_in 00062 #endif // CEYLAN_USES_ARPA_INET_H 00063 00064 #ifdef CEYLAN_USES_NETINET_IN_H 00065 #include <netinet/in.h> // for htonl, sockaddr_in 00066 #endif // CEYLAN_USES_NETINET_IN_H 00067 00068 } 00069 00070 00071 #include <cerrno> // for EAGAIN 00072 00073 00074 using namespace Ceylan::System ; 00075 using namespace Ceylan::Network ; 00076 using namespace Ceylan::Log ; 00077 00078 00079 using std::string ; 00080 00081 00082 00083 /* 00084 * Avoid::htonl, use directy htonl since it is a macro on some platforms 00085 * (ex: NetBSD) 00086 * 00087 */ 00088 00089 00090 00091 AnonymousStreamSocket::AnonymousStreamSocketException::AnonymousStreamSocketException( const std::string & reason ) : 00092 StreamSocketException( reason ) 00093 { 00094 00095 } 00096 00097 00098 00099 AnonymousStreamSocket::AnonymousStreamSocketException::~AnonymousStreamSocketException() throw() 00100 { 00101 00102 } 00103 00104 00105 00106 AnonymousStreamSocket::NonBlockingAcceptException::NonBlockingAcceptException( 00107 const std::string & reason ) : 00108 AnonymousStreamSocketException( reason ) 00109 { 00110 00111 } 00112 00113 00114 00115 AnonymousStreamSocket::NonBlockingAcceptException::~NonBlockingAcceptException() 00116 throw() 00117 { 00118 00119 } 00120 00121 00122 00123 AnonymousStreamSocket::AnonymousStreamSocket( 00124 Ceylan::System::FileDescriptor listeningFD, 00125 bool blocking, bool sacrificeThroughputToPacketTiming ) : 00126 StreamSocket( /* blocking */ true, 00127 sacrificeThroughputToPacketTiming ) 00128 { 00129 00130 #if CEYLAN_USES_NETWORK 00131 00132 LogPlug::debug( "AnonymousStreamSocket constructor: " 00133 "ready to accept a new connection using listening file descriptor " 00134 + Ceylan::toString( listeningFD ) + "." ) ; 00135 00136 #if CEYLAN_ARCH_WINDOWS 00137 00138 // socklen_t is lacking: 00139 int addressSize = sizeof( _address->_socketAddress ) ; 00140 00141 #else // CEYLAN_ARCH_WINDOWS 00142 00143 socklen_t addressSize = static_cast<socklen_t>( 00144 sizeof( _address->_socketAddress ) ) ; 00145 00146 #endif // CEYLAN_ARCH_WINDOWS 00147 00148 /* 00149 * A time-out could be added, in case the connection request was cancelled 00150 * after the select but before this accept, if ever blocking sockets 00151 * were chosen (non-blocking are to be preferred anyway): 00152 * 00153 */ 00154 _originalFD = static_cast<System::FileDescriptor>(::accept( listeningFD, 00155 reinterpret_cast<sockaddr *>( & _address->_socketAddress ), 00156 & addressSize ) ) ; 00157 00158 #if CEYLAN_ARCH_WINDOWS 00159 if ( _originalFD == INVALID_SOCKET ) 00160 { 00161 00162 if ( Network::getSocketError() == WSAEWOULDBLOCK ) 00163 #else // CEYLAN_ARCH_WINDOWS 00164 if ( _originalFD == -1 ) 00165 { 00166 00167 if ( System::getError() == EAGAIN ) 00168 #endif // CEYLAN_ARCH_WINDOWS 00169 { 00170 00171 /* 00172 * With non-blocking sockets, accept with no available connection 00173 * returns EAGAIN: 00174 * 00175 */ 00176 throw NonBlockingAcceptException( 00177 "AnonymousStreamSocket constructor: " 00178 "no available connection found." ) ; 00179 00180 } 00181 else 00182 { 00183 00184 throw AnonymousStreamSocketException( 00185 "AnonymousStreamSocket constructor failed: " 00186 + System::explainError() ) ; 00187 } 00188 00189 } 00190 00191 00192 LogPlug::debug( "AnonymousStreamSocket constructor: " 00193 "new connection accepted." ) ; 00194 00195 // This new file descriptor comes blocking: 00196 if ( blocking == false ) 00197 setBlocking( false ) ; 00198 00199 if ( _nagleAlgorithmDeactivated ) 00200 setNagleAlgorithmTo( false ) ; 00201 00202 00203 #else // CEYLAN_USES_NETWORK 00204 00205 throw AnonymousStreamSocketException( 00206 "AnonymousStreamSocket constructor failed: " 00207 "network support not available." ) ; 00208 00209 #endif // CEYLAN_USES_NETWORK 00210 00211 } 00212 00213 00214 00215 AnonymousStreamSocket::~AnonymousStreamSocket() throw() 00216 { 00217 00218 // StreamSocket takes care of everything needed. 00219 00220 } 00221 00222 00223 00224 bool AnonymousStreamSocket::isConnected() const 00225 { 00226 00227 return true ; 00228 00229 } 00230 00231 00232 00233 const std::string AnonymousStreamSocket::toString( 00234 Ceylan::VerbosityLevels level ) const 00235 { 00236 00237 #if CEYLAN_USES_NETWORK 00238 00239 return "AnonymousStreamSocket managing the connection-dedicated " 00240 "file descriptor " + Ceylan::toString( _originalFD ) ; 00241 00242 #else // CEYLAN_USES_NETWORK 00243 00244 return "AnonymousStreamSocket (no network support not available)" ; 00245 00246 #endif // CEYLAN_USES_NETWORK 00247 00248 } 00249