Announcement

Collapse
No announcement yet.

Quake and Port Forwarding

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Quake and Port Forwarding

    I've been working on my own personal build of ProQuake (I don't know if I'm going to distribute it yet - my code is kind of messy and I would have to release it as well due to the GPL). It's probably not very interesting to anybody. It fixes only a few things and it adds MP3 playing support (it only emulates the CD Audio engine so it plays the soundtracks for Quake and the two official Mission Packs). I'm even further less likely to release the source (and therefore the client) because I used FMOD to save time.

    While working on the code, I ran into the problem of Quake opening a bunch of random UDP port/socket combos when players connect. We couldn't get it working because we assumed the listen port we defined (default 26000) was the only port used, ala DarkPlaces.

    So that got me thinking about compromises. I didn't want to give up compatibility with normal NetQuake engines as either a client or a server. My solution is as follows:
    • I added a command-line parameter: -startport <port number>. If you don't provide this parameter, nothing is different in the engine.
    • qsocket now has an extra member: int defined_port
    • Whenever the net_freesockets pool is being populated, it sets the defined_port of each socket to be the <port number> from -startport plus i (the number of the socket from the for loop).
    • Now whenever the sockets are distributed from the pool, the same socket won't be used twice, but they will all be within a predictable range, maxed out at 16 players. Instead of NET_OpenSocket(0), just get the defined_port from the sock pulled from the net_freesockets pool: NET_OpenSocket(sock->defined_port).


    There are a lot of merits to doing this. It maintains compatibility with all other NetQuake engines, it's server-side, and it's a completely optional parameter. It fixes the issue of having to forward all UDP ports to host a Quake server. This way, you can actually have several separate machines behind a NAT running Quake servers by dedicating a different range of ports or each server. Best of all, it's easy as hell to implement. I doubt Baker would need more than the description I wrote above (though I would provide source to him if he asked).

    I'm sure something so simple has already been written by someone. I'm just wondering why it isn't widespread. So... there you go. Hell of a first post, right?

    P.S. Baker: Fix the options menu code for D3DProQuake. If you wrap from top to bottom, it goes to an empty slot (video options) that will cause a crash.
    Last edited by Skutarth; 05-04-2010, 04:33 PM.
    sigpic

  • #2
    I would very much like to see R00k implement this in Qrack as well. I hate having to forward all the UDP ports in order to host a simple TCP/IP game.

    Comment


    • #3
      Originally posted by Lightning_Hunter View Post
      I would very much like to see R00k implement this in Qrack as well. I hate having to forward all the UDP ports in order to host a simple TCP/IP game.
      Ideally, this should be implemented in all NetQuake clients that don't significantly change the netcode (ie DarkPlaces). It doesn't lower the amount of ports you need (one listen port + one port per player), but it doesn't break compatibility and it's a lot easier to forward and manage them when you know where they're going to be. Forwarding 17 ports is a lot better than forwarding 65535 ports.
      sigpic

      Comment


      • #4
        Originally posted by Skutarth View Post
        Forwarding 17 ports is a lot better than forwarding 65535 ports.
        I agree. At the moment, it's too annoying to even forward that many ports with my router. I'd have to first go through and disable all the UDP port forwarding already being done by other games. Otherwise, my router tells me that I can't forward all those ports, because other services are already using some of them.

        Comment


        • #5
          Sounds neat. I haven't dealt with the net code much (but some day I'm going to OO a lot of the mess) but from a quick glance through the relevant parts it looks as though it should be possible to implement this as a cvar rather than requiring a command-line option (no reason why both couldn't be done of course).

          I'm a big fan of the concept of making command-line options disappear - keep them around for the batch file fans, but don't make them obligatory.

          Have you looked at the possibility of doing it that way?
          IT LIVES! http://directq.blogspot.com/

          Comment


          • #6
            Originally posted by mhquake View Post
            Sounds neat. I haven't dealt with the net code much (but some day I'm going to OO a lot of the mess) but from a quick glance through the relevant parts it looks as though it should be possible to implement this as a cvar rather than requiring a command-line option (no reason why both couldn't be done of course).

            I'm a big fan of the concept of making command-line options disappear - keep them around for the batch file fans, but don't make them obligatory.

            Have you looked at the possibility of doing it that way?
            I'm too lazy to look for when a cvar changes to regenerate the socket pool. I also don't want to deal with the user trying to change it mid-game in multiplayer. Lazy, lazy, lazy. That's why.

            Keep in mind that it's just a simple solution I came up with for my own personal engine build (only for me and personal friends). Necessity is the mother of all invention. I just figured I'd point this out someplace where major engine writers frequent so they can at least use the idea. I don't even care if I'm not credited for it. Whatever makes this sort of thing more prominently available among major NetQuake engines is fine with me.
            sigpic

            Comment


            • #7
              Hmm, I experienced this a few weeks ago having to setup a local lan to test quakeC server stuff, yet my linksys router allows me to specify this range within the router,


              But every time i restart my network the server box is assigned a new value for the last octet. Then I have to connect to the router and change my port-forwarding value.

              I would most likely not use a commandline parameter, as well in favor of a cvar, (it's more friendly to edit .cfg files instead of .bat and .cfg), i'm still curious if the router will yield access? I'll have to re-read your first post more carefully.
              www.quakeone.com/qrack | www.quakeone.com/cax| http://en.twitch.tv/sputnikutah

              Comment


              • #8
                Originally posted by R00k View Post
                I would most likely not use a commandline parameter, as well in favor of a cvar, (it's more friendly to edit .cfg files instead of .bat and .cfg), i'm still curious if the router will yield access? I'll have to re-read your first post more carefully.
                I just used a command-line parameter for two kinds of convenience:
                1. I'm not planning on ever changing the -startport I define in a batch or shortcut unless a port conflict arises.
                2. I'm lazy.

                I could care less how the number is defined. I'm only concerned with the meat of it being implemented.

                //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\

                Here's a hypothetical situation to clarify:
                You want to host a dedicated server with a maximum of 16 players. You could set up a server with this code modification using this command line:
                wqpro400.exe -dedicated 16 -port 1414 -startport 1415

                Then you would need only forward UDP ports 1414-1431 to your local IP in the router's settings, and you wouldn't need to worry about changing the port forwarding again unless you change the command-line parameters. In the example, port 1414 would be the listen port and ports 1415-1431 would be the ports for player connections (1415 + 16 [players]). Thus, it uses the same number of ports as it would have originally (which has to be true for it to stay compatible with unmodified NetQuake clients). What it does do is make the client connection port usage predictable so you can forward only the number of ports you need to forward instead of effectively putting the server in a DMZ.

                Like I said before: Forwarding 17 ports is a lot better than forwarding 65535 ports.

                EDIT: Just to clarify, the server doesn't need to be a dedicated server. The new code will run on a listen server just as well.
                sigpic

                Comment


                • #9
                  Then you would need only forward UDP ports 1414-1431 to your local IP in the router's settings
                  I was under the assumption that your code took care of everything and you didnt need to even turn on port forwarding the router?

                  How is the router forwarding 65535 when u specify this...
                  Port Range
                  Application Start to End Protocol IP Address Enable
                  Quake 26000 26002 UDP 192.168.1.1 X

                  in net_dgrm.c

                  in _Datagram_CheckNewConnections where the server is handling CCREQ's

                  Yugo2Heck provided this tid bit
                  Code:
                  	if (control == -1)
                  		return NULL;
                  
                  	if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
                  	{
                  		/* Yugo2Heck: ProQuake 3.4 (and up) clients close their request socket
                  		** and make a new socket for the session.  This means we
                  		** connected back to the wrong socket when accepting the
                  		** connection.  So we look for a "bogus" request packet 
                  		** from that client on a different port, and re-connect 
                  		** back to that port instead.
                  		*/
                  		for (s = net_activeSockets; s; s = s->next)
                  		{
                  			if (s->driver != net_driverlevel)
                  				continue;
                  
                  			ret = dfunc.AddrCompare(&clientaddr, &s->addr);
                  			if (ret == 1)
                  			{	//same client, different port: reconnect back
                  				dfunc.Connect (s->socket, &clientaddr);
                  				/* TODO: check for failure, report error, etc */
                   				return NULL;
                  			}
                  		}
                  	}
                  This should help with the socket/port flip flopping.
                  Within the CCREQ_CONNECT this is used instead of NET_OpenSocket(0)

                  Code:
                  	// allocate a network socket
                  	{
                  		struct qsockaddr oldaddr;
                  		dfunc.GetSocketAddr(acceptsock, &oldaddr);
                  		newsock = dfunc.OpenSocket(dfunc.GetSocketPort(&oldaddr));
                  	}
                  I've omitted the part of opening a new socket (to get around NAT), and I have not had any problems connecting to any servers
                  Code:
                  ProQuake: make NAT work by opening a new socket
                  	/*
                  	{
                  		clientsock = dfunc.OpenSocket(0);
                  		if (clientsock == -1)
                  			goto ErrorReturn;
                  		dfunc.CloseSocket(newsock);
                  		newsock = clientsock;
                  		sock->socket = newsock;
                  	}
                  	*/
                  Last edited by R00k; 05-05-2010, 02:53 AM.
                  www.quakeone.com/qrack | www.quakeone.com/cax| http://en.twitch.tv/sputnikutah

                  Comment


                  • #10
                    Originally posted by R00k View Post
                    I was under the assumption that your code took care of everything and you didnt need to even turn on port forwarding the router?

                    How is the router forwarding 65535 when u specify this...
                    Nonsense. A server always has to have port forwarding unless it's connected directly to the WAN. How else would you route traffic to the server? The only way for it to be hands-free is to have UPnP implemented into the engine, which I'm not privy on implementing right now.

                    Either way, I don't see how the code you posted addresses the original issue. Looking at that code, the sockets won't flip-flop during run-time, but they are going to be different every time the server is started. That's the problem.

                    To clarify, here's a test case:

                    In vanilla Quake netcode:
                    Server starts. 2 clients connect:
                    Client Number: Port (As provided by WinSock)
                    1: 61582
                    2: 61583
                    Server changes map. 2 clients reconnect and probably recreates the sockets on new ports:
                    1: 61583
                    2: 61582

                    In ProQuake netcode, as per what you posted:
                    Server starts. 2 clients connect:
                    Client Number: Port (As provided by WinSock)
                    1: 52592
                    2: 52593
                    Server changes map. 2 clients reconnect and are reassigned to new sockets on the same ports:
                    1: 52592
                    2: 52593

                    In ProQuake netcode, as per what I'm suggesting:
                    Server starts using -startport 1415. 2 clients connect:
                    Client Number: Port (As provided by WinSock)
                    1: 1415
                    2: 1416
                    Server changes map. 2 clients reconnect and are reassigned to new sockets on the same ports specified in the command-line parameter:
                    1: 1415
                    2: 1416

                    The last case is the only one that provides a small, predictable range of ports for every time the server is run, and is therefore the only way to sanely maintain port forwarding.
                    Last edited by Skutarth; 05-05-2010, 03:14 AM. Reason: Clarification
                    sigpic

                    Comment


                    • #11
                      Maybe because its 4am, im missing the whole problem here.

                      Specifying 26000 - 26002 is two ports forwarded TO the server.

                      How does "connect quake.myserver.com:26000" connect me to port 61582?

                      I modified this where the CLIENT requests to connect...
                      Code:
                      newsock = dfunc.OpenSocket(net_hostport);//was 0 hard coded CLIENT-SIDE udp Port testing
                      and now when ever i connect to a server, my port FROM my machine uses UDP port 26000, verified via the STATUS command on the server.
                      The server's udp port should be static defined by the PORT command.
                      www.quakeone.com/qrack | www.quakeone.com/cax| http://en.twitch.tv/sputnikutah

                      Comment


                      • #12
                        Originally posted by Skutarth View Post
                        There are a lot of merits to doing this. It maintains compatibility with all other NetQuake engines, it's server-side, and it's a completely optional parameter. It fixes the issue of having to forward all UDP ports to host a Quake server. This way, you can actually have several separate machines behind a NAT running Quake servers by dedicating a different range of ports or each server. Best of all, it's easy as hell to implement. I doubt Baker would need more than the description I wrote above (though I would provide source to him if he asked).
                        My imagination sucks as of lately so yeah I'd probably have to see your source code. I'll private message you.

                        P.S. Baker: Fix the options menu code for D3DProQuake. If you wrap from top to bottom, it goes to an empty slot (video options) that will cause a crash.
                        Yep. That and a mouse acceleration fix and a few other things.
                        Quakeone.com - Being exactly one-half good and one-half evil has advantages. When a portal opens to the antimatter universe, my opposite is just me with a goatee.

                        So while you guys all have to fight your anti-matter counterparts, me and my evil twin will be drinking a beer laughing at you guys ...

                        Comment


                        • #13
                          Originally posted by R00k View Post
                          Maybe because its 4am, im missing the whole problem here.

                          Specifying 26000 - 26002 is two ports forwarded TO the server.

                          How does "connect quake.myserver.com:26000" connect me to port 61582?

                          I modified this where the CLIENT requests to connect...
                          Code:
                          newsock = dfunc.OpenSocket(net_hostport);//was 0 hard coded CLIENT-SIDE udp Port testing
                          and now when ever i connect to a server, my port FROM my machine uses UDP port 26000, verified via the STATUS command on the server.
                          The server's udp port should be static defined by the PORT command.
                          The client only ever used one port to establish a sustained connection to the server. The server uses one port for each player, though.

                          Here's a general overview of a client connection, assuming default settings:
                          1. Server opens using listen port 26000.
                          2. Client connects to server quake.myserver.com:26000.
                          3. Server receives client connection request and responds with either "Connection Accepted" or "Connection Denied". If the connection is accepted, info about the server is returned. Among that information is a new port number.
                          4. The exchange in 3 can possibly happen twice. If it does, it's just ignored the second time. (This is to deal with latency and packet loss)
                          5. The socket on the listen port is disconnected on both the server and client.
                          6a. The server sets up the listen port again as an open socket. It also open up the port number and socket from (3) and waits for the player.
                          6b. The client contacts the server using the new port provided in (3).
                          7. The server accepts the incoming connection on the port provided in (3).
                          8. The connection is complete between the server and the client on the new port.

                          The port number provided by the server in (3) needs to be forwarded to the server for anybody to be able to connect. The port number is determined by WinSock: dfunc.OpenSocket(0). It just picks a random unused UDP port to establish the sustained connection.

                          Fun fact: This also means that the server can only process one incoming connection at a time. Since it acts like each port can only have one socket, it has to do what it does: reassign each of those incoming connections to another port to sustain the connection and keep the listen port open.

                          P.S. Clients do not need to forward any ports. Reply packets make it back just fine.
                          sigpic

                          Comment

                          Working...
                          X