1 /*
   2  * Copyright (c) 2002, 2015, 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 4669040 8087304
  26  * @summary Test DatagramChannel receive with empty buffer
  27  * @author Mike McCloskey
  28  */
  29 
  30 import java.io.*;
  31 import java.net.*;
  32 import java.nio.*;
  33 import java.nio.channels.*;
  34 
  35 public class EmptyBuffer {
  36 
  37     static PrintStream log = System.err;
  38 
  39     public static void main(String[] args) throws Exception {
  40         test();
  41     }
  42 
  43     static void test() throws Exception {
  44         Server server = new Server();
  45         Thread serverThread = new Thread(server);
  46         serverThread.start();
  47         DatagramChannel dc = DatagramChannel.open();
  48         try {
  49             ByteBuffer bb = ByteBuffer.allocateDirect(12);
  50             bb.order(ByteOrder.BIG_ENDIAN);
  51             bb.putInt(1).putLong(1);
  52             bb.flip();
  53             InetAddress address = InetAddress.getLocalHost();
  54             InetSocketAddress isa = new InetSocketAddress(address, server.port());
  55             dc.connect(isa);
  56             server.setClientAddress(dc.getLocalAddress());
  57             dc.write(bb);
  58             bb.rewind();
  59             dc.write(bb);
  60             bb.rewind();
  61             dc.write(bb);
  62             Thread.sleep(2000);
  63             serverThread.interrupt();
  64             server.throwException();
  65         } finally {
  66             dc.close();
  67         }
  68     }
  69 
  70     public static class Server implements Runnable {
  71         final DatagramChannel dc;
  72         private SocketAddress clientAddress;
  73         Exception e = null;
  74 
  75         Server() throws IOException {
  76             this.dc = DatagramChannel.open().bind(new InetSocketAddress(0));
  77         }
  78 
  79         void setClientAddress(SocketAddress clientAddress) {
  80             this.clientAddress = clientAddress;
  81         }
  82 
  83         int port() {
  84             return dc.socket().getLocalPort();
  85         }
  86 
  87         void throwException() throws Exception {
  88             if (e != null)
  89                 throw e;
  90         }
  91 
  92         void showBuffer(String s, ByteBuffer bb) {
  93             log.println(s);
  94             bb.rewind();
  95             for (int i=0; i<bb.limit(); i++) {
  96                 byte element = bb.get();
  97                 log.print(element);
  98             }
  99             log.println();
 100         }
 101 
 102         @Override
 103         public void run() {
 104             SocketAddress sa;
 105             int numberReceived = 0;
 106             try {
 107                 ByteBuffer bb = ByteBuffer.allocateDirect(12);
 108                 bb.clear();
 109                 // Only one clear. The buffer will be full after
 110                 // the first receive, but it should still block
 111                 // and receive and discard the next two
 112                 while (!Thread.interrupted()) {
 113                     try {
 114                         sa = dc.receive(bb);
 115                     } catch (ClosedByInterruptException cbie) {
 116                         // Expected
 117                         log.println("Took expected exit");
 118                         // Verify that enough packets were received
 119                         if (numberReceived != 3)
 120                             throw new RuntimeException("Failed: Too few datagrams");
 121                         break;
 122                     }
 123                     if (sa != null) {
 124                         log.println("Client: " + sa);
 125                         // Check client address so as not to count stray packets
 126                         if (sa.equals(clientAddress)) {
 127                             showBuffer("RECV", bb);
 128                             numberReceived++;
 129                         }
 130                         if (numberReceived > 3)
 131                             throw new RuntimeException("Failed: Too many datagrams");
 132                         sa = null;
 133                     }
 134                 }
 135             } catch (Exception ex) {
 136                 e = ex;
 137             } finally {
 138                 try { dc.close(); } catch (IOException ignore) { }
 139             }
 140         }
 141     }
 142 
 143 }