1 /*
   2  * Copyright (c) 2020, 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 8053479
  26  * @run main Truncate
  27  * @summary Test DatagramChannel receive/read where there are fewer bytes remaining
  28  *     in the buffer than are required to hold the datagram. The remainder of the
  29  *     datagram should be silently discarded.
  30  */
  31 
  32 import java.io.IOException;
  33 import java.net.InetAddress;
  34 import java.net.InetSocketAddress;
  35 import java.net.SocketAddress;
  36 import java.nio.ByteBuffer;
  37 import java.nio.channels.DatagramChannel;
  38 import java.util.Arrays;
  39 import java.util.stream.IntStream;
  40 
  41 public class Truncate {
  42     static final int LARGE_SIZE = 1000;
  43     static final int SMALL_SIZE = 100;
  44 
  45     public static void main(String[] args) throws Exception {
  46         try (DatagramChannel dc = DatagramChannel.open()) {
  47             dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
  48 
  49             // not connected
  50             testReceiveDiscards(dc);
  51 
  52             // connected
  53             dc.connect(dc.getLocalAddress());
  54             testReceiveDiscards(dc);
  55             testReadDiscards(dc);
  56             testScatteringReadDiscards(dc);
  57         }
  58     }
  59 
  60     /**
  61      * Receive a datagram with a buffer that has fewer bytes remaining than are
  62      * required to hold the datagram.
  63      */
  64     static void testReceiveDiscards(DatagramChannel dc) throws IOException {
  65         ByteBuffer largeBuffer = send(dc, LARGE_SIZE, dc.getLocalAddress());
  66 
  67         ByteBuffer smallBuffer = ByteBuffer.allocate(SMALL_SIZE);
  68         SocketAddress sender = dc.receive(smallBuffer);
  69         assertTrue(sender.equals(dc.getLocalAddress()));
  70 
  71         // check buffer/contents
  72         smallBuffer.flip();
  73         assertTrue(smallBuffer.remaining() == SMALL_SIZE);
  74         assertTrue(Arrays.equals(smallBuffer.array(), 0, SMALL_SIZE,
  75                 largeBuffer.array(), 0, SMALL_SIZE));
  76     }
  77 
  78     /**
  79      * Read a datagram with a buffer that has fewer bytes remaining than are
  80      * required to hold the datagram.
  81      */
  82     static void testReadDiscards(DatagramChannel dc) throws IOException {
  83         ByteBuffer largeBuffer = send(dc, LARGE_SIZE, dc.getRemoteAddress());
  84 
  85         ByteBuffer smallBuffer = ByteBuffer.allocate(SMALL_SIZE);
  86         int n = dc.read(smallBuffer);
  87         assertTrue(n == SMALL_SIZE);
  88 
  89         // check buffer/contents
  90         smallBuffer.flip();
  91         assertTrue(smallBuffer.remaining() == SMALL_SIZE);
  92         assertTrue(Arrays.equals(smallBuffer.array(), 0, SMALL_SIZE,
  93                 largeBuffer.array(), 0, SMALL_SIZE));
  94     }
  95 
  96     /**
  97      * Read a datagram with an array of buffers that have fewer bytes remaining
  98      * than are required to hold the datagram.
  99      */
 100     static void testScatteringReadDiscards(DatagramChannel dc) throws IOException {
 101         ByteBuffer largeBuffer = send(dc, LARGE_SIZE, dc.getRemoteAddress());
 102 
 103         ByteBuffer smallBuffer1 = ByteBuffer.allocate(SMALL_SIZE);
 104         ByteBuffer smallBuffer2 = ByteBuffer.allocate(SMALL_SIZE);
 105         ByteBuffer[] bufs = new ByteBuffer[] { smallBuffer1, smallBuffer2 };
 106         long n = dc.read(bufs);
 107         assertTrue(n == (SMALL_SIZE * bufs.length));
 108 
 109         // check buffer/contents
 110         smallBuffer1.flip();
 111         assertTrue(smallBuffer1.remaining() == SMALL_SIZE);
 112         assertTrue(Arrays.equals(smallBuffer1.array(), 0, SMALL_SIZE,
 113                 largeBuffer.array(), 0, SMALL_SIZE));
 114         smallBuffer2.flip();
 115         assertTrue(smallBuffer2.remaining() == SMALL_SIZE);
 116         assertTrue(Arrays.equals(smallBuffer2.array(), 0, SMALL_SIZE,
 117                 largeBuffer.array(), SMALL_SIZE, SMALL_SIZE << 1));
 118     }
 119 
 120     /**
 121      * Send a datagram of the given size to the given target address.
 122      * @return the buffer with the datagram sent to the target address
 123      */
 124     static ByteBuffer send(DatagramChannel dc, int size, SocketAddress target)
 125         throws IOException
 126     {
 127         ByteBuffer buffer = ByteBuffer.allocate(size);
 128         IntStream.range(0, size).forEach(i -> buffer.put((byte)i));
 129         buffer.flip();
 130 
 131         int n = dc.send(buffer, target);
 132         assertTrue(n == size);
 133         buffer.flip();
 134         return buffer;
 135     }
 136 
 137     static void assertTrue(boolean e) {
 138         if (!e) throw new RuntimeException();
 139     }
 140 }