1 //-----------------------------------------------------------------------------
2 // Copyright (c) 2012 GarageGames, LLC
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
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"
30 //#define TORQUE_DEBUG_LOOKUPS
33 #if defined (TORQUE_OS_WIN)
34 #define TORQUE_USE_WINSOCK
39 #define EINPROGRESS WSAEINPROGRESS
42 #define ioctl ioctlsocket
44 typedef S32 socklen_t
;
46 #elif defined ( TORQUE_OS_MAC )
49 #include <sys/types.h>
50 #include <sys/socket.h>
52 #include <arpa/inet.h>
54 #include <netinet/in.h>
56 #include <sys/ioctl.h>
59 typedef sockaddr_in SOCKADDR_IN
;
60 typedef sockaddr
* PSOCKADDR
;
61 typedef sockaddr SOCKADDR
;
62 typedef in_addr IN_ADDR
;
65 #define INVALID_SOCKET -1
66 #define SOCKET_ERROR -1
68 #define closesocket close
70 #elif defined( TORQUE_OS_LINUX )
73 #include <sys/types.h>
74 #include <sys/socket.h>
76 #include <arpa/inet.h>
78 #include <netinet/in.h>
80 #include <sys/ioctl.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
;
91 #define INVALID_SOCKET -1
92 #define SOCKET_ERROR -1
94 #define closesocket close
96 #elif defined( TORQUE_OS_XENON )
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 );
118 #if defined(TORQUE_USE_WINSOCK)
119 static const char* strerror_wsa( S32 code
)
123 #define E( name ) case name: return #name;
124 E( WSANOTINITIALISED
);
129 E( WSAEADDRNOTAVAIL
);
130 E( WSAEAFNOSUPPORT
);
135 E( WSAEHOSTUNREACH
);
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
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
;
186 ~ReservedSocketList()
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();
230 return Net::WouldBlock
;
232 return Net::UnknownError
;
235 int theError
= errno
;
237 return Net::WouldBlock
;
240 if (errno
== EINPROGRESS
)
241 return Net::WouldBlock
;
243 return Net::UnknownError
;
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
;
254 #ifdef TORQUE_DISABLE_PC_CONNECTIVITY
255 // Xbox uses a VDP (voice/data protocol) socket for networking
256 protocol
= IPPROTO_VDP
;
263 struct addrinfo
* pickAddressByProtocol(struct addrinfo
* addr
, int protocol
)
265 for (addr
; addr
!= NULL
; addr
= addr
->ai_next
)
267 if (addr
->ai_family
== protocol
)
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
)
278 outFamily
= AF_UNSPEC
;
280 if (!dStrnicmp(addressString
, "ipx:", 4))
281 // ipx support deprecated
284 if (!dStrnicmp(addressString
, "ip:", 3))
286 addressString
+= 3; // eat off the ip:
289 else if (!dStrnicmp(addressString
, "ip6:", 4))
291 addressString
+= 4; // eat off the ip6:
292 outFamily
= AF_INET6
;
295 if (strlen(addressString
) > 255)
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
, ']');
309 // Sort out the :port after the ]
310 *portString
++ = '\0';
311 if (*portString
!= ':')
317 *portString
++ = '\0';
321 if (outFamily
== AF_UNSPEC
)
323 outFamily
= AF_INET6
;
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
;
334 while (*scan
!= '\0' && colonCount
< 2)
341 // either ipv4 or host
342 portString
= dStrchr(outAddress
, ':');
346 *portString
++ = '\0';
349 else if (outFamily
== AF_UNSPEC
)
352 outFamily
= AF_INET6
;
358 outPort
= dAtoi(portString
);
364 Net::Error
getSocketAddress(SOCKET socketFd
, int requiredFamily
, NetAddress
*outAddress
)
366 Net::Error error
= Net::UnknownError
;
368 if (requiredFamily
== AF_INET
)
371 int len
= sizeof(ipAddr
);
372 if (getsockname(socketFd
, (struct sockaddr
*)&ipAddr
, &len
) >= 0)
374 IPSocketToNetAddress(&ipAddr
, outAddress
);
375 error
= Net::NoError
;
379 error
= getLastError();
382 else if (requiredFamily
== AF_INET6
)
385 int len
= sizeof(ipAddr
);
386 if (getsockname(socketFd
, (struct sockaddr
*)&ipAddr
, &len
) >= 0)
388 IPSocket6ToNetAddress(&ipAddr
, outAddress
);
389 error
= Net::NoError
;
393 error
= getLastError();
403 template<class T
> NetSocket ReservedSocketList
<T
>::reserve(SOCKET reserveId
, bool doLock
)
408 handle
.lock(mMutex
, true);
411 S32 idx
= mSocketList
.find_next(EntryType());
415 entry
.value
= reserveId
;
417 mSocketList
.push_back(entry
);
418 return NetSocket::fromHandle(mSocketList
.size() - 1);
422 EntryType
&entry
= mSocketList
[idx
];
424 entry
.value
= reserveId
;
427 return NetSocket::fromHandle(idx
);
430 template<class T
> void ReservedSocketList
<T
>::remove(NetSocket socketToRemove
, bool doLock
)
435 handle
.lock(mMutex
, true);
438 if ((U32
)socketToRemove
.getHandle() >= (U32
)mSocketList
.size())
441 mSocketList
[socketToRemove
.getHandle()] = EntryType();
444 template<class T
> T ReservedSocketList
<T
>::activate(NetSocket socketToActivate
, int family
, bool useUDP
, bool clearOnFail
)
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())
455 EntryType
&entry
= mSocketList
[socketToActivate
.getHandle()];
459 T socketFd
= entry
.value
;
462 socketFd
= ::socket(family
, typeID
, protocol
);
464 if (socketFd
== InvalidSocketHandle
)
468 remove(socketToActivate
, false);
470 return InvalidSocketHandle
;
475 entry
.value
= socketFd
;
483 template<class T
> T ReservedSocketList
<T
>::resolve(NetSocket socketToResolve
)
486 h
.lock(mMutex
, true);
488 if ((U32
)socketToResolve
.getHandle() >= (U32
)mSocketList
.size())
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
;
521 bool Net::smMulticastEnabled
= true;
524 bool Net::smIpv4Enabled
= true;
525 bool Net::smIpv6Enabled
= false;
528 // the Socket structure helps us keep track of the
532 // local enum for socket states for polled sockets
545 handleFd
= NetSocket::INVALID
;
546 state
= InvalidState
;
554 char remoteAddr
[256];
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();
566 sock
->handleFd
= handleFd
;
569 dStrcpy(sock
->remoteAddr
, remoteAddr
);
571 sock
->remotePort
= port
;
572 gPolledSockets
.push_back(sock
);
576 bool netSocketWaitForWritable(NetSocket handleFd
, S32 timeoutMs
)
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 )
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!");
610 AssertISV( !XNetStartup( &xnsp
), "Net::init - failed to init XNet" );
614 AssertISV( !WSAStartup( 0x0101, &stWSAData
), "Net::init - failed to init WinSock!" );
616 //logprintf("Winsock initialization %s", success ? "succeeded." : "failed!");
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
);
634 Process::remove(&Net::process
);
636 while (gPolledSockets
.size() > 0)
638 if (gPolledSockets
[0] == NULL
)
639 gPolledSockets
.erase(gPolledSockets
.begin());
641 closeConnectTo(gPolledSockets
[0]->handleFd
);
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
)
658 #ifdef TORQUE_OS_XENON
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
);
675 if (address
->type
== NetAddress::IPBroadcastAddress
)
677 sockAddr
->sin_addr
.s_addr
= htonl(INADDR_BROADCAST
);
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
));
698 sockAddr
->sin6_len
= sizeof(struct sockaddr_in6
);
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
;
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())
733 return NetSocket::fromHandle(ret
);
736 Net::Error error
= NoError
;
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
));
754 handleFd
= NetSocket::INVALID
;
757 if (error
== NoError
)
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()));
792 NetSocket
Net::openConnectTo(const char *addressString
)
794 if (Journal::IsPlaying())
798 return NetSocket::fromHandle(ret
);
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
)
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
;
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
;
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
879 int actualFamily
= AF_UNSPEC
;
880 if (PlatformNetState::extractAddressParts(addressString
, addr
, port
, actualFamily
))
882 addPolledSocket(handleFd
, InvalidSocketHandle
, PolledSocket::NameLookupRequired
, addr
, port
);
884 gNetAsync
.queueLookup(addressString
, handleFd
);
888 closeSocket(handleFd
);
889 handleFd
= NetSocket::INVALID
;
894 closeSocket(handleFd
);
895 handleFd
= NetSocket::INVALID
;
898 if (Journal::IsRecording())
899 Journal::Write(U32(handleFd
.getHandle()));
903 void Net::closeConnectTo(NetSocket handleFd
)
905 if(Journal::IsPlaying())
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
;
919 closeSocket(handleFd
);
922 Net::Error
Net::sendtoSocket(NetSocket handleFd
, const U8
*buffer
, S32 bufferSize
, S32
*outBufferWritten
)
924 if(Journal::IsPlaying())
929 Journal::Read(&outBytes
);
930 if (outBufferWritten
)
931 *outBufferWritten
= outBytes
;
933 return (Net::Error
) e
;
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
;
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
;
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
;
976 NetAddress listenAddress
;
977 char listenAddressStr
[256];
979 if (Net::smIpv4Enabled
)
981 if (Net::getListenAddress(NetAddress::IPAddress
, &address
) == Net::NoError
)
984 socketFd
= ::socket(AF_INET
, SOCK_DGRAM
, protocol
);
986 if (socketFd
!= InvalidSocketHandle
)
988 PlatformNetState::udpSocket
= PlatformNetState::smReservedSocketList
.reserve(socketFd
);
989 Net::Error error
= NoError
;
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);
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
);
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
;
1045 setsockopt(socketFd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (const char *)&v
, sizeof(v
));
1046 PlatformNetState::getLastError();
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();
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())
1113 if(address
->type
== NetAddress::IPAddress
|| address
->type
== NetAddress::IPBroadcastAddress
)
1115 socketFd
= PlatformNetState::smReservedSocketList
.resolve(PlatformNetState::udpSocket
);
1116 if (socketFd
!= InvalidSocketHandle
)
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();
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();
1152 return WrongProtocolType
;
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)
1168 socklen_t optlen
= sizeof(S32
);
1171 bool removeSock
= false;
1172 PolledSocket
*currentSock
= NULL
;
1173 NetSocket incomingHandleFd
= NetSocket::INVALID
;
1174 NetAddress out_h_addr
;
1175 S32 out_h_length
= 0;
1177 NetSocket removeSockHandle
;
1179 for (S32 i
= 0; i
< gPolledSockets
.size();
1180 /* no increment, this is done at end of loop body */)
1183 currentSock
= gPolledSockets
[i
];
1185 // Cleanup if we've removed it
1186 if (currentSock
== NULL
)
1188 gPolledSockets
.erase(i
);
1192 switch (currentSock
->state
)
1194 case PolledSocket::InvalidState
:
1195 Con::errorf("Error, InvalidState socket in polled sockets list");
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 )
1204 if (getsockopt(currentSock
->fd
, SOL_SOCKET
, SO_ERROR
,
1205 (char*)&optval
, &optlen
) == -1)
1208 Con::errorf("Error getting socket options: %s", strerror(errno
));
1211 removeSockHandle
= currentSock
->handleFd
;
1213 smConnectionNotify
->trigger(currentSock
->handleFd
, Net::ConnectFailed
);
1217 if (optval
== EINPROGRESS
)
1218 // still connecting...
1223 // poll for writable status to be sure we're connected.
1224 bool ready
= netSocketWaitForWritable(currentSock
->handleFd
,0);
1228 currentSock
->state
= PolledSocket::Connected
;
1229 smConnectionNotify
->trigger(currentSock
->handleFd
, Net::Connected
);
1233 // some kind of error
1234 Con::errorf("Error connecting: %s", strerror(errno
));
1237 removeSockHandle
= currentSock
->handleFd
;
1239 smConnectionNotify
->trigger(currentSock
->handleFd
, Net::ConnectFailed
);
1243 case PolledSocket::Connected
:
1245 // try to get some data
1247 readBuff
.alloc(MaxPacketDataSize
);
1248 err
= Net::recv(currentSock
->handleFd
, (U8
*)readBuff
.data
, MaxPacketDataSize
, &bytesRead
);
1249 if(err
== Net::NoError
)
1253 // got some data, post it
1254 readBuff
.size
= bytesRead
;
1255 smConnectionReceive
->trigger(currentSock
->handleFd
, readBuff
);
1259 // ack! this shouldn't happen
1261 Con::errorf("Unexpected error on socket: %s", strerror(errno
));
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
));
1275 removeSockHandle
= currentSock
->handleFd
;
1277 smConnectionNotify
->trigger(currentSock
->handleFd
, Net::Disconnected
);
1280 case PolledSocket::NameLookupRequired
:
1283 // is the lookup complete?
1284 if (!gNetAsync
.checkLookup(
1285 currentSock
->handleFd
, &out_h_addr
, &out_h_length
,
1286 sizeof(out_h_addr
)))
1289 if (out_h_length
== -1)
1291 Con::errorf("DNS lookup failed: %s", currentSock
->remoteAddr
);
1292 newState
= Net::DNSFailed
;
1294 removeSockHandle
= currentSock
->handleFd
;
1299 out_h_addr
.port
= currentSock
->remotePort
;
1300 const sockaddr
*ai_addr
= NULL
;
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];
1317 IPSocketToNetAddress(&socketAddress
, &addr
);
1318 Net::addressToString(&addr
, addrString
);
1319 Con::printf("DNS: lookup resolved to %s", addrString
);
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];
1334 IPSocket6ToNetAddress(&socketAddress6
, &addr
);
1335 Net::addressToString(&addr
, addrString
);
1336 Con::printf("DNS: lookup resolved to %s", addrString
);
1341 Con::errorf("Error connecting to %s: Invalid Protocol",
1342 currentSock
->remoteAddr
);
1343 newState
= Net::ConnectFailed
;
1345 removeSockHandle
= currentSock
->handleFd
;
1350 if (::connect(currentSock
->fd
, ai_addr
,
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
;
1360 removeSockHandle
= currentSock
->handleFd
;
1364 newState
= Net::DNSResolved
;
1365 currentSock
->state
= PolledSocket::ConnectionPending
;
1370 newState
= Net::Connected
;
1371 currentSock
->state
= Connected
;
1376 smConnectionNotify
->trigger(currentSock
->handleFd
, newState
);
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
);
1391 // only increment index if we're not removing the connection, since
1392 // the removal will shift the indices down by one
1394 closeConnectTo(removeSockHandle
);
1400 void Net::processListenSocket(NetSocket socketHandle
)
1402 if (socketHandle
== NetSocket::INVALID
)
1405 sockaddr_storage sa
;
1406 sa
.ss_family
= AF_UNSPEC
;
1407 NetAddress srcAddress
;
1409 tmpBuffer
.alloc(Net::MaxPacketDataSize
);
1411 SOCKET socketFd
= PlatformNetState::smReservedSocketList
.resolve(socketHandle
);
1415 socklen_t addrLen
= sizeof(sa
);
1418 if (socketHandle
!= NetSocket::INVALID
)
1419 bytesRead
= ::recvfrom(socketFd
, (char *)tmpBuffer
.data
, Net::MaxPacketDataSize
, 0, (struct sockaddr
*)&sa
, &addrLen
);
1421 if (bytesRead
== -1)
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
);
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
)
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
))
1463 return PlatformNetState::getLastError();
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
)))
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
)))
1503 return PlatformNetState::getLastError();
1506 Net::Error
Net::listen(NetSocket handleFd
, S32 backlog
)
1508 SOCKET socketFd
= PlatformNetState::smReservedSocketList
.resolve(handleFd
);
1509 if (socketFd
== InvalidSocketHandle
)
1512 if(!::listen(socketFd
, backlog
))
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
)
1532 IPSocketToNetAddress(((struct sockaddr_in
*)&addr
), remoteAddress
);
1534 else if (addr
.ss_family
== AF_INET6
)
1537 IPSocket6ToNetAddress(((struct sockaddr_in6
*)&addr
), remoteAddress
);
1540 NetSocket newHandleFd
= PlatformNetState::smReservedSocketList
.reserve(acceptedSocketFd
);
1544 return NetSocket::INVALID
;
1547 Net::Error
Net::bindAddress(const NetAddress
&address
, NetSocket handleFd
, bool useUDP
)
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)
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
));
1576 return PlatformNetState::getLastError();
1579 Net::Error
Net::setBufferSize(NetSocket handleFd
, S32 bufferSize
)
1582 SOCKET socketFd
= PlatformNetState::smReservedSocketList
.resolve(handleFd
);
1583 if (socketFd
== InvalidSocketHandle
)
1586 error
= ::setsockopt(socketFd
, SOL_SOCKET
, SO_RCVBUF
, (char *) &bufferSize
, sizeof(bufferSize
));
1588 error
= ::setsockopt(socketFd
, SOL_SOCKET
, SO_SNDBUF
, (char *) &bufferSize
, sizeof(bufferSize
));
1591 return PlatformNetState::getLastError();
1594 Net::Error
Net::setBroadcast(NetSocket handleFd
, bool broadcast
)
1597 SOCKET socketFd
= PlatformNetState::smReservedSocketList
.resolve(handleFd
);
1598 if (socketFd
== InvalidSocketHandle
)
1600 S32 error
= ::setsockopt(socketFd
, SOL_SOCKET
, SO_BROADCAST
, (char*)&bc
, sizeof(bc
));
1603 return PlatformNetState::getLastError();
1606 Net::Error
Net::setBlocking(NetSocket handleFd
, bool blockingIO
)
1608 SOCKET socketFd
= PlatformNetState::smReservedSocketList
.resolve(handleFd
);
1609 if (socketFd
== InvalidSocketHandle
)
1612 unsigned long notblock
= !blockingIO
;
1613 S32 error
= ioctl(socketFd
, FIONBIO
, ¬block
);
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
;
1628 *((U32
*)address
->address
.ipv4
.netNum
) = INADDR_ANY
;
1629 return Net::NoError
;
1633 return Net::stringToAddress(serverIP
, address
, false);
1636 else if (type
== NetAddress::IPBroadcastAddress
)
1638 address
->type
= type
;
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')
1649 dMemset(&addr
, '\0', sizeof(addr
));
1652 addr
.sin6_addr
= in6addr_any
;
1654 IPSocket6ToNetAddress(&addr
, address
);
1655 return Net::NoError
;
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);
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);
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
)
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
)
1721 *bytesRead
= ::recv(socketFd
, (char*)buffer
, bufferSize
, 0);
1722 if(*bytesRead
== -1)
1723 return PlatformNetState::getLastError();
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
)
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
;
1763 address
->port
= port
;
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
;
1774 address
->port
= port
;
1776 address
->port
= PlatformNetState::defaultPort
;
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
);
1797 address
->port
= port
;
1799 address
->port
= PlatformNetState::defaultPort
;
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
);
1810 address
->port
= port
;
1812 address
->port
= PlatformNetState::defaultPort
;
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
)
1837 IPSocketToNetAddress(((struct sockaddr_in
*)res
->ai_addr
), address
);
1839 else if (res
&& res
->ai_family
== AF_INET6
)
1842 IPSocket6ToNetAddress(((struct sockaddr_in6
*)res
->ai_addr
), address
);
1847 return UnknownError
;
1851 address
->port
= port
;
1853 address
->port
= PlatformNetState::defaultPort
;
1861 void Net::addressToString(const NetAddress
*address
, char addressString
[256])
1863 if(address
->type
== NetAddress::IPAddress
|| address
->type
== NetAddress::IPBroadcastAddress
)
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");
1873 dSprintf(addressString
, 256, "IP:Broadcast:%d", ntohs(ipAddr
.sin_port
));
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
);
1885 dSprintf(addressString
, 256, "IP:%s:%i", buffer
, ntohs(ipAddr
.sin_port
));
1888 else if (address
->type
== NetAddress::IPV6Address
)
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
);
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");
1905 dSprintf(addressString
, 256, "IP6:Multicast:%d", address
->port
);
1914 void Net::enableMulticast()
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
));
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
);
1970 PlatformNetState::multicast6Group
.ipv6mr_interface
= if_nametoindex(multicastInterface
);
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
2028 case NetAddress::IPAddress
:
2029 value
= Torque::hash((const U8
*)&address
.ipv4
.netNum
, sizeof(address
.ipv4
.netNum
), 0);
2031 case NetAddress::IPV6Address
:
2032 value
= Torque::hash((const U8
*)address
.ipv6
.netNum
, sizeof(address
.ipv6
.netNum
), 0);
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
;