annotate sat/plugins/plugin_misc_nat-port.py @ 2617:81b70eeb710f

quick_frontend(contact list): refactored update: update is now called with appropriate constant value (C.UPDATE_ADD, C.UPDATE_DELETE, C.UPDATE_MODIFY and so on) when a widget change visibility according to current options. Before it was linked to cache only (C.UPDATE_ADD was only called when contact was first added to cache). This make widget handling in frontends more easy. Renamed entityToShow to entityVisible, which seems to correspond better. Started reducing lines lenght to 90 chars as a test. May become the new coding style soon.
author Goffi <goffi@goffi.org>
date Sun, 24 Jun 2018 21:59:29 +0200
parents 26edcf3a30eb
children 56f94936df1e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1934
2daf7b4c6756 use of /usr/bin/env instead of /usr/bin/python in shebang
Goffi <goffi@goffi.org>
parents: 1766
diff changeset
1 #!/usr/bin/env python2
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 # SAT plugin for NAT port mapping
2483
0046283a285d dates update
Goffi <goffi@goffi.org>
parents: 2414
diff changeset
5 # Copyright (C) 2009-2018 Jérôme Poisson (goffi@goffi.org)
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
6
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # This program is free software: you can redistribute it and/or modify
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 # (at your option) any later version.
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
11
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # This program is distributed in the hope that it will be useful,
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 # GNU Affero General Public License for more details.
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from sat.core.i18n import _
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 from sat.core.constants import Const as C
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 from sat.core.log import getLogger
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 log = getLogger(__name__)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from sat.core import exceptions
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 from twisted.internet import threads
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from twisted.internet import defer
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
27 from twisted.python import failure
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
28 import threading
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
29
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 try:
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
31 import miniupnpc
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
32 except ImportError:
1562
7d91dff71067 plugin NAT Port: added instruction with pip when miniupnpc is missing
Goffi <goffi@goffi.org>
parents: 1554
diff changeset
33 raise exceptions.MissingModule(u"Missing module MiniUPnPc, please download/install it (and its Python binding) at http://miniupnp.free.fr/ (or use pip install miniupnpc)")
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
34
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
35
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 PLUGIN_INFO = {
2145
33c8c4973743 core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents: 1934
diff changeset
37 C.PI_NAME: "NAT port mapping",
33c8c4973743 core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents: 1934
diff changeset
38 C.PI_IMPORT_NAME: "NAT-PORT",
33c8c4973743 core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents: 1934
diff changeset
39 C.PI_TYPE: C.PLUG_TYPE_MISC,
33c8c4973743 core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents: 1934
diff changeset
40 C.PI_MAIN: "NatPort",
33c8c4973743 core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents: 1934
diff changeset
41 C.PI_HANDLER: "no",
33c8c4973743 core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents: 1934
diff changeset
42 C.PI_DESCRIPTION: _("""Automatic NAT port mapping using UPnP"""),
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 }
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
44
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
45 STARTING_PORT = 6000 # starting point to automatically find a port
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
46 DEFAULT_DESC = u'SaT port mapping' # we don't use "à" here as some bugged NAT don't manage charset correctly
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
47
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
48
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
49 class MappingError(Exception):
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
50 pass
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
51
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
52
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 class NatPort(object):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 # TODO: refresh data if a new connection is detected (see plugin_misc_ip)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
55
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 def __init__(self, host):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
57 log.info(_("plugin NAT Port initialization"))
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 self.host = host
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 self._external_ip = None
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 self._initialised = defer.Deferred()
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 self._upnp = miniupnpc.UPnP() # will be None if no device is available
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 self._upnp.discoverdelay=200
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
63 self._mutex = threading.Lock() # used to protect access to self._upnp
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
64 self._starting_port_cache = None # used to cache the first available port
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
65 self._to_unmap = [] # list of tuples (ext_port, protocol) of ports to unmap on unload
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
66 discover_d = threads.deferToThread(self._discover)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 discover_d.chainDeferred(self._initialised)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 self._initialised.addErrback(self._init_failed)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
69
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
70 def unload(self):
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
71 if self._to_unmap:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
72 log.info(u"Cleaning mapped ports")
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
73 return threads.deferToThread(self._unmapPortsBlocking)
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
74
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
75 def _init_failed(self, failure_):
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
76 e = failure_.trap(exceptions.NotFound, exceptions.FeatureNotFound)
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
77 if e == exceptions.FeatureNotFound:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
78 log.info(u"UPnP-IGD seems to be not activated on the device")
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
79 else:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
80 log.info(u"UPnP-IGD not available")
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
81 self._upnp = None
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
82
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 def _discover(self):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
84 devices = self._upnp.discover()
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 if devices:
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 log.info(u"{nb} UPnP-IGD device(s) found".format(nb=devices))
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
87 else:
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 log.info(u"Can't find UPnP-IGD device on the local network")
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
89 raise failure.Failure(exceptions.NotFound())
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 self._upnp.selectigd()
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
91 try:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
92 self._external_ip = self._upnp.externalipaddress()
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
93 except Exception:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
94 raise failure.Failure(exceptions.FeatureNotFound())
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
95
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 def getIP(self, local=False):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
97 """Return IP address found with UPnP-IGD
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
98
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 @param local(bool): True to get external IP address, False to get local network one
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 @return (None, str): found IP address, or None of something got wrong
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 """
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 def getIP(dummy):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 if self._upnp is None:
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 return None
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 # lanaddr can be the empty string if not found,
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
106 # we need to return None in this case
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 return (self._upnp.lanaddr or None) if local else self._external_ip
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 return self._initialised.addCallback(getIP)
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
109
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
110 def _unmapPortsBlocking(self):
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
111 """Unmap ports mapped in this session"""
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
112 self._mutex.acquire()
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
113 try:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
114 for port, protocol in self._to_unmap:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
115 log.info(u"Unmapping port {}".format(port))
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
116 unmapping = self._upnp.deleteportmapping(
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
117 # the last parameter is remoteHost, we don't use it
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
118 port, protocol, '')
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
119
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
120 if not unmapping:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
121 log.error(u"Can't unmap port {port} ({protocol})".format(
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
122 port=port, protocol=protocol))
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
123 del self._to_unmap[:]
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
124 finally:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
125 self._mutex.release()
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
126
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
127 def _mapPortBlocking(self, int_port, ext_port, protocol, desc):
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
128 """Internal blocking method to map port
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
129
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
130 @param int_port(int): internal port to use
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
131 @param ext_port(int): external port to use, or None to find one automatically
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
132 @param protocol(str): 'TCP' or 'UDP'
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
133 @param desc(str): description of the mapping
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
134 @param return(int, None): external port used in case of success, otherwise None
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
135 """
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
136 # we use mutex to avoid race condition if 2 threads
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
137 # try to acquire a port at the same time
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
138 self._mutex.acquire()
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
139 try:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
140 if ext_port is None:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
141 # find a free port
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
142 starting_port = self._starting_port_cache
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
143 ext_port = STARTING_PORT if starting_port is None else starting_port
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
144 ret = self._upnp.getspecificportmapping(ext_port, protocol)
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
145 while ret != None and ext_port < 65536:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
146 ext_port += 1
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
147 ret = self._upnp.getspecificportmapping(ext_port, protocol)
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
148 if starting_port is None:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
149 # XXX: we cache the first successfuly found external port
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
150 # to avoid testing again the first series the next time
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
151 self._starting_port_cache = ext_port
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
152
2488
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
153 try:
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
154 mapping = self._upnp.addportmapping(
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
155 # the last parameter is remoteHost, we don't use it
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
156 ext_port, protocol, self._upnp.lanaddr, int_port, desc, '')
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
157 except Exception as e:
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
158 log.error(_(u"addportmapping error: {msg}").format(msg=e))
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
159 raise failure.Failure(MappingError())
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
160
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
161 if not mapping:
2488
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
162 raise failure.Failure(MappingError())
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
163 else:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
164 self._to_unmap.append((ext_port, protocol))
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
165 finally:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
166 self._mutex.release()
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
167
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
168 return ext_port
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
169
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
170 def mapPort(self, int_port, ext_port=None, protocol='TCP', desc=DEFAULT_DESC):
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
171 """Add a port mapping
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
172
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
173 @param int_port(int): internal port to use
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
174 @param ext_port(int,None): external port to use, or None to find one automatically
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
175 @param protocol(str): 'TCP' or 'UDP'
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
176 @param desc(unicode): description of the mapping
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
177 Some UPnP IGD devices have broken encoding. It's probably a good idea to avoid non-ascii chars here
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
178 @return (D(int, None)): external port used in case of success, otherwise None
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
179 """
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
180 if self._upnp is None:
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
181 return defer.succeed(None)
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
182 def mappingCb(ext_port):
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
183 log.info(u"{protocol} mapping from {int_port} to {ext_port} successful".format(
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
184 protocol = protocol,
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
185 int_port = int_port,
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
186 ext_port = ext_port,
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
187 ))
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
188 return ext_port
2488
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
189 def mappingEb(failure_):
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
190 failure_.trap(MappingError)
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
191 log.warning(u"Can't map internal {int_port}".format(int_port=int_port))
2488
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
192 def mappingUnknownEb(failure_):
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
193 log.error(_(u"error while trying to map ports: {msg}").format(msg=failure_))
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
194 d = threads.deferToThread(self._mapPortBlocking, int_port, ext_port, protocol, desc)
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
195 d.addCallbacks(mappingCb, mappingEb)
2488
78c7992a26ed plugin NAT-port: raise MappingError if something get wrong during "addportmapping" + log unexpected errors (i.e. everything else than MappingError)
Goffi <goffi@goffi.org>
parents: 2483
diff changeset
196 d.addErrback(mappingUnknownEb)
1554
e281ed2c21db plugin NAT port: added UPnP IGD mapping + automatic unmapping on backend shut down
Goffi <goffi@goffi.org>
parents: 1536
diff changeset
197 return d