DEADSOFTWARE

port forwarding and miniupnpc are now completely optional
[d2df-sdl.git] / src / game / g_net.pas
index 95f96739e62eea4e74a3d662097d2421261c1a50..4e2ed9a09f94f868abff12ccccba327c435a3b6d 100644 (file)
@@ -1,4 +1,4 @@
-(* Copyright (C)  DooM 2D:Forever Developers
+(* Copyright (C)  Doom 2D: Forever Developers
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ unit g_net;
 interface
 
 uses
-  e_log, e_msg, ENet, Classes;
+  e_log, e_msg, ENet, Classes, MAPDEF{$IFDEF USE_MINIUPNPC}, miniupnpc;{$ELSE};{$ENDIF}
 
 const
   NET_PROTOCOL_VER = 173;
@@ -136,9 +136,17 @@ var
 
   NetForcePlayerUpdate: Boolean = False;
   NetPredictSelf:       Boolean = True;
-  NetGotKeys:           Boolean = False;
+  NetForwardPorts:      Boolean = False;
 
   NetGotEverything: Boolean = False;
+  NetGotKeys:       Boolean = False;
+
+{$IFDEF USE_MINIUPNPC}
+  NetPortForwarded: Word = 0;
+  NetPongForwarded: Boolean = False;
+  NetIGDControl: AnsiString;
+  NetIGDService: TURLStr;
+{$ENDIF}
 
   NetDumpFile: TStream;
 
@@ -181,6 +189,9 @@ procedure g_Net_DumpSendBuffer();
 procedure g_Net_DumpRecvBuffer(Buf: penet_uint8; Len: LongWord);
 procedure g_Net_DumpEnd();
 
+function g_Net_ForwardPorts(ForwardPongPort: Boolean = True): Boolean;
+procedure g_Net_UnforwardPorts();
+
 implementation
 
 uses
@@ -305,6 +316,8 @@ begin
 
   NetMode := NET_NONE;
 
+  g_Net_UnforwardPorts();
+
   if NetDump then
     g_Net_DumpEnd();
 end;
@@ -348,6 +361,8 @@ begin
   NetAddr.host := IPAddr;
   NetAddr.port := Port;
 
+  if NetForwardPorts then g_Net_ForwardPorts();
+
   NetHost := enet_host_create(@NetAddr, NET_MAXCLIENTS, NET_CHANS, 0, 0);
 
   if (NetHost = nil) then
@@ -414,7 +429,7 @@ begin
   NetMode := NET_NONE;
 
   g_Net_Cleanup;
-  e_WriteLog('NET: Server stopped', MSG_NOTIFY);
+  e_WriteLog('NET: Server stopped', TMsgType.Notify);
 end;
 
 
@@ -582,7 +597,7 @@ begin
           TP.Lives := 0;
           TP.Kill(K_SIMPLEKILL, 0, HIT_DISCON);
           g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [TP.Name]), True);
-          e_WriteLog('NET: Client ' + TP.Name + ' [' + IntToStr(ID) + '] disconnected.', MSG_NOTIFY);
+          e_WriteLog('NET: Client ' + TP.Name + ' [' + IntToStr(ID) + '] disconnected.', TMsgType.Notify);
           g_Player_Remove(TP.UID);
         end;
 
@@ -636,7 +651,7 @@ begin
   end
   else
   begin
-    e_WriteLog('NET: Kicked from server: ' + IntToStr(NetEvent.data), MSG_NOTIFY);
+    e_WriteLog('NET: Kicked from server: ' + IntToStr(NetEvent.data), TMsgType.Notify);
     if (NetEvent.data <= NET_DISC_MAX) then
       g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_MSG_KICK] +
         _lc[TStrings_Locale(Cardinal(I_NET_DISC_NONE) + NetEvent.data)], True);
@@ -650,7 +665,7 @@ begin
   g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_MSG_CLIENT_DISC]);
 
   g_Net_Cleanup;
-  e_WriteLog('NET: Disconnected', MSG_NOTIFY);
+  e_WriteLog('NET: Disconnected', TMsgType.Notify);
 end;
 
 procedure g_Net_Client_Send(Reliable: Boolean; Chan: Byte = NET_CHAN_GAME);
@@ -789,8 +804,6 @@ begin
 
     ProcessLoading(true);
 
-    e_PollInput();
-
     if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) then
       OuterLoop := False;
   end;
@@ -954,8 +967,6 @@ begin
 
     ProcessLoading(true);
 
-    e_PollInput();
-
     if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) then
       break;
   end;
@@ -1101,6 +1112,141 @@ begin
   NetDumpFile := nil;
 end;
 
+function g_Net_ForwardPorts(ForwardPongPort: Boolean = True): Boolean;
+{$IFDEF USE_MINIUPNPC}
+var
+  DevList: PUPNPDev;
+  Urls: TUPNPUrls;
+  Data: TIGDDatas;
+  LanAddr: array [0..255] of Char;
+  ExtAddr: array [0..40] of Char;
+  StrPort: AnsiString;
+  Err, I: Integer;
+begin
+  Result := False;
+
+  if NetPortForwarded = NetPort then
+  begin
+    Result := True;
+    exit;
+  end;
+
+  conwriteln('trying to forward server ports...');
+
+  NetPongForwarded := False;
+  NetPortForwarded := 0;
+
+  DevList := upnpDiscover(2000, nil, nil, 0, 0, Addr(Err));
+  if DevList = nil then
+  begin
+    conwritefln('  upnpDiscover() failed: %d', [Err]);
+    exit;
+  end;
+
+  I := UPNP_GetValidIGD(DevList, @Urls, @Data, Addr(LanAddr[0]), 256);
+
+  if I = 0 then
+  begin
+    conwriteln('  could not find an IGD device on this LAN, aborting');
+    FreeUPNPDevList(DevList);
+    FreeUPNPUrls(@Urls);
+    exit;
+  end
+  else if I = 1 then
+    conwritefln('  found IGD @ %s', [Urls.controlURL])
+  else
+    conwritefln('  found some kind of UPNP device @ %s, maybe it''ll work', [Urls.controlURL]);
+
+  UPNP_GetExternalIPAddress(Urls.controlURL, Addr(data.first.servicetype[1]), Addr(ExtAddr[0]));
+  if ExtAddr[0] <> #0 then
+    conwritefln('  external IP address: %s', [Addr(ExtAddr[0])]);
+
+  StrPort := IntToStr(NetPort);
+  I := UPNP_AddPortMapping(
+    Urls.controlURL, Addr(data.first.servicetype[1]),
+    PChar(StrPort), PChar(StrPort), Addr(LanAddr[0]), PChar('D2DF'),
+    PChar('UDP'), nil, PChar('0')
+  );
+
+  if I <> 0 then
+  begin
+    conwritefln('  forwarding port %d failed: error %d', [NetPort, I]);
+    FreeUPNPDevList(DevList);
+    FreeUPNPUrls(@Urls);
+    exit;
+  end;
+
+  if ForwardPongPort then
+  begin
+    StrPort := IntToStr(NetPort + 1);
+    I := UPNP_AddPortMapping(
+      Urls.controlURL, Addr(data.first.servicetype[1]),
+      PChar(StrPort), PChar(StrPort), Addr(LanAddr[0]), PChar('D2DF'),
+      PChar('UDP'), nil, PChar('0')
+    );
+
+    if I <> 0 then
+    begin
+      conwritefln('  forwarding port %d failed: error %d', [NetPort + 1, I]);
+      NetPongForwarded := False;
+    end
+    else
+    begin
+      conwritefln('  forwarded port %d successfully', [NetPort + 1]);
+      NetPongForwarded := True;
+    end;
+  end;
+
+  conwritefln('  forwarded port %d successfully', [NetPort]);
+  NetIGDControl := AnsiString(Urls.controlURL);
+  NetIGDService := data.first.servicetype;
+  NetPortForwarded := NetPort;
+
+  FreeUPNPDevList(DevList);
+  FreeUPNPUrls(@Urls);
+  Result := True;
+end;
+{$ELSE}
+begin
+  Result := False;
+end;
+{$ENDIF}
+
+procedure g_Net_UnforwardPorts();
+{$IFDEF USE_MINIUPNPC}
+var
+  I: Integer;
+  StrPort: AnsiString;
+begin
+  if NetPortForwarded = 0 then Exit;
+
+  conwriteln('unforwarding ports...');
+
+  StrPort := IntToStr(NetPortForwarded);
+  I := UPNP_DeletePortMapping(
+    PChar(NetIGDControl), Addr(NetIGDService[1]),
+    PChar(StrPort), PChar('UDP'), nil
+  );
+  conwritefln('  port %d: %d', [NetPortForwarded, I]);
+
+  if NetPongForwarded then
+  begin
+    NetPongForwarded := False;
+    StrPort := IntToStr(NetPortForwarded + 1);
+    I := UPNP_DeletePortMapping(
+      PChar(NetIGDControl), Addr(NetIGDService[1]),
+      PChar(StrPort), PChar('UDP'), nil
+    );
+    conwritefln('  port %d: %d', [NetPortForwarded + 1, I]);
+  end;
+
+  NetPortForwarded := 0;
+end;
+{$ELSE}
+begin
+end;
+{$ENDIF}
+
 initialization
 
   NetIn.Alloc(NET_BUFSIZE);