gloox  1.0
tlsgnutlsbase.cpp
1 /*
2  Copyright (c) 2005-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 "tlsgnutlsbase.h"
16 
17 #ifdef HAVE_GNUTLS
18 
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 namespace gloox
24 {
25 
26  GnuTLSBase::GnuTLSBase( TLSHandler* th, const std::string& server )
27  : TLSBase( th, server ), m_session( new gnutls_session_t ), m_buf( 0 ), m_bufsize( 17000 )
28  {
29  m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );
30  }
31 
33  {
34  free( m_buf );
35  m_buf = 0;
36  cleanup();
37  delete m_session;
38 // FIXME: It segfaults if more then one account uses
39 // encryption at same time, so we comment it for now.
40 // Do we need to deinit at all?
41 // gnutls_global_deinit();
42  }
43 
44  bool GnuTLSBase::encrypt( const std::string& data )
45  {
46  if( !m_secure )
47  {
48  handshake();
49  return true;
50  }
51 
52  ssize_t ret = 0;
53  std::string::size_type sum = 0;
54  do
55  {
56  ret = gnutls_record_send( *m_session, data.c_str() + sum, data.length() - sum );
57  sum += ret;
58  }
59  while( ( ret == GNUTLS_E_AGAIN ) || ( ret == GNUTLS_E_INTERRUPTED ) || sum < data.length() );
60  return true;
61  }
62 
63  int GnuTLSBase::decrypt( const std::string& data )
64  {
65  m_recvBuffer += data;
66 
67  if( !m_secure )
68  {
69  handshake();
70  return static_cast<int>( data.length() );
71  }
72 
73  int sum = 0;
74  int ret = 0;
75  do
76  {
77  ret = static_cast<int>( gnutls_record_recv( *m_session, m_buf, m_bufsize ) );
78 
79  if( ret > 0 && m_handler )
80  {
81  m_handler->handleDecryptedData( this, std::string( m_buf, ret ) );
82  sum += ret;
83  }
84  }
85  while( ret > 0 );
86 
87  return sum;
88  }
89 
91  {
92  if( !m_mutex.trylock() )
93  return;
94 
95  TLSHandler* handler = m_handler;
96  m_handler = 0;
97  gnutls_bye( *m_session, GNUTLS_SHUT_RDWR );
98  gnutls_db_remove_session( *m_session );
99  gnutls_credentials_clear( *m_session );
100  if( m_secure )
101  gnutls_deinit( *m_session );
102 
103  m_secure = false;
104  m_valid = false;
105  delete m_session;
106  m_session = 0;
107  m_session = new gnutls_session_t;
108  m_handler = handler;
109 
110  m_mutex.unlock();
111  }
112 
114  {
115  if( !m_handler )
116  return false;
117 
118  int ret = gnutls_handshake( *m_session );
119  if( ret < 0 && gnutls_error_is_fatal( ret ) )
120  {
121  gnutls_perror( ret );
122  gnutls_db_remove_session( *m_session );
123  gnutls_deinit( *m_session );
124  m_valid = false;
125 
126  m_handler->handleHandshakeResult( this, false, m_certInfo );
127  return false;
128  }
129  else if( ret == GNUTLS_E_AGAIN )
130  {
131  return true;
132  }
133 
134  m_secure = true;
135 
136  getCertInfo();
137 
138  m_handler->handleHandshakeResult( this, true, m_certInfo );
139  return true;
140  }
141 
142  ssize_t GnuTLSBase::pullFunc( void* data, size_t len )
143  {
144  ssize_t cpy = ( len > m_recvBuffer.length() ) ? ( m_recvBuffer.length() ) : ( len );
145  if( cpy > 0 )
146  {
147  memcpy( data, (const void*)m_recvBuffer.c_str(), cpy );
148  m_recvBuffer.erase( 0, cpy );
149  return cpy;
150  }
151  else
152  {
153  errno = EAGAIN;
154  return GNUTLS_E_AGAIN;
155  }
156  }
157 
158  ssize_t GnuTLSBase::pullFunc( gnutls_transport_ptr_t ptr, void* data, size_t len )
159  {
160  return static_cast<GnuTLSBase*>( ptr )->pullFunc( data, len );
161  }
162 
163  ssize_t GnuTLSBase::pushFunc( const void* data, size_t len )
164  {
165  if( m_handler )
166  m_handler->handleEncryptedData( this, std::string( (const char*)data, len ) );
167 
168  return len;
169  }
170 
171  ssize_t GnuTLSBase::pushFunc( gnutls_transport_ptr_t ptr, const void* data, size_t len )
172  {
173  return static_cast<GnuTLSBase*>( ptr )->pushFunc( data, len );
174  }
175 
176 }
177 
178 #endif // HAVE_GNUTLS