1 /* bzflag
2  * Copyright (c) 1993-2021 Tim Riker
3  *
4  * This package is free software;  you can redistribute it and/or
5  * modify it under the terms of the license found in the file
6  * named COPYING that should have accompanied this file.
7  *
8  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11  */
12 
13 // interface header
14 #include "ServerLink.h"
15 // #include "MsgStrings.h"
16 
17 #if defined(DEBUG)
18 #define NETWORK_STATS
19 #endif
20 
21 // system headers
22 #include <string.h>
23 #include <sys/types.h>
24 #include <ctype.h>
25 #include <time.h>
26 #include <vector>
27 #if !defined(_WIN32)
28 #include <unistd.h>
29 #include <errno.h>
30 #endif
31 #include <stdio.h>
32 #include <stdlib.h>
33 
34 // common implementation headers
35 #include "ErrorHandler.h"
36 // invoke persistent rebuilding for current version dates
37 #include "version.h"
38 #if defined(NETWORK_STATS)
39 #include "bzfio.h"
40 #endif
41 #include "TimeKeeper.h"
42 
43 #define UDEBUG if (UDEBUGMSG) printf
44 #define UDEBUGMSG false
45 
46 #if defined(NETWORK_STATS)
47 static TimeKeeper   startTime;
48 static uint32_t     bytesSent;
49 static uint32_t     bytesReceived;
50 static uint32_t     packetsSent;
51 static uint32_t     packetsReceived;
52 #endif
53 
54 #if defined(_WIN32)
55 DWORD ThreadID;     // Thread ID
56 HANDLE hConnected;  // "Connected" event
57 HANDLE hThread;     // Connection thread
58 
59 typedef struct
60 {
61     int query;
62     CNCTType* addr;
63     int saddr;
64 } TConnect;
65 
66 TConnect conn;
67 
ThreadConnect(LPVOID params)68 DWORD WINAPI ThreadConnect(LPVOID params)
69 {
70     TConnect *conn = (TConnect*)params;
71     if (connect(conn->query, conn->addr, conn->saddr) >= 0)
72     {
73         SetEvent(hConnected); // Connect successful
74     }
75     ExitThread(0);
76     return 0;
77 }
78 
79 #endif // !defined(_WIN32)
80 
81 // FIXME -- packet recording
82 FILE* packetStream = NULL;
83 TimeKeeper packetStartTime;
84 static const unsigned long serverPacket = 1;
85 static const unsigned long endPacket = 0;
86 
87 ServerLink*     ServerLink::server = NULL;
88 
ServerLink(const Address & serverAddress,int port)89 ServerLink::ServerLink(const Address& serverAddress, int port) :
90     state(SocketError), // assume failure
91     fd(-1),         // assume failure
92     udpLength(0),
93     udpBufferPtr(),
94     ubuf()
95 {
96     int i;
97 
98     struct protoent* p;
99 #if defined(_WIN32)
100     BOOL off = FALSE;
101 #else
102     int off = 0;
103 #endif
104 
105     // standard server has no special abilities;
106     server_abilities = Nothing;
107 
108     // queue is empty
109 
110     urecvfd = -1;
111 
112     ulinkup = false;
113 
114     // initialize version to a bogus number
115     strcpy(version, "BZFS0000");
116 
117     // open connection to server.  first connect to given port.
118     // don't wait too long.
119     int query = socket(AF_INET, SOCK_STREAM, 0);
120     if (query < 0) return;
121 
122     struct sockaddr_in addr;
123     addr.sin_family = AF_INET;
124     addr.sin_port = htons(port);
125     addr.sin_addr = serverAddress;
126 
127     UDEBUG("Remote %s\n", inet_ntoa(addr.sin_addr));
128 
129     // for UDP, used later
130     memcpy((unsigned char *)&usendaddr,(unsigned char *)&addr, sizeof(addr));
131 
132     bool okay = true;
133     int fdMax = query;
134     struct timeval timeout;
135     fd_set write_set;
136     fd_set read_set;
137     int nfound;
138 
139 #if !defined(_WIN32)
140     okay = true;
141     fdMax = query;
142     if (BzfNetwork::setNonBlocking(query) < 0)
143     {
144         close(query);
145         return;
146     }
147     if (connect(query, (CNCTType*)&addr, sizeof(addr)) < 0)
148     {
149         if (getErrno() != EINPROGRESS)
150         {
151             close(query);
152             return;
153         }
154         FD_ZERO(&write_set);
155         FD_SET((unsigned int)query, &write_set);
156         timeout.tv_sec = long(5);
157         timeout.tv_usec = 0;
158         nfound = select(fdMax + 1, NULL, (fd_set*)&write_set, NULL, &timeout);
159         if (nfound <= 0)
160         {
161             close(query);
162             return;
163         }
164         int       connectError;
165         socklen_t errorLen = sizeof(int);
166         if (getsockopt(query, SOL_SOCKET, SO_ERROR, &connectError, &errorLen)
167                 < 0)
168         {
169             close(query);
170             return;
171         }
172         if (connectError != 0)
173         {
174             close(query);
175             return;
176         }
177     }
178 #else // Connection timeout for Windows
179 
180     // Initialize structure
181     conn.query = query;
182     conn.addr = (CNCTType*)&addr;
183     conn.saddr = sizeof(addr);
184 
185     // Create event
186     hConnected = CreateEvent(NULL, FALSE, FALSE, "Connected Event");
187 
188     hThread = CreateThread(NULL, 0, ThreadConnect, &conn, 0, &ThreadID);
189     okay = (WaitForSingleObject(hConnected, 5000) == WAIT_OBJECT_0);
190     if (!okay)
191         TerminateThread(hThread, 1);
192 
193     // Do some cleanup
194     CloseHandle(hConnected);
195     CloseHandle(hThread);
196 
197 #endif // !defined(_WIN32)
198     if (!okay)
199     {
200         close(query);
201         return;
202     }
203 
204     // send out the connect header
205     // this will let the server know we are BZFS protocol.
206     // after the server gets this it will send back a version for us to check
207     int sendRepply = ::send(query,BZ_CONNECT_HEADER,(int)strlen(BZ_CONNECT_HEADER),0);
208 
209     logDebugMessage(2,"CONNECT:send in connect returned %d\n",sendRepply);
210 
211     // wait to get data back. we are still blocking so these
212     // calls should be sync.
213 
214     FD_ZERO(&read_set);
215     FD_ZERO(&write_set);
216     FD_SET((unsigned int)query, &read_set);
217     FD_SET((unsigned int)query, &write_set);
218 
219     timeout.tv_sec = long(10);
220     timeout.tv_usec = 0;
221 
222     // pick some limit to time out on ( in seconds )
223     double thisStartTime = TimeKeeper::getCurrent().getSeconds();
224     double connectTimeout = 30.0;
225     if (BZDB.isSet("connectionTimeout"))
226         connectTimeout = BZDB.eval("connectionTimeout")  ;
227 
228     bool gotNetData = false;
229 
230     // loop calling select untill we read some data back.
231     // its only 8 bytes so it better come back in one packet.
232     int loopCount = 0;
233     while (!gotNetData)
234     {
235         loopCount++;
236         nfound = select(fdMax + 1, (fd_set*)&read_set, (fd_set*)&write_set, NULL, &timeout);
237 
238         // there has to be at least one socket active, or we are screwed
239         if (nfound <= 0)
240         {
241             logDebugMessage(1,"CONNECT:select in connect failed, nfound = %d\n",nfound);
242             close(query);
243             return;
244         }
245 
246         // try and get data back from the server
247         i = recv(query, (char*)version, 8, 0);
248 
249         // if we got some, then we are done
250         if (i > 0)
251         {
252             logDebugMessage(2,"CONNECT:got net data in connect, bytes read = %d\n",i);
253             logDebugMessage(2,"CONNECT:Time To Connect = %f\n",(TimeKeeper::getCurrent().getSeconds() - thisStartTime));
254             gotNetData = true;
255         }
256         else
257         {
258             // if we have waited too long, then bail
259             if ((TimeKeeper::getCurrent().getSeconds() - thisStartTime) > connectTimeout)
260             {
261                 logDebugMessage(1,"CONNECT:connect time out failed\n");
262                 logDebugMessage(2,"CONNECT:connect loop count = %d\n",loopCount);
263                 close(query);
264                 return;
265             }
266 
267             TimeKeeper::sleep(0.25f);
268         }
269     }
270 
271     logDebugMessage(2,"CONNECT:connect loop count = %d\n",loopCount);
272 
273     // if we got back less than the expected connect response (BZFSXXXX)
274     // then something went bad, and we are done.
275     if (i < 8)
276     {
277         close(query);
278         return;
279     }
280 
281     // since we are connected, we can go non blocking
282     // on BSD sockets systems
283     // all other messages after this are handled via the normal
284     // message system
285 #if !defined(_WIN32)
286     if (BzfNetwork::setNonBlocking(query) < 0)
287     {
288         close(query);
289         return;
290     }
291 #endif
292 
293     // FIXME is it ok to try UDP always?
294     server_abilities |= CanDoUDP;
295     if (strcmp(version, getServerVersion()) != 0)
296     {
297         state = BadVersion;
298 
299         if (strcmp(version, BanRefusalString) == 0)
300         {
301             state = Refused;
302             char message[512];
303             int len = recv(query, (char*)message, 512, 0);
304             if (len > 0)
305                 message[len - 1] = 0;
306             else
307                 message[0] = 0;
308             rejectionMessage = message;
309         }
310 
311         close(query);
312         return;
313     }
314 
315     // read local player's id
316 #if !defined(_WIN32)
317     FD_ZERO(&read_set);
318     FD_SET((unsigned int)query, &read_set);
319     timeout.tv_sec = long(5);
320     timeout.tv_usec = 0;
321     nfound = select(fdMax + 1, (fd_set*)&read_set, NULL, NULL, &timeout);
322     if (nfound <= 0)
323     {
324         close(query);
325         return;
326     }
327 #endif // !defined(_WIN32)
328     i = recv(query, (char *) &id, sizeof(id), 0);
329     if (i < (int) sizeof(id))
330         return;
331     if (id == 0xff)
332     {
333         state = Rejected;
334         close(query);
335         return;
336     }
337 
338 #if !defined(_WIN32)
339     if (BzfNetwork::setBlocking(query) < 0)
340     {
341         close(query);
342         return;
343     }
344 #endif // !defined(_WIN32)
345 
346     fd = query;
347 
348     // turn on TCP no delay
349     p = getprotobyname("tcp");
350     if (p)
351         setsockopt(fd, p->p_proto, TCP_NODELAY, (SSOType)&off, sizeof(off));  // changed
352 
353     state = Okay;
354 #if defined(NETWORK_STATS)
355     bytesSent = 0;
356     bytesReceived = 0;
357     packetsSent = 0;
358     packetsReceived = 0;
359 #endif
360 
361     // FIXME -- packet recording
362     if (getenv("BZFLAGSAVE"))
363     {
364         packetStream = fopen(getenv("BZFLAGSAVE"), "w");
365         packetStartTime = TimeKeeper::getCurrent();
366     }
367     return;
368 
369 }
370 
~ServerLink()371 ServerLink::~ServerLink()
372 {
373     if (state != Okay) return;
374     shutdown(fd, 2);
375     close(fd);
376 
377     if (urecvfd >= 0)
378         close(urecvfd);
379 
380     urecvfd = -1;
381     ulinkup = false;
382 
383     // FIXME -- packet recording
384     if (packetStream)
385     {
386         long dt = (long)((TimeKeeper::getCurrent() - packetStartTime) * 10000.0f);
387         size_t items_written = fwrite(&endPacket, sizeof(endPacket), 1, packetStream);
388         if (items_written == 1)
389             items_written = fwrite(&dt, sizeof(dt), 1, packetStream);
390         if (items_written != 1)
391             printError("Error writing on packetStream");
392         fclose(packetStream);
393     }
394 
395 #if defined(NETWORK_STATS)
396     const float dt = float(TimeKeeper::getCurrent() - startTime);
397     logDebugMessage(1,"Server network statistics:\n");
398     logDebugMessage(1,"  elapsed time    : %f\n", dt);
399     logDebugMessage(1,"  bytes sent      : %d (%f/sec)\n", bytesSent, (float)bytesSent / dt);
400     logDebugMessage(1,"  packets sent    : %d (%f/sec)\n", packetsSent, (float)packetsSent / dt);
401     if (packetsSent != 0)
402         logDebugMessage(1,"  bytes/packet    : %f\n", (float)bytesSent / (float)packetsSent);
403     logDebugMessage(1,"  bytes recieved  : %d (%f/sec)\n", bytesReceived, (float)bytesReceived / dt);
404     logDebugMessage(1,"  packets received: %d (%f/sec)\n", packetsReceived, (float)packetsReceived / dt);
405     if (packetsReceived != 0)
406         logDebugMessage(1,"  bytes/packet    : %f\n", (float)bytesReceived / (float)packetsReceived);
407 #endif
408 }
409 
getServer()410 ServerLink*     ServerLink::getServer() // const
411 {
412     return server;
413 }
414 
setServer(ServerLink * _server)415 void            ServerLink::setServer(ServerLink* _server)
416 {
417     server = _server;
418 }
419 
send(uint16_t code,uint16_t len,const void * msg)420 void            ServerLink::send(uint16_t code, uint16_t len,
421                                  const void* msg)
422 {
423     bool needForSpeed=false;
424     if (state != Okay) return;
425 //  if (code != MsgPlayerUpdateSmall && code != MsgPlayerUpdate)
426 //    logDebugMessage(1,"send %s len %d\n",MsgStrings::strMsgCode(code),len);
427     char msgbuf[MaxPacketLen];
428     void* buf = msgbuf;
429     buf = nboPackUShort(buf, len);
430     buf = nboPackUShort(buf, code);
431     if (msg && len != 0) buf = nboPackString(buf, msg, len);
432 
433     if ((urecvfd>=0) && ulinkup )
434     {
435         switch (code)
436         {
437         case MsgShotBegin:
438         case MsgShotEnd:
439         case MsgPlayerUpdate:
440         case MsgPlayerUpdateSmall:
441         case MsgGMUpdate:
442         case MsgUDPLinkRequest:
443         case MsgUDPLinkEstablished:
444             needForSpeed=true;
445             break;
446         }
447     }
448     // MsgUDPLinkRequest always goes udp
449     if (code == MsgUDPLinkRequest)
450         needForSpeed=true;
451 
452     if (needForSpeed)
453     {
454 #ifdef TESTLINK
455         if ((random()%TESTQUALTIY) != 0)
456 #endif
457             sendto(urecvfd, (const char *)msgbuf, (char*)buf - msgbuf, 0, &usendaddr, sizeof(usendaddr));
458         // we don't care about errors yet
459         return;
460     }
461 
462     int r = ::send(fd, (const char*)msgbuf, len + 4, 0);
463     (void)r; // silence g++
464 #if defined(_WIN32)
465     if (r == SOCKET_ERROR)
466     {
467         const int e = WSAGetLastError();
468         if (e == WSAENETRESET || e == WSAECONNABORTED ||
469                 e == WSAECONNRESET || e == WSAETIMEDOUT)
470             state = Hungup;
471         r = 0;
472     }
473 #endif
474 
475 #if defined(NETWORK_STATS)
476     bytesSent += r;
477     packetsSent++;
478 #endif
479 }
480 
481 #ifdef WIN32
482 /* This is a really really fugly hack to get around winsock sillyness
483  * The newer versions of winsock have a socken_t typedef, and there
484  * doesn't seem to be any way to tell the versions apart. However,
485  * VC++ helps us out here by treating typedef as #define
486  * If we've got a socklen_t typedefed, define HAVE_SOCKLEN_T to
487  * avoid #define'ing it in common.h */
488 
489 #ifndef socklen_t
490 #define socklen_t int
491 #endif
492 #endif //WIN32
493 
read(uint16_t & code,uint16_t & len,void * msg,int blockTime)494 int         ServerLink::read(uint16_t& code, uint16_t& len,
495                              void* msg, int blockTime)
496 {
497 
498     code = MsgNull;
499     len = 0;
500 
501     if (state != Okay) return -1;
502 
503     if ((urecvfd >= 0) /* && ulinkup */)
504     {
505 
506         if (!udpLength)
507         {
508             AddrLen recvlen = sizeof(urecvaddr);
509             int n = recvfrom(urecvfd, ubuf, MaxPacketLen, 0,
510                              &urecvaddr, (socklen_t*) &recvlen);
511             if (n > 0)
512             {
513                 udpLength    = n;
514                 udpBufferPtr = ubuf;
515             }
516         }
517         if (udpLength)
518         {
519             // unpack header and get message
520             udpLength -= 4;
521             if (udpLength < 0)
522             {
523                 udpLength = 0;
524                 return -1;
525             }
526             udpBufferPtr = (const char *)nboUnpackUShort(udpBufferPtr, len);
527             udpBufferPtr = (const char *)nboUnpackUShort(udpBufferPtr, code);
528 //      if (code != MsgPlayerUpdateSmall && code != MsgPlayerUpdate && code != MsgGameTime)
529 //  logDebugMessage(1,"rcvd %s len %d\n",MsgStrings::strMsgCode(code),len);
530             UDEBUG("<** UDP Packet Code %x Len %x\n",code, len);
531             if (len > udpLength)
532             {
533                 udpLength = 0;
534                 return -1;
535             }
536             memcpy((char *)msg, udpBufferPtr, len);
537             udpBufferPtr += len;
538             udpLength    -= len;
539             return 1;
540         }
541         if (UDEBUGMSG) printError("Fallback to normal TCP receive");
542         len = 0;
543         code = MsgNull;
544 
545         blockTime = 0;
546     }
547 
548     // block for specified period.  default is no blocking (polling)
549     struct timeval timeout;
550     timeout.tv_sec = blockTime / 1000;
551     timeout.tv_usec = blockTime - 1000 * timeout.tv_sec;
552 
553     // only check server
554     fd_set read_set;
555     FD_ZERO(&read_set);
556     FD_SET((unsigned int)fd, &read_set);
557     int nfound = select(fd+1, (fd_set*)&read_set, NULL, NULL,
558                         (struct timeval*)(blockTime >= 0 ? &timeout : NULL));
559     if (nfound == 0) return 0;
560     if (nfound < 0) return -1;
561 
562     // printError("<** TCP Packet Code Received %d", time(0));
563     // FIXME -- don't really want to take the chance of waiting forever
564     // on the remaining select() calls, but if the server and network
565     // haven't been hosed then the data will get here soon.  And if the
566     // server or network is down then we don't really care anyway.
567 
568     // get packet header -- keep trying until we get 4 bytes or an error
569     char headerBuffer[4];
570 
571 
572     int rlen = 0;
573     rlen = recv(fd, (char*)headerBuffer, 4, 0);
574 
575     int tlen = rlen;
576     while (rlen >= 1 && tlen < 4)
577     {
578         printError("ServerLink::read() loop");
579         FD_ZERO(&read_set);
580         FD_SET((unsigned int)fd, &read_set);
581         nfound = select(fd+1, (fd_set*)&read_set, NULL, NULL, NULL);
582         if (nfound == 0) continue;
583         if (nfound < 0) return -1;
584         rlen = recv(fd, (char*)headerBuffer + tlen, 4 - tlen, 0);
585         if (rlen >= 0) tlen += rlen;
586     }
587     if (tlen < 4) return -1;
588 #if defined(NETWORK_STATS)
589     bytesReceived += 4;
590     packetsReceived++;
591 #endif
592 
593     // unpack header and get message
594     const void* buf = headerBuffer;
595     buf = nboUnpackUShort(buf, len);
596     buf = nboUnpackUShort(buf, code);
597 
598 //  logDebugMessage(1,"rcvd %s len %d\n",MsgStrings::strMsgCode(code),len);
599     if (len > MaxPacketLen - 4)
600         return -1;
601     if (len > 0)
602         rlen = recv(fd, (char*)msg, int(len), 0);
603     else
604         rlen = 0;
605 #if defined(NETWORK_STATS)
606     if (rlen >= 0) bytesReceived += rlen;
607 #endif
608     if (rlen != int(len))
609     {
610         // keep reading until we get the whole message
611         tlen = rlen;
612         while (rlen >= 1 && tlen < int(len))
613         {
614             FD_ZERO(&read_set);
615             FD_SET((unsigned int)fd, &read_set);
616             nfound = select(fd+1, (fd_set*)&read_set, 0, 0, NULL);
617             if (nfound == 0) continue;
618             if (nfound < 0) return -1;
619             rlen = recv(fd, (char*)msg + tlen, int(len) - tlen, 0);
620             if (rlen >= 0) tlen += rlen;
621 #if defined(NETWORK_STATS)
622             if (rlen >= 0) bytesReceived += rlen;
623 #endif
624         }
625         if (tlen < int(len)) return -1;
626     }
627 
628     // FIXME -- packet recording
629     if (packetStream)
630     {
631         long dt = (long)((TimeKeeper::getCurrent() - packetStartTime) * 10000.0f);
632         size_t items_written = fwrite(&serverPacket, sizeof(serverPacket), 1, packetStream);
633         if (items_written == 1)
634             items_written = fwrite(&dt, sizeof(dt), 1, packetStream);
635         if (items_written == 1)
636             items_written = fwrite(headerBuffer, 4, 1, packetStream);
637         if (items_written == 1)
638             items_written = fwrite(msg, len, 1, packetStream);
639         if (items_written != 1)
640             printError("Error writing on packetStream");
641     }
642     return 1;
643 }
644 
sendEnter(PlayerType type,TeamColor team,const char * name,const char * motto,const char * token)645 void            ServerLink::sendEnter(PlayerType type,
646                                       TeamColor team,
647                                       const char* name,
648                                       const char* motto,
649                                       const char* token)
650 {
651     if (state != Okay) return;
652     char msg[PlayerIdPLen + 4 + CallSignLen + MottoLen + TokenLen + VersionLen];
653     ::memset(msg, 0, sizeof(msg));
654     void* buf = msg;
655     buf = nboPackUShort(buf, uint16_t(type));
656     buf = nboPackUShort(buf, uint16_t(team));
657     ::memcpy(buf, name, ::strlen(name));
658     buf = (void*)((char*)buf + CallSignLen);
659     ::memcpy(buf, motto, ::strlen(motto));
660     buf = (void*)((char*)buf + MottoLen);
661     ::memcpy(buf, token, ::strlen(token));
662     buf = (void*)((char*)buf + TokenLen);
663     ::memcpy(buf, getAppVersion(), ::strlen(getAppVersion()) + 1);
664     buf = (void*)((char*)buf + VersionLen);
665     send(MsgEnter, sizeof(msg), msg);
666 }
667 
readEnter(std::string & reason,uint16_t & code,uint16_t & rejcode)668 bool ServerLink::readEnter(std::string& reason,
669                            uint16_t& code, uint16_t& rejcode)
670 {
671     // wait for response
672     uint16_t len;
673     char msg[MaxPacketLen];
674 
675     while (true)
676     {
677         if (this->read(code, len, msg, -1) < 0)
678         {
679             reason = "Communication error joining game [No immediate respose].";
680             return false;
681         }
682 
683         if (code == MsgAccept)
684             return true;
685         else if (code == MsgSuperKill)
686         {
687             reason = "Server forced disconnection.";
688             return false;
689         }
690         else if (code == MsgReject)
691         {
692             const void *buf;
693             char buffer[MessageLen];
694             buf = nboUnpackUShort (msg, rejcode); // filler for now
695             buf = nboUnpackString (buf, buffer, MessageLen);
696             buffer[MessageLen - 1] = '\0';
697             reason = buffer;
698             return false;
699         }
700         // ignore other codes so that bzadmin doesn't choke
701         // on the MsgMessage's that the server can send before
702         // the MsgAccept (authorization holdoff, etc...)
703     }
704 
705     return true;
706 }
707 
708 // Local Variables: ***
709 // mode: C++ ***
710 // tab-width: 4 ***
711 // c-basic-offset: 4 ***
712 // indent-tabs-mode: nil ***
713 // End: ***
714 // ex: shiftwidth=4 tabstop=4
715