Esempio n. 1
0
 public void actionPerformed(ActionEvent ae) {
   if (ae.getActionCommand() == "timer") {
     if (counter >= imagePaths.length) {
       timer.stop();
       counter = 0;
       PlayStopButton.setText("Play");
     } else {
       try {
         // if the array contains URLs
         if (imagePaths[counter].contains("http://")) {
           scrollPane.setToolTipText(imagePaths[counter]);
           imageIcon = new ImageIcon((new URL(imagePaths[counter++])));
           scrollPane.setViewportView(new JLabel(imageIcon));
         }
         // if the array contains local images
         else {
           image.setIcon(new ImageIcon(imagePaths[counter]));
           image.setToolTipText(imagePaths[counter++]);
         }
       } catch (MalformedURLException ex) {
         Logger.getLogger(Slideshow.class.getName()).log(Level.SEVERE, null, ex);
         image = new JLabel("?" + imagePaths);
       }
     }
   }
 }
 /** metodo que se encarga de cerrar todas las conexiones que se realizaron en el socket */
 public void desconnectar() {
   try {
     socket.close();
   } catch (IOException ex) {
     Logger.getLogger(ServidorHilo.class.getName()).log(Level.SEVERE, null, ex);
   }
 }
Esempio n. 3
0
 // @Override
 public synchronized String getIP() {
   try {
     return NetUtils.getIPAddress();
   } catch (ConnectException ex) {
     Logger.getLogger(Mapa.class.getName()).log(Level.SEVERE, null, ex);
   }
   return "";
 }
Esempio n. 4
0
  DBPort(InetSocketAddress addr, DBPortPool pool, MongoOptions options) throws IOException {
    _options = options;
    _addr = addr;
    _pool = pool;

    _hashCode = _addr.hashCode();

    _logger = Logger.getLogger(_rootLogger.getName() + "." + addr.toString());
  }
Esempio n. 5
0
 public void actionPerformed(ActionEvent e) {
   try {
     undo.redo();
   } catch (CannotRedoException ex) {
     Logger.getLogger(RedoAction.class.getName()).log(Level.SEVERE, "Unable to redo", ex);
   }
   update();
   undoAction.update();
 }
Esempio n. 6
0
  /**
   * Construye el objeto que gestionara la comunicacion de datos.
   *
   * @param s Socket de conexion.
   * @throws Exception
   */
  public DataAttendant(Socket s) throws Exception {
    mylogger = Logger.getLogger("isabel.nereda.DataAttendant");
    mylogger.fine("Creating DataAttendant object.");

    sock = s;
    myPP = new PacketProcessor(sock);

    NeReDa.peers.Add(this);
  }
 // constructor  que inicializar el socket y asigna  el id al numero de sesión
 public ServidorHilo(Socket socket, int id) {
   this.socket = socket;
   this.idSessio = id;
   try {
     dos = new DataOutputStream(socket.getOutputStream());
     dis = new DataInputStream(socket.getInputStream());
   } catch (IOException ex) {
     Logger.getLogger(ServidorHilo.class.getName()).log(Level.SEVERE, null, ex);
   }
 }
Esempio n. 8
0
    @Override
    @SuppressWarnings("SleepWhileHoldingLock")
    public void run() {
      try {
        // initialize the statusbar
        status.removeAll();
        JProgressBar progress = new JProgressBar();
        progress.setMinimum(0);
        progress.setMaximum(doc.getLength());
        status.add(progress);
        status.revalidate();

        // start writing
        Writer out = new FileWriter(f);
        Segment text = new Segment();
        text.setPartialReturn(true);
        int charsLeft = doc.getLength();
        int offset = 0;
        while (charsLeft > 0) {
          doc.getText(offset, Math.min(4096, charsLeft), text);
          out.write(text.array, text.offset, text.count);
          charsLeft -= text.count;
          offset += text.count;
          progress.setValue(offset);
          try {
            Thread.sleep(10);
          } catch (InterruptedException e) {
            Logger.getLogger(FileSaver.class.getName()).log(Level.SEVERE, null, e);
          }
        }
        out.flush();
        out.close();
      } catch (IOException e) {
        final String msg = e.getMessage();
        SwingUtilities.invokeLater(
            new Runnable() {

              public void run() {
                JOptionPane.showMessageDialog(
                    getFrame(),
                    "Could not save file: " + msg,
                    "Error saving file",
                    JOptionPane.ERROR_MESSAGE);
              }
            });
      } catch (BadLocationException e) {
        System.err.println(e.getMessage());
      }
      // we are done... get rid of progressbar
      status.removeAll();
      status.revalidate();
    }
Esempio n. 9
0
  /** @param args the command line arguments */
  public static void main(String[] args) throws IOException {
    // TODO code application logic here

    Socket socket = null;
    BufferedReader read = null;
    BufferedReader in = null;
    PrintWriter out = null;

    try {
      socket = new Socket("10.151.34.155", 6666);

      read = new BufferedReader(new InputStreamReader(System.in));
      in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      out = new PrintWriter(socket.getOutputStream(), true);

    } catch (IOException ex) {
      Logger.getLogger(UTSProgjar.class.getName()).log(Level.SEVERE, null, ex);
    }

    String textToServer;
    while ((textToServer = read.readLine()) != null) {
      out.print(textToServer + "\r\n");
      out.flush();

      String messageFromServer;
      while ((messageFromServer = textToServer = in.readLine()) != null) {
        System.out.println(messageFromServer);
      }
    }

    Integer intToServer;
    while ((intToServer = Integer.parseInt(read.readLine())) != null) {
      out.print(intToServer + "\r\n");
      out.flush();

      String messageFromServer;
      while ((messageFromServer = textToServer = in.readLine()) != null) {
        System.out.println(messageFromServer);
      }
    }

    out.close();
    in.close();
    read.close();
    socket.close();
  }
Esempio n. 10
0
public class DBPort {

  public static final int PORT = 27017;
  static final boolean USE_NAGLE = false;

  static final long CONN_RETRY_TIME_MS = 15000;

  public DBPort(InetSocketAddress addr) throws IOException {
    this(addr, null, new MongoOptions());
  }

  DBPort(InetSocketAddress addr, DBPortPool pool, MongoOptions options) throws IOException {
    _options = options;
    _addr = addr;
    _pool = pool;

    _hashCode = _addr.hashCode();

    _logger = Logger.getLogger(_rootLogger.getName() + "." + addr.toString());
  }

  /** @param response will get wiped */
  DBMessage call(DBMessage msg, ByteDecoder decoder) throws IOException {
    return go(msg, decoder);
  }

  void say(DBMessage msg) throws IOException {
    go(msg, null);
  }

  private synchronized DBMessage go(DBMessage msg, ByteDecoder decoder) throws IOException {

    if (_sock == null) _open();

    {
      ByteBuffer out = msg.prepare();
      while (out.remaining() > 0) _sock.write(out);
    }

    if (_pool != null) _pool._everWorked = true;

    if (decoder == null) return null;

    ByteBuffer response = decoder._buf;

    if (response.position() != 0) throw new IllegalArgumentException();

    int read = 0;
    while (read < DBMessage.HEADER_LENGTH) read += _read(response);

    int len = response.getInt(0);
    if (len <= DBMessage.HEADER_LENGTH)
      throw new IllegalArgumentException("db sent invalid length: " + len);

    if (len > response.capacity())
      throw new IllegalArgumentException(
          "db message size is too big (" + len + ") " + "max is (" + response.capacity() + ")");

    response.limit(len);
    while (read < len) read += _read(response);

    if (read != len) throw new RuntimeException("something is wrong");

    response.flip();
    return new DBMessage(response);
  }

  public synchronized void ensureOpen() throws IOException {

    if (_sock != null) return;

    _open();
  }

  void _open() throws IOException {

    long sleepTime = 100;

    final long start = System.currentTimeMillis();
    while (true) {

      IOException lastError = null;

      try {
        _sock = SocketChannel.open();
        _socket = _sock.socket();
        _socket.connect(_addr, _options.connectTimeout);

        _socket.setTcpNoDelay(!USE_NAGLE);
        _socket.setSoTimeout(_options.socketTimeout);
        _in = _socket.getInputStream();
        return;
      } catch (IOException ioe) {
        //  TODO  - erh to fix                lastError = new IOException( "couldn't connect to [" +
        // _addr + "] bc:" + lastError , lastError );
        lastError = new IOException("couldn't connect to [" + _addr + "] bc:" + ioe);
        _logger.log(Level.INFO, "connect fail to : " + _addr, ioe);
      }

      if (!_options.autoConnectRetry || (_pool != null && !_pool._everWorked)) throw lastError;

      long sleptSoFar = System.currentTimeMillis() - start;

      if (sleptSoFar >= CONN_RETRY_TIME_MS) throw lastError;

      if (sleepTime + sleptSoFar > CONN_RETRY_TIME_MS) sleepTime = CONN_RETRY_TIME_MS - sleptSoFar;

      _logger.severe(
          "going to sleep and retry.  total sleep time after = "
              + (sleptSoFar + sleptSoFar)
              + "ms  this time:"
              + sleepTime
              + "ms");
      ThreadUtil.sleep(sleepTime);
      sleepTime *= 2;
    }
  }

  public int hashCode() {
    return _hashCode;
  }

  public String host() {
    return _addr.toString();
  }

  public String toString() {
    return "{DBPort  " + host() + "}";
  }

  protected void finalize() {
    if (_sock != null) {
      try {
        _sock.close();
      } catch (Exception e) {
        // don't care
      }

      _in = null;
      _socket = null;
      _sock = null;
    }
  }

  void checkAuth(DB db) {
    if (db._username == null) return;
    if (_authed.containsKey(db)) return;

    if (_inauth) return;

    _inauth = true;
    try {
      if (db.reauth()) {
        _authed.put(db, true);
        return;
      }
    } finally {
      _inauth = false;
    }

    throw new MongoInternalException("can't reauth!");
  }

  private int _read(ByteBuffer buf) throws IOException {
    int x = _in.read(buf.array(), buf.position(), buf.remaining());
    if (x < 0) throw new IOException("connection to server closed unexpectedly");
    buf.position(buf.position() + x);
    return x;
  }

  final int _hashCode;
  final InetSocketAddress _addr;
  final DBPortPool _pool;
  final MongoOptions _options;
  final Logger _logger;

  private SocketChannel _sock;
  private Socket _socket;
  private InputStream _in;

  private boolean _inauth = false;
  private Map<DB, Boolean> _authed = Collections.synchronizedMap(new WeakHashMap<DB, Boolean>());

  private static Logger _rootLogger = Logger.getLogger("com.mongodb.port");
}
Esempio n. 11
0
class DBPortPool extends SimplePool<DBPort> {

  static class Holder {

    Holder(MongoOptions options) {
      _options = options;
    }

    DBPortPool get(InetSocketAddress addr) {

      DBPortPool p = _pools.get(addr);

      if (p != null) return p;

      synchronized (_pools) {
        p = _pools.get(addr);
        if (p != null) {
          return p;
        }

        p = new DBPortPool(addr, _options);
        _pools.put(addr, p);
        String name = "com.mongodb:type=ConnectionPool,host=" + addr.toString().replace(':', '_');

        try {
          ObjectName on = new ObjectName(name);
          if (_server.isRegistered(on)) {
            _server.unregisterMBean(on);
            Bytes.LOGGER.log(
                Level.INFO, "multiple Mongo instances for same host, jmx numbers might be off");
          }
          _server.registerMBean(p, on);
        } catch (JMException e) {
          Bytes.LOGGER.log(Level.WARNING, "jmx registration error, continuing", e);
        } catch (java.security.AccessControlException e) {
          Bytes.LOGGER.log(Level.WARNING, "jmx registration error, continuing", e);
        }
      }

      return p;
    }

    void close() {
      synchronized (_pools) {
        for (DBPortPool p : _pools.values()) {
          p.close();
        }
      }
    }

    final MongoOptions _options;
    final Map<InetSocketAddress, DBPortPool> _pools =
        Collections.synchronizedMap(new HashMap<InetSocketAddress, DBPortPool>());
    final MBeanServer _server = ManagementFactory.getPlatformMBeanServer();
  }

  // ----

  public static class NoMoreConnection extends MongoInternalException {
    NoMoreConnection(String msg) {
      super(msg);
    }
  }

  public static class SemaphoresOut extends NoMoreConnection {
    SemaphoresOut() {
      super("Out of semaphores to get db connection");
    }
  }

  public static class ConnectionWaitTimeOut extends NoMoreConnection {
    ConnectionWaitTimeOut(int timeout) {
      super("Connection wait timeout after " + timeout + " ms");
    }
  }

  // ----

  DBPortPool(InetSocketAddress addr, MongoOptions options) {
    super("DBPortPool-" + addr.toString(), options.connectionsPerHost, options.connectionsPerHost);
    _options = options;
    _addr = addr;
    _waitingSem =
        new Semaphore(
            _options.connectionsPerHost * _options.threadsAllowedToBlockForConnectionMultiplier);
  }

  protected long memSize(DBPort p) {
    return 0;
  }

  protected int pick(int iThink, boolean couldCreate) {
    final int id = Thread.currentThread().hashCode();
    final int s = _availSafe.size();
    for (int i = 0; i < s; i++) {
      DBPort p = _availSafe.get(i);
      if (p._lastThread == id) return i;
    }

    if (couldCreate) return -1;
    return iThink;
  }

  public DBPort get() {
    DBPort port = null;
    if (!_waitingSem.tryAcquire()) throw new SemaphoresOut();

    try {
      port = get(_options.maxWaitTime);
    } finally {
      _waitingSem.release();
    }

    if (port == null) throw new ConnectionWaitTimeOut(_options.maxWaitTime);

    port._lastThread = Thread.currentThread().hashCode();
    return port;
  }

  void gotError(Exception e) {
    if (e instanceof java.nio.channels.ClosedByInterruptException
        || e instanceof InterruptedException) {
      // this is probably a request that is taking too long
      // so usually doesn't mean there is a real db problem
      return;
    }

    if (e instanceof java.net.SocketTimeoutException && _options.socketTimeout > 0) {
      // we don't want to clear the port pool for 1 connection timing out
      return;
    }

    // We don't want to clear the entire pool for the occasional error.
    if (e instanceof SocketException) {
      if (recentFailures < ALLOWED_ERRORS_BEFORE_CLEAR) {
        return;
      }
    }

    Bytes.LOGGER.log(Level.INFO, "emptying DBPortPool b/c of error", e);
    clear();
  }

  void close() {
    clear();
  }

  public void cleanup(DBPort p) {
    p.close();
  }

  public boolean ok(DBPort t) {
    return _addr.equals(t._addr);
  }

  protected DBPort createNew() throws MongoInternalException {
    try {
      return new DBPort(_addr, this, _options);
    } catch (IOException ioe) {
      throw new MongoInternalException("can't create port to:" + _addr, ioe);
    }
  }

  public int getRecentFailures() {
    return recentFailures;
  }

  public void incrementRecentFailures() {
    _logger.warning("Failure recorded:" + _addr.toString());
    this.recentFailures++;
  }

  public void resetRecentFailures() {
    if (this.recentFailures > 0) {
      _logger.warning("Successful Request. Reseting recent failures:" + _addr.toString());
    }

    this.recentFailures = 0;
  }

  final MongoOptions _options;
  private final Semaphore _waitingSem;
  final InetSocketAddress _addr;
  boolean _everWorked = false;
  public static final Integer ALLOWED_ERRORS_BEFORE_CLEAR =
      Integer.valueOf(System.getProperty("MONGO.ERRORS_BEFORE_CLEAR", "5"));
  private Logger _logger = Logger.getLogger(DBPortPool.class.toString());

  /** The number of failures that this port pool has recently experienced. */
  private int recentFailures = 0;
}
/**
 * Implements the {@link ReplacementService} to provide previews for direct image links.
 *
 * @author Purvesh Sahoo
 * @author Marin Dzhigarov
 */
public class ReplacementServiceDirectImageImpl implements DirectImageReplacementService {
  /** The logger for this class. */
  private static final Logger logger = Logger.getLogger(ReplacementServiceDirectImageImpl.class);

  /** The regex used to match the link in the message. */
  public static final String URL_PATTERN = "https?\\:\\/\\/(www\\.)*.*\\.(?:jpg|png|gif)";

  /** Configuration label shown in the config form. */
  public static final String DIRECT_IMAGE_CONFIG_LABEL = "Direct Image Link";

  /** Source name; also used as property label. */
  public static final String SOURCE_NAME = "DIRECTIMAGE";

  /** Maximum allowed size of the image in bytes. The default size is 2MB. */
  private long imgMaxSize = 2097152;

  /** Configuration property name for maximum allowed size of the image in bytes. */
  private static final String MAX_IMG_SIZE =
      "net.java.sip.communicator.impl.replacement.directimage.MAX_IMG_SIZE";

  /** Constructor for <tt>ReplacementServiceDirectImageImpl</tt>. */
  public ReplacementServiceDirectImageImpl() {
    setMaxImgSizeFromConf();
    logger.trace("Creating a Direct Image Link Source.");
  }

  /**
   * Gets the max allowed size value in bytes from Configuration service and sets the value to
   * <tt>imgMaxSize</tt> if succeed. If the configuration property isn't available or the value
   * can't be parsed correctly the value of <tt>imgMaxSize</tt> isn't changed.
   */
  private void setMaxImgSizeFromConf() {
    ConfigurationService configService = DirectImageActivator.getConfigService();

    if (configService != null) {
      String confImgSizeStr = (String) configService.getProperty(MAX_IMG_SIZE);
      try {
        if (confImgSizeStr != null) {
          imgMaxSize = Long.parseLong(confImgSizeStr);
        } else {
          configService.setProperty(MAX_IMG_SIZE, imgMaxSize);
        }
      } catch (NumberFormatException e) {
        if (logger.isDebugEnabled())
          logger.debug(
              "Failed to parse max image size: " + confImgSizeStr + ". Going for default.");
      }
    }
  }

  /**
   * Returns the thumbnail URL of the image link provided.
   *
   * @param sourceString the original image link.
   * @return the thumbnail image link; the original link in case of no match.
   */
  public String getReplacement(String sourceString) {
    return sourceString;
  }

  /**
   * Returns the source name
   *
   * @return the source name
   */
  public String getSourceName() {
    return SOURCE_NAME;
  }

  /**
   * Returns the pattern of the source
   *
   * @return the source pattern
   */
  public String getPattern() {
    return URL_PATTERN;
  }

  @Override
  /**
   * Returns the size of the image in bytes.
   *
   * @param sourceString the image link.
   * @return the file size in bytes of the image link provided; -1 if the size isn't available or
   *     exceeds the max allowed image size.
   */
  public int getImageSize(String sourceString) {
    int length = -1;
    try {

      URL url = new URL(sourceString);
      String protocol = url.getProtocol();
      if (protocol.equals("http") || protocol.equals("https")) {
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        length = connection.getContentLength();
        connection.disconnect();
      } else if (protocol.equals("ftp")) {
        FTPUtils ftp = new FTPUtils(sourceString);
        length = ftp.getSize();
        ftp.disconnect();
      }

      if (length > imgMaxSize) {
        length = -1;
      }
    } catch (Exception e) {
      logger.debug("Failed to get the length of the image in bytes", e);
    }
    return length;
  }

  /**
   * Returns true if the content type of the resource pointed by sourceString is an image.
   *
   * @param sourceString the original image link.
   * @return true if the content type of the resource pointed by sourceString is an image.
   */
  @Override
  public boolean isDirectImage(String sourceString) {
    boolean isDirectImage = false;
    try {
      URL url = new URL(sourceString);
      String protocol = url.getProtocol();
      if (protocol.equals("http") || protocol.equals("https")) {
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        isDirectImage = connection.getContentType().contains("image");
        connection.disconnect();
      } else if (protocol.equals("ftp")) {
        if (sourceString.endsWith(".png")
            || sourceString.endsWith(".jpg")
            || sourceString.endsWith(".gif")) {
          isDirectImage = true;
        }
      }
    } catch (Exception e) {
      logger.debug("Failed to retrieve content type information for" + sourceString, e);
    }
    return isDirectImage;
  }
}
Esempio n. 13
0
public class ClientThread extends Thread implements Observer, ServerInterface {
  private Socket s = null;
  private DataInputStream in = null;
  private DataOutputStream out = null;
  private Users users;
  private static final Logger logger = Logger.getLogger("im.server");
  private History history;
  private String userName = "******";
  private Messages messages = null;
  private boolean disabled = false;

  public ClientThread(Socket socket, History history, Users users) throws IOException {

    logger.warn("New client is trying to connect to the chat...");
    logger.info("Assigning a socket to a new client...");
    this.s = socket;

    logger.info("Getting the input stream...");
    in = new DataInputStream(s.getInputStream());

    logger.info("Getting the output stream...");
    out = new DataOutputStream(s.getOutputStream());

    this.users = users;
    users.addObserver(this);

    this.history = history;

    start();
    logger.warn("Connection with new user is established.");
  }

  public void run() {
    try {
      prepareClient();
      logger.info("Starting normal session with " + getClientName());
      while (true) {
        this.receive();
      }
    } catch (IOException ioe) {
      logger.warn("Client " + this + " has been disconnected.");
      this.setDisabled(true);
      users.remove(this);
    } finally {
      try {
        if (s != null && !s.isClosed()) {
          s.close();
          logger.warn("Socket with " + this + " has been closed.");
        }
      } catch (IOException ioe) {
        logger.error("Socket has not been closed.", ioe);
      }
    }
  }

  public void receive() throws IOException {
    Message message = Operations.receive(in);
    logger.info("New message received.");

    processMessage(message);
  }

  private void processMessage(Message message) throws IOException {
    if (message.getType().equals("SimpleMessage")) {
      MessageType messageType = (MessageType) message.getValue();
      String receiver = messageType.getToUser();
      history.get(receiver).add(messageType);
    }

    if (message.getType().equals("ConnectUserMessage")) {
      String user = (String) message.getValue();
      Messages messages = history.get(user);
      Operations.sendHistory(messages.getLastFiveWith(user), out);
    }
  }

  // public void send(MessageType message) throws IOException {
  // Operations.sendMessage(message, out);
  // }

  public String toString() {
    return getClientName() + " [" + s.getInetAddress() + "]";
  }

  public String getClientName() {
    return userName;
  }

  public void update(Observable source, Object object) {
    if (source instanceof Users) {
      if (!this.isDisabled()) {
        try {
          Operations.sendUserNamesList(users.getUserNames(), out);
        } catch (IOException io) {
          logger.error("IO Exception", io);
        }
      }
    }

    if (source instanceof Messages) {
      try {
        Operations.sendMessage((MessageType) object, out);
      } catch (IOException io) {
        if (out != null) {
          try {
            out.close();
          } catch (Exception ioe) {
            logger.error("Failed to close the output stream", ioe);
          }
        }

        logger.error("Impossible to send messages", io);
      }
    }
  }

  private void setDisabled(boolean state) {
    this.disabled = state;
  }

  private boolean isDisabled() {
    return this.disabled;
  }

  private void setClientName(String userName) {
    this.userName = userName;
  }

  private void prepareClient() throws IOException {
    logger.info("Waiting for client's name");
    Message mes = Operations.receive(in);
    setClientName((String) mes.getValue());
    logger.info("Username for " + s.getInetAddress() + " received: " + userName);

    users.add(this);
    logger.info("User " + getClientName() + " has been added to the userlist.");

    messages = new Messages();
    logger.info("Message list created");

    if (!history.containsKey(userName)) {
      history.put(userName, messages);
    } else {
      messages = history.get(userName);
    }
    messages.addObserver(this);
    logger.info("Message list assigned to history");

    logger.info("Sending the list of users.");
    Operations.sendUserNamesList(users.getUserNames(), out);
    logger.info("Userlist has been sent");
  }
}
/** Minimal fully functional plugin capable of serving a little static content. */
public class StaticContentPlugin extends BasePlugin implements PluginTestable {
  static Logger log = Logger.getLogger("StaticContentPlugin");

  Map cuMap = new HashMap();

  public StaticContentPlugin() {}

  public String getVersion() {
    throw new UnsupportedOperationException("Not implemented");
  }

  public String getPluginName() {
    return "Static Content";
  }

  public List getSupportedTitles() {
    throw new UnsupportedOperationException("Not implemented");
  }

  public List getLocalAuConfigDescrs() {
    return Collections.EMPTY_LIST;
    //    throw new UnsupportedOperationException("Not implemented");
  }

  protected ArchivalUnit createAu0(Configuration auConfig)
      throws ArchivalUnit.ConfigurationException {
    return new SAU(this);
  }

  public void registerArchivalUnit(ArchivalUnit au) {
    aus.add(au);
  }

  public void unregisterArchivalUnit(ArchivalUnit au) {
    aus.remove(au);
  }

  public class SAU extends BaseArchivalUnit {

    protected SAU(Plugin myPlugin) {
      super(myPlugin);
    }

    protected String makeName() {
      return "Static Content AU";
    }

    protected String makeStartUrl() {
      throw new UnsupportedOperationException("Not Implemented");
    }

    public CachedUrlSet makeCachedUrlSet(CachedUrlSetSpec cuss) {
      return new SCUS(this, cuss);
    }

    public CachedUrl makeCachedUrl(String url) {
      CachedUrl res = (CachedUrl) cuMap.get(url);
      log.debug("makeCachedUrl(" + url + ") = " + res);
      return (CachedUrl) cuMap.get(url);
    }

    public org.lockss.plugin.UrlCacher makeUrlCacher(String url) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public boolean shouldBeCached(String url) {
      return cuMap.containsKey(url);
    }

    public List getNewContentCrawlUrls() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public Collection getUrlStems() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public CachedUrlSet cachedUrlSetFactory(ArchivalUnit owner, CachedUrlSetSpec cuss) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public CachedUrl cachedUrlFactory(CachedUrlSet owner, String url) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public UrlCacher urlCacherFactory(CachedUrlSet owner, String url) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public String getManifestPage() {
      throw new UnsupportedOperationException("Not Implemented");
    }

    public FilterRule getFilterRule(String mimeType) {
      throw new UnsupportedOperationException("Not implemented");
    }

    /**
     * Create a CU with content and store it in AU
     *
     * @param owner the CUS owner
     * @param url the url
     * @param type the type
     * @param contents the contents
     */
    public void storeCachedUrl(CachedUrlSet owner, String url, String type, String contents) {
      SCU scu = new SCU(owner, url, type, contents);
      cuMap.put(scu.getUrl(), scu);
    }

    public void storeCachedUrl(String url, String type, String contents) {
      storeCachedUrl(null, url, type, contents);
    }

    public String toString() {
      return "[sau: " + cuMap + "]";
    }

    protected CrawlRule makeRules() {
      throw new UnsupportedOperationException("Not implemented");
    }

    /**
     * loadDefiningConfig
     *
     * @param config Configuration
     */
    protected void loadAuConfigDescrs(Configuration config) {}
  }

  public class SCU extends BaseCachedUrl {
    private String contents = null;
    private CIProperties props = new CIProperties();

    public SCU(CachedUrlSet owner, String url) {
      super(null, url);
    }

    /**
     * Create a CachedUrl with content
     *
     * @param owner the CUS owner
     * @param url the url
     * @param type the type
     * @param contents the contents
     */
    public SCU(CachedUrlSet owner, String url, String type, String contents) {
      this(owner, url);
      setContents(contents);
      props.setProperty(CachedUrl.PROPERTY_CONTENT_TYPE, type);
    }

    private void setContents(String s) {
      contents = s;
      props.setProperty("Content-Length", "" + s.length());
    }

    public String getUrl() {
      return url;
    }

    public boolean hasContent() {
      return contents != null;
    }

    public boolean isLeaf() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public InputStream getUnfilteredInputStream() {
      return new StringInputStream(contents);
    }

    public InputStream openForHashing() {
      return getUnfilteredInputStream();
    }

    protected InputStream getFilteredStream() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public Reader openForReading() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public long getContentSize() {
      return contents == null ? 0 : contents.length();
    }

    public CIProperties getProperties() {
      return props;
    }
  }

  class SCUS extends BaseCachedUrlSet {
    public SCUS(ArchivalUnit owner, CachedUrlSetSpec spec) {
      super(owner, spec);
    }

    public void storeActualHashDuration(long elapsed, Exception err) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public Iterator flatSetIterator() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public Iterator contentHashIterator() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public boolean isLeaf() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public CachedUrlSetHasher getContentHasher(MessageDigest digest) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public CachedUrlSetHasher getNameHasher(MessageDigest digest) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public long estimatedHashDuration() {
      return 1000;
    }
  }
}
Esempio n. 15
0
/**
 * The Network Access Point is the most outward part of the stack. It is constructed around a
 * datagram socket and takes care of forwarding incoming messages to the MessageProcessor as well as
 * sending datagrams to the STUN server specified by the original NetAccessPointDescriptor.
 *
 * @author Emil Ivov
 */
class Connector implements Runnable {
  /** Our class logger. */
  private static final Logger logger = Logger.getLogger(Connector.class.getName());

  /** The message queue is where incoming messages are added. */
  private final MessageQueue messageQueue;

  /** The socket object that used by this access point to access the network. */
  private IceSocketWrapper sock;

  /** The object that we use to lock socket operations (since the socket itself is often null) */
  private final Object sockLock = new Object();

  /** A flag that is set to false to exit the message processor. */
  private boolean running;

  /** The instance to be notified if errors occur in the network listening thread. */
  private final ErrorHandler errorHandler;

  /** The address that we are listening to. */
  private final TransportAddress listenAddress;

  /**
   * The remote address of the socket of this <tt>Connector</tt> if it is a TCP socket, or
   * <tt>null</tt> if it is UDP.
   */
  private final TransportAddress remoteAddress;

  /**
   * Creates a network access point.
   *
   * @param socket the socket that this access point is supposed to use for communication.
   * @param messageQueue the FIFO list where incoming messages should be queued
   * @param errorHandler the instance to notify when errors occur.
   */
  protected Connector(
      IceSocketWrapper socket, MessageQueue messageQueue, ErrorHandler errorHandler) {
    this.sock = socket;
    this.messageQueue = messageQueue;
    this.errorHandler = errorHandler;

    Transport transport = socket.getUDPSocket() != null ? Transport.UDP : Transport.TCP;

    listenAddress =
        new TransportAddress(socket.getLocalAddress(), socket.getLocalPort(), transport);
    if (transport == Transport.UDP) {
      remoteAddress = null;
    } else {
      Socket tcpSocket = socket.getTCPSocket();

      remoteAddress =
          new TransportAddress(tcpSocket.getInetAddress(), tcpSocket.getPort(), transport);
    }
  }

  /** Start the network listening thread. */
  void start() {
    this.running = true;

    Thread thread = new Thread(this, "IceConnector@" + hashCode());

    thread.setDaemon(true);
    thread.start();
  }

  /**
   * Returns the <tt>DatagramSocket</tt> that contains the port and address associated with this
   * access point.
   *
   * @return the <tt>DatagramSocket</tt> associated with this AP.
   */
  protected IceSocketWrapper getSocket() {
    return sock;
  }

  /** The listening thread's run method. */
  @Override
  public void run() {
    DatagramPacket packet = null;

    while (this.running) {
      try {
        IceSocketWrapper localSock;

        synchronized (sockLock) {
          if (!running) return;

          localSock = this.sock;
        }

        /*
         * Make sure localSock's receiveBufferSize is taken into
         * account including after it gets changed.
         */
        int receiveBufferSize = 1500;
        /*
        if(localSock.getTCPSocket() != null)
        {
            receiveBufferSize = localSock.getTCPSocket().
                getReceiveBufferSize();
        }
        else if(localSock.getUDPSocket() != null)
        {
            receiveBufferSize = localSock.getUDPSocket().
                getReceiveBufferSize();
        }
        */

        if (packet == null) {
          packet = new DatagramPacket(new byte[receiveBufferSize], receiveBufferSize);
        } else {
          byte[] packetData = packet.getData();

          if ((packetData == null) || (packetData.length < receiveBufferSize)) {
            packet.setData(new byte[receiveBufferSize], 0, receiveBufferSize);
          } else {
            /*
             * XXX Tell the packet it is large enough because the
             * socket will not look at the length of the data array
             * property and will just respect the length property.
             */
            packet.setLength(receiveBufferSize);
          }
        }

        localSock.receive(packet);

        // get lost if we are no longer running.
        if (!running) return;

        logger.finest("received datagram");

        RawMessage rawMessage =
            new RawMessage(
                packet.getData(),
                packet.getLength(),
                new TransportAddress(
                    packet.getAddress(), packet.getPort(), listenAddress.getTransport()),
                listenAddress);

        messageQueue.add(rawMessage);
      } catch (SocketException ex) {
        if (running) {
          logger.log(
              Level.WARNING, "Connector died: " + listenAddress + " -> " + remoteAddress, ex);

          stop();
          // Something wrong has happened
          errorHandler.handleFatalError(
              this, "A socket exception was thrown" + " while trying to receive a message.", ex);
        } else {
          // The exception was most probably caused by calling
          // this.stop().
        }
      } catch (ClosedChannelException cce) {
        logger.log(Level.WARNING, "A net access point has gone useless:", cce);

        stop();
        errorHandler.handleFatalError(
            this, "ClosedChannelException occurred while listening" + " for messages!", cce);
      } catch (IOException ex) {
        logger.log(Level.WARNING, "A net access point has gone useless:", ex);

        errorHandler.handleError(ex.getMessage(), ex);
        // do not stop the thread;
      } catch (Throwable ex) {
        logger.log(Level.WARNING, "A net access point has gone useless:", ex);

        stop();
        errorHandler.handleFatalError(
            this, "Unknown error occurred while listening for messages!", ex);
      }
    }
  }

  /** Makes the access point stop listening on its socket. */
  protected void stop() {
    synchronized (sockLock) {
      this.running = false;
      if (this.sock != null) {
        this.sock.close();
        this.sock = null;
      }
    }
  }

  /**
   * Sends message through this access point's socket.
   *
   * @param message the bytes to send.
   * @param address message destination.
   * @throws IOException if an exception occurs while sending the message.
   */
  void sendMessage(byte[] message, TransportAddress address) throws IOException {
    DatagramPacket datagramPacket = new DatagramPacket(message, 0, message.length, address);

    sock.send(datagramPacket);
  }

  /**
   * Returns a String representation of the object.
   *
   * @return a String representation of the object.
   */
  @Override
  public String toString() {
    return "ice4j.Connector@" + listenAddress + " status: " + (running ? "not" : "") + " running";
  }

  /**
   * Returns the <tt>TransportAddress</tt> that this access point is bound on.
   *
   * @return the <tt>TransportAddress</tt> associated with this AP.
   */
  TransportAddress getListenAddress() {
    return listenAddress;
  }

  /**
   * Returns the remote <tt>TransportAddress</tt> in case of TCP, or <tt>null</tt> in case of UDP.
   *
   * @return the remote <tt>TransportAddress</tt> in case of TCP, or <tt>null</tt> in case of UDP.
   */
  TransportAddress getRemoteAddress() {
    return remoteAddress;
  }
}
Esempio n. 16
0
/**
 * Implements a <tt>CandidateHarvester</tt> which gathers <tt>Candidate</tt>s for a specified {@link
 * Component} using UPnP.
 *
 * @author Sebastien Vincent
 */
public class UPNPHarvester extends AbstractCandidateHarvester {
  /** The logger. */
  private static final Logger logger = Logger.getLogger(UPNPHarvester.class.getName());

  /** Maximum port to try to allocate. */
  private static final int MAX_RETRIES = 5;

  /** ST search field for WANIPConnection. */
  private static final String stIP = "urn:schemas-upnp-org:service:WANIPConnection:1";

  /** ST search field for WANPPPConnection. */
  private static final String stPPP = "urn:schemas-upnp-org:service:WANPPPConnection:1";

  /** Synchronization object. */
  private final Object rootSync = new Object();

  /** Gateway device. */
  private GatewayDevice device = null;

  /** Number of UPnP discover threads that have finished. */
  private int finishThreads = 0;

  /**
   * Gathers UPnP candidates for all host <tt>Candidate</tt>s that are already present in the
   * specified <tt>component</tt>. This method relies on the specified <tt>component</tt> to already
   * contain all its host candidates so that it would resolve them.
   *
   * @param component the {@link Component} that we'd like to gather candidate UPnP
   *     <tt>Candidate</tt>s for
   * @return the <tt>LocalCandidate</tt>s gathered by this <tt>CandidateHarvester</tt>
   */
  public synchronized Collection<LocalCandidate> harvest(Component component) {
    Collection<LocalCandidate> candidates = new HashSet<>();
    int retries = 0;

    logger.fine("Begin UPnP harvesting");
    try {
      if (device == null) {
        // do it only once
        if (finishThreads == 0) {
          try {
            UPNPThread wanIPThread = new UPNPThread(stIP);
            UPNPThread wanPPPThread = new UPNPThread(stPPP);

            wanIPThread.start();
            wanPPPThread.start();

            synchronized (rootSync) {
              while (finishThreads != 2) {
                rootSync.wait();
              }
            }

            if (wanIPThread.getDevice() != null) {
              device = wanIPThread.getDevice();
            } else if (wanPPPThread.getDevice() != null) {
              device = wanPPPThread.getDevice();
            }

          } catch (Throwable e) {
            logger.info("UPnP discovery failed: " + e);
          }
        }

        if (device == null) return candidates;
      }

      InetAddress localAddress = device.getLocalAddress();
      String externalIPAddress = device.getExternalIPAddress();
      PortMappingEntry portMapping = new PortMappingEntry();

      IceSocketWrapper socket =
          new IceUdpSocketWrapper(new MultiplexingDatagramSocket(0, localAddress));
      int port = socket.getLocalPort();
      int externalPort = socket.getLocalPort();

      while (retries < MAX_RETRIES) {
        if (!device.getSpecificPortMappingEntry(port, "UDP", portMapping)) {
          if (device.addPortMapping(
              externalPort, port, localAddress.getHostAddress(), "UDP", "ice4j.org: " + port)) {
            List<LocalCandidate> cands =
                createUPNPCandidate(socket, externalIPAddress, externalPort, component, device);

            logger.info("Add UPnP port mapping: " + externalIPAddress + " " + externalPort);

            // we have to add the UPNPCandidate and also the base.
            // if we don't add the base, we won't be able to add
            // peer reflexive candidate if someone contact us on the
            // UPNPCandidate
            for (LocalCandidate cand : cands) {
              // try to add the candidate to the component and then
              // only add it to the harvest not redundant
              if (component.addLocalCandidate(cand)) {
                candidates.add(cand);
              }
            }

            break;
          } else {
            port++;
          }
        } else {
          port++;
        }
        retries++;
      }
    } catch (Throwable e) {
      logger.info("Exception while gathering UPnP candidates: " + e);
    }

    return candidates;
  }

  /**
   * Create a UPnP candidate.
   *
   * @param socket local socket
   * @param externalIP external IP address
   * @param port local port
   * @param component parent component
   * @param device the UPnP gateway device
   * @return a new <tt>UPNPCandidate</tt> instance which represents the specified
   *     <tt>TransportAddress</tt>
   * @throws Exception if something goes wrong during candidate creation
   */
  private List<LocalCandidate> createUPNPCandidate(
      IceSocketWrapper socket,
      String externalIP,
      int port,
      Component component,
      GatewayDevice device)
      throws Exception {
    List<LocalCandidate> ret = new ArrayList<>();
    TransportAddress addr = new TransportAddress(externalIP, port, Transport.UDP);

    HostCandidate base = new HostCandidate(socket, component);

    UPNPCandidate candidate = new UPNPCandidate(addr, base, component, device);
    IceSocketWrapper stunSocket = candidate.getStunSocket(null);
    candidate.getStunStack().addSocket(stunSocket);
    component.getComponentSocket().add(candidate.getCandidateIceSocketWrapper());

    ret.add(candidate);
    ret.add(base);

    return ret;
  }

  /** UPnP discover thread. */
  private class UPNPThread extends Thread {
    /** Gateway device. */
    private GatewayDevice device = null;

    /** ST search field. */
    private final String st;

    /**
     * Constructor.
     *
     * @param st ST search field
     */
    public UPNPThread(String st) {
      this.st = st;
    }

    /**
     * Returns gateway device.
     *
     * @return gateway device
     */
    public GatewayDevice getDevice() {
      return device;
    }

    /** Thread Entry point. */
    public void run() {
      try {
        GatewayDiscover gd = new GatewayDiscover(st);

        gd.discover();

        if (gd.getValidGateway() != null) {
          device = gd.getValidGateway();
        }
      } catch (Throwable e) {
        logger.info("Failed to harvest UPnP: " + e);

        /*
         * The Javadoc on ThreadDeath says: If ThreadDeath is caught by
         * a method, it is important that it be rethrown so that the
         * thread actually dies.
         */
        if (e instanceof ThreadDeath) throw (ThreadDeath) e;
      } finally {
        synchronized (rootSync) {
          finishThreads++;
          rootSync.notify();
        }
      }
    }
  }

  /**
   * Returns a <tt>String</tt> representation of this harvester containing its name.
   *
   * @return a <tt>String</tt> representation of this harvester containing its name.
   */
  @Override
  public String toString() {
    return getClass().getSimpleName();
  }
}
Esempio n. 17
0
public class CrawlRuleTester extends Thread {
  protected static Logger log = Logger.getLogger(CrawlRuleTester.class);

  /** Proxy host */
  public static final String PARAM_PROXY_HOST = Configuration.PREFIX + "crawltest.proxy.host";

  /** Proxy port */
  public static final String PARAM_PROXY_PORT = Configuration.PREFIX + "crawltest.proxy.port";

  public static final int DEFAULT_PROXY_PORT = -1;

  /** User-Agent */
  public static final String PARAM_USER_AGENT = Configuration.PREFIX + "crawltest.userAgent";

  /* Message Types */
  public static final int ERROR_MESSAGE = 0;
  public static final int WARNING_MESSAGE = 1;
  public static final int PLAIN_MESSAGE = 2;
  public static final int URL_SUMMARY_MESSAGE = 3;
  public static final int TEST_SUMMARY_MESSAGE = 4;

  private String m_baseUrl;
  private int m_crawlDepth;
  private long m_crawlDelay;
  private int m_curDepth;
  private ArchivalUnit m_au;
  private String m_outputFile = null;
  private BufferedWriter m_outWriter = null;
  private Deadline fetchDeadline = Deadline.in(0);
  private boolean useLocalWriter = true;
  private MessageHandler m_msgHandler;
  private LockssUrlConnectionPool connectionPool = new LockssUrlConnectionPool();
  private String proxyHost;
  private String userAgent;
  private int proxyPort;

  // our storage for extracted urls
  private TreeSet m_extracted = new TreeSet();
  private TreeSet m_incls = new TreeSet();
  private TreeSet m_excls = new TreeSet();
  private TreeSet m_reported = new TreeSet();

  public CrawlRuleTester(int crawlDepth, long crawlDelay, String baseUrl, ArchivalUnit au) {
    super("crawlrule tester");
    m_crawlDepth = crawlDepth;
    long minFetchDelay =
        CurrentConfig.getLongParam(
            BaseArchivalUnit.PARAM_MIN_FETCH_DELAY, BaseArchivalUnit.DEFAULT_MIN_FETCH_DELAY);
    m_crawlDelay = Math.max(crawlDelay, minFetchDelay);
    m_baseUrl = baseUrl;
    m_au = au;
  }
  /**
   * RuleTest
   *
   * @param outFile String
   * @param crawlDepth int
   * @param crawlDelay long
   * @param baseUrl String
   * @param crawlSpec CrawlSpec
   */
  public CrawlRuleTester(
      String outFile, int crawlDepth, long crawlDelay, String baseUrl, ArchivalUnit au) {

    this(crawlDepth, crawlDelay, baseUrl, au);
    m_outputFile = outFile;
  }

  /**
   * RuleTest
   *
   * @param outWriter BufferedWriter
   * @param crawlDepth int
   * @param crawlDelay long
   * @param baseUrl String
   * @param crawlSpec CrawlSpec
   */
  public CrawlRuleTester(
      BufferedWriter outWriter, int crawlDepth, long crawlDelay, String baseUrl, ArchivalUnit au) {
    this(crawlDepth, crawlDelay, baseUrl, au);
    m_outWriter = outWriter;
  }

  /**
   * RuleTest
   *
   * @param msgHandler MessageHandler to take all output
   * @param crawlDepth the crawl depth to use
   * @param crawlDelay the type to wait between fetches
   * @param baseUrl the url to start from
   * @param crawlSpec a CrawlSpec to use for url checking.
   */
  public CrawlRuleTester(
      MessageHandler msgHandler, int crawlDepth, long crawlDelay, String baseUrl, ArchivalUnit au) {
    this(crawlDepth, crawlDelay, baseUrl, au);
    m_msgHandler = msgHandler;
  }

  public void run() {
    try {
      setConfig(ConfigManager.getCurrentConfig());
      if (m_outWriter == null && m_msgHandler == null) {
        useLocalWriter = true;
      } else {
        useLocalWriter = false;
      }
      if (useLocalWriter) {
        openOutputFile();
      }
      checkRules();
      if (useLocalWriter) {
        closeOutputFile();
      }
    } finally {
      if (m_msgHandler != null) {
        m_msgHandler.close();
      }
    }
  }

  void setConfig(Configuration config) {
    log.debug("config: " + config);
    proxyHost = config.get(PARAM_PROXY_HOST);
    proxyPort = config.getInt(PARAM_PROXY_PORT, DEFAULT_PROXY_PORT);
    if (StringUtil.isNullString(proxyHost) || proxyPort <= 0) {
      String http_proxy = System.getenv("http_proxy");
      if (!StringUtil.isNullString(http_proxy)) {
        try {
          HostPortParser hpp = new HostPortParser(http_proxy);
          proxyHost = hpp.getHost();
          proxyPort = hpp.getPort();
        } catch (HostPortParser.InvalidSpec e) {
          log.warning("Can't parse http_proxy environment var, ignoring: " + http_proxy + ": " + e);
        }
      }
    }
    if (StringUtil.isNullString(proxyHost) || proxyPort <= 0) {
      proxyHost = null;
    } else {
      log.info("Proxying through " + proxyHost + ":" + proxyPort);
    }
    userAgent = config.get(PARAM_USER_AGENT);
    if (StringUtil.isNullString(userAgent)) {
      userAgent = null;
    } else {
      log.debug("Setting User-Agent to " + userAgent);
    }
  }

  private void openOutputFile() {
    if (m_outputFile != null) {
      try {
        m_outWriter = new BufferedWriter(new FileWriter(m_outputFile, false));
        return;
      } catch (Exception ex) {
        System.err.println("Error opening output file, writing to stdout: " + ex);
      }
    }
    m_outWriter = new BufferedWriter(new OutputStreamWriter(System.out));
  }

  private void closeOutputFile() {
    try {
      if (m_outWriter != null) {
        m_outWriter.close();
      }
    } catch (IOException ex) {
      System.err.println("Error closing output file.");
    }
  }

  int[] depth_incl;
  int[] depth_fetched;
  int[] depth_parsed;

  private void checkRules() {
    outputMessage("\nChecking " + m_baseUrl, TEST_SUMMARY_MESSAGE);
    outputMessage(
        "crawl depth: " + m_crawlDepth + "     crawl delay: " + m_crawlDelay + " ms.",
        PLAIN_MESSAGE);

    TreeSet crawlList = new TreeSet();
    TreeSet fetched = new TreeSet();
    // inialize with the baseUrl
    crawlList.add(m_baseUrl);
    depth_incl = new int[m_crawlDepth];
    depth_fetched = new int[m_crawlDepth];
    depth_parsed = new int[m_crawlDepth];
    long start_time = TimeBase.nowMs();
    for (int depth = 1; depth <= m_crawlDepth; depth++) {
      if (isInterrupted()) {
        return;
      }
      m_curDepth = depth;
      if (crawlList.isEmpty() && depth <= m_crawlDepth) {
        outputMessage("\nNothing left to crawl, exiting after depth " + (depth - 1), PLAIN_MESSAGE);
        break;
      }
      String[] urls = (String[]) crawlList.toArray(new String[0]);
      crawlList.clear();
      outputMessage("\nDepth " + depth, PLAIN_MESSAGE);
      for (int ix = 0; ix < urls.length; ix++) {
        if (isInterrupted()) {
          return;
        }
        pauseBeforeFetch();
        String urlstr = urls[ix];

        m_incls.clear();
        m_excls.clear();

        // crawl the page
        buildUrlSets(urlstr);
        fetched.add(urlstr);
        // output incl/excl results,
        // add the new_incls to the crawlList for next crawl depth loop
        crawlList.addAll(outputUrlResults(urlstr, m_incls, m_excls));
      }
    }
    long elapsed_time = TimeBase.nowMs() - start_time;
    outputSummary(m_baseUrl, fetched, crawlList, elapsed_time);
  }

  private void buildUrlSets(String url) {

    try {
      outputMessage("\nFetching " + url, TEST_SUMMARY_MESSAGE);
      URL srcUrl = new URL(url);
      //       URLConnection conn = srcUrl.openConnection();
      //       String type = conn.getContentType();
      //       type = conn.getHeaderField("content-type");
      //       InputStream istr = conn.getInputStream();

      LockssUrlConnection conn = UrlUtil.openConnection(url, connectionPool);
      if (proxyHost != null) {
        conn.setProxy(proxyHost, proxyPort);
      }
      if (userAgent != null) {
        conn.setRequestProperty("user-agent", userAgent);
      }
      try {
        conn.execute();
        int resp = conn.getResponseCode();
        if (resp != 200) {
          outputMessage("Resp: " + resp + ": " + conn.getResponseMessage(), TEST_SUMMARY_MESSAGE);
          return;
        }
        depth_fetched[m_curDepth - 1]++;
        String cookies = conn.getResponseHeaderValue("Set-Cookie");
        if (cookies != null) {
          outputMessage("Cookies: " + cookies, PLAIN_MESSAGE);
        }
        String type = conn.getResponseContentType();
        if (type == null || !type.toLowerCase().startsWith("text/html")) {
          outputMessage("Type: " + type + ", not parsing", URL_SUMMARY_MESSAGE);
          return;
        }
        outputMessage("Type: " + type + ", extracting Urls", URL_SUMMARY_MESSAGE);
        InputStream istr = conn.getResponseInputStream();
        InputStreamReader reader = new InputStreamReader(istr);
        //       MyMockCachedUrl mcu = new MyMockCachedUrl(srcUrl.toString(), reader);
        GoslingHtmlLinkExtractor extractor = new GoslingHtmlLinkExtractor();
        extractor.extractUrls(null, istr, null, srcUrl.toString(), new MyLinkExtractorCallback());
        istr.close();
        depth_parsed[m_curDepth - 1]++;
      } finally {
        conn.release();
      }
    } catch (MalformedURLException murle) {
      murle.printStackTrace();
      outputErrResults(url, "Malformed URL:" + murle.getMessage());
    } catch (IOException ex) {
      ex.printStackTrace();
      outputErrResults(url, "IOException: " + ex.getMessage());
    }
  }

  private void pauseBeforeFetch() {
    if (!fetchDeadline.expired()) {
      try {
        fetchDeadline.sleep();
      } catch (InterruptedException ie) {
        // no action
      }
    }
    fetchDeadline.expireIn(m_crawlDelay);
  }

  private void outputMessage(String msg, int msgType) {
    if (isInterrupted()) {
      return;
    }

    if (m_msgHandler != null) {
      m_msgHandler.outputMessage(msg + "\n", msgType);
    } else {
      try {
        m_outWriter.write(msg);
        m_outWriter.newLine();
      } catch (Exception ex) {
        System.err.println(msg);
      }
    }
  }

  private void outputErrResults(String url, String errMsg) {
    outputMessage("Error: " + errMsg + " occured while processing " + url, ERROR_MESSAGE);
  }

  private Set outputUrlResults(String url, Set m_inclset, Set m_exclset) {
    Set new_incls = new TreeSet(CollectionUtils.subtract(m_inclset, m_reported));
    Set new_excls = new TreeSet(CollectionUtils.subtract(m_exclset, m_reported));
    if (!m_inclset.isEmpty()) {
      outputMessage(
          "\nIncluded Urls: ("
              + new_incls.size()
              + " new, "
              + (m_inclset.size() - new_incls.size())
              + " old)",
          URL_SUMMARY_MESSAGE);
      depth_incl[m_curDepth - 1] += new_incls.size();
    }
    for (Iterator it = new_incls.iterator(); it.hasNext(); ) {
      outputMessage(it.next().toString(), PLAIN_MESSAGE);
    }

    if (!m_exclset.isEmpty()) {
      outputMessage(
          "\nExcluded Urls: ("
              + new_excls.size()
              + " new, "
              + (m_exclset.size() - new_excls.size())
              + " old)",
          URL_SUMMARY_MESSAGE);
    }
    for (Iterator it = new_excls.iterator(); it.hasNext(); ) {
      outputMessage(it.next().toString(), PLAIN_MESSAGE);
    }
    m_reported.addAll(new_incls);
    m_reported.addAll(new_excls);

    if (m_outWriter != null) {
      try {
        m_outWriter.flush();
      } catch (IOException ex) {
      }
    }
    return new_incls;
  }

  private void outputSummary(String baseUrl, Set fetched, Set toCrawl, long elapsedTime) {
    int fetchCount = fetched.size();
    outputMessage(
        "\n\nSummary for starting Url: " + baseUrl + " and depth: " + m_crawlDepth,
        TEST_SUMMARY_MESSAGE);
    outputMessage(
        "\nUrls fetched: " + fetchCount + "    Urls extracted: " + m_extracted.size(),
        PLAIN_MESSAGE);

    outputMessage("\nDepth  Fetched  Parsed  New URLs", PLAIN_MESSAGE);
    for (int depth = 1; depth <= m_crawlDepth; depth++) {
      PrintfFormat pf = new PrintfFormat("%5d  %7d  %6d  %8d");
      Integer[] args =
          new Integer[] {
            new Integer(depth),
            new Integer(depth_fetched[depth - 1]),
            new Integer(depth_parsed[depth - 1]),
            new Integer(depth_incl[depth - 1]),
          };
      String s = pf.sprintf(args);
      outputMessage(s, PLAIN_MESSAGE);
    }

    outputMessage("\nRemaining unfetched: " + toCrawl.size(), PLAIN_MESSAGE);
    if (false) {
      for (Iterator iter = toCrawl.iterator(); iter.hasNext(); ) {
        String url = (String) iter.next();
        outputMessage(url, PLAIN_MESSAGE);
      }
    }
    long secs = elapsedTime / Constants.SECOND;
    long fetchRate = 0;
    if (secs > 0) {
      fetchRate = fetchCount * 60 * Constants.SECOND / elapsedTime;
    }
    outputMessage(
        "\nElapsed Time: " + secs + " secs." + "    Fetch Rate: " + fetchRate + " p/m",
        PLAIN_MESSAGE);
  }

  public interface MessageHandler {
    void outputMessage(String message, int messageType);

    void close();
  }

  private class MyLinkExtractorCallback implements LinkExtractor.Callback {

    MyLinkExtractorCallback() {}

    public void foundLink(String url) {

      m_extracted.add(url);
      try {
        String normUrl = UrlUtil.normalizeUrl(url);
        if (BaseCrawler.isSupportedUrlProtocol(normUrl) && m_au.shouldBeCached(normUrl)) {
          m_incls.add(normUrl);
        } else {
          m_excls.add(normUrl);
        }
      } catch (MalformedURLException e) {
        m_excls.add(url);
      }
    }
  }

  class MyMockCachedUrl implements CachedUrl {
    private String url;
    private boolean doesExist = false;
    private Reader reader = null;

    public MyMockCachedUrl(String url, Reader reader) {
      this.url = url;

      this.reader = reader;
    }

    public ArchivalUnit getArchivalUnit() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public String getUrl() {
      return url;
    }

    public CachedUrl getCuVersion(int version) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public CachedUrl[] getCuVersions() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public CachedUrl[] getCuVersions(int maxVersions) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public int getVersion() {
      return 1;
    }

    public Reader openForReading() {
      return reader;
    }

    public LinkRewriterFactory getLinkRewriterFactory() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public String getEncoding() {
      return Constants.DEFAULT_ENCODING;
    }

    /**
     * getUnfilteredInputStream
     *
     * @return InputStream
     */
    public InputStream getUnfilteredInputStream() {
      throw new UnsupportedOperationException("Not implemented");
    }

    /**
     * getUnfilteredInputStream
     *
     * @return InputStream
     */
    public InputStream getUnfilteredInputStream(HashedInputStream.Hasher hasher) {
      throw new UnsupportedOperationException("Not implemented");
    }

    public InputStream getUncompressedInputStream() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public InputStream getUncompressedInputStream(HashedInputStream.Hasher hasher) {
      throw new UnsupportedOperationException("Not implemented");
    }

    /**
     * openForHashing
     *
     * @return InputStream
     */
    public InputStream openForHashing() {
      throw new UnsupportedOperationException("Not implemented");
    }

    /**
     * openForHashing
     *
     * @param hasher HashedInputStream.Hasher for unfiltered content
     * @return InputStream
     */
    public InputStream openForHashing(HashedInputStream.Hasher hasher) {
      throw new UnsupportedOperationException("Not implemented");
    }

    /**
     * getContentSize
     *
     * @return long
     */
    public long getContentSize() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public String getContentType() {
      throw new UnsupportedOperationException("Not implemented");
    }

    public void setOption(String option, String val) {}

    public boolean hasContent() {
      return doesExist;
    }

    public boolean isLeaf() {
      return true;
    }

    public int getType() {
      return CachedUrlSetNode.TYPE_CACHED_URL;
    }

    public CIProperties getProperties() {
      return null;
    }

    public void addProperty(String key, String value) {}

    public void release() {}

    public String toString() {
      StringBuffer sb = new StringBuffer(url.length() + 17);
      sb.append("[MyMockCachedUrl: ");
      sb.append(url);
      sb.append("]");
      return sb.toString();
    }

    @Override
    public FileMetadataExtractor getFileMetadataExtractor(MetadataTarget target) {
      return null;
    }

    public CachedUrl getArchiveMemberCu(ArchiveMemberSpec ams) {
      throw new UnsupportedOperationException("Not implemented");
    }

    @Override
    public boolean isArchiveMember() {
      return false;
    }
  }
}
Esempio n. 18
0
/**
 * Handles OPTIONS requests by replying with an OK response containing methods that we support.
 *
 * @author Emil Ivov
 * @author Pawel Domas
 */
public class ClientCapabilities extends MethodProcessorAdapter {

  /**
   * The <tt>Logger</tt> used by the <tt>ClientCapabilities</tt> class and its instances for logging
   * output.
   */
  private static final Logger logger = Logger.getLogger(ClientCapabilities.class);

  /** The protocol provider that created us. */
  private final ProtocolProviderServiceSipImpl provider;

  /** Registration listener instance. */
  private final RegistrationListener registrationListener;

  /** The timer that runs the keep-alive task */
  private Timer keepAliveTimer = null;

  /** The next long to use as a cseq header value. */
  private long nextCSeqValue = 1;

  /**
   * Creates a new instance of this class using the specified parent <tt>protocolProvider</tt>.
   *
   * @param protocolProvider a reference to the <tt>ProtocolProviderServiceSipImpl</tt> instance
   *     that created us.
   */
  public ClientCapabilities(ProtocolProviderServiceSipImpl protocolProvider) {
    this.provider = protocolProvider;

    provider.registerMethodProcessor(Request.OPTIONS, this);

    registrationListener = new RegistrationListener();
    provider.addRegistrationStateChangeListener(registrationListener);
  }

  /**
   * Receives options requests and replies with an OK response containing methods that we support.
   *
   * @param requestEvent the incoming options request.
   * @return <tt>true</tt> if request has been successfully processed, <tt>false</tt> otherwise
   */
  @Override
  public boolean processRequest(RequestEvent requestEvent) {
    Response optionsOK = null;
    try {
      optionsOK =
          provider.getMessageFactory().createResponse(Response.OK, requestEvent.getRequest());

      // add to the allows header all methods that we support
      for (String method : provider.getSupportedMethods()) {
        // don't support REGISTERs
        if (!method.equals(Request.REGISTER))
          optionsOK.addHeader(provider.getHeaderFactory().createAllowHeader(method));
      }

      Iterable<String> knownEventsList = provider.getKnownEventsList();

      synchronized (knownEventsList) {
        for (String event : knownEventsList)
          optionsOK.addHeader(provider.getHeaderFactory().createAllowEventsHeader(event));
      }
    } catch (ParseException ex) {
      // What else could we do apart from logging?
      logger.warn("Failed to create an incoming OPTIONS request", ex);
      return false;
    }

    try {
      SipStackSharing.getOrCreateServerTransaction(requestEvent).sendResponse(optionsOK);
    } catch (TransactionUnavailableException ex) {
      // this means that we received an OPTIONS request outside the scope
      // of a transaction which could mean that someone is simply sending
      // us b****hit to keep a NAT connection alive, so let's not get too
      // excited.
      if (logger.isInfoEnabled())
        logger.info("Failed to respond to an incoming " + "transactionless OPTIONS request");
      if (logger.isTraceEnabled()) logger.trace("Exception was:", ex);
      return false;
    } catch (InvalidArgumentException ex) {
      // What else could we do apart from logging?
      logger.warn("Failed to send an incoming OPTIONS request", ex);
      return false;
    } catch (SipException ex) {
      // What else could we do apart from logging?
      logger.warn("Failed to send an incoming OPTIONS request", ex);
      return false;
    }

    return true;
  }

  /**
   * Returns the next long to use as a cseq header value.
   *
   * @return the next long to use as a cseq header value.
   */
  private long getNextCSeqValue() {
    return nextCSeqValue++;
  }

  /** Fire event that connection has failed and we had to unregister the protocol provider. */
  private void disconnect() {
    // don't alert the user if we're already off
    if (provider.getRegistrationState().equals(RegistrationState.UNREGISTERED)) {
      return;
    }

    provider
        .getRegistrarConnection()
        .setRegistrationState(
            RegistrationState.CONNECTION_FAILED,
            RegistrationStateChangeEvent.REASON_NOT_SPECIFIED,
            "A timeout occurred while trying to connect to the server.");
  }

  /** Frees allocated resources. */
  void shutdown() {
    provider.removeRegistrationStateChangeListener(registrationListener);
  }

  /** The task would continuously send OPTIONs request that we use as a keep alive method. */
  private class OptionsKeepAliveTask extends TimerTask {
    @Override
    public void run() {
      try {
        logger.logEntry();

        // From
        FromHeader fromHeader = null;
        try {
          // this keep alive task only makes sense in case we have
          // a registrar so we deliberately use our AOR and do not
          // use the getOurSipAddress() method.
          fromHeader =
              provider
                  .getHeaderFactory()
                  .createFromHeader(
                      provider.getRegistrarConnection().getAddressOfRecord(),
                      SipMessageFactory.generateLocalTag());
        } catch (ParseException ex) {
          // this should never happen so let's just log and bail.
          logger.error("Failed to generate a from header for " + "our register request.", ex);
          return;
        }

        // Call ID Header
        CallIdHeader callIdHeader = provider.getDefaultJainSipProvider().getNewCallId();

        // CSeq Header
        CSeqHeader cSeqHeader = null;
        try {
          cSeqHeader =
              provider.getHeaderFactory().createCSeqHeader(getNextCSeqValue(), Request.OPTIONS);
        } catch (ParseException ex) {
          // Should never happen
          logger.error("Corrupt Sip Stack", ex);
          return;
        } catch (InvalidArgumentException ex) {
          // Should never happen
          logger.error("The application is corrupt", ex);
          return;
        }

        // To Header
        ToHeader toHeader = null;
        try {
          // this request isn't really going anywhere so we put our
          // own address in the To Header.
          toHeader = provider.getHeaderFactory().createToHeader(fromHeader.getAddress(), null);
        } catch (ParseException ex) {
          logger.error("Could not create a To header for address:" + fromHeader.getAddress(), ex);
          return;
        }

        // MaxForwardsHeader
        MaxForwardsHeader maxForwardsHeader = provider.getMaxForwardsHeader();
        // Request
        Request request = null;
        try {
          // create a host-only uri for the request uri header.
          String domain = ((SipURI) toHeader.getAddress().getURI()).getHost();

          // request URI
          SipURI requestURI = provider.getAddressFactory().createSipURI(null, domain);

          // Via Headers
          ArrayList<ViaHeader> viaHeaders = provider.getLocalViaHeaders(requestURI);

          request =
              provider
                  .getMessageFactory()
                  .createRequest(
                      requestURI,
                      Request.OPTIONS,
                      callIdHeader,
                      cSeqHeader,
                      fromHeader,
                      toHeader,
                      viaHeaders,
                      maxForwardsHeader);

          if (logger.isDebugEnabled()) logger.debug("Created OPTIONS request " + request);
        } catch (ParseException ex) {
          logger.error("Could not create an OPTIONS request!", ex);
          return;
        }

        Iterator<String> supportedMethods = provider.getSupportedMethods().iterator();

        // add to the allows header all methods that we support
        while (supportedMethods.hasNext()) {
          String method = supportedMethods.next();

          // don't support REGISTERs
          if (method.equals(Request.REGISTER)) continue;

          request.addHeader(provider.getHeaderFactory().createAllowHeader(method));
        }

        Iterator<String> events = provider.getKnownEventsList().iterator();

        synchronized (provider.getKnownEventsList()) {
          while (events.hasNext()) {
            String event = events.next();

            request.addHeader(provider.getHeaderFactory().createAllowEventsHeader(event));
          }
        }

        // Transaction
        ClientTransaction optionsTrans = null;
        try {
          optionsTrans = provider.getDefaultJainSipProvider().getNewClientTransaction(request);
        } catch (TransactionUnavailableException ex) {
          logger.error("Could not create options transaction!\n", ex);
          return;
        }
        try {
          optionsTrans.sendRequest();
          if (logger.isDebugEnabled()) logger.debug("sent request= " + request);
        } catch (SipException ex) {
          logger.error("Could not send out the options request!", ex);

          if (ex.getCause() instanceof IOException) {
            // IOException problem with network
            disconnect();
          }

          return;
        }
      } catch (Exception ex) {
        logger.error("Cannot send OPTIONS keep alive", ex);
      }
    }
  }

  /** Class implements CRLF keep alive method. */
  private class CRLfKeepAliveTask extends TimerTask {

    @Override
    public void run() {
      ProxyConnection connection = provider.getConnection();
      if (connection == null) {
        logger.error("No connection found to send CRLF keep alive" + " with " + provider);
        return;
      }

      ListeningPoint lp = provider.getListeningPoint(connection.getTransport());

      if (!(lp instanceof ListeningPointExt)) {
        logger.error("ListeningPoint is not ListeningPointExt" + "(or is null)");
        return;
      }

      InetSocketAddress address = connection.getAddress();
      try {
        ((ListeningPointExt) lp)
            .sendHeartbeat(address.getAddress().getHostAddress(), address.getPort());
      } catch (IOException e) {
        logger.error("Error while sending a heartbeat", e);
      }
    }
  }

  private class RegistrationListener implements RegistrationStateChangeListener {
    /**
     * The method is called by a ProtocolProvider implementation whenever a change in the
     * registration state of the corresponding provider had occurred. The method is particularly
     * interested in events stating that the SIP provider has unregistered so that it would fire
     * status change events for all contacts in our buddy list.
     *
     * @param evt ProviderStatusChangeEvent the event describing the status change.
     */
    public void registrationStateChanged(RegistrationStateChangeEvent evt) {
      if (evt.getNewState() == RegistrationState.UNREGISTERING
          || evt.getNewState() == RegistrationState.UNREGISTERED
          || evt.getNewState() == RegistrationState.AUTHENTICATION_FAILED
          || evt.getNewState() == RegistrationState.CONNECTION_FAILED) {
        // stop any task associated with the timer
        if (keepAliveTimer != null) {
          keepAliveTimer.cancel();
          keepAliveTimer = null;
        }
      } else if (evt.getNewState().equals(RegistrationState.REGISTERED)) {
        String keepAliveMethod =
            provider
                .getAccountID()
                .getAccountPropertyString(ProtocolProviderFactory.KEEP_ALIVE_METHOD);

        if (logger.isTraceEnabled()) logger.trace("Keep alive method " + keepAliveMethod);
        // options is default keep-alive, if property is missing
        // then options is used
        if (keepAliveMethod != null
            && !(keepAliveMethod.equalsIgnoreCase("options")
                || keepAliveMethod.equalsIgnoreCase("crlf"))) return;

        int keepAliveInterval =
            provider
                .getAccountID()
                .getAccountPropertyInt(ProtocolProviderFactory.KEEP_ALIVE_INTERVAL, -1);

        if (logger.isTraceEnabled()) logger.trace("Keep alive interval is " + keepAliveInterval);
        if (keepAliveInterval > 0 && !provider.getRegistrarConnection().isRegistrarless()) {
          if (keepAliveTimer == null) keepAliveTimer = new Timer();

          TimerTask keepAliveTask;
          // CRLF is used by default on Android
          if ((OSUtils.IS_ANDROID && keepAliveMethod == null)
              || "crlf".equalsIgnoreCase(keepAliveMethod)) {
            keepAliveTask = new CRLfKeepAliveTask();
          } else {
            // OPTIONS
            keepAliveTask = new OptionsKeepAliveTask();
          }

          if (logger.isDebugEnabled()) logger.debug("Scheduling keep alives: " + keepAliveTask);

          keepAliveTimer.schedule(keepAliveTask, 0, keepAliveInterval * 1000);
        }
      }
    }
  }
}
Esempio n. 19
0
public class ShowPreviewDialog extends SIPCommDialog
    implements ActionListener, ChatLinkClickedListener {
  /** Serial version UID. */
  private static final long serialVersionUID = 1L;

  /**
   * The <tt>Logger</tt> used by the <tt>ShowPreviewDialog</tt> class and its instances for logging
   * output.
   */
  private static final Logger logger = Logger.getLogger(ShowPreviewDialog.class);

  ConfigurationService cfg = GuiActivator.getConfigurationService();

  /** The Ok button. */
  private final JButton okButton;

  /** The cancel button. */
  private final JButton cancelButton;

  /** Checkbox that indicates whether or not to show this dialog next time. */
  private final JCheckBox enableReplacementProposal;

  /** Checkbox that indicates whether or not to show previews automatically */
  private final JCheckBox enableReplacement;

  /** The <tt>ChatConversationPanel</tt> that this dialog is associated with. */
  private final ChatConversationPanel chatPanel;

  /** Mapping between messageID and the string representation of the chat message. */
  private Map<String, String> msgIDToChatString = new ConcurrentHashMap<String, String>();

  /**
   * Mapping between the pair (messageID, link position) and the actual link in the string
   * representation of the chat message.
   */
  private Map<String, String> msgIDandPositionToLink = new ConcurrentHashMap<String, String>();

  /**
   * Mapping between link and replacement for this link that is acquired from it's corresponding
   * <tt>ReplacementService</tt>.
   */
  private Map<String, String> linkToReplacement = new ConcurrentHashMap<String, String>();

  /** The id of the message that is currently associated with this dialog. */
  private String currentMessageID = "";

  /** The position of the link in the current message. */
  private String currentLinkPosition = "";

  /**
   * Creates an instance of <tt>ShowPreviewDialog</tt>
   *
   * @param chatPanel The <tt>ChatConversationPanel</tt> that is associated with this dialog.
   */
  ShowPreviewDialog(final ChatConversationPanel chatPanel) {
    this.chatPanel = chatPanel;

    this.setTitle(
        GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW_DIALOG_TITLE"));
    okButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.OK"));
    cancelButton = new JButton(GuiActivator.getResources().getI18NString("service.gui.CANCEL"));

    JPanel mainPanel = new TransparentPanel();
    mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
    mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    // mainPanel.setPreferredSize(new Dimension(200, 150));
    this.getContentPane().add(mainPanel);

    JTextPane descriptionMsg = new JTextPane();
    descriptionMsg.setEditable(false);
    descriptionMsg.setOpaque(false);
    descriptionMsg.setText(
        GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW_WARNING_DESCRIPTION"));

    Icon warningIcon = null;
    try {
      warningIcon =
          new ImageIcon(
              ImageIO.read(
                  GuiActivator.getResources().getImageURL("service.gui.icons.WARNING_ICON")));
    } catch (IOException e) {
      logger.debug("failed to load the warning icon");
    }
    JLabel warningSign = new JLabel(warningIcon);

    JPanel warningPanel = new TransparentPanel();
    warningPanel.setLayout(new BoxLayout(warningPanel, BoxLayout.X_AXIS));
    warningPanel.add(warningSign);
    warningPanel.add(Box.createHorizontalStrut(10));
    warningPanel.add(descriptionMsg);

    enableReplacement =
        new JCheckBox(
            GuiActivator.getResources()
                .getI18NString("plugin.chatconfig.replacement.ENABLE_REPLACEMENT_STATUS"));
    enableReplacement.setOpaque(false);
    enableReplacement.setSelected(cfg.getBoolean(ReplacementProperty.REPLACEMENT_ENABLE, true));
    enableReplacementProposal =
        new JCheckBox(
            GuiActivator.getResources()
                .getI18NString("plugin.chatconfig.replacement.ENABLE_REPLACEMENT_PROPOSAL"));
    enableReplacementProposal.setOpaque(false);

    JPanel checkBoxPanel = new TransparentPanel();
    checkBoxPanel.setLayout(new BoxLayout(checkBoxPanel, BoxLayout.Y_AXIS));
    checkBoxPanel.add(enableReplacement);
    checkBoxPanel.add(enableReplacementProposal);

    JPanel buttonsPanel = new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
    buttonsPanel.add(okButton);
    buttonsPanel.add(cancelButton);

    mainPanel.add(warningPanel);
    mainPanel.add(Box.createVerticalStrut(10));
    mainPanel.add(checkBoxPanel);
    mainPanel.add(buttonsPanel);

    okButton.addActionListener(this);
    cancelButton.addActionListener(this);

    this.setPreferredSize(new Dimension(390, 230));
  }

  @Override
  public void actionPerformed(ActionEvent arg0) {
    if (arg0.getSource().equals(okButton)) {
      cfg.setProperty(ReplacementProperty.REPLACEMENT_ENABLE, enableReplacement.isSelected());
      cfg.setProperty(
          ReplacementProperty.REPLACEMENT_PROPOSAL, enableReplacementProposal.isSelected());
      SwingWorker worker =
          new SwingWorker() {
            /**
             * Called on the event dispatching thread (not on the worker thread) after the <code>
             * construct</code> method has returned.
             */
            @Override
            public void finished() {
              String newChatString = (String) get();

              if (newChatString != null) {
                try {
                  Element elem = chatPanel.document.getElement(currentMessageID);
                  chatPanel.document.setOuterHTML(elem, newChatString);
                  msgIDToChatString.put(currentMessageID, newChatString);
                } catch (BadLocationException ex) {
                  logger.error("Could not replace chat message", ex);
                } catch (IOException ex) {
                  logger.error("Could not replace chat message", ex);
                }
              }
            }

            @Override
            protected Object construct() throws Exception {
              String newChatString = msgIDToChatString.get(currentMessageID);
              try {
                String originalLink =
                    msgIDandPositionToLink.get(currentMessageID + "#" + currentLinkPosition);
                String replacementLink = linkToReplacement.get(originalLink);
                String replacement;
                DirectImageReplacementService source =
                    GuiActivator.getDirectImageReplacementSource();
                if (originalLink.equals(replacementLink)
                    && (!source.isDirectImage(originalLink)
                        || source.getImageSize(originalLink) == -1)) {
                  replacement = originalLink;
                } else {
                  replacement =
                      "<IMG HEIGHT=\"90\" WIDTH=\"120\" SRC=\""
                          + replacementLink
                          + "\" BORDER=\"0\" ALT=\""
                          + originalLink
                          + "\"></IMG>";
                }

                String old =
                    originalLink
                        + "</A> <A href=\"jitsi://"
                        + ShowPreviewDialog.this.getClass().getName()
                        + "/SHOWPREVIEW?"
                        + currentMessageID
                        + "#"
                        + currentLinkPosition
                        + "\">"
                        + GuiActivator.getResources().getI18NString("service.gui.SHOW_PREVIEW");

                newChatString = newChatString.replace(old, replacement);
              } catch (Exception ex) {
                logger.error("Could not replace chat message", ex);
              }
              return newChatString;
            }
          };
      worker.start();
      this.setVisible(false);
    } else if (arg0.getSource().equals(cancelButton)) {
      this.setVisible(false);
    }
  }

  @Override
  public void chatLinkClicked(URI url) {
    String action = url.getPath();
    if (action.equals("/SHOWPREVIEW")) {
      enableReplacement.setSelected(cfg.getBoolean(ReplacementProperty.REPLACEMENT_ENABLE, true));
      enableReplacementProposal.setSelected(
          cfg.getBoolean(ReplacementProperty.REPLACEMENT_PROPOSAL, true));

      currentMessageID = url.getQuery();
      currentLinkPosition = url.getFragment();

      this.setVisible(true);
      this.setLocationRelativeTo(chatPanel);
    }
  }

  /**
   * Returns mapping between messageID and the string representation of the chat message.
   *
   * @return mapping between messageID and chat string.
   */
  Map<String, String> getMsgIDToChatString() {
    return msgIDToChatString;
  }

  /**
   * Returns mapping between the pair (messageID, link position) and the actual link in the string
   * representation of the chat message.
   *
   * @return mapping between (messageID, linkPosition) and link.
   */
  Map<String, String> getMsgIDandPositionToLink() {
    return msgIDandPositionToLink;
  }

  /**
   * Returns mapping between link and replacement for this link that was acquired from it's
   * corresponding <tt>ReplacementService</tt>.
   *
   * @return mapping between link and it's corresponding replacement.
   */
  Map<String, String> getLinkToReplacement() {
    return linkToReplacement;
  }
}
Esempio n. 20
0
/** Export the contents and metadata from an AU */
public abstract class Exporter {

  private static final Logger log = Logger.getLogger(Exporter.class);

  static final String PREFIX = Configuration.PREFIX + "exporter.";

  /** Abort export after this many errors */
  public static final String PARAM_MAX_ERRORS = PREFIX + "maxErrors";

  public static final int DEFAULT_MAX_ERRORS = 5;

  protected static int maxErrors = DEFAULT_MAX_ERRORS;

  protected LockssDaemon daemon;
  protected ArchivalUnit au;
  protected File dir;
  protected String prefix;
  protected long maxSize = -1;
  protected int maxVersions = 1;
  protected boolean compress = false;
  protected boolean excludeDirNodes = false;
  protected FilenameTranslation xlate = FilenameTranslation.XLATE_NONE;
  protected List errors = new ArrayList();
  protected boolean isDiskFull = false;

  protected abstract void start() throws IOException;

  protected abstract void finish() throws IOException;

  protected abstract void writeCu(CachedUrl cu) throws IOException;

  protected Exporter(LockssDaemon daemon, ArchivalUnit au) {
    this.daemon = daemon;
    this.au = au;
  }

  /** Called by org.lockss.config.MiscConfig */
  public static void setConfig(
      Configuration config, Configuration oldConfig, Configuration.Differences diffs) {
    if (diffs.contains(PREFIX)) {
      maxErrors = config.getInt(PARAM_MAX_ERRORS, DEFAULT_MAX_ERRORS);
    }
  }

  public void setCompress(boolean val) {
    compress = val;
  }

  public boolean getCompress() {
    return compress;
  }

  public void setExcludeDirNodes(boolean val) {
    excludeDirNodes = val;
  }

  public boolean getExcludeDirNodes() {
    return excludeDirNodes;
  }

  public void setFilenameTranslation(FilenameTranslation val) {
    xlate = val;
  }

  public FilenameTranslation getFilenameTranslation() {
    return xlate;
  }

  public void setDir(File val) {
    dir = val;
  }

  public File getDir() {
    return dir;
  }

  public void setPrefix(String val) {
    prefix = val;
  }

  public String getPrefix() {
    return prefix;
  }

  public void setMaxSize(long val) {
    maxSize = val;
  }

  public long getMaxSize() {
    return maxSize;
  }

  public void setMaxVersions(int val) {
    maxVersions = val;
  }

  public int getMaxVersions() {
    return maxVersions;
  }

  public List getErrors() {
    return errors;
  }

  protected void checkArgs() {
    if (getDir() == null) {
      throw new IllegalArgumentException("Must supply output directory");
    }
    if (getPrefix() == null) {
      throw new IllegalArgumentException("Must supply file name/prefix");
    }
  }

  public void export() {
    log.debug("export(" + au.getName() + ")");
    log.debug(
        "dir: "
            + dir
            + ", pref: "
            + prefix
            + ", size: "
            + maxSize
            + ", ver: "
            + maxVersions
            + (compress ? ", (C)" : ""));
    checkArgs();
    try {
      start();
    } catch (IOException e) {
      recordError("Error opening file", e);
      return;
    }
    writeFiles();
    try {
      finish();
    } catch (IOException e) {
      if (!isDiskFull) {
        // If we already knew (and reported) disk full, also reporting it
        // as a close error is misleading.
        recordError("Error closing file", e);
      }
    }
  }

  protected String xlateFilename(String url) {
    return xlate.xlate(url);
  }

  protected void recordError(String msg, Throwable t) {
    log.error(msg, t);
    errors.add(msg + ": " + t.toString());
  }

  protected void recordError(String msg) {
    log.error(msg);
    errors.add(msg);
  }

  protected String getSoftwareVersion() {
    String releaseName = BuildInfo.getBuildProperty(BuildInfo.BUILD_RELEASENAME);
    StringBuilder sb = new StringBuilder();
    sb.append("LOCKSS Daemon ");
    if (releaseName != null) {
      sb.append(releaseName);
    }
    return sb.toString();
  }

  protected String getHostIp() {
    try {
      IPAddr localHost = IPAddr.getLocalHost();
      return localHost.getHostAddress();
    } catch (UnknownHostException e) {
      log.error("getHostIp()", e);
      return "1.1.1.1";
    }
  }

  protected String getHostName() {
    String res = ConfigManager.getPlatformHostname();
    if (res == null) {
      try {
        InetAddress inet = InetAddress.getLocalHost();
        return inet.getHostName();
      } catch (UnknownHostException e) {
        log.warning("Can't get hostname", e);
        return "unknown";
      }
    }
    return res;
  }

  protected Properties filterResponseProps(Properties props) {
    Properties res = new Properties();
    for (Map.Entry ent : props.entrySet()) {
      String key = (String) ent.getKey();
      if (StringUtil.startsWithIgnoreCase(key, "x-lockss")
          || StringUtil.startsWithIgnoreCase(key, "x_lockss")
          || key.equalsIgnoreCase("org.lockss.version.number")) {
        continue;
      }
      // We've lost the original case - capitalize them the way most people
      // expect
      res.put(StringUtil.titleCase(key, '-'), (String) ent.getValue());
    }
    return res;
  }

  protected String getHttpResponseString(CachedUrl cu) {
    Properties cuProps = cu.getProperties();
    Properties filteredProps = filterResponseProps(cuProps);
    String hdrString = PropUtil.toHeaderString(filteredProps);
    StringBuilder sb = new StringBuilder(hdrString.length() + 30);
    String line1 = inferHttpResponseCode(cu, cuProps);
    sb.append(line1);
    sb.append(Constants.CRLF);
    sb.append(hdrString);
    sb.append(Constants.CRLF);
    return sb.toString();
  }

  String inferHttpResponseCode(CachedUrl cu, Properties cuProps) {
    if (cuProps.get("location") == null) {
      return "HTTP/1.1 200 OK";
    } else {
      return "HTTP/1.1 302 Found";
    }
  }

  // return the next CU with content
  private CachedUrl getNextCu(CuIterator iter) {
    return iter.hasNext() ? iter.next() : null;
  }

  /**
   * Return true if, interpreting URLs as filenames, dirCu is a directory containing fileCu. Used to
   * exclude directory content from output files, so they can be unpacked by standard utilities
   * (e.g., unzip). Shouldn't be called with equal URLs, but return false in that case, as we
   * wouldn't want to exclude the URL
   */
  boolean isDirOf(CachedUrl dirCu, CachedUrl fileCu) {
    String dir = dirCu.getUrl();
    String file = fileCu.getUrl();
    if (!dir.endsWith("/")) {
      dir = dir + "/";
    }
    return file.startsWith(dir) && !file.equals(dir);
  }

  private void writeFiles() {
    PlatformUtil platutil = PlatformUtil.getInstance();
    CuIterator iter = AuUtil.getCuIterator(au);
    int errs = 0;
    CachedUrl curCu = null;
    CachedUrl nextCu = getNextCu(iter);
    while (nextCu != null) {
      curCu = nextCu;
      nextCu = getNextCu(iter);
      if (excludeDirNodes && nextCu != null && isDirOf(curCu, nextCu)) {
        continue;
      }
      CachedUrl[] cuVersions =
          curCu.getCuVersions(maxVersions > 0 ? maxVersions : Integer.MAX_VALUE);
      for (CachedUrl cu : cuVersions) {
        try {
          log.debug2("Exporting " + cu.getUrl());
          writeCu(cu);
        } catch (IOException e) {
          if (platutil.isDiskFullError(e)) {
            recordError("Disk full, can't write export file.");
            isDiskFull = true;
            return;
          }
        } catch (Exception e) {
          // XXX Would like to differentiate between errors opening or
          // reading CU, which shouldn't cause abort, and errors writing
          // to export file, which should.
          recordError("Unable to copy " + cu.getUrl(), e);
          if (errs++ >= maxErrors) {
            recordError("Aborting after " + errs + " errors");
            return;
          }
        }
      }
    }
  }

  private Set<File> fileSet = new HashSet<File>();
  private List<File> fileList = new ArrayList<File>();

  protected void recordExportFile(File file) {
    if (fileSet.add(file)) {
      fileList.add(file);
    }
  }

  /**
   * Return the list of export files written
   *
   * @return List of File written
   */
  public List<File> getExportFiles() {
    return fileList;
  }

  public interface Factory {
    public Exporter makeExporter(LockssDaemon daemon, ArchivalUnit au);
  }

  static final String WINDOWS_FROM = "?<>:*|\\";
  static final String WINDOWS_TO = "_______";
  static final String MAC_FROM = ":";
  static final String MAC_TO = "_";

  /** Enum of filename translation types */
  public static enum FilenameTranslation {
    XLATE_NONE("None") {
      public String xlate(String s) {
        return s;
      }
    },
    XLATE_WINDOWS("Windows") {
      public String xlate(String s) {
        return StringUtils.replaceChars(s, WINDOWS_FROM, WINDOWS_TO);
      }
    },
    XLATE_MAC("MacOS") {
      public String xlate(String s) {
        return StringUtils.replaceChars(s, MAC_FROM, MAC_TO);
      }
    };

    private final String label;

    FilenameTranslation(String label) {
      this.label = label;
    }

    public String getLabel() {
      return label;
    }

    public abstract String xlate(String s);
  };

  /** Enum of Exporter types, and factories */
  public static enum Type implements Factory {
    ARC_RESOURCE("ARC (content only)") {
      public Exporter makeExporter(LockssDaemon daemon, ArchivalUnit au) {
        return new ArcExporter(daemon, au, false);
      }
    },
    ARC_RESPONSE("ARC (response and content)") {
      public Exporter makeExporter(LockssDaemon daemon, ArchivalUnit au) {
        return new ArcExporter(daemon, au, true);
      }
    },
    WARC_RESOURCE("WARC (content only)") {
      public Exporter makeExporter(LockssDaemon daemon, ArchivalUnit au) {
        return new WarcExporter(daemon, au, false);
      }
    },
    WARC_RESPONSE("WARC (response and content)") {
      public Exporter makeExporter(LockssDaemon daemon, ArchivalUnit au) {
        return new WarcExporter(daemon, au, true);
      }
    },
    ZIP("ZIP") {
      public Exporter makeExporter(LockssDaemon daemon, ArchivalUnit au) {
        return new ZipExporter(daemon, au);
      }
    };

    private final String label;

    Type(String label) {
      this.label = label;
    }

    public abstract Exporter makeExporter(LockssDaemon daemon, ArchivalUnit au);

    public String getLabel() {
      return label;
    }
  };
}
Esempio n. 21
0
/**
 * keeps replica set status has a background thread to ping so it stays current
 *
 * <p>TODO pull config to get priority slave delay tags (when we do it)
 */
public class ReplicaSetStatus {

  static final Logger _rootLogger = Logger.getLogger("com.mongodb.ReplicaSetStatus");
  static final int UNAUTHENTICATED_ERROR_CODE = 10057;

  ReplicaSetStatus(Mongo mongo, List<ServerAddress> initial) {
    _mongo = mongo;
    _all = Collections.synchronizedList(new ArrayList<Node>());
    for (ServerAddress addr : initial) {
      _all.add(new Node(addr));
    }
    _nextResolveTime = System.currentTimeMillis() + inetAddrCacheMS;

    _updater = new Updater();
    _updater.start();
  }

  boolean ready() {
    return _setName != null;
  }

  public String getName() {
    return _setName;
  }

  void _checkClosed() {
    if (_closed) throw new IllegalStateException("ReplicaSetStatus closed");
  }

  /** @return master or null if don't have one */
  ServerAddress getMaster() {
    Node n = getMasterNode();
    if (n == null) return null;
    return n._addr;
  }

  Node getMasterNode() {
    _checkClosed();
    for (int i = 0; i < _all.size(); i++) {
      Node n = _all.get(i);
      if (n.master()) return n;
    }
    return null;
  }

  /** @return a good secondary or null if can't find one */
  ServerAddress getASecondary() {
    _checkClosed();
    Node best = null;
    double badBeforeBest = 0;

    int start = _random.nextInt(_all.size());

    double mybad = 0;

    for (int i = 0; i < _all.size(); i++) {
      Node n = _all.get((start + i) % _all.size());

      if (!n.secondary()) {
        mybad++;
        continue;
      }

      if (best == null) {
        best = n;
        badBeforeBest = mybad;
        mybad = 0;
        continue;
      }

      long diff = best._pingTime - n._pingTime;
      if (diff > slaveAcceptableLatencyMS
          ||
          // this is a complex way to make sure we get a random distribution of slaves
          ((badBeforeBest - mybad) / (_all.size() - 1)) > _random.nextDouble()) {
        best = n;
        badBeforeBest = mybad;
        mybad = 0;
      }
    }

    if (best == null) return null;
    return best._addr;
  }

  class Node {

    Node(ServerAddress addr) {
      _addr = addr;
      _port = new DBPort(addr, null, _mongoOptions);
      _names.add(addr.toString());
    }

    private void updateAddr() {
      try {
        if (_addr.updateInetAddr()) {
          // address changed, need to use new ports
          _port = new DBPort(_addr, null, _mongoOptions);
          _mongo.getConnector().updatePortPool(_addr);
        }
      } catch (UnknownHostException ex) {
        _logger.log(Level.WARNING, null, ex);
      }
    }

    synchronized void update() {
      update(null);
    }

    synchronized void update(Set<Node> seenNodes) {
      try {
        long start = System.currentTimeMillis();
        CommandResult res = _port.runCommand(_mongo.getDB("admin"), _isMasterCmd);
        _lastCheck = System.currentTimeMillis();
        _pingTime = _lastCheck - start;

        if (res == null) {
          _ok = false;
          return;
        }

        _ok = true;
        _isMaster = res.getBoolean("ismaster", false);
        _isSecondary = res.getBoolean("secondary", false);
        _lastPrimarySignal = res.getString("primary");

        if (res.containsField("hosts")) {
          for (Object x : (List) res.get("hosts")) {
            String host = x.toString();
            Node node = _addIfNotHere(host);
            if (node != null && seenNodes != null) seenNodes.add(node);
          }
        }

        if (res.containsField("passives")) {
          for (Object x : (List) res.get("passives")) {
            String host = x.toString();
            Node node = _addIfNotHere(host);
            if (node != null && seenNodes != null) seenNodes.add(node);
          }
        }

        if (_isMaster) {
          // max size was added in 1.8
          if (res.containsField("maxBsonObjectSize"))
            maxBsonObjectSize = ((Integer) res.get("maxBsonObjectSize")).intValue();
          else maxBsonObjectSize = Bytes.MAX_OBJECT_SIZE;
        }

      } catch (MongoException e) {
        Throwable root = e;
        if (e.getCause() != null) root = e.getCause();
        _logger.log(Level.FINE, "node down: " + _addr + " " + root);
        _ok = false;
      } catch (Exception e) {
        _logger.log(Level.SEVERE, "can't update node: " + _addr, e);
        _ok = false;
      }

      if (!_isMaster) return;

      try {
        DB db = _mongo.getDB("local");
        _port.checkAuth(db);
        DBObject config = _port.findOne(db, "system.replset", new BasicDBObject());
        if (config == null) {
          // probably a replica pair
          // TODO: add this in when pairs are really gone
          // _logger.log( Level.SEVERE , "no replset config!" );
        } else if (config.get("$err") != null
            && UNAUTHENTICATED_ERROR_CODE == (Integer) config.get("code")) {
          _logger.log(
              Level.WARNING,
              "Replica Set updater cannot get results, call authenticate on 'local' or 'admin' db");
        } else {

          String setName = config.get("_id").toString();
          if (_setName == null) {
            _setName = setName;
            _logger = Logger.getLogger(_rootLogger.getName() + "." + setName);
          } else if (!_setName.equals(setName)) {
            _logger.log(Level.SEVERE, "mis match set name old: " + _setName + " new: " + setName);
            return;
          }

          // TODO: look at members
        }
      } catch (MongoException e) {
        if (_setName != null) {
          // this probably means the master is busy, so going to ignore
        } else {
          _logger.log(Level.SEVERE, "can't get initial config from node: " + _addr, e);
        }
      } catch (Exception e) {
        _logger.log(Level.SEVERE, "unexpected error getting config from node: " + _addr, e);
      }
    }

    public boolean master() {
      return _ok && _isMaster;
    }

    public boolean secondary() {
      return _ok && _isSecondary;
    }

    public String toString() {
      StringBuilder buf = new StringBuilder();
      buf.append("Replica Set Node: ").append(_addr).append("\n");
      buf.append("\t ok \t").append(_ok).append("\n");
      buf.append("\t ping \t").append(_pingTime).append("\n");

      buf.append("\t master \t").append(_isMaster).append("\n");
      buf.append("\t secondary \t").append(_isSecondary).append("\n");

      buf.append("\t priority \t").append(_priority).append("\n");

      return buf.toString();
    }

    final ServerAddress _addr;
    final Set<String> _names = Collections.synchronizedSet(new HashSet<String>());
    DBPort _port; // we have our own port so we can set different socket options and don't have to
    // owrry about the pool

    boolean _ok = false;
    long _lastCheck = 0;
    long _pingTime = 0;

    boolean _isMaster = false;
    boolean _isSecondary = false;

    double _priority = 0;
  }

  class Updater extends Thread {
    Updater() {
      super("ReplicaSetStatus:Updater");
      setDaemon(true);
    }

    public void run() {
      while (!_closed) {
        try {
          updateAll();

          long now = System.currentTimeMillis();
          if (inetAddrCacheMS > 0 && _nextResolveTime < now) {
            _nextResolveTime = now + inetAddrCacheMS;
            for (Node node : _all) {
              node.updateAddr();
            }
          }

          // force check on master
          // otherwise master change may go unnoticed for a while if no write concern
          _mongo.getConnector().checkMaster(true, false);
        } catch (Exception e) {
          _logger.log(Level.WARNING, "couldn't do update pass", e);
        }

        try {
          Thread.sleep(updaterIntervalMS);
        } catch (InterruptedException ie) {
        }
      }
    }
  }

  Node ensureMaster() {
    Node n = getMasterNode();
    if (n != null) {
      n.update();
      if (n._isMaster) return n;
    }

    if (_lastPrimarySignal != null) {
      n = findNode(_lastPrimarySignal);
      n.update();
      if (n._isMaster) return n;
    }

    updateAll();
    return getMasterNode();
  }

  synchronized void updateAll() {
    HashSet<Node> seenNodes = new HashSet<Node>();
    for (int i = 0; i < _all.size(); i++) {
      Node n = _all.get(i);
      n.update(seenNodes);
    }

    if (!seenNodes.isEmpty()) {
      // not empty, means that at least 1 server gave node list
      // remove unused hosts
      Iterator<Node> it = _all.iterator();
      while (it.hasNext()) {
        if (!seenNodes.contains(it.next())) it.remove();
      }
    }
  }

  List<ServerAddress> getServerAddressList() {
    List<ServerAddress> addrs = new ArrayList<ServerAddress>();
    for (Node node : _all) addrs.add(node._addr);
    return addrs;
  }

  Node _addIfNotHere(String host) {
    Node n = findNode(host);
    if (n == null) {
      try {
        n = new Node(new ServerAddress(host));
        _all.add(n);
      } catch (UnknownHostException un) {
        _logger.log(Level.WARNING, "couldn't resolve host [" + host + "]");
      }
    }
    return n;
  }

  Node findNode(String host) {
    for (int i = 0; i < _all.size(); i++) if (_all.get(i)._names.contains(host)) return _all.get(i);

    ServerAddress addr = null;
    try {
      addr = new ServerAddress(host);
    } catch (UnknownHostException un) {
      _logger.log(Level.WARNING, "couldn't resolve host [" + host + "]");
      return null;
    }

    for (int i = 0; i < _all.size(); i++) {
      if (_all.get(i)._addr.equals(addr)) {
        _all.get(i)._names.add(host);
        return _all.get(i);
      }
    }

    return null;
  }

  void printStatus() {
    for (int i = 0; i < _all.size(); i++) System.out.println(_all.get(i));
  }

  void close() {
    _closed = true;
  }

  /**
   * Gets the maximum size for a BSON object supported by the current master server. Note that this
   * value may change over time depending on which server is master.
   *
   * @return the maximum size, or 0 if not obtained from servers yet.
   */
  public int getMaxBsonObjectSize() {
    return maxBsonObjectSize;
  }

  final List<Node> _all;
  Updater _updater;
  Mongo _mongo;
  String _setName = null; // null until init
  int maxBsonObjectSize = 0;
  Logger _logger = _rootLogger; // will get changed to use set name once its found

  String _lastPrimarySignal;
  boolean _closed = false;

  final Random _random = new Random();
  long _nextResolveTime;

  static int updaterIntervalMS;
  static int slaveAcceptableLatencyMS;
  static int inetAddrCacheMS;

  static final MongoOptions _mongoOptions = new MongoOptions();

  static {
    updaterIntervalMS =
        Integer.parseInt(System.getProperty("com.mongodb.updaterIntervalMS", "5000"));
    slaveAcceptableLatencyMS =
        Integer.parseInt(System.getProperty("com.mongodb.slaveAcceptableLatencyMS", "15"));
    inetAddrCacheMS = Integer.parseInt(System.getProperty("com.mongodb.inetAddrCacheMS", "300000"));
    _mongoOptions.connectTimeout =
        Integer.parseInt(System.getProperty("com.mongodb.updaterConnectTimeoutMS", "20000"));
    _mongoOptions.socketTimeout =
        Integer.parseInt(System.getProperty("com.mongodb.updaterSocketTimeoutMS", "20000"));
  }

  static final DBObject _isMasterCmd = new BasicDBObject("ismaster", 1);

  public static void main(String args[]) throws Exception {
    List<ServerAddress> addrs = new LinkedList<ServerAddress>();
    addrs.add(new ServerAddress("127.0.0.1", 27017));
    addrs.add(new ServerAddress("127.0.0.1", 27018));

    Mongo m = new Mongo(addrs);

    ReplicaSetStatus status = new ReplicaSetStatus(m, addrs);
    System.out.println(status.ensureMaster()._addr);

    while (true) {
      System.out.println(status.ready());
      if (status.ready()) {
        status.printStatus();
        System.out.println(
            "master: " + status.getMaster() + "\t secondary: " + status.getASecondary());
      }
      System.out.println("-----------------------");
      Thread.sleep(5000);
    }
  }
}
Esempio n. 22
0
    synchronized void update(Set<Node> seenNodes) {
      try {
        long start = System.currentTimeMillis();
        CommandResult res = _port.runCommand(_mongo.getDB("admin"), _isMasterCmd);
        _lastCheck = System.currentTimeMillis();
        _pingTime = _lastCheck - start;

        if (res == null) {
          _ok = false;
          return;
        }

        _ok = true;
        _isMaster = res.getBoolean("ismaster", false);
        _isSecondary = res.getBoolean("secondary", false);
        _lastPrimarySignal = res.getString("primary");

        if (res.containsField("hosts")) {
          for (Object x : (List) res.get("hosts")) {
            String host = x.toString();
            Node node = _addIfNotHere(host);
            if (node != null && seenNodes != null) seenNodes.add(node);
          }
        }

        if (res.containsField("passives")) {
          for (Object x : (List) res.get("passives")) {
            String host = x.toString();
            Node node = _addIfNotHere(host);
            if (node != null && seenNodes != null) seenNodes.add(node);
          }
        }

        if (_isMaster) {
          // max size was added in 1.8
          if (res.containsField("maxBsonObjectSize"))
            maxBsonObjectSize = ((Integer) res.get("maxBsonObjectSize")).intValue();
          else maxBsonObjectSize = Bytes.MAX_OBJECT_SIZE;
        }

      } catch (MongoException e) {
        Throwable root = e;
        if (e.getCause() != null) root = e.getCause();
        _logger.log(Level.FINE, "node down: " + _addr + " " + root);
        _ok = false;
      } catch (Exception e) {
        _logger.log(Level.SEVERE, "can't update node: " + _addr, e);
        _ok = false;
      }

      if (!_isMaster) return;

      try {
        DB db = _mongo.getDB("local");
        _port.checkAuth(db);
        DBObject config = _port.findOne(db, "system.replset", new BasicDBObject());
        if (config == null) {
          // probably a replica pair
          // TODO: add this in when pairs are really gone
          // _logger.log( Level.SEVERE , "no replset config!" );
        } else if (config.get("$err") != null
            && UNAUTHENTICATED_ERROR_CODE == (Integer) config.get("code")) {
          _logger.log(
              Level.WARNING,
              "Replica Set updater cannot get results, call authenticate on 'local' or 'admin' db");
        } else {

          String setName = config.get("_id").toString();
          if (_setName == null) {
            _setName = setName;
            _logger = Logger.getLogger(_rootLogger.getName() + "." + setName);
          } else if (!_setName.equals(setName)) {
            _logger.log(Level.SEVERE, "mis match set name old: " + _setName + " new: " + setName);
            return;
          }

          // TODO: look at members
        }
      } catch (MongoException e) {
        if (_setName != null) {
          // this probably means the master is busy, so going to ignore
        } else {
          _logger.log(Level.SEVERE, "can't get initial config from node: " + _addr, e);
        }
      } catch (Exception e) {
        _logger.log(Level.SEVERE, "unexpected error getting config from node: " + _addr, e);
      }
    }
Esempio n. 23
0
/**
 * DHCP transaction class.
 *
 * @author Sebastien Vincent
 */
public class DHCPTransaction {
  /** Logger. */
  private final Logger logger = Logger.getLogger(DHCPTransaction.class);

  /** Number of retransmission before giving up. */
  private int maxRetransmit = 2;

  /** Current number of retransmission. */
  private int nbRetransmit = 0;

  /**
   * Fix interval for retransmission. This final interval will be obtained by adding a random number
   * between [-1, 1].
   */
  private int interval = 2;

  /** The Timer that will trigger retransmission. */
  private Timer timer = null;

  /** The DHCP packet content. */
  private final DatagramPacket message;

  /** The socket that will be used to retransmit DHCP packet. */
  private final DatagramSocket sock;

  /**
   * Constructor.
   *
   * @param sock UDP socket
   * @param message DHCP packet content
   */
  public DHCPTransaction(DatagramSocket sock, DatagramPacket message) {
    this.sock = sock;
    this.message = message;
    this.timer = new Timer();
  }

  /**
   * Schedule a timer for retransmission.
   *
   * @throws Exception if message cannot be sent on the socket
   */
  public void schedule() throws Exception {
    sock.send(message);

    /* choose a random between [-1, 1] */
    int rand = new Random().nextInt(2) - 1;
    timer.schedule(new RetransmissionHandler(), (interval + rand) * 1000);
  }

  /** Cancel the transaction (i.e stop retransmission). */
  public void cancel() {
    timer.cancel();
  }

  /**
   * Set the maximum retransmission for a transaction.
   *
   * @param maxRetransmit maximum retransmission for this transaction
   */
  public void setMaxRetransmit(int maxRetransmit) {
    this.maxRetransmit = maxRetransmit;
  }

  /**
   * Set the fixed interval for retransmission.
   *
   * @param interval interval to set
   */
  public void setInterval(int interval) {
    this.interval = interval;
  }

  /**
   * A <tt>TimerTask</tt> that will handle retransmission of DHCP INFORM.
   *
   * @author Sebastien Vincent
   */
  private class RetransmissionHandler extends TimerTask {
    /** Thread entry point. */
    public void run() {
      int rand = new Random().nextInt(2) - 1;

      try {
        sock.send(message);
      } catch (Exception e) {
        logger.warn("Failed to send DHCP packet", e);
      }

      nbRetransmit++;
      if (nbRetransmit < maxRetransmit) {
        timer.schedule(new RetransmissionHandler(), (interval + rand) * 1000);
      }
    }
  };
}
/**
 * A default implementation of the <tt>ResourceManagementService</tt>.
 *
 * @author Damian Minkov
 * @author Yana Stamcheva
 * @author Lubomir Marinov
 * @author Adam Netocny
 */
public class ResourceManagementServiceImpl extends AbstractResourcesService {
  /**
   * The <tt>Logger</tt> used by the <tt>ResourceManagementServiceImpl</tt> class and its instances
   * for logging output.
   */
  private static final Logger logger = Logger.getLogger(ResourceManagementServiceImpl.class);

  /** UI Service reference. */
  private UIService uiService = null;

  /** Initializes already registered default resource packs. */
  ResourceManagementServiceImpl() {
    super(ResourceManagementActivator.bundleContext);

    UIService serv = getUIService();
    if (serv != null) {
      serv.repaintUI();
    }
  }

  /**
   * Returns the <tt>UIService</tt> obtained from the bundle context.
   *
   * @return the <tt>UIService</tt> obtained from the bundle context
   */
  private UIService getUIService() {
    if (uiService == null) {
      uiService =
          ServiceUtils.getService(ResourceManagementActivator.bundleContext, UIService.class);
    }
    return uiService;
  }

  /**
   * Gets a reference to the <tt>UIService</tt> when this one is registered.
   *
   * @param event the <tt>ServiceEvent</tt> that has notified us
   */
  @Override
  public void serviceChanged(ServiceEvent event) {
    super.serviceChanged(event);

    Object sService =
        ResourceManagementActivator.bundleContext.getService(event.getServiceReference());

    if (sService instanceof UIService
        && uiService == null
        && event.getType() == ServiceEvent.REGISTERED) {
      uiService = (UIService) sService;
      uiService.repaintUI();
    } else if (sService instanceof UIService && event.getType() == ServiceEvent.UNREGISTERING) {
      if (uiService != null && uiService.equals(sService)) {
        uiService = null;
      }
    }
  }

  /** Repaints the whole UI when a skin pack has changed. */
  @Override
  protected void onSkinPackChanged() {
    UIService serv = getUIService();
    if (serv != null) {
      serv.repaintUI();
    }
  }

  /**
   * Returns the int representation of the color corresponding to the given key.
   *
   * @param key The key of the color in the colors properties file.
   * @return the int representation of the color corresponding to the given key.
   */
  public int getColor(String key) {
    String res = getColorResources().get(key);

    if (res == null) {
      logger.error("Missing color resource for key: " + key);

      return 0xFFFFFF;
    } else return Integer.parseInt(res, 16);
  }

  /**
   * Returns the string representation of the color corresponding to the given key.
   *
   * @param key The key of the color in the colors properties file.
   * @return the string representation of the color corresponding to the given key.
   */
  public String getColorString(String key) {
    String res = getColorResources().get(key);

    if (res == null) {
      logger.error("Missing color resource for key: " + key);

      return "0xFFFFFF";
    } else return res;
  }

  /**
   * Returns the <tt>InputStream</tt> of the image corresponding to the given path.
   *
   * @param path The path to the image file.
   * @return the <tt>InputStream</tt> of the image corresponding to the given path.
   */
  public InputStream getImageInputStreamForPath(String path) {
    SkinPack skinPack = getSkinPack();
    if (skinPack != null) {
      if (skinPack.getClass().getClassLoader().getResourceAsStream(path) != null) {
        return skinPack.getClass().getClassLoader().getResourceAsStream(path);
      }
    }

    ImagePack imagePack = getImagePack();
    if (path != null && imagePack != null)
      return imagePack.getClass().getClassLoader().getResourceAsStream(path);

    return null;
  }

  /**
   * Returns the <tt>InputStream</tt> of the image corresponding to the given key.
   *
   * @param streamKey The identifier of the image in the resource properties file.
   * @return the <tt>InputStream</tt> of the image corresponding to the given key.
   */
  public InputStream getImageInputStream(String streamKey) {
    String path = getImagePath(streamKey);

    if (path == null || path.length() == 0) {
      logger.warn("Missing resource for key: " + streamKey);
      return null;
    }

    return getImageInputStreamForPath(path);
  }

  /**
   * Returns the <tt>URL</tt> of the image corresponding to the given key.
   *
   * @param urlKey The identifier of the image in the resource properties file.
   * @return the <tt>URL</tt> of the image corresponding to the given key
   */
  public URL getImageURL(String urlKey) {
    String path = getImagePath(urlKey);

    if (path == null || path.length() == 0) {
      if (logger.isInfoEnabled()) logger.info("Missing resource for key: " + urlKey);
      return null;
    }
    return getImageURLForPath(path);
  }

  /**
   * Returns the <tt>URL</tt> of the image corresponding to the given path.
   *
   * @param path The path to the given image file.
   * @return the <tt>URL</tt> of the image corresponding to the given path.
   */
  public URL getImageURLForPath(String path) {
    SkinPack skinPack = getSkinPack();
    if (skinPack != null) {
      if (skinPack.getClass().getClassLoader().getResource(path) != null) {
        return skinPack.getClass().getClassLoader().getResource(path);
      }
    }

    ImagePack imagePack = getImagePack();
    return imagePack.getClass().getClassLoader().getResource(path);
  }

  /**
   * Returns the <tt>URL</tt> of the sound corresponding to the given property key.
   *
   * @return the <tt>URL</tt> of the sound corresponding to the given property key.
   */
  public URL getSoundURL(String urlKey) {
    String path = getSoundPath(urlKey);

    if (path == null || path.length() == 0) {
      logger.warn("Missing resource for key: " + urlKey);
      return null;
    }
    return getSoundURLForPath(path);
  }

  /**
   * Returns the <tt>URL</tt> of the sound corresponding to the given path.
   *
   * @param path the path, for which we're looking for a sound URL
   * @return the <tt>URL</tt> of the sound corresponding to the given path.
   */
  public URL getSoundURLForPath(String path) {
    return getSoundPack().getClass().getClassLoader().getResource(path);
  }

  /**
   * Loads an image from a given image identifier.
   *
   * @param imageID The identifier of the image.
   * @return The image for the given identifier.
   */
  @Override
  public byte[] getImageInBytes(String imageID) {
    InputStream in = getImageInputStream(imageID);

    if (in == null) return null;

    byte[] image = null;

    try {
      image = new byte[in.available()];
      in.read(image);
    } catch (IOException e) {
      logger.error("Failed to load image:" + imageID, e);
    }

    return image;
  }

  /**
   * Loads an image from a given image identifier.
   *
   * @param imageID The identifier of the image.
   * @return The image for the given identifier.
   */
  @Override
  public ImageIcon getImage(String imageID) {
    URL imageURL = getImageURL(imageID);

    return (imageURL == null) ? null : new ImageIcon(imageURL);
  }

  /**
   * Builds a new skin bundle from the zip file content.
   *
   * @param zipFile Zip file with skin information.
   * @return <tt>File</tt> for the bundle.
   * @throws Exception When something goes wrong.
   */
  public File prepareSkinBundleFromZip(File zipFile) throws Exception {
    return SkinJarBuilder.createBundleFromZip(zipFile, getImagePack());
  }

  /**
   * Gets the specified setting from the config service if present, otherwise from the embedded
   * resources (resources/config/defaults.properties).
   *
   * @param key The setting to lookup.
   * @return The setting for the key or {@code null} if not found.
   */
  @Override
  public String getSettingsString(String key) {
    Object configValue = ResourceManagementActivator.getConfigService().getProperty(key);
    if (configValue == null) {
      configValue = super.getSettingsString(key);
    }

    return configValue == null ? null : configValue.toString();
  }
}
/**
 * This implementation of the Network Address Manager allows you to intelligently retrieve the
 * address of your localhost according to preferences specified in a number of properties like: <br>
 * net.java.sip.communicator.STUN_SERVER_ADDRESS - the address of the stun server to use for NAT
 * traversal <br>
 * net.java.sip.communicator.STUN_SERVER_PORT - the port of the stun server to use for NAT traversal
 * <br>
 * java.net.preferIPv6Addresses - a system property specifying weather ipv6 addresses are to be
 * preferred in address resolution (default is false for backward compatibility) <br>
 * net.java.sip.communicator.common.PREFERRED_NETWORK_ADDRESS - the address that the user would like
 * to use. (If this is a valid address it will be returned in getLocalhost() calls) <br>
 * net.java.sip.communicator.common.PREFERRED_NETWORK_INTERFACE - the network interface that the
 * user would like to use for fommunication (addresses belonging to that interface will be prefered
 * when selecting a localhost address)
 *
 * @todo further explain the way the service works. explain address selection algorithms and
 *     priorities.
 * @author Emil Ivov
 */
public class NetworkAddressManagerServiceImpl
    implements NetworkAddressManagerService, VetoableChangeListener {
  private static Logger logger = Logger.getLogger(NetworkAddressManagerServiceImpl.class);

  /** The name of the property containing the stun server address. */
  private static final String PROP_STUN_SERVER_ADDRESS =
      "net.java.sip.communicator.impl.netaddr.STUN_SERVER_ADDRESS";
  /** The port number of the stun server to use for NAT traversal */
  private static final String PROP_STUN_SERVER_PORT =
      "net.java.sip.communicator.impl.netaddr.STUN_SERVER_PORT";

  /** A stun4j address resolver */
  private SimpleAddressDetector detector = null;

  /** Specifies whether or not STUN should be used for NAT traversal */
  private boolean useStun = false;

  /** The address of the stun server that we're currently using. */
  private StunAddress stunServerAddress = null;

  /**
   * The socket that we use for dummy connections during selection of a local address that has to be
   * used when communicating with a specific location.
   */
  DatagramSocket localHostFinderSocket = null;

  /**
   * A random (unused)local port to use when trying to select a local host address to use when
   * sending messages to a specific destination.
   */
  private static final int RANDOM_ADDR_DISC_PORT = 55721;

  /**
   * The prefix used for Dynamic Configuration of IPv4 Link-Local Addresses. <br>
   * {@link http://ietf.org/rfc/rfc3927.txt}
   */
  private static final String DYNAMIC_CONF_FOR_IPV4_ADDR_PREFIX = "169.254";

  /**
   * The name of the property containing the number of binds that we should should execute in case a
   * port is already bound to (each retry would be on a new random port).
   */
  public static final String BIND_RETRIES_PROPERTY_NAME =
      "net.java.sip.communicator.service.netaddr.BIND_RETRIES";

  /** Default STUN server address. */
  public static final String DEFAULT_STUN_SERVER_ADDRESS = "stun.iptel.org";

  /** Default STUN server port. */
  public static final int DEFAULT_STUN_SERVER_PORT = 3478;

  /**
   * Initializes this network address manager service implementation and starts all
   * processes/threads associated with this address manager, such as a stun firewall/nat detector,
   * keep alive threads, binding lifetime discovery threads and etc. The method may also be used
   * after a call to stop() as a reinitialization technique.
   */
  public void start() {
    // init stun
    String stunAddressStr = null;
    int port = -1;
    stunAddressStr = NetaddrActivator.getConfigurationService().getString(PROP_STUN_SERVER_ADDRESS);
    String portStr = NetaddrActivator.getConfigurationService().getString(PROP_STUN_SERVER_PORT);

    this.localHostFinderSocket = initRandomPortSocket();

    if (stunAddressStr == null || portStr == null) {
      useStun = false;
      // we use the default stun server address only for chosing a public
      // route and not for stun queries.
      stunServerAddress = new StunAddress(DEFAULT_STUN_SERVER_ADDRESS, DEFAULT_STUN_SERVER_PORT);
      logger.info(
          "Stun server address("
              + stunAddressStr
              + ")/port("
              + portStr
              + ") not set (or invalid). Disabling STUN.");

    } else {
      try {
        port = Integer.valueOf(portStr).intValue();
      } catch (NumberFormatException ex) {
        logger.error(portStr + " is not a valid port number. " + "Defaulting to 3478", ex);
        port = 3478;
      }

      stunServerAddress = new StunAddress(stunAddressStr, port);
      detector = new SimpleAddressDetector(stunServerAddress);

      if (logger.isDebugEnabled()) {
        logger.debug(
            "Created a STUN Address detector for the following "
                + "STUN server: "
                + stunAddressStr
                + ":"
                + port);
      }
      detector.start();
      logger.debug("STUN server detector started;");

      // make sure that someone doesn't set invalid stun address and port
      NetaddrActivator.getConfigurationService()
          .addVetoableChangeListener(PROP_STUN_SERVER_ADDRESS, this);
      NetaddrActivator.getConfigurationService()
          .addVetoableChangeListener(PROP_STUN_SERVER_PORT, this);

      // now start a thread query to the stun server and only set the
      // useStun flag to true if it succeeds.
      launchStunServerTest();
    }
  }

  /**
   * Kills all threads/processes lauched by this thread and prepares it for shutdown. You may use
   * this method as a reinitialization technique ( you'll have to call start afterwards)
   */
  public void stop() {
    try {
      try {
        detector.shutDown();
      } catch (Exception ex) {
        logger.debug("Failed to properly shutdown a stun detector: " + ex.getMessage());
      }
      detector = null;
      useStun = false;

      // remove the listeners
      NetaddrActivator.getConfigurationService()
          .removeVetoableChangeListener(PROP_STUN_SERVER_ADDRESS, this);

      NetaddrActivator.getConfigurationService()
          .removeVetoableChangeListener(PROP_STUN_SERVER_PORT, this);

    } finally {
      logger.logExit();
    }
  }

  /**
   * Returns an InetAddress instance that represents the localhost, and that a socket can bind upon
   * or distribute to peers as a contact address.
   *
   * @param intendedDestination the destination that we'd like to use the localhost address with.
   * @return an InetAddress instance representing the local host, and that a socket can bind upon or
   *     distribute to peers as a contact address.
   */
  public synchronized InetAddress getLocalHost(InetAddress intendedDestination) {
    // no point in making sure that the localHostFinderSocket is initialized.
    // better let it through a NullPointerException.
    InetAddress localHost = null;
    localHostFinderSocket.connect(intendedDestination, this.RANDOM_ADDR_DISC_PORT);
    localHost = localHostFinderSocket.getLocalAddress();
    localHostFinderSocket.disconnect();
    // windows socket implementations return the any address so we need to
    // find something else here ... InetAddress.getLocalHost seems to work
    // better on windows so lets hope it'll do the trick.
    if (localHost.isAnyLocalAddress()) {
      try {
        // all that's inside the if is an ugly IPv6 hack
        // (good ol' IPv6 - always causing more problems than it solves.)
        if (intendedDestination instanceof Inet6Address) {
          // return the first globally routable ipv6 address we find
          // on the machine (and hope it's a good one)
          Enumeration interfaces = NetworkInterface.getNetworkInterfaces();

          while (interfaces.hasMoreElements()) {
            NetworkInterface iface = (NetworkInterface) interfaces.nextElement();
            Enumeration addresses = iface.getInetAddresses();
            while (addresses.hasMoreElements()) {
              InetAddress address = (InetAddress) addresses.nextElement();
              if (address instanceof Inet6Address) {
                if (!address.isAnyLocalAddress()
                    && !address.isLinkLocalAddress()
                    && !address.isSiteLocalAddress()
                    && !address.isLoopbackAddress()) {
                  return address;
                }
              }
            }
          }
        } else localHost = InetAddress.getLocalHost();
        /** @todo test on windows for ipv6 cases */
      } catch (Exception ex) {
        // sigh ... ok return 0.0.0.0
        logger.warn("Failed to get localhost ", ex);
      }
    }

    return localHost;
  }

  /**
   * The method queries a Stun server for a binding for the specified port.
   *
   * @param port the port to resolve (the stun message gets sent trhough that port)
   * @return StunAddress the address returned by the stun server or null if an error occurred or no
   *     address was returned
   * @throws IOException if an error occurs while stun4j is using sockets.
   * @throws BindException if the port is already in use.
   */
  private StunAddress queryStunServer(int port) throws IOException, BindException {
    StunAddress mappedAddress = null;
    if (detector != null && useStun) {
      mappedAddress = detector.getMappingFor(port);
      if (logger.isDebugEnabled())
        logger.debug(
            "For port:"
                + port
                + "a Stun server returned the "
                + "following mapping ["
                + mappedAddress);
    }
    return mappedAddress;
  }

  /**
   * The method queries a Stun server for a binding for the port and address that <tt>sock</tt> is
   * bound on.
   *
   * @param sock the socket whose port and address we'dlike to resolve (the stun message gets sent
   *     trhough that socket)
   * @return StunAddress the address returned by the stun server or null if an error occurred or no
   *     address was returned
   * @throws IOException if an error occurs while stun4j is using sockets.
   * @throws BindException if the port is already in use.
   */
  private StunAddress queryStunServer(DatagramSocket sock) throws IOException, BindException {
    StunAddress mappedAddress = null;
    if (detector != null && useStun) {
      mappedAddress = detector.getMappingFor(sock);
      if (logger.isTraceEnabled()) {
        logger.trace(
            "For socket with address "
                + sock.getLocalAddress().getHostAddress()
                + " and port "
                + sock.getLocalPort()
                + " the stun server returned the "
                + "following mapping ["
                + mappedAddress
                + "]");
      }
    }
    return mappedAddress;
  }

  /**
   * Tries to obtain a mapped/public address for the specified port (possibly by executing a STUN
   * query).
   *
   * @param dst the destination that we'd like to use this address with.
   * @param port the port whose mapping we are interested in.
   * @return a public address corresponding to the specified port or null if all attempts to
   *     retrieve such an address have failed.
   * @throws IOException if an error occurs while stun4j is using sockets.
   * @throws BindException if the port is already in use.
   */
  public InetSocketAddress getPublicAddressFor(InetAddress dst, int port)
      throws IOException, BindException {
    if (!useStun || (dst instanceof Inet6Address)) {
      logger.debug(
          "Stun is disabled for destination "
              + dst
              + ", skipping mapped address recovery (useStun="
              + useStun
              + ", IPv6@="
              + (dst instanceof Inet6Address)
              + ").");
      // we'll still try to bind though so that we could notify the caller
      // if the port has been taken already.
      DatagramSocket bindTestSocket = new DatagramSocket(port);
      bindTestSocket.close();

      // if we're here then the port was free.
      return new InetSocketAddress(getLocalHost(dst), port);
    }
    StunAddress mappedAddress = queryStunServer(port);
    InetSocketAddress result = null;
    if (mappedAddress != null) result = mappedAddress.getSocketAddress();
    else {
      // Apparently STUN failed. Let's try to temporarily disble it
      // and use algorithms in getLocalHost(). ... We should probably
      // eveng think about completely disabling stun, and not only
      // temporarily.
      // Bug report - John J. Barton - IBM
      InetAddress localHost = getLocalHost(dst);
      result = new InetSocketAddress(localHost, port);
    }
    if (logger.isDebugEnabled())
      logger.debug("Returning mapping for port:" + port + " as follows: " + result);
    return result;
  }

  /**
   * Tries to obtain a mapped/public address for the specified port (possibly by executing a STUN
   * query).
   *
   * @param port the port whose mapping we are interested in.
   * @return a public address corresponding to the specified port or null if all attempts to
   *     retrieve such an address have failed.
   * @throws IOException if an error occurs while stun4j is using sockets.
   * @throws BindException if the port is already in use.
   */
  public InetSocketAddress getPublicAddressFor(int port) throws IOException, BindException {
    return getPublicAddressFor(this.stunServerAddress.getSocketAddress().getAddress(), port);
  }

  /**
   * This method gets called when a bound property is changed.
   *
   * @param evt A PropertyChangeEvent object describing the event source and the property that has
   *     changed.
   */
  public void propertyChange(PropertyChangeEvent evt) {
    // there's no point in implementing this method as we have no way of
    // knowing whether the current property change event is the only event
    // we're going to get or whether another one is going to follow..

    // in the case of a STUN_SERVER_ADDRESS property change for example
    // there's no way of knowing whether a STUN_SERVER_PORT property change
    // will follow or not.

    // Reinitializaion will therefore only happen if the reinitialize()
    // method is called.
  }

  /**
   * This method gets called when a property we're interested in is about to change. In case we
   * don't like the new value we throw a PropertyVetoException to prevent the actual change from
   * happening.
   *
   * @param evt a <tt>PropertyChangeEvent</tt> object describing the event source and the property
   *     that will change.
   * @exception PropertyVetoException if we don't want the change to happen.
   */
  public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
    if (evt.getPropertyName().equals(PROP_STUN_SERVER_ADDRESS)) {
      // make sure that we have a valid fqdn or ip address.

      // null or empty port is ok since it implies turning STUN off.
      if (evt.getNewValue() == null) return;

      String host = evt.getNewValue().toString();
      if (host.trim().length() == 0) return;

      boolean ipv6Expected = false;
      if (host.charAt(0) == '[') {
        // This is supposed to be an IPv6 litteral
        if (host.length() > 2 && host.charAt(host.length() - 1) == ']') {
          host = host.substring(1, host.length() - 1);
          ipv6Expected = true;
        } else {
          // This was supposed to be a IPv6 address, but it's not!
          throw new PropertyVetoException("Invalid address string" + host, evt);
        }
      }

      for (int i = 0; i < host.length(); i++) {
        char c = host.charAt(i);
        if (Character.isLetterOrDigit(c)) continue;

        if ((c != '.' && c != ':') || (c == '.' && ipv6Expected) || (c == ':' && !ipv6Expected))
          throw new PropertyVetoException(host + " is not a valid address nor host name", evt);
      }

    } // is prop_stun_server_address
    else if (evt.getPropertyName().equals(PROP_STUN_SERVER_PORT)) {

      // null or empty port is ok since it implies turning STUN off.
      if (evt.getNewValue() == null) return;

      String port = evt.getNewValue().toString();
      if (port.trim().length() == 0) return;

      try {
        Integer.valueOf(evt.getNewValue().toString());
      } catch (NumberFormatException ex) {
        throw new PropertyVetoException(port + " is not a valid port! " + ex.getMessage(), evt);
      }
    }
  }

  /**
   * Initializes and binds a socket that on a random port number. The method would try to bind on a
   * random port and retry 5 times until a free port is found.
   *
   * @return the socket that we have initialized on a randomport number.
   */
  private DatagramSocket initRandomPortSocket() {
    DatagramSocket resultSocket = null;
    String bindRetriesStr =
        NetaddrActivator.getConfigurationService().getString(BIND_RETRIES_PROPERTY_NAME);

    int bindRetries = 5;

    if (bindRetriesStr != null) {
      try {
        bindRetries = Integer.parseInt(bindRetriesStr);
      } catch (NumberFormatException ex) {
        logger.error(
            bindRetriesStr
                + " does not appear to be an integer. "
                + "Defaulting port bind retries to "
                + bindRetries,
            ex);
      }
    }

    int currentlyTriedPort = NetworkUtils.getRandomPortNumber();

    // we'll first try to bind to a random port. if this fails we'll try
    // again (bindRetries times in all) until we find a free local port.
    for (int i = 0; i < bindRetries; i++) {
      try {
        resultSocket = new DatagramSocket(currentlyTriedPort);
        // we succeeded - break so that we don't try to bind again
        break;
      } catch (SocketException exc) {
        if (exc.getMessage().indexOf("Address already in use") == -1) {
          logger.fatal(
              "An exception occurred while trying to create" + "a local host discovery socket.",
              exc);
          resultSocket = null;
          return null;
        }
        // port seems to be taken. try another one.
        logger.debug("Port " + currentlyTriedPort + " seems in use.");
        currentlyTriedPort = NetworkUtils.getRandomPortNumber();
        logger.debug("Retrying bind on port " + currentlyTriedPort);
      }
    }

    return resultSocket;
  }

  /**
   * Runs a test query agains the stun server. If it works we set useStun to true, otherwise we set
   * it to false.
   */
  private void launchStunServerTest() {
    Thread stunServerTestThread =
        new Thread("StunServerTestThread") {
          public void run() {
            DatagramSocket randomSocket = initRandomPortSocket();
            try {
              StunAddress stunAddress = detector.getMappingFor(randomSocket);
              randomSocket.disconnect();
              if (stunAddress != null) {
                useStun = true;
                logger.trace(
                    "StunServer check succeeded for server: "
                        + detector.getServerAddress()
                        + " and local port: "
                        + randomSocket.getLocalPort());
              } else {
                useStun = false;
                logger.trace(
                    "StunServer check failed for server: "
                        + detector.getServerAddress()
                        + " and local port: "
                        + randomSocket.getLocalPort()
                        + ". No address returned by server.");
              }
            } catch (Throwable ex) {
              logger.error(
                  "Failed to run a stun query against " + "server :" + detector.getServerAddress(),
                  ex);
              if (randomSocket.isConnected()) randomSocket.disconnect();
              useStun = false;
            }
          }
        };
    stunServerTestThread.setDaemon(true);
    stunServerTestThread.start();
  }
}
Esempio n. 26
0
/** Implements the "get status table" command */
public class AddAuConfigure extends AuActivityBase {

  private static String NAME = "AddAuConfigure";
  private static Logger log = Logger.getLogger(NAME);

  public AddAuConfigure() {
    super();
  }

  /**
   * Populate the response body
   *
   * @return true on success
   */
  public boolean doRemoteSetupAndVerification() throws IOException {

    /*
     * Stop if any required parameters are missing (error)
     */
    if (!verifyMinimumParameters()) {
      throw new ResponseException("Missing required parameters");
    }
    /*
     * Initial page setup
     */
    return commandSetup();
  }

  /**
   * Populate the response body
   *
   * @return true on success
   */
  public boolean doCommand() throws IOException {
    Element infoElement;

    /*
     * Return disk space
     */
    infoElement = getXmlUtils().createElement(getResponseRoot(), AP_E_INFO);
    renderDiskXml(infoElement);

    /*
     * No further action if this isn't a create command (success)
     */
    if (!isCreateCommand()) {
      return true;
    }
    /*
     * Stop if any required parameters are missing (error)
     */
    if (!verifyTarget() || !verifyMinimumParameters() || !verifyDefiningParameters()) {
      throw new ResponseException("Missing required parameters");
    }
    /*
     * Create the AU
     */
    if (!commandSetup()) {
      return false;
    }
    return createAu();
  }

  /*
   * "Helpers"
   */

  /**
   * Did the client provide the minimal parameters required?
   *
   * @return true If so
   */
  private boolean verifyMinimumParameters() {
    int count = 0;

    if (!StringUtil.isNullString(getParameter(AP_E_PUBLICATION))) count++;
    if (!StringUtil.isNullString(getParameter(AP_E_CLASSNAME))) count++;
    if (!StringUtil.isNullString(getParameter(AP_E_PLUGIN))) count++;

    return (count > 0);
  }

  /**
   * A target system is required to create an AU - was it provided?
   *
   * @return true If at least one target was specified
   */
  private boolean verifyTarget() {
    if (!isCreateCommand()) {
      return true;
    }

    return !StringUtil.isNullString(getParameter(AP_E_TARGET));
  }

  /**
   * Are all of the "defining parameters" required to create an AU available?
   *
   * @return true If so
   */
  private boolean verifyDefiningParameters() {
    KeyedList parameters;
    int size;

    if (!isCreateCommand()) {
      return true;
    }

    parameters = ParseUtils.getDynamicFields(getXmlUtils(), getRequestDocument(), AP_MD_AUDEFINING);
    size = parameters.size();

    for (int i = 0; i < size; i++) {
      if (StringUtil.isNullString((String) parameters.getValue(i))) {
        return false;
      }
    }
    return true;
  }

  /**
   * "Create" command?
   *
   * @return true If so...
   */
  private boolean isCreateCommand() {
    return "create".equalsIgnoreCase(getParameter(AP_E_ACTION));
  }

  /** Query the daemon for information required to set up this command */
  private boolean commandSetup() {

    Configuration configuration = null;
    Collection noEditKeys = null;
    String key;
    String value;

    /*
     * Configure a well known publication?
     */
    if ((value = getParameter(AP_E_PUBLICATION)) != null) {
      PluginProxy plugin = getTitlePlugin(value);

      /*
       * Set plugin and Title configuration information
       */
      if (plugin == null) {
        String message = "Unknown Publication:" + value;

        log.warning(message);
        return error(message);
      }

      setPlugin(plugin);
      setTitleConfig(plugin.getTitleConfig(value));

      configuration = getTitleConfig().getConfig();
      noEditKeys = getNoEditKeys();

    } else {
      /*
       * Lookup by Plugin or Class name - set the plugin
       *
       * NB: As of 23-Feb-04, this is not supported from AddAuPage.java.  See
       *     AddAuWithCompleteFunctionalityPage.java for full support.
       */
      if ((value = getParameter(AP_E_PLUGIN)) != null) {
        key = RemoteApi.pluginKeyFromId(value);

      } else if ((value = getParameter(AP_E_CLASSNAME)) != null) {
        key = RemoteApi.pluginKeyFromId(value);

      } else {
        return error("Supply a Publication, Plugin, or Class name");
      }

      if (StringUtil.isNullString(key)) {
        return error("Supply a valid Publication, Plugin, or Class name");
      }

      if (!pluginLoaded(key)) {
        return error("Plugin is not loaded: " + key);
      }

      setPlugin(getPluginProxy(key));
    }

    /*
     * Finally, return an XML rendition of the Plugin and AU key set up
     */
    generateSetupXml(configuration, noEditKeys);
    return true;
  }

  /**
   * Create an Archival Unit
   *
   * @return true If successful
   */
  private boolean createAu() {

    Configuration config = getAuConfigFromForm();

    AuProxy au;
    Element element;

    try {
      au = getRemoteApi().createAndSaveAuConfiguration(getPlugin(), config);

    } catch (ArchivalUnit.ConfigurationException exception) {
      return error("Configuration failed: " + exception.getMessage());

    } catch (IOException exception) {
      return error("Unable to save configuration: " + exception.getMessage());
    }
    /*
     * Successful creation - add the AU name and ID to the response document
     */
    element = getXmlUtils().createElement(getResponseRoot(), AP_E_AU);
    XmlUtils.addText(element, au.getName());

    element = getXmlUtils().createElement(getResponseRoot(), AP_E_AUID);
    XmlUtils.addText(element, au.getAuId());

    return true;
  }
}
/**
 * Class is a transport layer for WebRTC data channels. It consists of SCTP connection running on
 * top of ICE/DTLS layer. Manages WebRTC data channels. See
 * http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-08 for more info on WebRTC data
 * channels.
 *
 * <p>Control protocol: http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-03 FIXME handle
 * closing of data channels(SCTP stream reset)
 *
 * @author Pawel Domas
 * @author Lyubomir Marinov
 * @author Boris Grozev
 */
public class SctpConnection extends Channel
    implements SctpDataCallback, SctpSocket.NotificationListener {
  /** Generator used to track debug IDs. */
  private static int debugIdGen = -1;

  /** DTLS transport buffer size. Note: randomly chosen. */
  private static final int DTLS_BUFFER_SIZE = 2048;

  /** Switch used for debugging SCTP traffic purposes. FIXME to be removed */
  private static final boolean LOG_SCTP_PACKETS = false;

  /** The logger */
  private static final Logger logger = Logger.getLogger(SctpConnection.class);

  /**
   * Message type used to acknowledge WebRTC data channel allocation on SCTP stream ID on which
   * <tt>MSG_OPEN_CHANNEL</tt> message arrives.
   */
  private static final int MSG_CHANNEL_ACK = 0x2;

  private static final byte[] MSG_CHANNEL_ACK_BYTES = new byte[] {MSG_CHANNEL_ACK};

  /**
   * Message with this type sent over control PPID in order to open new WebRTC data channel on SCTP
   * stream ID that this message is sent.
   */
  private static final int MSG_OPEN_CHANNEL = 0x3;

  /** SCTP transport buffer size. */
  private static final int SCTP_BUFFER_SIZE = DTLS_BUFFER_SIZE - 13;

  /** The pool of <tt>Thread</tt>s which run <tt>SctpConnection</tt>s. */
  private static final ExecutorService threadPool =
      ExecutorUtils.newCachedThreadPool(true, SctpConnection.class.getName());

  /** Payload protocol id that identifies binary data in WebRTC data channel. */
  static final int WEB_RTC_PPID_BIN = 53;

  /** Payload protocol id for control data. Used for <tt>WebRtcDataStream</tt> allocation. */
  static final int WEB_RTC_PPID_CTRL = 50;

  /** Payload protocol id that identifies text data UTF8 encoded in WebRTC data channels. */
  static final int WEB_RTC_PPID_STRING = 51;

  /**
   * The <tt>String</tt> value of the <tt>Protocol</tt> field of the <tt>DATA_CHANNEL_OPEN</tt>
   * message.
   */
  private static final String WEBRTC_DATA_CHANNEL_PROTOCOL = "http://jitsi.org/protocols/colibri";

  private static synchronized int generateDebugId() {
    debugIdGen += 2;
    return debugIdGen;
  }

  /**
   * Indicates whether the STCP association is ready and has not been ended by a subsequent state
   * change.
   */
  private boolean assocIsUp;

  /** Indicates if we have accepted incoming connection. */
  private boolean acceptedIncomingConnection;

  /** Data channels mapped by SCTP stream identified(sid). */
  private final Map<Integer, WebRtcDataStream> channels = new HashMap<Integer, WebRtcDataStream>();

  /** Debug ID used to distinguish SCTP sockets in packet logs. */
  private final int debugId;

  /**
   * The <tt>AsyncExecutor</tt> which is to asynchronously dispatch the events fired by this
   * instance in order to prevent possible listeners from blocking this <tt>SctpConnection</tt> in
   * general and {@link #sctpSocket} in particular for too long. The timeout of <tt>15</tt> is
   * chosen to be in accord with the time it takes to expire a <tt>Channel</tt>.
   */
  private final AsyncExecutor<Runnable> eventDispatcher =
      new AsyncExecutor<Runnable>(15, TimeUnit.MILLISECONDS);

  /** Datagram socket for ICE/UDP layer. */
  private IceSocketWrapper iceSocket;

  /**
   * List of <tt>WebRtcDataStreamListener</tt>s that will be notified whenever new WebRTC data
   * channel is opened.
   */
  private final List<WebRtcDataStreamListener> listeners =
      new ArrayList<WebRtcDataStreamListener>();

  /** Remote SCTP port. */
  private final int remoteSctpPort;

  /** <tt>SctpSocket</tt> used for SCTP transport. */
  private SctpSocket sctpSocket;

  /**
   * Flag prevents from starting this connection multiple times from {@link #maybeStartStream()}.
   */
  private boolean started;

  /**
   * Initializes a new <tt>SctpConnection</tt> instance.
   *
   * @param id the string identifier of this connection instance
   * @param content the <tt>Content</tt> which is initializing the new instance
   * @param endpoint the <tt>Endpoint</tt> of newly created instance
   * @param remoteSctpPort the SCTP port used by remote peer
   * @param channelBundleId the ID of the channel-bundle this <tt>SctpConnection</tt> is to be a
   *     part of (or <tt>null</tt> if no it is not to be a part of a channel-bundle).
   * @throws Exception if an error occurs while initializing the new instance
   */
  public SctpConnection(
      String id, Content content, Endpoint endpoint, int remoteSctpPort, String channelBundleId)
      throws Exception {
    super(content, id, channelBundleId);

    setEndpoint(endpoint.getID());

    this.remoteSctpPort = remoteSctpPort;
    this.debugId = generateDebugId();
  }

  /**
   * Adds <tt>WebRtcDataStreamListener</tt> to the list of listeners.
   *
   * @param listener the <tt>WebRtcDataStreamListener</tt> to be added to the listeners list.
   */
  public void addChannelListener(WebRtcDataStreamListener listener) {
    if (listener == null) {
      throw new NullPointerException("listener");
    } else {
      synchronized (listeners) {
        if (!listeners.contains(listener)) {
          listeners.add(listener);
        }
      }
    }
  }

  /** {@inheritDoc} */
  @Override
  protected void closeStream() throws IOException {
    try {
      synchronized (this) {
        assocIsUp = false;
        acceptedIncomingConnection = false;
        if (sctpSocket != null) {
          sctpSocket.close();
          sctpSocket = null;
        }
      }
    } finally {
      if (iceSocket != null) {
        // It is now the responsibility of the transport manager to
        // close the socket.
        // iceUdpSocket.close();
      }
    }
  }

  /** {@inheritDoc} */
  @Override
  public void expire() {
    try {
      eventDispatcher.shutdown();
    } finally {
      super.expire();
    }
  }

  /**
   * Gets the <tt>WebRtcDataStreamListener</tt>s added to this instance.
   *
   * @return the <tt>WebRtcDataStreamListener</tt>s added to this instance or <tt>null</tt> if there
   *     are no <tt>WebRtcDataStreamListener</tt>s added to this instance
   */
  private WebRtcDataStreamListener[] getChannelListeners() {
    WebRtcDataStreamListener[] ls;

    synchronized (listeners) {
      if (listeners.isEmpty()) {
        ls = null;
      } else {
        ls = listeners.toArray(new WebRtcDataStreamListener[listeners.size()]);
      }
    }
    return ls;
  }

  /**
   * Returns default <tt>WebRtcDataStream</tt> if it's ready or <tt>null</tt> otherwise.
   *
   * @return <tt>WebRtcDataStream</tt> if it's ready or <tt>null</tt> otherwise.
   * @throws IOException
   */
  public WebRtcDataStream getDefaultDataStream() throws IOException {
    WebRtcDataStream def;

    synchronized (this) {
      if (sctpSocket == null) {
        def = null;
      } else {
        // Channel that runs on sid 0
        def = channels.get(0);
        if (def == null) {
          def = openChannel(0, 0, 0, 0, "default");
        }
        // Pawel Domas: Must be acknowledged before use
        /*
         * XXX Lyubomir Marinov: We're always sending ordered. According
         * to "WebRTC Data Channel Establishment Protocol", we can start
         * sending messages containing user data after the
         * DATA_CHANNEL_OPEN message has been sent without waiting for
         * the reception of the corresponding DATA_CHANNEL_ACK message.
         */
        //                if (!def.isAcknowledged())
        //                    def = null;
      }
    }
    return def;
  }

  /**
   * Returns <tt>true</tt> if this <tt>SctpConnection</tt> is connected to the remote peer and
   * operational.
   *
   * @return <tt>true</tt> if this <tt>SctpConnection</tt> is connected to the remote peer and
   *     operational
   */
  public boolean isReady() {
    return assocIsUp && acceptedIncomingConnection;
  }

  /** {@inheritDoc} */
  @Override
  protected void maybeStartStream() throws IOException {
    // connector
    final StreamConnector connector = getStreamConnector();

    if (connector == null) return;

    synchronized (this) {
      if (started) return;

      threadPool.execute(
          new Runnable() {
            @Override
            public void run() {
              try {
                Sctp.init();

                runOnDtlsTransport(connector);
              } catch (IOException e) {
                logger.error(e, e);
              } finally {
                try {
                  Sctp.finish();
                } catch (IOException e) {
                  logger.error("Failed to shutdown SCTP stack", e);
                }
              }
            }
          });

      started = true;
    }
  }

  /**
   * Submits {@link #notifyChannelOpenedInEventDispatcher(WebRtcDataStream)} to {@link
   * #eventDispatcher} for asynchronous execution.
   *
   * @param dataChannel
   */
  private void notifyChannelOpened(final WebRtcDataStream dataChannel) {
    if (!isExpired()) {
      eventDispatcher.execute(
          new Runnable() {
            @Override
            public void run() {
              notifyChannelOpenedInEventDispatcher(dataChannel);
            }
          });
    }
  }

  private void notifyChannelOpenedInEventDispatcher(WebRtcDataStream dataChannel) {
    /*
     * When executing asynchronously in eventDispatcher, it is technically
     * possible that this SctpConnection may have expired by now.
     */
    if (!isExpired()) {
      WebRtcDataStreamListener[] ls = getChannelListeners();

      if (ls != null) {
        for (WebRtcDataStreamListener l : ls) {
          l.onChannelOpened(this, dataChannel);
        }
      }
    }
  }

  /**
   * Submits {@link #notifySctpConnectionReadyInEventDispatcher()} to {@link #eventDispatcher} for
   * asynchronous execution.
   */
  private void notifySctpConnectionReady() {
    if (!isExpired()) {
      eventDispatcher.execute(
          new Runnable() {
            @Override
            public void run() {
              notifySctpConnectionReadyInEventDispatcher();
            }
          });
    }
  }

  /**
   * Notifies the <tt>WebRtcDataStreamListener</tt>s added to this instance that this
   * <tt>SctpConnection</tt> is ready i.e. it is connected to the remote peer and operational.
   */
  private void notifySctpConnectionReadyInEventDispatcher() {
    /*
     * When executing asynchronously in eventDispatcher, it is technically
     * possible that this SctpConnection may have expired by now.
     */
    if (!isExpired() && isReady()) {
      WebRtcDataStreamListener[] ls = getChannelListeners();

      if (ls != null) {
        for (WebRtcDataStreamListener l : ls) {
          l.onSctpConnectionReady(this);
        }
      }
    }
  }

  /**
   * Handles control packet.
   *
   * @param data raw packet data that arrived on control PPID.
   * @param sid SCTP stream id on which the data has arrived.
   */
  private synchronized void onCtrlPacket(byte[] data, int sid) throws IOException {
    ByteBuffer buffer = ByteBuffer.wrap(data);
    int messageType = /* 1 byte unsigned integer */ 0xFF & buffer.get();

    if (messageType == MSG_CHANNEL_ACK) {
      if (logger.isDebugEnabled()) {
        logger.debug(getEndpoint().getID() + " ACK received SID: " + sid);
      }
      // Open channel ACK
      WebRtcDataStream channel = channels.get(sid);
      if (channel != null) {
        // Ack check prevents from firing multiple notifications
        // if we get more than one ACKs (by mistake/bug).
        if (!channel.isAcknowledged()) {
          channel.ackReceived();
          notifyChannelOpened(channel);
        } else {
          logger.warn("Redundant ACK received for SID: " + sid);
        }
      } else {
        logger.error("No channel exists on sid: " + sid);
      }
    } else if (messageType == MSG_OPEN_CHANNEL) {
      int channelType = /* 1 byte unsigned integer */ 0xFF & buffer.get();
      int priority = /* 2 bytes unsigned integer */ 0xFFFF & buffer.getShort();
      long reliability = /* 4 bytes unsigned integer */ 0xFFFFFFFFL & buffer.getInt();
      int labelLength = /* 2 bytes unsigned integer */ 0xFFFF & buffer.getShort();
      int protocolLength = /* 2 bytes unsigned integer */ 0xFFFF & buffer.getShort();
      String label;
      String protocol;

      if (labelLength == 0) {
        label = "";
      } else {
        byte[] labelBytes = new byte[labelLength];

        buffer.get(labelBytes);
        label = new String(labelBytes, "UTF-8");
      }
      if (protocolLength == 0) {
        protocol = "";
      } else {
        byte[] protocolBytes = new byte[protocolLength];

        buffer.get(protocolBytes);
        protocol = new String(protocolBytes, "UTF-8");
      }

      if (logger.isDebugEnabled()) {
        logger.debug(
            "!!! "
                + getEndpoint().getID()
                + " data channel open request on SID: "
                + sid
                + " type: "
                + channelType
                + " prio: "
                + priority
                + " reliab: "
                + reliability
                + " label: "
                + label
                + " proto: "
                + protocol);
      }

      if (channels.containsKey(sid)) {
        logger.error("Channel on sid: " + sid + " already exists");
      }

      WebRtcDataStream newChannel = new WebRtcDataStream(sctpSocket, sid, label, true);
      channels.put(sid, newChannel);

      sendOpenChannelAck(sid);

      notifyChannelOpened(newChannel);
    } else {
      logger.error("Unexpected ctrl msg type: " + messageType);
    }
  }

  /** {@inheritDoc} */
  @Override
  protected void onEndpointChanged(Endpoint oldValue, Endpoint newValue) {
    if (oldValue != null) oldValue.setSctpConnection(null);
    if (newValue != null) newValue.setSctpConnection(this);
  }

  /** Implements notification in order to track socket state. */
  @Override
  public synchronized void onSctpNotification(SctpSocket socket, SctpNotification notification) {
    if (logger.isDebugEnabled()) {
      logger.debug("socket=" + socket + "; notification=" + notification);
    }
    switch (notification.sn_type) {
      case SctpNotification.SCTP_ASSOC_CHANGE:
        SctpNotification.AssociationChange assocChange =
            (SctpNotification.AssociationChange) notification;

        switch (assocChange.state) {
          case SctpNotification.AssociationChange.SCTP_COMM_UP:
            if (!assocIsUp) {
              boolean wasReady = isReady();

              assocIsUp = true;
              if (isReady() && !wasReady) notifySctpConnectionReady();
            }
            break;

          case SctpNotification.AssociationChange.SCTP_COMM_LOST:
          case SctpNotification.AssociationChange.SCTP_SHUTDOWN_COMP:
          case SctpNotification.AssociationChange.SCTP_CANT_STR_ASSOC:
            try {
              closeStream();
            } catch (IOException e) {
              logger.error("Error closing SCTP socket", e);
            }
            break;
        }
        break;
    }
  }

  /**
   * {@inheritDoc}
   *
   * <p>SCTP input data callback.
   */
  @Override
  public void onSctpPacket(
      byte[] data, int sid, int ssn, int tsn, long ppid, int context, int flags) {
    if (ppid == WEB_RTC_PPID_CTRL) {
      // Channel control PPID
      try {
        onCtrlPacket(data, sid);
      } catch (IOException e) {
        logger.error("IOException when processing ctrl packet", e);
      }
    } else if (ppid == WEB_RTC_PPID_STRING || ppid == WEB_RTC_PPID_BIN) {
      WebRtcDataStream channel;

      synchronized (this) {
        channel = channels.get(sid);
      }

      if (channel == null) {
        logger.error("No channel found for sid: " + sid);
        return;
      }
      if (ppid == WEB_RTC_PPID_STRING) {
        // WebRTC String
        String str;
        String charsetName = "UTF-8";

        try {
          str = new String(data, charsetName);
        } catch (UnsupportedEncodingException uee) {
          logger.error("Unsupported charset encoding/name " + charsetName, uee);
          str = null;
        }
        channel.onStringMsg(str);
      } else {
        // WebRTC Binary
        channel.onBinaryMsg(data);
      }
    } else {
      logger.warn("Got message on unsupported PPID: " + ppid);
    }
  }

  /**
   * Opens new WebRTC data channel using specified parameters.
   *
   * @param type channel type as defined in control protocol description. Use 0 for "reliable".
   * @param prio channel priority. The higher the number, the lower the priority.
   * @param reliab Reliability Parameter<br>
   *     This field is ignored if a reliable channel is used. If a partial reliable channel with
   *     limited number of retransmissions is used, this field specifies the number of
   *     retransmissions. If a partial reliable channel with limited lifetime is used, this field
   *     specifies the maximum lifetime in milliseconds. The following table summarizes this:<br>
   *     </br>
   *     <p>+------------------------------------------------+------------------+ | Channel Type |
   *     Reliability | | | Parameter |
   *     +------------------------------------------------+------------------+ |
   *     DATA_CHANNEL_RELIABLE | Ignored | | DATA_CHANNEL_RELIABLE_UNORDERED | Ignored | |
   *     DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT | Number of RTX | |
   *     DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT_UNORDERED | Number of RTX | |
   *     DATA_CHANNEL_PARTIAL_RELIABLE_TIMED | Lifetime in ms | |
   *     DATA_CHANNEL_PARTIAL_RELIABLE_TIMED_UNORDERED | Lifetime in ms |
   *     +------------------------------------------------+------------------+
   * @param sid SCTP stream id that will be used by new channel (it must not be already used).
   * @param label text label for the channel.
   * @return new instance of <tt>WebRtcDataStream</tt> that represents opened WebRTC data channel.
   * @throws IOException if IO error occurs.
   */
  public synchronized WebRtcDataStream openChannel(
      int type, int prio, long reliab, int sid, String label) throws IOException {
    if (channels.containsKey(sid)) {
      throw new IOException("Channel on sid: " + sid + " already exists");
    }

    // Label Length & Label
    byte[] labelBytes;
    int labelByteLength;

    if (label == null) {
      labelBytes = null;
      labelByteLength = 0;
    } else {
      labelBytes = label.getBytes("UTF-8");
      labelByteLength = labelBytes.length;
      if (labelByteLength > 0xFFFF) labelByteLength = 0xFFFF;
    }

    // Protocol Length & Protocol
    String protocol = WEBRTC_DATA_CHANNEL_PROTOCOL;
    byte[] protocolBytes;
    int protocolByteLength;

    if (protocol == null) {
      protocolBytes = null;
      protocolByteLength = 0;
    } else {
      protocolBytes = protocol.getBytes("UTF-8");
      protocolByteLength = protocolBytes.length;
      if (protocolByteLength > 0xFFFF) protocolByteLength = 0xFFFF;
    }

    ByteBuffer packet = ByteBuffer.allocate(12 + labelByteLength + protocolByteLength);

    // Message open new channel on current sid
    // Message Type
    packet.put((byte) MSG_OPEN_CHANNEL);
    // Channel Type
    packet.put((byte) type);
    // Priority
    packet.putShort((short) prio);
    // Reliability Parameter
    packet.putInt((int) reliab);
    // Label Length
    packet.putShort((short) labelByteLength);
    // Protocol Length
    packet.putShort((short) protocolByteLength);
    // Label
    if (labelByteLength != 0) {
      packet.put(labelBytes, 0, labelByteLength);
    }
    // Protocol
    if (protocolByteLength != 0) {
      packet.put(protocolBytes, 0, protocolByteLength);
    }

    int sentCount = sctpSocket.send(packet.array(), true, sid, WEB_RTC_PPID_CTRL);

    if (sentCount != packet.capacity()) {
      throw new IOException("Failed to open new chanel on sid: " + sid);
    }

    WebRtcDataStream channel = new WebRtcDataStream(sctpSocket, sid, label, false);

    channels.put(sid, channel);

    return channel;
  }

  /**
   * Removes <tt>WebRtcDataStreamListener</tt> from the list of listeners.
   *
   * @param listener the <tt>WebRtcDataStreamListener</tt> to be removed from the listeners list.
   */
  public void removeChannelListener(WebRtcDataStreamListener listener) {
    if (listener != null) {
      synchronized (listeners) {
        listeners.remove(listener);
      }
    }
  }

  private void runOnDtlsTransport(StreamConnector connector) throws IOException {
    DtlsControlImpl dtlsControl = (DtlsControlImpl) getTransportManager().getDtlsControl(this);
    DtlsTransformEngine engine = dtlsControl.getTransformEngine();
    final DtlsPacketTransformer transformer = (DtlsPacketTransformer) engine.getRTPTransformer();

    byte[] receiveBuffer = new byte[SCTP_BUFFER_SIZE];

    if (LOG_SCTP_PACKETS) {
      System.setProperty(
          ConfigurationService.PNAME_SC_HOME_DIR_LOCATION, System.getProperty("java.io.tmpdir"));
      System.setProperty(
          ConfigurationService.PNAME_SC_HOME_DIR_NAME, SctpConnection.class.getName());
    }

    synchronized (this) {
      // FIXME local SCTP port is hardcoded in bridge offer SDP (Jitsi
      // Meet)
      sctpSocket = Sctp.createSocket(5000);
      assocIsUp = false;
      acceptedIncomingConnection = false;
    }

    // Implement output network link for SCTP stack on DTLS transport
    sctpSocket.setLink(
        new NetworkLink() {
          @Override
          public void onConnOut(SctpSocket s, byte[] packet) throws IOException {
            if (LOG_SCTP_PACKETS) {
              LibJitsi.getPacketLoggingService()
                  .logPacket(
                      PacketLoggingService.ProtocolName.ICE4J,
                      new byte[] {0, 0, 0, (byte) debugId},
                      5000,
                      new byte[] {0, 0, 0, (byte) (debugId + 1)},
                      remoteSctpPort,
                      PacketLoggingService.TransportName.UDP,
                      true,
                      packet);
            }

            // Send through DTLS transport
            transformer.sendApplicationData(packet, 0, packet.length);
          }
        });

    if (logger.isDebugEnabled()) {
      logger.debug("Connecting SCTP to port: " + remoteSctpPort + " to " + getEndpoint().getID());
    }

    sctpSocket.setNotificationListener(this);
    sctpSocket.listen();

    // FIXME manage threads
    threadPool.execute(
        new Runnable() {
          @Override
          public void run() {
            SctpSocket sctpSocket = null;
            try {
              // sctpSocket is set to null on close
              sctpSocket = SctpConnection.this.sctpSocket;
              while (sctpSocket != null) {
                if (sctpSocket.accept()) {
                  acceptedIncomingConnection = true;
                  break;
                }
                Thread.sleep(100);
                sctpSocket = SctpConnection.this.sctpSocket;
              }
              if (isReady()) {
                notifySctpConnectionReady();
              }
            } catch (Exception e) {
              logger.error("Error accepting SCTP connection", e);
            }

            if (sctpSocket == null && logger.isInfoEnabled()) {
              logger.info(
                  "SctpConnection " + getID() + " closed" + " before SctpSocket accept()-ed.");
            }
          }
        });

    // Notify that from now on SCTP connection is considered functional
    sctpSocket.setDataCallback(this);

    // Setup iceSocket
    DatagramSocket datagramSocket = connector.getDataSocket();
    if (datagramSocket != null) {
      this.iceSocket = new IceUdpSocketWrapper(datagramSocket);
    } else {
      this.iceSocket = new IceTcpSocketWrapper(connector.getDataTCPSocket());
    }

    DatagramPacket rcvPacket = new DatagramPacket(receiveBuffer, 0, receiveBuffer.length);

    // Receive loop, breaks when SCTP socket is closed
    try {
      do {
        iceSocket.receive(rcvPacket);

        RawPacket raw =
            new RawPacket(rcvPacket.getData(), rcvPacket.getOffset(), rcvPacket.getLength());

        raw = transformer.reverseTransform(raw);
        // Check for app data
        if (raw == null) continue;

        if (LOG_SCTP_PACKETS) {
          LibJitsi.getPacketLoggingService()
              .logPacket(
                  PacketLoggingService.ProtocolName.ICE4J,
                  new byte[] {0, 0, 0, (byte) (debugId + 1)},
                  remoteSctpPort,
                  new byte[] {0, 0, 0, (byte) debugId},
                  5000,
                  PacketLoggingService.TransportName.UDP,
                  false,
                  raw.getBuffer(),
                  raw.getOffset(),
                  raw.getLength());
        }

        // Pass network packet to SCTP stack
        sctpSocket.onConnIn(raw.getBuffer(), raw.getOffset(), raw.getLength());
      } while (true);
    } finally {
      // Eventually, close the socket although it should happen from
      // expire().
      synchronized (this) {
        assocIsUp = false;
        acceptedIncomingConnection = false;
        if (sctpSocket != null) {
          sctpSocket.close();
          sctpSocket = null;
        }
      }
    }
  }

  /**
   * Sends acknowledgment for open channel request on given SCTP stream ID.
   *
   * @param sid SCTP stream identifier to be used for sending ack.
   */
  private void sendOpenChannelAck(int sid) throws IOException {
    // Send ACK
    byte[] ack = MSG_CHANNEL_ACK_BYTES;
    int sendAck = sctpSocket.send(ack, true, sid, WEB_RTC_PPID_CTRL);

    if (sendAck != ack.length) {
      logger.error("Failed to send open channel confirmation");
    }
  }

  /**
   * {@inheritDoc}
   *
   * <p>Creates a <tt>TransportManager</tt> instance suitable for an <tt>SctpConnection</tt> (e.g.
   * with 1 component only).
   */
  protected TransportManager createTransportManager(String xmlNamespace) throws IOException {
    if (IceUdpTransportPacketExtension.NAMESPACE.equals(xmlNamespace)) {
      Content content = getContent();
      return new IceUdpTransportManager(
          content.getConference(), isInitiator(), 1 /* num components */, content.getName());
    } else if (RawUdpTransportPacketExtension.NAMESPACE.equals(xmlNamespace)) {
      // TODO: support RawUdp once RawUdpTransportManager is updated
      // return new RawUdpTransportManager(this);
      throw new IllegalArgumentException("Unsupported Jingle transport " + xmlNamespace);
    } else {
      throw new IllegalArgumentException("Unsupported Jingle transport " + xmlNamespace);
    }
  }
}
Esempio n. 28
0
// SingleThreadModel causes servlet instances to be assigned to only a
// single thread (request) at a time.
public abstract class LockssServlet extends HttpServlet implements SingleThreadModel {
  protected static Logger log = Logger.getLogger("LockssServlet");

  // Constants
  static final String PARAM_LOCAL_IP = Configuration.PREFIX + "localIPAddress";

  static final String PARAM_PLATFORM_VERSION = Configuration.PREFIX + "platform.version";

  /** Inactive HTTP session (cookie) timeout */
  static final String PARAM_UI_SESSION_TIMEOUT = Configuration.PREFIX + "ui.sessionTimeout";

  static final long DEFAULT_UI_SESSION_TIMEOUT = 2 * Constants.DAY;

  /** Maximum size of uploaded file accepted */
  static final String PARAM_MAX_UPLOAD_FILE_SIZE = Configuration.PREFIX + "ui.maxUploadFileSize";

  static final int DEFAULT_MAX_UPLOAD_FILE_SIZE = 500000;

  /** The warning string to display when the UI is disabled. */
  static final String PARAM_UI_WARNING = Configuration.PREFIX + "ui.warning";

  // session keys
  static final String SESSION_KEY_OBJECT_ID = "obj_id";
  static final String SESSION_KEY_OBJ_MAP = "obj_map";
  public static final String SESSION_KEY_RUNNING_SERVLET = "running_servlet";
  public static final String SESSION_KEY_REQUEST_HOST = "request_host";

  // Name given to form element whose value is the action that should be
  // performed when the form is submitted.  (Not always the submit button.)
  public static final String ACTION_TAG = "lockssAction";

  public static final String JAVASCRIPT_RESOURCE = "org/lockss/htdocs/admin.js";

  public static final String ATTR_INCLUDE_SCRIPT = "IncludeScript";
  public static final String ATTR_ALLOW_ROLES = "AllowRoles";

  /** User may configure admin access (add/delete/modify users, set admin access list) */
  public static final String ROLE_USER_ADMIN = "userAdminRole";

  /** User may configure content access (set content access list) */
  public static final String ROLE_CONTENT_ADMIN = "contentAdminRole";

  /** User may change AU configuration (add/delete content) */
  public static final String ROLE_AU_ADMIN = "auAdminRole";

  public static final String ROLE_DEBUG = "debugRole";

  protected ServletContext context;

  private LockssApp theApp = null;
  private ServletManager servletMgr;
  private AccountManager acctMgr;

  // Request-local storage.  Convenient, but requires servlet instances
  // to be single threaded, and must ensure reset them to avoid carrying
  // over state between requests.
  protected HttpServletRequest req;
  protected HttpServletResponse resp;
  protected URL reqURL;
  protected HttpSession session;
  private String adminDir = null;
  protected String clientAddr; // client addr, even if no param
  protected String localAddr;
  protected MultiPartRequest multiReq;

  private Vector footnotes;
  private int footNumber;
  private int tabindex;
  ServletDescr _myServletDescr = null;
  private String myName = null;

  // number submit buttons sequentially so unit tests can find them
  protected int submitButtonNumber = 0;

  /** Run once when servlet loaded. */
  public void init(ServletConfig config) throws ServletException {
    super.init(config);
    context = config.getServletContext();
    theApp = (LockssApp) context.getAttribute(ServletManager.CONTEXT_ATTR_LOCKSS_APP);
    servletMgr = (ServletManager) context.getAttribute(ServletManager.CONTEXT_ATTR_SERVLET_MGR);
    if (theApp instanceof LockssDaemon) {
      acctMgr = getLockssDaemon().getAccountManager();
    }
  }

  public ServletManager getServletManager() {
    return servletMgr;
  }

  protected ServletDescr[] getServletDescrs() {
    return servletMgr.getServletDescrs();
  }

  /** Servlets must implement this method. */
  protected abstract void lockssHandleRequest() throws ServletException, IOException;

  /** Common request handling. */
  public void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    resetState();
    boolean success = false;
    HttpSession session = req.getSession(false);
    try {
      this.req = req;
      this.resp = resp;
      if (log.isDebug()) {
        logParams();
      }
      resp.setContentType("text/html");

      if (!mayPageBeCached()) {
        resp.setHeader("pragma", "no-cache");
        resp.setHeader("Cache-control", "no-cache");
      }

      reqURL = new URL(UrlUtil.getRequestURL(req));
      clientAddr = getLocalIPAddr();

      // check that current user has permission to run this servlet
      if (!isServletAllowed(myServletDescr())) {
        displayWarningInLieuOfPage("You are not authorized to use " + myServletDescr().heading);
        return;
      }

      // check whether servlet is disabled
      String reason = ServletUtil.servletDisabledReason(myServletDescr().getServletName());
      if (reason != null) {
        displayWarningInLieuOfPage("This function is disabled. " + reason);
        return;
      }
      if (session != null) {
        session.setAttribute(SESSION_KEY_RUNNING_SERVLET, getHeading());
        String reqHost = req.getRemoteHost();
        String forw = req.getHeader(HttpFields.__XForwardedFor);
        if (!StringUtil.isNullString(forw)) {
          reqHost += " (proxies for " + forw + ")";
        }
        session.setAttribute(SESSION_KEY_REQUEST_HOST, reqHost);
      }
      lockssHandleRequest();
      success = (errMsg == null);
    } catch (ServletException e) {
      log.error("Servlet threw", e);
      throw e;
    } catch (IOException e) {
      log.error("Servlet threw", e);
      throw e;
    } catch (RuntimeException e) {
      log.error("Servlet threw", e);
      throw e;
    } finally {
      if (session != null) {
        session.setAttribute(SESSION_KEY_RUNNING_SERVLET, null);
        session.setAttribute(LockssFormAuthenticator.__J_AUTH_ACTIVITY, TimeBase.nowMs());
      }
      if ("please".equalsIgnoreCase(req.getHeader("X-Lockss-Result"))) {
        log.debug3("X-Lockss-Result: " + (success ? "Ok" : "Fail"));
        resp.setHeader("X-Lockss-Result", success ? "Ok" : "Fail");
      }
      resetMyLocals();
      resetLocals();
    }
  }

  protected void resetState() {
    multiReq = null;
    footNumber = 0;
    submitButtonNumber = 0;
    tabindex = 1;
    statusMsg = null;
    errMsg = null;
    isFramed = false;
  }

  protected void resetLocals() {}

  protected void resetMyLocals() {
    // Don't hold on to stuff forever
    req = null;
    resp = null;
    session = null;
    reqURL = null;
    adminDir = null;
    localAddr = null;
    footnotes = null;
    _myServletDescr = null;
    myName = null;
    multiReq = null;
  }

  /**
   * Return true if generated page may be cached (e.g., by browser). Default is false as most
   * servlets generate dynamic results
   */
  protected boolean mayPageBeCached() {
    return false;
  }

  /** Set the session timeout to the configured value */
  protected void setSessionTimeout(HttpSession session) {
    Configuration config = CurrentConfig.getCurrentConfig();
    setSessionTimeout(
        session, config.getTimeInterval(PARAM_UI_SESSION_TIMEOUT, DEFAULT_UI_SESSION_TIMEOUT));
  }

  /** Set the session timeout */
  protected void setSessionTimeout(HttpSession session, long time) {
    session.setMaxInactiveInterval((int) (time / Constants.SECOND));
  }

  /** Get the current session, creating it if necessary (and set the timeout if so) */
  protected HttpSession getSession() {
    if (session == null) {
      session = req.getSession(true);
      if (session.isNew()) {
        setSessionTimeout(session);
      }
    }
    return session;
  }

  /** Return true iff a session has already been established */
  protected boolean hasSession() {
    return req.getSession(false) != null;
  }

  /** Get an unused ID string for storing an object in the session */
  protected String getNewSessionObjectId() {
    HttpSession session = getSession();
    synchronized (session) {
      Integer id = (Integer) getSession().getAttribute(SESSION_KEY_OBJECT_ID);
      if (id == null) {
        id = new Integer(1);
      }
      session.setAttribute(SESSION_KEY_OBJECT_ID, new Integer(id.intValue() + 1));
      return id.toString();
    }
  }

  /** Get the object associated with the ID in the session */
  protected Object getSessionIdObject(String id) {
    HttpSession session = getSession();
    synchronized (session) {
      BidiMap map = (BidiMap) session.getAttribute(SESSION_KEY_OBJ_MAP);
      if (map == null) {
        return null;
      }
      return map.getKey(id);
    }
  }

  /** Get the String associated with the ID in the session */
  protected String getSessionIdString(String id) {
    return (String) getSessionIdObject(id);
  }

  /** Get the ID with which the object is associated with the session, if any */
  protected String getSessionObjectId(Object obj) {
    HttpSession session = getSession();
    BidiMap map;
    synchronized (session) {
      map = (BidiMap) session.getAttribute(SESSION_KEY_OBJ_MAP);
      if (map == null) {
        map = new DualHashBidiMap();
        session.setAttribute(SESSION_KEY_OBJ_MAP, map);
      }
    }
    synchronized (map) {
      String id = (String) map.get(obj);
      if (id == null) {
        id = getNewSessionObjectId();
        map.put(obj, id);
      }
      return id;
    }
  }

  // Return descriptor of running servlet
  protected ServletDescr myServletDescr() {
    if (_myServletDescr == null) {
      _myServletDescr = servletMgr.findServletDescr(this);
    }
    return _myServletDescr;
  }

  // By default, servlet heading is in descr.  Override method to
  // compute other heading
  protected String getHeading(ServletDescr d) {
    if (d == null) return "Unknown Servlet";
    return d.heading;
  }

  protected String getHeading() {
    return getHeading(myServletDescr());
  }

  String getLocalIPAddr() {
    if (localAddr == null) {
      try {
        IPAddr localHost = IPAddr.getLocalHost();
        localAddr = localHost.getHostAddress();
      } catch (UnknownHostException e) {
        // shouldn't happen
        log.error("LockssServlet: getLocalHost: " + e.toString());
        return "???";
      }
    }
    return localAddr;
  }

  // Return IP addr used by LCAP.  If specified by (misleadingly named)
  // localIPAddress prop, might not really be our address (if we are
  // behind NAT).
  String getLcapIPAddr() {
    String ip = CurrentConfig.getParam(PARAM_LOCAL_IP);
    if (ip == null || ip.length() <= 0) {
      return getLocalIPAddr();
    }
    return ip;
  }

  String getRequestHost() {
    return reqURL.getHost();
  }

  String getMachineName() {
    return PlatformUtil.getLocalHostname();
  }

  //   String getMachineName0() {
  //     if (myName == null) {
  //       // Return the canonical name of the interface the request was aimed
  //       // at.  (localIPAddress prop isn't necessarily right here, as it
  //       // might be the address of a NAT that we're behind.)
  //       String host = reqURL.getHost();
  //       try {
  // 	IPAddr localHost = IPAddr.getByName(host);
  // 	String ip = localHost.getHostAddress();
  // 	myName = getMachineName(ip);
  //       } catch (UnknownHostException e) {
  // 	// shouldn't happen
  // 	log.error("getMachineName", e);
  // 	return host;
  //       }
  //     }
  //     return myName;
  //   }

  //   String getMachineName(String ip) {
  //     try {
  //       IPAddr inet = IPAddr.getByName(ip);
  //       return inet.getHostName();
  //     } catch (UnknownHostException e) {
  //       log.warning("getMachineName", e);
  //     }
  //     return ip;
  //   }

  // return IP given name or IP
  String getMachineIP(String name) {
    try {
      IPAddr inet = IPAddr.getByName(name);
      return inet.getHostAddress();
    } catch (UnknownHostException e) {
      return null;
    }
  }

  boolean isServletLinkInNav(ServletDescr d) {
    return !isThisServlet(d) || linkMeInNav();
  }

  boolean isThisServlet(ServletDescr d) {
    return d == myServletDescr();
  }

  /** servlets may override this to determine whether they should be a link in nav table */
  protected boolean linkMeInNav() {
    return false;
  }

  boolean isLargeLogo() {
    return myServletDescr().isLargeLogo();
  }

  // user predicates
  String getUsername() {
    Principal user = req.getUserPrincipal();
    return user != null ? user.toString() : null;
  }

  protected UserAccount getUserAccount() {
    if (acctMgr != null) {
      return acctMgr.getUser(getUsername());
    }
    return AccountManager.NOBODY_ACCOUNT;
  }

  protected boolean isDebugUser() {
    return doesUserHaveRole(ROLE_DEBUG);
  }

  protected boolean doesUserHaveRole(String role) {
    if ((req.isUserInRole(role) || req.isUserInRole(ROLE_USER_ADMIN)) && !hasNoRoleParsm(role)) {
      return true;
    }
    return hasTestRole(role);
  }

  static Map<String, String> noRoleParams = new HashMap<String, String>();

  static {
    noRoleParams.put(ROLE_USER_ADMIN, "noadmin");
    noRoleParams.put(ROLE_CONTENT_ADMIN, "nocontent");
    noRoleParams.put(ROLE_AU_ADMIN, "noau");
    noRoleParams.put(ROLE_DEBUG, "nodebug");
  }

  protected boolean hasNoRoleParsm(String roleName) {
    String noRoleParam = noRoleParams.get(roleName);
    return (noRoleParam != null && !StringUtil.isNullString(req.getParameter(noRoleParam)));
  }

  protected boolean hasTestRole(String role) {
    // Servlet test harness puts roles in context
    List roles = (List) context.getAttribute(ATTR_ALLOW_ROLES);
    return roles != null && (roles.contains(role) || roles.contains(ROLE_USER_ADMIN));
  }

  protected boolean isServletAllowed(ServletDescr d) {
    if (d.needsUserAdminRole() && !doesUserHaveRole(ROLE_USER_ADMIN)) return false;
    if (d.needsContentAdminRole() && !doesUserHaveRole(ROLE_CONTENT_ADMIN)) return false;
    if (d.needsAuAdminRole() && !doesUserHaveRole(ROLE_AU_ADMIN)) return false;

    return d.isEnabled(getLockssDaemon());
  }

  protected boolean isServletDisplayed(ServletDescr d) {
    if (!isServletAllowed(d)) return false;
    if (d.needsDebugRole() && !doesUserHaveRole(ROLE_DEBUG)) return false;
    return true;
  }

  protected boolean isServletInNav(ServletDescr d) {
    if (d.cls == ServletDescr.UNAVAILABLE_SERVLET_MARKER) return false;
    return d.isInNav(this) && isServletDisplayed(d);
  }

  // Called when a servlet doesn't get the parameters it expects/needs
  protected void paramError() throws IOException {
    // FIXME: As of 2006-03-15 this method and its only caller checkParam() are not called from
    // anywhere
    PrintWriter wrtr = resp.getWriter();
    Page page = new Page();
    // add referer, params, msg to contact lockss unless from old bookmark
    // or manually entered url
    page.add("Parameter error");
    page.write(wrtr);
  }

  // return true iff error
  protected boolean checkParam(boolean ok, String msg) throws IOException {
    if (ok) return false;
    log.error(myServletDescr().getPath() + ": " + msg);
    paramError();
    return true;
  }

  /** Construct servlet URL */
  String srvURL(ServletDescr d) {
    return srvURL((String) null, d, null);
  }

  /** Construct servlet URL with params */
  String srvURL(ServletDescr d, String params) {
    return srvURL((String) null, d, params);
  }

  /** Construct servlet URL with params */
  String srvURL(ServletDescr d, Properties params) {
    return srvURL(d, concatParams(params));
  }

  /** Construct servlet absolute URL, with params as necessary. */
  String srvAbsURL(ServletDescr d, String params) {
    return srvURL(getRequestHost(), d, params);
  }

  /**
   * Construct servlet URL, with params as necessary. Avoid generating a hostname different from
   * that used in the original request, or browsers will prompt again for login
   */
  String srvURL(String host, ServletDescr d, String params) {
    return srvURLFromStem(srvUrlStem(host), d, params);
  }

  String srvURL(PeerIdentity peer, ServletDescr d, String params) {
    return srvURLFromStem(peer.getUiUrlStem(reqURL.getPort()), d, params);
  }

  /**
   * Construct servlet URL, with params as necessary. Avoid generating a hostname different from
   * that used in the original request, or browsers will prompt again for login
   */
  String srvURLFromStem(String stem, ServletDescr d, String params) {
    if (d.isPathIsUrl()) {
      return d.getPath();
    }
    StringBuilder sb = new StringBuilder(80);
    if (stem != null) {
      sb.append(stem);
      if (stem.charAt(stem.length() - 1) != '/') {
        sb.append('/');
      }
    } else {
      // ensure absolute path even if no scheme/host/port
      sb.append('/');
    }
    sb.append(d.getPath());
    if (params != null) {
      sb.append('?');
      sb.append(params);
    }
    return sb.toString();
  }

  String srvUrlStem(String host) {
    if (host == null) {
      return null;
    }
    StringBuilder sb = new StringBuilder();
    sb.append(reqURL.getProtocol());
    sb.append("://");
    sb.append(host);
    sb.append(':');
    sb.append(reqURL.getPort());
    return sb.toString();
  }

  /** Return a link to a servlet */
  String srvLink(ServletDescr d, String text) {
    return srvLink(d, text, (String) null);
  }

  /** Return a link to a servlet with params */
  String srvLink(ServletDescr d, String text, String params) {
    return new Link(srvURL(d, params), (text != null ? text : d.heading)).toString();
  }

  /** Return a link to a servlet with params */
  String srvLink(ServletDescr d, String text, Properties params) {
    return new Link(srvURL(d, params), text).toString();
  }

  /** Return an absolute link to a servlet with params */
  String srvAbsLink(ServletDescr d, String text, Properties params) {
    return srvAbsLink(d, text, concatParams(params));
  }

  /** Return an absolute link to a servlet with params */
  String srvAbsLink(ServletDescr d, String text, String params) {
    return new Link(srvAbsURL(d, params), (text != null ? text : d.heading)).toString();
  }

  /** Return an absolute link to a servlet with params */
  String srvAbsLink(String host, ServletDescr d, String text, String params) {
    return new Link(srvURL(host, d, params), (text != null ? text : d.heading)).toString();
  }

  /** Return an absolute link to a servlet with params */
  String srvAbsLink(PeerIdentity peer, ServletDescr d, String text, String params) {
    return new Link(srvURL(peer, d, params), (text != null ? text : d.heading)).toString();
  }

  /** Return text as a link iff isLink */
  String conditionalSrvLink(ServletDescr d, String text, String params, boolean isLink) {
    if (isLink) {
      return srvLink(d, text, params);
    } else {
      return text;
    }
  }

  /** Return text as a link iff isLink */
  String conditionalSrvLink(ServletDescr d, String text, boolean isLink) {
    return conditionalSrvLink(d, text, null, isLink);
  }

  /** Concatenate params for URL string */
  static String concatParams(String p1, String p2) {
    if (StringUtil.isNullString(p1)) {
      return p2;
    }
    if (StringUtil.isNullString(p2)) {
      return p1;
    }
    return p1 + "&" + p2;
  }

  /** Concatenate params for URL string */
  String concatParams(Properties props) {
    if (props == null) {
      return null;
    }
    java.util.List list = new ArrayList();
    for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
      String key = (String) iter.next();
      String val = props.getProperty(key);
      if (!StringUtil.isNullString(val)) {
        list.add(key + "=" + urlEncode(val));
      }
    }
    return StringUtil.separatedString(list, "&");
  }

  String modifyParams(String key, String val) {
    Properties props = getParamsAsProps();
    props.setProperty(key, val);
    return concatParams(props);
  }

  /**
   * Return the request parameters as a Properties. Only the first value of multivalued parameters
   * is included.
   */
  Properties getParamsAsProps() {
    Properties props = new Properties();
    for (Enumeration en = req.getParameterNames(); en.hasMoreElements(); ) {
      String name = (String) en.nextElement();
      props.setProperty(name, req.getParameter(name));
    }
    return props;
  }

  /**
   * Return the request parameters as a Map<String,String>. Only the first value of multivalued
   * parameters is included.
   */
  Map<String, String> getParamsAsMap() {
    Map<String, String> map = new HashMap<String, String>();
    for (Enumeration en = req.getParameterNames(); en.hasMoreElements(); ) {
      String name = (String) en.nextElement();
      map.put(name, req.getParameter(name));
    }
    return map;
  }

  protected String urlEncode(String param) {
    return UrlUtil.encodeUrl(param);
  }

  protected String getRequestKey() {
    String key = req.getPathInfo();
    if (key != null && key.startsWith("/")) {
      return key.substring(1);
    }
    return key;
  }

  /** Common page setup. */
  protected Page newPage() {
    // Compute heading
    String heading = getHeading();
    if (heading == null) {
      heading = "Box Administration";
    }

    // Create page and layout header
    Page page = ServletUtil.doNewPage(getPageTitle(), isFramed());
    Iterator inNavIterator;
    if (myServletDescr().hasNoNavTable()) {
      inNavIterator = CollectionUtil.EMPTY_ITERATOR;
    } else {
      inNavIterator =
          new FilterIterator(
              new ObjectArrayIterator(getServletDescrs()),
              new Predicate() {
                public boolean evaluate(Object obj) {
                  return isServletInNav((ServletDescr) obj);
                }
              });
    }
    ServletUtil.layoutHeader(
        this,
        page,
        heading,
        isLargeLogo(),
        getMachineName(),
        getLockssApp().getStartDate(),
        inNavIterator);
    String warnMsg = CurrentConfig.getParam(PARAM_UI_WARNING);
    if (warnMsg != null) {
      Composite warning = new Composite();
      warning.add("<center><font color=red size=+1>");
      warning.add(warnMsg);
      warning.add("</font></center><br>");
      page.add(warning);
    }
    return page;
  }

  protected Page addBarePageHeading(Page page) {
    // FIXME: Move the following fragment elsewhere
    // It causes the doctype statement to appear in the middle,
    // after the <body> tag.
    page.add("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">");
    page.addHeader("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">");
    page.addHeader("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">");
    page.addHeader("<link rel=\"shortcut icon\" href=\"/favicon.ico\" type=\"image/x-icon\" />");
    return page;
  }

  private boolean isFramed = false;

  protected String errMsg;

  protected String statusMsg;

  protected boolean isFramed() {
    return isFramed;
  }

  protected void setFramed(boolean v) {
    isFramed = v;
  }

  protected String getPageTitle() {
    String heading = getHeading();
    if (heading != null) {
      return "LOCKSS: " + heading;
    } else {
      return "LOCKSS";
    }
  }

  /** Return a button that invokes the javascript submit routine with the specified action */
  protected Element submitButton(String label, String action) {
    return submitButton(label, action, null, null);
  }

  /** Return a button that invokes javascript when clicked. */
  Input jsButton(String label, String js) {
    Input btn = new Input("button", null);
    btn.attribute("value", label);
    setTabOrder(btn);
    btn.attribute("onClick", js);
    return btn;
  }

  /**
   * Return a button that invokes the javascript submit routine with the specified action, first
   * storing the value in the specified form prop.
   */
  protected Element submitButton(String label, String action, String prop, String value) {
    StringBuilder sb = new StringBuilder(40);
    sb.append("lockssButton(this, '");
    sb.append(action);
    sb.append("'");
    if (prop != null && value != null) {
      sb.append(", '");
      sb.append(prop);
      sb.append("', '");
      sb.append(value);
      sb.append("'");
    }
    sb.append(")");
    Input btn = jsButton(label, sb.toString());
    btn.attribute("id", "lsb." + (++submitButtonNumber));
    return btn;
  }

  /**
   * Return a (possibly labelled) checkbox.
   *
   * @param label appears to right of checkbox if non null
   * @param value value included in result set if box checked
   * @param key form key to which result set is assigned
   * @param checked if true, box is initially checked
   * @return a checkbox Element
   */
  Element checkBox(String label, String value, String key, boolean checked) {
    Input in = new Input(Input.Checkbox, key, value);
    if (checked) {
      in.check();
    }
    setTabOrder(in);
    if (StringUtil.isNullString(label)) {
      return in;
    } else {
      Composite c = new Composite();
      c.add(in);
      c.add(" ");
      c.add(label);
      return c;
    }
  }

  /**
   * Return a labelled rasio button
   *
   * @param label label to right of circle, and form value if checked
   * @param key form key to which value is assigned
   * @param checked if true, is initially checked
   * @return a readio button Element
   */
  protected Element radioButton(String label, String key, boolean checked) {
    return radioButton(label, label, key, checked);
  }

  /**
   * Return a labelled rasio button
   *
   * @param label appears to right of circle if non null
   * @param value value assigned to key if box checked
   * @param key form key to which value is assigned
   * @param checked if true, is initially checked
   * @return a readio button Element
   */
  protected Element radioButton(String label, String value, String key, boolean checked) {
    Composite c = new Composite();
    Input in = new Input(Input.Radio, key, value);
    if (checked) {
      in.check();
    }
    setTabOrder(in);
    c.add(in);
    c.add(label);
    return c;
  }

  /** Add html tags to grey the text if isGrey is true */
  protected String greyText(String txt, boolean isGrey) {
    if (!isGrey) {
      return txt;
    }
    return "<font color=gray>" + txt + "</font>";
  }

  /**
   * Set this element next in the tab order. Returns the element for easier nesting in expressions.
   */
  protected Element setTabOrder(Element ele) {
    ele.attribute("tabindex", tabindex++);
    return ele;
  }

  /**
   * Store a footnote, assign it a number, return html for footnote reference. If footnote in null
   * or empty, no footnote is added and an empty string is returned. Footnote numbers get turned
   * into links; <b>Do not put the result of addFootnote inside a link!</b>.
   */
  protected String addFootnote(String s) {
    if (s == null || s.length() == 0) {
      return "";
    }
    if (footNumber == 0) {
      if (footnotes == null) {
        footnotes = new Vector(10, 10);
      } else {
        footnotes.removeAllElements();
      }
    }
    int n = footnotes.indexOf(s);
    if (n < 0) {
      n = footNumber++;
      footnotes.addElement(s);
    }
    return "<sup><font size=-1><a href=#foottag" + (n + 1) + ">" + (n + 1) + "</a></font></sup>";
  }

  /**
   * Add javascript to page. Normally adds a link to the script file, but can be told to include the
   * script directly in the page, to accomodate unit testing of individual servlets, when other
   * fetches won't work.
   */
  protected void addJavaScript(Composite comp) {
    String include = (String) context.getAttribute(ATTR_INCLUDE_SCRIPT);
    if (StringUtil.isNullString(include)) {
      linkToJavaScript(comp);
    } else {
      includeJavaScript0(comp);
    }
  }

  private void includeJavaScript0(Composite comp) {
    Script script = new Script(getJavascript());
    comp.add(script);
  }

  private void linkToJavaScript(Composite comp) {
    Script script = new Script("");
    script.attribute("src", "admin.js");
    comp.add(script);
  }

  private static String jstext = null;

  private static synchronized String getJavascript() {
    if (jstext == null) {
      InputStream istr = null;
      try {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        istr = loader.getResourceAsStream(JAVASCRIPT_RESOURCE);
        jstext = StringUtil.fromInputStream(istr);
        istr.close();
      } catch (Exception e) {
        log.error("Can't load javascript", e);
      } finally {
        IOUtil.safeClose(istr);
      }
    }
    return jstext;
  }

  /** Display a message in lieu of the normal page */
  protected void displayMsgInLieuOfPage(String msg) throws IOException {
    // TODO: Look at HTML
    Page page = newPage();
    Composite warning = new Composite();
    warning.add(msg);
    warning.add("<br>");
    page.add(warning);
    layoutFooter(page);
    page.write(resp.getWriter());
  }

  /** Display a warning in red, in lieu of the normal page */
  protected void displayWarningInLieuOfPage(String msg) throws IOException {
    displayMsgInLieuOfPage("<center><font color=red size=+1>" + msg + "</font></center>");
  }

  /** Display "The cache isn't ready yet, come back later" */
  protected void displayNotStarted() throws IOException {
    displayWarningInLieuOfPage(
        "This LOCKSS box is still starting.  Please "
            + srvLink(myServletDescr(), "try again", getParamsAsProps())
            + " in a moment.");
  }

  public MultiPartRequest getMultiPartRequest() throws FormDataTooLongException, IOException {
    int maxUpload =
        CurrentConfig.getIntParam(PARAM_MAX_UPLOAD_FILE_SIZE, DEFAULT_MAX_UPLOAD_FILE_SIZE);
    return getMultiPartRequest(maxUpload);
  }

  public MultiPartRequest getMultiPartRequest(int maxLen)
      throws FormDataTooLongException, IOException {
    if (req.getContentType() == null || !req.getContentType().startsWith("multipart/form-data")) {
      return null;
    }
    if (req.getContentLength() > maxLen) {
      throw new FormDataTooLongException(req.getContentLength() + " bytes, " + maxLen + " allowed");
    }
    MultiPartRequest multi = new MultiPartRequest(req);
    if (log.isDebug2()) {
      String[] parts = multi.getPartNames();
      log.debug3("Multipart request, " + parts.length + " parts");
      if (log.isDebug3()) {
        for (int p = 0; p < parts.length; p++) {
          String name = parts[p];
          String cont = multi.getString(parts[p]);
          log.debug3(name + ": " + cont);
        }
      }
    }
    multiReq = multi;
    return multi;
  }

  public String getParameter(String name) {
    String val = req.getParameter(name);
    if (val == null && multiReq != null) {
      val = multiReq.getString(name);
    }
    if (val == null) {
      return null;
    }
    val = StringUtils.strip(val, " \t");
    //     if (StringUtil.isNullString(val)) {
    if ("".equals(val)) {
      return null;
    }
    return val;
  }

  protected void layoutFooter(Page page) {
    ServletUtil.doLayoutFooter(
        page, (footnotes == null ? null : footnotes.iterator()), getLockssApp().getVersionInfo());
    if (footnotes != null) {
      footnotes.removeAllElements();
    }
  }

  /** Return the app instance. */
  protected LockssApp getLockssApp() {
    return theApp;
  }

  /**
   * Return the daemon instance, assumes that the servlet is running in the daemon.
   *
   * @throws ClassCastException if the servlet is running in an app other than the daemon
   */
  protected LockssDaemon getLockssDaemon() {
    return (LockssDaemon) theApp;
  }

  protected void logParams() {
    Enumeration en = req.getParameterNames();
    while (en.hasMoreElements()) {
      String name = (String) en.nextElement();
      String vals[];
      String dispval;
      if (StringUtil.indexOfIgnoreCase(name, "passw") >= 0) {
        dispval = req.getParameter(name).length() == 0 ? "" : "********";
      } else if (log.isDebug2() && (vals = req.getParameterValues(name)).length > 1) {
        dispval = StringUtil.separatedString(vals, ", ");
      } else {
        dispval = req.getParameter(name);
      }
      log.debug(name + " = " + dispval);
    }
  }

  /** Convenience method */
  protected String encodeText(String s) {
    return HtmlUtil.encode(s, HtmlUtil.ENCODE_TEXT);
  }

  /** Convenience method */
  protected String encodeTextArea(String s) {
    return HtmlUtil.encode(s, HtmlUtil.ENCODE_TEXTAREA);
  }

  /** Convenience method */
  protected String encodeAttr(String s) {
    return HtmlUtil.encode(s, HtmlUtil.ENCODE_ATTR);
  }

  /**
   * Create message and error message block
   *
   * @param composite TODO
   */
  protected void layoutErrorBlock(Composite composite) {
    if (errMsg != null || statusMsg != null) {
      ServletUtil.layoutErrorBlock(composite, errMsg, statusMsg);
    }
  }

  /** Exception thrown if multipart form data is longer than the caller-supplied max */
  public static class FormDataTooLongException extends Exception {
    public FormDataTooLongException(String message) {
      super(message);
    }
  }
}
Esempio n. 29
0
/** @author james.bloom */
public class SocketManager implements Runnable {
  private static Logger dLog = Logger.getLogger(SocketManager.class);
  private Socket socket = null;
  private ObjectInputStream in = null;
  private ObjectOutputStream out = null;
  private boolean exit = false;
  private boolean auth = false;
  private User tUser;
  private List<User> users;
  private static String SOCKET_PORT;
  private StatusUI parent;
  private IUserSvc userSvc;

  // Spring configuration
  private static final String SPRING_CONFIG_DEFAULT = "applicationContext.xml";

  public SocketManager(Socket socket) {
    this.socket = socket;

    users = new ArrayList<User>();
    tUser = new User();

    // Spring Framework IoC
    ClassPathXmlApplicationContext beanfactory = null;
    try {
      beanfactory = new ClassPathXmlApplicationContext(SPRING_CONFIG_DEFAULT);
      userSvc = (IUserSvc) beanfactory.getBean("userSvc");

    } catch (Exception e) {
      dLog.error("Unable to configure Spring beans", e);
    } finally {
      if (beanfactory != null) {
        beanfactory.close();
      }
    }

    dLog.trace("In constructor");
  }

  public SocketManager(Socket socket, StatusUI parent) {
    this(socket);
    this.parent = parent;
  }

  public void close() throws IOException {
    if (in != null) {
      in.close();
    }
    if (out != null) {
      out.close();
    }
    if (socket != null && !socket.isClosed()) {
      socket.close();
    }
  }

  @Override
  public void run() {
    SOCKET_PORT = String.valueOf(socket.getRemoteSocketAddress());
    dLog.trace("Starting to run server");
    // get all users
    try {
      users = userSvc.getAllUsers();
    } catch (Exception e2) {
      dLog.error("Unable to get all users", e2);
    }
    dLog.trace("Got " + users.size() + " users");

    try {
      while (!exit) {
        out = new ObjectOutputStream(socket.getOutputStream());
        in = new ObjectInputStream(socket.getInputStream());
        dLog.trace("Successfully got input/output streams");

        String inputStr = "";
        out.writeObject("Burrito POS Server Connected. Enter Username: "******"OUTPUT | Burrito POS Server Connected. Enter Username: "******"OUTPUT | Burrito POS Server Connected. Enter Username: "******"INPUT | " + inputStr);
        parent.updateStatus(appendInfo("INPUT | " + inputStr));

        while (!inputStr.equals("exit") && !this.exit) {
          dLog.trace("Exit? " + exit);
          if (tUser.getUserName() == null) {
            tUser.setUserName(inputStr);
            out.writeObject("OK User " + inputStr + ", enter password: "******"OUTPUT | OK User " + inputStr + ", enter password: "******"OUTPUT | Burrito POS Server Connected. Enter Username: "******"Username: "******" | Password: "******"Stored user: "******" | stored pass: "******"OK User verified. Enter command: ");
              dLog.trace("OUTPUT | OK User verified. Enter command: ");
              parent.updateStatus(appendInfo("OUTPUT | OK User verified. Enter command: "));
              auth = true;
            } else {
              tUser.setUserName(null);
              tUser.setPassword(null);
              out.writeObject("ERROR Invalid Credentials. Enter Username: "******"OUTPUT | ERROR Invalid Credentials. Enter Username: "******"OUTPUT | ERROR Invalid Credentials. Enter Username: "******"exit")) {
              out.writeObject("OK Command " + inputStr + " entered. Enter command: ");
              dLog.trace("OUTPUT | OK Command " + inputStr + " entered. Enter command: ");
              parent.updateStatus(
                  appendInfo("OUTPUT | OK Command " + inputStr + " entered. Enter command: "));
            }
          }

          inputStr = (String) in.readObject();
          dLog.trace("INPUT | " + inputStr);
          parent.updateStatus(appendInfo("INPUT | " + inputStr));
        }

        exit = true;
        try {
          dLog.trace("Closing the socket");
          auth = false;
          out.writeObject("Exiting");
          dLog.trace("Exiting");
          parent.updateStatus(appendInfo("Exiting"));
          this.close();
        } catch (Exception e1) {
          dLog.error("Exception in closing socket", e1);
        }
      }
    } catch (Exception e) {
      dLog.error("Exception in SocketManager run", e);
    }
  }

  public void setExit(boolean exit) {
    dLog.trace("setExit: " + exit);
    this.exit = exit;
  }

  public boolean getExit() {
    return this.exit;
  }

  /**
   * Append some additional information to info messages to help better track requests as they come
   * across the UI
   *
   * @param msg
   * @return
   */
  private String appendInfo(String msg) {
    return new Date() + " | " + SOCKET_PORT + " | " + msg;
  }
}
Esempio n. 30
0
/**
 * HostInfo information on the local host to be able to cope with change of addresses.
 *
 * @version %I%, %G%
 * @author Pierre Frisch, Werner Randelshofer
 */
class HostInfo {
  private static Logger logger = Logger.getLogger(HostInfo.class.toString());
  protected String name;
  protected InetAddress address;
  protected NetworkInterface interfaze;
  /** This is used to create a unique name for the host name. */
  private int hostNameCount;

  public HostInfo(InetAddress address, String name) {
    super();

    String SLevel = System.getProperty("jmdns.debug");
    if (SLevel == null) SLevel = "INFO";
    logger.setLevel(Level.parse(SLevel));

    this.address = address;
    this.name = name;
    if (address != null) {
      try {
        interfaze = NetworkInterface.getByInetAddress(address);
      } catch (Exception exception) {
        // FIXME Shouldn't we take an action here?
        logger.log(Level.WARNING, "LocalHostInfo() exception ", exception);
      }
    }
  }

  public String getName() {
    return name;
  }

  public InetAddress getAddress() {
    return address;
  }

  public NetworkInterface getInterface() {
    return interfaze;
  }

  synchronized String incrementHostName() {
    hostNameCount++;
    int plocal = name.indexOf(".local.");
    int punder = name.lastIndexOf("-");
    name = name.substring(0, (punder == -1 ? plocal : punder)) + "-" + hostNameCount + ".local.";
    return name;
  }

  boolean shouldIgnorePacket(DatagramPacket packet) {
    boolean result = false;
    if (getAddress() != null) {
      InetAddress from = packet.getAddress();
      if (from != null) {
        if (from.isLinkLocalAddress() && (!getAddress().isLinkLocalAddress())) {
          // Ignore linklocal packets on regular interfaces, unless this is
          // also a linklocal interface. This is to avoid duplicates. This is
          // a terrible hack caused by the lack of an API to get the address
          // of the interface on which the packet was received.
          result = true;
        }
        if (from.isLoopbackAddress() && (!getAddress().isLoopbackAddress())) {
          // Ignore loopback packets on a regular interface unless this is
          // also a loopback interface.
          result = true;
        }
      }
    }
    return result;
  }

  DNSRecord.Address getDNSAddressRecord(DNSRecord.Address address) {
    return (DNSConstants.TYPE_AAAA == address.type
        ? getDNS6AddressRecord()
        : getDNS4AddressRecord());
  }

  DNSRecord.Address getDNS4AddressRecord() {
    if ((getAddress() != null)
        && ((getAddress() instanceof Inet4Address)
            || ((getAddress() instanceof Inet6Address)
                && (((Inet6Address) getAddress()).isIPv4CompatibleAddress())))) {
      return new DNSRecord.Address(
          getName(),
          DNSConstants.TYPE_A,
          DNSConstants.CLASS_IN,
          DNSConstants.DNS_TTL,
          getAddress());
    }
    return null;
  }

  DNSRecord.Address getDNS6AddressRecord() {
    if ((getAddress() != null) && (getAddress() instanceof Inet6Address)) {
      return new DNSRecord.Address(
          getName(),
          DNSConstants.TYPE_AAAA,
          DNSConstants.CLASS_IN,
          DNSConstants.DNS_TTL,
          getAddress());
    }
    return null;
  }

  public String toString() {
    StringBuffer buf = new StringBuffer();
    buf.append("local host info[");
    buf.append(getName() != null ? getName() : "no name");
    buf.append(", ");
    buf.append(getInterface() != null ? getInterface().getDisplayName() : "???");
    buf.append(":");
    buf.append(getAddress() != null ? getAddress().getHostAddress() : "no address");
    buf.append("]");
    return buf.toString();
  }
}