Author: norman
Date: Wed Nov 17 11:56:05 2010
New Revision: 1035990

URL: http://svn.apache.org/viewvc?rev=1035990&view=rev
Log:
Fix a deadlock which can cause the RETR and TOP command to just hang. This 
fixed JAMES-1136. Thx to Sylvain Vieujot for reporting

Added:
    
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonWaitingChannelOutputStream.java
      - copied, changed from r1033370, 
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonClosingChannelOutputStream.java
Removed:
    
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonClosingChannelOutputStream.java
Modified:
    
james/server/trunk/netty-socket/src/main/java/org/jboss/netty/handler/stream/ChannelOutputStream.java
    
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/POP3NettySession.java
    
james/server/trunk/pop3server/src/test/java/org/apache/james/pop3server/AbstractAsyncPOP3ServerTest.java

Modified: 
james/server/trunk/netty-socket/src/main/java/org/jboss/netty/handler/stream/ChannelOutputStream.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/netty-socket/src/main/java/org/jboss/netty/handler/stream/ChannelOutputStream.java?rev=1035990&r1=1035989&r2=1035990&view=diff
==============================================================================
--- 
james/server/trunk/netty-socket/src/main/java/org/jboss/netty/handler/stream/ChannelOutputStream.java
 (original)
+++ 
james/server/trunk/netty-socket/src/main/java/org/jboss/netty/handler/stream/ChannelOutputStream.java
 Wed Nov 17 11:56:05 2010
@@ -42,6 +42,9 @@ public class ChannelOutputStream extends
         this.channel = channel;
     }
 
+    /**
+     * As this use {...@link ChannelFuture#awaitUninterruptibly()} it should 
not be called from an I/O Thread! If so it will deadlock!
+     */
     @Override
     public void close() throws IOException {
         try {
@@ -75,6 +78,9 @@ public class ChannelOutputStream extends
         write(buf);
     }
 
+    /**
+     * As this use {...@link ChannelFuture#awaitUninterruptibly()} it should 
not be called from an I/O Thread! If so it will deadlock!
+     */
     @Override
     public synchronized void flush() throws IOException {
         if (lastChannelFuture == null) {

Copied: 
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonWaitingChannelOutputStream.java
 (from r1033370, 
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonClosingChannelOutputStream.java)
URL: 
http://svn.apache.org/viewvc/james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonWaitingChannelOutputStream.java?p2=james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonWaitingChannelOutputStream.java&p1=james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonClosingChannelOutputStream.java&r1=1033370&r2=1035990&rev=1035990&view=diff
==============================================================================
--- 
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonClosingChannelOutputStream.java
 (original)
+++ 
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/NonWaitingChannelOutputStream.java
 Wed Nov 17 11:56:05 2010
@@ -25,22 +25,31 @@ import org.jboss.netty.channel.Channel;
 import org.jboss.netty.handler.stream.ChannelOutputStream;
 
 /**
- * Allow to write via an {...@link OutputStream} to the underlying {...@link 
Channel}
+ * Allow to write via an {...@link OutputStream} to the underlying {...@link 
Channel}. All writes are just passed to the {...@link Channel} without waiting 
for 
+ * acknowledge. 
  *
  */
-public class NonClosingChannelOutputStream extends ChannelOutputStream{
+public class NonWaitingChannelOutputStream extends ChannelOutputStream{
 
-    public NonClosingChannelOutputStream(Channel channel) {
+    public NonWaitingChannelOutputStream(Channel channel) {
         super(channel);
     }
 
     /**
-     * Just flush the stream. This will NOT close the underlying Channel
+     * This will NOT close the underlying Channel
      * 
      */
     @Override
     public void close() throws IOException {
-        flush();
+        
+    }
+    
+
+    /**
+     * Every write is flushed so this will not do anything
+     */
+    @Override
+    public void flush() throws IOException {
     }
 
 }

Modified: 
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/POP3NettySession.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/POP3NettySession.java?rev=1035990&r1=1035989&r2=1035990&view=diff
==============================================================================
--- 
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/POP3NettySession.java
 (original)
+++ 
james/server/trunk/pop3server/src/main/java/org/apache/james/pop3server/netty/POP3NettySession.java
 Wed Nov 17 11:56:05 2010
@@ -44,7 +44,7 @@ public class POP3NettySession extends Ab
 
     private MessageManager mailbox;
 
-    private NonClosingChannelOutputStream out;
+    private NonWaitingChannelOutputStream out;
 
     public POP3NettySession(POP3HandlerConfigurationData configData, Log 
logger, ChannelHandlerContext handlerContext) {
         this(configData, logger, handlerContext, null);
@@ -54,7 +54,7 @@ public class POP3NettySession extends Ab
     public POP3NettySession(POP3HandlerConfigurationData configData, Log 
logger, ChannelHandlerContext handlerContext, SSLEngine engine) {
         super(logger, handlerContext, engine);
         this.configData = configData;
-        this.out = new 
NonClosingChannelOutputStream(getChannelHandlerContext().getChannel());
+        this.out = new 
NonWaitingChannelOutputStream(getChannelHandlerContext().getChannel());
     }
 
 

Modified: 
james/server/trunk/pop3server/src/test/java/org/apache/james/pop3server/AbstractAsyncPOP3ServerTest.java
URL: 
http://svn.apache.org/viewvc/james/server/trunk/pop3server/src/test/java/org/apache/james/pop3server/AbstractAsyncPOP3ServerTest.java?rev=1035990&r1=1035989&r2=1035990&view=diff
==============================================================================
--- 
james/server/trunk/pop3server/src/test/java/org/apache/james/pop3server/AbstractAsyncPOP3ServerTest.java
 (original)
+++ 
james/server/trunk/pop3server/src/test/java/org/apache/james/pop3server/AbstractAsyncPOP3ServerTest.java
 Wed Nov 17 11:56:05 2010
@@ -20,6 +20,7 @@
 package org.apache.james.pop3server;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.Reader;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -66,6 +67,10 @@ public abstract class AbstractAsyncPOP3S
     protected MockFileSystem fSystem;
     protected JamesProtocolHandlerChain chain;
     private InMemoryMailboxManager manager;
+    private byte[] content =        ("Return-path: [email protected]\r\n"+
+            "Content-Transfer-Encoding: plain\r\n"+
+            "Subject: test\r\n\r\n"+
+            "Body Text POP3ServerTest.setupTestMails\r\n").getBytes();
     
     public AbstractAsyncPOP3ServerTest() {
         super("AsyncPOP3ServerTest");
@@ -409,10 +414,7 @@ public abstract class AbstractAsyncPOP3S
     }
 
     private void setupTestMails(MailboxSession session, MessageManager 
mailbox) throws MessagingException {
-        byte[] content =        ("Return-path: [email protected]\r\n"+
-                                 "Content-Transfer-Encoding: plain\r\n"+
-                                 "Subject: test\r\n\r\n"+
-                                 "Body Text 
POP3ServerTest.setupTestMails\r\n").getBytes();
+       
         
         mailbox.appendMessage(new ByteArrayInputStream(content), new Date(), 
session, true, new Flags());
         byte[] content2 = ("EMPTY").getBytes();
@@ -559,4 +561,60 @@ public abstract class AbstractAsyncPOP3S
     }
     */
     
+    
+    // See JAMES-1136
+    public void testDeadlockOnRetr() throws Exception {
+        finishSetUp(m_testConfiguration);
+
+        m_pop3Protocol = new POP3Client();
+        m_pop3Protocol.connect("127.0.0.1",m_pop3ListenerPort);
+
+        m_usersRepository.addUser("foo6", "bar6");
+
+        MailboxPath mailboxPath = MailboxPath.inbox("foo6");
+        MailboxSession session = manager.login("foo6", "bar6", new 
SimpleLog("Test"));
+        
+        manager.startProcessingRequest(session);
+        if (manager.mailboxExists(mailboxPath, session) == false) {
+            manager.createMailbox(mailboxPath, session);
+        }
+        
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        out.write(content);
+        
+        byte[] bigMail = new byte[1024 * 1024 * 10];
+        int c = 0;
+        for (int i = 0; i < bigMail.length; i++) {
+            
+            bigMail[i] = 'X';
+            c++;
+            if (c == 1000 || i + 3 == bigMail.length) {
+                c = 0;
+                bigMail[++i] = '\r';
+                bigMail[++i] = '\n';
+            }
+        }
+        out.write(bigMail);
+        bigMail = null;
+        
+        manager.getMailbox(mailboxPath, session).appendMessage(new 
ByteArrayInputStream(out.toByteArray()), new Date(), session, false, new 
Flags());
+        manager.startProcessingRequest(session);
+        
+        m_pop3Protocol.login("foo6", "bar6");
+        assertEquals(1, m_pop3Protocol.getState());
+
+        POP3MessageInfo[] entries = m_pop3Protocol.listMessages();
+
+        assertNotNull(entries);
+        assertEquals(1, entries.length);
+        assertEquals(1, m_pop3Protocol.getState());
+
+        Reader r = m_pop3Protocol.retrieveMessage(entries[0].number);
+
+        assertNotNull(r);
+        r.close();
+        manager.deleteMailbox(mailboxPath, session);
+        
+    }
+    
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to