View Javadoc
1   /*
2    * Copyright 2012 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    *   http://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.channel.socket.nio;
17  
18  import io.netty.channel.ChannelException;
19  import io.netty.channel.ChannelMetadata;
20  import io.netty.channel.ChannelOutboundBuffer;
21  import io.netty.channel.nio.AbstractNioMessageChannel;
22  import io.netty.channel.socket.DefaultServerSocketChannelConfig;
23  import io.netty.channel.socket.ServerSocketChannelConfig;
24  import io.netty.util.internal.logging.InternalLogger;
25  import io.netty.util.internal.logging.InternalLoggerFactory;
26  
27  import java.io.IOException;
28  import java.net.InetSocketAddress;
29  import java.net.ServerSocket;
30  import java.net.SocketAddress;
31  import java.nio.channels.SelectionKey;
32  import java.nio.channels.ServerSocketChannel;
33  import java.nio.channels.SocketChannel;
34  import java.nio.channels.spi.SelectorProvider;
35  import java.util.List;
36  
37  /**
38   * A {@link io.netty.channel.socket.ServerSocketChannel} implementation which uses
39   * NIO selector based implementation to accept new connections.
40   */
41  public class NioServerSocketChannel extends AbstractNioMessageChannel
42                               implements io.netty.channel.socket.ServerSocketChannel {
43  
44      private static final ChannelMetadata METADATA = new ChannelMetadata(false);
45      private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
46  
47      private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioServerSocketChannel.class);
48  
49      private static ServerSocketChannel newSocket(SelectorProvider provider) {
50          try {
51              /**
52               *  Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in
53               *  {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.
54               *
55               *  See <a href="See https://github.com/netty/netty/issues/2308">#2308</a>.
56               */
57              return provider.openServerSocketChannel();
58          } catch (IOException e) {
59              throw new ChannelException(
60                      "Failed to open a server socket.", e);
61          }
62      }
63  
64      private final ServerSocketChannelConfig config;
65  
66      /**
67       * Create a new instance
68       */
69      public NioServerSocketChannel() {
70          this(newSocket(DEFAULT_SELECTOR_PROVIDER));
71      }
72  
73      /**
74       * Create a new instance using the given {@link SelectorProvider}.
75       */
76      public NioServerSocketChannel(SelectorProvider provider) {
77          this(newSocket(provider));
78      }
79  
80      /**
81       * Create a new instance using the given {@link ServerSocketChannel}.
82       */
83      public NioServerSocketChannel(ServerSocketChannel channel) {
84          super(null, channel, SelectionKey.OP_ACCEPT);
85          config = new NioServerSocketChannelConfig(this, javaChannel().socket());
86      }
87  
88      @Override
89      public InetSocketAddress localAddress() {
90          return (InetSocketAddress) super.localAddress();
91      }
92  
93      @Override
94      public ChannelMetadata metadata() {
95          return METADATA;
96      }
97  
98      @Override
99      public ServerSocketChannelConfig config() {
100         return config;
101     }
102 
103     @Override
104     public boolean isActive() {
105         return javaChannel().socket().isBound();
106     }
107 
108     @Override
109     public InetSocketAddress remoteAddress() {
110         return null;
111     }
112 
113     @Override
114     protected ServerSocketChannel javaChannel() {
115         return (ServerSocketChannel) super.javaChannel();
116     }
117 
118     @Override
119     protected SocketAddress localAddress0() {
120         return javaChannel().socket().getLocalSocketAddress();
121     }
122 
123     @Override
124     protected void doBind(SocketAddress localAddress) throws Exception {
125         javaChannel().socket().bind(localAddress, config.getBacklog());
126     }
127 
128     @Override
129     protected void doClose() throws Exception {
130         javaChannel().close();
131     }
132 
133     @Override
134     protected int doReadMessages(List<Object> buf) throws Exception {
135         SocketChannel ch = javaChannel().accept();
136 
137         try {
138             if (ch != null) {
139                 buf.add(new NioSocketChannel(this, ch));
140                 return 1;
141             }
142         } catch (Throwable t) {
143             logger.warn("Failed to create a new channel from an accepted socket.", t);
144 
145             try {
146                 ch.close();
147             } catch (Throwable t2) {
148                 logger.warn("Failed to close a socket.", t2);
149             }
150         }
151 
152         return 0;
153     }
154 
155     // Unnecessary stuff
156     @Override
157     protected boolean doConnect(
158             SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
159         throw new UnsupportedOperationException();
160     }
161 
162     @Override
163     protected void doFinishConnect() throws Exception {
164         throw new UnsupportedOperationException();
165     }
166 
167     @Override
168     protected SocketAddress remoteAddress0() {
169         return null;
170     }
171 
172     @Override
173     protected void doDisconnect() throws Exception {
174         throw new UnsupportedOperationException();
175     }
176 
177     @Override
178     protected boolean doWriteMessage(Object msg, ChannelOutboundBuffer in) throws Exception {
179         throw new UnsupportedOperationException();
180     }
181 
182     @Override
183     protected final Object filterOutboundMessage(Object msg) throws Exception {
184         throw new UnsupportedOperationException();
185     }
186 
187     private final class NioServerSocketChannelConfig  extends DefaultServerSocketChannelConfig {
188         private NioServerSocketChannelConfig(NioServerSocketChannel channel, ServerSocket javaSocket) {
189             super(channel, javaSocket);
190         }
191 
192         @Override
193         protected void autoReadCleared() {
194             setReadPending(false);
195         }
196     }
197 }