1 /////////////////////////////////////////
2 //
3 // OpenLieroX
4 //
5 // code under LGPL, based on JasonBs work,
6 // enhanced by Dark Charlie and Albert Zeyer
7 //
8 //
9 /////////////////////////////////////////
10
11
12 // Common networking routines to help us
13 // Created 18/12/02
14 // Jason Boettcher
15
16 #include <memory.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <errno.h>
20
21 #include <curl/curl.h>
22
23 #include "ThreadPool.h"
24 #ifndef WIN32
25 #include <signal.h>
26 #endif
27
28 #include "LieroX.h"
29 #include "Debug.h"
30 #include "Options.h"
31 #include "Error.h"
32 #include "Networking.h"
33 #include "StringUtils.h"
34 #include "SmartPointer.h"
35 #include "Timer.h"
36 #include "ThreadVar.h"
37 #include "MathLib.h"
38 #include "InputEvents.h"
39 #include "TaskManager.h"
40 #include "ReadWriteLock.h"
41 #include "Mutex.h"
42
43
44 #ifdef _MSC_VER
45 #pragma warning(disable: 4786)
46 #endif
47
48 #include <map>
49
50 #include <nl.h>
51 #include <nlinternal.h>
52 // workaraound for bad named makros by nl.h
53 // macros are bad, esp the names (reserved/used by CBytestream)
54 // TODO: they seem to not work correctly!
55 // all use of it in CBytestream was removed
nl_writeShort(char * x,int & y,NLushort z)56 inline void nl_writeShort(char* x, int& y, NLushort z) { writeShort(x, y, z); }
nl_writeLong(char * x,int & y,NLulong z)57 inline void nl_writeLong(char* x, int& y, NLulong z) { writeLong(x, y, z); }
nl_writeFloat(char * x,int & y,NLfloat z)58 inline void nl_writeFloat(char* x, int& y, NLfloat z) { writeFloat(x, y, z); }
nl_writeDouble(char * x,int & y,NLdouble z)59 inline void nl_writeDouble(char* x, int& y, NLdouble z) { writeDouble(x, y, z); }
nl_readShort(char * x,int & y,NLushort z)60 inline void nl_readShort(char* x, int& y, NLushort z) { readShort(x, y, z); }
nl_readLong(char * x,int & y,NLulong z)61 inline void nl_readLong(char* x, int& y, NLulong z) { readLong(x, y, z); }
nl_readFloat(char * x,int & y,NLfloat z)62 inline void nl_readFloat(char* x, int& y, NLfloat z) { readFloat(x, y, z); }
nl_readDouble(char * x,int & y,NLdouble z)63 inline void nl_readDouble(char* x, int& y, NLdouble z) { readDouble(x, y, z); }
64 #undef writeByte
65 #undef writeShort
66 #undef writeFloat
67 #undef writeString
68 #undef readByte
69 #undef readShort
70 #undef readFloat
71 #undef readString
72
73
74 #if defined WIN32 || defined WIN64 || defined (_WIN32_WCE)
75
76 #include "wsock.h"
77
78 #elif defined Macintosh
79
80 #include <Types.h>
81 #include <stdio.h>
82 #include <fcntl.h>
83 #include <sys/ioctl.h>
84 #include <sys/types.h>
85 #include <sys/socket.h>
86 #include <string.h>
87 #include <sys/time.h>
88 #include <LowMem.h>
89 #define closesocket close
90 #define INVALID_SOCKET -1
91 #define SOCKET_ERROR -1
92 #define SOCKET int
93 #define sockerrno errno
94
95 /* define INADDR_NONE if not already */
96 #ifndef INADDR_NONE
97 #define INADDR_NONE ((unsigned long) -1)
98 #endif
99
100 #else
101
102 /* Unix-style systems */
103 #ifdef SOLARIS
104 #include <sys/filio.h> /* for FIONBIO */
105 #endif
106
107 #include <unistd.h>
108 #include <sys/types.h>
109 #include <sys/time.h>
110 #include <sys/socket.h>
111 #include <netinet/in.h>
112 #include <netinet/tcp.h>
113 #include <arpa/inet.h>
114 #include <netdb.h>
115 #include <sys/ioctl.h>
116 #define closesocket close
117 #define INVALID_SOCKET -1
118 #define SOCKET_ERROR -1
119 #define SOCKET int
120 #define sockerrno errno
121
122 /* define INADDR_NONE if not already */
123 #ifndef INADDR_NONE
124 #define INADDR_NONE ((unsigned long) -1)
125 #endif
126
127 /* SGI do not include socklen_t */
128 #if defined __sgi
129 typedef int socklen_t;
130 #endif
131
132 #endif /* WINDOWS_APP*/
133
134
135
136 class NetAddrIniter {
137 public:
operator ()(SmartPointer<NLaddress,NetAddrIniter> * addr)138 void operator()(SmartPointer<NLaddress, NetAddrIniter>* addr) {
139 NLaddress* addrPtr = new NLaddress;
140 memset(addrPtr, 0, sizeof(NLaddress));
141 *addr = addrPtr;
142 }
143 };
144
AreNetworkAddrEqual(const NetworkAddr & addr1,const NetworkAddr & addr2)145 bool AreNetworkAddrEqual(const NetworkAddr& addr1, const NetworkAddr& addr2)
146 {
147 return AreNetAddrEqual(addr1, addr2);
148 };
149
150 class NetAddrInternal
151 {
152 public:
NetAddrInternal()153 NetAddrInternal() {};
NetAddrInternal(const NetAddrInternal & other)154 NetAddrInternal(const NetAddrInternal & other)
155 {
156 *this = other;
157 };
158
operator =(const NetAddrInternal & other)159 const NetAddrInternal & operator= (const NetAddrInternal & other)
160 {
161 *NetAddrSmartPtr.get() = *other.NetAddrSmartPtr.get();
162 return *this;
163 }
164
operator =(const NLaddress & addr)165 const NetAddrInternal & operator= (const NLaddress & addr)
166 {
167 *NetAddrSmartPtr.get() = addr;
168 return *this;
169 }
170
NetAddrInternal(const NLaddress & addr)171 NetAddrInternal(const NLaddress & addr)
172 {
173 *this = addr;
174 };
175
176 typedef SmartPointer<NLaddress, NetAddrIniter> Ptr_t;
177
getPtr() const178 const Ptr_t & getPtr() const
179 {
180 return NetAddrSmartPtr;
181 }
182
183 private:
184 Ptr_t NetAddrSmartPtr;
185 };
186
187 DECLARE_INTERNDATA_CLASS( NetworkAddr, NetAddrInternal );
188
getNLaddr(NetworkAddr & addr)189 static NLaddress* getNLaddr(NetworkAddr& addr) {
190 return NetworkAddrData(addr).getPtr().get();
191 }
192
getNLaddr(const NetworkAddr & addr)193 static const NLaddress* getNLaddr(const NetworkAddr& addr) {
194 return NetworkAddrData(addr).getPtr().get();
195 }
196
197
198 // ------------------------------------------------------------------------
199
200
201 #ifndef WIN32
sigpipe_handler(int i)202 static void sigpipe_handler(int i) {
203 warnings << "got SIGPIPE, ignoring..." << endl;
204 signal(SIGPIPE, sigpipe_handler);
205 }
206 #endif
207
208
209 /*
210 *
211 * HawkNL Network wrapper
212 *
213 */
214
215
216 bool bNetworkInited = false;
217 ReadWriteLock nlSystemUseChangeLock;
218
219
220 typedef std::map<std::string, std::pair< NLaddress, AbsTime > > dnsCacheT; // Second parameter is expiration time of DNS record
221 ThreadVar<dnsCacheT>* dnsCache4 = NULL;
222 ThreadVar<dnsCacheT>* dnsCache6 = NULL;
223
AddToDnsCache4(const std::string & name,const NetworkAddr & addr,TimeDiff expireTime=TimeDiff (600.0f))224 static void AddToDnsCache4(const std::string& name, const NetworkAddr& addr, TimeDiff expireTime = TimeDiff(600.0f)) {
225 ScopedReadLock lock(nlSystemUseChangeLock);
226 if(dnsCache4 == NULL) return;
227 ThreadVar<dnsCacheT>::Writer dns( *dnsCache4 );
228 dns.get()[name] = std::make_pair( *getNLaddr(addr), GetTime() + expireTime );
229 }
230
AddToDnsCache6(const std::string & name,const NetworkAddr & addr,TimeDiff expireTime=TimeDiff (600.0f))231 static void AddToDnsCache6(const std::string& name, const NetworkAddr& addr, TimeDiff expireTime = TimeDiff(600.0f)) {
232 ScopedReadLock lock(nlSystemUseChangeLock);
233 if(dnsCache6 == NULL) return;
234 ThreadVar<dnsCacheT>::Writer dns6( *dnsCache6 );
235 dns6.get()[name] = std::make_pair( *getNLaddr(addr), GetTime() + expireTime );
236 }
237
GetFromDnsCache(const std::string & name,NetworkAddr & addr4,NetworkAddr & addr6)238 bool GetFromDnsCache(const std::string& name, NetworkAddr& addr4, NetworkAddr& addr6) {
239
240 getNLaddr(addr4)->valid = NL_FALSE;
241 getNLaddr(addr6)->valid = NL_FALSE;
242
243 if (IsNetAddrV6(name) && StringToNetAddr(name, addr6)) {
244 return true;
245 }
246 if (StringToNetAddr(name, addr4)) {
247 return true;
248 }
249
250 ScopedReadLock lock(nlSystemUseChangeLock);
251 if(dnsCache4 == NULL) return false;
252 if(dnsCache6 == NULL) return false;
253 bool v4 = false, v6 = false;
254 ThreadVar<dnsCacheT>::Writer dns( *dnsCache4 );
255 dnsCacheT::iterator it = dns.get().find(name);
256 if(it != dns.get().end()) {
257 if( it->second.second < tLX->currentTime )
258 {
259 dns.get().erase(it);
260 }
261 else
262 {
263 *getNLaddr(addr4) = it->second.first;
264 v4 = true;
265 }
266 }
267 ThreadVar<dnsCacheT>::Writer dns6( *dnsCache6 );
268 it = dns6.get().find(name);
269 if(it != dns6.get().end()) {
270 if( it->second.second < tLX->currentTime )
271 {
272 dns6.get().erase(it);
273 }
274 else
275 {
276 *getNLaddr(addr6) = it->second.first;
277 v6 = true;
278 }
279 }
280 return v4 && v6; // Cache needs both address families to be present to consider an entry valid
281 }
282
283
284
285 /////////////////////
286 // Initializes network
InitNetworkSystem()287 bool InitNetworkSystem() {
288 curl_global_init(CURL_GLOBAL_ALL);
289 nlSystemUseChangeLock.startWriteAccess();
290 bNetworkInited = false;
291
292 if(!nlInit()) {
293 SystemError("nlInit failed");
294 nlSystemUseChangeLock.endWriteAccess();
295 return false;
296 }
297
298 if(!nlSelectNetwork(NL_IP)) {
299 SystemError("could not select IP-based network");
300 nlSystemUseChangeLock.endWriteAccess();
301 return false;
302 }
303
304 bNetworkInited = true;
305
306 dnsCache4 = new ThreadVar<dnsCacheT>();
307 dnsCache6 = new ThreadVar<dnsCacheT>();
308
309 #if !defined(WIN32) && !defined(__ANDROID__)
310 //sigignore(SIGPIPE);
311 signal(SIGPIPE, sigpipe_handler);
312 #endif
313
314 nlSystemUseChangeLock.endWriteAccess();
315 return true;
316 }
317
318 //////////////////
319 // Shutdowns the network system
QuitNetworkSystem()320 bool QuitNetworkSystem() {
321 nlSystemUseChangeLock.startWriteAccess();
322 nlShutdown();
323 bNetworkInited = false;
324 delete dnsCache4; dnsCache4 = NULL;
325 delete dnsCache6; dnsCache6 = NULL;
326 nlSystemUseChangeLock.endWriteAccess();
327 curl_global_cleanup();
328 return true;
329 }
330
331
332 /*
333 Sadly, HawkNL lacks some support for specific things. For example we cannot get the real socket nr.
334
335 Atm., we are doing these:
336
337 nlUpdateState
338 nlPrepareClose
339
340 */
341
342 // ---------------------------------------------------
343 // ----------- for state checking -------------------
344
345 // WARNING: both these function assume that we selected the IP-network driver in HawkNL
346
347 // modified sock_Write of sock.c from HawkNL
348 // returns true if socket is connected and data could be send
nlUpdateState(NLsocket socket)349 static bool nlUpdateState(NLsocket socket)
350 {
351 if(nlIsValidSocket(socket) != NL_TRUE) return false;
352
353 struct Unlocker {
354 NLsocket socket;
355 ~Unlocker() {
356 nlUnlockSocket(socket, NL_BOTH);
357 }
358 Unlocker(NLsocket s) : socket(s) {}
359 };
360
361 if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
362 {
363 return false;
364 }
365
366 Unlocker unlocker(socket);
367
368 nl_socket_t *sock = nlSockets[socket];
369 NLint count = 0;
370
371 if((sock->type == NL_RELIABLE) || (sock->type == NL_RELIABLE_PACKETS)) /* TCP */
372 {
373 if(sock->connecting == NL_TRUE)
374 {
375 fd_set fdset;
376 struct timeval t = {0,0};
377 int serrval = -1;
378 socklen_t serrsize = (socklen_t)sizeof(serrval);
379
380
381 FD_ZERO(&fdset);
382 FD_SET((SOCKET)sock->realsocket, &fdset);
383 if(select(sock->realsocket + 1, NULL, &fdset, NULL, &t) == 1)
384 {
385 /* Check the socket status */
386 (void)getsockopt( sock->realsocket, SOL_SOCKET, SO_ERROR, (char *)&serrval, &serrsize );
387 if(serrval != 0)
388 {
389 if(serrval == ECONNREFUSED)
390 {
391 nlSetError(NL_CON_REFUSED);
392 }
393 else if(serrval == EINPROGRESS || serrval == EWOULDBLOCK)
394 {
395 nlSetError(NL_CON_PENDING);
396 }
397 return false;
398 }
399 /* the connect has completed */
400 sock->connected = NL_TRUE;
401 sock->connecting = NL_FALSE;
402 }
403 else
404 {
405 /* check for a failed connect */
406 FD_ZERO(&fdset);
407 FD_SET((SOCKET)sock->realsocket, &fdset);
408 if(select(sock->realsocket + 1, NULL, NULL, &fdset, &t) == 1)
409 {
410 nlSetError(NL_CON_REFUSED);
411 }
412 else
413 {
414 nlSetError(NL_CON_PENDING);
415 }
416 return false;
417 }
418 }
419 /* check for reliable packets */
420 if(sock->type == NL_RELIABLE_PACKETS)
421 {
422 return true;
423 }
424 return true;
425 }
426 else /* unconnected UDP */
427 {
428 /* check for a non-blocking connection pending */
429 if(sock->connecting == NL_TRUE)
430 {
431 nlSetError(NL_CON_PENDING);
432 return false;
433 }
434 /* check for a connection error */
435 if(sock->conerror == NL_TRUE)
436 {
437 nlSetError(NL_CON_REFUSED);
438 return false;
439 }
440 if(sock->type == NL_BROADCAST)
441 {
442 memcpy(&((struct sockaddr_in6 *)&sock->addressin)->sin6_addr, &in6addr_any, sizeof(in6addr_any));
443 }
444 if(sock->type == NL_UDP_MULTICAST)
445 {
446 return true;
447 }
448 else if(sock->connected == NL_TRUE)
449 {
450 return true;
451 }
452 else
453 {
454 return true;
455 }
456 }
457 if(count == SOCKET_ERROR)
458 {
459 return false;
460 }
461 return false;
462 }
463
464
nlPrepareClose(NLsocket socket)465 static void nlPrepareClose(NLsocket socket) {
466 if(nlIsValidSocket(socket) != NL_TRUE) return;
467
468 struct Unlocker {
469 NLsocket socket;
470 ~Unlocker() {
471 nlUnlockSocket(socket, NL_BOTH);
472 }
473 Unlocker(NLsocket s) : socket(s) {}
474 };
475
476 if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
477 {
478 return;
479 }
480
481 Unlocker unlocker(socket);
482
483 // code copied&modified from sock_Close
484 // The advantage we have here is that we don't lock the whole socket array.
485 // nlClose is doing this, so if we would hang in nlClose, we block the
486 // *whole* HawkNL system (or at least actions like opening new sockets etc.)!
487
488 nl_socket_t *sock = nlSockets[socket];
489
490 if(sock->type == NL_UDP_MULTICAST)
491 {
492 /* leave the multicast group */
493 }
494 if(sock->type == NL_RELIABLE_PACKETS)
495 {
496 /* check for unsent data */
497 if(sock->sendlen > 0)
498 {
499 int tries = 200;
500
501 /* 200 * 50 ms = up to a 10 second delay to allow data to be sent */
502 while(tries-- > 0 && sock->sendlen > 0)
503 {
504 SDL_Delay(50);
505 }
506 }
507
508 // oh just fuck it
509 sock->sendlen = 0;
510 }
511 if((sock->type == NL_RELIABLE_PACKETS || sock->type == NL_RELIABLE) && sock->listen == NL_FALSE)
512 {
513 struct linger l = {1, 10};
514
515 (void)setsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_LINGER, (const char *)&l, (int)sizeof(l));
516 }
517 (void)closesocket((SOCKET)sock->realsocket);
518 }
519
520
521
522
523
524 struct NetworkSocket::EventHandler {
525 struct SharedData {
526 Mutex mutex;
527 bool quitSignal;
528 NetworkSocket* sock;
529 NLint nlGroup;
530
SharedDataNetworkSocket::EventHandler::SharedData531 SharedData(NetworkSocket* _s) : quitSignal(false), sock(_s) {
532 nlGroup = nlGroupCreate();
533 addSocketToGroup();
534 }
535
536 void addSocketToGroup();
537
~SharedDataNetworkSocket::EventHandler::SharedData538 ~SharedData() { nlGroupDestroy(nlGroup); nlGroup = NL_INVALID; }
539 };
540 SmartPointer<SharedData> sharedData;
541
542 EventHandler(NetworkSocket* sock);
543
quitNetworkSocket::EventHandler544 void quit() {
545 if(sharedData.get()) {
546 Mutex::ScopedLock lock(sharedData->mutex);
547 sharedData->quitSignal = true;
548 sharedData->sock = NULL;
549 }
550 }
551
~EventHandlerNetworkSocket::EventHandler552 ~EventHandler() {
553 // just to be sure
554 quit();
555 sharedData = NULL;
556 }
557 };
558
559 struct NetworkSocket::InternSocket {
560 NLsocket sock;
561 SmartPointer<EventHandler> eventHandler;
562
InternSocketNetworkSocket::InternSocket563 InternSocket() : sock(NL_INVALID) {}
~InternSocketNetworkSocket::InternSocket564 ~InternSocket() {
565 // just a double check - there really shouldn't be a case where this could be true
566 if(eventHandler.get()) {
567 errors << "NetworkSocket::~InternSocket: event handler was not unset" << endl;
568 eventHandler->quit();
569 eventHandler = NULL;
570 }
571 }
572 };
573
addSocketToGroup()574 void NetworkSocket::EventHandler::SharedData::addSocketToGroup() {
575 nlGroupAddSocket(nlGroup, sock->m_socket->sock);
576 }
577
EventHandler(NetworkSocket * sock)578 NetworkSocket::EventHandler::EventHandler(NetworkSocket* sock) {
579 if(!sock) {
580 errors << "NetworkSocket::EventHandler: socket == NULL" << endl;
581 return;
582 }
583
584 if(!sock->isOpen()) {
585 errors << "NetworkSocket::EventHandler: socket is closed" << endl;
586 return;
587 }
588
589 struct EventHandlerThread : Action {
590 SmartPointer<SharedData> sharedData;
591 uint pollType; // NL_READ_STATUS or NL_ERROR_STATUS
592
593 EventHandlerThread(const SmartPointer<SharedData>& _data, uint _pollType) :
594 sharedData(_data), pollType(_pollType) {}
595
596 bool pushNewDataEvent() {
597 Mutex::ScopedLock lock(sharedData->mutex);
598 if(sharedData->sock) {
599 sharedData->sock->OnNewData.pushToMainQueue(EventData(sharedData->sock));
600 return true;
601 }
602 return false;
603 }
604
605 bool pushErrorEvent() {
606 Mutex::ScopedLock lock(sharedData->mutex);
607 if(sharedData->sock) {
608 sharedData->sock->OnError.pushToMainQueue(EventData(sharedData->sock));
609 return true;
610 }
611 return false;
612 }
613
614 int handle() {
615 const int maxFPS = tLXOptions ? tLXOptions->nMaxFPS : 100;
616 TimeDiff max_frame_time = TimeDiff(MAX(0.01f, (maxFPS > 0) ? 1.0f/(float)maxFPS : 0.0f));
617 AbsTime lastTime = GetTime();
618
619 while(!sharedData->quitSignal) {
620 NLsocket s;
621 NLint ret = nlPollGroup(sharedData->nlGroup, pollType, &s, /* amount of sockets */ 1, /* timeout */ max_frame_time.milliseconds());
622 // if no error, ret is amount of sockets which triggered the event
623
624 if(ret > 0) {
625 switch(pollType) {
626 case NL_READ_STATUS: if(!pushNewDataEvent()) return -1; break;
627 case NL_ERROR_STATUS: if(!pushErrorEvent()) return -1; break;
628 }
629 }
630
631 AbsTime curTime = GetTime();
632 if(curTime - lastTime < max_frame_time) {
633 SDL_Delay( (Uint32)( ( max_frame_time - (curTime - lastTime) ).milliseconds() ) );
634 }
635 lastTime = curTime;
636 }
637
638 return 0;
639 }
640 };
641
642 sharedData = new SharedData(sock);
643 threadPool->start(new EventHandlerThread(sharedData, NL_READ_STATUS), "socket " + itoa(sock->m_socket->sock) + " read event checker", true);
644 threadPool->start(new EventHandlerThread(sharedData, NL_ERROR_STATUS), "socket " + itoa(sock->m_socket->sock) + " error event checker", true);
645 }
646
NetworkSocket()647 NetworkSocket::NetworkSocket() : m_type(NST_INVALID), m_state(NSS_NONE), m_withEvents(false), m_socket(NULL) {
648 m_socket = new InternSocket();
649 }
650
~NetworkSocket()651 NetworkSocket::~NetworkSocket() {
652 Clear();
653 delete m_socket;
654 m_socket = NULL;
655 }
656
setWithEvents(bool v)657 void NetworkSocket::setWithEvents( bool v )
658 {
659 if( v == m_withEvents ) return;
660 m_withEvents = v;
661 checkEventHandling();
662 }
663
checkEventHandling()664 void NetworkSocket::checkEventHandling() {
665 if(isOpen() && m_withEvents) {
666 // we must have an event handler
667 if(m_socket->eventHandler.get() == NULL) {
668 m_socket->eventHandler = new EventHandler(this);
669 }
670 }
671 else {
672 // we must not have an event handler
673 if(m_socket->eventHandler.get()) {
674 m_socket->eventHandler->quit();
675 m_socket->eventHandler = NULL;
676 }
677 }
678 }
679
debugString() const680 std::string NetworkSocket::debugString() const {
681 if(!isOpen()) return "Closed";
682 std::string ret = TypeStr(m_type) + "/" + StateStr(m_state);
683 {
684 std::string localStr = "INVALIDLOCAL";
685 NetworkAddr addr;
686 if(nlGetLocalAddr(m_socket->sock, getNLaddr(addr)) != NL_FALSE)
687 NetAddrToString(addr, localStr);
688 else {
689 localStr = "ERRORLOCALADDR(" + GetLastErrorStr() + ")";
690 ResetSocketError();
691 }
692 ret += " " + localStr;
693 }
694 if(m_state == NSS_CONNECTED) {
695 ret += " connected to ";
696 std::string remoteStr = "INVALIDREMOTE";
697 NetworkAddr addr;
698 if(nlGetRemoteAddr(m_socket->sock, getNLaddr(addr)) != NL_FALSE)
699 NetAddrToString(remoteAddress(), remoteStr);
700 else {
701 remoteStr = "ERRORREMOTEADDR(" + GetLastErrorStr() + ")";
702 ResetSocketError();
703 }
704 ret += remoteStr;
705 }
706 return ret;
707 }
708
OpenReliable(Port port)709 bool NetworkSocket::OpenReliable(Port port) {
710 if(isOpen()) {
711 warnings << "NetworkSocket " << debugString() << ": OpenReliable: socket is already opened, reopening now" << endl;
712 Close();
713 }
714
715 NLsocket ret = nlOpen(port, NL_RELIABLE);
716 if (ret == NL_INVALID) {
717 #ifdef DEBUG
718 errors << "OpenReliableSocket: " << GetLastErrorStr() << endl;
719 #endif
720 ResetSocketError();
721 return false;
722 }
723 m_socket->sock = ret;
724 m_type = NST_TCP;
725 m_state = NSS_NONE;
726 checkEventHandling();
727 return true;
728 }
729
OpenUnreliable(Port port)730 bool NetworkSocket::OpenUnreliable(Port port) {
731 if(isOpen()) {
732 warnings << "NetworkSocket " << debugString() << ": OpenReliable: socket is already opened, reopening now" << endl;
733 Close();
734 }
735
736 NLsocket ret = nlOpen(port, NL_UNRELIABLE);
737 if (ret == NL_INVALID) {
738 #ifdef DEBUG
739 errors << "OpenUnreliableSocket: " << GetLastErrorStr() << endl;
740 #endif
741 ResetSocketError();
742 return false;
743 }
744 m_socket->sock = ret;
745 m_type = NST_UDP;
746 m_state = NSS_NONE;
747 checkEventHandling();
748 return true;
749 }
750
OpenBroadcast(Port port)751 bool NetworkSocket::OpenBroadcast(Port port) {
752 if(isOpen()) {
753 warnings << "NetworkSocket " << debugString() << ": OpenBroadcast: socket is already opened, reopening now" << endl;
754 Close();
755 }
756
757 NLsocket ret = nlOpen(port, NL_BROADCAST);
758 if (ret == NL_INVALID) {
759 #ifdef DEBUG
760 errors << "OpenBroadcastSocket: " << GetLastErrorStr() << endl;
761 #endif
762 ResetSocketError();
763 return false;
764 }
765 m_socket->sock = ret;
766 m_type = NST_UDPBROADCAST;
767 m_state = NSS_NONE;
768 checkEventHandling();
769 return true;
770 }
771
Connect(const NetworkAddr & addr)772 bool NetworkSocket::Connect(const NetworkAddr& addr) {
773 if(!isOpen()) {
774 errors << "NetworkSocket::Connect: socket is closed" << endl;
775 return false;
776 }
777
778 if(m_type != NST_TCP) {
779 errors << "NetworkSocket::Connect " << debugString() << ": connect only works with TCP" << endl;
780 return false;
781 }
782
783 if(nlConnect(m_socket->sock, getNLaddr(addr)) == NL_FALSE) {
784 #ifdef DEBUG
785 errors << "Connect: " << GetLastErrorStr() << endl;
786 #endif
787 ResetSocketError();
788 return false;
789 }
790
791 checkEventHandling();
792 return true;
793 }
794
Listen()795 bool NetworkSocket::Listen() {
796 if(!isOpen()) {
797 errors << "NetworkSocket::Listen: socket is closed" << endl;
798 return false;
799 }
800
801 if(nlListen(m_socket->sock) == NL_FALSE) {
802 #ifdef DEBUG
803 errors << "Listen: " << GetLastErrorStr() << endl;
804 #endif
805 ResetSocketError();
806 return false;
807 }
808
809 checkEventHandling();
810 return true;
811 }
812
Close()813 void NetworkSocket::Close() {
814 if(!isOpen()) {
815 warnings << "NetworkSocket::Close: cannot close already closed socket" << endl;
816 return;
817 }
818
819 struct CloseSocketWorker : Task {
820 NLsocket sock;
821 int handle() {
822 nlSystemUseChangeLock.startReadAccess();
823 int ret = -1;
824 if(bNetworkInited) { // only do that if we have the network system still up
825 // this should already close the socket but not lock other parts in HawkNL
826 nlPrepareClose(sock);
827 // hopefully this does not block anymore
828 ret = (nlClose(sock) != NL_FALSE) ? 0 : -1;
829 }
830 nlSystemUseChangeLock.endReadAccess();
831 return ret;
832 }
833 };
834 CloseSocketWorker* worker = new CloseSocketWorker();
835 worker->name = "close socket";
836 worker->sock = m_socket->sock;
837 taskManager->start(worker);
838
839 m_socket->sock = NL_INVALID;
840 m_type = NST_INVALID;
841 m_state = NSS_NONE;
842
843 checkEventHandling();
844 }
845
Write(const void * buffer,int nbytes)846 int NetworkSocket::Write(const void* buffer, int nbytes) {
847 if(!isOpen()) {
848 errors << "NetworkSocket::Write: cannot write on closed socket" << endl;
849 return NL_INVALID;
850 }
851
852 ResetSocketError();
853 NLint ret = nlWrite(m_socket->sock, buffer, nbytes);
854
855 // Error checking
856 if (ret == NL_INVALID) {
857 #ifdef DEBUG
858 std::string errStr = GetLastErrorStr(); // cache errStr that debugString will not overwrite it
859 warnings << "WriteSocket " << debugString() << ": " << errStr << endl;
860 #endif // DEBUG
861 return NL_INVALID;
862 }
863
864 /*if (ret == 0) { // HINT: this is not an error, it is one of the ways to find out if a socket is writeable
865 errors << "WriteSocket: Could not send the packet, network buffers are full." << endl;
866 }*/
867
868 return ret;
869 }
870
871
Read(void * buffer,int nbytes)872 int NetworkSocket::Read(void* buffer, int nbytes) {
873 if(!isOpen()) {
874 errors << "NetworkSocket::Read: cannot read on closed socket" << endl;
875 return NL_INVALID;
876 }
877
878 ResetSocketError();
879 NLint ret = nlRead(m_socket->sock, buffer, nbytes);
880
881 // Error checking
882 if (ret == NL_INVALID) {
883 // messageend-error is just that there is no data; we can ignore that
884 if (!IsMessageEndSocketErrorNr(GetSocketErrorNr())) {
885 #ifdef DEBUG
886 std::string errStr = GetLastErrorStr(); // cache errStr that debugString will not overwrite it
887 errors << "ReadSocket " << debugString() << ": " << errStr << endl;
888 #endif // DEBUG
889
890 // Is this perhaps the solution for the Bad file descriptor error?
891 //Close();
892 }
893 return NL_INVALID;
894 }
895
896 return ret;
897 }
898
899
900
901
902
isReady() const903 bool NetworkSocket::isReady() const {
904 return isOpen() && nlUpdateState(m_socket->sock);
905 }
906
907
908 // TODO: Remove the following functions because they are blocking.
909
910 /////////////////////
911 // Wait until the socket is writable
912 // TODO: remove this function, don't use it!
WaitForSocketWrite(int timeout)913 void NetworkSocket::WaitForSocketWrite(int timeout)
914 {
915 if(!isOpen()) {
916 errors << "WaitForSocketWrite: socket closed" << endl;
917 return;
918 }
919
920 NLint group = nlGroupCreate();
921 nlGroupAddSocket(group, m_socket->sock);
922 NLsocket s;
923 nlPollGroup(group, NL_WRITE_STATUS, &s, 1, (NLint)timeout);
924 nlGroupDestroy(group);
925 }
926
927 //////////////////////
928 // Wait until the socket contains some data to read
929 // TODO: remove this function, don't use it!
WaitForSocketRead(int timeout)930 void NetworkSocket::WaitForSocketRead(int timeout)
931 {
932 if(!isOpen()) {
933 errors << "WaitForSocketRead: socket closed" << endl;
934 return;
935 }
936
937 NLint group = nlGroupCreate();
938 nlGroupAddSocket(group, m_socket->sock);
939 NLsocket s;
940 nlPollGroup(group, NL_READ_STATUS, &s, 1, (NLint)timeout);
941 nlGroupDestroy(group);
942 }
943
944 /////////////////////
945 // Wait until the socket contains some data or is writeable
946 // TODO: remove this function, don't use it!
WaitForSocketReadOrWrite(int timeout)947 void NetworkSocket::WaitForSocketReadOrWrite(int timeout)
948 {
949 if(!isOpen()) {
950 errors << "WaitForSocketReadOrWrite: socket closed" << endl;
951 return;
952 }
953
954 NLint group = nlGroupCreate();
955 nlGroupAddSocket(group, m_socket->sock);
956 NLsocket s;
957
958 if (timeout < 0) {
959 // Infinite timeout
960 while (true) {
961 if (nlPollGroup(group, NL_READ_STATUS, &s, 1, 0))
962 break;
963 if (nlPollGroup(group, NL_WRITE_STATUS, &s, 1, 0))
964 break;
965 SDL_Delay(2);
966 }
967 } else if (timeout > 0) {
968 // Blocking, with a timeout
969 Uint32 start = SDL_GetTicks();
970 while (SDL_GetTicks() - start <= (Uint32)timeout) {
971 if (nlPollGroup(group, NL_READ_STATUS, &s, 1, 0))
972 break;
973 if (nlPollGroup(group, NL_WRITE_STATUS, &s, 1, 0))
974 break;
975 SDL_Delay(2);
976 }
977 }
978
979 nlGroupDestroy(group);
980 }
981
localAddress() const982 NetworkAddr NetworkSocket::localAddress() const {
983 NetworkAddr addr;
984
985 if(!isOpen()) {
986 errors << "NetworkSocket::localAddress: socket is closed" << endl;
987 return addr;
988 }
989
990 if(nlGetLocalAddr(m_socket->sock, getNLaddr(addr)) == NL_FALSE) {
991 errors << "NetworkSocket::localAddress: cannot get local address (" << debugString() << "): " << GetLastErrorStr() << endl;
992 ResetSocketError();
993 return addr;
994 }
995
996 return addr;
997 }
998
remoteAddress() const999 NetworkAddr NetworkSocket::remoteAddress() const {
1000 NetworkAddr addr;
1001
1002 if(!isOpen()) {
1003 errors << "NetworkSocket::remoteAddress: socket is closed" << endl;
1004 return addr;
1005 }
1006
1007 if(nlGetRemoteAddr(m_socket->sock, getNLaddr(addr)) == NL_FALSE) {
1008 errors << "NetworkSocket::remoteAddress: cannot get remote address" << "(" << debugString() << "): " << GetLastErrorStr() << endl;
1009 ResetSocketError();
1010 return addr;
1011 }
1012
1013 return addr;
1014 }
1015
setRemoteAddress(const NetworkAddr & addr)1016 bool NetworkSocket::setRemoteAddress(const NetworkAddr& addr) {
1017 if(!isOpen()) {
1018 errors << "NetworkSocket::setRemoteAddress: socket is closed" << endl;
1019 return false;
1020 }
1021
1022 if(getNLaddr(addr) == NULL) {
1023 errors << "NetworkSocket::setRemoteAddress " << debugString() << ": given address is invalid" << endl;
1024 return false;
1025 }
1026 if( GetNetAddrPort(addr) == 0 )
1027 {
1028 errors << "NetworkSocket::setRemoteAddress " << debugString() << ": port is set to 0" << endl;
1029 }
1030
1031 if(nlSetRemoteAddr(m_socket->sock, getNLaddr(addr)) == NL_FALSE) {
1032 std::string addrStr = "INVALIDADDR";
1033 NetAddrToString(addr, addrStr);
1034 errors << "NetworkSocket::setRemoteAddress " << debugString() << ": failed to set destination " << addrStr << ": " << GetLastErrorStr() << endl;
1035 ResetSocketError();
1036 return false;
1037 }
1038
1039 return true;
1040 }
1041
GetSocketErrorNr()1042 int GetSocketErrorNr() {
1043 return nlGetError();
1044 }
1045
GetSocketErrorStr(int errnr)1046 std::string GetSocketErrorStr(int errnr) {
1047 return GetLastErrorStr();
1048 }
1049
GetLastErrorStr()1050 std::string GetLastErrorStr() {
1051 if (nlGetError() != NL_SYSTEM_ERROR)
1052 return std::string(nlGetErrorStr(nlGetError()));
1053 else
1054 return std::string(nlGetSystemErrorStr(nlGetSystemError()));
1055 }
1056
IsMessageEndSocketErrorNr(int errnr)1057 bool IsMessageEndSocketErrorNr(int errnr) {
1058 return (errnr == NL_MESSAGE_END);
1059 }
1060
ResetSocketError()1061 void ResetSocketError() {
1062 if (!bNetworkInited)
1063 return;
1064
1065 nlSetError(NL_NO_ERROR);
1066 }
1067
1068
1069
1070
IsNetAddrValid(const NetworkAddr & addr)1071 bool IsNetAddrValid(const NetworkAddr& addr) {
1072 if(getNLaddr(addr))
1073 return (getNLaddr(addr)->valid != NL_FALSE);
1074 else
1075 return false;
1076 }
1077
SetNetAddrValid(NetworkAddr & addr,bool valid)1078 bool SetNetAddrValid(NetworkAddr& addr, bool valid) {
1079 if(!getNLaddr(addr)) return false;
1080 getNLaddr(addr)->valid = valid ? NL_TRUE : NL_FALSE;
1081 return true;
1082 }
1083
ResetNetAddr(NetworkAddr & addr)1084 void ResetNetAddr(NetworkAddr& addr) {
1085 if(!getNLaddr(addr)) return;
1086 // TODO: is this the best way?
1087 memset(getNLaddr(addr), 0, sizeof(NLaddress));
1088 SetNetAddrValid(addr, false);
1089 }
1090
IsNetAddrV6(const std::string & s)1091 bool IsNetAddrV6(const std::string& s)
1092 {
1093 // Any IPv6 address will be in a format [XXXX:XXXX:...:XXXX]:XXXX or [XXXX:XXXX:...:XXXX]
1094 return s.size() > 0 && s[0] == '[';
1095 }
1096
IsNetAddrV6(const NetworkAddr & addr)1097 bool IsNetAddrV6(const NetworkAddr& addr)
1098 {
1099 std::string s;
1100 NetAddrToString(addr, s);
1101 return IsNetAddrV6(s);
1102 }
1103
isStringValidIP(const std::string & str)1104 static bool isStringValidIP(const std::string& str) {
1105 NetworkAddr addr;
1106 return (nlStringToAddr(str.c_str(), getNLaddr(addr)) == NL_TRUE);
1107 }
1108
1109 // accepts "%i.%i.%i.%i[:%l]" as input
StringToNetAddr(const std::string & string,NetworkAddr & addr,std::string * errorStr)1110 bool StringToNetAddr(const std::string& string, NetworkAddr& addr, std::string* errorStr) {
1111 if(getNLaddr(addr) == NULL) return false;
1112
1113 if(!isStringValidIP(string)) {
1114 SetNetAddrValid(addr, false);
1115 return false;
1116 }
1117
1118 if(nlStringToAddr(string.c_str(), getNLaddr(addr)) == NL_FALSE) {
1119 errors << "StringToNetAddr: cannot use " << string << " as address: " << GetLastErrorStr() << endl;
1120 if(errorStr) *errorStr = GetLastErrorStr();
1121 ResetSocketError();
1122 return false;
1123 }
1124
1125 return true;
1126 }
1127
NetAddrToString(const NetworkAddr & addr,std::string & string)1128 bool NetAddrToString(const NetworkAddr& addr, std::string& string) {
1129 // TODO: safty here for buffer
1130 char buf[256];
1131 NLchar* res = nlAddrToString(getNLaddr(addr), buf);
1132 if(res) {
1133 fix_markend(buf);
1134 string = buf;
1135 return true;
1136 } else {
1137 string = "";
1138 return false;
1139 }
1140 }
1141
StringToNetAddr(const std::string & string)1142 NetworkAddr StringToNetAddr(const std::string& string) {
1143 NetworkAddr ret;
1144 ResetNetAddr(ret);
1145 StringToNetAddr(string, ret);
1146 return ret;
1147 };
1148
NetAddrToString(const NetworkAddr & addr)1149 std::string NetAddrToString(const NetworkAddr& addr) {
1150 std::string ret;
1151 NetAddrToString(addr, ret);
1152 return ret;
1153 };
1154
GetNetAddrPort(const NetworkAddr & addr)1155 unsigned short GetNetAddrPort(const NetworkAddr& addr) {
1156 if(getNLaddr(addr) == NULL)
1157 return 0;
1158 else
1159 return nlGetPortFromAddr(getNLaddr(addr));
1160 }
1161
SetNetAddrPort(NetworkAddr & addr,unsigned short port,std::string * errorStr)1162 bool SetNetAddrPort(NetworkAddr& addr, unsigned short port, std::string* errorStr) {
1163 if(getNLaddr(addr) == NULL)
1164 return false;
1165 else {
1166 if(nlSetAddrPort(getNLaddr(addr), port) == NL_FALSE) {
1167 errors << "SetNetAddrPort: cannot set port " << port << ": " << GetLastErrorStr() << endl;
1168 if(errorStr) *errorStr = GetLastErrorStr();
1169 ResetSocketError();
1170 return false;
1171 }
1172 return true;
1173 }
1174 }
1175
AreNetAddrEqual(const NetworkAddr & addr1,const NetworkAddr & addr2)1176 bool AreNetAddrEqual(const NetworkAddr& addr1, const NetworkAddr& addr2) {
1177 if(getNLaddr(addr1) == getNLaddr(addr2))
1178 return true;
1179 else
1180 return nlAddrCompare(getNLaddr(addr1), getNLaddr(addr2)) != NL_FALSE;
1181 }
1182
1183
1184
1185
1186 Event<> onDnsReady;
1187
1188 // copied from HawkNL sock.c and modified to not use nlStringToNetAddr
GetAddrFromNameAsync_Internal(const NLchar * name,NLaddress * address4,NLaddress * address6)1189 static bool GetAddrFromNameAsync_Internal(const NLchar* name, NLaddress* address4, NLaddress* address6) {
1190 NLushort port = 0;
1191 char *pos;
1192 int status;
1193 NLbyte temp[NL_MAX_STRING_LENGTH];
1194 struct addrinfo hints;
1195 struct addrinfo *result, *rp;
1196
1197 address4->valid = NL_FALSE;
1198 address6->valid = NL_FALSE;
1199 #ifdef _UNICODE
1200 /* convert from wide char string to multibyte char string */
1201 (void)wcstombs(temp, (const NLchar *)name, NL_MAX_STRING_LENGTH);
1202 #else
1203 strncpy(temp, name, NL_MAX_STRING_LENGTH);
1204 #endif
1205 temp[NL_MAX_STRING_LENGTH - 1] = (NLbyte)'\0';
1206 pos = strrchr(temp, ':');
1207 if(pos != NULL)
1208 {
1209 pos[0] = (NLbyte)'\0';
1210 (void)sscanf(pos+1, "%hu", &port);
1211 }
1212
1213 memset(&hints, 0, sizeof(struct addrinfo));
1214 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
1215 hints.ai_socktype = 0;
1216 hints.ai_flags = 0; /* For wildcard IP address */
1217 hints.ai_protocol = 0; /* Any protocol */
1218 hints.ai_canonname = NULL;
1219 hints.ai_addr = NULL;
1220 hints.ai_next = NULL;
1221
1222 status = getaddrinfo(temp, NULL, &hints, &result);
1223 if(status != 0 || result == NULL)
1224 {
1225 nlSetError(NL_SYSTEM_ERROR);
1226 return false;
1227 }
1228
1229 for (rp = result; rp != NULL; rp = rp->ai_next)
1230 {
1231 if(rp->ai_family == AF_INET && !address4->valid)
1232 {
1233 ((struct sockaddr_in6 *)address4)->sin6_family = AF_INET6;
1234 ((struct sockaddr_in6 *)address4)->sin6_port = htons(port);
1235 struct in_addr v4addr;
1236 v4addr = ((struct sockaddr_in *)rp->ai_addr)->sin_addr;
1237 char addr6[32] = "::ffff:";
1238 strcat(addr6, inet_ntoa(v4addr));
1239 inet_pton(AF_INET6, addr6, &((struct sockaddr_in6 *)address4)->sin6_addr);
1240 address4->valid = NL_TRUE;
1241 }
1242 if(rp->ai_family == AF_INET6 && !address6->valid)
1243 {
1244 ((struct sockaddr_in6 *)address6)->sin6_family = AF_INET6;
1245 ((struct sockaddr_in6 *)address6)->sin6_port = htons(port);
1246 memcpy(&((struct sockaddr_in6 *)address6)->sin6_addr, &((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr, sizeof(struct in6_addr));
1247 address6->valid = NL_TRUE;
1248 }
1249 }
1250
1251 freeaddrinfo(result);
1252
1253 return address4->valid || address6->valid;
1254 }
1255
1256 static std::set<std::string> PendingDnsQueries;
1257 static Mutex PendingDnsQueriesMutex;
1258
GetNetAddrFromNameAsync(const std::string & name)1259 bool GetNetAddrFromNameAsync(const std::string& name)
1260 {
1261 // We don't use nlGetAddrFromNameAsync here because we have to use SmartPointers
1262 // The problem is, if you call this and then delete the memory of the network address
1263 // while the thread isn't ready, it will write after to deleted memory.
1264
1265 NetworkAddr addr4, addr6;
1266
1267 if(name == "") {
1268 return false;
1269 }
1270 if (StringToNetAddr(name, addr4)) {
1271 return true;
1272 }
1273
1274 ResetSocketError(); // Clear the bad address error
1275
1276 if(GetFromDnsCache(name, addr4, addr6)) {
1277 return true;
1278 }
1279
1280 {
1281 Mutex::ScopedLock l(PendingDnsQueriesMutex);
1282 if(PendingDnsQueries.find(name) != PendingDnsQueries.end())
1283 return true;
1284 PendingDnsQueries.insert(name);
1285 }
1286
1287 struct GetAddrFromNameAsync_Executer : Task {
1288 std::string addr_name;
1289 NetworkAddr address4, address6;
1290
1291 int handle() {
1292 getNLaddr(address4)->valid = NL_FALSE;
1293 getNLaddr(address6)->valid = NL_FALSE;
1294 if(GetAddrFromNameAsync_Internal(addr_name.c_str(), getNLaddr(address4), getNLaddr(address6))) {
1295 // TODO: we use default DNS record expire time of 1 hour, we should include some DNS client to make it in correct way
1296 // Cache both valid and invalid addersses, one server may have IPv4 but no IPv6 address
1297 notes << "DNS: resolved " << addr_name << " to " << NetAddrToString(address4) << " IPv6 " << NetAddrToString(address6) << endl;
1298 AddToDnsCache4(addr_name, address4);
1299 AddToDnsCache6(addr_name, address6);
1300 }
1301
1302 // TODO: handle failures here? there should be, but we only have the valid field
1303 // For now, we leave it at false, so the timeout handling will just occur.
1304
1305 // push a net event
1306 onDnsReady.pushToMainQueue(EventData());
1307
1308 Mutex::ScopedLock l(PendingDnsQueriesMutex);
1309 PendingDnsQueries.erase(addr_name);
1310
1311 return 0;
1312 }
1313 };
1314 GetAddrFromNameAsync_Executer* data = new GetAddrFromNameAsync_Executer();
1315 if(data == NULL) return false;
1316 data->name = "GetNetAddrFromNameAsync for " + name;
1317 data->addr_name = name;
1318
1319 taskManager->start(data, false);
1320 return true;
1321 }
1322
1323
isDataAvailable()1324 bool NetworkSocket::isDataAvailable() {
1325 NLint group = nlGroupCreate();
1326 nlGroupAddSocket( group, m_socket->sock );
1327 NLsocket sock_out[2];
1328 int ret = nlPollGroup( group, NL_READ_STATUS, sock_out, 1, 0 );
1329 nlGroupDestroy(group);
1330 return ret > 0;
1331 }
1332
1333 // In some cases, e.g. if the network is not connected, some IPs are
1334 // not available. Most likely, without any network, you just have
1335 // 127.* in the routing table.
IsNetAddrAvailable(const NetworkAddr & addr)1336 bool IsNetAddrAvailable(const NetworkAddr& addr) {
1337 // TODO: implement...
1338 return true;
1339 }
1340
1341
reapplyRemoteAddress()1342 void NetworkSocket::reapplyRemoteAddress() {
1343 if(m_type == NST_UDP || m_type == NST_UDPBROADCAST)
1344 // TODO: comment this, why we need that in some cases
1345 setRemoteAddress(remoteAddress());
1346 else
1347 errors << "NetworkSocket::reapplyRemoteAddress cannot be done as " << TypeStr(m_type) << endl;
1348 }
1349
1350