Preliminary IPV6 Support

This commit is contained in:
James Urquhart 2016-09-10 23:01:10 +01:00
parent 1a851f167d
commit 704577e051
22 changed files with 1712 additions and 592 deletions

View file

@ -177,7 +177,7 @@ static Vector<Ping> gQueryList(__FILE__, __LINE__);
struct PacketStatus
{
U8 index;
U16 index;
S32 key;
U32 time;
U32 tryCount;
@ -191,6 +191,9 @@ struct PacketStatus
time = _time;
tryCount = gPacketRetryCount;
}
inline U8 getOldIndex() { return (U8)index; }
inline U16 getIndex() { return index; }
};
static Vector<PacketStatus> gPacketStatusList(__FILE__, __LINE__);
@ -212,6 +215,7 @@ struct ServerFilter
OnlineQuery = 0, // Authenticated with master
OfflineQuery = BIT(0), // On our own
NoStringCompress = BIT(1),
NewStyleResponse = BIT(2), // Include IPV6 servers
};
enum // Filter flags:
@ -222,6 +226,14 @@ struct ServerFilter
CurrentVersion = BIT(7),
NotXenon = BIT(6)
};
enum // Region mask flags
{
RegionIsIPV4Address = BIT(30),
RegionIsIPV6Address = BIT(31),
RegionAddressMask = RegionIsIPV4Address | RegionIsIPV6Address
};
//Rearranging the fields according to their sizes
char* gameType;
@ -241,7 +253,7 @@ struct ServerFilter
ServerFilter()
{
type = Normal;
queryFlags = 0;
queryFlags = NewStyleResponse;
gameType = NULL;
missionType = NULL;
minPlayers = 0;
@ -401,10 +413,17 @@ void queryLanServers(U32 port, U8 flags, const char* gameType, const char* missi
NetAddress addr;
char addrText[256];
// IPV4
dSprintf( addrText, sizeof( addrText ), "IP:BROADCAST:%d", port );
Net::stringToAddress( addrText, &addr );
pushPingBroadcast( &addr );
// IPV6
dSprintf(addrText, sizeof(addrText), "IP6:MULTICAST:%d", port);
Net::stringToAddress(addrText, &addr);
pushPingBroadcast(&addr);
Con::executef("onServerQueryStatus", "start", "Querying LAN servers", "0");
processPingsAndQueries( gPingSession );
}
@ -502,7 +521,7 @@ void queryMasterServer(U8 flags, const char* gameType, const char* missionType,
dStrcpy( sActiveFilter.missionType, missionType );
}
sActiveFilter.queryFlags = flags;
sActiveFilter.queryFlags = flags | ServerFilter::NewStyleResponse;
sActiveFilter.minPlayers = minPlayers;
sActiveFilter.maxPlayers = maxPlayers;
sActiveFilter.maxBots = maxBots;
@ -519,6 +538,7 @@ void queryMasterServer(U8 flags, const char* gameType, const char* missionType,
sActiveFilter.type = ServerFilter::Buddy;
sActiveFilter.buddyCount = buddyCount;
sActiveFilter.buddyList = (U32*) dRealloc( sActiveFilter.buddyList, buddyCount * 4 );
sActiveFilter.queryFlags = ServerFilter::NewStyleResponse;
dMemcpy( sActiveFilter.buddyList, buddyList, buddyCount * 4 );
clearServerList();
}
@ -775,7 +795,7 @@ Vector<MasterInfo>* getMasterServerList()
U32 region = 1; // needs to default to something > 0
dSscanf(master,"%d:",&region);
const char* madd = dStrchr(master,':') + 1;
if (region && Net::stringToAddress(madd,&address)) {
if (region && Net::stringToAddress(madd,&address) == Net::NoError) {
masterList.increment();
MasterInfo& info = masterList.last();
info.address = address;
@ -1171,10 +1191,13 @@ static void processMasterServerQuery( U32 session )
// Send a request to the master server for the server list:
BitStream *out = BitStream::getPacketStream();
out->clearStringBuffer();
out->write( U8( NetInterface::MasterServerListRequest ) );
out->write( U8( sActiveFilter.queryFlags) );
out->write( ( gMasterServerPing.session << 16 ) | ( gMasterServerPing.key & 0xFFFF ) );
out->write( U8( 255 ) );
writeCString( out, sActiveFilter.gameType );
writeCString( out, sActiveFilter.missionType );
out->write( sActiveFilter.minPlayers );
@ -1359,23 +1382,35 @@ static void processServerListPackets( U32 session )
if ( !p.tryCount )
{
// Packet timed out :(
Con::printf( "Server list packet #%d timed out.", p.index + 1 );
Con::printf( "Server list packet #%d timed out.", p.getIndex() + 1 );
gPacketStatusList.erase( i );
}
else
{
// Try again...
Con::printf( "Rerequesting server list packet #%d...", p.index + 1 );
Con::printf( "Rerequesting server list packet #%d...", p.getIndex() + 1 );
p.tryCount--;
p.time = currentTime;
p.key = gKey++;
BitStream *out = BitStream::getPacketStream();
bool extendedPacket = (sActiveFilter.queryFlags & ServerFilter::NewStyleResponse) != 0;
out->clearStringBuffer();
out->write( U8( NetInterface::MasterServerListRequest ) );
if ( extendedPacket )
out->write( U8( NetInterface::MasterServerExtendedListRequest ) );
else
out->write( U8( NetInterface::MasterServerListRequest ) );
out->write( U8( sActiveFilter.queryFlags ) ); // flags
out->write( ( session << 16) | ( p.key & 0xFFFF ) );
out->write( p.index ); // packet index
if ( extendedPacket )
out->write( p.getOldIndex() ); // packet index
else
out->write( p.getIndex() ); // packet index
out->write( U8( 0 ) ); // game type
out->write( U8( 0 ) ); // mission type
out->write( U8( 0 ) ); // minPlayers
@ -1569,6 +1604,98 @@ static void handleMasterServerListResponse( BitStream* stream, U32 key, U8 /*fla
//-----------------------------------------------------------------------------
static void handleExtendedMasterServerListResponse(BitStream* stream, U32 key, U8 /*flags*/)
{
U16 packetIndex, packetTotal;
U32 i;
U16 serverCount, port;
U8 netNum[16];
char addressBuffer[256];
NetAddress addr;
stream->read(&packetIndex);
// Validate the packet key:
U32 packetKey = gMasterServerPing.key;
if (gGotFirstListPacket)
{
for (i = 0; i < gPacketStatusList.size(); i++)
{
if (gPacketStatusList[i].index == packetIndex)
{
packetKey = gPacketStatusList[i].key;
break;
}
}
}
U32 testKey = (gPingSession << 16) | (packetKey & 0xFFFF);
if (testKey != key)
return;
stream->read(&packetTotal);
stream->read(&serverCount);
Con::printf("Received server list packet %d of %d from the master server (%d servers).", (packetIndex + 1), packetTotal, serverCount);
// Enter all of the servers in this packet into the ping list:
for (i = 0; i < serverCount; i++)
{
U8 type;
stream->read(&type);
dMemset(&addr, '\0', sizeof(NetAddress));
if (type == 0)
{
// IPV4
addr.type = NetAddress::IPAddress;
stream->read(4, &addr.address.ipv4.netNum[0]);
stream->read(&addr.port);
}
else
{
// IPV6
addr.type = NetAddress::IPV6Address;
stream->read(16, &addr.address.ipv6.netNum[0]);
stream->read(&addr.port);
}
pushPingRequest(&addr);
}
// If this is the first list packet we have received, fill the packet status list
// and start processing:
if (!gGotFirstListPacket)
{
gGotFirstListPacket = true;
gMasterServerQueryAddress = gMasterServerPing.address;
U32 currentTime = Platform::getVirtualMilliseconds();
for (i = 0; i < packetTotal; i++)
{
if (i != packetIndex)
{
PacketStatus* p = new PacketStatus(i, gMasterServerPing.key, currentTime);
gPacketStatusList.push_back(*p);
}
}
processServerListPackets(gPingSession);
}
else
{
// Remove the packet we just received from the status list:
for (i = 0; i < gPacketStatusList.size(); i++)
{
if (gPacketStatusList[i].index == packetIndex)
{
gPacketStatusList.erase(i);
break;
}
}
}
}
//-----------------------------------------------------------------------------
static void handleGameMasterInfoRequest( const NetAddress* address, U32 key, U8 flags )
{
if ( GNet->doesAllowConnections() )
@ -1585,7 +1712,7 @@ static void handleGameMasterInfoRequest( const NetAddress* address, U32 key, U8
for(U32 i = 0; i < masterList->size(); i++)
{
masterAddr = &(*masterList)[i].address;
if (*(U32*)(masterAddr->netNum) == *(U32*)(address->netNum))
if (masterAddr->isSameAddress(*address))
{
fromMaster = true;
break;
@ -2098,6 +2225,10 @@ void DemoNetInterface::handleInfoPacket( const NetAddress* address, U8 packetTyp
case GameMasterInfoRequest:
handleGameMasterInfoRequest( address, key, flags );
break;
case MasterServerExtendedListResponse:
handleExtendedMasterServerListResponse(stream, key, flags);
break;
}
}