1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.support.igd;
17
18 import org.fourthline.cling.model.action.ActionInvocation;
19 import org.fourthline.cling.model.message.UpnpResponse;
20 import org.fourthline.cling.model.meta.Device;
21 import org.fourthline.cling.model.meta.Service;
22 import org.fourthline.cling.model.types.DeviceType;
23 import org.fourthline.cling.model.types.ServiceType;
24 import org.fourthline.cling.model.types.UDADeviceType;
25 import org.fourthline.cling.model.types.UDAServiceType;
26 import org.fourthline.cling.registry.DefaultRegistryListener;
27 import org.fourthline.cling.registry.Registry;
28 import org.fourthline.cling.support.igd.callback.PortMappingAdd;
29 import org.fourthline.cling.support.igd.callback.PortMappingDelete;
30 import org.fourthline.cling.support.model.PortMapping;
31
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.logging.Logger;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public class PortMappingListener extends DefaultRegistryListener {
71
72 private static final Logger log = Logger.getLogger(PortMappingListener.class.getName());
73
74 public static final DeviceType IGD_DEVICE_TYPE = new UDADeviceType("InternetGatewayDevice", 1);
75 public static final DeviceType CONNECTION_DEVICE_TYPE = new UDADeviceType("WANConnectionDevice", 1);
76
77 public static final ServiceType IP_SERVICE_TYPE = new UDAServiceType("WANIPConnection", 1);
78 public static final ServiceType PPP_SERVICE_TYPE = new UDAServiceType("WANPPPConnection", 1);
79
80 protected PortMapping[] portMappings;
81
82
83 protected Map<Service, List<PortMapping>> activePortMappings = new HashMap<>();
84
85 public PortMappingListener(PortMapping portMapping) {
86 this(new PortMapping[]{portMapping});
87 }
88
89 public PortMappingListener(PortMapping[] portMappings) {
90 this.portMappings = portMappings;
91 }
92
93 @Override
94 synchronized public void deviceAdded(Registry registry, Device device) {
95
96 Service connectionService;
97 if ((connectionService = discoverConnectionService(device)) == null) return;
98
99 log.fine("Activating port mappings on: " + connectionService);
100
101 final List<PortMapping> activeForService = new ArrayList<>();
102 for (final PortMapping pm : portMappings) {
103 new PortMappingAdd(connectionService, registry.getUpnpService().getControlPoint(), pm) {
104
105 @Override
106 public void success(ActionInvocation invocation) {
107 log.fine("Port mapping added: " + pm);
108 activeForService.add(pm);
109 }
110
111 @Override
112 public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
113 handleFailureMessage("Failed to add port mapping: " + pm);
114 handleFailureMessage("Reason: " + defaultMsg);
115 }
116 }.run();
117 }
118
119 activePortMappings.put(connectionService, activeForService);
120 }
121
122 @Override
123 synchronized public void deviceRemoved(Registry registry, Device device) {
124 for (Service service : device.findServices()) {
125 Iterator<Map.Entry<Service, List<PortMapping>>> it = activePortMappings.entrySet().iterator();
126 while (it.hasNext()) {
127 Map.Entry<Service, List<PortMapping>> activeEntry = it.next();
128 if (!activeEntry.getKey().equals(service)) continue;
129
130 if (activeEntry.getValue().size() > 0)
131 handleFailureMessage("Device disappeared, couldn't delete port mappings: " + activeEntry.getValue().size());
132
133 it.remove();
134 }
135 }
136 }
137
138 @Override
139 synchronized public void beforeShutdown(Registry registry) {
140 for (Map.Entry<Service, List<PortMapping>> activeEntry : activePortMappings.entrySet()) {
141
142 final Iterator<PortMapping> it = activeEntry.getValue().iterator();
143 while (it.hasNext()) {
144 final PortMapping pm = it.next();
145 log.fine("Trying to delete port mapping on IGD: " + pm);
146 new PortMappingDelete(activeEntry.getKey(), registry.getUpnpService().getControlPoint(), pm) {
147
148 @Override
149 public void success(ActionInvocation invocation) {
150 log.fine("Port mapping deleted: " + pm);
151 it.remove();
152 }
153
154 @Override
155 public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
156 handleFailureMessage("Failed to delete port mapping: " + pm);
157 handleFailureMessage("Reason: " + defaultMsg);
158 }
159
160 }.run();
161 }
162 }
163 }
164
165 protected Service discoverConnectionService(Device device) {
166 if (!device.getType().equals(IGD_DEVICE_TYPE)) {
167 return null;
168 }
169
170 Device[] connectionDevices = device.findDevices(CONNECTION_DEVICE_TYPE);
171 if (connectionDevices.length == 0) {
172 log.fine("IGD doesn't support '" + CONNECTION_DEVICE_TYPE + "': " + device);
173 return null;
174 }
175
176 Device connectionDevice = connectionDevices[0];
177 log.fine("Using first discovered WAN connection device: " + connectionDevice);
178
179 Service ipConnectionService = connectionDevice.findService(IP_SERVICE_TYPE);
180 Service pppConnectionService = connectionDevice.findService(PPP_SERVICE_TYPE);
181
182 if (ipConnectionService == null && pppConnectionService == null) {
183 log.fine("IGD doesn't support IP or PPP WAN connection service: " + device);
184 }
185
186 return ipConnectionService != null ? ipConnectionService : pppConnectionService;
187 }
188
189 protected void handleFailureMessage(String s) {
190 log.warning(s);
191 }
192
193 }
194