View Javadoc
1   /*
2    * Copyright 2019 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.svm;
17  
18  import io.netty.bootstrap.ServerBootstrap;
19  import io.netty.buffer.AdaptiveByteBufAllocator;
20  import io.netty.buffer.ByteBufAllocator;
21  import io.netty.buffer.PooledByteBufAllocator;
22  import io.netty.buffer.UnpooledByteBufAllocator;
23  import io.netty.channel.Channel;
24  import io.netty.channel.ChannelOption;
25  import io.netty.channel.EventLoopGroup;
26  import io.netty.channel.IoHandlerFactory;
27  import io.netty.channel.MultiThreadIoEventLoopGroup;
28  import io.netty.channel.epoll.EpollIoHandler;
29  import io.netty.channel.epoll.EpollServerSocketChannel;
30  import io.netty.channel.epoll.EpollSocketChannel;
31  import io.netty.channel.nio.NioIoHandler;
32  import io.netty.channel.socket.ServerSocketChannel;
33  import io.netty.channel.socket.nio.NioServerSocketChannel;
34  import io.netty.channel.socket.nio.NioSocketChannel;
35  import io.netty.channel.uring.IoUring;
36  import io.netty.channel.uring.IoUringBufferRingConfig;
37  import io.netty.channel.uring.IoUringFixedBufferRingAllocator;
38  import io.netty.channel.uring.IoUringIoHandler;
39  import io.netty.channel.uring.IoUringIoHandlerConfig;
40  import io.netty.channel.uring.IoUringServerSocketChannel;
41  import io.netty.channel.uring.IoUringSocketChannel;
42  import io.netty.handler.codec.http.DefaultFullHttpRequest;
43  import io.netty.handler.codec.http.HttpMethod;
44  import io.netty.handler.codec.http.HttpVersion;
45  import io.netty.handler.logging.LogLevel;
46  import io.netty.handler.logging.LoggingHandler;
47  
48  import java.net.InetSocketAddress;
49  import java.util.concurrent.CompletableFuture;
50  
51  /**
52   * An HTTP server that sends back the content of the received HTTP request
53   * in a pretty plaintext form.
54   */
55  public final class HttpNativeServer {
56  
57      /**
58       * Main entry point (not instantiable)
59       */
60      private HttpNativeServer() {
61      }
62  
63      public static void main(String[] args) throws Exception {
64          for (TransportType value : TransportType.values()) {
65              for (AllocatorType allocatorType : AllocatorType.values()) {
66                  boolean serverStartSucess = testTransport(value, allocatorType);
67                  System.out.println("Server started with transport type " + value + ": " + serverStartSucess);
68                  if (!serverStartSucess) {
69                      System.exit(1);
70                  }
71              }
72          }
73          // return the right system exit code to signal success
74          System.exit(0);
75      }
76  
77      public static boolean testTransport(TransportType ioType, AllocatorType allocatorType) throws Exception {
78          // Configure the server.
79          EventLoopGroup group = new MultiThreadIoEventLoopGroup(chooseFactory(ioType));
80          // Control status.
81          boolean serverStartSucess = false;
82          try {
83              CompletableFuture<Void> httpRequestFuture = new CompletableFuture<>();
84              ServerBootstrap b = new ServerBootstrap();
85              b.option(ChannelOption.SO_BACKLOG, 1024);
86              b.group(group)
87                      .channel(chooseServerChannelClass(ioType))
88                      .handler(new LoggingHandler(LogLevel.INFO))
89                      .childOption(ChannelOption.ALLOCATOR, chooseAllocator(allocatorType))
90                      .childHandler(new HttpNativeServerInitializer(httpRequestFuture));
91  
92              Channel channel = b.bind(0).sync().channel();
93              System.err.println("Server started, will shutdown now.");
94  
95              Channel httpClient = new HttpNativeClient(
96                      ((InetSocketAddress) channel.localAddress()).getPort(),
97                      group, chooseChannelClass(ioType)
98              ).initClient();
99              DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/hello");
100 
101             httpClient.writeAndFlush(request).sync();
102 
103             httpRequestFuture.get();
104 
105             channel.close().sync();
106             httpClient.close().sync();
107             serverStartSucess = true;
108         } finally {
109             group.shutdownGracefully();
110         }
111         return serverStartSucess;
112     }
113 
114     public static IoHandlerFactory chooseFactory(TransportType ioType) {
115         if (ioType == TransportType.EPOLL) {
116             return EpollIoHandler.newFactory();
117         }
118 
119         if (ioType == TransportType.IO_URING) {
120             IoUringIoHandlerConfig config = new IoUringIoHandlerConfig();
121             if (IoUring.isRegisterBufferRingSupported()) {
122                 config.setBufferRingConfig(
123                         IoUringBufferRingConfig.builder()
124                                 .bufferGroupId((short) 0)
125                                 .bufferRingSize((short) 16)
126                                 .batchSize(16)
127                                 .allocator(new IoUringFixedBufferRingAllocator(1024))
128                                 .batchAllocation(false)
129                                 .build()
130                 );
131             }
132 
133            return IoUringIoHandler.newFactory(config);
134         }
135 
136         return NioIoHandler.newFactory();
137     }
138 
139     public static ByteBufAllocator chooseAllocator(AllocatorType allocatorType) {
140         switch (allocatorType) {
141             case POOLED : return PooledByteBufAllocator.DEFAULT;
142             case UNPOOLED : return UnpooledByteBufAllocator.DEFAULT;
143             case ADAPTIVE: return new AdaptiveByteBufAllocator();
144             default: return PooledByteBufAllocator.DEFAULT;
145         }
146     }
147 
148     public static Class<? extends ServerSocketChannel> chooseServerChannelClass(TransportType ioType) {
149         if (ioType == TransportType.EPOLL) {
150             return EpollServerSocketChannel.class;
151         }
152 
153         if (ioType == TransportType.IO_URING) {
154             return IoUringServerSocketChannel.class;
155         }
156 
157         return NioServerSocketChannel.class;
158     }
159 
160     public static Class<? extends Channel> chooseChannelClass(TransportType ioType) {
161         if (ioType == TransportType.EPOLL) {
162             return EpollSocketChannel.class;
163         }
164 
165         if (ioType == TransportType.IO_URING) {
166             return IoUringSocketChannel.class;
167         }
168 
169         return NioSocketChannel.class;
170     }
171 
172     enum TransportType {
173         NIO,
174         EPOLL,
175         IO_URING,
176     }
177 
178     enum AllocatorType {
179         POOLED,
180         UNPOOLED,
181         ADAPTIVE
182     }
183 }