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 bossGroup = new MultiThreadIoEventLoopGroup(1, chooseFactory(ioType));
80          EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(chooseFactory(ioType));
81          // Control status.
82          boolean serverStartSucess = false;
83          try {
84              CompletableFuture<Void> httpRequestFuture = new CompletableFuture<>();
85              ServerBootstrap b = new ServerBootstrap();
86              b.option(ChannelOption.SO_BACKLOG, 1024);
87              b.group(bossGroup, workerGroup)
88                      .channel(chooseServerChannelClass(ioType))
89                      .handler(new LoggingHandler(LogLevel.INFO))
90                      .childOption(ChannelOption.ALLOCATOR, chooseAllocator(allocatorType))
91                      .childHandler(new HttpNativeServerInitializer(httpRequestFuture));
92  
93              Channel channel = b.bind(0).sync().channel();
94              System.err.println("Server started, will shutdown now.");
95  
96              Channel httpClient = new HttpNativeClient(
97                      ((InetSocketAddress) channel.localAddress()).getPort(),
98                      workerGroup, chooseChannelClass(ioType)
99              ).initClient();
100             DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/hello");
101 
102             httpClient.writeAndFlush(request).sync();
103 
104             httpRequestFuture.get();
105 
106             channel.close().sync();
107             httpClient.close().sync();
108             serverStartSucess = true;
109         } finally {
110             bossGroup.shutdownGracefully();
111             workerGroup.shutdownGracefully();
112         }
113         return serverStartSucess;
114     }
115 
116     public static IoHandlerFactory chooseFactory(TransportType ioType) {
117         if (ioType == TransportType.EPOLL) {
118             return EpollIoHandler.newFactory();
119         }
120 
121         if (ioType == TransportType.IO_URING) {
122             IoUringIoHandlerConfig config = new IoUringIoHandlerConfig();
123             if (IoUring.isRegisterBufferRingSupported()) {
124                 config.setBufferRingConfig(new IoUringBufferRingConfig(
125                         (short) 0, (short) 16, 16 * 16,
126                         new IoUringFixedBufferRingAllocator(1024)
127                 ));
128             }
129 
130            return IoUringIoHandler.newFactory(config);
131         }
132 
133         return NioIoHandler.newFactory();
134     }
135 
136     public static ByteBufAllocator chooseAllocator(AllocatorType allocatorType) {
137         switch (allocatorType) {
138             case POOLED : return PooledByteBufAllocator.DEFAULT;
139             case UNPOOLED : return UnpooledByteBufAllocator.DEFAULT;
140             case ADAPTIVE: return new AdaptiveByteBufAllocator();
141             default: return PooledByteBufAllocator.DEFAULT;
142         }
143     }
144 
145     public static Class<? extends ServerSocketChannel> chooseServerChannelClass(TransportType ioType) {
146         if (ioType == TransportType.EPOLL) {
147             return EpollServerSocketChannel.class;
148         }
149 
150         if (ioType == TransportType.IO_URING) {
151             return IoUringServerSocketChannel.class;
152         }
153 
154         return NioServerSocketChannel.class;
155     }
156 
157     public static Class<? extends Channel> chooseChannelClass(TransportType ioType) {
158         if (ioType == TransportType.EPOLL) {
159             return EpollSocketChannel.class;
160         }
161 
162         if (ioType == TransportType.IO_URING) {
163             return IoUringSocketChannel.class;
164         }
165 
166         return NioSocketChannel.class;
167     }
168 
169     enum TransportType {
170         NIO,
171         EPOLL,
172         IO_URING,
173     }
174 
175     enum AllocatorType {
176         POOLED,
177         UNPOOLED,
178         ADAPTIVE
179     }
180 }