"Fossies" - the Fresh Open Source Software Archive 
Member "postal-0.76/basictcp.cpp" (1 Jan 2012, 7953 Bytes) of package /linux/privat/postal-0.76.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "basictcp.cpp" see the
Fossies "Dox" file reference documentation.
1 #define TCP_BODY
2
3 #include "basictcp.h"
4
5 #include <sys/socket.h>
6 #include <unistd.h>
7 #include <arpa/inet.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 #include <stdarg.h>
11 #include "postal.h"
12 #include "userlist.h"
13 #include "address.h"
14 #include "logit.h"
15 #include "results.h"
16
17 #ifdef USE_GNUTLS
18 int base_tcp::m_init_dh_params = 0;
19 gnutls_dh_params_t base_tcp::m_dh_params;
20 #endif
21
22 base_tcp::base_tcp(int fd, Logit *log, Logit *debug, results *res
23 #ifdef USE_SSL
24 , int ssl
25 #endif
26 ) :
27 #ifdef USE_SSL
28 m_canTLS(false),
29 m_useTLS(ssl),
30 #endif
31 m_sock(fd)
32 , m_start(0)
33 , m_end(0)
34 , m_open(true)
35 , m_log(log)
36 , m_debug(debug)
37 , m_res(res)
38 #ifdef USE_SSL
39 #ifdef USE_OPENSSL
40 , m_sslMeth(NULL)
41 , m_sslCtx(NULL)
42 , m_ssl(NULL)
43 #else
44 , m_gnutls_session(NULL)
45 #endif
46 , m_isTLS(false)
47 #endif
48 {
49 m_poll.fd = m_sock;
50 #ifdef USE_SSL
51 if(m_useTLS)
52 {
53 #ifdef USE_OPENSSL
54 //don't seem to need this SSL_library_init();
55 SSLeay_add_ssl_algorithms();
56 SSL_load_error_strings();
57 #endif
58 }
59 #endif
60 }
61
62 base_tcp::~base_tcp()
63 {
64 }
65
66 #ifdef USE_SSL
67
68 #ifdef USE_GNUTLS
69 #define DH_BITS 1024
70
71 void base_tcp::m_initialize_tls_session()
72 {
73 gnutls_init(&m_gnutls_session, GNUTLS_SERVER);
74
75 /* avoid calling all the priority functions, since the defaults
76 * are adequate.
77 */
78 gnutls_set_default_priority(m_gnutls_session);
79 // Need to enable anonymous specifically
80 gnutls_priority_set_direct(m_gnutls_session, "NORMAL:+ANON-DH", NULL);
81
82 gnutls_credentials_set(m_gnutls_session, GNUTLS_CRD_ANON, m_anoncred);
83
84 gnutls_dh_set_prime_bits(m_gnutls_session, DH_BITS);
85 }
86
87 void base_tcp::m_generate_dh_params()
88 {
89 /* Generate Diffie Hellman parameters - for use with DHE
90 * kx algorithms. These should be discarded and regenerated
91 * once a day, once a week or once a month. Depending on the
92 * security requirements.
93 */
94 gnutls_dh_params_init(&m_dh_params);
95 gnutls_dh_params_generate2(m_dh_params, DH_BITS);
96 }
97 #endif // USE_GNUTLS
98
99 int base_tcp::ConnectTLS()
100 {
101 #ifdef USE_OPENSSL
102 m_sslMeth = NULL;
103 m_sslCtx = NULL;
104 m_ssl = NULL;
105 m_sslMeth = SSLv2_client_method();
106 if(m_sslMeth == NULL)
107 {
108 fprintf(stderr, "Can't get SSLv2_client_method.\n");
109 return 2;
110 }
111 m_sslCtx = SSL_CTX_new(m_sslMeth);
112 if(m_sslCtx == NULL)
113 {
114 fprintf(stderr, "Can't SSL_CTX_new\n");
115 return 2;
116 }
117 if((m_ssl = SSL_new(m_sslCtx)) == NULL)
118 {
119 fprintf(stderr, "Can't SSL_new\n");
120 SSL_CTX_free(m_sslCtx);
121 return 2;
122 }
123 SSL_set_fd(m_ssl, m_sock);
124 if(-1 == SSL_connect(m_ssl))
125 {
126 fprintf(stderr, "Can't SSL_CONNECT\n");
127 SSL_free(m_ssl);
128 SSL_CTX_free(m_sslCtx);
129 return 1;
130 }
131 m_isTLS = true;
132
133 // debugging code that may be useful to have around in a commented-out state.
134 #if 0
135 /* Following two steps are optional and not required for
136 data exchange to be successful. */
137
138 /* Get the cipher - opt */
139
140 printf ("SSL connection using %s\n", SSL_get_cipher(m_ssl));
141
142 /* Get server's certificate (note: beware of dynamic allocation) - opt */
143
144 X509 *server_cert;
145 server_cert = SSL_get_peer_certificate(m_ssl);
146 if(!server_cert)
147 {
148 fprintf(stderr, "Can't SSL_get_peer_certificate\n");
149 return 2;
150 }
151 printf ("Server certificate:\n");
152
153 char *str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0);
154 if(!str)
155 {
156 fprintf(stderr, "Can't X509_NAME_oneline\n");
157 return 2;
158 }
159 printf ("\t subject: %s\n", str);
160 Free (str);
161 str = X509_NAME_oneline (X509_get_issuer_name(server_cert),0,0);
162 if(!str)
163 {
164 fprintf(stderr, "Can't X509_get_issuer_name\n");
165 return 2;
166 }
167 printf ("\t issuer: %s\n", str);
168 Free (str);
169
170 /* We could do all sorts of certificate verification stuff here before
171 deallocating the certificate. */
172
173 X509_free(server_cert);
174 #endif // 0
175 #else
176
177 gnutls_anon_allocate_server_credentials(&m_anoncred);
178 m_initialize_tls_session();
179
180 if(!m_init_dh_params)
181 {
182 m_init_dh_params = 1;
183 m_generate_dh_params();
184 }
185
186 gnutls_anon_set_server_dh_params(m_anoncred, m_dh_params);
187
188 gnutls_transport_set_ptr(m_gnutls_session, (gnutls_transport_ptr_t)m_sock);
189 int rc = gnutls_handshake(m_gnutls_session);
190 if(rc < 0)
191 {
192 gnutls_deinit(m_gnutls_session);
193 return 2;
194 }
195 m_isTLS = 1;
196
197 /* request client certificate if any.
198 */
199 gnutls_certificate_server_set_request(m_gnutls_session, GNUTLS_CERT_REQUEST);
200
201 #endif // USE_OPENSSL
202 return 0;
203 }
204 #endif // USE_SSL
205
206 int base_tcp::disconnect()
207 {
208 if(m_open)
209 {
210 #ifdef USE_SSL
211 if(m_isTLS)
212 {
213 #ifdef USE_OPENSSL
214 SSL_shutdown(m_ssl);
215 close(m_sock);
216 SSL_free(m_ssl);
217 SSL_CTX_free(m_sslCtx);
218 m_isTLS = false;
219 #else
220 #endif
221 }
222 else
223 #endif
224 {
225 close(m_sock);
226 }
227 }
228 m_open = false;
229 return 0;
230 }
231
232 ERROR_TYPE base_tcp::printf(CPCCHAR fmt, ...)
233 {
234 va_list argp;
235 va_start(argp, fmt);
236 char buf[1024];
237 int len = vsnprintf(buf, sizeof(buf), fmt, argp);
238 if(len > (int)sizeof(buf))
239 len = sizeof(buf);
240 return sendData(buf, len);
241 }
242
243 ERROR_TYPE base_tcp::sendData(CPCCHAR buf, int size)
244 {
245 if(!m_open)
246 return eCorrupt;
247 int sent = 0;
248 m_poll.events = POLLOUT | POLLERR | POLLHUP;
249 int rc;
250 while(sent != size)
251 {
252 rc = poll(&m_poll, 1, 60000);
253 if(rc == 0)
254 {
255 fprintf(stderr, "Server timed out on write.\n");
256 return eTimeout;
257 }
258 if(rc < 0)
259 {
260 fprintf(stderr, "Poll error.\n");
261 return eSocket;
262 }
263 #ifdef USE_SSL
264 if(m_isTLS)
265 {
266 #ifdef USE_OPENSSL
267 rc = SSL_write(m_ssl, &buf[sent], size - sent);
268 #else
269 rc = gnutls_record_send(m_gnutls_session, &buf[sent], size - sent);
270 #endif
271 }
272 else
273 #endif
274 {
275 rc = write(m_sock, &buf[sent], size - sent);
276 }
277 if(rc < 1)
278 {
279 // fprintf(stderr, "Can't write to socket.\n");
280 return eSocket;
281 }
282 if(m_debug)
283 m_debug->Write(buf, rc);
284 sent += rc;
285 }
286 sentData(size);
287 return eNoError;
288 }
289
290 int base_tcp::readLine(char *buf, int bufSize, bool stripCR, int timeout)
291 {
292 if(!m_open)
293 return eCorrupt;
294 int ind = 0;
295 if(m_start < m_end)
296 {
297 do
298 {
299 buf[ind] = m_buf[m_start];
300 ind++;
301 m_start++;
302 }
303 while(m_start < m_end && m_buf[m_start - 1] != '\n' && ind < bufSize);
304 }
305 if(ind == bufSize || (ind > 0 && buf[ind - 1] == '\n') )
306 {
307 receivedData(ind);
308 if(m_debug)
309 m_debug->Write(buf, ind);
310 if(ind < bufSize)
311 {
312 ind--;
313 buf[ind] = '\0';
314 if(stripCR && buf[ind - 1] == '\r')
315 {
316 ind--;
317 buf[ind] = '\0';
318 }
319 }
320 return ind;
321 }
322 // buffer is empty
323 m_start = 0;
324 m_end = 0;
325
326 time_t now = time(NULL);
327 m_poll.events = POLLIN | POLLERR | POLLHUP;
328 while(1)
329 {
330 int tmo = timeout - (time(NULL) - now);
331 int rc;
332 if(tmo < 0 || (rc = poll(&m_poll, 1, tmo * 1000)) == 0)
333 {
334 return eTimeout;
335 }
336 if(rc < 0)
337 {
338 fprintf(stderr, "Poll error.\n");
339 return eCorrupt;
340 }
341 #ifdef USE_SSL
342 if(m_isTLS)
343 {
344 #ifdef USE_OPENSSL
345 rc = SSL_read(m_ssl, m_buf, sizeof(m_buf));
346 #else
347 rc = gnutls_record_recv(m_gnutls_session, m_buf, sizeof(m_buf));
348 #endif
349 }
350 else
351 #endif
352 {
353 rc = read(m_sock, m_buf, sizeof(m_buf));
354 }
355 if(rc < 0)
356 return eSocket;
357 m_end = rc;
358 do
359 {
360 buf[ind] = m_buf[m_start];
361 ind++;
362 m_start++;
363 } while(m_start < m_end && m_buf[m_start - 1] != '\n' && ind < bufSize);
364
365 if(ind == bufSize || (ind > 0 && buf[ind - 1] == '\n') )
366 {
367 receivedData(ind);
368 if(m_debug)
369 m_debug->Write(buf, ind);
370 if(ind < bufSize)
371 {
372 ind--;
373 buf[ind] = '\0';
374 if(stripCR && buf[ind - 1] == '\r')
375 {
376 ind--;
377 buf[ind] = '\0';
378 }
379 }
380 return ind;
381 }
382 if(m_start == m_end)
383 {
384 m_start = 0;
385 m_end = 0;
386 }
387 }
388 return 0; // never reached
389 }
390
391 void base_tcp::sentData(int)
392 {
393 }
394
395 void base_tcp::receivedData(int bytes)
396 {
397 m_res->dataBytes(bytes);
398 }
399