gloox
1.0
|
00001 /* 00002 Copyright (c) 2004-2009 by Jakob Schroeter <js@camaya.net> 00003 This file is part of the gloox library. http://camaya.net/gloox 00004 00005 This software is distributed under a license. The full license 00006 agreement can be found in the file LICENSE in this distribution. 00007 This software may not be copied, modified, sold or distributed 00008 other than expressed in the named license agreement. 00009 00010 This software is distributed without any warranty. 00011 */ 00012 00013 00014 00015 #include "gloox.h" 00016 00017 #include "connectiontcpbase.h" 00018 #include "dns.h" 00019 #include "logsink.h" 00020 #include "prep.h" 00021 #include "mutexguard.h" 00022 00023 #ifdef __MINGW32__ 00024 # include <winsock.h> 00025 #endif 00026 00027 #if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ ) 00028 # include <arpa/inet.h> 00029 # include <sys/types.h> 00030 # include <sys/socket.h> 00031 # include <sys/select.h> 00032 # include <netinet/in.h> 00033 # include <unistd.h> 00034 #elif ( defined( _WIN32 ) || defined( _WIN32_WCE ) ) && !defined( __SYMBIAN32__ ) 00035 # include <winsock.h> 00036 typedef int socklen_t; 00037 #endif 00038 00039 #include <ctime> 00040 00041 #include <cstdlib> 00042 #include <string> 00043 00044 namespace gloox 00045 { 00046 00047 ConnectionTCPBase::ConnectionTCPBase( const LogSink& logInstance, 00048 const std::string& server, int port ) 00049 : ConnectionBase( 0 ), 00050 m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ), 00051 m_totalBytesOut( 0 ), m_bufsize( 1024 ), m_cancel( true ) 00052 { 00053 init( server, port ); 00054 } 00055 00056 ConnectionTCPBase::ConnectionTCPBase( ConnectionDataHandler* cdh, const LogSink& logInstance, 00057 const std::string& server, int port ) 00058 : ConnectionBase( cdh ), 00059 m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ), 00060 m_totalBytesOut( 0 ), m_bufsize( 1024 ), m_cancel( true ) 00061 { 00062 init( server, port ); 00063 } 00064 00065 void ConnectionTCPBase::init( const std::string& server, int port ) 00066 { 00067 // FIXME check return value? 00068 prep::idna( server, m_server ); 00069 m_port = port; 00070 m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) ); 00071 } 00072 00073 ConnectionTCPBase::~ConnectionTCPBase() 00074 { 00075 cleanup(); 00076 free( m_buf ); 00077 m_buf = 0; 00078 } 00079 00080 void ConnectionTCPBase::disconnect() 00081 { 00082 util::MutexGuard rm( m_recvMutex ); 00083 m_cancel = true; 00084 } 00085 00086 bool ConnectionTCPBase::dataAvailable( int timeout ) 00087 { 00088 if( m_socket < 0 ) 00089 return true; // let recv() catch the closed fd 00090 00091 fd_set fds; 00092 struct timeval tv; 00093 00094 FD_ZERO( &fds ); 00095 // the following causes a C4127 warning in VC++ Express 2008 and possibly other versions. 00096 // however, the reason for the warning can't be fixed in gloox. 00097 FD_SET( m_socket, &fds ); 00098 00099 tv.tv_sec = timeout / 1000000; 00100 tv.tv_usec = timeout % 1000000; 00101 00102 return ( ( select( m_socket + 1, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 ) 00103 && FD_ISSET( m_socket, &fds ) != 0 ); 00104 } 00105 00106 ConnectionError ConnectionTCPBase::receive() 00107 { 00108 if( m_socket < 0 ) 00109 return ConnNotConnected; 00110 00111 ConnectionError err = ConnNoError; 00112 while( !m_cancel && ( err = recv( 10 ) ) == ConnNoError ) 00113 ; 00114 return err == ConnNoError ? ConnNotConnected : err; 00115 } 00116 00117 bool ConnectionTCPBase::send( const std::string& data ) 00118 { 00119 m_sendMutex.lock(); 00120 00121 if( data.empty() || ( m_socket < 0 ) ) 00122 { 00123 m_sendMutex.unlock(); 00124 return false; 00125 } 00126 00127 int sent = 0; 00128 for( size_t num = 0, len = data.length(); sent != -1 && num < len; num += sent ) 00129 { 00130 sent = static_cast<int>( ::send( m_socket, (data.c_str()+num), (int)(len - num), 0 ) ); 00131 } 00132 00133 m_totalBytesOut += (int)data.length(); 00134 00135 m_sendMutex.unlock(); 00136 00137 if( sent == -1 && m_handler ) 00138 m_handler->handleDisconnect( this, ConnIoError ); 00139 00140 return sent != -1; 00141 } 00142 00143 void ConnectionTCPBase::getStatistics( long int &totalIn, long int &totalOut ) 00144 { 00145 totalIn = m_totalBytesIn; 00146 totalOut = m_totalBytesOut; 00147 } 00148 00149 void ConnectionTCPBase::cleanup() 00150 { 00151 if( !m_sendMutex.trylock() ) 00152 return; 00153 00154 if( !m_recvMutex.trylock() ) 00155 { 00156 m_sendMutex.unlock(); 00157 return; 00158 } 00159 00160 if( m_socket >= 0 ) 00161 { 00162 DNS::closeSocket( m_socket, m_logInstance ); 00163 m_socket = -1; 00164 } 00165 00166 m_state = StateDisconnected; 00167 m_cancel = true; 00168 m_totalBytesIn = 0; 00169 m_totalBytesOut = 0; 00170 00171 m_recvMutex.unlock(), 00172 m_sendMutex.unlock(); 00173 } 00174 00175 int ConnectionTCPBase::localPort() const 00176 { 00177 struct sockaddr local; 00178 socklen_t len = (socklen_t)sizeof( local ); 00179 if( getsockname ( m_socket, &local, &len ) < 0 ) 00180 return -1; 00181 else 00182 return ntohs( ((struct sockaddr_in *)&local)->sin_port ); 00183 } 00184 00185 const std::string ConnectionTCPBase::localInterface() const 00186 { 00187 struct sockaddr_in local; 00188 socklen_t len = (socklen_t)sizeof( local ); 00189 if( getsockname ( m_socket, (reinterpret_cast<struct sockaddr*>( &local )), &len ) < 0 ) 00190 return EmptyString; 00191 else 00192 { 00193 // char addr[INET_ADDRSTRLEN]; 00194 // return inet_ntop( AF_INET, &(local.sin_addr), addr, sizeof( addr ) ); //FIXME is this portable? 00195 return inet_ntoa( local.sin_addr ); 00196 } 00197 } 00198 00199 }