1 /*
   2  * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @bug 8195160
  26  * @summary Test RDMA SocketChannel.finishConnect
  27  * @requires (os.family == "linux")
  28  * @library .. /test/lib
  29  * @build jdk.test.lib.Utils TestServers
  30  * @build RsocketTest
  31  * @run main/othervm -Djava.net.preferIPv4Stack=true FinishConnect
  32  */
  33 
  34 import java.net.*;
  35 import java.nio.*;
  36 import java.nio.channels.*;
  37 import java.nio.channels.spi.SelectorProvider;
  38 import java.nio.charset.*;
  39 import java.util.*;
  40 import jdk.net.Sockets;
  41 
  42 public class FinishConnect {
  43 
  44     public static void main(String[] args) throws Exception {
  45         if (!RsocketTest.isRsocketAvailable())
  46             return;
  47 
  48         try (TestServers.DayTimeServer dayTimeServer
  49                 = TestServers.DayTimeServer.startNewServer(100)) {
  50             test1(dayTimeServer, true, true);
  51             test1(dayTimeServer, true, false);
  52             test1(dayTimeServer, false, true);
  53             test1(dayTimeServer, false, false);
  54             test2(dayTimeServer);
  55         }
  56     }
  57 
  58     static void test1(TestServers.DayTimeServer daytimeServer,
  59                       boolean select,
  60                       boolean setBlocking)
  61         throws Exception
  62     {
  63         InetSocketAddress isa
  64             = new InetSocketAddress(daytimeServer.getAddress(),
  65                                     daytimeServer.getPort());
  66         SocketChannel sc = Sockets.openRdmaSocketChannel();
  67         sc.configureBlocking(false);
  68         boolean connected = sc.connect(isa);
  69         int attempts = 0;
  70 
  71         try {
  72             sc.connect(isa);
  73             throw new RuntimeException("Allowed another connect call");
  74         } catch (IllegalStateException ise) {
  75             // Correct behavior
  76         }
  77 
  78         if (setBlocking)
  79             sc.configureBlocking(true);
  80 
  81         if (!connected && select && !setBlocking) {
  82             Selector selector = Sockets.openRdmaSelector();
  83             sc.register(selector, SelectionKey.OP_CONNECT);
  84             while (!connected) {
  85                 int keysAdded = selector.select(100);
  86                 if (keysAdded > 0) {
  87                     Set readyKeys = selector.selectedKeys();
  88                     Iterator i = readyKeys.iterator();
  89                     while (i.hasNext()) {
  90                         SelectionKey sk = (SelectionKey)i.next();
  91                         SocketChannel nextReady =
  92                             (SocketChannel)sk.channel();
  93                         connected = sc.finishConnect();
  94                     }
  95                 }
  96             }
  97             selector.close();
  98         }
  99 
 100         while (!connected) {
 101             if (attempts++ > 30)
 102                 throw new RuntimeException("Failed to connect");
 103             Thread.sleep(100);
 104             connected = sc.finishConnect();
 105         }
 106 
 107         ByteBuffer bb = ByteBuffer.allocateDirect(100);
 108         int bytesRead = 0;
 109         int totalRead = 0;
 110         while (totalRead < 20) {
 111             bytesRead = sc.read(bb);
 112             if (bytesRead > 0)
 113                 totalRead += bytesRead;
 114             if (bytesRead < 0)
 115                 throw new RuntimeException("Message shorter than expected");
 116         }
 117         bb.position(bb.position() - 2);         // Drop CRLF
 118         bb.flip();
 119         CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb);
 120         System.err.println(isa + " says: \"" + cb + "\"");
 121         sc.close();
 122     }
 123 
 124     static void test2(TestServers.DayTimeServer daytimeServer) throws Exception {
 125         InetSocketAddress isa
 126             = new InetSocketAddress(daytimeServer.getAddress(),
 127                                     daytimeServer.getPort());
 128         boolean done = false;
 129         int globalAttempts = 0;
 130         int connectSuccess = 0;
 131         while (!done) {
 132             // When using a local daytime server it is not always possible
 133             // to get a pending connection, as sc.connect(isa) may always
 134             // return true.
 135             // So we're going to throw the exception only if there was
 136             // at least 1 case where we did not manage to connect.
 137             if (globalAttempts++ > 50) {
 138                 if (globalAttempts == connectSuccess + 1) {
 139                     System.out.println("Can't fully test on "
 140                             + System.getProperty("os.name"));
 141                     break;
 142                 }
 143                 throw new RuntimeException("Failed to connect");
 144             }
 145             SocketChannel sc = Sockets.openRdmaSocketChannel();
 146             sc.configureBlocking(false);
 147             boolean connected = sc.connect(isa);
 148             int localAttempts = 0;
 149             while (!connected) {
 150                 if (localAttempts++ > 500)
 151                     throw new RuntimeException("Failed to connect");
 152                 connected = sc.finishConnect();
 153                 if (connected) {
 154                     done = true;
 155                     break;
 156                 }
 157                 Thread.sleep(10);
 158             }
 159             if (connected) {
 160                 connectSuccess++;
 161             }
 162             sc.close();
 163         }
 164     }
 165 
 166 }