View Javadoc
1   /*
2    * Copyright 2021 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.testsuite.transport.socket;
17  
18  import io.netty.bootstrap.Bootstrap;
19  import io.netty.buffer.ByteBuf;
20  import io.netty.channel.Channel;
21  import io.netty.channel.ChannelFuture;
22  import io.netty.channel.ChannelHandlerAdapter;
23  import io.netty.channel.ChannelHandlerContext;
24  import io.netty.channel.ChannelInitializer;
25  import io.netty.channel.SimpleChannelInboundHandler;
26  import io.netty.channel.socket.DatagramChannel;
27  import io.netty.channel.socket.DatagramPacket;
28  import org.junit.jupiter.api.Test;
29  import org.junit.jupiter.api.TestInfo;
30  
31  import java.net.InetSocketAddress;
32  import java.net.SocketAddress;
33  import java.util.concurrent.CountDownLatch;
34  import java.util.concurrent.atomic.AtomicReference;
35  
36  import static org.junit.jupiter.api.Assertions.assertEquals;
37  import static org.junit.jupiter.api.Assertions.assertNotNull;
38  
39  public class DatagramUnicastInetTest extends DatagramUnicastTest {
40  
41      @Test
42      public void testBindWithPortOnly(TestInfo testInfo) throws Throwable {
43          run(testInfo, new Runner<Bootstrap, Bootstrap>() {
44              @Override
45              public void run(Bootstrap bootstrap, Bootstrap bootstrap2) throws Throwable {
46                  testBindWithPortOnly(bootstrap2);
47              }
48          });
49      }
50  
51      private static void testBindWithPortOnly(Bootstrap cb) throws Throwable {
52          Channel channel = null;
53          try {
54              cb.handler(new ChannelHandlerAdapter() { });
55              channel = cb.bind(0).sync().channel();
56          } finally {
57              closeChannel(channel);
58          }
59      }
60  
61      @Override
62      protected boolean isConnected(Channel channel) {
63          return ((DatagramChannel) channel).isConnected();
64      }
65  
66      @Override
67      protected Channel setupClientChannel(Bootstrap cb, final byte[] bytes, final CountDownLatch latch,
68                                           final AtomicReference<Throwable> errorRef) throws Throwable {
69          cb.handler(new SimpleChannelInboundHandler<DatagramPacket>() {
70  
71              @Override
72              public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) {
73                  try {
74                      ByteBuf buf = msg.content();
75                      assertEquals(bytes.length, buf.readableBytes());
76                      for (int i = 0; i < bytes.length; i++) {
77                          assertEquals(bytes[i], buf.getByte(buf.readerIndex() + i));
78                      }
79  
80                      InetSocketAddress localAddress = (InetSocketAddress) ctx.channel().localAddress();
81                      if (localAddress.getAddress().isAnyLocalAddress()) {
82                          assertEquals(localAddress.getPort(), msg.recipient().getPort());
83                      } else {
84                          // Test that the channel's localAddress is equal to the message's recipient
85                          assertEquals(localAddress, msg.recipient());
86                      }
87                  } finally {
88                      latch.countDown();
89                  }
90              }
91  
92              @Override
93              public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
94                  errorRef.compareAndSet(null, cause);
95              }
96          });
97          return cb.bind(newSocketAddress()).sync().channel();
98      }
99  
100     @Override
101     protected Channel setupServerChannel(Bootstrap sb, final byte[] bytes, final SocketAddress sender,
102                                          final CountDownLatch latch, final AtomicReference<Throwable> errorRef,
103                                          final boolean echo) throws Throwable {
104         sb.handler(new ChannelInitializer<Channel>() {
105             @Override
106             protected void initChannel(Channel ch) {
107                 ch.pipeline().addLast(new SimpleChannelInboundHandler<DatagramPacket>() {
108 
109                     @Override
110                     public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) {
111                         try {
112                             if (sender == null) {
113                                 assertNotNull(msg.sender());
114                             } else {
115                                 InetSocketAddress senderAddress = (InetSocketAddress) sender;
116                                 if (senderAddress.getAddress().isAnyLocalAddress()) {
117                                     assertEquals(senderAddress.getPort(), msg.sender().getPort());
118                                 } else {
119                                     assertEquals(sender, msg.sender());
120                                 }
121                             }
122 
123                             ByteBuf buf = msg.content();
124                             assertEquals(bytes.length, buf.readableBytes());
125                             for (int i = 0; i < bytes.length; i++) {
126                                 assertEquals(bytes[i], buf.getByte(buf.readerIndex() + i));
127                             }
128 
129                             // Test that the channel's localAddress is equal to the message's recipient
130                             assertEquals(ctx.channel().localAddress(), msg.recipient());
131 
132                             if (echo) {
133                                 ctx.writeAndFlush(new DatagramPacket(buf.retainedDuplicate(), msg.sender()));
134                             }
135                         } finally {
136                             latch.countDown();
137                         }
138                     }
139 
140                     @Override
141                     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
142                         errorRef.compareAndSet(null, cause);
143                     }
144                 });
145             }
146         });
147         return sb.bind(newSocketAddress()).sync().channel();
148     }
149 
150     @Override
151     protected boolean supportDisconnect() {
152         return true;
153     }
154 
155     @Override
156     protected ChannelFuture write(Channel cc, ByteBuf buf, SocketAddress remote, WrapType wrapType) {
157         switch (wrapType) {
158             case DUP:
159                 return cc.write(new DatagramPacket(buf.retainedDuplicate(), (InetSocketAddress) remote));
160             case SLICE:
161                 return cc.write(new DatagramPacket(buf.retainedSlice(), (InetSocketAddress) remote));
162             case READ_ONLY:
163                 return cc.write(new DatagramPacket(buf.retain().asReadOnly(), (InetSocketAddress) remote));
164             case NONE:
165                 return cc.write(new DatagramPacket(buf.retain(), (InetSocketAddress) remote));
166             default:
167                 throw new Error("unknown wrap type: " + wrapType);
168         }
169     }
170 }