gloox  1.0
connectiontcpbase.cpp
1 /*
2  Copyright (c) 2004-2009 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 
23 #ifdef __MINGW32__
24 # include <winsock.h>
25 #endif
26 
27 #if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
28 # include <arpa/inet.h>
29 # include <sys/types.h>
30 # include <sys/socket.h>
31 # include <sys/select.h>
32 # include <netinet/in.h>
33 # include <unistd.h>
34 #elif ( defined( _WIN32 ) || defined( _WIN32_WCE ) ) && !defined( __SYMBIAN32__ )
35 # include <winsock.h>
36 typedef int socklen_t;
37 #endif
38 
39 #include <ctime>
40 
41 #include <cstdlib>
42 #include <string>
43 
44 namespace gloox
45 {
46 
48  const std::string& server, int port )
49  : ConnectionBase( 0 ),
50  m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ),
51  m_totalBytesOut( 0 ), m_bufsize( 1024 ), m_cancel( true )
52  {
53  init( server, port );
54  }
55 
57  const std::string& server, int port )
58  : ConnectionBase( cdh ),
59  m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ),
60  m_totalBytesOut( 0 ), m_bufsize( 1024 ), m_cancel( true )
61  {
62  init( server, port );
63  }
64 
65  void ConnectionTCPBase::init( const std::string& server, int port )
66  {
67 // FIXME check return value?
68  prep::idna( server, m_server );
69  m_port = port;
70  m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );
71  }
72 
74  {
75  cleanup();
76  free( m_buf );
77  m_buf = 0;
78  }
79 
81  {
82  util::MutexGuard rm( m_recvMutex );
83  m_cancel = true;
84  }
85 
86  bool ConnectionTCPBase::dataAvailable( int timeout )
87  {
88  if( m_socket < 0 )
89  return true; // let recv() catch the closed fd
90 
91  fd_set fds;
92  struct timeval tv;
93 
94  FD_ZERO( &fds );
95  // the following causes a C4127 warning in VC++ Express 2008 and possibly other versions.
96  // however, the reason for the warning can't be fixed in gloox.
97  FD_SET( m_socket, &fds );
98 
99  tv.tv_sec = timeout / 1000000;
100  tv.tv_usec = timeout % 1000000;
101 
102  return ( ( select( m_socket + 1, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 )
103  && FD_ISSET( m_socket, &fds ) != 0 );
104  }
105 
107  {
108  if( m_socket < 0 )
109  return ConnNotConnected;
110 
112  while( !m_cancel && ( err = recv( 10 ) ) == ConnNoError )
113  ;
114  return err == ConnNoError ? ConnNotConnected : err;
115  }
116 
117  bool ConnectionTCPBase::send( const std::string& data )
118  {
119  m_sendMutex.lock();
120 
121  if( data.empty() || ( m_socket < 0 ) )
122  {
123  m_sendMutex.unlock();
124  return false;
125  }
126 
127  int sent = 0;
128  for( size_t num = 0, len = data.length(); sent != -1 && num < len; num += sent )
129  {
130  sent = static_cast<int>( ::send( m_socket, (data.c_str()+num), (int)(len - num), 0 ) );
131  }
132 
133  m_totalBytesOut += (int)data.length();
134 
135  m_sendMutex.unlock();
136 
137  if( sent == -1 && m_handler )
139 
140  return sent != -1;
141  }
142 
143  void ConnectionTCPBase::getStatistics( long int &totalIn, long int &totalOut )
144  {
145  totalIn = m_totalBytesIn;
146  totalOut = m_totalBytesOut;
147  }
148 
150  {
151  if( !m_sendMutex.trylock() )
152  return;
153 
154  if( !m_recvMutex.trylock() )
155  {
156  m_sendMutex.unlock();
157  return;
158  }
159 
160  if( m_socket >= 0 )
161  {
162  DNS::closeSocket( m_socket, m_logInstance );
163  m_socket = -1;
164  }
165 
167  m_cancel = true;
168  m_totalBytesIn = 0;
169  m_totalBytesOut = 0;
170 
171  m_recvMutex.unlock(),
172  m_sendMutex.unlock();
173  }
174 
176  {
177  struct sockaddr local;
178  socklen_t len = (socklen_t)sizeof( local );
179  if( getsockname ( m_socket, &local, &len ) < 0 )
180  return -1;
181  else
182  return ntohs( ((struct sockaddr_in *)&local)->sin_port );
183  }
184 
185  const std::string ConnectionTCPBase::localInterface() const
186  {
187  struct sockaddr_in local;
188  socklen_t len = (socklen_t)sizeof( local );
189  if( getsockname ( m_socket, (reinterpret_cast<struct sockaddr*>( &local )), &len ) < 0 )
190  return EmptyString;
191  else
192  {
193 // char addr[INET_ADDRSTRLEN];
194 // return inet_ntop( AF_INET, &(local.sin_addr), addr, sizeof( addr ) ); //FIXME is this portable?
195  return inet_ntoa( local.sin_addr );
196  }
197  }
198 
199 }