Game Development Community

Using Arranged Connections to punch through firewalls and router

by Affectworks · in Torque Game Engine · 12/27/2006 (4:37 pm) · 28 replies

Cool Title huh? I guess I should explain it first.

It has been a nuisance to me to always have to depend on my end users to have the knowledge of how to forward their router ports in order to host a game (and don't many if not most people have routers now days?). Then it came to my attention, about a month ago, that GG has had the technology to 'punch' through routers for years now in the form of the Torque Network Library (TNL). TNL is GPL and can be found here http://www.opentnl.org For all who don't know, here is how the Arrangement of Connections essentially works in TNL.

Quote:- The server sends cyclic messages to the master, so the firewall is open for the master.
- The client sends a request to the master, and receives the server IP list
- The client sends a message to the master, for inform it that it wants to contact the server
- the master sends a message to the server with client's IP
- the server contacts the client, just to open firewall (with n retry)
- the client contacts the server to entering the game (with n retry)

Quite ingenious and extremely useful with today's standard home network. This connection arrangement feature should probably be standard in all the Torque Engines, but since it is not, I am attempting to integrate it. It is not necessary to integrate all of TNL for this feature, therefore I am just working with implementing 'Punch' PacketTypes and all else that is along that same vein. This will also require a custom master server that I haven't even had an opportunity to touch yet.

So, here is the point of this thread, I am reaching out to the community in hope of helpful hints, thoughts, code snippets you may have written earlier and maybe even a periodic 'a-ta-boy! It is a goal of mine to turn this thread into a spectacular community created resource that will benefit everyone.
Page «Previous 1 2
#1
12/27/2006 (5:51 pm)
Sounds like a great add-on to Torque's networking. Longterm we definitely want to move all our engines over to TNL, although there are some more pressing technical clean-ups we want to do first (that you should be hearing more about in the first half of '07). Short-term, this sounds like a great project that would benefit the community.

If you can get the client part of this going, I'd be happy to look into updating the GG master server to support it.
#2
12/28/2006 (6:02 am)
Sounds great Ben!
#3
01/02/2007 (7:13 am)
OK, I am back from my mostly blacked out new years trip and I am back to work on this unresolved feature. If anyone has any comments, feel free to post :)
#4
01/04/2007 (6:33 am)
I toyed with the idea of looking into this near the end of last year, but other projects took priority so it never went beyond the "would be neat" phase.

It's a project that would really benefit many multiplayer TGE games though, so I hope you manage to make some progress and keep us informed :)
#5
01/04/2007 (8:10 am)
We are in complete agreement. I look forward to not having email after email saying "Why I not able to host game?" Not to mention the possibilities of Online Gaming if everyone in-game had the ability to host.
#6
01/05/2007 (6:01 am)
That would be the whip. Good Luck!
#7
01/05/2007 (7:29 am)
@ Jeff :) cool phrase! I'm so uncool I looked up 'whip' in the 'urban dictionary' and it means car. :) so I guess your not speaking U.S. slang :D

@all
To give you an update on my progress:
I am basically working in 3 files.

netInterface.cc, netInterface.h, netConnection.h
which, in TNL, correspond to
netInterface.cpp, tnlNetInterface.h, tnlNetConnection.h

I also need to implement the Nonce structure from tnlNonce.h

There is also a ConnectionParameters Stucture that plays an integral part yet is a little troublesome.

It seems so simple... :)
#8
01/07/2007 (8:41 pm)
psuedo code removed for less confusion...
#9
01/08/2007 (6:44 am)
I'm not really positive how useful if any the consoleMethod will turn out to be.
#10
01/08/2007 (1:08 pm)
I have started looking into masterservers and I find that the one written by Ben is pretty cool however to modify it to arrange connections will probably not be easy :( here is the link. Let me know what you think... anybody...
#11
01/08/2007 (1:31 pm)
The console method seems useful. But I think you need to punch to multiple addresses at once (as TNL does).

Also, how are you testing this?
#12
01/08/2007 (1:45 pm)
Thx for the helpful advise.

Testing is the biggest problem with this project because I need to have a new master server running and working :( However for now, I needed a starting point and this code so far is mainly just my thoughts, sort of getting them down in hope of help and thoughts from others.
#13
01/12/2007 (7:16 am)
Good News Everyone! After working with the pbms for a couple of days now, I have successfully created a heck of a hack that connects clients to hosts on the other side of a router.

I didn't believe my eyes when I saw it so I disabled the 'punch packet' and then I couldn't connect to the host on the other side, then I re-enabled the packet and it connected without a hitch. w00t!

It has worked with every router I have tested it on but 1, and that 1 doesn't even work with guild wars, without special configuration, so I think if Arena.net can get away with it so can I :)

I have 1 major bug I need to fix and then I will post my findings.
#14
01/12/2007 (7:40 am)
That's really great news!
Thanks for taking the time to work on it, it will be extremely useful for all TGE multiplayer projects.
#15
01/12/2007 (12:32 pm)
That's great news Affectworks.
I echo Mathieu's sentiment. Thanks for working on this.
#16
01/28/2007 (4:44 pm)
OK, here is the simple little hack that I have created to be able to host from behind a router.

One problem remains and that is being a client behind a router connecting to a host behind a router. Hopefully I can get some help on this because I have beat my head against this same wall for about a month now and I haven't been able to get further then connecting a client not behind a router to a host that is behind one. Here are my changes.

In file sim/netInterface.h

Inside 'enum PacketTypes' @ line 27 add what is in bold
GameInfoResponse              = 20,
GameHeartbeat                 = 22,
[b]Punch		              = 24,[/b]
ConnectChallengeRequest       = 26,

In file sim/netInterface.cc

@ line 90 change:
if(packetType <= GameHeartbeat)
to
if(packetType <= [b]Punch[/b])

In file game/net/serverQuery.cc

@ line 2008 add
static void handlePunch( BitStream* stream, U32 key, U8 /*flags*/ )
{
   U8 packetIndex;//, packetTotal;
   U32 i;
   U16 port;//serverCount
   U8 netNum[4];
   char addressBuffer[256];
   NetAddress addr;

   stream->read( &packetIndex );

   stream->read( &netNum[0] );
   stream->read( &netNum[1] );
   stream->read( &netNum[2] );
   stream->read( &netNum[3] );
   stream->read( &port );

   dSprintf( addressBuffer, sizeof( addressBuffer ), "IP:%d.%d.%d.%d:%d", netNum[0], netNum[1], netNum[2], netNum[3], port );
   Net::stringToAddress( addressBuffer, &addr );

   // Send a request to the master server for the game types:
   Con::printf( "Sending punch packet to client - IP:%d.%d.%d.%d:%d", netNum[0], netNum[1], netNum[2], netNum[3], port );
   handleGamePingRequest(&addr, key, 0);
}

//-----------------------------------------------------------------------------

Then a few lines from the bottom inside the 'switch( packetType ){}' add what is in bold
case GameMasterInfoRequest:
   handleGameMasterInfoRequest( address, key, flags );
   break;
[b]case Punch:
   handlePunch( stream, key, flags );
   break;[/b]
}

Now the changes that I made to the Pushbutton Master Server (you can find the pmbs resource here

In TorqueIO.cpp

Replace 'void sendListResponse(...){...}' @ line 287 with what is in the codeblock.
void sendListResponse(ServerAddress * where, unsigned short session, unsigned short key, ServerResults * res, int which)
{
	Packet * list = new Packet(LIST_PACKET_SIZE);
    	Packet * punchReply = new Packet(LIST_PACKET_SIZE);

	list->stuffHeader(8, 0, session, key);
	punchReply->stuffHeader(24, 0, session, key);

	list->writeU8(which);	// packet index
	punchReply->writeU8(which);

	// Now get the relevant ServerResult

	ServerResults * cur = res, *relevant;
	int i=0, total=0;

	// Calculate and find.
	while(cur)
	{
		total++;
		if(i==which) relevant = cur;
		cur = cur->next;
	}

	list->writeU8(total); // total packets to send.
	list->writeU16(relevant->count);  // count of servers in this packet

	ServerAddress * HostLocation;
	// Now loop through the relevant chunk's servers...
	for(i=0; i<relevant->count ; i++)
	{
		// Write the quads
		list->writeU8( relevant->server[i].addy[0] );
		list->writeU8( relevant->server[i].addy[1] );
		list->writeU8( relevant->server[i].addy[2] );
		list->writeU8( relevant->server[i].addy[3] );

		// Write the port
		list->writeU16(relevant->server[i].port );

		printf("Address in list %s:%d <- Here is the list broken down.\n", relevant->server[i].toString(), relevant->server[i].port);
		punchReply->writeU8( where->addy[0] );
		punchReply->writeU8( where->addy[1] );
		punchReply->writeU8( where->addy[2] );
		punchReply->writeU8( where->addy[3] );
		punchReply->writeU16( where->port );

		HostLocation = new ServerAddress(relevant->server[i]);
		transport->sendPacket(punchReply, HostLocation);
	
	}
#17
01/28/2007 (4:59 pm)
Hmm - what should happen for a succesful punch is:

Each end of the connection should get two addresses to send punch packets to, the addy that the other end says it is and the addy that the master server observed the packet coming from. Each end then sends punch packets to both possibilities. When the connection has been established (ie, each end starts getting packets from the other end), then you can determine to what you must really send your data and move on with life.

It looks like this implementation only sends one of the addresses, so won't work in all cases.
#18
01/29/2007 (7:32 am)
Thx again Ben!
#19
01/29/2007 (8:17 am)
Hey, only thank me if my suggestion works. ;)

Does it?
#20
01/29/2007 (8:37 am)
Haha... Hey, with as must work as I have put into this I would gladly thank anybody for any related info. :)

Heck, I even thanked my artist when he suggested that I "put it in an 'IF loop'". Don't even ask me what that means or what he thought that could mean, but he said it with a straight face so I thanked him for his input, turned away and muttered under my breath "Why do I even talk to you, tracer"

I plan on getting back to this tonight. I will let you know my progress.
Page «Previous 1 2