Use correct address in multicast print
[Torque-3d.git] / Engine / source / platform / platformNet.cpp
blobe1ab88f09a79106a9ac4d2dcc6083a368a2efce0
1 //-----------------------------------------------------------------------------
2 // Copyright (c) 2012 GarageGames, LLC
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to
6 // deal in the Software without restriction, including without limitation the
7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // sell copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 // IN THE SOFTWARE.
21 //-----------------------------------------------------------------------------
23 #include "platform/platformNet.h"
24 #include "platform/threads/mutex.h"
25 #include "core/strings/stringFunctions.h"
26 #include "core/util/hashFunction.h"
27 #include "console/consoleTypes.h"
29 // jamesu - debug DNS
30 //#define TORQUE_DEBUG_LOOKUPS
33 #if defined (TORQUE_OS_WIN)
34 #define TORQUE_USE_WINSOCK
35 #include <errno.h>
36 #include <ws2tcpip.h>
38 #ifndef EINPROGRESS
39 #define EINPROGRESS WSAEINPROGRESS
40 #endif // EINPROGRESS
42 #define ioctl ioctlsocket
44 typedef S32 socklen_t;
46 #elif defined ( TORQUE_OS_MAC )
48 #include <unistd.h>
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <sys/poll.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
54 #include <netinet/in.h>
55 #include <errno.h>
56 #include <sys/ioctl.h>
57 #include <net/if.h>
59 typedef sockaddr_in SOCKADDR_IN;
60 typedef sockaddr * PSOCKADDR;
61 typedef sockaddr SOCKADDR;
62 typedef in_addr IN_ADDR;
63 typedef int SOCKET;
65 #define INVALID_SOCKET -1
66 #define SOCKET_ERROR -1
68 #define closesocket close
70 #elif defined( TORQUE_OS_LINUX )
72 #include <unistd.h>
73 #include <sys/types.h>
74 #include <sys/socket.h>
75 #include <sys/poll.h>
76 #include <arpa/inet.h>
77 #include <netdb.h>
78 #include <netinet/in.h>
79 #include <errno.h>
80 #include <sys/ioctl.h>
81 #include <net/if.h>
83 typedef sockaddr_in SOCKADDR_IN;
84 typedef sockaddr_in6 SOCKADDR_IN6;
85 typedef sockaddr * PSOCKADDR;
86 typedef sockaddr SOCKADDR;
87 typedef in_addr IN_ADDR;
88 typedef in6_addr IN6_ADDR;
89 typedef int SOCKET;
91 #define INVALID_SOCKET -1
92 #define SOCKET_ERROR -1
94 #define closesocket close
96 #elif defined( TORQUE_OS_XENON )
98 #include <Xtl.h>
99 #include <string>
101 #define TORQUE_USE_WINSOCK
102 #define EINPROGRESS WSAEINPROGRESS
103 #define ioctl ioctlsocket
104 typedef S32 socklen_t;
106 DWORD _getLastErrorAndClear()
108 DWORD err = WSAGetLastError();
109 WSASetLastError( 0 );
111 return err;
114 #else
116 #endif
118 #if defined(TORQUE_USE_WINSOCK)
119 static const char* strerror_wsa( S32 code )
121 switch( code )
123 #define E( name ) case name: return #name;
124 E( WSANOTINITIALISED );
125 E( WSAENETDOWN );
126 E( WSAEADDRINUSE );
127 E( WSAEINPROGRESS );
128 E( WSAEALREADY );
129 E( WSAEADDRNOTAVAIL );
130 E( WSAEAFNOSUPPORT );
131 E( WSAEFAULT );
132 E( WSAEINVAL );
133 E( WSAEISCONN );
134 E( WSAENETUNREACH );
135 E( WSAEHOSTUNREACH );
136 E( WSAENOBUFS );
137 E( WSAENOTSOCK );
138 E( WSAETIMEDOUT );
139 E( WSAEWOULDBLOCK );
140 E( WSAEACCES );
141 #undef E
142 default:
143 return "Unknown";
146 #endif
148 #include "core/util/tVector.h"
149 #include "platform/platformNetAsync.h"
150 #include "console/console.h"
151 #include "core/util/journal/process.h"
152 #include "core/util/journal/journal.h"
155 NetSocket NetSocket::INVALID = NetSocket::fromHandle(-1);
157 template<class T> class ReservedSocketList
159 public:
160 struct EntryType
162 T value;
163 bool used;
165 EntryType() : value(-1), used(false) { ; }
167 bool operator==(const EntryType &e1)
169 return value == e1.value && used == e1.used;
172 bool operator!=(const EntryType &e1)
174 return !(value == e1.value && used == e1.used);
178 Vector<EntryType> mSocketList;
179 Mutex *mMutex;
181 ReservedSocketList()
183 mMutex = new Mutex;
186 ~ReservedSocketList()
188 delete mMutex;
191 inline void modify() { Mutex::lockMutex(mMutex); }
192 inline void endModify() { Mutex::unlockMutex(mMutex); }
194 NetSocket reserve(SOCKET reserveId = -1, bool doLock = true);
195 void remove(NetSocket socketToRemove, bool doLock = true);
197 T activate(NetSocket socketToActivate, int family, bool useUDP, bool clearOnFail = false);
198 T resolve(NetSocket socketToResolve);
201 const SOCKET InvalidSocketHandle = -1;
203 static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address);
204 static void IPSocket6ToNetAddress(const struct sockaddr_in6 *sockAddr, NetAddress *address);
206 namespace PlatformNetState
208 static S32 initCount = 0;
210 static const S32 defaultPort = 28000;
211 static S32 netPort = 0;
213 static NetSocket udpSocket = NetSocket::INVALID;
214 static NetSocket udp6Socket = NetSocket::INVALID;
215 static NetSocket multicast6Socket = NetSocket::INVALID;
217 static ipv6_mreq multicast6Group;
219 static ReservedSocketList<SOCKET> smReservedSocketList;
221 Net::Error getLastError()
223 #if defined(TORQUE_USE_WINSOCK)
224 S32 err = WSAGetLastError();
225 switch (err)
227 case 0:
228 return Net::NoError;
229 case WSAEWOULDBLOCK:
230 return Net::WouldBlock;
231 default:
232 return Net::UnknownError;
234 #else
235 int theError = errno;
236 if (errno == EAGAIN)
237 return Net::WouldBlock;
238 if (errno == 0)
239 return Net::NoError;
240 if (errno == EINPROGRESS)
241 return Net::WouldBlock;
243 return Net::UnknownError;
244 #endif
247 S32 getDefaultGameProtocol()
249 // we turn off VDP in non-release builds because VDP does not support broadcast packets
250 // which are required for LAN queries (PC->Xbox connectivity). The wire protocol still
251 // uses the VDP packet structure, though.
252 S32 protocol = IPPROTO_UDP;
253 bool useVDP = false;
254 #ifdef TORQUE_DISABLE_PC_CONNECTIVITY
255 // Xbox uses a VDP (voice/data protocol) socket for networking
256 protocol = IPPROTO_VDP;
257 useVDP = true;
258 #endif
260 return protocol;
263 struct addrinfo* pickAddressByProtocol(struct addrinfo* addr, int protocol)
265 for (addr; addr != NULL; addr = addr->ai_next)
267 if (addr->ai_family == protocol)
268 return addr;
271 return NULL;
274 /// Extracts core address parts from an address string. Returns false if it's malformed.
275 bool extractAddressParts(const char *addressString, char outAddress[256], int &outPort, int &outFamily)
277 outPort = 0;
278 outFamily = AF_UNSPEC;
280 if (!dStrnicmp(addressString, "ipx:", 4))
281 // ipx support deprecated
282 return false;
284 if (!dStrnicmp(addressString, "ip:", 3))
286 addressString += 3; // eat off the ip:
287 outFamily = AF_INET;
289 else if (!dStrnicmp(addressString, "ip6:", 4))
291 addressString += 4; // eat off the ip6:
292 outFamily = AF_INET6;
295 if (strlen(addressString) > 255)
296 return false;
298 char *portString = NULL;
300 if (addressString[0] == '[')
302 // Must be ipv6 notation
303 dStrcpy(outAddress, addressString+1);
304 addressString = outAddress;
306 portString = dStrchr(outAddress, ']');
307 if (portString)
309 // Sort out the :port after the ]
310 *portString++ = '\0';
311 if (*portString != ':')
313 portString = NULL;
315 else
317 *portString++ = '\0';
321 if (outFamily == AF_UNSPEC)
323 outFamily = AF_INET6;
326 else
328 dStrcpy(outAddress, addressString);
329 addressString = outAddress;
331 // Check to see if we have multiple ":" which would indicate this is an ipv6 address
332 char* scan = outAddress;
333 int colonCount = 0;
334 while (*scan != '\0' && colonCount < 2)
336 if (*scan++ == ':')
337 colonCount++;
339 if (colonCount <= 1)
341 // either ipv4 or host
342 portString = dStrchr(outAddress, ':');
344 if (portString)
346 *portString++ = '\0';
349 else if (outFamily == AF_UNSPEC)
351 // Must be ipv6
352 outFamily = AF_INET6;
356 if (portString)
358 outPort = dAtoi(portString);
361 return true;
364 Net::Error getSocketAddress(SOCKET socketFd, int requiredFamily, NetAddress *outAddress)
366 Net::Error error = Net::UnknownError;
368 if (requiredFamily == AF_INET)
370 sockaddr_in ipAddr;
371 int len = sizeof(ipAddr);
372 if (getsockname(socketFd, (struct sockaddr*)&ipAddr, &len) >= 0)
374 IPSocketToNetAddress(&ipAddr, outAddress);
375 error = Net::NoError;
377 else
379 error = getLastError();
382 else if (requiredFamily == AF_INET6)
384 sockaddr_in6 ipAddr;
385 int len = sizeof(ipAddr);
386 if (getsockname(socketFd, (struct sockaddr*)&ipAddr, &len) >= 0)
388 IPSocket6ToNetAddress(&ipAddr, outAddress);
389 error = Net::NoError;
391 else
393 error = getLastError();
397 return error;
403 template<class T> NetSocket ReservedSocketList<T>::reserve(SOCKET reserveId, bool doLock)
405 MutexHandle handle;
406 if (doLock)
408 handle.lock(mMutex, true);
411 S32 idx = mSocketList.find_next(EntryType());
412 if (idx == -1)
414 EntryType entry;
415 entry.value = reserveId;
416 entry.used = true;
417 mSocketList.push_back(entry);
418 return NetSocket::fromHandle(mSocketList.size() - 1);
420 else
422 EntryType &entry = mSocketList[idx];
423 entry.used = true;
424 entry.value = reserveId;
427 return NetSocket::fromHandle(idx);
430 template<class T> void ReservedSocketList<T>::remove(NetSocket socketToRemove, bool doLock)
432 MutexHandle handle;
433 if (doLock)
435 handle.lock(mMutex, true);
438 if ((U32)socketToRemove.getHandle() >= (U32)mSocketList.size())
439 return;
441 mSocketList[socketToRemove.getHandle()] = EntryType();
444 template<class T> T ReservedSocketList<T>::activate(NetSocket socketToActivate, int family, bool useUDP, bool clearOnFail)
446 MutexHandle h;
447 h.lock(mMutex, true);
449 int typeID = useUDP ? SOCK_DGRAM : SOCK_STREAM;
450 int protocol = useUDP ? PlatformNetState::getDefaultGameProtocol() : 0;
452 if ((U32)socketToActivate.getHandle() >= (U32)mSocketList.size())
453 return -1;
455 EntryType &entry = mSocketList[socketToActivate.getHandle()];
456 if (!entry.used)
457 return -1;
459 T socketFd = entry.value;
460 if (socketFd == -1)
462 socketFd = ::socket(family, typeID, protocol);
464 if (socketFd == InvalidSocketHandle)
466 if (clearOnFail)
468 remove(socketToActivate, false);
470 return InvalidSocketHandle;
472 else
474 entry.used = true;
475 entry.value = socketFd;
476 return socketFd;
480 return socketFd;
483 template<class T> T ReservedSocketList<T>::resolve(NetSocket socketToResolve)
485 MutexHandle h;
486 h.lock(mMutex, true);
488 if ((U32)socketToResolve.getHandle() >= (U32)mSocketList.size())
489 return -1;
491 EntryType &entry = mSocketList[socketToResolve.getHandle()];
492 return entry.used ? entry.value : -1;
495 static ConnectionNotifyEvent* smConnectionNotify = NULL;
496 static ConnectionAcceptedEvent* smConnectionAccept = NULL;
497 static ConnectionReceiveEvent* smConnectionReceive = NULL;
498 static PacketReceiveEvent* smPacketReceive = NULL;
500 ConnectionNotifyEvent& Net::getConnectionNotifyEvent()
502 return *smConnectionNotify;
505 ConnectionAcceptedEvent& Net::getConnectionAcceptedEvent()
507 return *smConnectionAccept;
510 ConnectionReceiveEvent& Net::getConnectionReceiveEvent()
512 return *smConnectionReceive;
515 PacketReceiveEvent& Net::getPacketReceiveEvent()
517 return *smPacketReceive;
520 // Multicast stuff
521 bool Net::smMulticastEnabled = true;
523 // Protocol Stuff
524 bool Net::smIpv4Enabled = true;
525 bool Net::smIpv6Enabled = false;
528 // the Socket structure helps us keep track of the
529 // above states
530 struct PolledSocket
532 // local enum for socket states for polled sockets
533 enum SocketState
535 InvalidState,
536 Connected,
537 ConnectionPending,
538 Listening,
539 NameLookupRequired
542 PolledSocket()
544 fd = -1;
545 handleFd = NetSocket::INVALID;
546 state = InvalidState;
547 remoteAddr[0] = 0;
548 remotePort = -1;
551 SOCKET fd;
552 NetSocket handleFd;
553 S32 state;
554 char remoteAddr[256];
555 S32 remotePort;
558 // list of polled sockets
559 static Vector<PolledSocket*> gPolledSockets( __FILE__, __LINE__ );
561 static PolledSocket* addPolledSocket(NetSocket handleFd, SOCKET fd, S32 state,
562 char* remoteAddr = NULL, S32 port = -1)
564 PolledSocket* sock = new PolledSocket();
565 sock->fd = fd;
566 sock->handleFd = handleFd;
567 sock->state = state;
568 if (remoteAddr)
569 dStrcpy(sock->remoteAddr, remoteAddr);
570 if (port != -1)
571 sock->remotePort = port;
572 gPolledSockets.push_back(sock);
573 return sock;
576 bool netSocketWaitForWritable(NetSocket handleFd, S32 timeoutMs)
578 fd_set writefds;
579 timeval timeout;
580 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
582 FD_ZERO( &writefds );
583 FD_SET( socketFd, &writefds );
585 timeout.tv_sec = timeoutMs / 1000;
586 timeout.tv_usec = ( timeoutMs % 1000 ) * 1000;
588 if( select(socketFd + 1, NULL, &writefds, NULL, &timeout) > 0 )
589 return true;
591 return false;
594 bool Net::init()
596 #if defined(TORQUE_USE_WINSOCK)
597 if(!PlatformNetState::initCount)
599 #ifdef TORQUE_OS_XENON
600 // Configure startup parameters
601 XNetStartupParams xnsp;
602 memset( &xnsp, 0, sizeof( xnsp ) );
603 xnsp.cfgSizeOfStruct = sizeof( XNetStartupParams );
605 #ifndef TORQUE_DISABLE_PC_CONNECTIVITY
606 xnsp.cfgFlags = XNET_STARTUP_BYPASS_SECURITY;
607 Con::warnf("XNET_STARTUP_BYPASS_SECURITY enabled! This build can talk to PCs!");
608 #endif
610 AssertISV( !XNetStartup( &xnsp ), "Net::init - failed to init XNet" );
611 #endif
613 WSADATA stWSAData;
614 AssertISV( !WSAStartup( 0x0101, &stWSAData ), "Net::init - failed to init WinSock!" );
616 //logprintf("Winsock initialization %s", success ? "succeeded." : "failed!");
618 #endif
619 PlatformNetState::initCount++;
621 smConnectionNotify = new ConnectionNotifyEvent();
622 smConnectionAccept = new ConnectionAcceptedEvent();
623 smConnectionReceive = new ConnectionReceiveEvent();
624 smPacketReceive = new PacketReceiveEvent();
627 Process::notify(&Net::process, PROCESS_NET_ORDER);
629 return(true);
632 void Net::shutdown()
634 Process::remove(&Net::process);
636 while (gPolledSockets.size() > 0)
638 if (gPolledSockets[0] == NULL)
639 gPolledSockets.erase(gPolledSockets.begin());
640 else
641 closeConnectTo(gPolledSockets[0]->handleFd);
644 closePort();
645 PlatformNetState::initCount--;
647 // Destroy event handlers
648 delete smConnectionNotify;
649 delete smConnectionAccept;
650 delete smConnectionReceive;
651 delete smPacketReceive;
653 #if defined(TORQUE_USE_WINSOCK)
654 if(!PlatformNetState::initCount)
656 WSACleanup();
658 #ifdef TORQUE_OS_XENON
659 XNetCleanup();
660 #endif
662 #endif
665 // ipv4 version of name routines
667 static void NetAddressToIPSocket(const NetAddress *address, struct sockaddr_in *sockAddr)
669 dMemset(sockAddr, 0, sizeof(struct sockaddr_in));
670 sockAddr->sin_family = AF_INET;
671 sockAddr->sin_port = htons(address->port);
672 #if defined(TORQUE_OS_BSD) || defined(TORQUE_OS_MAC)
673 sockAddr->sin_len = sizeof(struct sockaddr_in);
674 #endif
675 if (address->type == NetAddress::IPBroadcastAddress)
677 sockAddr->sin_addr.s_addr = htonl(INADDR_BROADCAST);
679 else
681 dMemcpy(&sockAddr->sin_addr, &address->address.ipv4.netNum[0], 4);
685 static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address)
687 address->type = NetAddress::IPAddress;
688 address->port = ntohs(sockAddr->sin_port);
689 dMemcpy(&address->address.ipv4.netNum[0], &sockAddr->sin_addr, 4);
692 // ipv6 version of name routines
694 static void NetAddressToIPSocket6(const NetAddress *address, struct sockaddr_in6 *sockAddr)
696 dMemset(sockAddr, 0, sizeof(struct sockaddr_in6));
697 #ifdef SIN6_LEN
698 sockAddr->sin6_len = sizeof(struct sockaddr_in6);
699 #endif
700 sockAddr->sin6_family = AF_INET6;
701 sockAddr->sin6_port = ntohs(address->port);
703 if (address->type == NetAddress::IPV6MulticastAddress)
705 sockAddr->sin6_addr = PlatformNetState::multicast6Group.ipv6mr_multiaddr;
706 sockAddr->sin6_scope_id = PlatformNetState::multicast6Group.ipv6mr_interface;
708 else
710 sockAddr->sin6_flowinfo = address->address.ipv6.netFlow;
711 sockAddr->sin6_scope_id = address->address.ipv6.netScope;
712 dMemcpy(&sockAddr->sin6_addr, address->address.ipv6.netNum, sizeof(address->address.ipv6.netNum));
716 static void IPSocket6ToNetAddress(const struct sockaddr_in6 *sockAddr, NetAddress *address)
718 address->type = NetAddress::IPV6Address;
719 address->port = ntohs(sockAddr->sin6_port);
720 dMemcpy(address->address.ipv6.netNum, &sockAddr->sin6_addr, sizeof(address->address.ipv6.netNum));
721 address->address.ipv6.netFlow = sockAddr->sin6_flowinfo;
722 address->address.ipv6.netScope = sockAddr->sin6_scope_id;
727 NetSocket Net::openListenPort(U16 port, NetAddress::Type addressType)
729 if(Journal::IsPlaying())
731 U32 ret;
732 Journal::Read(&ret);
733 return NetSocket::fromHandle(ret);
736 Net::Error error = NoError;
737 NetAddress address;
738 if (Net::getListenAddress(addressType, &address) != Net::NoError)
739 error = Net::WrongProtocolType;
741 NetSocket handleFd = NetSocket::INVALID;
742 SOCKET sockId = InvalidSocketHandle;
744 if (error == NoError)
746 handleFd = openSocket();
747 sockId = PlatformNetState::smReservedSocketList.activate(handleFd, address.type == NetAddress::IPAddress ? AF_INET : AF_INET6, false, true);
750 if (error == NoError && (handleFd == NetSocket::INVALID || sockId == InvalidSocketHandle))
752 Con::errorf("Unable to open listen socket: %s", strerror(errno));
753 error = NotASocket;
754 handleFd = NetSocket::INVALID;
757 if (error == NoError)
759 address.port = port;
760 error = bindAddress(address, handleFd, false);
761 if (error != NoError)
763 Con::errorf("Unable to bind port %d: %s", port, strerror(errno));
764 closeSocket(handleFd);
765 handleFd = NetSocket::INVALID;
769 if (error == NoError)
771 error = listen(handleFd, 4);
772 if (error != NoError)
774 Con::errorf("Unable to listen on port %d: %s", port, strerror(errno));
775 closeSocket(handleFd);
776 handleFd = NetSocket::INVALID;
780 if (error == NoError)
782 setBlocking(handleFd, false);
783 addPolledSocket(handleFd, sockId, PolledSocket::Listening);
786 if(Journal::IsRecording())
787 Journal::Write(U32(handleFd.getHandle()));
789 return handleFd;
792 NetSocket Net::openConnectTo(const char *addressString)
794 if (Journal::IsPlaying())
796 U32 ret;
797 Journal::Read(&ret);
798 return NetSocket::fromHandle(ret);
801 NetAddress address;
802 NetSocket handleFd = NetSocket::INVALID;
803 Net::Error error = NoError;
805 error = Net::stringToAddress(addressString, &address, false);
807 if (error == NoError && address.type != NetAddress::IPAddress && address.type != NetAddress::IPV6Address)
809 error = Net::WrongProtocolType;
812 if (error != NoError || error == NeedHostLookup)
814 handleFd = openSocket();
817 // Attempt to connect or queue a lookup
818 if (error == NoError && address.type == NetAddress::IPAddress)
820 sockaddr_in ipAddr;
821 NetAddressToIPSocket(&address, &ipAddr);
822 SOCKET socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET, false, true);
823 if (socketFd != InvalidSocketHandle)
825 setBlocking(handleFd, false);
826 if (::connect(socketFd, (struct sockaddr *)&ipAddr, sizeof(ipAddr)) == -1 &&
827 errno != EINPROGRESS)
829 Con::errorf("Error connecting %s: %s",
830 addressString, strerror(errno));
831 closeSocket(handleFd);
832 handleFd = NetSocket::INVALID;
835 else
837 PlatformNetState::smReservedSocketList.remove(handleFd);
838 handleFd = NetSocket::INVALID;
841 if (handleFd != NetSocket::INVALID)
843 // add this socket to our list of polled sockets
844 addPolledSocket(handleFd, socketFd, PolledSocket::ConnectionPending);
847 else if (error == NoError && address.type == NetAddress::IPV6Address)
849 sockaddr_in6 ipAddr6;
850 NetAddressToIPSocket6(&address, &ipAddr6);
851 SOCKET socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET6, false, true);
852 if (::connect(socketFd, (struct sockaddr *)&ipAddr6, sizeof(ipAddr6)) == -1 &&
853 errno != EINPROGRESS)
855 setBlocking(handleFd, false);
856 Con::errorf("Error connecting %s: %s",
857 addressString, strerror(errno));
858 closeSocket(handleFd);
859 handleFd = NetSocket::INVALID;
861 else
863 PlatformNetState::smReservedSocketList.remove(handleFd);
864 handleFd = NetSocket::INVALID;
867 if (handleFd != NetSocket::INVALID)
869 // add this socket to our list of polled sockets
870 addPolledSocket(handleFd, socketFd, PolledSocket::ConnectionPending);
873 else if (error == Net::NeedHostLookup)
875 // need to do an asynchronous name lookup. first, add the socket
876 // to the polled list
877 char addr[256];
878 int port = 0;
879 int actualFamily = AF_UNSPEC;
880 if (PlatformNetState::extractAddressParts(addressString, addr, port, actualFamily))
882 addPolledSocket(handleFd, InvalidSocketHandle, PolledSocket::NameLookupRequired, addr, port);
883 // queue the lookup
884 gNetAsync.queueLookup(addressString, handleFd);
886 else
888 closeSocket(handleFd);
889 handleFd = NetSocket::INVALID;
892 else
894 closeSocket(handleFd);
895 handleFd = NetSocket::INVALID;
898 if (Journal::IsRecording())
899 Journal::Write(U32(handleFd.getHandle()));
900 return handleFd;
903 void Net::closeConnectTo(NetSocket handleFd)
905 if(Journal::IsPlaying())
906 return;
908 // if this socket is in the list of polled sockets, remove it
909 for (S32 i = 0; i < gPolledSockets.size(); ++i)
911 if (gPolledSockets[i] && gPolledSockets[i]->handleFd == handleFd)
913 delete gPolledSockets[i];
914 gPolledSockets[i] = NULL;
915 break;
919 closeSocket(handleFd);
922 Net::Error Net::sendtoSocket(NetSocket handleFd, const U8 *buffer, S32 bufferSize, S32 *outBufferWritten)
924 if(Journal::IsPlaying())
926 U32 e;
927 S32 outBytes;
928 Journal::Read(&e);
929 Journal::Read(&outBytes);
930 if (outBufferWritten)
931 *outBufferWritten = outBytes;
933 return (Net::Error) e;
936 S32 outBytes = 0;
937 Net::Error e = send(handleFd, buffer, bufferSize, &outBytes);
939 if (Journal::IsRecording())
941 Journal::Write(U32(e));
942 Journal::Write(outBytes);
945 if (outBufferWritten)
946 *outBufferWritten = outBytes;
948 return e;
951 bool Net::openPort(S32 port, bool doBind)
953 if (PlatformNetState::udpSocket != NetSocket::INVALID)
955 closeSocket(PlatformNetState::udpSocket);
956 PlatformNetState::udpSocket = NetSocket::INVALID;
958 if (PlatformNetState::udp6Socket != NetSocket::INVALID)
960 closeSocket(PlatformNetState::udp6Socket);
961 PlatformNetState::udp6Socket = NetSocket::INVALID;
964 // Update prefs
965 Net::smMulticastEnabled = Con::getBoolVariable("pref::Net::Multicast6Enabled", true);
966 Net::smIpv4Enabled = Con::getBoolVariable("pref::Net::IPV4Enabled", true);
967 Net::smIpv6Enabled = Con::getBoolVariable("pref::Net::IPV6Enabled", false);
969 // we turn off VDP in non-release builds because VDP does not support broadcast packets
970 // which are required for LAN queries (PC->Xbox connectivity). The wire protocol still
971 // uses the VDP packet structure, though.
972 S32 protocol = PlatformNetState::getDefaultGameProtocol();
974 SOCKET socketFd = InvalidSocketHandle;
975 NetAddress address;
976 NetAddress listenAddress;
977 char listenAddressStr[256];
979 if (Net::smIpv4Enabled)
981 if (Net::getListenAddress(NetAddress::IPAddress, &address) == Net::NoError)
983 address.port = port;
984 socketFd = ::socket(AF_INET, SOCK_DGRAM, protocol);
986 if (socketFd != InvalidSocketHandle)
988 PlatformNetState::udpSocket = PlatformNetState::smReservedSocketList.reserve(socketFd);
989 Net::Error error = NoError;
990 if (doBind)
992 error = bindAddress(address, PlatformNetState::udpSocket, true);
995 if (error == NoError)
996 error = setBufferSize(PlatformNetState::udpSocket, 32768 * 8);
998 #ifndef TORQUE_DISABLE_PC_CONNECTIVITY
999 if (error == NoError)
1000 error = setBroadcast(PlatformNetState::udpSocket, true);
1001 #endif
1003 if (error == NoError)
1004 error = setBlocking(PlatformNetState::udpSocket, false);
1006 if (error == NoError)
1008 error = PlatformNetState::getSocketAddress(socketFd, AF_INET, &listenAddress);
1009 if (error == NoError)
1011 Net::addressToString(&listenAddress, listenAddressStr);
1012 Con::printf("UDP initialized on ipv4 %s", listenAddressStr);
1016 if (error != NoError)
1018 closeSocket(PlatformNetState::udpSocket);
1019 PlatformNetState::udpSocket = NetSocket::INVALID;
1020 Con::printf("Unable to initialize UDP on ipv4 - error %d", error);
1024 else
1026 Con::errorf("Unable to initialize UDP on ipv4 - invalid address.");
1027 PlatformNetState::udpSocket = NetSocket::INVALID;
1031 if (Net::smIpv6Enabled)
1033 if (Net::getListenAddress(NetAddress::IPV6Address, &address) == Net::NoError)
1035 address.port = port;
1036 socketFd = ::socket(AF_INET6, SOCK_DGRAM, protocol);
1038 if (socketFd != InvalidSocketHandle)
1040 PlatformNetState::udp6Socket = PlatformNetState::smReservedSocketList.reserve(socketFd);
1042 Net::Error error = NoError;
1044 int v = 1;
1045 setsockopt(socketFd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&v, sizeof(v));
1046 PlatformNetState::getLastError();
1048 if (doBind)
1050 error = bindAddress(address, PlatformNetState::udp6Socket, true);
1053 if (error == NoError)
1054 error = setBufferSize(PlatformNetState::udp6Socket, 32768 * 8);
1056 if (error == NoError)
1057 error = setBlocking(PlatformNetState::udp6Socket, false);
1059 if (error == NoError)
1061 error = PlatformNetState::getSocketAddress(socketFd, AF_INET6, &listenAddress);
1062 if (error == NoError)
1064 Net::addressToString(&listenAddress, listenAddressStr);
1065 Con::printf("UDP initialized on ipv6 %s", listenAddressStr);
1069 if (error != NoError)
1071 closeSocket(PlatformNetState::udp6Socket);
1072 PlatformNetState::udp6Socket = NetSocket::INVALID;
1073 Con::printf("Unable to initialize UDP on ipv6 - error %d", error);
1076 if (Net::smMulticastEnabled && doBind)
1078 Net::enableMulticast();
1080 else
1082 Net::disableMulticast();
1088 PlatformNetState::netPort = port;
1090 return PlatformNetState::udpSocket != NetSocket::INVALID || PlatformNetState::udp6Socket != NetSocket::INVALID;
1093 NetSocket Net::getPort()
1095 return PlatformNetState::udpSocket;
1098 void Net::closePort()
1100 if (PlatformNetState::udpSocket != NetSocket::INVALID)
1101 closeSocket(PlatformNetState::udpSocket);
1102 if (PlatformNetState::udp6Socket != NetSocket::INVALID)
1103 closeSocket(PlatformNetState::udp6Socket);
1106 Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32 bufferSize)
1108 if(Journal::IsPlaying())
1109 return NoError;
1111 SOCKET socketFd;
1113 if(address->type == NetAddress::IPAddress || address->type == NetAddress::IPBroadcastAddress)
1115 socketFd = PlatformNetState::smReservedSocketList.resolve(PlatformNetState::udpSocket);
1116 if (socketFd != InvalidSocketHandle)
1118 sockaddr_in ipAddr;
1119 NetAddressToIPSocket(address, &ipAddr);
1121 if (::sendto(socketFd, (const char*)buffer, bufferSize, 0,
1122 (sockaddr *)&ipAddr, sizeof(sockaddr_in)) == SOCKET_ERROR)
1123 return PlatformNetState::getLastError();
1124 else
1125 return NoError;
1127 else
1129 return NotASocket;
1132 else if (address->type == NetAddress::IPV6Address || address->type == NetAddress::IPV6MulticastAddress)
1134 socketFd = PlatformNetState::smReservedSocketList.resolve(address->type == NetAddress::IPV6MulticastAddress ? PlatformNetState::multicast6Socket : PlatformNetState::udp6Socket);
1136 if (socketFd != InvalidSocketHandle)
1138 sockaddr_in6 ipAddr;
1139 NetAddressToIPSocket6(address, &ipAddr);
1140 if (::sendto(socketFd, (const char*)buffer, bufferSize, 0,
1141 (struct sockaddr *) &ipAddr, sizeof(sockaddr_in6)) == SOCKET_ERROR)
1142 return PlatformNetState::getLastError();
1143 else
1144 return NoError;
1146 else
1148 return NotASocket;
1152 return WrongProtocolType;
1155 void Net::process()
1157 // Process listening sockets
1158 processListenSocket(PlatformNetState::udpSocket);
1159 processListenSocket(PlatformNetState::udp6Socket);
1161 // process the polled sockets. This blob of code performs functions
1162 // similar to WinsockProc in winNet.cc
1164 if (gPolledSockets.size() == 0)
1165 return;
1167 S32 optval;
1168 socklen_t optlen = sizeof(S32);
1169 S32 bytesRead;
1170 Net::Error err;
1171 bool removeSock = false;
1172 PolledSocket *currentSock = NULL;
1173 NetSocket incomingHandleFd = NetSocket::INVALID;
1174 NetAddress out_h_addr;
1175 S32 out_h_length = 0;
1176 RawData readBuff;
1177 NetSocket removeSockHandle;
1179 for (S32 i = 0; i < gPolledSockets.size();
1180 /* no increment, this is done at end of loop body */)
1182 removeSock = false;
1183 currentSock = gPolledSockets[i];
1185 // Cleanup if we've removed it
1186 if (currentSock == NULL)
1188 gPolledSockets.erase(i);
1189 continue;
1192 switch (currentSock->state)
1194 case PolledSocket::InvalidState:
1195 Con::errorf("Error, InvalidState socket in polled sockets list");
1196 break;
1197 case PolledSocket::ConnectionPending:
1198 // see if it is now connected
1199 #ifdef TORQUE_OS_XENON
1200 // WSASetLastError has no return value, however part of the SO_ERROR behavior
1201 // is to clear the last error, so this needs to be done here.
1202 if( ( optval = _getLastErrorAndClear() ) == -1 )
1203 #else
1204 if (getsockopt(currentSock->fd, SOL_SOCKET, SO_ERROR,
1205 (char*)&optval, &optlen) == -1)
1206 #endif
1208 Con::errorf("Error getting socket options: %s", strerror(errno));
1210 removeSock = true;
1211 removeSockHandle = currentSock->handleFd;
1213 smConnectionNotify->trigger(currentSock->handleFd, Net::ConnectFailed);
1215 else
1217 if (optval == EINPROGRESS)
1218 // still connecting...
1219 break;
1221 if (optval == 0)
1223 // poll for writable status to be sure we're connected.
1224 bool ready = netSocketWaitForWritable(currentSock->handleFd,0);
1225 if(!ready)
1226 break;
1228 currentSock->state = PolledSocket::Connected;
1229 smConnectionNotify->trigger(currentSock->handleFd, Net::Connected);
1231 else
1233 // some kind of error
1234 Con::errorf("Error connecting: %s", strerror(errno));
1236 removeSock = true;
1237 removeSockHandle = currentSock->handleFd;
1239 smConnectionNotify->trigger(currentSock->handleFd, Net::ConnectFailed);
1242 break;
1243 case PolledSocket::Connected:
1245 // try to get some data
1246 bytesRead = 0;
1247 readBuff.alloc(MaxPacketDataSize);
1248 err = Net::recv(currentSock->handleFd, (U8*)readBuff.data, MaxPacketDataSize, &bytesRead);
1249 if(err == Net::NoError)
1251 if (bytesRead > 0)
1253 // got some data, post it
1254 readBuff.size = bytesRead;
1255 smConnectionReceive->trigger(currentSock->handleFd, readBuff);
1257 else
1259 // ack! this shouldn't happen
1260 if (bytesRead < 0)
1261 Con::errorf("Unexpected error on socket: %s", strerror(errno));
1263 removeSock = true;
1264 removeSockHandle = currentSock->handleFd;
1266 // zero bytes read means EOF
1267 smConnectionNotify->trigger(currentSock->handleFd, Net::Disconnected);
1270 else if (err != Net::NoError && err != Net::WouldBlock)
1272 Con::errorf("Error reading from socket: %s", strerror(errno));
1274 removeSock = true;
1275 removeSockHandle = currentSock->handleFd;
1277 smConnectionNotify->trigger(currentSock->handleFd, Net::Disconnected);
1279 break;
1280 case PolledSocket::NameLookupRequired:
1281 U32 newState;
1283 // is the lookup complete?
1284 if (!gNetAsync.checkLookup(
1285 currentSock->handleFd, &out_h_addr, &out_h_length,
1286 sizeof(out_h_addr)))
1287 break;
1289 if (out_h_length == -1)
1291 Con::errorf("DNS lookup failed: %s", currentSock->remoteAddr);
1292 newState = Net::DNSFailed;
1293 removeSock = true;
1294 removeSockHandle = currentSock->handleFd;
1296 else
1298 // try to connect
1299 out_h_addr.port = currentSock->remotePort;
1300 const sockaddr *ai_addr = NULL;
1301 int ai_addrlen = 0;
1302 sockaddr_in socketAddress;
1303 sockaddr_in6 socketAddress6;
1305 if (out_h_addr.type == NetAddress::IPAddress)
1307 ai_addr = (const sockaddr*)&socketAddress;
1308 ai_addrlen = sizeof(socketAddress);
1309 NetAddressToIPSocket(&out_h_addr, &socketAddress);
1311 currentSock->fd = PlatformNetState::smReservedSocketList.activate(currentSock->handleFd, AF_INET, false);
1312 setBlocking(currentSock->handleFd, false);
1314 #ifdef TORQUE_DEBUG_LOOKUPS
1315 char addrString[256];
1316 NetAddress addr;
1317 IPSocketToNetAddress(&socketAddress, &addr);
1318 Net::addressToString(&addr, addrString);
1319 Con::printf("DNS: lookup resolved to %s", addrString);
1320 #endif
1322 else if (out_h_addr.type == NetAddress::IPV6Address)
1324 ai_addr = (const sockaddr*)&socketAddress6;
1325 ai_addrlen = sizeof(socketAddress6);
1326 NetAddressToIPSocket6(&out_h_addr, &socketAddress6);
1328 currentSock->fd = PlatformNetState::smReservedSocketList.activate(currentSock->handleFd, AF_INET6, false);
1329 setBlocking(currentSock->handleFd, false);
1331 #ifdef TORQUE_DEBUG_LOOKUPS
1332 char addrString[256];
1333 NetAddress addr;
1334 IPSocket6ToNetAddress(&socketAddress6, &addr);
1335 Net::addressToString(&addr, addrString);
1336 Con::printf("DNS: lookup resolved to %s", addrString);
1337 #endif
1339 else
1341 Con::errorf("Error connecting to %s: Invalid Protocol",
1342 currentSock->remoteAddr);
1343 newState = Net::ConnectFailed;
1344 removeSock = true;
1345 removeSockHandle = currentSock->handleFd;
1348 if (ai_addr)
1350 if (::connect(currentSock->fd, ai_addr,
1351 ai_addrlen) == -1)
1353 err = PlatformNetState::getLastError();
1354 if (err != Net::WouldBlock)
1356 Con::errorf("Error connecting to %s: %u",
1357 currentSock->remoteAddr, err);
1358 newState = Net::ConnectFailed;
1359 removeSock = true;
1360 removeSockHandle = currentSock->handleFd;
1362 else
1364 newState = Net::DNSResolved;
1365 currentSock->state = PolledSocket::ConnectionPending;
1368 else
1370 newState = Net::Connected;
1371 currentSock->state = Connected;
1376 smConnectionNotify->trigger(currentSock->handleFd, newState);
1377 break;
1378 case PolledSocket::Listening:
1379 NetAddress incomingAddy;
1381 incomingHandleFd = Net::accept(currentSock->handleFd, &incomingAddy);
1382 if(incomingHandleFd != NetSocket::INVALID)
1384 setBlocking(incomingHandleFd, false);
1385 addPolledSocket(incomingHandleFd, PlatformNetState::smReservedSocketList.resolve(incomingHandleFd), Connected);
1386 smConnectionAccept->trigger(currentSock->handleFd, incomingHandleFd, incomingAddy);
1388 break;
1391 // only increment index if we're not removing the connection, since
1392 // the removal will shift the indices down by one
1393 if (removeSock)
1394 closeConnectTo(removeSockHandle);
1395 else
1396 i++;
1400 void Net::processListenSocket(NetSocket socketHandle)
1402 if (socketHandle == NetSocket::INVALID)
1403 return;
1405 sockaddr_storage sa;
1406 sa.ss_family = AF_UNSPEC;
1407 NetAddress srcAddress;
1408 RawData tmpBuffer;
1409 tmpBuffer.alloc(Net::MaxPacketDataSize);
1411 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(socketHandle);
1413 for (;;)
1415 socklen_t addrLen = sizeof(sa);
1416 S32 bytesRead = -1;
1418 if (socketHandle != NetSocket::INVALID)
1419 bytesRead = ::recvfrom(socketFd, (char *)tmpBuffer.data, Net::MaxPacketDataSize, 0, (struct sockaddr*)&sa, &addrLen);
1421 if (bytesRead == -1)
1422 break;
1424 if (sa.ss_family == AF_INET)
1425 IPSocketToNetAddress((sockaddr_in *)&sa, &srcAddress);
1426 else if (sa.ss_family == AF_INET6)
1427 IPSocket6ToNetAddress((sockaddr_in6 *)&sa, &srcAddress);
1428 else
1429 continue;
1431 if (bytesRead <= 0)
1432 continue;
1434 if (srcAddress.type == NetAddress::IPAddress &&
1435 srcAddress.address.ipv4.netNum[0] == 127 &&
1436 srcAddress.address.ipv4.netNum[1] == 0 &&
1437 srcAddress.address.ipv4.netNum[2] == 0 &&
1438 srcAddress.address.ipv4.netNum[3] == 1 &&
1439 srcAddress.port == PlatformNetState::netPort)
1440 continue;
1442 tmpBuffer.size = bytesRead;
1444 smPacketReceive->trigger(srcAddress, tmpBuffer);
1448 NetSocket Net::openSocket()
1450 return PlatformNetState::smReservedSocketList.reserve();
1453 Net::Error Net::closeSocket(NetSocket handleFd)
1455 if(handleFd != NetSocket::INVALID)
1457 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1458 PlatformNetState::smReservedSocketList.remove(handleFd);
1460 if(!::closesocket(socketFd))
1461 return NoError;
1462 else
1463 return PlatformNetState::getLastError();
1465 else
1466 return NotASocket;
1469 Net::Error Net::connect(NetSocket handleFd, const NetAddress *address)
1471 if(!(address->type == NetAddress::IPAddress || address->type == NetAddress::IPV6Address))
1472 return WrongProtocolType;
1474 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1476 if (address->type == NetAddress::IPAddress)
1478 sockaddr_in socketAddress;
1479 NetAddressToIPSocket(address, &socketAddress);
1481 if (socketFd == InvalidSocketHandle)
1483 socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET, false);
1486 if (!::connect(socketFd, (struct sockaddr *) &socketAddress, sizeof(socketAddress)))
1487 return NoError;
1489 else if (address->type == NetAddress::IPV6Address)
1491 sockaddr_in6 socketAddress;
1492 NetAddressToIPSocket6(address, &socketAddress);
1494 if (socketFd == InvalidSocketHandle)
1496 socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET6, false);
1499 if (!::connect(socketFd, (struct sockaddr *) &socketAddress, sizeof(socketAddress)))
1500 return NoError;
1503 return PlatformNetState::getLastError();
1506 Net::Error Net::listen(NetSocket handleFd, S32 backlog)
1508 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1509 if (socketFd == InvalidSocketHandle)
1510 return NotASocket;
1512 if(!::listen(socketFd, backlog))
1513 return NoError;
1514 return PlatformNetState::getLastError();
1517 NetSocket Net::accept(NetSocket handleFd, NetAddress *remoteAddress)
1519 sockaddr_storage addr;
1520 socklen_t addrLen = sizeof(addr);
1522 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1523 if (socketFd == InvalidSocketHandle)
1524 return NetSocket::INVALID;
1526 SOCKET acceptedSocketFd = ::accept(socketFd, (sockaddr *)&addr, &addrLen);
1527 if (acceptedSocketFd != InvalidSocketHandle)
1529 if (addr.ss_family == AF_INET)
1531 // ipv4
1532 IPSocketToNetAddress(((struct sockaddr_in*)&addr), remoteAddress);
1534 else if (addr.ss_family == AF_INET6)
1536 // ipv6
1537 IPSocket6ToNetAddress(((struct sockaddr_in6*)&addr), remoteAddress);
1540 NetSocket newHandleFd = PlatformNetState::smReservedSocketList.reserve(acceptedSocketFd);
1541 return newHandleFd;
1544 return NetSocket::INVALID;
1547 Net::Error Net::bindAddress(const NetAddress &address, NetSocket handleFd, bool useUDP)
1549 int error = 0;
1550 sockaddr_storage socketAddress;
1552 dMemset(&socketAddress, '\0', sizeof(socketAddress));
1554 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1555 if (socketFd == InvalidSocketHandle)
1557 if (handleFd.getHandle() == -1)
1558 return NotASocket;
1561 if (address.type == NetAddress::IPAddress)
1563 socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET, useUDP);
1564 NetAddressToIPSocket(&address, (struct sockaddr_in*)&socketAddress);
1565 error = ::bind(socketFd, (struct sockaddr*)&socketAddress, sizeof(sockaddr_in));
1567 else if (address.type == NetAddress::IPV6Address)
1569 socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET6, useUDP);
1570 NetAddressToIPSocket6(&address, (struct sockaddr_in6*)&socketAddress);
1571 error = ::bind(socketFd, (struct sockaddr*)&socketAddress, sizeof(sockaddr_in6));
1574 if (!error)
1575 return NoError;
1576 return PlatformNetState::getLastError();
1579 Net::Error Net::setBufferSize(NetSocket handleFd, S32 bufferSize)
1581 S32 error;
1582 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1583 if (socketFd == InvalidSocketHandle)
1584 return NotASocket;
1586 error = ::setsockopt(socketFd, SOL_SOCKET, SO_RCVBUF, (char *) &bufferSize, sizeof(bufferSize));
1587 if(!error)
1588 error = ::setsockopt(socketFd, SOL_SOCKET, SO_SNDBUF, (char *) &bufferSize, sizeof(bufferSize));
1589 if(!error)
1590 return NoError;
1591 return PlatformNetState::getLastError();
1594 Net::Error Net::setBroadcast(NetSocket handleFd, bool broadcast)
1596 S32 bc = broadcast;
1597 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1598 if (socketFd == InvalidSocketHandle)
1599 return NotASocket;
1600 S32 error = ::setsockopt(socketFd, SOL_SOCKET, SO_BROADCAST, (char*)&bc, sizeof(bc));
1601 if(!error)
1602 return NoError;
1603 return PlatformNetState::getLastError();
1606 Net::Error Net::setBlocking(NetSocket handleFd, bool blockingIO)
1608 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1609 if (socketFd == InvalidSocketHandle)
1610 return NotASocket;
1612 unsigned long notblock = !blockingIO;
1613 S32 error = ioctl(socketFd, FIONBIO, &notblock);
1614 if(!error)
1615 return NoError;
1616 return PlatformNetState::getLastError();
1619 Net::Error Net::getListenAddress(const NetAddress::Type type, NetAddress *address, bool forceDefaults)
1621 if (type == NetAddress::IPAddress)
1623 const char* serverIP = forceDefaults ? NULL : Con::getVariable("pref::Net::BindAddress");
1624 if (!serverIP || serverIP[0] == '\0')
1626 address->type = type;
1627 address->port = 0;
1628 *((U32*)address->address.ipv4.netNum) = INADDR_ANY;
1629 return Net::NoError;
1631 else
1633 return Net::stringToAddress(serverIP, address, false);
1636 else if (type == NetAddress::IPBroadcastAddress)
1638 address->type = type;
1639 address->port = 0;
1640 *((U32*)address->address.ipv4.netNum) = INADDR_BROADCAST;
1641 return Net::NoError;
1643 else if (type == NetAddress::IPV6Address)
1645 const char* serverIP6 = forceDefaults ? NULL : Con::getVariable("pref::Net::BindAddress6");
1646 if (!serverIP6 || serverIP6[0] == '\0')
1648 sockaddr_in6 addr;
1649 dMemset(&addr, '\0', sizeof(addr));
1651 addr.sin6_port = 0;
1652 addr.sin6_addr = in6addr_any;
1654 IPSocket6ToNetAddress(&addr, address);
1655 return Net::NoError;
1657 else
1659 return Net::stringToAddress(serverIP6, address, false);
1662 else if (type == NetAddress::IPV6MulticastAddress)
1664 const char* multicastAddressValue = forceDefaults ? NULL : Con::getVariable("pref::Net::Multicast6Address");
1665 if (!multicastAddressValue || multicastAddressValue[0] == '\0')
1667 multicastAddressValue = TORQUE_NET_DEFAULT_MULTICAST_ADDRESS;
1670 return Net::stringToAddress(multicastAddressValue, address, false);
1672 else
1674 return Net::WrongProtocolType;
1678 void Net::getIdealListenAddress(NetAddress *address)
1680 dMemset(address, '\0', sizeof(NetAddress));
1682 if (Net::smIpv6Enabled)
1684 if (Net::getListenAddress(NetAddress::IPV6Address, address) == NeedHostLookup)
1686 Net::getListenAddress(NetAddress::IPV6Address, address, true);
1689 else
1691 if (Net::getListenAddress(NetAddress::IPAddress, address) == NeedHostLookup)
1693 Net::getListenAddress(NetAddress::IPAddress, address, true);
1698 Net::Error Net::send(NetSocket handleFd, const U8 *buffer, S32 bufferSize, S32 *outBytesWritten)
1700 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1701 if (socketFd == InvalidSocketHandle)
1702 return NotASocket;
1704 errno = 0;
1705 S32 bytesWritten = ::send(socketFd, (const char*)buffer, bufferSize, 0);
1707 if (outBytesWritten)
1709 *outBytesWritten = outBytesWritten < 0 ? 0 : bytesWritten;
1712 return PlatformNetState::getLastError();
1715 Net::Error Net::recv(NetSocket handleFd, U8 *buffer, S32 bufferSize, S32 *bytesRead)
1717 SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
1718 if (socketFd == InvalidSocketHandle)
1719 return NotASocket;
1721 *bytesRead = ::recv(socketFd, (char*)buffer, bufferSize, 0);
1722 if(*bytesRead == -1)
1723 return PlatformNetState::getLastError();
1724 return NoError;
1727 bool Net::compareAddresses(const NetAddress *a1, const NetAddress *a2)
1729 return a1->isSameAddressAndPort(*a2);
1732 Net::Error Net::stringToAddress(const char *addressString, NetAddress *address, bool hostLookup, int requiredFamily)
1734 char addr[256];
1735 int port = 0;
1736 int actualFamily = AF_UNSPEC;
1737 if (!PlatformNetState::extractAddressParts(addressString, addr, port, actualFamily))
1739 return WrongProtocolType;
1742 // Make sure family matches (in cast we have IP: stuff in address)
1743 if (requiredFamily != AF_UNSPEC && actualFamily != AF_UNSPEC && (actualFamily != requiredFamily))
1745 return WrongProtocolType;
1748 if (actualFamily == AF_UNSPEC)
1750 actualFamily = requiredFamily;
1753 addressString = addr;
1754 dMemset(address, '\0', sizeof(NetAddress));
1756 if (!dStricmp(addressString, "broadcast"))
1758 address->type = NetAddress::IPBroadcastAddress;
1759 if (!(actualFamily == AF_UNSPEC || actualFamily == AF_INET))
1760 return WrongProtocolType;
1762 if (port != 0)
1763 address->port = port;
1764 else
1765 address->port = PlatformNetState::defaultPort;
1767 else if (!dStricmp(addressString, "multicast"))
1769 address->type = NetAddress::IPV6MulticastAddress;
1770 if (!(actualFamily == AF_UNSPEC || actualFamily == AF_INET6))
1771 return WrongProtocolType;
1773 if (port != 0)
1774 address->port = port;
1775 else
1776 address->port = PlatformNetState::defaultPort;
1778 else
1780 sockaddr_in ipAddr;
1781 sockaddr_in6 ipAddr6;
1783 dMemset(&ipAddr, 0, sizeof(ipAddr));
1784 dMemset(&ipAddr6, 0, sizeof(ipAddr6));
1786 bool hasInterface = dStrchr(addressString, '%') != NULL; // if we have an interface, best use getaddrinfo to parse
1788 // Check if we've got a simple ipv4 / ipv6
1790 if (inet_pton(AF_INET, addressString, &ipAddr.sin_addr) == 1)
1792 if (!(actualFamily == AF_UNSPEC || actualFamily == AF_INET))
1793 return WrongProtocolType;
1794 IPSocketToNetAddress(((struct sockaddr_in*)&ipAddr), address);
1796 if (port != 0)
1797 address->port = port;
1798 else
1799 address->port = PlatformNetState::defaultPort;
1801 return NoError;
1803 else if (!hasInterface && inet_pton(AF_INET6, addressString, &ipAddr6.sin6_addr) == 1)
1805 if (!(actualFamily == AF_UNSPEC || actualFamily == AF_INET6))
1806 return WrongProtocolType;
1807 IPSocket6ToNetAddress(((struct sockaddr_in6*)&ipAddr6), address);
1809 if (port != 0)
1810 address->port = port;
1811 else
1812 address->port = PlatformNetState::defaultPort;
1814 return NoError;
1816 else
1818 if (!hostLookup && !hasInterface)
1819 return NeedHostLookup;
1821 struct addrinfo hint, *res = NULL;
1822 dMemset(&hint, 0, sizeof(hint));
1823 hint.ai_family = actualFamily;
1824 hint.ai_flags = hostLookup ? 0 : AI_NUMERICHOST;
1826 if (getaddrinfo(addressString, NULL, &hint, &res) == 0)
1828 if (actualFamily != AF_UNSPEC)
1830 // Prefer desired protocol
1831 res = PlatformNetState::pickAddressByProtocol(res, actualFamily);
1834 if (res && res->ai_family == AF_INET)
1836 // ipv4
1837 IPSocketToNetAddress(((struct sockaddr_in*)res->ai_addr), address);
1839 else if (res && res->ai_family == AF_INET6)
1841 // ipv6
1842 IPSocket6ToNetAddress(((struct sockaddr_in6*)res->ai_addr), address);
1844 else
1846 // unknown
1847 return UnknownError;
1850 if (port != 0)
1851 address->port = port;
1852 else
1853 address->port = PlatformNetState::defaultPort;
1858 return NoError;
1861 void Net::addressToString(const NetAddress *address, char addressString[256])
1863 if(address->type == NetAddress::IPAddress || address->type == NetAddress::IPBroadcastAddress)
1865 sockaddr_in ipAddr;
1866 NetAddressToIPSocket(address, &ipAddr);
1868 if (ipAddr.sin_addr.s_addr == htonl(INADDR_BROADCAST) || address->type == NetAddress::IPBroadcastAddress)
1870 if (ipAddr.sin_port == 0)
1871 dSprintf(addressString, 256, "IP:Broadcast");
1872 else
1873 dSprintf(addressString, 256, "IP:Broadcast:%d", ntohs(ipAddr.sin_port));
1875 else
1877 char buffer[256];
1878 buffer[0] = '\0';
1879 sockaddr_in ipAddr;
1880 NetAddressToIPSocket(address, &ipAddr);
1881 inet_ntop(AF_INET, &(ipAddr.sin_addr), buffer, sizeof(buffer));
1882 if (ipAddr.sin_port == 0)
1883 dSprintf(addressString, 256, "IP:%s", buffer);
1884 else
1885 dSprintf(addressString, 256, "IP:%s:%i", buffer, ntohs(ipAddr.sin_port));
1888 else if (address->type == NetAddress::IPV6Address)
1890 char buffer[256];
1891 buffer[0] = '\0';
1892 sockaddr_in6 ipAddr;
1893 NetAddressToIPSocket6(address, &ipAddr);
1894 inet_ntop(AF_INET6, &(ipAddr.sin6_addr), buffer, sizeof(buffer));
1895 if (ipAddr.sin6_port == 0)
1896 dSprintf(addressString, 256, "IP6:%s", buffer);
1897 else
1898 dSprintf(addressString, 256, "IP6:[%s]:%i", buffer, ntohs(ipAddr.sin6_port));
1900 else if (address->type == NetAddress::IPV6MulticastAddress)
1902 if (address->port == 0)
1903 dSprintf(addressString, 256, "IP6:Multicast");
1904 else
1905 dSprintf(addressString, 256, "IP6:Multicast:%d", address->port);
1907 else
1909 *addressString = 0;
1910 return;
1914 void Net::enableMulticast()
1916 SOCKET socketFd;
1918 if (Net::smIpv6Enabled)
1920 socketFd = PlatformNetState::smReservedSocketList.resolve(PlatformNetState::udp6Socket);
1922 if (socketFd != InvalidSocketHandle)
1924 PlatformNetState::multicast6Socket = PlatformNetState::udp6Socket;
1926 Net::Error error = NoError;
1928 if (error == NoError)
1930 unsigned long multicastTTL = 1;
1932 if (setsockopt(socketFd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1933 (char*)&multicastTTL, sizeof(multicastTTL)) < 0)
1935 error = PlatformNetState::getLastError();
1939 // Find multicast to bind to...
1941 NetAddress multicastAddress;
1942 sockaddr_in6 multicastSocketAddress;
1944 const char *multicastAddressValue = Con::getVariable("pref::Net::Multicast6Address");
1945 if (!multicastAddressValue || multicastAddressValue[0] == '\0')
1947 multicastAddressValue = TORQUE_NET_DEFAULT_MULTICAST_ADDRESS;
1950 error = Net::stringToAddress(multicastAddressValue, &multicastAddress, false);
1952 if (error == NoError)
1954 dMemset(&PlatformNetState::multicast6Group, '\0', sizeof(&PlatformNetState::multicast6Group));
1955 NetAddressToIPSocket6(&multicastAddress, &multicastSocketAddress);
1956 dMemcpy(&PlatformNetState::multicast6Group.ipv6mr_multiaddr, &multicastSocketAddress.sin6_addr, sizeof(PlatformNetState::multicast6Group.ipv6mr_multiaddr));
1959 // Setup group
1961 if (error == NoError)
1963 const char *multicastInterface = Con::getVariable("pref::Net::Multicast6Interface");
1965 if (multicastInterface && multicastInterface[0] != '\0')
1967 #ifdef TORQUE_USE_WINSOCK
1968 PlatformNetState::multicast6Group.ipv6mr_interface = dAtoi(multicastInterface);
1969 #else
1970 PlatformNetState::multicast6Group.ipv6mr_interface = if_nametoindex(multicastInterface);
1971 #endif
1973 else
1975 PlatformNetState::multicast6Group.ipv6mr_interface = 0; // 0 == accept from any interface
1978 if (PlatformNetState::multicast6Group.ipv6mr_interface && error == NoError)
1980 if (setsockopt(socketFd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&PlatformNetState::multicast6Group.ipv6mr_interface, sizeof(PlatformNetState::multicast6Group.ipv6mr_interface)) < 0)
1982 error = PlatformNetState::getLastError();
1986 if (error == NoError && setsockopt(socketFd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&PlatformNetState::multicast6Group, sizeof(PlatformNetState::multicast6Group)) < 0)
1988 error = PlatformNetState::getLastError();
1993 if (error == NoError)
1995 NetAddress listenAddress;
1996 char listenAddressStr[256];
1997 Net::addressToString(&multicastAddress, listenAddressStr);
1998 Con::printf("Multicast initialized on %s", listenAddressStr);
2001 if (error != NoError)
2003 PlatformNetState::multicast6Socket = NetSocket::INVALID;
2004 Con::printf("Unable to multicast UDP - error %d", error);
2010 void Net::disableMulticast()
2012 if (PlatformNetState::multicast6Socket != NetSocket::INVALID)
2014 PlatformNetState::multicast6Socket = NetSocket::INVALID;
2018 bool Net::isMulticastEnabled()
2020 return PlatformNetState::multicast6Socket != NetSocket::INVALID;
2023 U32 NetAddress::getHash() const
2025 U32 value = 0;
2026 switch (type)
2028 case NetAddress::IPAddress:
2029 value = Torque::hash((const U8*)&address.ipv4.netNum, sizeof(address.ipv4.netNum), 0);
2030 break;
2031 case NetAddress::IPV6Address:
2032 value = Torque::hash((const U8*)address.ipv6.netNum, sizeof(address.ipv6.netNum), 0);
2033 break;
2034 default:
2035 value = 0;
2036 break;
2038 return value;
2041 bool Net::isAddressTypeAvailable(NetAddress::Type addressType)
2043 switch (addressType)
2045 case NetAddress::IPAddress:
2046 return PlatformNetState::udpSocket != NetSocket::INVALID;
2047 case NetAddress::IPV6Address:
2048 return PlatformNetState::udp6Socket != NetSocket::INVALID;
2049 case NetAddress::IPBroadcastAddress:
2050 return PlatformNetState::udpSocket != NetSocket::INVALID;
2051 case NetAddress::IPV6MulticastAddress:
2052 return PlatformNetState::multicast6Socket != NetSocket::INVALID;
2053 default:
2054 return false;