jens@26
|
1 |
//
|
jens@26
|
2 |
// MYPortMapper.m
|
jens@26
|
3 |
// MYNetwork
|
jens@26
|
4 |
//
|
jens@26
|
5 |
// Created by Jens Alfke on 1/4/08.
|
jens@26
|
6 |
// Copyright 2008 Jens Alfke. All rights reserved.
|
jens@26
|
7 |
//
|
jens@26
|
8 |
|
jens@27
|
9 |
#import "MYDNSService.h"
|
jens@26
|
10 |
@class IPAddress;
|
jens@26
|
11 |
|
jens@26
|
12 |
|
jens@26
|
13 |
/* MYPortMapper attempts to make a particular network port on this computer publicly reachable
|
jens@26
|
14 |
for incoming connections, by "opening a hole" through a Network Address Translator
|
jens@26
|
15 |
(NAT) or firewall that may be in between the computer and the public Internet.
|
jens@26
|
16 |
|
jens@26
|
17 |
The port mapping may fail if:
|
jens@26
|
18 |
* the NAT/router/firewall does not support either the UPnP or NAT-PMP protocols;
|
jens@26
|
19 |
* the device doesn't implement the protocols correctly (this happens);
|
jens@26
|
20 |
* the network administrator has disabled port-mapping;
|
jens@26
|
21 |
* there is a second layer of NAT/firewall (this happens in some ISP networks.)
|
jens@26
|
22 |
|
jens@26
|
23 |
The PortMapper is asynchronous. It will take a nonzero amount of time to set up the
|
jens@26
|
24 |
mapping, and the mapping may change in the future as the network configuration changes.
|
jens@26
|
25 |
To be informed of changes, either use key-value observing to watch the "error" and
|
jens@26
|
26 |
"publicAddress" properties, or observe the MYPortMapperChangedNotification.
|
jens@26
|
27 |
|
jens@26
|
28 |
Typical usage is to:
|
jens@26
|
29 |
* Start a network service that listens for incoming connections on a port
|
jens@26
|
30 |
* Open a MYPortMapper
|
jens@26
|
31 |
* When the MYPortMapper reports the public address and port of the mapping, you somehow
|
jens@26
|
32 |
notify other peers of that address and port, so they can connect to you.
|
jens@26
|
33 |
* When the MYPortMapper reports changes, you (somehow) notify peers of the changes.
|
jens@26
|
34 |
* When closing the network service, close the MYPortMapper object too.
|
jens@26
|
35 |
*/
|
jens@27
|
36 |
@interface MYPortMapper : MYDNSService
|
jens@26
|
37 |
{
|
jens@27
|
38 |
@private
|
jens@26
|
39 |
UInt16 _localPort, _desiredPublicPort;
|
jens@26
|
40 |
BOOL _mapTCP, _mapUDP;
|
jens@26
|
41 |
IPAddress *_publicAddress, *_localAddress;
|
jens@26
|
42 |
}
|
jens@26
|
43 |
|
jens@26
|
44 |
/** Initializes a PortMapper that will map the given local (private) port.
|
jens@26
|
45 |
By default it will map TCP and not UDP, and will not suggest a desired public port,
|
jens@26
|
46 |
but this can be configured by setting properties before opening the PortMapper. */
|
jens@26
|
47 |
- (id) initWithLocalPort: (UInt16)localPort;
|
jens@26
|
48 |
|
jens@26
|
49 |
/** Initializes a PortMapper that will not map any ports.
|
jens@26
|
50 |
This is useful if you just want to find out your public IP address.
|
jens@26
|
51 |
(For a simplified, but synchronous, convenience method for this, see
|
jens@26
|
52 |
+findPublicAddress.) */
|
jens@26
|
53 |
- (id) initWithNullMapping;
|
jens@26
|
54 |
|
jens@26
|
55 |
/** Should the TCP or UDP port, or both, be mapped? By default, TCP only.
|
jens@26
|
56 |
These properties have no effect if changed while the PortMapper is open. */
|
jens@26
|
57 |
@property BOOL mapTCP, mapUDP;
|
jens@26
|
58 |
|
jens@26
|
59 |
/** You can set this to the public port number you'd like to get.
|
jens@26
|
60 |
It defaults to 0, which means "no preference".
|
jens@26
|
61 |
This property has no effect if changed while the PortMapper is open. */
|
jens@26
|
62 |
@property UInt16 desiredPublicPort;
|
jens@26
|
63 |
|
jens@26
|
64 |
/** Blocks till the PortMapper finishes opening. Returns YES if it opened, NO on error.
|
jens@26
|
65 |
It's not usually a good idea to use this, as it will lock up your application
|
jens@26
|
66 |
until a response arrives from the NAT. Listen for asynchronous notifications instead.
|
jens@26
|
67 |
If called when the PortMapper is closed, it will call -open for you.
|
jens@26
|
68 |
If called when it's already open, it just returns YES. */
|
jens@26
|
69 |
- (BOOL) waitTillOpened;
|
jens@26
|
70 |
|
jens@26
|
71 |
/** The known public IPv4 address/port, once it's been determined.
|
jens@26
|
72 |
This property is KV observable. */
|
jens@26
|
73 |
@property (readonly,retain) IPAddress* publicAddress;
|
jens@26
|
74 |
|
jens@26
|
75 |
/** The current local address/port, as of the time the port mapping was last updated.
|
jens@26
|
76 |
The address part is of the main interface; the port is the specified local port.
|
jens@26
|
77 |
This property is KV observable. */
|
jens@26
|
78 |
@property (readonly,retain) IPAddress* localAddress;
|
jens@26
|
79 |
|
jens@26
|
80 |
/** Returns YES if a non-null port mapping is in effect:
|
jens@26
|
81 |
that is, if the public address differs from the local one. */
|
jens@26
|
82 |
@property (readonly) BOOL isMapped;
|
jens@26
|
83 |
|
jens@26
|
84 |
|
jens@26
|
85 |
// UTILITY CLASS METHOD:
|
jens@26
|
86 |
|
jens@26
|
87 |
/** Determine the main interface's public IP address, without mapping any ports.
|
jens@26
|
88 |
This method internally calls -waitTillOpened, so it may take a nontrivial amount
|
jens@26
|
89 |
of time (and will crank the runloop while it waits.)
|
jens@26
|
90 |
If you want to do this asynchronously, you should instead create a new
|
jens@26
|
91 |
MYPortMapper instance using -initWithNullMapping. */
|
jens@26
|
92 |
+ (IPAddress*) findPublicAddress;
|
jens@26
|
93 |
|
jens@26
|
94 |
@end
|
jens@26
|
95 |
|
jens@26
|
96 |
|
jens@26
|
97 |
/** This notification is posted asynchronously when the status of a PortMapper
|
jens@26
|
98 |
(its error, publicAddress or publicPort) changes. */
|
jens@26
|
99 |
extern NSString* const MYPortMapperChangedNotification;
|