upnp port forwarding
[p2pool.git] / nattraverso / portmapper.py
1 """
2 Generic NAT Port mapping interface.
3
4 TODO: Example
5
6 @author: Raphael Slinckx
7 @copyright: Copyright 2005
8 @license: LGPL
9 @contact: U{raphael@slinckx.net<mailto:raphael@slinckx.net>}
10 @version: 0.1.0
11 """
12
13 __revision__ = "$id"
14
15 from twisted.internet.base import BasePort
16
17 # Public API
18 def get_port_mapper(proto="TCP"):
19         """
20         Returns a L{NATMapper} instance, suited to map a port for
21         the given protocol. Defaults to TCP.
22         
23         For the moment, only upnp mapper is available. It accepts both UDP and TCP.
24         
25         @param proto: The protocol: 'TCP' or 'UDP'
26         @type proto: string
27         @return: A deferred called with a L{NATMapper} instance
28         @rtype: L{twisted.internet.defer.Deferred}
29         """
30         import nattraverso.pynupnp
31         return nattraverso.pynupnp.get_port_mapper()
32         
33 class NATMapper:
34         """
35         Define methods to map port objects (as returned by twisted's listenXX).
36         This allows NAT to be traversed from incoming packets.
37         
38         Currently the only implementation of this class is the UPnP Mapper, which
39         can map UDP and TCP ports, if an UPnP Device exists.
40         """
41         def __init__(self):
42                 raise NotImplementedError("Cannot instantiate the class")
43                 
44         def map(self, port):
45                 """
46                 Create a mapping for the given twisted's port object.
47                 
48                 The deferred will call back with a tuple (extaddr, extport):
49                         - extaddr: The ip string of the external ip address of this host
50                         - extport: the external port number used to map the given Port object
51                 
52                 When called multiple times with the same Port,
53                 callback with the existing mapping.
54                 
55                 @param port: The port object to map
56                 @type port: a L{twisted.internet.interfaces.IListeningPort} object
57                 @return: A deferred called with the above defined tuple
58                 @rtype: L{twisted.internet.defer.Deferred}
59                 """
60                 raise NotImplementedError
61
62         def info(self, port):
63                 """
64                 Returns the existing mapping for the given port object. That means map()
65                 has to be called before.
66                 
67                 @param port: The port object to retreive info from
68                 @type port: a L{twisted.internet.interfaces.IListeningPort} object
69                 @raise ValueError: When there is no such existing mapping
70                 @return: a tuple (extaddress, extport).
71                 @see: L{map() function<map>}
72                 """
73                 raise NotImplementedError
74
75         def unmap(self, port):
76                 """
77                 Remove an existing mapping for the given twisted's port object.
78                 
79                 @param port: The port object to unmap
80                 @type port: a L{twisted.internet.interfaces.IListeningPort} object
81                 @return: A deferred called with None
82                 @rtype: L{twisted.internet.defer.Deferred}
83                 @raise ValueError: When there is no such existing mapping
84                 """
85                 raise NotImplementedError
86         
87         def get_port_mappings(self):
88                 """
89                 Returns a deferred that will be called with a dictionnary of the
90                 existing mappings.
91                 
92                 The dictionnary structure is the following:
93                         - Keys: tuple (protocol, external_port)
94                                 - protocol is "TCP" or "UDP".
95                                 - external_port is the external port number, as see on the
96                                         WAN side.
97                         - Values:tuple (internal_ip, internal_port)
98                                 - internal_ip is the LAN ip address of the host.
99                                 - internal_port is the internal port number mapped
100                                         to external_port.
101                 
102                 @return: A deferred called with the above defined dictionnary
103                 @rtype: L{twisted.internet.defer.Deferred}
104                 """
105                 raise NotImplementedError
106                 
107         def _check_valid_port(self, port):
108                 """Various Port object validity checks. Raise a ValueError."""
109                 if not isinstance(port, BasePort):
110                         raise ValueError("expected a Port, got %r"%(port))
111
112                 if not port.connected:
113                         raise ValueError("Port %r is not listening"%(port))
114
115                 loc_addr = port.getHost()
116                 if loc_addr.port == 0:
117                         raise ValueError("Port %r has port number of 0"%(port))
118