1 /***************************************************************************
2 csocket.cpp - description
3 -------------------
4 begin : Sat Oct 6 2001
5 copyright : (C) 2001-2003 by Mathias Küster
6 email : mathen@users.berlios.de
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "csocket.h"
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <signal.h>
28
29 #ifdef WIN32
30 #include <winsock2.h>
31 #else
32 #include <netdb.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <sys/time.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <net/if.h>
42
43 // includes for sun os
44 #ifdef HAVE_SYS_SOCKIO_H
45 #include <sys/sockio.h>
46 #endif
47 #ifdef HAVE_SYS_TERMIOS_H
48 #include <sys/termios.h>
49 #endif
50 #ifdef HAVE_SYS_FILIO_H
51 #include <sys/filio.h>
52 #endif
53 #endif
54
55 #include <sys/types.h>
56
57 #ifndef MSG_NOSIGNAL
58 // 0x2000 /* don't raise SIGPIPE */
59 #define MSG_NOSIGNAL 0
60 #endif
61
62 #include "../dcos.h"
63 #include "casyncdns.h"
64 #include "clogfile.h"
65 #include "cssl.h"
66 #include "cnetaddr.h"
67
68 #ifdef HAVE_SOCKS
69 extern "C" {
70 #include <socks.h>
71 }
72 #endif
73
74 // init static socket vars
75 CTraffic CSocket::m_Traffic = CTraffic();
76 eSocketLog CSocket::m_eSocketLog = eslNONE;
77
CSocket(eSocketType type)78 CSocket::CSocket( eSocketType type )
79 {
80 SocketType = type;
81 iHandle = INVALID_SOCKET;
82 m_eSocketMode = esmSOCKET;
83
84 m_pCTX = 0;
85 m_pSSL = 0;
86 }
87
~CSocket()88 CSocket::~CSocket()
89 {
90 Disconnect();
91
92 #if DCLIB_USES_OPENSSL == 1
93 /* This is in case iHandle == INVALID_SOCKET but somehow m_pSSL / m_pCTX are still here */
94 if ( m_pSSL )
95 {
96 SSL_free(m_pSSL);
97 m_pSSL = 0;
98 }
99
100 if ( m_pCTX )
101 {
102 SSL_CTX_free(m_pCTX);
103 m_pCTX = 0;
104 }
105 #endif
106 }
107
108 /** */
SetSocket(int handle,eSocketType sockettype)109 int CSocket::SetSocket( int handle, eSocketType sockettype )
110 {
111 if ( handle == INVALID_SOCKET )
112 {
113 return -1;
114 }
115
116 if ( (sockettype != estTCP) && (sockettype != estUDP) )
117 {
118 return -1;
119 }
120
121 SocketType = sockettype;
122 iHandle = handle;
123
124 #if DCLIB_USES_OPENSSL == 1
125 if ( (m_eSocketMode == esmFULLSSLSERVER) || (m_eSocketMode == esmFULLSSLCLIENT) )
126 {
127 if ( SSL_set_fd(m_pSSL,iHandle) == 0 )
128 {
129 sError = "CSocket::SetSocket: SSL_set_fd failed: ";
130 sError += ERR_reason_error_string( ERR_get_error() );
131 return -1;
132 }
133 }
134 #endif
135
136 return 0;
137 }
138
139 /** */
GetFreeSendBufferSize()140 int CSocket::GetFreeSendBufferSize()
141 {
142 int tot, free = 0;
143 #ifndef WIN32
144 int unsent;
145 #endif
146 socklen_t ilen;
147
148 if ( iHandle == INVALID_SOCKET )
149 {
150 return free;
151 }
152
153 ilen = sizeof(int);
154
155 if ( getsockopt(iHandle, SOL_SOCKET, SO_SNDBUF, (char*)&tot, &ilen) == 0 )
156 {
157 // quick & dirty fix for free bsd
158 free = tot;
159 #ifndef WIN32
160 #ifndef __CYGWIN__
161 if ( ioctl(iHandle, TIOCOUTQ, &unsent) == 0 )
162 {
163 free = tot - unsent;
164 }
165 #endif
166 #endif
167 }
168
169 return free;
170 }
171
172 /** */
IsConnect()173 int CSocket::IsConnect()
174 {
175 int i,err;
176 struct timeval tv;
177 fd_set rset,wset,eset;
178
179 if ( iHandle == INVALID_SOCKET )
180 {
181 return -1;
182 }
183
184 FD_ZERO(&rset);
185 FD_ZERO(&wset);
186 FD_ZERO(&eset);
187 FD_SET(iHandle, &rset);
188 FD_SET(iHandle, &wset);
189 FD_SET(iHandle, &eset);
190
191 tv.tv_sec = 0;
192 tv.tv_usec = 1;
193
194 err = -1;
195
196 i = select(FD_SETSIZE, &rset, &wset, &eset, &tv);
197
198 if ( (i > 0) && (!FD_ISSET(iHandle, &eset)) && (FD_ISSET(iHandle, &wset)) )
199 {
200 err = 1;
201 }
202 else if ( i == 0 )
203 {
204 err = 0;
205 }
206 else if ( err == -1 )
207 {
208 err = SocketError();
209
210 if ( err != 0 )
211 {
212 sError = ext_strerror(err);
213 err = -1;
214 }
215 }
216
217 FD_CLR(iHandle, &rset);
218 FD_CLR(iHandle, &wset);
219 FD_CLR(iHandle, &eset);
220
221 return err;
222 }
223
224 /** */
SocketError()225 int CSocket::SocketError()
226 {
227 int err = 0;
228 socklen_t ilen;
229
230 if ( iHandle == INVALID_SOCKET )
231 {
232 return err;
233 }
234
235 ilen = sizeof(int);
236
237 if ( getsockopt(iHandle, SOL_SOCKET, SO_ERROR, (char*)&err, &ilen) != 0 )
238 {
239 err = 0;
240 }
241
242 return err;
243 }
244
245 /** */
Connect(CString Host,bool bAsync)246 eConnectState CSocket::Connect( CString Host, bool bAsync )
247 {
248 unsigned int port;
249 CString s;
250
251 CNetAddr::ParseHost( Host, s, port );
252
253 // set default port
254 if ( port == 0 )
255 {
256 port = 411;
257 }
258
259 return Connect( s, port, bAsync );
260 }
261
262 /** */
Connect(CString Host,int Port,bool bAsync)263 eConnectState CSocket::Connect( CString Host, int Port, bool bAsync )
264 {
265 struct sockaddr_in sin,t_sin;
266 SOCKET sockfd;
267 eAsyncDns ead;
268
269 if ( iHandle != INVALID_SOCKET )
270 {
271 Disconnect();
272 }
273
274 memset((void *)&sin, 0, sizeof(sin));
275 sin.sin_family = AF_INET;
276
277 if ( Host.IsEmpty() )
278 {
279 if ( SocketType == estTCP )
280 {
281 return ecsERROR;
282 }
283 else
284 {
285 sin.sin_addr.s_addr = htonl(INADDR_ANY);
286 }
287 }
288 else
289 {
290 /* skip host lookup if it is a valid IP address */
291 #ifdef WIN32
292 sin.sin_addr.s_addr = inet_addr( Host.Data() );
293 if ( sin.sin_addr.s_addr != INADDR_NONE )
294 #else
295 if ( inet_aton( Host.Data(), &sin.sin_addr ) != 0 )
296 #endif
297 {
298 m_sIP = Host;
299 }
300 else if ( bAsync == false )
301 {
302 // use blocked getaddrinfo
303 if ( CNetAddr::GetHostI4( Host.Data(), &t_sin, &sError ) == false )
304 {
305 return ecsERROR;
306 }
307 else
308 {
309 memcpy((void *)&sin.sin_addr, (void *)&t_sin.sin_addr, sizeof(t_sin.sin_addr));
310 m_sIP = inet_ntoa(sin.sin_addr);
311 }
312 }
313 else
314 {
315 // use async dns class
316 if ( CAsyncDns::Instance() )
317 {
318 ead = CAsyncDns::Instance()->GetHostI4( Host, &t_sin, &sError );
319 }
320 else
321 {
322 return ecsERROR;
323 }
324
325 if ( ead == eadAGAIN )
326 {
327 return ecsAGAIN;
328 }
329 else if ( ead == eadERROR )
330 {
331 return ecsERROR;
332 }
333 else
334 {
335 memcpy((void *)&sin.sin_addr, (void *)&t_sin.sin_addr, sizeof(t_sin.sin_addr));
336 m_sIP = inet_ntoa(sin.sin_addr);
337 }
338 }
339 }
340
341 sin.sin_port = htons((unsigned short)Port);
342
343 // update m_sIP
344 m_sIP += ':';
345 m_sIP += CString::number(Port);
346
347 // socket
348 if ( SocketType == estTCP )
349 {
350 if ((sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
351 {
352 sError = ext_strerror(errno);
353 return ecsERROR;
354 }
355 }
356 else
357 {
358 if( (sockfd = socket( PF_INET, SOCK_DGRAM, 0 )) < 0 )
359 {
360 sError = ext_strerror(errno);
361 return ecsERROR;
362 }
363 }
364
365 // set async flag
366 #ifdef WIN32
367 unsigned long flag = bAsync;
368 if ( ioctlsocket(sockfd, FIONBIO, &flag ) != 0 )
369 #else
370 int flag = bAsync;
371 if ( ioctl(sockfd, FIONBIO, &flag ) != 0 )
372 #endif
373 {
374 sError = ext_strerror(errno);
375 return ecsERROR;
376 }
377
378 if ( Host.NotEmpty() )
379 {
380 // connect
381 if ( connect(sockfd, (struct sockaddr *)&sin, sizeof(sin)) != 0 )
382 {
383 #ifdef WIN32
384 int e = WSAGetLastError();
385 if ( (e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK) )
386 #else
387 if ( errno != EINPROGRESS )
388 #endif
389 {
390 sError = ext_strerror(errno);
391 #ifdef WIN32
392 closesocket(sockfd);
393 #else
394 close(sockfd);
395 #endif
396 return ecsERROR;
397 }
398 }
399 }
400 else
401 {
402 if ( bind(sockfd, (struct sockaddr *) &sin, sizeof(sin)) < 0 )
403 {
404 sError = ext_strerror(errno);
405 #ifdef WIN32
406 closesocket(sockfd);
407 #else
408 close(sockfd);
409 #endif
410 return ecsERROR;
411 }
412 }
413
414 #if DCLIB_USES_OPENSSL == 1
415 if ( m_eSocketMode == esmFULLSSLCLIENT )
416 {
417 if ( SSL_set_fd(m_pSSL, sockfd) == 0 )
418 {
419 sError = "CSocket::Connect: SSL_set_fd failed: ";
420 sError += ERR_reason_error_string( ERR_get_error() );
421 #ifdef WIN32
422 closesocket(sockfd);
423 #else
424 close(sockfd);
425 #endif
426 return ecsERROR;
427 }
428 }
429 #endif /* DCLIB_USES_OPENSSL */
430
431 iHandle = sockfd;
432 return ecsSUCCESS;
433 }
434
435 /** */
Disconnect()436 int CSocket::Disconnect()
437 {
438 if ( iHandle != INVALID_SOCKET )
439 {
440 #if DCLIB_USES_OPENSSL == 1
441 if ( (m_eSocketMode != esmSOCKET) && (m_pSSL) )
442 {
443 SSL_shutdown(m_pSSL); // FIXME check return value
444 SSL_free(m_pSSL);
445 m_pSSL = 0;
446 }
447 #endif
448
449 #ifdef WIN32
450 closesocket(iHandle);
451 #else
452 close(iHandle);
453 #endif
454 #if DCLIB_USES_OPENSSL == 1
455 if ( (m_eSocketMode != esmSOCKET) && (m_pCTX) )
456 {
457 SSL_CTX_free(m_pCTX);
458 m_pCTX = 0;
459 }
460 #endif
461 m_eSocketMode = esmSOCKET;
462 iHandle = INVALID_SOCKET;
463 }
464
465 return 0;
466 }
467
468 /** */
Read(char * buffer,int len,int sec_timeout,int usec_timeout)469 int CSocket::Read( char * buffer, int len, int sec_timeout, int usec_timeout )
470 {
471 int l = 0, i = 0;
472 struct timeval tv;
473 fd_set readset;
474 struct sockaddr_in cli_addr;
475 socklen_t cli_len = sizeof(cli_addr);
476
477 if ( (iHandle == INVALID_SOCKET) || (!buffer) || (len <= 0) )
478 {
479 return -1;
480 }
481
482 #if DCLIB_USES_OPENSSL == 1
483 if ( m_eSocketMode != esmSOCKET )
484 {
485 l = SSL_read(m_pSSL, buffer, len);
486
487 // if ( (l <= 0) && ((i=IsConnect()) != -1) )
488 if ( l <= 0 )
489 {
490 // printf("READ: %d %d\n",l,i);
491
492 l = SSL_get_error(m_pSSL,l);
493
494 if ( (l != SSL_ERROR_WANT_READ) && (l != SSL_ERROR_WANT_WRITE) )
495 {
496 l = -1;
497 unsigned long sslerr = ERR_peek_error(); // ERR_get_error() if not printed
498 ERR_print_errors_fp(stderr);
499 sError = "SSL ERROR lib:";
500 sError += ERR_lib_error_string(sslerr);
501 sError += " func:";
502 sError += ERR_func_error_string(sslerr);
503 sError += " reason:";
504 sError += ERR_reason_error_string(sslerr);
505 Disconnect();
506 }
507 else
508 {
509 l = i = 0;
510 }
511 }
512 }
513 else
514 #endif
515 {
516 if ( IsConnect() < 0 )
517 {
518 i = 1;
519 l = 0;
520 }
521 else
522 {
523 FD_ZERO(&readset);
524 FD_SET(iHandle, &readset);
525
526 tv.tv_sec = sec_timeout;
527 tv.tv_usec = usec_timeout;
528
529 i = select(FD_SETSIZE, &readset, NULL, NULL, &tv);
530
531 if ( (i > 0) && (FD_ISSET(iHandle,&readset)) )
532 {
533 // handle udp socket
534 if ( SocketType == estUDP )
535 {
536 if ( (l=recvfrom(iHandle,buffer,len,0,(struct sockaddr*)&cli_addr,&cli_len)) < 0 )
537 {
538 #ifdef WIN32
539 int e = WSAGetLastError();
540 if ( (e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK) )
541 {
542 #else
543 int e = errno;
544 if ( (e != EINPROGRESS) && (e != EAGAIN) )
545 {
546 #endif
547 sError = ext_strerror(e);
548 }
549 else
550 {
551 i = l = 0;
552 }
553 }
554 else if ( l > 0 )
555 {
556 m_sIP = inet_ntoa( cli_addr.sin_addr );
557 }
558 }
559 // handle tcp socket
560 else if ( SocketType == estTCP )
561 {
562 if ( (l=recv(iHandle,buffer,len,0)) < 0 )
563 {
564 #ifdef WIN32
565 int e = WSAGetLastError();
566 if ( (e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK) )
567 {
568 #else
569 int e = errno;
570 if ( (e != EINPROGRESS) && (e != EAGAIN) )
571 {
572 #endif
573 sError = ext_strerror(e);
574 }
575 else
576 {
577 i = l = 0;
578 }
579 }
580 }
581 }
582 else if ( i < 0 )
583 {
584 i = SocketError();
585
586 if ( i == 0 )
587 {
588 l = i = 0;
589 }
590 else
591 {
592 sError = ext_strerror(i);
593 i = l = -1;
594 }
595 }
596
597 FD_CLR(iHandle, &readset);
598 }
599 }
600
601 // log options TODO: fix
602 if ( (CSocket::m_eSocketLog == eslRECV) ||
603 (CSocket::m_eSocketLog == eslBOTH) )
604 {
605 if ( l > 0 )
606 {
607 CString s = "RECV:";
608 s += CString::number(l);
609 CLogFile::Write("dcsocket.log",eltINFO,s);
610
611 if( l <= len )
612 {
613 s.Set(buffer,l);
614 CLogFile::Write("dcsocket.log",eltINFO,s);
615 }
616 }
617 }
618
619 /** we are disconnected */
620 if ( (i==1) && (l==0) )
621 {
622 i = errno;
623 l = SocketError();
624
625 // printf("1: %s\n",ext_strerror(i).Data());
626 // printf("2: %s\n",ext_strerror(l).Data());
627
628 if ( l == 0 )
629 l = i;
630
631 // if ( (l != EINPROGRESS) && (l != EAGAIN) )
632 // {
633 sError = ext_strerror(l);
634 l = -1;
635 // }
636 // else
637 // {
638 // l = 0;
639 // }
640 }
641
642 if ( l > 0 )
643 CSocket::m_Traffic.AddTraffic( ettRX, l );
644
645 return l;
646 }
647
648 /** */
649 int CSocket::Write( const unsigned char * buffer, int len, int sec_timeout, int usec_timeout )
650 {
651 int i;
652 struct timeval tv;
653 fd_set writeset;
654
655 if ( (iHandle == INVALID_SOCKET) || (!buffer) || (len <= 0) )
656 {
657 return -1;
658 }
659
660 #if DCLIB_USES_OPENSSL == 1
661 if ( m_eSocketMode != esmSOCKET )
662 {
663 i = SSL_write(m_pSSL, buffer, len);
664
665 // if ( (i <= 0) && (IsConnect() != -1) )
666 if ( i <= 0 )
667 {
668 // printf("WRITE: %d %d\n",i,IsConnect());
669
670 i = SSL_get_error(m_pSSL,i);
671
672 if ( (i != SSL_ERROR_WANT_READ) && (i != SSL_ERROR_WANT_WRITE) )
673 {
674 i = -1;
675 unsigned long sslerr = ERR_peek_error(); // ERR_get_error() if not printed
676 ERR_print_errors_fp(stderr);
677 sError = "SSL ERROR lib:";
678 sError += ERR_lib_error_string(sslerr);
679 sError += " func:";
680 sError += ERR_func_error_string(sslerr);
681 sError += " reason:";
682 sError += ERR_reason_error_string(sslerr);
683 Disconnect();
684 }
685 else
686 {
687 i = 0;
688 }
689 }
690 }
691 else
692 #endif
693 {
694 if ( IsConnect() < 0 )
695 {
696 i = -1;
697 }
698 else
699 {
700 FD_ZERO(&writeset);
701 FD_SET(iHandle, &writeset);
702
703 tv.tv_sec = sec_timeout;
704 tv.tv_usec = usec_timeout;
705
706 i = select(FD_SETSIZE, NULL, &writeset, NULL, &tv);
707
708 FD_CLR(iHandle, &writeset);
709 }
710
711 if ( i > 0 )
712 {
713 i = send( iHandle, (const char*)buffer, len, MSG_NOSIGNAL );
714
715 // send error
716 if ( i < 0 )
717 {
718 #ifdef WIN32
719 int e = WSAGetLastError();
720 if ( (e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK) )
721 {
722 #else
723 int e = errno;
724 if ( (e != EINPROGRESS) && (e != 0) && (e != EAGAIN) )
725 {
726 #endif
727 sError = ext_strerror(e);
728 }
729 else
730 {
731 i = 0;
732 }
733 }
734 else if ( i == 0 )
735 {
736 i = -1;
737 }
738
739 }
740 else if ( i < 0 )
741 {
742 i = SocketError();
743
744 if ( i != 0 )
745 {
746 sError = ext_strerror(i);
747 i = -1;
748 }
749 }
750 }
751
752 // log options TODO: fix
753 if ( (CSocket::m_eSocketLog == eslSEND) ||
754 (CSocket::m_eSocketLog == eslBOTH) )
755 {
756 if ( i > 0 )
757 {
758 CString s = "SEND:";
759 s += CString::number(len);
760 CLogFile::Write("dcsocket.log",eltINFO,s);
761
762 s.Set( (const char*)buffer ,i );
763 CLogFile::Write("dcsocket.log",eltINFO,s);
764 }
765 }
766
767 if ( i > 0 )
768 CSocket::m_Traffic.AddTraffic( ettTX, i );
769
770 return i;
771 }
772
773 /** */
774 int CSocket::Accept()
775 {
776 struct timeval tv;
777 fd_set readset;
778 struct sockaddr_in serv_addr;
779 SOCKET s = INVALID_SOCKET;
780 int i;
781 socklen_t sin_size = sizeof(struct sockaddr_in);
782
783 if ( iHandle == INVALID_SOCKET )
784 {
785 return s;
786 }
787
788 FD_ZERO(&readset);
789 FD_SET(iHandle, &readset);
790
791 tv.tv_sec = 0;
792 tv.tv_usec = 1;
793
794 i = select(FD_SETSIZE, &readset, NULL, NULL, &tv);
795
796 FD_CLR(iHandle, &readset);
797
798 if ( i > 0 )
799 {
800 if ((s = accept(iHandle, (struct sockaddr *)&serv_addr, &sin_size)) == INVALID_SOCKET)
801 {
802 sError = ext_strerror(SocketError());
803 return -1;
804 }
805 else
806 {
807 // set async flag
808 #ifdef WIN32
809 unsigned long flag = 1;
810 if ( ioctlsocket(s, FIONBIO, &flag ) != 0 )
811 #else
812 int flag = 1;
813 if ( ioctl(s, FIONBIO, &flag ) != 0 )
814 #endif
815 {
816 sError = ext_strerror(errno);
817 return -1;
818 }
819 }
820 }
821
822 return s;
823 }
824
825 /** */
826 int CSocket::Listen( int port, CString ip )
827 {
828 SOCKET sockfd;
829 struct sockaddr_in serv_addr;
830
831 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
832 {
833 #ifdef WIN32
834 sError = ext_strerror(WSAGetLastError());
835 #else
836 sError = ext_strerror(errno);
837 #endif
838 return -1;
839 }
840
841 /* Let the kernel reuse the socket address. This lets us run
842 twice in a row, without waiting for the (ip, port) tuple
843 to time out. */
844 #ifdef WIN32
845 const char i = 1;
846 #else
847 int i = 1;
848 #endif
849 if ( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) != 0 )
850 {
851 #ifdef WIN32
852 sError = ext_strerror(WSAGetLastError());
853 closesocket(sockfd);
854 #else
855 sError = ext_strerror(errno);
856 close(sockfd);
857 #endif
858 return -1;
859 }
860
861 serv_addr.sin_family = AF_INET;
862 serv_addr.sin_port = htons((unsigned short)port);
863
864 if ( ip.NotEmpty() )
865 {
866 #ifdef WIN32
867 serv_addr.sin_addr.s_addr = inet_addr( ip.Data() );
868 if ( serv_addr.sin_addr.s_addr == INADDR_NONE )
869 #else
870 if ( inet_aton( ip.Data(), &serv_addr.sin_addr ) == 0 )
871 #endif
872 {
873 sError = "Invalid IP address";
874 return -1;
875 }
876 }
877 else
878 {
879 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
880 }
881
882 if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
883 {
884 #ifdef WIN32
885 sError = ext_strerror(WSAGetLastError());
886 closesocket(sockfd);
887 #else
888 sError = ext_strerror(errno);
889 close(sockfd);
890 #endif
891 return -1;
892 }
893
894 if (listen(sockfd, 5) == -1)
895 {
896 #ifdef WIN32
897 sError = ext_strerror(WSAGetLastError());
898 closesocket(sockfd);
899 #else
900 sError = ext_strerror(errno);
901 close(sockfd);
902 #endif
903 return -1;
904 }
905
906 #if DCLIB_USES_OPENSSL == 1
907 if ( m_eSocketMode == esmFULLSSLSERVER )
908 {
909 if ( SSL_set_fd(m_pSSL, sockfd) == 0 )
910 {
911 sError = "CSocket::Listen: SSL_set_fd failed: ";
912 sError += ERR_reason_error_string( ERR_get_error() );
913 #ifdef WIN32
914 closesocket(sockfd);
915 #else
916 close(sockfd);
917 #endif
918 return -1;
919 }
920 }
921 #endif /* DCLIB_USES_OPENSSL */
922
923 iHandle = sockfd;
924 return 0;
925 }
926
927 /** */
928 bool CSocket::GetPeerName( CString * host, int * port )
929 {
930 struct sockaddr_in addr;
931 socklen_t sin_size;
932
933 if ( (iHandle == INVALID_SOCKET) || (!host) || (!port) )
934 {
935 return false;
936 }
937
938 sin_size = sizeof(struct sockaddr_in);
939
940 if ( getpeername( iHandle, (struct sockaddr*)&addr, &sin_size ) == -1 )
941 {
942 sError = ext_strerror(SocketError());
943 return false;
944 }
945
946 *host = inet_ntoa(addr.sin_addr);
947 *port = ntohs(addr.sin_port);
948
949 return true;
950 }
951
952 /** */
953 #if DCLIB_USES_OPENSSL == 1
954 bool CSocket::ChangeSocketMode( eSocketMode mode, CString cert, CString key )
955 #else
956 bool CSocket::ChangeSocketMode( eSocketMode mode, CString /* cert */, CString /* key */ )
957 #endif
958 {
959 bool res = false;
960
961 switch(mode)
962 {
963 case esmSOCKET:
964 {
965 m_eSocketMode = mode;
966 res = true;
967 break;
968 }
969 #if DCLIB_USES_OPENSSL == 1
970 case esmSSLCLIENT:
971 case esmSSLSERVER:
972 case esmFULLSSLCLIENT:
973 case esmFULLSSLSERVER:
974 {
975 if ( (cert.IsEmpty() || key.IsEmpty()) && ((mode == esmSSLSERVER) || (mode == esmFULLSSLSERVER)) )
976 {
977 printf("no cert/key available\n");
978 return res;
979 }
980
981 if ( m_eSocketMode == esmSOCKET )
982 {
983 if ( mode == esmFULLSSLCLIENT )
984 {
985 m_pCTX = CSSL::NewTLSv1ClientCTX();
986
987 if ( m_pCTX == 0 )
988 {
989 printf("CSocket::ChangeSocketMode NewTLSv1ClientCTX failed\n");
990 return res;
991 }
992 }
993 else if ( mode == esmFULLSSLSERVER )
994 {
995 m_pCTX = CSSL::NewTLSv1ServerCTX();
996
997 if ( m_pCTX == 0 )
998 {
999 printf("CSocket::ChangeSocketMode NewTLSv1ServerCTX failed\n");
1000 return res;
1001 }
1002 }
1003 else if ( mode == esmSSLCLIENT )
1004 {
1005 m_pCTX = CSSL::InitClientCTX();
1006
1007 if ( m_pCTX == 0 )
1008 {
1009 printf("InitClientCTX failed\n");
1010 return res;
1011 }
1012 }
1013 else
1014 {
1015 m_pCTX = CSSL::InitServerCTX();
1016
1017 if ( m_pCTX == 0 )
1018 {
1019 printf("InitServerCTX failed\n");
1020 return res;
1021 }
1022 }
1023
1024 if ( cert.NotEmpty() && key.NotEmpty() )
1025 {
1026 if ( CSSL::LoadCertificates( m_pCTX, cert.Data(), key.Data() ) == false )
1027 {
1028 SSL_CTX_free(m_pCTX);
1029 m_pCTX = 0;
1030
1031 printf("load cert/key failed\n");
1032 return res;
1033 }
1034 }
1035
1036 SSL_CTX_set_mode(m_pCTX, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|SSL_MODE_ENABLE_PARTIAL_WRITE);
1037
1038 if ( (m_pSSL = SSL_new(m_pCTX)) == 0 )
1039 {
1040 printf("SSL_new failed\n");
1041 SSL_CTX_free(m_pCTX);
1042 m_pCTX = 0;
1043
1044 return res;
1045 }
1046
1047 if ( (mode == esmSSLSERVER) || (mode == esmFULLSSLSERVER) )
1048 {
1049 SSL_set_accept_state(m_pSSL);
1050 }
1051 else
1052 {
1053 SSL_set_connect_state(m_pSSL);
1054 }
1055
1056 if ( SSL_set_fd(m_pSSL, iHandle) == 0 )
1057 {
1058 printf("SSL_set_fd failed\n");
1059 SSL_CTX_free(m_pCTX);
1060 m_pCTX = 0;
1061 SSL_free(m_pSSL);
1062 m_pSSL = 0;
1063
1064 return res;
1065 }
1066
1067 m_eSocketMode = mode;
1068 res = true;
1069 }
1070 else
1071 {
1072 printf("CSocket: wrong socket mode to change\n");
1073 }
1074
1075 break;
1076 }
1077 #endif
1078 default:
1079 break;
1080 }
1081
1082 return res;
1083 }
1084
1085 /** http://synergy2.sourceforge.net/ */
1086 CString CSocket::ext_strerror( int err )
1087 {
1088 #ifdef WIN32
1089 // built-in windows function for looking up error message strings
1090 // may not look up network error messages correctly. we'll have
1091 // to do it ourself.
1092 static const struct { int m_code; const char* m_msg; } s_netErrorCodes[] = {
1093 /* 10004 */{WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"},
1094 /* 10009 */{WSAEBADF, "Bad file handle"},
1095 /* 10013 */{WSAEACCES, "The requested address is a broadcast address, but the appropriate flag was not set"},
1096 /* 10014 */{WSAEFAULT, "WSAEFAULT"},
1097 /* 10022 */{WSAEINVAL, "WSAEINVAL"},
1098 /* 10024 */{WSAEMFILE, "No more file descriptors available"},
1099 /* 10035 */{WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections are present or the receive operation would block"},
1100 /* 10036 */{WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"},
1101 /* 10037 */{WSAEALREADY, "The asynchronous routine being canceled has already completed"},
1102 /* 10038 */{WSAENOTSOCK, "At least on descriptor is not a socket"},
1103 /* 10039 */{WSAEDESTADDRREQ, "A destination address is required"},
1104 /* 10040 */{WSAEMSGSIZE, "The datagram was too large to fit into the specified buffer and was truncated"},
1105 /* 10041 */{WSAEPROTOTYPE, "The specified protocol is the wrong type for this socket"},
1106 /* 10042 */{WSAENOPROTOOPT, "The option is unknown or unsupported"},
1107 /* 10043 */{WSAEPROTONOSUPPORT,"The specified protocol is not supported"},
1108 /* 10044 */{WSAESOCKTNOSUPPORT,"The specified socket type is not supported by this address family"},
1109 /* 10045 */{WSAEOPNOTSUPP, "The referenced socket is not a type that supports that operation"},
1110 /* 10046 */{WSAEPFNOSUPPORT, "BSD: Protocol family not supported"},
1111 /* 10047 */{WSAEAFNOSUPPORT, "The specified address family is not supported"},
1112 /* 10048 */{WSAEADDRINUSE, "The specified address is already in use"},
1113 /* 10049 */{WSAEADDRNOTAVAIL, "The specified address is not available from the local machine"},
1114 /* 10050 */{WSAENETDOWN, "The Windows Sockets implementation has detected that the network subsystem has failed"},
1115 /* 10051 */{WSAENETUNREACH, "The network can't be reached from this hos at this time"},
1116 /* 10052 */{WSAENETRESET, "The connection must be reset because the Windows Sockets implementation dropped it"},
1117 /* 10053 */{WSAECONNABORTED, "The virtual circuit was aborted due to timeout or other failure"},
1118 /* 10054 */{WSAECONNRESET, "The virtual circuit was reset by the remote side"},
1119 /* 10055 */{WSAENOBUFS, "No buffer space is available or a buffer deadlock has occured. The socket cannot be created"},
1120 /* 10056 */{WSAEISCONN, "The socket is already connected"},
1121 /* 10057 */{WSAENOTCONN, "The socket is not connected"},
1122 /* 10058 */{WSAESHUTDOWN, "The socket has been shutdown"},
1123 /* 10059 */{WSAETOOMANYREFS, "BSD: Too many references"},
1124 /* 10060 */{WSAETIMEDOUT, "Attempt to connect timed out without establishing a connection"},
1125 /* 10061 */{WSAECONNREFUSED, "The attempt to connect was forcefully rejected"},
1126 /* 10062 */{WSAELOOP, "Undocumented WinSock error code used in BSD"},
1127 /* 10063 */{WSAENAMETOOLONG, "Undocumented WinSock error code used in BSD"},
1128 /* 10064 */{WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"},
1129 /* 10065 */{WSAEHOSTUNREACH, "No route to host"},
1130 /* 10066 */{WSAENOTEMPTY, "Undocumented WinSock error code"},
1131 /* 10067 */{WSAEPROCLIM, "Undocumented WinSock error code"},
1132 /* 10068 */{WSAEUSERS, "Undocumented WinSock error code"},
1133 /* 10069 */{WSAEDQUOT, "Undocumented WinSock error code"},
1134 /* 10070 */{WSAESTALE, "Undocumented WinSock error code"},
1135 /* 10071 */{WSAEREMOTE, "Undocumented WinSock error code"},
1136 /* 10091 */{WSASYSNOTREADY, "Underlying network subsytem is not ready for network communication"},
1137 /* 10092 */{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is not provided in this implementation"},
1138 /* 10093 */{WSANOTINITIALISED, "WinSock subsystem not properly initialized"},
1139 /* 10101 */{WSAEDISCON, "Virtual circuit has gracefully terminated connection"},
1140 /* 11001 */{WSAHOST_NOT_FOUND, "The specified host is unknown"},
1141 /* 11002 */{WSATRY_AGAIN, "A temporary error occurred on an authoritative name server"},
1142 /* 11003 */{WSANO_RECOVERY, "A non-recoverable name server error occurred"},
1143 /* 11004 */{WSANO_DATA, "The requested name is valid but does not have an IP address"},
1144 /* end */{0, NULL}
1145 };
1146
1147 for (unsigned int i = 0; s_netErrorCodes[i].m_code != 0; ++i)
1148 {
1149 if ( s_netErrorCodes[i].m_code == err )
1150 {
1151 return s_netErrorCodes[i].m_msg;
1152 }
1153 }
1154 #endif
1155 return strerror(err);
1156 }
1157
1158 /** */
1159 CString CSocket::GetSSLVersion()
1160 {
1161 CString result;
1162 #if DCLIB_USES_OPENSSL == 1
1163 if ( m_pSSL )
1164 {
1165 result = SSL_get_cipher_version(m_pSSL);
1166 }
1167 #endif
1168 return result;
1169 }
1170
1171 /** */
1172 CString CSocket::GetSSLCipher()
1173 {
1174 CString result;
1175 #if DCLIB_USES_OPENSSL == 1
1176 if ( m_pSSL )
1177 {
1178 result = SSL_get_cipher(m_pSSL);
1179 }
1180 #endif
1181 return result;
1182 }
1183
1184 /** */
1185 CString CSocket::VerifyPeerCertificate()
1186 {
1187 CString result;
1188 #if DCLIB_USES_OPENSSL == 1
1189 if ( m_pSSL )
1190 {
1191 if ( SSL_get_peer_certificate(m_pSSL) == NULL )
1192 {
1193 result = "No certificate";
1194 }
1195 else
1196 {
1197 int certerr = SSL_get_verify_result(m_pSSL);
1198
1199 if ( certerr == X509_V_OK )
1200 {
1201 result = "Certificate verified";
1202 }
1203 else
1204 {
1205 result = "Certificate verify failed: ";
1206 result += X509_verify_cert_error_string(certerr);
1207 }
1208 }
1209 }
1210 #endif
1211 return result;
1212 }
1213
1214 /** */
1215 int CSocket::SysInit()
1216 {
1217 #ifdef WIN32
1218 /* According to the docs WSAStartup()
1219 * will fail if the requested version could not be
1220 * provided, plus 2.2 is the latest version and that
1221 * can even be installed on Windows 95.
1222 */
1223 WORD wVersionRequested = MAKEWORD( 2, 2 );
1224 WSADATA wsaData;
1225 return WSAStartup( wVersionRequested, &wsaData );
1226 #else
1227 /* nothing to do */
1228 return 0;
1229 #endif
1230 }
1231
1232 /** */
1233 int CSocket::SysDeInit()
1234 {
1235 #ifdef WIN32
1236 return WSACleanup();
1237 #else
1238 /* nothing to do */
1239 return 0;
1240 #endif
1241 }
1242