Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
tcp.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/****************************************************************************\
20TCP Neal Kettler neal@westwood.com
21******************************************************************************
22
23A general purpose TCP class that can be used in either CLIENT or
24SERVER mode. Note that this uses non-blocking sockets.
25
26The FD_* macros:
27
28 FD_CLR(int fd, fd_set *set); // clear a single FD
29 FD_ISSET(int fd, fd_set *set); // check whether a single FD is set
30 FD_SET(int fd, fd_set *set); // set a single FD
31 FD_ZERO(fd_set * set); // clear the entire set
32
33NOTE: The fd_set returned by 'Wait' is static, don't call delete
34on it!
35
36
37If you are writing a CLIENT:
38 The last argument to many functions is an integer whichFD, this is used
39only by SERVER mode, so you can omit this argument. Sample Code:
40
41fd_set *fdSet;
42uint8 *buff=new uint8[1024];
43int retval;
44TCP tcp(CLIENT);
45
46tcp.Bind((uint32)0,(uint16)0); // let system pick local IP and a Port for you
47tcp.Connect("tango",13); // can connect by name or "10.1.1.10"
48 // or the integerßin host byte order
49
50fdSet=tcp.Wait(10,0); // wait for UP TO 10 sec and 0 microseconds
51if (FD_ISSET(tcp.GetFD(),fdSet)) // Is there something to read?
52{
53 retval=tcp.Read(buff,1024); // Read something
54 // Retval will contain the number of
55 // bytes read, or...
56 // 0 = remote end closed connection
57 // -1 = nothing to read
58 fprintf(stderr,"%s",buff);
59}
60else
61 fprintf(stderr,"Nothing was read!\n");
62
63
64If you are writing a SERVER:
65
66 The structure called 'clientList' contains all the File Descriptors
67that have connected to the server. Make sure you look at the FD_*
68functions so you can use this sort of structure. When you are writing
69a server, you need to specify the 'whichFD' arguments to all the
70functions. Sample Code:
71
72fd_set *fdSet;
73uint8 *buff=new uint8[1024];
74int retval;
75TCP tcp(SERVER);
76
77tcp.Bind((uint32)0,(uint16)2121); // You need to bind to a well defined
78 // port number or nobody will know where
79 // to connect to.
80
81while (1)
82{
83 fdSet=tcp.Wait(-1,-1); // Wait until there is something on the socket
84 if (FD_ISSET(tcp.GetFD(),fdSet)) // somebody must want a connection
85 {
86 retval=tcp.GetConnection(); // Get a connection if somebody's trying
87 if (retval!=-1)
88 {
89 tcp.Write("Hello World!\n",strlen("Hello World!\n"),retval);
90 tcp.Close(retval);
91 }
92 }
93}
94
95
96\****************************************************************************/
97
98
99#include "tcp.h"
100#include <stdarg.h>
101
102#ifndef _WINDOWS
103#include <errno.h>
104#define closesocket close
105#endif
106
107// newMode should be either CLIENT or SERVER
108TCP::TCP(int new_mode)
109{
110 mode=CLIENT;
111 maxFD=0;
112 fd = -1;
113 clientCount=0;
114 if ((new_mode==CLIENT)||(new_mode==SERVER))
115 mode=new_mode;
116 FD_ZERO(&clientList);
117 connectionState=CLOSED;
118 inputDelay=5;
119 outputDelay=5;
120}
121
122// Create a TCP object on a pre-existing socket
123TCP::TCP(int new_mode,sint16 socket)
124{
125 sint32 retval;
126
127 mode=CLIENT;
128 maxFD= socket;
129 fd = socket;
130 clientCount=0;
131 if ((new_mode==CLIENT)||(new_mode==SERVER))
132 mode=new_mode;
133 FD_ZERO(&clientList);
134
135 inputDelay=5;
136 outputDelay=5;
137
138
139 retval=SetBlocking(FALSE,socket); // set to NB mode
140 //DBGMSG("Setblocking: "<<retval);
141
142 connectionState=CLOSED;
143 if (mode==CLIENT) // determine what state the socket is in
144 {
145 connectionState=CONNECTING; // this is used when state is unsure
146 if (IsConnected(socket))
147 connectionState=CONNECTED;
148 else
149 connectionState=CLOSED;
150 }
151 //DBGMSG("Connstate = "<<connectionState);
152}
153
154
156{
157 CloseAll();
158}
159
160
162{
163 return(fd);
164}
165
166
167// private function
169{
170 if (whichFD==0)
171 whichFD=fd;
172
173 #ifdef _WINDOWS
174 unsigned long flag=1;
175 if (block)
176 flag=0;
177 int retval;
178 retval=ioctlsocket(whichFD,FIONBIO,&flag);
179 if (retval==SOCKET_ERROR)
180 return(-1);
181 else
182 return(0);
183 #else
184 int flags = fcntl(whichFD, F_GETFL, 0);
185 if (block==FALSE) // set nonblocking
186 flags |= O_NONBLOCK;
187 else // set blocking
188 flags &= ~(O_NONBLOCK);
189
190 if (fcntl(whichFD, F_SETFL, flags) < 0)
191 {
192 return(-1);
193 }
194 return(0);
195 #endif
196}
197
198
200{
201 if (mode==CLIENT)
202 return(fd);
203 else if (mode==SERVER)
204 return(maxFD);
205 else
206 return(-1);
207}
208
209// Only specify whichFD if this is a server application
211{
212 sint32 retval;
213
214 if (whichFD==0)
215 {
216 if (mode==SERVER)
217 assert(FALSE);
218 whichFD=fd;
219 }
220 SetBlocking(TRUE,whichFD);
221 retval=send(whichFD,(const char *)msg,len,0);
222 #ifdef _WINDOWS
223 if (retval==SOCKET_ERROR)
224 retval=-1;
225 #endif
226 SetBlocking(FALSE,whichFD);
227 return(retval);
228}
229
230
231// Only specify whichFD if this is a server application
232// NON BLOCKING WRITE
234{
235 sint32 retval;
236
237 if (whichFD==0)
238 {
239 if (mode==SERVER)
240 assert(FALSE);
241 whichFD=fd;
242 }
243 retval=send(whichFD,(const char *)msg,len,0);
244 #ifdef _WINDOWS
245 if (retval==SOCKET_ERROR)
246 retval=-1;
247 #endif
248 return(retval);
249}
250
251
252// Encapsulate data for lame ass proxys that won't pass 0's or 255's through
253// 0 goes to 1,1
254// 1 goes to 1,2
255// 255 goes to 1,3
256// everything else is the same
258{
259 sint32 retval;
260 uint32 i,bytesSent=0;
261 uint8 data,one=1;
262
263 if (mode==CLIENT)
264 whichFD=fd;
265 SetBlocking(TRUE,whichFD);
266 for (i=0; i<len; i++)
267 {
268 data=msg[i];
269 if ((data>1)&&(data<255))
270 {
271 retval=send(whichFD,(char *)&data,1,0);
272 if (retval<1)
273 {
274 SetBlocking(FALSE,whichFD);
275 return(i);
276 }
277 bytesSent++;
278 }
279 else
280 {
281 retval=send(whichFD,(char *)&one,1,0);
282 if (retval<1)
283 {
284 SetBlocking(FALSE,whichFD);
285 return(i);
286 }
287 if (data==0)
288 data=1;
289 else if (data==1)
290 data=2;
291 else if (data==255)
292 data=3;
293
294 retval=send(whichFD,(char *)&data,1,0);
295 if (retval<1)
296 {
297 SetBlocking(FALSE,whichFD);
298 return(i);
299 }
300 bytesSent+=2;
301 }
302 }
303 SetBlocking(FALSE,whichFD);
305 return(len);
306}
307
308
309// Make sure string is '\0' terminated
311{
312 if (mode==CLIENT)
313 whichFD=fd;
314
315 WaitWrite(whichFD);
316
317 sint32 retval;
318
319 if (mode==CLIENT)
320 {
321 SetBlocking(TRUE,fd);
322 retval=send(fd,msg,strlen(msg),0);
323 SetBlocking(FALSE,fd);
324 return(retval);
325 }
326 else if (mode==SERVER)
327 {
328 if ((whichFD<=maxFD) && (FD_ISSET(whichFD,&clientList)))
329 {
330 SetBlocking(TRUE,whichFD);
331 retval=send(whichFD,msg,strlen(msg),0);
332 SetBlocking(FALSE,whichFD);
333 return(retval);
334 }
335 }
336 return(-1);
337}
338
339
340// only use for strings up to 1024 chars!
341sint32 TCP::Printf(sint32 whichFD,const char *format,...)
342{
343 va_list arg;
344 char string[1024];
345 sint32 retval;
346 va_start(arg,format);
347 vsprintf(string,format,arg);
348 va_end(arg);
349
350 if (mode==CLIENT)
351 whichFD=fd;
352
353 WaitWrite(fd);
354 if (mode==CLIENT)
355 {
356 SetBlocking(TRUE,whichFD);
357 retval=send(fd,string,strlen(string),0);
358 SetBlocking(FALSE,whichFD);
359 return(retval);
360 }
361 else if (mode==SERVER)
362 {
363 if ((whichFD<=maxFD) && (FD_ISSET(whichFD,&clientList)))
364 {
365 SetBlocking(TRUE,whichFD);
366 retval=send(whichFD,string,strlen(string),0);
367 SetBlocking(FALSE,whichFD);
368 return(retval);
369 }
370 }
371 return(-1);
372}
373
374
375
376// Returns 0 on failure
377// Returns IP in host byte order!
379{
380 struct sockaddr_in sin;
381 int sinSize=sizeof(sin);
382
383 if (mode==CLIENT)
384 {
385 if(getpeername(fd,(sockaddr *)&sin,&sinSize)==0)
386 return(ntohl(sin.sin_addr.s_addr));
387 }
388 else if (mode==SERVER)
389 {
390 if(getpeername(whichFD,(sockaddr *)&sin,&sinSize)==0)
391 return(ntohl(sin.sin_addr.s_addr));
392 }
393 return(0);
394}
395
396
397// Returns 0 on failure
398// Returns Port in host byte order!
400{
401 struct sockaddr_in sin;
402 int sinSize=sizeof(sin);
403
404 if (mode==CLIENT)
405 {
406 if(getpeername(fd,(sockaddr *)&sin,&sinSize)==0)
407 return(ntohs(sin.sin_port));
408 }
409 else if (mode==SERVER)
410 {
411 if(getpeername(whichFD,(sockaddr *)&sin,&sinSize)==0)
412 return(ntohs(sin.sin_port));
413 }
414 return(0);
415}
416
417
418// Is the FD connected?
420{
421 struct sockaddr_in sin;
422 int sinSize=sizeof(sin);
423
424 if (mode==CLIENT)
425 whichFD=fd;
426
427 if (mode==CLIENT)
428 {
429 if (connectionState==CONNECTED)
430 return(TRUE);
431 if (connectionState==CLOSED)
432 return(FALSE);
433 }
434
435 // only get here if state==CONNECTING
436 if(getpeername(whichFD,(sockaddr *)&sin,&sinSize)==0)
437 if ( (sin.sin_addr.s_addr!=htonl(0)) && (CanWrite(whichFD)) )
438 {
439 connectionState=CONNECTED;
440 return(TRUE);
441 }
442 return(FALSE);
443}
444
445
446// Not portable?
447/**************
448sint32 TCP::GetSockStatus(sint32 whichFD)
449{
450 sint32 retval;
451 int status,size=sizeof(int);
452
453 if (whichFD==0)
454 whichFD=fd;
455 retval=getsockopt(whichFD,SOL_SOCKET,SO_ERROR,(char *)&status,&size);
456 if (retval==-1)
457 return(-1);
458 return(status);
459}
460*******************/
461
462
463
464// The TCP equivalent of fgets()
465char *TCP::Gets(char *string,int n,int whichFD)
466{
467 char c;
468 int retval,i=0;
469 fd_set fdSet;
470
471 if (whichFD==0)
472 whichFD=GetFD();
473
474 if (whichFD <= 0)
475 return(NULL);
476
477 memset(string,0,n);
478
479 while(1)
480 {
481 if (i==n)
482 return(string);
483
484 Wait(inputDelay,0,fdSet,whichFD); // inputDelay = 5 sec or so
485 if (! FD_ISSET(whichFD,&fdSet))
486 {
487 DBGMSG("Gets timeout: " << inputDelay);
488 return(NULL);
489 }
490
491 retval=Read((unsigned char *)&c,1,whichFD);
492 if ((retval>0)&&(c!=0))
493 {
494 string[i]=c;
495 if (c=='\n')
496 return(string);
497 i++;
498 }
499 else if ((retval==0)&&(i==0))
500 {
501 DBGMSG("Remote endpoint closed (1)");
502 return(NULL);
503 }
504 else if (retval==0)
505 return(string);
506 }
507 return(string);
508}
509
510
511// only specify whichFD if this is a server
513{
514 sint32 retval;
515 //DBGMSG("In read, mode: "<<mode<<" FD: "<<fd);
516 if (mode==CLIENT)
517 {
518 retval=recv(fd,(char *)msg,len,0);
520 if (retval==0)
521 Close();
522 return(retval);
523 }
524 else if (mode==SERVER)
525 {
526 if ((whichFD<=maxFD) && (FD_ISSET(whichFD,&clientList)))
527 {
528 retval=recv(whichFD,(char *)msg,len,0);
529 if (retval==0)
530 {
531 Close(whichFD);
532 }
533 return(retval);
534 }
535 else
536 {
537 return(0); // closed
538 }
539 }
540 return(-1);
541}
542
543
544// only specify whichFD if this is a server
545// Try and read 'len' bytes until the timer goes out.
546// This is effectively a blocking call, but it's still useful
547// in threaded environments.
548sint32 TCP::TimedRead(uint8 *msg,uint32 len,int seconds,sint32 whichFD)
549{
550 fd_set set;
551 sint32 bytes_read=0;
552 sint32 retval;
553
554 time_t stop_time=time(NULL)+seconds;
555 while ((time(NULL)<=stop_time)&&((uint32)bytes_read<len))
556 {
557 Wait(1,0,set,whichFD);
558 //DBGMSG("Calling read");
559 retval=Read(msg+bytes_read,len-bytes_read,whichFD);
560 if (retval==0) // they closed
561 {
562 DBGMSG("Remote close!\n");
563 return(bytes_read);
564 }
565 else if (retval>0)
566 bytes_read+=retval;
567 // otherwise some error
568 }
569 return(bytes_read);
570}
571
572
573
574// only specify whichFD if this is a server
575// Peek at data in system buffer
577{
578 sint32 retval;
579 if (mode==CLIENT)
580 {
581 retval=recv(fd,(char *)msg,len,MSG_PEEK);
582 if (retval==0)
583 Close();
584 return(retval);
585 }
586 else if (mode==SERVER)
587 {
588 if ((whichFD<=maxFD) && (FD_ISSET(whichFD,&clientList)))
589 {
590 retval=recv(whichFD,(char *)msg,len,MSG_PEEK);
591 if (retval==0)
592 Close(whichFD);
593 return(retval);
594 }
595 else
596 return(0); // closed
597 }
598 return(-1);
599}
600
601
602// only specify whichFD if this is a server
603// (this is used for non-8 bit clean pipes, you probably don't
604// want to use it!)
606{
607 sint32 retval,bytesRead=0;
608 uint32 i;
609 char data;
610
611 if (mode==CLIENT)
612 whichFD=fd;
613 else if (mode==SERVER)
614 {
615 if ((whichFD>maxFD) || (!FD_ISSET(whichFD,&clientList)))
616 return(0);
617 }
618 else
619 return(-1);
620
621 for (i=0; i<len; i++)
622 {
623 retval=recv(fd,&data,1,0);
624 if (retval==0)
625 {
626 Close();
627 return(bytesRead);
628 }
629 if (retval==1)
630 {
631 bytesRead++;
632 if (data==1)
633 {
634 retval=0;
635 while(retval!=1)
636 {
637 retval=recv(fd,&data,1,0);
638 if (retval==0)
639 {
640 Close();
641 return(bytesRead);
642 }
643 }
644 if (data==1)
645 data=0;
646 else if (data==2)
647 data=1;
648 else if (data==3)
649 data=(char)255;
650 }
651 msg[i]=data;
652 }
653 if (retval==-1)
654 return(bytesRead);
655 }
656 return(bytesRead);
657}
658
659
661{
662 int i;
663
664 if (mode==CLIENT)
665 return(Close());
666
667 for(i=0; i<=maxFD; i++)
668 {
669 if ((i!=fd)&&(FD_ISSET(i,&clientList)))
670 Close(i);
671 }
672 return(Close(fd)); // close the master fd last
673}
674
675//
676// For clients this is used to give up ownership of a socket.
677// Often used so the destructor won't call close on a socket.
678//
680{
681 if (mode==CLIENT)
682 {
683 fd=-1;
684 connectionState=CLOSED;
685 }
686}
687
688// for a server 0 = master FD, or a client FD can be passed in
689// for a client the whichFD argument is ignored completely
691{
692 int i;
693 if (mode==CLIENT)
694 {
695 connectionState=CLOSED;
696 if(fd != -1)
697 {
698 sint32 retval = closesocket(fd);
699 fd = -1;
700 return retval;
701 }
702 }
703 else if (mode==SERVER)
704 {
705 if (whichFD==0)
706 {
707 if (shutdown(fd,2)==0)
708 return(closesocket(fd));
709 else
710 return(-1);
711 }
712 else if ((whichFD<=maxFD) && (FD_ISSET(whichFD,&clientList)))
713 {
714 if (whichFD==maxFD) // make sure maxFD is still correct
715 {
716 for (i=maxFD; i>=0; i--)
717 if (FD_ISSET(i,&clientList))
718 {
719 maxFD=i;
720 break;
721 }
722 }
723 FD_CLR((uint32)whichFD,&clientList);
724 clientCount--;
725 return(closesocket(whichFD));
726 }
727 }
728 return(-1);
729}
730
731
732
733// if 'sec' AND 'usec' are -1 then this will sleep until
734// there is socket activity
735
736int TCP::Wait(sint32 sec,sint32 usec,fd_set &returnSet,sint32 whichFD)
737{
738 fd_set inputSet;
739
740 FD_ZERO(&inputSet);
741
742 if (mode==SERVER)
743 {
744 if (whichFD==0)
745 {
746 inputSet=clientList;
747 if (fd > 0)
748 FD_SET(fd,&inputSet);
749 }
750 else if (whichFD > 0)
751 FD_SET(whichFD,&inputSet);
752 }
753 else if (mode==CLIENT)
754 {
755 if (whichFD==0)
756 whichFD=fd;
757 if (whichFD > 0)
758 FD_SET(whichFD,&inputSet);
759 }
760
761 return(Wait(sec,usec,inputSet,returnSet));
762}
763
764int TCP::Wait(sint32 sec,sint32 usec,fd_set &givenSet,fd_set &returnSet)
765{
766 Wtime timeout;
767 Wtime timenow;
768 Wtime timethen;
769 fd_set backupSet;
770 int retval=0,done,givenMax;
771 bit8 noTimeout=FALSE;
772 timeval tv;
773
774 returnSet=givenSet;
775 backupSet=returnSet;
776
777 if ((sec==-1)&&(usec==-1))
778 noTimeout=TRUE;
779
780 timeout.SetSec(sec);
781 timeout.SetUsec(usec);
782 timethen+=timeout;
783
784 givenMax=maxFD;
785 for (uint32 i=0; i<(sizeof(fd_set)*8); i++) // i=maxFD+1
786 {
787 if (FD_ISSET(i,&givenSet))
788 givenMax=i;
789 }
790
791 done=0;
792 while( ! done)
793 {
794 if (noTimeout)
795 retval=select(givenMax+1,&returnSet,0,0,NULL);
796 else
797 {
798 timeout.GetTimevalMT(tv);
799 retval=select(givenMax+1,&returnSet,0,0,&tv);
800 }
801
802 if (retval>=0)
803 done=1;
804
805 else if ((retval==-1)&&(errno==EINTR)) // in case of signal
806 {
807 if (noTimeout==FALSE)
808 {
809 timenow.Update();
810 timeout=timethen-timenow;
811 }
812 if ((noTimeout==FALSE)&&(timenow.GetSec()==0)&&(timenow.GetUsec()==0))
813 done=1;
814 else
815 returnSet=backupSet;
816 }
817 else // maybe out of memory?
818 {
819 done=1;
820 }
821 }
822 return(retval);
823}
824
825
827{
828 fd_set backupSet;
829 int retval=0,done;
830 fd_set outputSet;
831
832 if (whichFD==0)
833 whichFD=fd;
834
835 if (whichFD==-1)
836 return;
837
838 FD_ZERO(&outputSet);
839 FD_SET(whichFD,&outputSet);
840 backupSet=outputSet;
841
842 done=0;
843 while( ! done)
844 {
845 retval=select(maxFD+1,0,&outputSet,0,NULL);
846
847 if (retval>=0)
848 done=1;
849
850 else if ((retval==-1)&&(errno==EINTR)) // in case of signal
851 outputSet=backupSet;
852 else // maybe out of memory?
853 done=1;
854 }
855}
856
857// Can a FD be written to?
859{
860 int retval=0;
861 fd_set outputSet;
862 Wtime timeout;
863 timeval tv;
864
865 timeout.SetSec(0);
866 timeout.SetUsec(0);
867
868 if (whichFD==0)
869 whichFD=fd;
870
871 FD_ZERO(&outputSet);
872 FD_SET(whichFD,&outputSet);
873
874 timeout.GetTimevalMT(tv);
875 retval=select(whichFD+1,0,&outputSet,0,&tv);
876 if (retval>0)
877 return(TRUE);
878 else
879 return(FALSE);
880}
881
882
883bit8 TCP::Bind(char *Host,uint16 port,bit8 reuseAddr)
884{
885 char hostName[100];
886 struct hostent *hostStruct;
887 struct in_addr *hostNode;
888
889 if (isdigit(Host[0]))
890 return ( Bind( ntohl(inet_addr(Host)), port,reuseAddr) );
891
892 strcpy(hostName, Host);
893
894 hostStruct = gethostbyname(Host);
895 if (hostStruct == NULL)
896 return (0);
897 hostNode = (struct in_addr *) hostStruct->h_addr;
898 return ( Bind(ntohl(hostNode->s_addr),port,reuseAddr) );
899}
900
901
902// You must call bind, implicit binding is for sissies
903// Well... you can get implicit binding if you pass 0 for either arg
904
905bit8 TCP::Bind(uint32 IP,uint16 Port,bit8 reuseAddr)
906{
907 int retval;
908 int status;
909
910 IP=htonl(IP);
911 Port=htons(Port);
912
913 addr.sin_family=AF_INET;
914 addr.sin_port=Port;
915 addr.sin_addr.s_addr=IP;
916 fd=socket(AF_INET,SOCK_STREAM,DEFAULT_PROTOCOL);
917 if (fd==-1)
918 return(FALSE);
919
920 retval=SetBlocking(FALSE,fd);
921 if (retval==-1)
922 ERRMSG("Couldn't set nonblocking mode!");
923
924 if (reuseAddr==TRUE)
925 {
926 uint32 opval;
927
928 #ifdef SO_REUSEPORT
929/****************** this may make the socket get garbage data??
930 opval=1;
931 retval=setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&opval,sizeof(opval));
932 if (retval!=0)
933 fprintf(stderr,"Could not set socket to SO_REUSEPORT\n");
934**********************/
935 #endif
936 #ifdef SO_REUSEADDR
937 opval=1;
938 retval=setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&opval,sizeof(opval));
939 if (retval!=0)
940 fprintf(stderr,"Could not set socket to SO_REUSEADDR\n");
941 #endif
942 }
943
944 retval=bind(fd,(struct sockaddr *)&addr,sizeof(addr));
945 #ifdef _WINDOWS
946 if (retval==SOCKET_ERROR)
947 retval=-1;
948 #endif
949
950 if (retval==-1)
951 {
952 status=GetStatus();
953 DBGMSG("Bind failure (" << status << ") IP "<< IP <<" PORT "<< ntohs(Port));
954 return(FALSE);
955 }
956 myIP=IP;
957 myPort=Port;
958 maxFD=fd;
959
960 if (mode==SERVER)
961 listen(fd,64); //Solaris needs lots of listen slots for some reason
962
963 return(TRUE);
964}
965
966
967// This is only for clients
968
969bit8 TCP::Connect(char *Host,uint16 port)
970{
971 char hostName[100];
972 struct hostent *hostStruct;
973 struct in_addr *hostNode;
974
975 if (isdigit(Host[0]))
976 return ( Connect( ntohl(inet_addr(Host)), port) );
977
978 strcpy(hostName, Host);
979
980 hostStruct = gethostbyname(Host);
981 if (hostStruct == NULL)
982 {ERRMSG("Can't resolve host");return (0);}
983 hostNode = (struct in_addr *) hostStruct->h_addr;
984 return ( Connect(ntohl(hostNode->s_addr),port) );
985}
986
988{
989 int tries,result;
990 struct timeval sleep_time;
991 struct sockaddr_in serverAddr;
992 int status;
993
994 IP=htonl(IP);
995 Port=htons(Port);
996
997 serverAddr.sin_family=AF_INET;
998 serverAddr.sin_port=Port;
999 serverAddr.sin_addr.s_addr=IP;
1000
1001 if (mode!=CLIENT)
1002 {ERRMSG("Can't connect in server mode");return(FALSE);}
1003
1004 tries=0;
1005 result=-1;
1006
1007
1008 // try 10 connects with a greater and greater sleep time after each one
1009 // this can go on for upto 5.4 seconds
1010 while ((tries < 10) && (result == -1))
1011 {
1012 ClearStatus();
1013 result = connect(fd,(struct sockaddr *)&serverAddr, sizeof(serverAddr));
1014 status=GetStatus();
1015
1016 #ifdef _WINDOWS
1017 if (result==SOCKET_ERROR)
1018 result=-1;
1019 #endif
1020
1021 if ((status == ISCONN) && (result == -1))
1022 {
1023 result = 0;
1024 }
1025 if (result == -1)
1026 {
1027 if ((status!=INPROGRESS)&&(status!=ALREADY)&&(status!=AGAIN)&&
1028 (status!=WOULDBLOCK))
1029 {
1030 Close();
1031 Bind(myIP,myPort);
1032 }
1033 tries++;
1034 sleep_time.tv_sec = 0;
1035 sleep_time.tv_usec = (100000*(tries+1));
1036 #ifdef WIN32
1037 Sleep((sleep_time.tv_usec)/1000);
1038 #else
1039 select(0, 0, 0, 0, &sleep_time);
1040 #endif
1041 }
1042 }
1043
1044 if (result == -1)
1045 {
1046 return(FALSE);
1047 }
1048 connectionState=CONNECTED;
1049 return (TRUE);
1050}
1051
1052
1053
1054// Asynchronous Connection
1056{
1057 char hostName[100];
1058 struct hostent *hostStruct;
1059 struct in_addr *hostNode;
1060
1061 if (isdigit(Host[0]))
1062 return ( ConnectAsync( ntohl(inet_addr(Host)), port) );
1063
1064 strcpy(hostName, Host);
1065
1066 hostStruct = gethostbyname(Host);
1067 if (hostStruct == NULL)
1068 return (0);
1069 hostNode = (struct in_addr *) hostStruct->h_addr;
1070 return ( ConnectAsync(ntohl(hostNode->s_addr),port) );
1071}
1072
1073// Asynchronous Connection
1075{
1076 int result;
1077 struct sockaddr_in serverAddr;
1078 int status,connectErrno;
1079 int retval;
1080
1081 IP=htonl(IP);
1082 Port=htons(Port);
1083
1084 serverAddr.sin_family=AF_INET;
1085 serverAddr.sin_port=Port;
1086 serverAddr.sin_addr.s_addr=IP;
1087
1088 if (mode!=CLIENT)
1089 return(FALSE);
1090
1091 result=-1;
1092
1093 if (connectionState==CONNECTING)
1094 {
1095 if (IsConnected(fd))
1096 {
1097 DBGMSG("CONNECTION COMPLETE at point 1");
1098 connectionState=CONNECTED;
1099 return(TRUE);
1100 }
1101 else
1102 return(TRUE); // Still trying
1103 }
1104
1105 ClearStatus();
1106 result = connect(fd,(struct sockaddr *)&serverAddr, sizeof(serverAddr));
1107 connectErrno=errno;
1108 status=GetStatus();
1109
1110 #ifdef _WINDOWS
1111 if (result==SOCKET_ERROR)
1112 {
1113 DBGMSG("Socket error 1 " << status);
1114 result=-1;
1115 }
1116 #endif
1117
1118 // If we have a bogus FD, try again after closing and re-binding
1119 if ((result==-1)&&((status==BADF)||(status==NOTSOCK)||(status==INVAL)))
1120 {
1121 Close();
1122 retval=Bind(myIP,myPort);
1123 DBGMSG("BIND = "<<retval);
1124 ClearStatus();
1125 result = connect(fd,(struct sockaddr *)&serverAddr, sizeof(serverAddr));
1126 status=GetStatus();
1127 #ifdef _WINDOWS
1128 if (result==SOCKET_ERROR)
1129 {
1130 DBGMSG("Socket error 2 " << status);
1131 result=-1;
1132 }
1133 #endif
1134 }
1135
1136 if (result==-1)
1137 {
1138 if ((status==ISCONN)||(status==INPROGRESS)||(status==ALREADY)||
1139 (status==WOULDBLOCK))
1140 {
1141 connectionState=CONNECTING;
1142 return(TRUE); // The socket's trying to connect
1143 }
1144 else // Must be a "real" problem
1145 {
1146 Close();
1147 DBGMSG("Fail " << connectErrno << " " << status);
1148 connectionState=CLOSED;
1149 return(FALSE);
1150 }
1151 }
1152 //printf("Connected for real\n");
1153 connectionState=CONNECTED;
1154 return(TRUE);
1155}
1156
1157
1158
1159
1161{
1162 #ifndef _WINDOWS
1163 errno=0;
1164 #endif
1165}
1166
1168{
1169 #ifdef _WINDOWS
1170 int status=WSAGetLastError();
1171 if (status==0) return(OK);
1172 else if (status==WSAEINTR) return(INTR);
1173 else if (status==WSAEINPROGRESS) return(INPROGRESS);
1174 else if (status==WSAECONNREFUSED) return(CONNREFUSED);
1175 else if (status==WSAEINVAL) return(INVAL);
1176 else if (status==WSAEISCONN) return(ISCONN);
1177 else if (status==WSAENOTSOCK) return(NOTSOCK);
1178 else if (status==WSAETIMEDOUT) return(TIMEDOUT);
1179 else if (status==WSAEALREADY) return(ALREADY);
1180 else if (status==WSAEWOULDBLOCK) return(WOULDBLOCK);
1181 else if (status==WSAEBADF) return(BADF);
1182 else return(UNKNOWN);
1183 #else
1184 int status=errno;
1185 if (status==0) return(OK);
1186 else if (status==EINTR) return(INTR);
1187 else if (status==EINPROGRESS) return(INPROGRESS);
1188 else if (status==ECONNREFUSED) return(CONNREFUSED);
1189 else if (status==EINVAL) return(INVAL);
1190 else if (status==EISCONN) return(ISCONN);
1191 else if (status==ENOTSOCK) return(NOTSOCK);
1192 else if (status==ETIMEDOUT) return(TIMEDOUT);
1193 else if (status==EALREADY) return(ALREADY);
1194 else if (status==EAGAIN) return(AGAIN);
1195 else if (status==EWOULDBLOCK) return(WOULDBLOCK);
1196 else if (status==EBADF) return(BADF);
1197 else return(UNKNOWN);
1198 #endif
1199}
1200
1201
1202// this is only for servers
1203
1205{
1206 if (mode!=SERVER)
1207 return(-1);
1208
1209 sint32 clientFD;
1210 struct sockaddr_in clientAddr;
1211 int addrlen=sizeof(clientAddr);
1212
1213 clientFD=accept(fd,(struct sockaddr *)&clientAddr,&addrlen);
1214 if (clientFD!=-1)
1215 {
1216 if (clientFD>maxFD)
1217 maxFD=clientFD;
1218 FD_SET(clientFD,&clientList);
1219 clientCount++;
1220 }
1221 return(clientFD);
1222}
1223
1224sint32 TCP::GetConnection(struct sockaddr *clientAddr)
1225{
1226 if (mode!=SERVER)
1227 return(-1);
1228
1229 sint32 clientFD;
1230 int addrlen=sizeof(struct sockaddr);
1231
1232 clientFD=accept(fd,(struct sockaddr *)clientAddr,&addrlen);
1233 if (clientFD!=-1)
1234 {
1235 if (clientFD>maxFD)
1236 maxFD=clientFD;
1237 FD_SET(clientFD,&clientList);
1238 clientCount++;
1239 }
1240 return(clientFD);
1241}
1242
#define NULL
Definition BaseType.h:92
#define TRUE
Definition BaseType.h:109
#define FALSE
Definition BaseType.h:113
#define ERRMSG(X)
Definition wdebug.h:86
#define DBGMSG(X)
Definition wdebug.h:128
char bit8
Definition wstypes.h:61
unsigned short uint16
Definition bittype.h:45
unsigned long uint32
Definition bittype.h:46
signed short sint16
Definition bittype.h:50
signed long sint32
Definition bittype.h:51
unsigned char uint8
Definition bittype.h:44
sint32 TimedRead(uint8 *msg, uint32 len, int seconds, sint32 whichFD=0)
Definition tcp.cpp:548
bit8 ConnectAsync(uint32 IP, uint16 port)
Definition tcp.cpp:1074
int Wait(sint32 sec, sint32 usec, fd_set &returnSet, sint32 whichFD=0)
Definition tcp.cpp:736
TCP(int newMode)
Definition tcp.cpp:108
sint32 SetBlocking(bit8 block, sint32 whichFD=0)
Definition tcp.cpp:168
fd_set clientList
Definition tcp.h:128
sint32 GetMaxFD(void)
Definition tcp.cpp:199
void DisownSocket(void)
Definition tcp.cpp:679
sint32 Close(sint32 whichFD=0)
Definition tcp.cpp:690
bit8 CanWrite(sint32 whichFD=0)
Definition tcp.cpp:858
bit8 Connect(uint32 IP, uint16 port)
Definition tcp.cpp:987
sint32 GetConnection(void)
Definition tcp.cpp:1204
uint16 GetRemotePort(sint32 whichFD=0)
Definition tcp.cpp:399
sint32 Peek(uint8 *msg, uint32 len, sint32 whichFD=0)
Definition tcp.cpp:576
sint32 EncapsulatedRead(uint8 *msg, uint32 len, sint32 whichFD=0)
Definition tcp.cpp:605
sint32 EncapsulatedWrite(uint8 *msg, uint32 len, sint32 whichFD=0)
Definition tcp.cpp:257
sint32 WriteNB(uint8 *msg, uint32 len, sint32 whichFD=0)
Definition tcp.cpp:233
uint32 GetRemoteIP(sint32 whichFD=0)
Definition tcp.cpp:378
sint32 WriteString(char *msg, sint32 whichFD=0)
Definition tcp.cpp:310
sint32 Write(const uint8 *msg, uint32 len, sint32 whichFD=0)
Definition tcp.cpp:210
int GetStatus(void)
Definition tcp.cpp:1167
sint32 CloseAll(void)
Definition tcp.cpp:660
bit8 IsConnected(sint32 whichFD=0)
Definition tcp.cpp:419
void ClearStatus(void)
Definition tcp.cpp:1160
sint32 Printf(sint32 whichFD, const char *format,...)
Definition tcp.cpp:341
sint32 Read(uint8 *msg, uint32 len, sint32 whichFD=0)
Definition tcp.cpp:512
~TCP()
Definition tcp.cpp:155
void WaitWrite(sint32 whichFD=0)
Definition tcp.cpp:826
@ SERVER
Definition tcp.h:100
@ CLIENT
Definition tcp.h:99
@ AGAIN
Definition tcp.h:114
@ OK
Definition tcp.h:107
@ INPROGRESS
Definition tcp.h:110
@ CONNREFUSED
Definition tcp.h:118
@ INTR
Definition tcp.h:119
@ INVAL
Definition tcp.h:123
@ NOTSOCK
Definition tcp.h:120
@ UNKNOWN
Definition tcp.h:108
@ BADF
Definition tcp.h:117
@ ISCONN
Definition tcp.h:109
@ TIMEDOUT
Definition tcp.h:124
@ WOULDBLOCK
Definition tcp.h:122
@ ALREADY
Definition tcp.h:112
bit8 Bind(uint32 IP, uint16 port, bit8 reuseAddr=FALSE)
Definition tcp.cpp:905
sint32 GetFD(void)
Definition tcp.cpp:161
char * Gets(char *string, int n, int whichFD=0)
Definition tcp.cpp:465
Definition wtime.h:47
void Update()
Definition wtime.cpp:82
void SetSec(uint32 newsec)
Definition wtime.cpp:424
uint32 GetSec(void) const
Definition wtime.cpp:414
void SetUsec(uint32 newusec)
Definition wtime.cpp:429
void GetTimevalMT(struct timeval &tv)
Definition wtime.cpp:450
uint32 GetUsec(void) const
Definition wtime.cpp:419
#define closesocket
Definition tcp.cpp:104
#define DEFAULT_PROTOCOL
Definition tcp.h:62
MSG msg
Definition patch.cpp:409
unsigned char flag
Definition vchannel.cpp:273
long time_t
Definition wolapi.h:436