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