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