gloox  1.0.1
socks5bytestreamserver.cpp
1 /*
2  Copyright (c) 2007-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 #include "socks5bytestreamserver.h"
15 #include "mutexguard.h"
16 #include "util.h"
17 
18 namespace gloox
19 {
20 
22  const std::string& ip )
23  : m_tcpServer( 0 ), m_logInstance( logInstance ), m_ip( ip ), m_port( port )
24  {
25  m_tcpServer = new ConnectionTCPServer( this, m_logInstance, m_ip, m_port );
26  }
27 
29  {
30  if( m_tcpServer )
31  delete m_tcpServer;
32  m_tcpServer = 0;
33 
34  m_mutex.lock();
35  ConnectionMap::const_iterator it = m_connections.begin();
36  for( ; it != m_connections.end(); ++it )
37  delete (*it).first;
38  m_connections.clear();
39  util::clearList( m_oldConnections );
40  m_mutex.unlock();
41  }
42 
44  {
45  if( m_tcpServer )
46  return m_tcpServer->connect();
47 
48  return ConnNotConnected;
49  }
50 
52  {
53  if( !m_tcpServer )
54  return ConnNotConnected;
55 
56  ConnectionError ce = m_tcpServer->recv( timeout );
57  if( ce != ConnNoError )
58  return ce;
59 
60  // First take a snapshot of our connections, and then iterate the snapshot
61  // (so that the live map can be modified by an erase while we
62  // iterate the snapshot of the map)
63  ConnectionMap connectionsSnapshot;
64 
65  m_mutex.lock();
66  connectionsSnapshot.insert( m_connections.begin(), m_connections.end() );
67  m_mutex.unlock();
68 
69  ConnectionMap::const_iterator it = connectionsSnapshot.begin();
70  for( ; it != connectionsSnapshot.end(); ++it )
71  {
72  (*it).first->recv( timeout );
73  }
74  connectionsSnapshot.clear();
75 
76  m_mutex.lock();
77  util::clearList( m_oldConnections );
78  m_mutex.unlock();
79 
80  return ConnNoError;
81  }
82 
84  {
85  if( m_tcpServer )
86  {
87  m_tcpServer->disconnect();
88  m_tcpServer->cleanup();
89  }
90  }
91 
93  {
94  if( m_tcpServer )
95  return m_tcpServer->localPort();
96 
97  return m_port;
98  }
99 
100  const std::string SOCKS5BytestreamServer::localInterface() const
101  {
102  if( m_tcpServer )
103  return m_tcpServer->localInterface();
104 
105  return m_ip;
106  }
107 
108  ConnectionBase* SOCKS5BytestreamServer::getConnection( const std::string& hash )
109  {
110  util::MutexGuard mg( m_mutex );
111 
112  ConnectionMap::iterator it = m_connections.begin();
113  for( ; it != m_connections.end(); ++it )
114  {
115  if( (*it).second.hash == hash )
116  {
117  ConnectionBase* conn = (*it).first;
119  m_connections.erase( it );
120  return conn;
121  }
122  }
123 
124  return 0;
125  }
126 
127  void SOCKS5BytestreamServer::registerHash( const std::string& hash )
128  {
129  util::MutexGuard mg( m_mutex );
130  m_hashes.push_back( hash );
131  }
132 
133  void SOCKS5BytestreamServer::removeHash( const std::string& hash )
134  {
135  util::MutexGuard mg( m_mutex );
136  m_hashes.remove( hash );
137  }
138 
140  {
141  connection->registerConnectionDataHandler( this );
142  ConnectionInfo ci;
143  ci.state = StateUnnegotiated;
144 
145  m_mutex.lock();
146  m_connections[connection] = ci;
147  m_mutex.unlock();
148  }
149 
151  const std::string& data )
152  {
153  m_mutex.lock();
154  ConnectionMap::iterator it = m_connections.find( const_cast<ConnectionBase*>( connection ) );
155  if( it == m_connections.end() )
156  {
157  m_mutex.unlock();
158  return;
159  }
160  m_mutex.unlock();
161 
162  switch( (*it).second.state )
163  {
164  case StateDisconnected:
165  (*it).first->disconnect();
166  break;
167  case StateUnnegotiated:
168  {
169  char c[2];
170  c[0] = 0x05;
171  c[1] = (char)(unsigned char)0xFF;
172  (*it).second.state = StateDisconnected;
173 
174  if( data.length() >= 3 && data[0] == 0x05 )
175  {
176  unsigned int sz = ( data.length() - 2 < static_cast<unsigned int>( data[1] ) )
177  ? static_cast<unsigned int>( data.length() - 2 )
178  : static_cast<unsigned int>( data[1] );
179  for( unsigned int i = 2; i < sz + 2; ++i )
180  {
181  if( data[i] == 0x00 )
182  {
183  c[1] = 0x00;
184  (*it).second.state = StateAuthAccepted;
185  break;
186  }
187  }
188  }
189  (*it).first->send( std::string( c, 2 ) );
190  break;
191  }
192  case StateAuthmethodAccepted:
193  // place to implement any future auth support
194  break;
195  case StateAuthAccepted:
196  {
197  std::string reply = data;
198  if( reply.length() < 2 )
199  reply.resize( 2 );
200 
201  reply[0] = 0x05;
202  reply[1] = 0x01; // general SOCKS server failure
203  (*it).second.state = StateDisconnected;
204 
205  if( data.length() == 47 && data[0] == 0x05 && data[1] == 0x01 && data[2] == 0x00
206  && data[3] == 0x03 && data[4] == 0x28 && data[45] == 0x00 && data[46] == 0x00 )
207  {
208  const std::string hash = data.substr( 5, 40 );
209 
210  m_mutex.lock();
211  HashMap::const_iterator ith = m_hashes.begin();
212  for( ; ith != m_hashes.end() && (*ith) != hash; ++ith )
213  ;
214 
215  if( ith != m_hashes.end() )
216  {
217  reply[1] = 0x00;
218  (*it).second.hash = hash;
219  (*it).second.state = StateDestinationAccepted;
220  }
221  m_mutex.unlock();
222  }
223  (*it).first->send( reply );
224  break;
225  }
226  case StateDestinationAccepted:
227  case StateActive:
228  // should not happen
229  break;
230  }
231  }
232 
234  {
235  // should never happen, TCP connection is already established
236  }
237 
239  ConnectionError /*reason*/ )
240  {
241  util::MutexGuard mg( m_mutex );
242  m_connections.erase( const_cast<ConnectionBase*>( connection ) );
243  m_oldConnections.push_back( connection );
244  }
245 
246 }