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.oio;
17  
18  import io.netty.channel.ChannelException;
19  import io.netty.channel.ChannelMetadata;
20  import io.netty.channel.ChannelOutboundBuffer;
21  import io.netty.channel.oio.AbstractOioMessageChannel;
22  import io.netty.channel.socket.ServerSocketChannel;
23  import io.netty.util.internal.logging.InternalLogger;
24  import io.netty.util.internal.logging.InternalLoggerFactory;
25  
26  import java.io.IOException;
27  import java.net.InetSocketAddress;
28  import java.net.ServerSocket;
29  import java.net.Socket;
30  import java.net.SocketAddress;
31  import java.net.SocketTimeoutException;
32  import java.util.List;
33  import java.util.concurrent.locks.Lock;
34  import java.util.concurrent.locks.ReentrantLock;
35  
36  /**
37   * {@link ServerSocketChannel} which accepts new connections and create the {@link OioSocketChannel}'s for them.
38   *
39   * This implementation use Old-Blocking-IO.
40   */
41  public class OioServerSocketChannel extends AbstractOioMessageChannel
42                                      implements ServerSocketChannel {
43  
44      private static final InternalLogger logger =
45          InternalLoggerFactory.getInstance(OioServerSocketChannel.class);
46  
47      private static final ChannelMetadata METADATA = new ChannelMetadata(false);
48  
49      private static ServerSocket newServerSocket() {
50          try {
51              return new ServerSocket();
52          } catch (IOException e) {
53              throw new ChannelException("failed to create a server socket", e);
54          }
55      }
56  
57      final ServerSocket socket;
58      final Lock shutdownLock = new ReentrantLock();
59      private final OioServerSocketChannelConfig config;
60  
61      /**
62       * Create a new instance with an new {@link Socket}
63       */
64      public OioServerSocketChannel() {
65          this(newServerSocket());
66      }
67  
68      /**
69       * Create a new instance from the given {@link ServerSocket}
70       *
71       * @param socket    the {@link ServerSocket} which is used by this instance
72       */
73      public OioServerSocketChannel(ServerSocket socket) {
74          super(null);
75          if (socket == null) {
76              throw new NullPointerException("socket");
77          }
78  
79          boolean success = false;
80          try {
81              socket.setSoTimeout(SO_TIMEOUT);
82              success = true;
83          } catch (IOException e) {
84              throw new ChannelException(
85                      "Failed to set the server socket timeout.", e);
86          } finally {
87              if (!success) {
88                  try {
89                      socket.close();
90                  } catch (IOException e) {
91                      if (logger.isWarnEnabled()) {
92                          logger.warn(
93                                  "Failed to close a partially initialized socket.", e);
94                      }
95                  }
96              }
97          }
98          this.socket = socket;
99          config = new DefaultOioServerSocketChannelConfig(this, socket);
100     }
101 
102     @Override
103     public InetSocketAddress localAddress() {
104         return (InetSocketAddress) super.localAddress();
105     }
106 
107     @Override
108     public ChannelMetadata metadata() {
109         return METADATA;
110     }
111 
112     @Override
113     public OioServerSocketChannelConfig config() {
114         return config;
115     }
116 
117     @Override
118     public InetSocketAddress remoteAddress() {
119         return null;
120     }
121 
122     @Override
123     public boolean isOpen() {
124         return !socket.isClosed();
125     }
126 
127     @Override
128     public boolean isActive() {
129         return isOpen() && socket.isBound();
130     }
131 
132     @Override
133     protected SocketAddress localAddress0() {
134         return socket.getLocalSocketAddress();
135     }
136 
137     @Override
138     protected void doBind(SocketAddress localAddress) throws Exception {
139         socket.bind(localAddress, config.getBacklog());
140     }
141 
142     @Override
143     protected void doClose() throws Exception {
144         socket.close();
145     }
146 
147     @Override
148     protected int doReadMessages(List<Object> buf) throws Exception {
149         if (socket.isClosed()) {
150             return -1;
151         }
152 
153         try {
154             Socket s = socket.accept();
155             try {
156                 buf.add(new OioSocketChannel(this, s));
157                 return 1;
158             } catch (Throwable t) {
159                 logger.warn("Failed to create a new channel from an accepted socket.", t);
160                 try {
161                     s.close();
162                 } catch (Throwable t2) {
163                     logger.warn("Failed to close a socket.", t2);
164                 }
165             }
166         } catch (SocketTimeoutException e) {
167             // Expected
168         }
169         return 0;
170     }
171 
172     @Override
173     protected void doWrite(ChannelOutboundBuffer in) throws Exception {
174         throw new UnsupportedOperationException();
175     }
176 
177     @Override
178     protected Object filterOutboundMessage(Object msg) throws Exception {
179         throw new UnsupportedOperationException();
180     }
181 
182     @Override
183     protected void doConnect(
184             SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
185         throw new UnsupportedOperationException();
186     }
187 
188     @Override
189     protected SocketAddress remoteAddress0() {
190         return null;
191     }
192 
193     @Override
194     protected void doDisconnect() throws Exception {
195         throw new UnsupportedOperationException();
196     }
197 
198     @Override
199     protected void setReadPending(boolean readPending) {
200         super.setReadPending(readPending);
201     }
202 }