Revision: 54a49396b123
Author:   Alexandre Mendonça <ammendonca>
Date:     Tue Jan  8 14:51:33 2013
Log:      Diameter Stack: TCP Transport to use non-blocking I/O

Update Issue 25
Status: Fixed
Applied attached patch.

http://code.google.com/p/jdiameter/source/detail?r=54a49396b123

Modified:
/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/tcp/TCPTransportClient.java

=======================================
--- /core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/tcp/TCPTransportClient.java Mon Nov 5 18:46:19 2012 +++ /core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/transport/tcp/TCPTransportClient.java Tue Jan 8 14:51:33 2013
@@ -36,8 +36,11 @@
 import java.nio.ByteBuffer;
 import java.nio.channels.AsynchronousCloseException;
 import java.nio.channels.ClosedByInterruptException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
 import java.nio.channels.SocketChannel;
 import java.nio.channels.spi.SelectorProvider;
+import java.util.Iterator;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;

@@ -74,6 +77,9 @@

private static final Logger logger = LoggerFactory.getLogger(TCPTransportClient.class);

+  //PCB - allow non blocking IO
+  private static final boolean BLOCKING_IO = false;
+
   public TCPTransportClient() {
   }

@@ -101,7 +107,8 @@
       socketChannel.socket().bind(origAddress);
     }
     socketChannel.connect(destAddress);
-    socketChannel.configureBlocking(true);
+    //PCB added logging
+    socketChannel.configureBlocking(BLOCKING_IO);
     getParent().onConnected();
   }

@@ -113,7 +120,8 @@
logger.debug("Initialising TCPTransportClient for a socket on [{}]", socket);
     socketDescription = socket.toString();
     socketChannel = socket.getChannel();
-    socketChannel.configureBlocking(true);
+    //PCB added logging
+    socketChannel.configureBlocking(BLOCKING_IO);
destAddress = new InetSocketAddress(socket.getInetAddress(), socket.getPort());
   }

@@ -143,50 +151,73 @@
     }
   }

+  //PCB added logging
   public void run() {
- logger.debug("Transport is started. Socket is [{}]", socketDescription); // Workaround for Issue #4 (http://code.google.com/p/jdiameter/issues/detail?id=4)
     // BEGIN WORKAROUND // Give some time to initialization...
+    int sleepTime = 250;
+ logger.debug("Sleeping for {}ms before starting transport so that listeners can all be added and ready for messages", sleepTime);
     try {
-      Thread.sleep(100);
+      Thread.sleep(sleepTime);
     }
     catch (InterruptedException e) {
       // ignore
     }
-    // END WORKAROUND // Give some time to initialization...
+ logger.debug("Finished sleeping for {}ms. By now, MutablePeerTableImpl should have added its listener", sleepTime);
+
+ logger.debug("Transport is started. Socket is [{}]", socketDescription);
+    Selector selector = null;
     try {
+      selector = Selector.open();
+      socketChannel.register(selector, SelectionKey.OP_READ);
       while (!stop) {
-        int dataLength = socketChannel.read(buffer);
- logger.debug("Just read [{}] bytes on [{}]", dataLength, socketDescription);
-        if (dataLength == -1) {
-          break;
+        selector.select();
+        Iterator<SelectionKey> it = selector.selectedKeys().iterator();
+        while (it.hasNext()) {
+          // Get the selection key
+          SelectionKey selKey = it.next();
+          // Remove it from the list to indicate that it is being processed
+          it.remove();
+          if (selKey.isValid() && selKey.isReadable()) {
+            // Get channel with bytes to read
+            SocketChannel sChannel = (SocketChannel) selKey.channel();
+            int dataLength = sChannel.read(buffer);
+ logger.debug("Just read [{}] bytes on [{}]", dataLength, socketDescription);
+            if (dataLength == -1) {
+              stop = true;
+              break;
+            }
+            buffer.flip();
+            byte[] data = new byte[buffer.limit()];
+            buffer.get(data);
+            append(data);
+            buffer.clear();
+          }
         }
-        buffer.flip();
-        byte[] data = new byte[buffer.limit()];
-        buffer.get(data);
-        append(data);
-        buffer.clear();
       }
     }
     catch (ClosedByInterruptException e) {
-      logger.debug("Transport exception ", e);
+      logger.error("Transport exception ", e);
     }
     catch (AsynchronousCloseException e) {
-      logger.debug("Transport exception ", e);
+      logger.error("Transport is closed");
     }
     catch (Throwable e) {
-      logger.debug("Transport exception ", e);
+      logger.error("Transport exception ", e);
     }
     finally {
       try {
         clearBuffer();
+        if (selector != null) {
+          selector.close();
+        }
         if (socketChannel != null && socketChannel.isOpen()) {
           socketChannel.close();
         }
         getParent().onDisconnect();
       }
       catch (Exception e) {
-        logger.debug("Error", e);
+        logger.error("Error", e);
       }
       stop = false;
logger.info("Read thread is stopped for socket [{}]", socketDescription);
@@ -234,8 +265,7 @@
     }
   }

-  public InetSocketAddress getOrigAddress()
-  {
+  public InetSocketAddress getOrigAddress() {
     return this.origAddress;
   }

@@ -244,16 +274,17 @@
logger.debug("About to send a byte buffer of size [{}] over the TCP nio socket [{}]", bytes.array().length, socketDescription);
     }
     int rc;
-    lock.lock();
+    // PCB - removed locking
+    // lock.lock();
     try {
       rc = socketChannel.write(bytes);
     }
     catch (Exception e) {
-      logger.debug("Unable to send message", e);
+      logger.error("Unable to send message", e);
       throw new IOException("Error while sending message: " + e);
     }
     finally {
-      lock.unlock();
+      // lock.unlock();
     }
     if (rc == -1) {
       throw new IOException("Connection closed");
@@ -355,7 +386,9 @@

       try {
         // make a message out of data and process it
+        logger.debug("Passing message on to parent");
         getParent().onMessageReceived(ByteBuffer.wrap(data));
+        logger.debug("Finished passing message on to parent");
       }
       catch (AvpDataException e) {
         logger.debug("Garbage was received. Discarding.");

Reply via email to