1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.testsuite.transport.socket;
17
18 import io.netty.bootstrap.Bootstrap;
19 import io.netty.bootstrap.ServerBootstrap;
20 import io.netty.channel.Channel;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.channel.ChannelInboundHandlerAdapter;
23 import io.netty.channel.ChannelInitializer;
24 import io.netty.channel.ChannelOption;
25 import org.junit.jupiter.api.Test;
26 import org.junit.jupiter.api.TestInfo;
27 import org.junit.jupiter.api.Timeout;
28
29 import java.io.IOException;
30 import java.util.Locale;
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.atomic.AtomicReference;
34
35 import static org.junit.jupiter.api.Assertions.assertNull;
36 import static org.junit.jupiter.api.Assertions.assertTrue;
37
38 public class SocketRstTest extends AbstractSocketTest {
39 protected void assertRstOnCloseException(IOException cause, Channel clientChannel) {
40 if (Locale.getDefault() == Locale.US || Locale.getDefault() == Locale.UK) {
41 assertTrue(cause.getMessage().contains("reset") || cause.getMessage().contains("closed"),
42 "actual message: " + cause.getMessage());
43 }
44 }
45
46 @Test
47 @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS)
48 public void testSoLingerZeroCausesOnlyRstOnClose(TestInfo testInfo) throws Throwable {
49 run(testInfo, new Runner<ServerBootstrap, Bootstrap>() {
50 @Override
51 public void run(ServerBootstrap serverBootstrap, Bootstrap bootstrap) throws Throwable {
52 testSoLingerZeroCausesOnlyRstOnClose(serverBootstrap, bootstrap);
53 }
54 });
55 }
56
57 public void testSoLingerZeroCausesOnlyRstOnClose(ServerBootstrap sb, Bootstrap cb) throws Throwable {
58 final AtomicReference<Channel> serverChannelRef = new AtomicReference<Channel>();
59 final AtomicReference<Throwable> throwableRef = new AtomicReference<Throwable>();
60 final CountDownLatch latch = new CountDownLatch(1);
61 final CountDownLatch latch2 = new CountDownLatch(1);
62
63 sb.childOption(ChannelOption.SO_LINGER, 0);
64 sb.childHandler(new ChannelInitializer<Channel>() {
65 @Override
66 protected void initChannel(Channel ch) throws Exception {
67 serverChannelRef.compareAndSet(null, ch);
68 latch.countDown();
69 }
70 });
71 cb.handler(new ChannelInitializer<Channel>() {
72 @Override
73 protected void initChannel(Channel ch) throws Exception {
74 ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
75 @Override
76 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
77 throwableRef.compareAndSet(null, cause);
78 }
79
80 @Override
81 public void channelInactive(ChannelHandlerContext ctx) {
82 latch2.countDown();
83 }
84 });
85 }
86 });
87 Channel sc = sb.bind().sync().channel();
88 Channel cc = cb.connect(sc.localAddress()).sync().channel();
89
90
91 latch.await();
92
93
94 serverChannelRef.get().close();
95
96
97 latch2.await();
98
99
100 Throwable cause = throwableRef.get();
101 assertTrue(cause instanceof IOException,
102 "actual [type, message]: [" + cause.getClass() + ", " + cause.getMessage() + "]");
103
104 assertRstOnCloseException((IOException) cause, cc);
105 }
106
107 @Test
108 @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS)
109 public void testNoRstIfSoLingerOnClose(TestInfo testInfo) throws Throwable {
110 run(testInfo, new Runner<ServerBootstrap, Bootstrap>() {
111 @Override
112 public void run(ServerBootstrap serverBootstrap, Bootstrap bootstrap) throws Throwable {
113 testNoRstIfSoLingerOnClose(serverBootstrap, bootstrap);
114 }
115 });
116 }
117
118 public void testNoRstIfSoLingerOnClose(ServerBootstrap sb, Bootstrap cb) throws Throwable {
119 final AtomicReference<Channel> serverChannelRef = new AtomicReference<Channel>();
120 final AtomicReference<Throwable> throwableRef = new AtomicReference<Throwable>();
121 final CountDownLatch latch = new CountDownLatch(1);
122 final CountDownLatch latch2 = new CountDownLatch(1);
123 sb.childHandler(new ChannelInitializer<Channel>() {
124 @Override
125 protected void initChannel(Channel ch) throws Exception {
126 serverChannelRef.compareAndSet(null, ch);
127 latch.countDown();
128 }
129 });
130 cb.handler(new ChannelInitializer<Channel>() {
131 @Override
132 protected void initChannel(Channel ch) throws Exception {
133 ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
134 @Override
135 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
136 throwableRef.compareAndSet(null, cause);
137 }
138
139 @Override
140 public void channelInactive(ChannelHandlerContext ctx) {
141 latch2.countDown();
142 }
143 });
144 }
145 });
146 Channel sc = sb.bind().sync().channel();
147 cb.connect(sc.localAddress()).syncUninterruptibly();
148
149
150 latch.await();
151
152
153 serverChannelRef.get().close();
154
155
156 latch2.await();
157
158
159 assertNull(throwableRef.get());
160 }
161 }