1 46 47 58 59 package org.mr.core.net; 60 61 import java.net.InetAddress ; 62 import java.net.InetSocketAddress ; 63 import java.util.HashMap ; 64 import java.util.HashSet ; 65 import java.util.Iterator ; 66 import java.util.Map ; 67 68 import org.apache.commons.logging.Log; 69 import org.apache.commons.logging.LogFactory; 70 import org.cybergarage.upnp.Action; 71 import org.cybergarage.upnp.ControlPoint; 72 import org.cybergarage.upnp.Device; 73 import org.cybergarage.upnp.DeviceList; 74 import org.cybergarage.upnp.Service; 75 import org.cybergarage.upnp.ServiceList; 76 import org.cybergarage.upnp.UPnPStatus; 77 import org.mr.MantaAgent; 78 import org.mr.core.configuration.ConfigManager; 79 import org.mr.core.util.SystemTime; 80 import org.mr.core.util.TimeoutTimer; 81 import org.mr.core.util.Timeoutable; 82 83 public class IGDPortMapper implements Timeoutable { 84 class Mapping { 85 private static final long DEFAULT_MIN_MAP_INTERVAL = 1000; 86 private static final long DEFAULT_REMAP_INTERVAL = 300000; 87 88 InetSocketAddress inner; 89 InetSocketAddress outer; 90 boolean tcp; 91 boolean pending; 92 long nextAction; 93 long interval; 94 95 Mapping(InetSocketAddress inner, InetSocketAddress outer, boolean tcp) 96 { 97 this.inner = inner; 98 this.outer = outer; 99 this.tcp = tcp; 100 this.pending = true; 101 this.nextAction = SystemTime.currentTimeMillis(); 102 this.interval = DEFAULT_MIN_MAP_INTERVAL; 103 } 104 105 public boolean equals(Mapping other) { 106 return (this.inner.equals(other.inner) && this.tcp == other.tcp); 107 } 108 109 112 public int hashCode(){ 113 return this.inner.hashCode(); 114 } 115 public int getLeaseDuration() { 116 return (int) (DEFAULT_REMAP_INTERVAL / 1000) * 2; 117 } 118 119 public boolean readyForAction() { 120 return SystemTime.currentTimeMillis() >= this.nextAction; 121 } 122 123 public void mappingSucceeded() { 124 this.pending = false; 125 this.nextAction = this.nextAction + DEFAULT_REMAP_INTERVAL; 126 } 127 128 public void mappingFailed() { 129 if (this.pending == false) { 130 this.interval = DEFAULT_MIN_MAP_INTERVAL; 131 } else { 132 this.interval = (long) ((double) this.interval * 1.7); 133 } 134 this.nextAction = this.nextAction + interval; 135 } 136 137 public String toString() { 138 StringBuffer buf = new StringBuffer (); 139 buf.append(inner).append('/').append(outer).append('/'); 140 buf.append(tcp ? "TCP" : "UDP"); 141 return buf.toString(); 142 } 143 144 public String dumpStatus() { 145 StringBuffer buf = new StringBuffer (); 146 buf.append(toString()); 147 buf.append(" ["); 148 buf.append(pending ? "pending " : ""); 149 buf.append(nextAction).append(' '); 150 buf.append(interval).append(']'); 151 return buf.toString(); 152 } 153 } 154 155 private ControlPoint cpoint; 156 private HashSet mappings; 157 private HashMap services; 158 private TimeoutTimer timer; 159 private Log log; 160 private boolean enabled; 161 private boolean infiniteLease; 162 163 private final static String WAN_CONNECTION_DEVICE = 164 "urn:schemas-upnp-org:device:WANConnectionDevice:1"; 165 private final static String WAN_IP_SERVICE = 166 "urn:schemas-upnp-org:service:WANIPConnection:1"; 167 private final static String WAN_PPP_SERVICE = 168 "urn:schemas-upnp-org:service:WANPPPConnection:1"; 169 private final static long TIMER_INTERVAL = 1000; 170 171 private static IGDPortMapper instance = null; 172 173 public static synchronized IGDPortMapper getInstance() { 174 if (instance == null) { 175 instance = new IGDPortMapper(); 176 } 177 return instance; 178 } 179 180 private IGDPortMapper() { 181 this.enabled = true; 183 this.infiniteLease = false; 184 ConfigManager config = MantaAgent.getInstance().getSingletonRepository().getConfigManager(); 185 if (config != null) { 186 this.enabled = 187 config.getBooleanProperty("network.upnp.enabled", false); 188 this.infiniteLease = 189 config.getBooleanProperty("network.upnp.infinite-lease", false); 190 } 191 192 if (isEnabled()) { 193 this.cpoint = new ControlPoint(); 194 this.mappings = new HashSet (); 195 this.services = new HashMap (); 196 this.timer = new TimeoutTimer("upnp",TIMER_INTERVAL, 1); 197 this.log = LogFactory.getLog("IGDPortMapper"); 198 this.cpoint.start(); 200 this.timer.addTimeout(this, this, TIMER_INTERVAL); 203 } 204 } 206 212 public boolean isEnabled() { 213 return this.enabled; 214 } 215 216 229 public void addMapping(InetSocketAddress inner, InetSocketAddress outer, 230 boolean tcp) 231 { 232 Mapping mapping = new Mapping(inner, outer, tcp); 233 this.mappings.add(mapping); 234 if(log.isDebugEnabled()){ 235 log.debug("Mapping added " + mapping+"."); 236 } 237 } 238 239 246 public void removeMapping(InetSocketAddress inner, boolean tcp) { 247 Mapping mapping = new Mapping(inner, null, tcp); 248 this.mappings.remove(mapping); 249 if(log.isDebugEnabled()){ 250 log.debug("Mapping removed " + mapping+"."); 251 } 252 } 253 254 265 public void timeout(Object event) { 266 housekeeper(); 267 this.timer.addTimeout(this, this, TIMER_INTERVAL); 268 } 269 270 273 public void dumpStatus() { 274 Iterator i = this.mappings.iterator(); 275 System.out.println("Mappings"); 276 System.out.println("--------"); 277 while (i.hasNext()) { 278 System.out.println(((Mapping) i.next()).dumpStatus()); 279 } 280 System.out.println(); 281 System.out.println("Cached Services"); 282 System.out.println("---------------"); 283 i = this.services.entrySet().iterator(); 284 while (i.hasNext()) { 285 Map.Entry entry = (Map.Entry ) i.next(); 286 System.out.print(entry.getKey().toString() + ": "); 287 System.out.println(entry.getValue().toString()); 288 } 289 System.out.println(); 290 System.out.println(); 291 } 292 293 private void housekeeper() { 294 Iterator i = this.mappings.iterator(); 295 while (i.hasNext()) { 296 Mapping mapping = (Mapping) i.next(); 297 if (mapping.readyForAction()) { 298 tryMapping(mapping); 299 } 300 } 301 } 302 303 private void tryMapping(Mapping mapping) { 304 Service service = findService(mapping.outer.getAddress()); 305 if (service == null) { 306 if(log.isWarnEnabled()){ 307 log.warn("Could not create mapping " + mapping + 308 ": no device with specified address found."); 309 } 310 mapping.mappingFailed(); 311 } else { 312 Action mapAction = service.getAction("AddPortMapping"); 313 mapAction.setArgumentValue("NewRemoteHost", ""); mapAction.setArgumentValue("NewExternalPort", 315 "" + mapping.outer.getPort()); 316 mapAction.setArgumentValue("NewProtocol", 317 mapping.tcp ? "TCP" : "UDP"); 318 mapAction.setArgumentValue("NewInternalPort", 319 "" + mapping.inner.getPort()); 320 mapAction.setArgumentValue("NewInternalClient", 321 "" + mapping.inner.getAddress().getHostAddress()); 322 mapAction.setArgumentValue("NewEnabled", "1"); 323 mapAction.setArgumentValue("NewPortMappingDescription", "Manta!"); 324 int leaseDuration = 325 (infiniteLease ? 0 : mapping.getLeaseDuration()); 326 mapAction.setArgumentValue("NewLeaseDuration", "" + leaseDuration); 327 328 if (mapAction.postControlAction()) { 329 mapping.mappingSucceeded(); 330 if(log.isDebugEnabled()){ 331 log.debug("Mapping succeeded " + mapping+"."); 332 } 333 } else { 334 if(log.isWarnEnabled()){ 335 UPnPStatus err = mapAction.getStatus(); 336 log.warn("Could not create mapping " + mapping + 337 ": " + 338 UPnPStatus.code2String(err.getCode()) + 339 ": " + err.getDescription()+"."); 340 } 341 mapping.mappingFailed(); 342 removeCachedService(mapping.outer.getAddress()); 343 } 344 } 345 } 346 347 private Service findService(InetAddress address) { 348 Service service = (Service) this.services.get(address); 349 if (service == null) { 350 DeviceList devices = this.cpoint.getDeviceList(); 351 for (int i = 0; i < devices.size(); i++) { 352 Device rootDevice = devices.getDevice(i); 353 Device wanDevice = rootDevice.getDevice(WAN_CONNECTION_DEVICE); 354 if (wanDevice != null) { 355 ServiceList serviceList = wanDevice.getServiceList(); 356 for (int j = 0; j < serviceList.size(); j++) { 357 service = serviceList.getService(j); 358 if (service.getServiceType().equals(WAN_IP_SERVICE) || 359 service.getServiceType().equals(WAN_PPP_SERVICE)) { 360 cacheService(service); 361 } 362 } 363 } 364 } 365 } 366 367 return (Service) this.services.get(address); 369 } 370 371 374 private void cacheService(Service service) { 375 Action action = service.getAction("GetExternalIPAddress"); 376 if (action.postControlAction()) { 377 InetAddress addr; 378 String addrString = 379 action.getArgumentValue("NewExternalIPAddress"); 380 try { 381 addr = InetAddress.getByName(addrString); 382 this.services.put(addr, service); 383 } catch (Exception e) { 384 log.error("IGD: " + e.getMessage()); 387 } 388 } else { 389 if(log.isWarnEnabled()){ 390 log.warn("Could not get address from service" + service+"."); 391 } 392 } 393 } 394 395 private void removeCachedService(InetAddress addr) { 396 this.services.remove(addr); 397 } 398 } | Popular Tags |