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.sctp.oio;
17  
18  import com.sun.nio.sctp.SctpChannel;
19  import com.sun.nio.sctp.SctpServerChannel;
20  import io.netty.channel.ChannelException;
21  import io.netty.channel.ChannelFuture;
22  import io.netty.channel.ChannelMetadata;
23  import io.netty.channel.ChannelOutboundBuffer;
24  import io.netty.channel.ChannelPromise;
25  import io.netty.channel.oio.AbstractOioMessageChannel;
26  import io.netty.channel.sctp.DefaultSctpServerChannelConfig;
27  import io.netty.channel.sctp.SctpServerChannelConfig;
28  import io.netty.util.internal.logging.InternalLogger;
29  import io.netty.util.internal.logging.InternalLoggerFactory;
30  
31  import java.io.IOException;
32  import java.net.InetAddress;
33  import java.net.InetSocketAddress;
34  import java.net.SocketAddress;
35  import java.nio.channels.SelectionKey;
36  import java.nio.channels.Selector;
37  import java.util.Collections;
38  import java.util.Iterator;
39  import java.util.LinkedHashSet;
40  import java.util.List;
41  import java.util.Set;
42  
43  /**
44   * {@link io.netty.channel.sctp.SctpServerChannel} implementation which use blocking mode to accept new
45   * connections and create the {@link OioSctpChannel} for them.
46   *
47   * Be aware that not all operations systems support SCTP. Please refer to the documentation of your operation system,
48   * to understand what you need to do to use it. Also this feature is only supported on Java 7+.
49   *
50   * @deprecated use {@link io.netty.channel.sctp.nio.NioSctpServerChannel}.
51   */
52  @Deprecated
53  public class OioSctpServerChannel extends AbstractOioMessageChannel
54          implements io.netty.channel.sctp.SctpServerChannel {
55  
56      private static final InternalLogger logger =
57              InternalLoggerFactory.getInstance(OioSctpServerChannel.class);
58  
59      private static final ChannelMetadata METADATA = new ChannelMetadata(false, 1);
60  
61      private static SctpServerChannel newServerSocket() {
62          try {
63              return SctpServerChannel.open();
64          } catch (IOException e) {
65              throw new ChannelException("failed to create a sctp server channel", e);
66          }
67      }
68  
69      private final SctpServerChannel sch;
70      private final SctpServerChannelConfig config;
71      private final Selector selector;
72  
73      /**
74       * Create a new instance with an new {@link SctpServerChannel}
75       */
76      public OioSctpServerChannel() {
77          this(newServerSocket());
78      }
79  
80      /**
81       * Create a new instance from the given {@link SctpServerChannel}
82       *
83       * @param sch    the {@link SctpServerChannel} which is used by this instance
84       */
85      public OioSctpServerChannel(SctpServerChannel sch) {
86          super(null);
87          if (sch == null) {
88              throw new NullPointerException("sctp server channel");
89          }
90  
91          this.sch = sch;
92          boolean success = false;
93          try {
94              sch.configureBlocking(false);
95              selector = Selector.open();
96              sch.register(selector, SelectionKey.OP_ACCEPT);
97              config = new OioSctpServerChannelConfig(this, sch);
98              success = true;
99          } catch (Exception e) {
100             throw new ChannelException("failed to initialize a sctp server channel", e);
101         } finally {
102             if (!success) {
103                 try {
104                     sch.close();
105                 } catch (IOException e) {
106                     logger.warn("Failed to close a sctp server channel.", e);
107                 }
108             }
109         }
110     }
111 
112     @Override
113     public ChannelMetadata metadata() {
114         return METADATA;
115     }
116 
117     @Override
118     public SctpServerChannelConfig config() {
119         return config;
120     }
121 
122     @Override
123     public InetSocketAddress remoteAddress() {
124         return null;
125     }
126 
127     @Override
128     public InetSocketAddress localAddress() {
129         return (InetSocketAddress) super.localAddress();
130     }
131 
132     @Override
133     public boolean isOpen() {
134         return sch.isOpen();
135     }
136 
137     @Override
138     protected SocketAddress localAddress0() {
139         try {
140             Iterator<SocketAddress> i = sch.getAllLocalAddresses().iterator();
141             if (i.hasNext()) {
142                 return i.next();
143             }
144         } catch (IOException e) {
145             // ignore
146         }
147         return null;
148     }
149 
150     @Override
151     public Set<InetSocketAddress> allLocalAddresses() {
152         try {
153             final Set<SocketAddress> allLocalAddresses = sch.getAllLocalAddresses();
154             final Set<InetSocketAddress> addresses = new LinkedHashSet<InetSocketAddress>(allLocalAddresses.size());
155             for (SocketAddress socketAddress : allLocalAddresses) {
156                 addresses.add((InetSocketAddress) socketAddress);
157             }
158             return addresses;
159         } catch (Throwable ignored) {
160             return Collections.emptySet();
161         }
162     }
163 
164     @Override
165     public boolean isActive() {
166         return isOpen() && localAddress0() != null;
167     }
168 
169     @Override
170     protected void doBind(SocketAddress localAddress) throws Exception {
171         sch.bind(localAddress, config.getBacklog());
172     }
173 
174     @Override
175     protected void doClose() throws Exception {
176         try {
177             selector.close();
178         } catch (IOException e) {
179             logger.warn("Failed to close a selector.", e);
180         }
181         sch.close();
182     }
183 
184     @Override
185     protected int doReadMessages(List<Object> buf) throws Exception {
186         if (!isActive()) {
187             return -1;
188         }
189 
190         SctpChannel s = null;
191         int acceptedChannels = 0;
192         try {
193             final int selectedKeys = selector.select(SO_TIMEOUT);
194             if (selectedKeys > 0) {
195                 final Iterator<SelectionKey> selectionKeys = selector.selectedKeys().iterator();
196                 for (;;) {
197                     SelectionKey key = selectionKeys.next();
198                     selectionKeys.remove();
199                     if (key.isAcceptable()) {
200                         s = sch.accept();
201                         if (s != null) {
202                             buf.add(new OioSctpChannel(this, s));
203                             acceptedChannels ++;
204                         }
205                     }
206                     if (!selectionKeys.hasNext()) {
207                         return acceptedChannels;
208                     }
209                 }
210             }
211         } catch (Throwable t) {
212             logger.warn("Failed to create a new channel from an accepted sctp channel.", t);
213             if (s != null) {
214                 try {
215                     s.close();
216                 } catch (Throwable t2) {
217                     logger.warn("Failed to close a sctp channel.", t2);
218                 }
219             }
220         }
221 
222         return acceptedChannels;
223     }
224 
225     @Override
226     public ChannelFuture bindAddress(InetAddress localAddress) {
227         return bindAddress(localAddress, newPromise());
228     }
229 
230     @Override
231     public ChannelFuture bindAddress(final InetAddress localAddress, final ChannelPromise promise) {
232         if (eventLoop().inEventLoop()) {
233             try {
234                 sch.bindAddress(localAddress);
235                 promise.setSuccess();
236             } catch (Throwable t) {
237                 promise.setFailure(t);
238             }
239         } else {
240             eventLoop().execute(new Runnable() {
241                 @Override
242                 public void run() {
243                     bindAddress(localAddress, promise);
244                 }
245             });
246         }
247         return promise;
248     }
249 
250     @Override
251     public ChannelFuture unbindAddress(InetAddress localAddress) {
252         return unbindAddress(localAddress, newPromise());
253     }
254 
255     @Override
256     public ChannelFuture unbindAddress(final InetAddress localAddress, final ChannelPromise promise) {
257         if (eventLoop().inEventLoop()) {
258             try {
259                 sch.unbindAddress(localAddress);
260                 promise.setSuccess();
261             } catch (Throwable t) {
262                 promise.setFailure(t);
263             }
264         } else {
265             eventLoop().execute(new Runnable() {
266                 @Override
267                 public void run() {
268                     unbindAddress(localAddress, promise);
269                 }
270             });
271         }
272         return promise;
273     }
274 
275     @Override
276     protected void doConnect(
277             SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
278         throw new UnsupportedOperationException();
279     }
280 
281     @Override
282     protected SocketAddress remoteAddress0() {
283         return null;
284     }
285 
286     @Override
287     protected void doDisconnect() throws Exception {
288         throw new UnsupportedOperationException();
289     }
290 
291     @Override
292     protected void doWrite(ChannelOutboundBuffer in) throws Exception {
293         throw new UnsupportedOperationException();
294     }
295 
296     @Override
297     protected Object filterOutboundMessage(Object msg) throws Exception {
298         throw new UnsupportedOperationException();
299     }
300 
301     private final class OioSctpServerChannelConfig extends DefaultSctpServerChannelConfig {
302         private OioSctpServerChannelConfig(OioSctpServerChannel channel, SctpServerChannel javaChannel) {
303             super(channel, javaChannel);
304         }
305 
306         @Override
307         protected void autoReadCleared() {
308             clearReadPending();
309         }
310     }
311 }