View Javadoc
1   /*
2    * Copyright (C) 2013 4th Line GmbH, Switzerland
3    *
4    * The contents of this file are subject to the terms of either the GNU
5    * Lesser General Public License Version 2 or later ("LGPL") or the
6    * Common Development and Distribution License Version 1 or later
7    * ("CDDL") (collectively, the "License"). You may not use this file
8    * except in compliance with the License. See LICENSE.txt for more
9    * information.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14   */
15  package example.igd;
16  
17  import org.fourthline.cling.UpnpService;
18  import org.fourthline.cling.mock.MockUpnpService;
19  import org.fourthline.cling.model.action.ActionInvocation;
20  import org.fourthline.cling.model.message.UpnpResponse;
21  import org.fourthline.cling.model.meta.LocalDevice;
22  import org.fourthline.cling.model.meta.LocalService;
23  import org.fourthline.cling.model.meta.Service;
24  import org.fourthline.cling.model.types.UDAServiceId;
25  import org.fourthline.cling.model.types.UnsignedIntegerTwoBytes;
26  import org.fourthline.cling.registry.RegistryListener;
27  import org.fourthline.cling.support.igd.callback.PortMappingEntryGet;
28  import org.fourthline.cling.support.igd.callback.PortMappingAdd;
29  import org.fourthline.cling.support.model.PortMapping;
30  import org.fourthline.cling.support.igd.callback.PortMappingDelete;
31  import org.fourthline.cling.support.igd.PortMappingListener;
32  import org.testng.annotations.Test;
33  
34  import static org.testng.Assert.assertEquals;
35  import static org.testng.Assert.assertTrue;
36  
37  /**
38   * Mapping a NAT port
39   * <p>
40   * Cling Support contains all the neccessary functionality, creating a port mapping
41   * on all NAT routers on a network requires only three lines of code:
42   * </p>
43   * <a class="citation" href="javacode://this#addDeleteWithListener" style="include: PM1;"/>
44   * <p>
45   * The first line creates a port mapping configuration with the external/internal port, an
46   * internal host IP, the protocol and an optional description.
47   * </p>
48   * <p>
49   * The second line starts the UPnP service with a special listener. This listener
50   * will add the port mapping on any <em>InternetGatewayDevice</em> with a <em>WANIPConnection</em>
51   * or a <em>WANPPPConnection</em> service as soon as it is discovered. You should immediately start
52   * a <code>ControlPoint#search()</code> for all devices on your network, this triggers a response
53   * and discovery of all NAT routers, activating the port mapping.
54   * </p>
55   * <p>
56   * The listener will also delete the port mapping when you stop the UPnP stack through
57   * <code>UpnpService#shutdown()</code>, usually before your application quits. If you forget
58   * to shutdown the stack the port mapping will remain on the <em>InternetGatewayDevice</em>
59   * - the default lease duration is <code>0</code>!
60   * </p>
61   * <p>
62   * If anything goes wrong, log messages with <code>WARNING</code> level will be created on the
63   * category <code>org.fourthline.cling.support.igd.PortMappingListener</code>. You can override the
64   * <code>PortMappingListener#handleFailureMessage(String)</code> method to customize this behavior.
65   * </p>
66   * <p>
67   * Alternatively, you can manually add and delete port mappings on an already discovered device with
68   * the following ready-to-use action callbacks:
69   * </p>
70   * <a class="citation" href="javacode://this#addDeleteManually" style="include: PM1; exclude: EXC1, EXC2"/>
71   *
72   */
73  public class PortMappingTest {
74  
75      @Test
76      public void addDeleteWithListener() throws Exception {
77  
78          PortMapping desiredMapping =                                    // DOC: PM1
79                  new PortMapping(
80                          8123,
81                          "192.168.0.123",
82                          PortMapping.Protocol.TCP,
83                          "My Port Mapping"
84                  );
85  
86          UpnpService upnpService =
87                  new UpnpServiceImpl(
88                          new PortMappingListener(desiredMapping)
89                  );
90  
91          upnpService.getControlPoint().search();                         // DOC: PM1
92  
93          LocalDevice device = IGDSampleData.createIGDevice(TestConnection.class);
94          upnpService.getRegistry().addDevice(device);
95  
96          upnpService.shutdown();
97  
98          LocalService<TestConnection> service = device.findService(new UDAServiceId("WANIPConnection"));
99          for (boolean test : service.getManager().getImplementation().tests) {
100             assert test;
101         }
102 
103     }
104 
105     @Test
106     public void addDeleteManually() throws Exception {
107 
108         final boolean[] tests = new boolean[2];
109 
110         PortMapping desiredMapping =
111                 new PortMapping(
112                         8123,
113                         "192.168.0.123",
114                         PortMapping.Protocol.TCP,
115                         "My Port Mapping"
116                 );
117 
118         UpnpService upnpService = new UpnpServiceImpl();
119 
120         LocalDevice device = IGDSampleData.createIGDevice(TestConnection.class);
121         upnpService.getRegistry().addDevice(device);
122 
123         Service service = device.findService(new UDAServiceId("WANIPConnection"));         // DOC: PM1
124 
125         upnpService.getControlPoint().execute(
126             new PortMappingAdd(service, desiredMapping) {
127 
128                 @Override
129                 public void success(ActionInvocation invocation) {
130                     // All OK
131                     tests[0] = true;                                                        // DOC: EXC1
132                 }
133 
134                 @Override
135                 public void failure(ActionInvocation invocation,
136                                     UpnpResponse operation,
137                                     String defaultMsg) {
138                     // Something is wrong
139                 }
140             }
141         );
142 
143         final PortMapping[] mapping = {null};
144         upnpService.getControlPoint().execute(
145                 new PortMappingEntryGet(service, 0L) {
146 
147                     @Override
148                     public void success(PortMapping portMapping) {
149                         // All OK
150                         mapping[0] = portMapping;                                       // DOC: EXC1
151                     }
152 
153                     @Override
154                     public void failure(ActionInvocation invocation,
155                                         UpnpResponse operation,
156                                         String defaultMsg) {
157                         // Something is wrong
158                     }
159                 }
160         );
161         assertEquals(mapping[0].getInternalClient(), "192.168.0.123");
162         assertEquals(mapping[0].getInternalPort().getValue().longValue(), 8123);
163         assertTrue(mapping[0].isEnabled());
164 
165         upnpService.getControlPoint().execute(
166             new PortMappingDelete(service, desiredMapping) {
167 
168                 @Override
169                 public void success(ActionInvocation invocation) {
170                     // All OK
171                     tests[1] = true;                                                        // DOC: EXC2
172                 }
173 
174                 @Override
175                 public void failure(ActionInvocation invocation,
176                                     UpnpResponse operation,
177                                     String defaultMsg) {
178                     // Something is wrong
179                 }
180             }
181         );                                                                                      // DOC: PM1
182 
183         for (boolean test : tests) {
184             assert test;
185         }
186         for (boolean test : ((LocalService<TestConnection>)service).getManager().getImplementation().tests) {
187             assert test;
188         }
189 
190     }
191 
192     public static class TestConnection extends IGDSampleData.WANIPConnectionService {
193 
194         boolean[] tests = new boolean[2];
195 
196         @Override
197         protected void addPortMapping(PortMapping portMapping) {
198             assertEquals(portMapping.getExternalPort().getValue(), new Long(8123));
199             assertEquals(portMapping.getInternalPort().getValue(), new Long(8123));
200             assertEquals(portMapping.getProtocol(), PortMapping.Protocol.TCP);
201             assertEquals(portMapping.getDescription(), "My Port Mapping");
202             assertEquals(portMapping.getInternalClient(), "192.168.0.123");
203             assertEquals(portMapping.getLeaseDurationSeconds().getValue(), new Long(0));
204             assertEquals(portMapping.hasRemoteHost(), false);
205             assertEquals(portMapping.hasDescription(), true);
206             tests[0] = true;
207         }
208 
209         @Override
210         protected void deletePortMapping(PortMapping portMapping) {
211             assertEquals(portMapping.getExternalPort().getValue(), new Long(8123));
212             assertEquals(portMapping.getProtocol(), PortMapping.Protocol.TCP);
213             assertEquals(portMapping.hasRemoteHost(), false);
214             tests[1] = true;
215         }
216 
217         public PortMapping getGenericPortMappingEntry(UnsignedIntegerTwoBytes index) {
218             assertEquals(index.getValue().longValue(), 0);
219             return new PortMapping(
220                     8123,
221                     "192.168.0.123",
222                     PortMapping.Protocol.TCP,
223                     "My Port Mapping"
224             );
225         }
226     }
227 
228     class UpnpServiceImpl extends MockUpnpService {
229         UpnpServiceImpl(RegistryListener... registryListeners) {
230             super();
231             for (RegistryListener registryListener : registryListeners) {
232                 getRegistry().addListener(registryListener);
233             }
234         }
235     }
236 
237 }