public void attachLoggerChannel(LoggerChannel channel) {
    channel.addListener(
        new LoggerChannelListener() {
          public void messageLogged(String message, Throwable t) {
            messageLogged(LoggerChannel.LT_ERROR, message, t);
          }

          public void messageLogged(int logtype, String message) {
            messageLogged(logtype, message, null);
          }

          public void messageLogged(int logtype, String message, Throwable t) {
            String log_type_s = null;
            switch (logtype) {
              case LoggerChannel.LT_WARNING:
                log_type_s = "warning";
                break;
              case LoggerChannel.LT_ERROR:
                log_type_s = "error";
                break;
            }
            if (log_type_s != null) {
              String prefix = MessageText.getString("AlertMessageBox." + log_type_s);
              log.appendText("[" + prefix.toUpperCase() + "] ");
            }
            log.appendText(message + "\n");
            if (t != null) {
              StringWriter sw = new StringWriter();
              PrintWriter pw = new PrintWriter(sw);
              t.printStackTrace(pw);
              log.appendText(sw.toString() + "\n");
            }
          }
        });
  }
示例#2
0
  protected void logAlert(int type, String resource, String[] params) {
    String text =
        plugin_interface
            .getUtilities()
            .getLocaleUtilities()
            .getLocalisedMessageText(resource, params);

    log.logAlertRepeatable(type, text);
  }
示例#3
0
  protected void removeService(UPnPWANConnection wan_service, boolean replaced) {
    try {
      this_mon.enter();

      String name =
          wan_service.getGenericService().getServiceType().indexOf("PPP") == -1
              ? "WANIPConnection"
              : "WANPPPConnection";

      String text =
          MessageText.getString(
              "upnp.alert.lostdevice",
              new String[] {
                name,
                wan_service.getGenericService().getDevice().getRootDevice().getLocation().getHost()
              });

      log.log(text);

      if ((!replaced) && alert_device_probs_param.getValue()) {

        log.logAlertRepeatable(LoggerChannel.LT_WARNING, text);
      }

      for (int i = 0; i < services.size(); i++) {

        UPnPPluginService ps = (UPnPPluginService) services.get(i);

        if (ps.getService() == wan_service) {

          services.remove(i);

          break;
        }
      }
    } finally {

      this_mon.exit();
    }
  }
示例#4
0
  protected void logNoRepeat(String usn, String msg) {
    synchronized (log_no_repeat_map) {
      String last = (String) log_no_repeat_map.get(usn);

      if (last != null && last.equals(msg)) {

        return;
      }

      log_no_repeat_map.put(usn, msg);
    }

    log.log(msg);
  }
示例#5
0
  public void rootDeviceFound(UPnPRootDevice device) {
    incrementDeviceStats(device.getUSN(), "found");

    checkDeviceStats(device);

    try {
      int interesting = processDevice(device.getDevice());

      if (interesting > 0) {

        try {
          this_mon.enter();

          root_info_map.put(device.getLocation(), device.getInfo());

          Iterator<String> it = root_info_map.values().iterator();

          String all_info = "";

          List reported_info = new ArrayList();

          while (it.hasNext()) {

            String info = (String) it.next();

            if (info != null && !reported_info.contains(info)) {

              reported_info.add(info);

              all_info += (all_info.length() == 0 ? "" : ",") + info;
            }
          }

          if (all_info.length() > 0) {

            plugin_interface.getPluginconfig().setPluginParameter("plugin.info", all_info);
          }

        } finally {

          this_mon.exit();
        }
      }
    } catch (Throwable e) {

      log.log("Root device processing fails", e);
    }
  }
示例#6
0
  protected void closeDown(final boolean end_of_day) {
    // problems here at end of day regarding devices that hang and cause AZ to hang around
    // got ages before terminating

    final AESemaphore sem = new AESemaphore("UPnPPlugin:closeTimeout");

    new AEThread("UPnPPlugin:closeTimeout", true) {
      public void runSupport() {
        try {
          for (int i = 0; i < mappings.size(); i++) {

            UPnPMapping mapping = (UPnPMapping) mappings.get(i);

            if (!mapping.isEnabled()) {

              continue;
            }

            for (int j = 0; j < services.size(); j++) {

              UPnPPluginService service = (UPnPPluginService) services.get(j);

              service.removeMapping(log, mapping, end_of_day);
            }
          }
        } finally {

          sem.release();
        }
      }
    }.start();

    if (!sem.reserve(end_of_day ? 15 * 1000 : 0)) {

      String msg =
          "A UPnP device is taking a long time to release its port mappings, consider disabling this via the UPnP configuration.";

      if (upnp_log_listener != null) {

        upnp_log_listener.logAlert(msg, false, UPnPLogListener.TYPE_ONCE_PER_SESSION);

      } else {

        log.logAlertRepeatable(LoggerChannel.LT_WARNING, msg);
      }
    }
  }
示例#7
0
  protected void addMapping(UPnPMapping mapping) {
    try {
      this_mon.enter();

      mappings.add(mapping);

      log.log("Mapping request: " + mapping.getString() + ", enabled = " + mapping.isEnabled());

      mapping.addListener(this);

      checkState();

    } finally {

      this_mon.exit();
    }
  }
示例#8
0
  public void mappingDestroyed(UPnPMapping mapping) {
    try {
      this_mon.enter();

      mappings.remove(mapping);

      log.log("Mapping request removed: " + mapping.getString());

      for (int j = 0; j < services.size(); j++) {

        UPnPPluginService service = (UPnPPluginService) services.get(j);

        service.removeMapping(log, mapping, false);
      }
    } finally {

      this_mon.exit();
    }
  }
示例#9
0
  protected void updateIgnoreList() {
    try {
      String param = "";

      if (ignore_bad_devices.getValue()) {

        PluginConfig pc = plugin_interface.getPluginconfig();

        Map ignored = pc.getPluginMapParameter("upnp.device.ignorelist", new HashMap());

        Iterator it = ignored.entrySet().iterator();

        while (it.hasNext()) {

          Map.Entry entry = (Map.Entry) it.next();

          Map value = (Map) entry.getValue();

          param += "\n    " + entry.getKey() + ": " + new String((byte[]) value.get("Location"));
        }

        if (ignored.size() > 0) {

          log.log("Devices currently being ignored: " + param);
        }
      }

      String text =
          plugin_interface
              .getUtilities()
              .getLocaleUtilities()
              .getLocalisedMessageText("upnp.ignorebaddevices.info", new String[] {param});

      ignored_devices_list.setLabelText(text);

    } catch (Throwable e) {

      Debug.printStackTrace(e);
    }
  }
示例#10
0
  protected void ignoreDevice(String USN, URL location) {
    // only take note of this if enabled to do so

    if (ignore_bad_devices.getValue()) {

      try {
        PluginConfig pc = plugin_interface.getPluginconfig();

        Map ignored = pc.getPluginMapParameter("upnp.device.ignorelist", new HashMap());

        Map entry = (Map) ignored.get(USN);

        if (entry == null) {

          entry = new HashMap();

          entry.put("Location", location.toString().getBytes());

          ignored.put(USN, entry);

          pc.setPluginMapParameter("upnp.device.ignorelist", ignored);

          updateIgnoreList();

          String text =
              plugin_interface
                  .getUtilities()
                  .getLocaleUtilities()
                  .getLocalisedMessageText(
                      "upnp.ignorebaddevices.alert", new String[] {location.toString()});

          log.logAlertRepeatable(LoggerChannel.LT_WARNING, text);
        }
      } catch (Throwable e) {

        Debug.printStackTrace(e);
      }
    }
  }
示例#11
0
  protected void setNATPMPEnableState() {
    boolean enabled = natpmp_enable_param.getValue() && upnp_enable_param.getValue();

    try {
      if (enabled) {

        if (nat_pmp_upnp == null) {

          nat_pmp_upnp =
              NatPMPUPnPFactory.create(
                  upnp,
                  NatPMPDeviceFactory.getSingleton(
                      new NATPMPDeviceAdapter() {
                        public String getRouterAddress() {
                          return (nat_pmp_router.getValue());
                        }

                        public void log(String str) {
                          log.log("NAT-PMP: " + str);
                        }
                      }));

          nat_pmp_upnp.addListener(this);
        }

        nat_pmp_upnp.setEnabled(true);
      } else {

        if (nat_pmp_upnp != null) {

          nat_pmp_upnp.setEnabled(false);
        }
      }
    } catch (Throwable e) {

      log.log("Failed to initialise NAT-PMP subsystem", e);
    }
  }
示例#12
0
  public void execute(String commandName, final ConsoleInput ci, CommandLine commandLine) {
    Appender con = Logger.getRootLogger().getAppender("ConsoleAppender");
    List args = commandLine.getArgList();
    if ((con != null) && (!args.isEmpty())) {
      String subcommand = (String) args.get(0);
      if ("off".equalsIgnoreCase(subcommand)) {
        if (args.size() == 1) {
          con.addFilter(new DenyAllFilter());
          ci.out.println("> Console logging off");
        } else {

          String name = (String) args.get(1);

          Object[] entry = (Object[]) channel_listener_map.remove(name);

          if (entry == null) {

            ci.out.println("> Channel '" + name + "' not being logged");

          } else {

            ((LoggerChannel) entry[0]).removeListener((LoggerChannelListener) entry[1]);

            ci.out.println("> Channel '" + name + "' logging off");
          }
        }
      } else if ("on".equalsIgnoreCase(subcommand)) {

        if (args.size() == 1) {

          if (commandLine.hasOption('f')) {
            // send log output to a file
            String filename = commandLine.getOptionValue('f');

            try {
              Appender newAppender =
                  new FileAppender(new PatternLayout("%d{ISO8601} %c{1}-%p: %m%n"), filename, true);
              newAppender.setName("ConsoleAppender");
              Logger.getRootLogger().removeAppender(con);
              Logger.getRootLogger().addAppender(newAppender);
              ci.out.println("> Logging to filename: " + filename);
            } catch (IOException e) {
              ci.out.println("> Unable to log to file: " + filename + ": " + e);
            }
          } else {
            if (!(con instanceof ConsoleAppender)) {
              Logger.getRootLogger().removeAppender(con);
              con = new ConsoleAppender(new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN));
              con.setName("ConsoleAppender");
              Logger.getRootLogger().addAppender(con);
            }
            // switch back to console appender
            ci.out.println("> Console logging on");
          }

          con.clearFilters();
        } else {
          // hack - dunno how to do plugin-specific logging using these damn appenders..

          Map channel_map = getChannelMap(ci);

          final String name = (String) args.get(1);

          LoggerChannel channel = (LoggerChannel) channel_map.get(name);

          if (channel == null) {

            ci.out.println("> Channel '" + name + "' not found");

          } else if (channel_listener_map.get(name) != null) {

            ci.out.println("> Channel '" + name + "' already being logged");

          } else {

            LoggerChannelListener l =
                new LoggerChannelListener() {
                  public void messageLogged(int type, String content) {
                    ci.out.println("[" + name + "] " + content);
                  }

                  public void messageLogged(String str, Throwable error) {
                    ci.out.println("[" + name + "] " + str);

                    error.printStackTrace(ci.out);
                  }
                };

            channel.addListener(l);

            channel_listener_map.put(name, new Object[] {channel, l});

            ci.out.println("> Channel '" + name + "' on");
          }
        }
      } else if (subcommand.equalsIgnoreCase("list")) {

        Map channel_map = getChannelMap(ci);

        Iterator it = channel_map.keySet().iterator();

        while (it.hasNext()) {

          String name = (String) it.next();

          ci.out.println(
              "  " + name + " [" + (channel_listener_map.get(name) == null ? "off" : "on") + "]");
        }
      } else {

        ci.out.println("> Command 'log': Subcommand '" + subcommand + "' unknown.");
      }
    } else {
      ci.out.println(
          "> Console logger not found or missing subcommand for 'log'\r\n> log syntax: log [-f filename] (on [name]|off [name]|list)");
    }
  }
示例#13
0
  protected void startUp() {
    if (upnp != null) {

      // already started up, must have been re-enabled

      refreshMappings();

      return;
    }

    final LoggerChannel core_log = plugin_interface.getLogger().getChannel("UPnP Core");

    try {
      upnp =
          UPnPFactory.getSingleton(
              new UPnPAdapter() {
                Set exception_traces = new HashSet();

                public SimpleXMLParserDocument parseXML(String data)
                    throws SimpleXMLParserDocumentException {
                  return (plugin_interface
                      .getUtilities()
                      .getSimpleXMLParserDocumentFactory()
                      .create(data));
                }

                public ResourceDownloaderFactory getResourceDownloaderFactory() {
                  return (plugin_interface.getUtilities().getResourceDownloaderFactory());
                }

                public UTTimer createTimer(String name) {
                  return (plugin_interface.getUtilities().createTimer(name, true));
                }

                public void createThread(String name, Runnable runnable) {
                  plugin_interface.getUtilities().createThread(name, runnable);
                }

                public Comparator getAlphanumericComparator() {
                  return (plugin_interface
                      .getUtilities()
                      .getFormatters()
                      .getAlphanumericComparator(true));
                }

                public void trace(String str) {
                  core_log.log(str);
                  if (trace_to_log.getValue()) {
                    upnp_log_listener.log(str);
                  }
                }

                public void log(Throwable e) {
                  String nested = Debug.getNestedExceptionMessage(e);

                  if (!exception_traces.contains(nested)) {

                    exception_traces.add(nested);

                    if (exception_traces.size() > 128) {

                      exception_traces.clear();
                    }

                    core_log.log(e);

                  } else {

                    core_log.log(nested);
                  }
                }

                public void log(String str) {
                  log.log(str);
                }

                public String getTraceDir() {
                  return (plugin_interface.getUtilities().getAzureusUserDir());
                }
              },
              getSelectedInterfaces());

      upnp.addRootDeviceListener(this);

      upnp_log_listener =
          new UPnPLogListener() {
            public void log(String str) {
              log.log(str);
            }

            public void logAlert(String str, boolean error, int type) {
              boolean logged = false;

              if (alert_device_probs_param.getValue()) {

                if (type == UPnPLogListener.TYPE_ALWAYS) {

                  log.logAlertRepeatable(
                      error ? LoggerChannel.LT_ERROR : LoggerChannel.LT_WARNING, str);

                  logged = true;

                } else {

                  boolean do_it = false;

                  if (type == UPnPLogListener.TYPE_ONCE_EVER) {

                    byte[] fp =
                        plugin_interface
                            .getUtilities()
                            .getSecurityManager()
                            .calculateSHA1(str.getBytes());

                    String key =
                        "upnp.alert.fp."
                            + plugin_interface
                                .getUtilities()
                                .getFormatters()
                                .encodeBytesToString(fp);

                    PluginConfig pc = plugin_interface.getPluginconfig();

                    if (!pc.getPluginBooleanParameter(key, false)) {

                      pc.setPluginParameter(key, true);

                      do_it = true;
                    }
                  } else {

                    do_it = true;
                  }

                  if (do_it) {

                    log.logAlert(error ? LoggerChannel.LT_ERROR : LoggerChannel.LT_WARNING, str);

                    logged = true;
                  }
                }
              }

              if (!logged) {

                log.log(str);
              }
            }
          };

      upnp.addLogListener(upnp_log_listener);

      mapping_manager.addListener(
          new UPnPMappingManagerListener() {
            public void mappingAdded(UPnPMapping mapping) {
              addMapping(mapping);
            }
          });

      UPnPMapping[] upnp_mappings = mapping_manager.getMappings();

      for (int i = 0; i < upnp_mappings.length; i++) {

        addMapping(upnp_mappings[i]);
      }

      setNATPMPEnableState();

    } catch (Throwable e) {

      log.log(e);
    }
  }
示例#14
0
  public void initialize(PluginInterface _plugin_interface) {
    plugin_interface = _plugin_interface;

    log = plugin_interface.getLogger().getTimeStampedChannel("UPnP");
    log.setDiagnostic();
    log.setForce(true);

    UIManager ui_manager = plugin_interface.getUIManager();

    final BasicPluginViewModel model = ui_manager.createBasicPluginViewModel("UPnP");
    model.setConfigSectionID(UPNP_PLUGIN_CONFIGSECTION_ID);

    BasicPluginConfigModel upnp_config =
        ui_manager.createBasicPluginConfigModel(
            ConfigSection.SECTION_PLUGINS, UPNP_PLUGIN_CONFIGSECTION_ID);

    // NATPMP

    BasicPluginConfigModel natpmp_config =
        ui_manager.createBasicPluginConfigModel(
            UPNP_PLUGIN_CONFIGSECTION_ID, NATPMP_PLUGIN_CONFIGSECTION_ID);

    natpmp_config.addLabelParameter2("natpmp.info");

    ActionParameter natpmp_wiki =
        natpmp_config.addActionParameter2("Utils.link.visit", "MainWindow.about.internet.wiki");

    natpmp_wiki.setStyle(ActionParameter.STYLE_LINK);

    natpmp_wiki.addListener(
        new ParameterListener() {
          public void parameterChanged(Parameter param) {
            try {
              plugin_interface.getUIManager().openURL(new URL("http://wiki.vuze.com/w/NATPMP"));

            } catch (Throwable e) {

              e.printStackTrace();
            }
          }
        });

    natpmp_enable_param =
        natpmp_config.addBooleanParameter2("natpmp.enable", "natpmp.enable", false);

    nat_pmp_router =
        natpmp_config.addStringParameter2("natpmp.routeraddress", "natpmp.routeraddress", "");

    natpmp_enable_param.addListener(
        new ParameterListener() {
          public void parameterChanged(Parameter param) {
            setNATPMPEnableState();
          }
        });

    natpmp_enable_param.addEnabledOnSelection(nat_pmp_router);

    // UPNP

    upnp_config.addLabelParameter2("upnp.info");
    upnp_config.addHyperlinkParameter2("upnp.wiki_link", "http://wiki.vuze.com/w/UPnP");

    upnp_enable_param = upnp_config.addBooleanParameter2("upnp.enable", "upnp.enable", true);

    grab_ports_param = upnp_config.addBooleanParameter2("upnp.grabports", "upnp.grabports", false);

    release_mappings_param =
        upnp_config.addBooleanParameter2("upnp.releasemappings", "upnp.releasemappings", true);

    ActionParameter refresh_param =
        upnp_config.addActionParameter2("upnp.refresh.label", "upnp.refresh.button");

    refresh_param.addListener(
        new ParameterListener() {
          public void parameterChanged(Parameter param) {
            UPnPPlugin.this.refreshMappings();
          }
        });

    // Auto-refresh mappings every minute when enabled.
    final BooleanParameter auto_refresh_on_bad_nat_param =
        upnp_config.addBooleanParameter2(
            "upnp.refresh_on_bad_nat", "upnp.refresh_mappings_on_bad_nat", false);
    plugin_interface
        .getUtilities()
        .createTimer("upnp mapping auto-refresh", true)
        .addPeriodicEvent(
            1 * 60 * 1000,
            new UTTimerEventPerformer() {
              private long last_bad_nat = 0;

              public void perform(UTTimerEvent event) {
                if (upnp == null) {
                  return;
                }
                if (!auto_refresh_on_bad_nat_param.getValue()) {
                  return;
                }
                if (!upnp_enable_param.getValue()) {
                  return;
                }
                int status = plugin_interface.getConnectionManager().getNATStatus();
                if (status == ConnectionManager.NAT_BAD) {
                  // Only try to refresh the mappings if this is the first bad NAT
                  // message we've been given in the last 15 minutes - we don't want
                  // to endlessly retry performing the mappings
                  long now = plugin_interface.getUtilities().getCurrentSystemTime();
                  if (last_bad_nat + (15 * 60 * 1000) < now) {
                    last_bad_nat = now;
                    log.log(
                        LoggerChannel.LT_WARNING,
                        "NAT status is firewalled - trying to refresh UPnP mappings");
                    refreshMappings(true);
                  }
                }
              }
            });

    upnp_config.addLabelParameter2("blank.resource");

    alert_success_param =
        upnp_config.addBooleanParameter2("upnp.alertsuccess", "upnp.alertsuccess", false);

    alert_other_port_param =
        upnp_config.addBooleanParameter2(
            "upnp.alertothermappings", "upnp.alertothermappings", true);

    alert_device_probs_param =
        upnp_config.addBooleanParameter2(
            "upnp.alertdeviceproblems", "upnp.alertdeviceproblems", true);

    selected_interfaces_param =
        upnp_config.addStringParameter2("upnp.selectedinterfaces", "upnp.selectedinterfaces", "");
    selected_addresses_param =
        upnp_config.addStringParameter2("upnp.selectedaddresses", "upnp.selectedaddresses", "");

    ignore_bad_devices =
        upnp_config.addBooleanParameter2("upnp.ignorebaddevices", "upnp.ignorebaddevices", true);

    ignored_devices_list = upnp_config.addLabelParameter2("upnp.ignorebaddevices.info");

    ActionParameter reset_param =
        upnp_config.addActionParameter2(
            "upnp.ignorebaddevices.reset", "upnp.ignorebaddevices.reset.action");

    reset_param.addListener(
        new ParameterListener() {
          public void parameterChanged(Parameter param) {
            PluginConfig pc = plugin_interface.getPluginconfig();

            for (int i = 0; i < STATS_KEYS.length; i++) {

              String key = "upnp.device.stats." + STATS_KEYS[i];

              pc.setPluginMapParameter(key, new HashMap());
            }

            pc.setPluginMapParameter("upnp.device.ignorelist", new HashMap());

            updateIgnoreList();
          }
        });

    trace_to_log =
        upnp_config.addBooleanParameter2("upnp.trace_to_log", "upnp.trace_to_log", false);

    final boolean enabled = upnp_enable_param.getValue();

    upnp_enable_param.addEnabledOnSelection(alert_success_param);
    upnp_enable_param.addEnabledOnSelection(grab_ports_param);
    upnp_enable_param.addEnabledOnSelection(refresh_param);
    upnp_enable_param.addEnabledOnSelection(alert_other_port_param);
    upnp_enable_param.addEnabledOnSelection(alert_device_probs_param);
    upnp_enable_param.addEnabledOnSelection(release_mappings_param);
    upnp_enable_param.addEnabledOnSelection(selected_interfaces_param);
    upnp_enable_param.addEnabledOnSelection(selected_addresses_param);
    upnp_enable_param.addEnabledOnSelection(ignore_bad_devices);
    upnp_enable_param.addEnabledOnSelection(ignored_devices_list);
    upnp_enable_param.addEnabledOnSelection(reset_param);
    upnp_enable_param.addEnabledOnSelection(trace_to_log);

    natpmp_enable_param.setEnabled(enabled);

    model.getStatus().setText(enabled ? "Running" : "Disabled");

    upnp_enable_param.addListener(
        new ParameterListener() {
          public void parameterChanged(Parameter p) {
            boolean e = upnp_enable_param.getValue();

            natpmp_enable_param.setEnabled(e);

            model.getStatus().setText(e ? "Running" : "Disabled");

            if (e) {

              startUp();

            } else {

              closeDown(true);
            }

            setNATPMPEnableState();
          }
        });

    model.getActivity().setVisible(false);
    model.getProgress().setVisible(false);

    log.addListener(
        new LoggerChannelListener() {
          public void messageLogged(int type, String message) {
            model.getLogArea().appendText(message + "\n");
          }

          public void messageLogged(String str, Throwable error) {
            model.getLogArea().appendText(error.toString() + "\n");
          }
        });

    // startup() used to be called on initializationComplete()
    // Moved to delayed task because rootDeviceFound can take
    // a lot of CPU cycle.  Let's hope nothing breaks
    DelayedTask dt =
        plugin_interface
            .getUtilities()
            .createDelayedTask(
                new Runnable() {
                  public void run() {
                    if (enabled) {

                      updateIgnoreList();

                      startUp();
                    }
                  }
                });
    dt.queue();

    plugin_interface.addListener(
        new PluginListener() {
          public void initializationComplete() {}

          public void closedownInitiated() {
            if (services.size() == 0) {

              plugin_interface.getPluginconfig().setPluginParameter("plugin.info", "");
            }
          }

          public void closedownComplete() {
            closeDown(true);
          }
        });
  }
示例#15
0
  protected void addService(UPnPWANConnection wan_service) throws UPnPException {

    wan_service.addListener(this);

    mapping_manager.serviceFound(wan_service);

    try {
      this_mon.enter();

      log.log(
          "    Found "
              + (wan_service.getGenericService().getServiceType().indexOf("PPP") == -1
                  ? "WANIPConnection"
                  : "WANPPPConnection"));

      UPnPWANConnectionPortMapping[] ports;

      String usn = wan_service.getGenericService().getDevice().getRootDevice().getUSN();

      if (getDeviceStats(usn, STATS_READ_OK) == 0 && getDeviceStats(usn, STATS_READ_BAD) > 2) {

        ports = new UPnPWANConnectionPortMapping[0];

        wan_service.periodicallyRecheckMappings(false);

        log.log("    Not reading port mappings from device due to previous failures");

      } else {

        ports = wan_service.getPortMappings();
      }

      for (int j = 0; j < ports.length; j++) {

        log.log(
            "      mapping ["
                + j
                + "] "
                + ports[j].getExternalPort()
                + "/"
                + (ports[j].isTCP() ? "TCP" : "UDP")
                + " ["
                + ports[j].getDescription()
                + "] -> "
                + ports[j].getInternalHost());
      }

      services.add(
          new UPnPPluginService(
              wan_service,
              ports,
              alert_success_param,
              grab_ports_param,
              alert_other_port_param,
              release_mappings_param));

      if (services.size() > 1) {

        // check this isn't a single device with multiple services

        String new_usn = wan_service.getGenericService().getDevice().getRootDevice().getUSN();

        boolean multiple_found = false;

        for (int i = 0; i < services.size() - 1; i++) {

          UPnPPluginService service = (UPnPPluginService) services.get(i);

          String existing_usn =
              service.getService().getGenericService().getDevice().getRootDevice().getUSN();

          if (!new_usn.equals(existing_usn)) {

            multiple_found = true;

            break;
          }
        }

        if (multiple_found) {

          PluginConfig pc = plugin_interface.getPluginconfig();

          if (!pc.getPluginBooleanParameter("upnp.device.multipledevices.warned", false)) {

            pc.setPluginParameter("upnp.device.multipledevices.warned", true);

            String text = MessageText.getString("upnp.alert.multipledevice.warning");

            log.logAlertRepeatable(LoggerChannel.LT_WARNING, text);
          }
        }
      }

      checkState();

    } finally {

      this_mon.exit();
    }
  }