gloox  1.0.20
connectiontcpbase.cpp
1 /*
2  Copyright (c) 2004-2017 by Jakob Schröter <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 <winsock2.h>
26 # include <ws2tcpip.h>
27 #endif
28 
29 #if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
30 # include <arpa/inet.h>
31 # include <sys/types.h>
32 # include <sys/socket.h>
33 # include <sys/select.h>
34 # include <netinet/in.h>
35 # include <unistd.h>
36 # include <string.h>
37 # include <errno.h>
38 # include <netdb.h>
39 #elif ( defined( _WIN32 ) || defined( _WIN32_WCE ) ) && !defined( __SYMBIAN32__ )
40 # include <winsock2.h>
41 # include <ws2tcpip.h>
42 typedef int socklen_t;
43 #endif
44 
45 #include <ctime>
46 
47 #include <cstdlib>
48 #include <string>
49 
50 namespace gloox
51 {
52 
54  const std::string& server, int port )
55  : ConnectionBase( 0 ),
56  m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ),
57  m_totalBytesOut( 0 ), m_bufsize( 8192 ), m_cancel( true )
58  {
59  init( server, port );
60  }
61 
63  const std::string& server, int port )
64  : ConnectionBase( cdh ),
65  m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ),
66  m_totalBytesOut( 0 ), m_bufsize( 8192 ), m_cancel( true )
67  {
68  init( server, port );
69  }
70 
71  void ConnectionTCPBase::init( const std::string& server, int port )
72  {
73 // FIXME check return value?
74  prep::idna( server, m_server );
75  m_port = port;
76  m_buf = static_cast<char*>( calloc( m_bufsize + 1, sizeof( char ) ) );
77  }
78 
80  {
81  cleanup();
82  free( m_buf );
83  m_buf = 0;
84  }
85 
87  {
88  util::MutexGuard rm( m_recvMutex );
89  m_cancel = true;
90  }
91 
92  bool ConnectionTCPBase::dataAvailable( int timeout )
93  {
94  if( m_socket < 0 )
95  return true; // let recv() catch the closed fd
96 
97  fd_set fds;
98  struct timeval tv;
99 
100  FD_ZERO( &fds );
101  // the following causes a C4127 warning in VC++ Express 2008 and possibly other versions.
102  // however, the reason for the warning can't be fixed in gloox.
103  FD_SET( m_socket, &fds );
104 
105  tv.tv_sec = timeout / 1000000;
106  tv.tv_usec = timeout % 1000000;
107 
108  return ( ( select( m_socket + 1, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 )
109  && FD_ISSET( m_socket, &fds ) != 0 );
110  }
111 
113  {
114  if( m_socket < 0 )
115  return ConnNotConnected;
116 
118  while( !m_cancel && ( err = recv( 1000000 ) ) == ConnNoError )
119  ;
120  return err == ConnNoError ? ConnNotConnected : err;
121  }
122 
123  bool ConnectionTCPBase::send( const std::string& data )
124  {
125  m_sendMutex.lock();
126 
127  if( data.empty() || ( m_socket < 0 ) )
128  {
129  m_sendMutex.unlock();
130  return false;
131  }
132 
133  int sent = 0;
134  for( size_t num = 0, len = data.length(); sent != -1 && num < len; num += sent )
135  {
136  sent = static_cast<int>( ::send( m_socket, (data.c_str()+num), static_cast<int>( len - num ), 0 ) );
137  }
138 
139  m_totalBytesOut += data.length();
140 
141  m_sendMutex.unlock();
142 
143  if( sent == -1 )
144  {
145  // send() failed for an unexpected reason
146  std::string message = "send() failed. "
147 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
148  "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
149 #else
150  "errno: " + util::int2string( errno ) + ": " + strerror( errno );
151 #endif
152  m_logInstance.err( LogAreaClassConnectionTCPBase, message );
153 
154  if( m_handler )
156  }
157 
158  return sent != -1;
159  }
160 
161  void ConnectionTCPBase::getStatistics( long int &totalIn, long int &totalOut )
162  {
163  totalIn = m_totalBytesIn;
164  totalOut = m_totalBytesOut;
165  }
166 
168  {
169  if( !m_sendMutex.trylock() )
170  return;
171 
172  if( !m_recvMutex.trylock() )
173  {
174  m_sendMutex.unlock();
175  return;
176  }
177 
178  if( m_socket >= 0 )
179  {
180  DNS::closeSocket( m_socket, m_logInstance );
181  m_socket = -1;
182  }
183 
185  m_cancel = true;
186  m_totalBytesIn = 0;
187  m_totalBytesOut = 0;
188 
189  m_recvMutex.unlock(),
190  m_sendMutex.unlock();
191  }
192 
194  {
195  struct sockaddr local;
196  socklen_t len = static_cast<socklen_t>( sizeof( local ) );
197  if( getsockname ( m_socket, &local, &len ) < 0 )
198  return -1;
199  else
200  return ntohs( (reinterpret_cast<struct sockaddr_in*>( &local ) )->sin_port );
201  }
202 
203  const std::string ConnectionTCPBase::localInterface() const
204  {
205  struct sockaddr_storage local;
206  socklen_t len = static_cast<socklen_t>( sizeof( local ) );
207  if( getsockname( m_socket, reinterpret_cast<struct sockaddr*>( &local ), &len ) < 0 )
208  return EmptyString;
209  else
210  {
211  char buffer[INET6_ADDRSTRLEN];
212  int err = getnameinfo( reinterpret_cast<struct sockaddr*>( &local ), len, buffer, sizeof( buffer ),
213  0, 0, NI_NUMERICHOST );
214  if( !err )
215  return buffer;
216  else
217  return EmptyString;
218  }
219  }
220 
221 }
An abstract base class for a connection.
virtual ConnectionError receive()
A simple implementation of a mutex guard.
Definition: mutexguard.h:31
static void closeSocket(int fd, const LogSink &logInstance)
Definition: dns.cpp:514
virtual int localPort() const
ConnectionError
Definition: gloox.h:683
ConnectionTCPBase(const LogSink &logInstance, const std::string &server, int port=-1)
This is an abstract base class to receive events from a ConnectionBase-derived object.
virtual void handleDisconnect(const ConnectionBase *connection, ConnectionError reason)=0
The namespace for the gloox library.
Definition: adhoc.cpp:27
virtual bool send(const std::string &data)
virtual ConnectionError recv(int timeout=-1)=0
bool idna(const std::string &domain, std::string &out)
Definition: prep.cpp:107
ConnectionState m_state
ConnectionDataHandler * m_handler
virtual const std::string localInterface() const
const std::string & server() const
An implementation of log sink and source.
Definition: logsink.h:38
void err(LogArea area, const std::string &message) const
Definition: logsink.h:84
const std::string EmptyString
Definition: gloox.cpp:124
virtual void getStatistics(long int &totalIn, long int &totalOut)