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