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); } }
// @Override public synchronized String getIP() { try { return NetUtils.getIPAddress(); } catch (ConnectException ex) { Logger.getLogger(Mapa.class.getName()).log(Level.SEVERE, null, ex); } return ""; }
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()); }
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(); }
/** * 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); } }
@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(); }
/** @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(); }
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"); }
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; } }
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; } } }
/** * 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; } }
/** * 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(); } }
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; } } }
/** * 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); } } } } }
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; } }
/** 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; } }; }
/** * 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); } } }
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); } }
/** * 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(); } }
/** 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); } } }
// 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); } } }
/** @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; } }
/** * 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(); } }