1#ifdef CONF_UPNP
2
3#include "upnp.h"
4#include <base/system.h>
5#include <engine/shared/config.h>
6#include <game/version.h>
7#include <miniupnpc/miniupnpc.h>
8#include <miniupnpc/upnpcommands.h>
9#include <miniupnpc/upnperrors.h>
10
11#include <cstdlib>
12
13void CUPnP::Open(NETADDR Address)
14{
15 if(g_Config.m_SvUseUPnP)
16 {
17 m_Enabled = false;
18 m_Addr = Address;
19 m_pUPnPUrls = (struct UPNPUrls *)malloc(size: sizeof(struct UPNPUrls));
20 m_pUPnPData = (struct IGDdatas *)malloc(size: sizeof(struct IGDdatas));
21
22 char aLanAddr[64];
23 char aPort[6];
24 int Error;
25
26 m_pUPnPDevice = upnpDiscover(delay: 2000, NULL, NULL, localport: 0, ipv6: 0, ttl: 2, error: &Error);
27
28#if MINIUPNPC_API_VERSION > 17
29 char aWanAddr[64];
30 int Status = UPNP_GetValidIGD(devlist: m_pUPnPDevice, urls: m_pUPnPUrls, data: m_pUPnPData, lanaddr: aLanAddr, lanaddrlen: sizeof(aLanAddr), wanaddr: aWanAddr, wanaddrlen: sizeof(aWanAddr));
31 dbg_msg(sys: "upnp", fmt: "status=%d, lan_addr=%s, wan_addr=%s", Status, aLanAddr, aWanAddr);
32#else
33 int Status = UPNP_GetValidIGD(m_pUPnPDevice, m_pUPnPUrls, m_pUPnPData, aLanAddr, sizeof(aLanAddr));
34 dbg_msg("upnp", "status=%d, lan_addr=%s", Status, aLanAddr);
35#endif
36
37 if(Status == 1)
38 {
39 m_Enabled = true;
40 dbg_msg(sys: "upnp", fmt: "found valid IGD: %s", m_pUPnPUrls->controlURL);
41 str_format(buffer: aPort, buffer_size: sizeof(aPort), format: "%d", m_Addr.port);
42 Error = UPNP_AddPortMapping(controlURL: m_pUPnPUrls->controlURL, servicetype: m_pUPnPData->first.servicetype,
43 extPort: aPort, inPort: aPort, inClient: aLanAddr,
44 desc: "DDNet Server " GAME_RELEASE_VERSION,
45 proto: "UDP", NULL, leaseDuration: "0");
46
47 if(Error)
48 dbg_msg(sys: "upnp", fmt: "failed to map port, error: %s", strupnperror(err: Error));
49 else
50 dbg_msg(sys: "upnp", fmt: "successfully mapped port");
51 }
52 else
53 dbg_msg(sys: "upnp", fmt: "no valid IGD found, disabled");
54 }
55}
56
57void CUPnP::Shutdown()
58{
59 if(g_Config.m_SvUseUPnP)
60 {
61 if(m_Enabled)
62 {
63 char aPort[6];
64 str_format(buffer: aPort, buffer_size: sizeof(aPort), format: "%d", m_Addr.port);
65 int Error = UPNP_DeletePortMapping(controlURL: m_pUPnPUrls->controlURL, servicetype: m_pUPnPData->first.servicetype, extPort: aPort, proto: "UDP", NULL);
66
67 if(Error != 0)
68 {
69 dbg_msg(sys: "upnp", fmt: "failed to delete port mapping on shutdown: %s", strupnperror(err: Error));
70 }
71 FreeUPNPUrls(m_pUPnPUrls);
72 freeUPNPDevlist(devlist: m_pUPnPDevice);
73 }
74 free(ptr: m_pUPnPUrls);
75 free(ptr: m_pUPnPData);
76 m_pUPnPUrls = NULL;
77 m_pUPnPData = NULL;
78 }
79}
80
81#endif
82