blob: 1bec40e24361a96cd1df39f77198cdd535fd4193 [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <ucommon-config.h>
40#include <commoncpp/config.h>
41#include <commoncpp/export.h>
42#include <commoncpp/string.h>
43#include <commoncpp/socket.h>
44#include <commoncpp/tcp.h>
45
46#include <iostream>
47
48#ifdef _MSWINDOWS_
49#include <io.h>
50#define _IOLEN64 (unsigned)
51#define _IORET64 (int)
52typedef int socklen_t;
53
54#define socket_errno WSAGetLastError()
55#else
56#include <sys/ioctl.h>
57#include <netinet/tcp.h>
58#ifdef HAVE_NET_IP6_H
59#include <netinet/ip6.h>
60#endif
61#define socket_errno errno
62# ifndef O_NONBLOCK
63# define O_NONBLOCK O_NDELAY
64# endif
65# ifdef IPPROTO_IP
66# ifndef SOL_IP
67# define SOL_IP IPPROTO_IP
68# endif // !SOL_IP
69# endif // IPPROTO_IP
70#endif // !WIN32
71
72#ifndef INADDR_LOOPBACK
73#define INADDR_LOOPBACK (unsigned long)0x7f000001
74#endif
75
76#ifdef HAVE_NETINET_IN_H
77#include <netinet/in.h>
78#endif
79
80#if defined(__hpux)
81#define _XOPEN_SOURCE_EXTENDED
82#endif
83
84#ifdef HAVE_NET_IF_H
85#include <net/if.h>
86#endif
87
88#ifndef _IOLEN64
89#define _IOLEN64
90#endif
91
92#ifndef _IORET64
93#define _IORET64
94#endif
95
96using namespace COMMONCPP_NAMESPACE;
97using namespace std;
98
99void TCPSocket::setSegmentSize(unsigned mss)
100{
101#ifdef TCP_MAXSEG
102 if(mss > 1)
103 setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss));
104#endif
105 segsize = mss;
106}
107
108#ifdef HAVE_GETADDRINFO
109TCPSocket::TCPSocket(const char *name, unsigned backlog, unsigned mss) :
110Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
111{
112 char namebuf[128], *cp;
113 struct addrinfo hint, *list = NULL, *first;
114 snprintf(namebuf, sizeof(namebuf), "%s", name);
115 cp = strrchr(namebuf, '/');
116 if(!cp)
117 cp = strrchr(namebuf, ':');
118
119 if(!cp) {
120 cp = namebuf;
121 name = NULL;
122 }
123 else {
124 name = namebuf;
125 *(cp++) = 0;
126 if(!strcmp(name, "*"))
127 name = NULL;
128 }
129
130 memset(&hint, 0, sizeof(hint));
131 hint.ai_family = AF_INET;
132 hint.ai_socktype = SOCK_STREAM;
133 hint.ai_protocol = IPPROTO_TCP;
134 hint.ai_flags = AI_PASSIVE;
135
136 if(getaddrinfo(name, cp, &hint, &list) || !list) {
137 endSocket();
138 error(errBindingFailed, (char *)"Could not find service", errno);
139 return;
140 }
141
142#if defined(SO_REUSEADDR)
143 int opt = 1;
144 setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
145 (socklen_t)sizeof(opt));
146#endif
147
148 first = list;
149 while(list) {
150 if(!bind(so, list->ai_addr, (socklen_t)list->ai_addrlen)) {
151 state = BOUND;
152 break;
153 }
154 list = list->ai_next;
155 }
156 freeaddrinfo(first);
157 if(state != BOUND) {
158 endSocket();
159 error(errBindingFailed,(char *)"Could not bind socket",socket_errno);
160 return;
161 }
162
163 setSegmentSize(mss);
164 if(listen(so, backlog)) {
165 endSocket();
166 error(errBindingFailed,(char *)"Could not listen on socket",socket_errno);
167 return;
168 }
169}
170
171#else
172TCPSocket::TCPSocket(const char *name, unsigned backlog, unsigned mss) :
173Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
174{
175 char namebuf[128], *cp;
176 struct sockaddr_in addr;
177 struct servent *svc;
178
179 memset(&addr, 0, sizeof(addr));
180 snprintf(namebuf, sizeof(namebuf), "%s", name);
181 cp = strrchr(namebuf, '/');
182 if(!cp)
183 cp = strrchr(namebuf, ':');
184
185 if(!cp) {
186 cp = namebuf;
187 name = "*";
188 }
189 else {
190 name = namebuf;
191 *(cp++) = 0;
192 }
193
194 addr.sin_family = AF_INET;
195 if(isdigit(*cp))
196 addr.sin_port = htons(atoi(cp));
197 else {
198 mutex.enter();
199 svc = getservbyname(cp, "tcp");
200 if(svc)
201 addr.sin_port = svc->s_port;
202 mutex.leave();
203 if(!svc) {
204 endSocket();
205 error(errBindingFailed, "Could not find service", errno);
206 return;
207
208 }
209 }
210
211 IPV4Address ia(name);
212 addr.sin_addr = getaddress(ia);
213
214#if defined(SO_REUSEADDR)
215 int opt = 1;
216 setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
217 (socklen_t)sizeof(opt));
218#endif
219
220 if(bind(so, (struct sockaddr *)&addr, sizeof(addr))) {
221 endSocket();
222 error(errBindingFailed,(char *)"Could not bind socket",socket_errno);
223 return;
224 }
225
226 setSegmentSize(mss);
227 if(listen(so, backlog)) {
228 endSocket();
229 error(errBindingFailed,(char *)"Could not listen on socket",
230 socket_errno);
231 return;
232 }
233 state = BOUND;
234}
235
236#endif
237
238TCPSocket::TCPSocket(const IPV4Address &ia, tpport_t port, unsigned backlog, unsigned mss) :
239Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
240{
241 struct sockaddr_in addr;
242
243 memset(&addr, 0, sizeof(addr));
244 addr.sin_family = AF_INET;
245 addr.sin_addr = getaddress(ia);
246 addr.sin_port = htons(port);
247
248#if defined(SO_REUSEADDR)
249 int opt = 1;
250 setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt));
251#endif
252 if(bind(so, (struct sockaddr *)&addr, sizeof(addr))) {
253 endSocket();
254 error(errBindingFailed,(char *)"Could not bind socket",socket_errno);
255 return;
256 }
257
258 setSegmentSize(mss);
259
260 if(listen(so, backlog)) {
261 endSocket();
262 error(errBindingFailed,(char *)"Could not listen on socket",socket_errno);
263 return;
264 }
265 state = BOUND;
266}
267
268bool TCPSocket::onAccept(const IPV4Host &ia, tpport_t port)
269{
270 return true;
271}
272
273TCPSocket::~TCPSocket()
274{
275 endSocket();
276}
277
278#ifdef CCXX_IPV6
279
280void TCPV6Socket::setSegmentSize(unsigned mss)
281{
282#ifdef TCP_MAXSEG
283 if(mss > 1)
284 setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss));
285#endif
286 segsize = mss;
287}
288
289TCPV6Socket::TCPV6Socket(const char *name, unsigned backlog, unsigned mss) :
290Socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)
291{
292 char namebuf[128], *cp;
293 struct addrinfo hint, *list = NULL, *first;
294
295 snprintf(namebuf, sizeof(namebuf), "%s", name);
296 cp = strrchr(namebuf, '/');
297
298 if(!cp) {
299 cp = namebuf;
300 name = NULL;
301 }
302 else {
303 name = namebuf;
304 *(cp++) = 0;
305 if(!strcmp(name, "*"))
306 name = NULL;
307 }
308
309 memset(&hint, 0, sizeof(hint));
310 hint.ai_family = AF_INET6;
311 hint.ai_socktype = SOCK_STREAM;
312 hint.ai_protocol = IPPROTO_TCP;
313 hint.ai_flags = AI_PASSIVE;
314
315 if(getaddrinfo(name, cp, &hint, &list) || !list) {
316 endSocket();
317 error(errBindingFailed, (char *)"Could not find service", errno);
318 return;
319 }
320
321#if defined(SO_REUSEADDR)
322 int opt = 1;
323 setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
324 (socklen_t)sizeof(opt));
325#endif
326
327 first = list;
328 while(list) {
329 if(!bind(so, list->ai_addr, (socklen_t)list->ai_addrlen)) {
330 state = BOUND;
331 break;
332 }
333 list = list->ai_next;
334 }
335 freeaddrinfo(first);
336 if(state != BOUND) {
337 endSocket();
338 error(errBindingFailed,(char *)"Could not bind socket",socket_errno);
339 return;
340 }
341
342 setSegmentSize(mss);
343
344 if(listen(so, backlog)) {
345 endSocket();
346 error(errBindingFailed,(char *)"Could not listen on socket",socket_errno);
347 return;
348 }
349}
350
351TCPV6Socket::TCPV6Socket(const IPV6Address &ia, tpport_t port, unsigned backlog, unsigned mss) :
352Socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)
353{
354 struct sockaddr_in6 addr;
355
356 memset(&addr, 0, sizeof(addr));
357 addr.sin6_family = AF_INET6;
358 addr.sin6_addr = getaddress(ia);
359 addr.sin6_port = htons(port);
360
361#if defined(SO_REUSEADDR)
362 int opt = 1;
363 setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt));
364#endif
365 if(bind(so, (struct sockaddr *)&addr, sizeof(addr))) {
366 endSocket();
367 error(errBindingFailed,(char *)"Could not bind socket",socket_errno);
368 return;
369 }
370
371 setSegmentSize(mss);
372
373 if(listen(so, backlog)) {
374 endSocket();
375 error(errBindingFailed,(char *)"Could not listen on socket",socket_errno);
376 return;
377 }
378 state = BOUND;
379}
380
381bool TCPV6Socket::onAccept(const IPV6Host &ia, tpport_t port)
382{
383 return true;
384}
385
386TCPV6Socket::~TCPV6Socket()
387{
388 endSocket();
389}
390
391#endif
392
393void TCPSocket::reject(void)
394{
395 SOCKET rej = accept(so, NULL, NULL);
396 ::shutdown(rej, 2);
397 release(rej);
398}
399
400#ifdef CCXX_IPV6
401void TCPV6Socket::reject(void)
402{
403 SOCKET rej = accept(so, NULL, NULL);
404 ::shutdown(rej, 2);
405 release(rej);
406}
407#endif
408
409TCPStream::TCPStream(TCPSocket &server, bool throwflag, timeout_t to) :
410 streambuf(), Socket(accept(server.getSocket(), NULL, NULL)),
411#ifdef OLD_IOSTREAM
412 iostream()
413#else
414 iostream((streambuf *)this)
415#endif
416 ,bufsize(0)
417 ,gbuf(NULL)
418 ,pbuf(NULL) {
419 tpport_t port;
420 family = IPV4;
421
422#ifdef OLD_IOSTREAM
423 init((streambuf *)this);
424#endif
425
426 timeout = to;
427 setError(throwflag);
428 IPV4Host host = getPeer(&port);
429 if(!server.onAccept(host, port)) {
430 endSocket();
431 error(errConnectRejected);
432 iostream::clear(ios::failbit | rdstate());
433 return;
434 }
435
436 segmentBuffering(server.getSegmentSize());
437 Socket::state = CONNECTED;
438}
439
440#ifdef CCXX_IPV6
441TCPStream::TCPStream(TCPV6Socket &server, bool throwflag, timeout_t to) :
442 streambuf(), Socket(accept(server.getSocket(), NULL, NULL)),
443#ifdef OLD_IOSTREAM
444 iostream()
445#else
446 iostream((streambuf *)this)
447#endif
448 ,bufsize(0)
449 ,gbuf(NULL)
450 ,pbuf(NULL) {
451 tpport_t port;
452
453 family = IPV6;
454
455#ifdef OLD_IOSTREAM
456 init((streambuf *)this);
457#endif
458
459 timeout = to;
460 setError(throwflag);
461 IPV6Host host = getIPV6Peer(&port);
462 if(!server.onAccept(host, port)) {
463 endSocket();
464 error(errConnectRejected);
465 iostream::clear(ios::failbit | rdstate());
466 return;
467 }
468
469 segmentBuffering(server.getSegmentSize());
470 Socket::state = CONNECTED;
471}
472#endif
473
474TCPStream::TCPStream(const IPV4Host &host, tpport_t port, unsigned size, bool throwflag, timeout_t to) :
475 streambuf(), Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP),
476#ifdef OLD_IOSTREAM
477 iostream(),
478#else
479 iostream((streambuf *)this),
480#endif
481 bufsize(0),gbuf(NULL),pbuf(NULL) {
482#ifdef OLD_IOSTREAM
483 init((streambuf *)this);
484#endif
485 family = IPV4;
486 timeout = to;
487 setError(throwflag);
488 connect(host, port, size);
489}
490
491#ifdef CCXX_IPV6
492TCPStream::TCPStream(const IPV6Host &host, tpport_t port, unsigned size, bool throwflag, timeout_t to) :
493 streambuf(), Socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP),
494#ifdef OLD_IOSTREAM
495 iostream(),
496#else
497 iostream((streambuf *)this),
498#endif
499 bufsize(0),gbuf(NULL),pbuf(NULL) {
500 family = IPV6;
501
502#ifdef OLD_IOSTREAM
503 init((streambuf *)this);
504#endif
505 timeout = to;
506 setError(throwflag);
507 connect(host, port, size);
508}
509#endif
510
511TCPStream::~TCPStream()
512{
513#ifdef CCXX_EXCEPTIONS
514 try { endStream(); }
515 catch( ... ) { if ( ! std::uncaught_exception()) throw;};
516#else
517 endStream();
518#endif
519}
520
521#ifdef HAVE_GETADDRINFO
522
523void TCPStream::connect(const char *target, unsigned mss)
524{
525 char namebuf[128];
526 char *cp;
527 struct addrinfo hint, *list = NULL, *next, *first;
528 bool connected = false;
529
530 snprintf(namebuf, sizeof(namebuf), "%s", target);
531 cp = strrchr(namebuf, '/');
532 if(!cp)
533 cp = strrchr(namebuf, ':');
534
535 if(!cp) {
536 endStream();
537 connectError();
538 return;
539 }
540
541 *(cp++) = 0;
542
543 memset(&hint, 0, sizeof(hint));
544 hint.ai_family = family;
545 hint.ai_socktype = SOCK_STREAM;
546 hint.ai_protocol = IPPROTO_TCP;
547
548 if(getaddrinfo(namebuf, cp, &hint, &list) || !list) {
549 endStream();
550 connectError();
551 return;
552 }
553
554 first = list;
555
556#ifdef TCP_MAXSEG
557 if(mss)
558 setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss));
559#endif
560
561 while(list) {
562 if(!::connect(so, list->ai_addr, (socklen_t)list->ai_addrlen)) {
563 connected = true;
564 break;
565 }
566 next = list->ai_next;
567 list = next;
568 }
569
570 freeaddrinfo(first);
571
572 if(!connected) {
573 endStream();
574 connectError();
575 return;
576 }
577
578 segmentBuffering(mss);
579 Socket::state = CONNECTED;
580}
581
582#else
583void TCPStream::connect(const char *target, unsigned mss)
584{
585 char namebuf[128];
586 char *cp;
587 struct servent *svc;
588 tpport_t port;
589
590 snprintf(namebuf, sizeof(namebuf), "%s", target);
591 cp = strrchr(namebuf, '/');
592 if(!cp)
593 cp = strrchr(namebuf, ':');
594
595 if(!cp) {
596 endStream();
597 connectError();
598 return;
599 }
600
601 *(cp++) = 0;
602
603 if(isdigit(*cp))
604 port = atoi(cp);
605 else {
606 mutex.enter();
607 svc = getservbyname(cp, "tcp");
608 if(svc)
609 port = ntohs(svc->s_port);
610 mutex.leave();
611 if(!svc) {
612 endStream();
613 connectError();
614 return;
615 }
616 }
617
618 switch(family) {
619 case IPV4:
620 connect(IPV4Host(namebuf), port, mss);
621 break;
622#ifdef CCXX_IPV6
623 case IPV6:
624 connect(IPV6Host(namebuf), port, mss);
625 break;
626#endif
627 default:
628 endStream();
629 connectError();
630 }
631}
632#endif
633
634void TCPStream::connect(const IPV4Host &host, tpport_t port, unsigned mss)
635{
636 size_t i;
637 fd_set fds;
638 struct timeval to;
639 bool connected = false;
640 int rtn;
641 int sockopt;
642 socklen_t len = sizeof(sockopt);
643
644#ifdef TCP_MAXSEG
645 if(mss)
646 setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss));
647#endif
648
649 for(i = 0 ; i < host.getAddressCount(); i++) {
650 struct sockaddr_in addr;
651 memset(&addr, 0, sizeof(addr));
652 addr.sin_family = AF_INET;
653 addr.sin_addr = host.getAddress(i);
654 addr.sin_port = htons(port);
655
656 if(timeout)
657 setCompletion(false);
658
659 // Win32 will crash if you try to connect to INADDR_ANY.
660 if ( INADDR_ANY == addr.sin_addr.s_addr )
661 addr.sin_addr.s_addr = INADDR_LOOPBACK;
662 rtn = ::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr));
663 if(!rtn) {
664 connected = true;
665 break;
666 }
667
668#ifndef _MSWINDOWS_
669 if(errno == EINPROGRESS)
670#else
671 if(WSAGetLastError() == WSAEINPROGRESS)
672#endif
673 {
674 FD_ZERO(&fds);
675 FD_SET(so, &fds);
676 to.tv_sec = timeout / 1000;
677 to.tv_usec = timeout % 1000 * 1000;
678
679 // timeout check for connect completion
680
681 if(::select((int)so + 1, NULL, &fds, NULL, &to) < 1)
682 continue;
683
684 getsockopt(so, SOL_SOCKET, SO_ERROR, (char *)&sockopt, &len);
685 if(!sockopt) {
686 connected = true;
687 break;
688 }
689 endSocket();
690 so = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
691 if(so == INVALID_SOCKET)
692 break;
693 }
694 }
695
696 setCompletion(true);
697 if(!connected) {
698 rtn = errno;
699 endStream();
700 errno = rtn;
701 connectError();
702 return;
703 }
704
705 segmentBuffering(mss);
706 Socket::state = CONNECTED;
707}
708
709#ifdef CCXX_IPV6
710void TCPStream::connect(const IPV6Host &host, tpport_t port, unsigned mss)
711{
712 size_t i;
713 fd_set fds;
714 struct timeval to;
715 bool connected = false;
716 int rtn;
717 int sockopt;
718 socklen_t len = sizeof(sockopt);
719
720#ifdef TCP_MAXSEG
721 if(mss)
722 setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss));
723#endif
724
725 for(i = 0 ; i < host.getAddressCount(); i++) {
726 struct sockaddr_in6 addr;
727 memset(&addr, 0, sizeof(addr));
728 addr.sin6_family = AF_INET6;
729 addr.sin6_addr = host.getAddress(i);
730 addr.sin6_port = htons(port);
731
732 if(timeout)
733 setCompletion(false);
734
735 // Win32 will crash if you try to connect to INADDR_ANY.
736 if ( !memcmp(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)))
737 memcpy(&addr.sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback));
738 rtn = ::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr));
739 if(!rtn) {
740 connected = true;
741 break;
742 }
743
744#ifndef _MSWINDOWS_
745 if(errno == EINPROGRESS)
746#else
747 if(WSAGetLastError() == WSAEINPROGRESS)
748#endif
749 {
750 FD_ZERO(&fds);
751 FD_SET(so, &fds);
752 to.tv_sec = timeout / 1000;
753 to.tv_usec = timeout % 1000 * 1000;
754
755 // timeout check for connect completion
756
757 if(::select((int)so + 1, NULL, &fds, NULL, &to) < 1)
758 continue;
759
760 getsockopt(so, SOL_SOCKET, SO_ERROR, (char *)&sockopt, &len);
761 if(!sockopt) {
762 connected = true;
763 break;
764 }
765 endSocket();
766 so = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
767 if(so == INVALID_SOCKET)
768 break;
769 }
770 }
771
772 setCompletion(true);
773 if(!connected) {
774 rtn = errno;
775 endStream();
776 errno = rtn;
777 connectError();
778 return;
779 }
780
781 segmentBuffering(mss);
782 Socket::state = CONNECTED;
783}
784#endif
785
786TCPStream::TCPStream(const char *target, Family fam, unsigned mss, bool throwflag, timeout_t to) :
787streambuf(), Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP),
788#ifdef OLD_IOSTREAM
789iostream(),
790#else
791iostream((streambuf *)this),
792#endif
793timeout(to), bufsize(0),gbuf(NULL),pbuf(NULL)
794{
795 family = fam;
796#ifdef OLD_IOSTREAM
797 init((streambuf *)this);
798#endif
799 setError(throwflag);
800 connect(target, mss);
801}
802
803TCPStream::TCPStream(Family fam, bool throwflag, timeout_t to) :
804streambuf(), Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP),
805#ifdef OLD_IOSTREAM
806iostream(),
807#else
808iostream((streambuf *)this),
809#endif
810timeout(to), bufsize(0),gbuf(NULL),pbuf(NULL)
811{
812 family = fam;
813#ifdef OLD_IOSTREAM
814 init((streambuf *)this);
815#endif
816 setError(throwflag);
817}
818
819void TCPStream::connect(TCPSocket &tcpip)
820{
821 tpport_t port;
822
823 endStream();
824 family = IPV4;
825 so = accept(tcpip.getSocket(), NULL, NULL);
826 if(so == INVALID_SOCKET)
827 return;
828
829 IPV4Host host = getPeer(&port);
830 if(!tcpip.onAccept(host, port)) {
831 endSocket();
832 iostream::clear(ios::failbit | rdstate());
833 return;
834 }
835
836 segmentBuffering(tcpip.getSegmentSize());
837 Socket::state = CONNECTED;
838}
839
840#ifdef CCXX_IPV6
841
842void TCPStream::connect(TCPV6Socket &tcpip)
843{
844 tpport_t port;
845
846 endStream();
847 family = IPV6;
848 so = accept(tcpip.getSocket(), NULL, NULL);
849 if(so == INVALID_SOCKET)
850 return;
851
852 IPV6Host host = getIPV6Peer(&port);
853 if(!tcpip.onAccept(host, port)) {
854 endSocket();
855 iostream::clear(ios::failbit | rdstate());
856 return;
857 }
858
859 segmentBuffering(tcpip.getSegmentSize());
860 Socket::state = CONNECTED;
861}
862#endif
863
864void TCPStream::segmentBuffering(unsigned mss)
865{
866 unsigned max = 0;
867
868 if(mss == 1) { // special interactive
869 allocate(1);
870 return;
871 }
872
873#ifdef TCP_MAXSEG
874 socklen_t alen = sizeof(max);
875
876 if(mss)
877 setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&max, sizeof(max));
878 getsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&max, &alen);
879#endif
880
881 if(max && max < mss)
882 mss = max;
883
884 if(!mss) {
885 if(max)
886 mss = max;
887 else
888 mss = 536;
889 allocate(mss);
890 return;
891 }
892
893#ifdef TCP_MAXSEG
894 setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, sizeof(mss));
895#endif
896
897 if(mss < 80)
898 mss = 80;
899
900 if(mss * 7 < 64000)
901 bufferSize(mss * 7);
902 else if(mss * 6 < 64000)
903 bufferSize(mss * 6);
904 else
905 bufferSize(mss * 5);
906
907 if(mss < 512)
908 sendLimit(mss * 4);
909
910 allocate(mss);
911}
912
913int TCPStream::getSegmentSize(void)
914{
915 unsigned mss = 0;
916#ifdef TCP_MAXSEG
917 socklen_t alen = sizeof(mss);
918
919 getsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &alen);
920#endif
921 if(!mss)
922 return (int)bufsize;
923
924 return mss;
925}
926
927void TCPStream::disconnect(void)
928{
929 if(Socket::state == AVAILABLE)
930 return;
931
932 endStream();
933 so = socket(family, SOCK_STREAM, IPPROTO_TCP);
934 if(so != INVALID_SOCKET)
935 Socket::state = AVAILABLE;
936}
937
938void TCPStream::endStream(void)
939{
940 if(bufsize)
941 sync();
942 if(gbuf)
943 delete[] gbuf;
944 if(pbuf)
945 delete[] pbuf;
946 gbuf = pbuf = NULL;
947 bufsize = 0;
948 iostream::clear();
949 endSocket();
950}
951
952void TCPStream::allocate(size_t size)
953{
954 if(size < 2) {
955 bufsize = 1;
956 gbuf = pbuf = 0;
957 return;
958 }
959
960 gbuf = new char[size];
961 pbuf = new char[size];
962 if(!pbuf || !gbuf) {
963 error(errResourceFailure, (char *)"Could not allocate socket stream buffers");
964 return;
965 }
966 bufsize = size;
967 iostream::clear();
968
969#if (defined(__GNUC__) && (__GNUC__ < 3)) && !defined(_MSWINDOWS_) && !defined(STLPORT)
970 setb(gbuf, gbuf + size, 0);
971#endif
972 setg(gbuf, gbuf + size, gbuf + size);
973 setp(pbuf, pbuf + size);
974}
975
976int TCPStream::doallocate()
977{
978 if(bufsize)
979 return 0;
980
981 allocate(1);
982 return 1;
983}
984
985int TCPStream::uflow()
986{
987 int ret = underflow();
988
989 if (ret == EOF)
990 return EOF;
991
992 if (bufsize != 1)
993 gbump(1);
994
995 return ret;
996}
997
998int TCPStream::underflow()
999{
1000 ssize_t rlen = 1;
1001 unsigned char ch;
1002
1003 if(bufsize == 1) {
1004 if(Socket::state == STREAM)
1005 rlen = ::read((int)so, (char *)&ch, 1);
1006 else if(timeout && !Socket::isPending(pendingInput, timeout)) {
1007 iostream::clear(ios::failbit | rdstate());
1008 error(errTimeout,(char *)"Socket read timed out",socket_errno);
1009 return EOF;
1010 }
1011 else
1012 rlen = readData(&ch, 1);
1013 if(rlen < 1) {
1014 if(rlen < 0) {
1015 iostream::clear(ios::failbit | rdstate());
1016 error(errInput,(char *)"Could not read from socket",socket_errno);
1017 }
1018 return EOF;
1019 }
1020 return ch;
1021 }
1022
1023 if(!gptr())
1024 return EOF;
1025
1026 if(gptr() < egptr())
1027 return (unsigned char)*gptr();
1028
1029 rlen = (ssize_t)((gbuf + bufsize) - eback());
1030 if(Socket::state == STREAM)
1031 rlen = ::read((int)so, (char *)eback(), _IOLEN64 rlen);
1032 else if(timeout && !Socket::isPending(pendingInput, timeout)) {
1033 iostream::clear(ios::failbit | rdstate());
1034 error(errTimeout,(char *)"Socket read timed out",socket_errno);
1035 return EOF;
1036 }
1037 else
1038 rlen = readData(eback(), rlen);
1039 if(rlen < 1) {
1040// clear(ios::failbit | rdstate());
1041 if(rlen < 0)
1042 error(errNotConnected,(char *)"Connection error",socket_errno);
1043 else {
1044 error(errInput,(char *)"Could not read from socket",socket_errno);
1045 iostream::clear(ios::failbit | rdstate());
1046 }
1047 return EOF;
1048 }
1049 error(errSuccess);
1050
1051 setg(eback(), eback(), eback() + rlen);
1052 return (unsigned char) *gptr();
1053}
1054
1055bool TCPStream::isPending(Pending pending, timeout_t timer)
1056{
1057 if(pending == pendingInput && in_avail())
1058 return true;
1059 else if(pending == pendingOutput)
1060 flush();
1061
1062 return Socket::isPending(pending, timer);
1063}
1064
1065int TCPStream::sync(void)
1066{
1067 overflow(EOF);
1068 setg(gbuf, gbuf + bufsize, gbuf + bufsize);
1069 return 0;
1070}
1071
1072size_t TCPStream::printf(const char *format, ...)
1073{
1074 va_list args;
1075 size_t len;
1076 char *buf;
1077
1078 va_start(args, format);
1079 overflow(EOF);
1080 len = pptr() - pbase();
1081 buf = pptr();
1082 vsnprintf(buf, len, format, args);
1083 va_end(args);
1084 len = strlen(buf);
1085 if(Socket::state == STREAM)
1086 return ::write((int)so, buf, _IOLEN64 len);
1087 else
1088 return writeData(buf, len);
1089}
1090
1091int TCPStream::overflow(int c)
1092{
1093 unsigned char ch;
1094 ssize_t rlen, req;
1095
1096 if(bufsize == 1) {
1097 if(c == EOF)
1098 return 0;
1099
1100 ch = (unsigned char)(c);
1101 if(Socket::state == STREAM)
1102 rlen = ::write((int)so, (const char *)&ch, 1);
1103 else
1104 rlen = writeData(&ch, 1);
1105 if(rlen < 1) {
1106 if(rlen < 0) {
1107 iostream::clear(ios::failbit | rdstate());
1108 error(errOutput,(char *)"Could not write to socket",socket_errno);
1109 }
1110 return EOF;
1111 }
1112 else
1113 return c;
1114 }
1115
1116 if(!pbase())
1117 return EOF;
1118
1119 req = (ssize_t)(pptr() - pbase());
1120 if(req) {
1121 if(Socket::state == STREAM)
1122 rlen = ::write((int)so, (const char *)pbase(), req);
1123 else
1124 rlen = writeData(pbase(), req);
1125 if(rlen < 1) {
1126 if(rlen < 0) {
1127 iostream::clear(ios::failbit | rdstate());
1128 error(errOutput,(char *)"Could not write to socket",socket_errno);
1129 }
1130 return EOF;
1131 }
1132 req -= rlen;
1133 }
1134
1135 // if write "partial", rebuffer remainder
1136
1137 if(req)
1138// memmove(pbuf, pptr() + rlen, req);
1139 memmove(pbuf, pbuf + rlen, req);
1140 setp(pbuf, pbuf + bufsize);
1141 pbump(req);
1142
1143 if(c != EOF) {
1144 *pptr() = (unsigned char)c;
1145 pbump(1);
1146 }
1147 return c;
1148}
1149
1150TCPSession::TCPSession(const IPV4Host &ia, tpport_t port, size_t size, int pri, size_t stack) :
1151Thread(pri, stack), TCPStream(IPV4)
1152{
1153 setCompletion(false);
1154 setError(false);
1155 allocate(size);
1156
1157 size_t i;
1158 for(i = 0 ; i < ia.getAddressCount(); i++) {
1159 struct sockaddr_in addr;
1160 memset(&addr, 0, sizeof(addr));
1161 addr.sin_family = AF_INET;
1162 addr.sin_addr = ia.getAddress(i);
1163 addr.sin_port = htons(port);
1164
1165 // Win32 will crash if you try to connect to INADDR_ANY.
1166 if ( INADDR_ANY == addr.sin_addr.s_addr )
1167 addr.sin_addr.s_addr = INADDR_LOOPBACK;
1168 if(::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)) == 0)
1169 break;
1170
1171#ifdef _MSWINDOWS_
1172 if(WSAGetLastError() == WSAEISCONN || WSAGetLastError() == WSAEWOULDBLOCK)
1173#else
1174 if(errno == EINPROGRESS)
1175#endif
1176 {
1177 Socket::state = CONNECTING;
1178 return;
1179 }
1180 }
1181
1182 if(i == ia.getAddressCount()) {
1183 endSocket();
1184 Socket::state = INITIAL;
1185 return;
1186 }
1187
1188 setCompletion(true);
1189 Socket::state = CONNECTED;
1190}
1191
1192#ifdef CCXX_IPV6
1193TCPSession::TCPSession(const IPV6Host &ia, tpport_t port, size_t size, int pri, size_t stack) :
1194Thread(pri, stack), TCPStream(IPV6)
1195{
1196 setCompletion(false);
1197 setError(false);
1198 allocate(size);
1199
1200 size_t i;
1201 for(i = 0 ; i < ia.getAddressCount(); i++) {
1202 struct sockaddr_in6 addr;
1203 memset(&addr, 0, sizeof(addr));
1204 addr.sin6_family = AF_INET6;
1205 addr.sin6_addr = ia.getAddress(i);
1206 addr.sin6_port = htons(port);
1207
1208 // Win32 will crash if you try to connect to INADDR_ANY.
1209 if(!memcmp(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)))
1210 memcpy(&addr.sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback));
1211 if(::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)) == 0)
1212 break;
1213
1214#ifdef _MSWINDOWS_
1215// if(WSAGetLastError() == WSAEWOULDBLOCK)
1216 if(WSAGetLastError() == WSAEISCONN)
1217#else
1218 if(errno == EINPROGRESS)
1219#endif
1220 {
1221 Socket::state = CONNECTING;
1222 return;
1223 }
1224 }
1225
1226 if(i == ia.getAddressCount()) {
1227 endSocket();
1228 Socket::state = INITIAL;
1229 return;
1230 }
1231
1232 setCompletion(true);
1233 Socket::state = CONNECTED;
1234}
1235#endif
1236
1237TCPSession::TCPSession(TCPSocket &s, int pri, size_t stack) :
1238Thread(pri, stack), TCPStream(s)
1239{
1240 setCompletion(true);
1241 setError(false);
1242}
1243
1244#ifdef CCXX_IPV6
1245TCPSession::TCPSession(TCPV6Socket &s, int pri, size_t stack) :
1246Thread(pri, stack), TCPStream(s)
1247{
1248 setCompletion(true);
1249 setError(false);
1250}
1251#endif
1252
1253TCPSession::~TCPSession()
1254{
1255 endStream();
1256}
1257
1258int TCPSession::waitConnection(timeout_t timer)
1259{
1260 int sockopt = 0;
1261 socklen_t len = sizeof(sockopt);
1262
1263 switch(Socket::state) {
1264 case INITIAL:
1265 return -1;
1266 case CONNECTED:
1267 break;
1268 case CONNECTING:
1269 if(!Socket::isPending(pendingOutput, timer)) {
1270 endSocket();
1271 Socket::state = INITIAL;
1272 return -1;
1273 }
1274
1275 getsockopt(so, SOL_SOCKET, SO_ERROR, (char *)&sockopt, &len);
1276 if(sockopt) {
1277 endSocket();
1278 Socket::state = INITIAL;
1279 return -1;
1280 }
1281 default:
1282 break;
1283 }
1284 Socket::state = CONNECTED;
1285 return 0;
1286}
1287
1288void TCPSession::initial(void)
1289{
1290 if(waitConnection(60000))
1291 exit();
1292}
1293
1294