gloox  1.0.1
connectiontcpbase.cpp
1 /*
2  Copyright (c) 2004-2012 by Jakob Schroeter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 
14 
15 #include "gloox.h"
16 
17 #include "connectiontcpbase.h"
18 #include "dns.h"
19 #include "logsink.h"
20 #include "prep.h"
21 #include "mutexguard.h"
22 #include "util.h"
23 
24 #ifdef __MINGW32__
25 # include <winsock.h>
26 #endif
27 
28 #if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
29 # include <arpa/inet.h>
30 # include <sys/types.h>
31 # include <sys/socket.h>
32 # include <sys/select.h>
33 # include <netinet/in.h>
34 # include <unistd.h>
35 # include <string.h>
36 # include <errno.h>
37 #elif ( defined( _WIN32 ) || defined( _WIN32_WCE ) ) && !defined( __SYMBIAN32__ )
38 # include <winsock.h>
39 typedef int socklen_t;
40 #endif
41 
42 #include <ctime>
43 
44 #include <cstdlib>
45 #include <string>
46 
47 namespace gloox
48 {
49 
51  const std::string& server, int port )
52  : ConnectionBase( 0 ),
53  m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ),
54  m_totalBytesOut( 0 ), m_bufsize( 8192 ), m_cancel( true )
55  {
56  init( server, port );
57  }
58 
60  const std::string& server, int port )
61  : ConnectionBase( cdh ),
62  m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ),
63  m_totalBytesOut( 0 ), m_bufsize( 8192 ), m_cancel( true )
64  {
65  init( server, port );
66  }
67 
68  void ConnectionTCPBase::init( const std::string& server, int port )
69  {
70 // FIXME check return value?
71  prep::idna( server, m_server );
72  m_port = port;
73  m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );
74  }
75 
77  {
78  cleanup();
79  free( m_buf );
80  m_buf = 0;
81  }
82 
84  {
85  util::MutexGuard rm( m_recvMutex );
86  m_cancel = true;
87  }
88 
89  bool ConnectionTCPBase::dataAvailable( int timeout )
90  {
91  if( m_socket < 0 )
92  return true; // let recv() catch the closed fd
93 
94  fd_set fds;
95  struct timeval tv;
96 
97  FD_ZERO( &fds );
98  // the following causes a C4127 warning in VC++ Express 2008 and possibly other versions.
99  // however, the reason for the warning can't be fixed in gloox.
100  FD_SET( m_socket, &fds );
101 
102  tv.tv_sec = timeout / 1000000;
103  tv.tv_usec = timeout % 1000000;
104 
105  return ( ( select( m_socket + 1, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 )
106  && FD_ISSET( m_socket, &fds ) != 0 );
107  }
108 
110  {
111  if( m_socket < 0 )
112  return ConnNotConnected;
113 
115  while( !m_cancel && ( err = recv( 1000000 ) ) == ConnNoError )
116  ;
117  return err == ConnNoError ? ConnNotConnected : err;
118  }
119 
120  bool ConnectionTCPBase::send( const std::string& data )
121  {
122  m_sendMutex.lock();
123 
124  if( data.empty() || ( m_socket < 0 ) )
125  {
126  m_sendMutex.unlock();
127  return false;
128  }
129 
130  int sent = 0;
131  for( size_t num = 0, len = data.length(); sent != -1 && num < len; num += sent )
132  {
133  sent = static_cast<int>( ::send( m_socket, (data.c_str()+num), (int)(len - num), 0 ) );
134  }
135 
136  m_totalBytesOut += (int)data.length();
137 
138  m_sendMutex.unlock();
139 
140  if( sent == -1 )
141  {
142  // send() failed for an unexpected reason
143  std::string message = "send() failed. "
144 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
145  "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
146 #else
147  "errno: " + util::int2string( errno ) + ": " + strerror( errno );
148 #endif
149  m_logInstance.err( LogAreaClassConnectionTCPBase, message );
150 
151  if( m_handler )
153  }
154 
155  return sent != -1;
156  }
157 
158  void ConnectionTCPBase::getStatistics( long int &totalIn, long int &totalOut )
159  {
160  totalIn = m_totalBytesIn;
161  totalOut = m_totalBytesOut;
162  }
163 
165  {
166  if( !m_sendMutex.trylock() )
167  return;
168 
169  if( !m_recvMutex.trylock() )
170  {
171  m_sendMutex.unlock();
172  return;
173  }
174 
175  if( m_socket >= 0 )
176  {
177  DNS::closeSocket( m_socket, m_logInstance );
178  m_socket = -1;
179  }
180 
182  m_cancel = true;
183  m_totalBytesIn = 0;
184  m_totalBytesOut = 0;
185 
186  m_recvMutex.unlock(),
187  m_sendMutex.unlock();
188  }
189 
191  {
192  struct sockaddr local;
193  socklen_t len = (socklen_t)sizeof( local );
194  if( getsockname ( m_socket, &local, &len ) < 0 )
195  return -1;
196  else
197  return ntohs( ((struct sockaddr_in *)&local)->sin_port );
198  }
199 
200  const std::string ConnectionTCPBase::localInterface() const
201  {
202  struct sockaddr_in local;
203  socklen_t len = (socklen_t)sizeof( local );
204  if( getsockname ( m_socket, (reinterpret_cast<struct sockaddr*>( &local )), &len ) < 0 )
205  return EmptyString;
206  else
207  {
208 // char addr[INET_ADDRSTRLEN];
209 // return inet_ntop( AF_INET, &(local.sin_addr), addr, sizeof( addr ) ); //FIXME is this portable?
210  return inet_ntoa( local.sin_addr );
211  }
212  }
213 
214 }