[libbluray-devel] Close Xlet sockets when it is terminated

hpi1 git at videolan.org
Wed Oct 29 14:00:41 CET 2014


libbluray | branch: master | hpi1 <hpi1 at anonymous.org> | Wed Oct 29 14:51:15 2014 +0200| [6bfd1d1141a5a53339ec26705ae63eaeb7ff4d8f] | committer: hpi1

Close Xlet sockets when it is terminated

> http://git.videolan.org/gitweb.cgi/libbluray.git/?a=commit;h=6bfd1d1141a5a53339ec26705ae63eaeb7ff4d8f
---

 .../bdj/java/org/videolan/BDJAppProxy.java         |    1 +
 .../bdj/java/org/videolan/BDJSocketFactory.java    |   79 +++++++++++++++++
 .../bdj/java/org/videolan/BDJSockets.java          |   89 ++++++++++++++++++++
 .../bdj/java/org/videolan/BDJXletContext.java      |   14 +++
 src/libbluray/bdj/java/org/videolan/Libbluray.java |    2 +
 5 files changed, 185 insertions(+)

diff --git a/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java b/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java
index 5da21b6..ccefb8a 100644
--- a/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java
+++ b/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java
@@ -238,6 +238,7 @@ public class BDJAppProxy implements DVBJProxy, Runnable {
             try {
                 xlet.destroyXlet(force);
 
+                context.closeSockets();
                 context.getThreadGroup().waitForShutdown(1000, 1 + context.numEventQueueThreads());
 
                 String persistent = System.getProperty("dvb.persistent.root") + File.separator +
diff --git a/src/libbluray/bdj/java/org/videolan/BDJSocketFactory.java b/src/libbluray/bdj/java/org/videolan/BDJSocketFactory.java
new file mode 100644
index 0000000..876a9d9
--- /dev/null
+++ b/src/libbluray/bdj/java/org/videolan/BDJSocketFactory.java
@@ -0,0 +1,79 @@
+/*
+ * This file is part of libbluray
+ * Copyright (C) 2014  Petri Hintukainen <phintuka at users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+package org.videolan;
+
+import java.io.IOException;
+
+import java.lang.reflect.Constructor;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketImpl;
+import java.net.SocketImplFactory;
+
+class BDJSocketFactory implements SocketImplFactory {
+
+    protected static void init() {
+        try {
+            Socket.setSocketImplFactory(new BDJSocketFactory(false));
+            ServerSocket.setSocketFactory(new BDJSocketFactory(true));
+        } catch (IOException e) {
+            logger.error("Failed to hook SocketFactory: " + e);
+        }
+    }
+
+    private BDJSocketFactory(boolean server) {
+        this.server = server;
+    }
+
+    private SocketImpl newSocket() {
+        try {
+            Class defaultSocketImpl = Class.forName("java.net.SocksSocketImpl");
+            Constructor constructor = defaultSocketImpl.getDeclaredConstructor/*s*/(new Class[0])/*[0]*/;
+            constructor.setAccessible(true);
+            return (SocketImpl) constructor.newInstance(new Object[0]);
+        } catch (Exception e) {
+            logger.error("Failed to create socket: " + e + " at " + logger.dumpStack());
+            throw new RuntimeException(e);
+        }
+    }
+
+    public SocketImpl createSocketImpl() {
+
+        if (server) {
+            logger.error("Xlet tried to create server socket");
+            throw new RuntimeException("server sockets disabled");
+        }
+
+        SocketImpl socket = newSocket();
+        BDJXletContext ctx = BDJXletContext.getCurrentContext();
+        if (ctx != null) {
+            logger.info("Xlet " + ctx + " created new socket");
+            ctx.addSocket(socket);
+        } else {
+            logger.error("New socket created outside of Xlet context: " + logger.dumpStack());
+        }
+        return socket;
+    }
+
+    private boolean server = false;
+
+    private static final Logger logger = Logger.getLogger(BDJSocketFactory.class.getName());
+}
diff --git a/src/libbluray/bdj/java/org/videolan/BDJSockets.java b/src/libbluray/bdj/java/org/videolan/BDJSockets.java
new file mode 100644
index 0000000..0395399
--- /dev/null
+++ b/src/libbluray/bdj/java/org/videolan/BDJSockets.java
@@ -0,0 +1,89 @@
+/*
+ * This file is part of libbluray
+ * Copyright (C) 2014  Petri Hintukainen <phintuka at users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+package org.videolan;
+
+import java.lang.reflect.Method;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import java.net.Socket;
+import java.net.SocketImpl;
+
+class BDJSockets {
+
+    protected BDJSockets() {
+    }
+
+    protected synchronized void add(Object obj) {
+        if (!(obj instanceof SocketImpl)) {
+            throw new Error("expected SocketImpl");
+        }
+
+        if (closed) {
+            logger.error("Terminated Xlet tried to create socket at " + logger.dumpStack());
+            throw new Error("Terminated Xlet can not create sockets");
+        }
+
+        /* drop closed sockets */
+        for (Iterator it = sockets.iterator(); it.hasNext(); ) {
+            SocketImpl socketImpl = (SocketImpl)it.next();
+            Socket     socket = getSocket(socketImpl);
+            if (socket != null && socket.isClosed()) {
+                it.remove();
+            }
+        }
+
+        sockets.addLast(obj);
+    }
+
+    protected synchronized void closeAll() {
+        closed = true;
+
+        while (!sockets.isEmpty()) {
+            SocketImpl socketImpl = (SocketImpl)sockets.removeFirst();
+            Socket socket = getSocket(socketImpl);
+            if (socket != null && !socket.isClosed()) {
+                logger.warning("Closing " + socket);
+                try {
+                    socket.close();
+                } catch (Exception e) {
+                    logger.error("Failed to close socket: " + e);
+                }
+            }
+        }
+    }
+
+    private Socket getSocket(SocketImpl socketImpl) {
+        try {
+            Method getSocket = SocketImpl.class.getDeclaredMethod("getSocket", new Class[0]);
+            getSocket.setAccessible(true);
+            return (Socket) getSocket.invoke(socketImpl, new Object[0]);
+        } catch (Exception e) {
+            logger.error("Failed to get Socket: " + e + " at " + logger.dumpStack());
+            return null;
+        }
+    }
+
+    private LinkedList sockets = new LinkedList();
+    private boolean    closed  = false;
+
+    private static final Logger logger = Logger.getLogger(BDJSockets.class.getName());
+}
diff --git a/src/libbluray/bdj/java/org/videolan/BDJXletContext.java b/src/libbluray/bdj/java/org/videolan/BDJXletContext.java
index d1208f6..65a6281 100644
--- a/src/libbluray/bdj/java/org/videolan/BDJXletContext.java
+++ b/src/libbluray/bdj/java/org/videolan/BDJXletContext.java
@@ -263,6 +263,18 @@ public class BDJXletContext implements javax.tv.xlet.XletContext, javax.microedi
     }
 
     /*
+     * sockets
+     */
+
+    protected void addSocket(Object socket) {
+        sockets.add(socket);
+    }
+
+    protected void closeSockets() {
+        sockets.closeAll();
+    }
+
+    /*
      * Ixc
      */
 
@@ -383,6 +395,7 @@ public class BDJXletContext implements javax.tv.xlet.XletContext, javax.microedi
 
     protected void release() {
 
+        closeSockets();
         removeAllFAA();
         stopIxcThreads();
         defaultLooks.clear();
@@ -424,6 +437,7 @@ public class BDJXletContext implements javax.tv.xlet.XletContext, javax.microedi
     private BDJThreadGroup threadGroup = null;
     private LinkedList ixcThreads = new LinkedList();
     private LinkedList faaList = new LinkedList();
+    private BDJSockets sockets = new BDJSockets();
     private HashMap defaultLooks = new HashMap();
     private BDJActionQueue callbackQueue;
     private static final Logger logger = Logger.getLogger(BDJXletContext.class.getName());
diff --git a/src/libbluray/bdj/java/org/videolan/Libbluray.java b/src/libbluray/bdj/java/org/videolan/Libbluray.java
index 2f1488a..2bb2fa8 100644
--- a/src/libbluray/bdj/java/org/videolan/Libbluray.java
+++ b/src/libbluray/bdj/java/org/videolan/Libbluray.java
@@ -130,6 +130,8 @@ public class Libbluray {
             System.setProperty("bluray.memory.font_cache", "4096");
 
             System.setProperty("bluray.network.connected", "YES");
+
+            BDJSocketFactory.init();
     }
 
     public static void shutdown() {



More information about the libbluray-devel mailing list