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