You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2014/09/11 23:21:24 UTC

git commit: [SSHD-69] Unix ssh agent leaks /tmp/mina*apr sockets and threads

Repository: mina-sshd
Updated Branches:
  refs/heads/master 44597914e -> 635de65ff


[SSHD-69] Unix ssh agent leaks /tmp/mina*apr sockets and threads


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/635de65f
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/635de65f
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/635de65f

Branch: refs/heads/master
Commit: 635de65ffcb278e76adddd1be86c6df726537d9e
Parents: 4459791
Author: Guillaume Nodet <gn...@apache.org>
Authored: Thu Sep 11 23:21:14 2014 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Thu Sep 11 23:21:14 2014 +0200

----------------------------------------------------------------------
 .../sshd/agent/unix/AgentServerProxy.java       | 139 ++++++++++++++-----
 1 file changed, 108 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/635de65f/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
index f358740..69322f6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
@@ -18,13 +18,14 @@
  */
 package org.apache.sshd.agent.unix;
 
+import java.io.File;
 import java.io.IOException;
 
 import org.apache.sshd.agent.SshAgentServer;
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.session.ConnectionService;
-import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.common.util.OsUtils;
 import org.apache.tomcat.jni.Local;
 import org.apache.tomcat.jni.Pool;
 import org.apache.tomcat.jni.Socket;
@@ -40,19 +41,27 @@ public class AgentServerProxy implements SshAgentServer {
     private static final Logger LOG = LoggerFactory.getLogger(AgentServerProxy.class);
 
     private final ConnectionService service;
-    private String authSocket;
-    private long pool;
-    private long handle;
-    private Thread thread;
-    private boolean closed;
+    private final String authSocket;
+    private final long pool;
+    private final long handle;
+    private final Thread thread;
+    private volatile boolean closed;
+    private volatile boolean innerFinished;
+
+    //used to wake the Local.listen() JNI call
+    private static final byte[] END_OF_STREAM_MESSAGE = new byte[] { "END_OF_STREAM".getBytes()[0] };
 
     public AgentServerProxy(ConnectionService service) throws IOException {
         this.service = service;
         try {
             String authSocket = AprLibrary.createLocalSocketAddress();
+
             pool = Pool.create(AprLibrary.getInstance().getRootPool());
             handle = Local.create(authSocket, pool);
+            this.authSocket = authSocket;
+
             int result = Local.bind(handle, 0);
+
             if (result != Status.APR_SUCCESS) {
                 throwException(result);
             }
@@ -61,34 +70,39 @@ public class AgentServerProxy implements SshAgentServer {
             if (result != Status.APR_SUCCESS) {
                 throwException(result);
             }
-            thread = new Thread() {
+            thread = new Thread("sshd-AgentServerProxy-PIPE-" + authSocket) {
+                @Override
                 public void run() {
-                    while (!closed) {
-                        try {
-                            long clientSock = Local.accept(handle);
-                            if (closed) {
-                                break;
-                            }
-                            Socket.timeoutSet(clientSock, 10000000);
-                            AgentForwardedChannel channel = new AgentForwardedChannel(clientSock);
-                            AgentServerProxy.this.service.registerChannel(channel);
-                            OpenFuture future = channel.open().await();
-                            Throwable t = future.getException();
-                            if (t instanceof Exception) {
-                                throw (Exception) t;
-                            } else if (t != null) {
-                                throw new Exception(t);
-                            }
-                        } catch (Exception e) {
-                            if (!closed) {
-                                LOG.info("Exchange caught in authentication forwarding", e);
+                    try {
+                        while (!closed) {
+                            try {
+                                long clientSock = Local.accept(handle);
+                                if (closed) {
+                                    break;
+                                }
+                                Socket.timeoutSet(clientSock, 10000000);
+                                AgentForwardedChannel channel = new AgentForwardedChannel(clientSock);
+                                AgentServerProxy.this.service.registerChannel(channel);
+                                OpenFuture future = channel.open().await();
+                                Throwable t = future.getException();
+                                if (t instanceof Exception) {
+                                    throw (Exception) t;
+                                } else if (t != null) {
+                                    throw new Exception(t);
+                                }
+                            } catch (Exception e) {
+                                if (!closed) {
+                                    LOG.info("Exchange caught in authentication forwarding", e);
+                                }
                             }
                         }
+                    } finally {
+                        innerFinished = true;
                     }
                 }
             };
+            thread.setDaemon(true);
             thread.start();
-            this.authSocket = authSocket;
         } catch (IOException e) {
             throw e;
         } catch (Exception e) {
@@ -101,9 +115,74 @@ public class AgentServerProxy implements SshAgentServer {
     }
 
     public synchronized void close() {
+        if (closed) {
+            return;
+        }
         closed = true;
+        final boolean isDebug = LOG.isDebugEnabled();
+
         if (handle != 0) {
-            Socket.close(handle);
+            if (!innerFinished) {
+                try {
+
+                    final long tmpPool = Pool.create(AprLibrary.getInstance().getRootPool());
+                    final long tmpSocket = Local.create(authSocket, tmpPool);
+                    long connectResult = Local.connect(tmpSocket, 0);
+
+                    if (connectResult != Status.APR_SUCCESS) {
+                        if (isDebug) {
+                            LOG.debug("Unable to connect to socket PIPE {}. APR errcode {}", authSocket, connectResult);
+                        }
+                    }
+
+                    //write a single byte -- just wake up the accept()
+                    int sendResult = Socket.send(tmpSocket, END_OF_STREAM_MESSAGE, 0, 1);
+                    if (sendResult != 1) {
+                        if (isDebug) {
+                            LOG.debug("Unable to send signal the EOS for {}. APR retcode {} != 1", authSocket,
+                                    sendResult);
+                        }
+                    }
+                } catch (Exception e) {
+                    //log eventual exceptions in debug mode
+                    if (isDebug) {
+                        LOG.debug("Exception connecting to the PIPE socket: " + authSocket, e);
+                    }
+                }
+            }
+
+            final int closeCode = Socket.close(handle);
+            if (closeCode != Status.APR_SUCCESS) {
+                LOG.warn("Exceptions closing the PIPE: {}. APR error code: {} ", authSocket, closeCode);
+            }
+        }
+
+        try {
+            if (authSocket != null) {
+
+                final File socketFile = new File(authSocket);
+                if (socketFile.exists()) {
+                    if (socketFile.delete()) {
+                        if (isDebug) {
+                            LOG.debug("Deleted PIPE socket {}", socketFile);
+                        }
+                    }
+
+                    if (OsUtils.isUNIX()) {
+                        final File parentFile = socketFile.getParentFile();
+                        if (parentFile.delete()) {
+                            if (isDebug) {
+                                LOG.debug("Deleted parent PIPE socket {}", parentFile);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            //log eventual exceptions in debug mode
+            if (isDebug) {
+                LOG.debug("Exception deleting the PIPE socket: " + authSocket, e);
+            }
         }
     }
 
@@ -113,9 +192,7 @@ public class AgentServerProxy implements SshAgentServer {
      * @throws java.io.IOException the produced exception for the given APR error number
      */
     static void throwException(int code) throws IOException {
-        throw new IOException(
-                org.apache.tomcat.jni.Error.strerror(-code) +
-                " (code: " + code + ")");
+        throw new IOException(org.apache.tomcat.jni.Error.strerror(-code) + " (code: " + code + ")");
     }
 
 }