View Javadoc

1   /*
2    * Copyright 2009 Red Hat, Inc.
3    *
4    * Red Hat licenses this file to you under the Apache License, version 2.0
5    * (the "License"); you may not use this file except in compliance with the
6    * 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 org.jboss.netty.channel.socket.oio;
17  
18  import static org.jboss.netty.channel.Channels.*;
19  
20  import java.io.IOException;
21  import java.net.InetAddress;
22  import java.net.InetSocketAddress;
23  import java.net.MulticastSocket;
24  import java.net.NetworkInterface;
25  import java.net.SocketAddress;
26  import java.net.SocketException;
27  
28  import org.jboss.netty.channel.AbstractChannel;
29  import org.jboss.netty.channel.ChannelException;
30  import org.jboss.netty.channel.ChannelFactory;
31  import org.jboss.netty.channel.ChannelFuture;
32  import org.jboss.netty.channel.ChannelPipeline;
33  import org.jboss.netty.channel.ChannelSink;
34  import org.jboss.netty.channel.socket.DatagramChannel;
35  import org.jboss.netty.channel.socket.DatagramChannelConfig;
36  import org.jboss.netty.channel.socket.DefaultDatagramChannelConfig;
37  
38  /**
39   *
40   * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
41   * @author <a href="http://gleamynode.net/">Trustin Lee</a>
42   *
43   * @version $Rev: 2080 $, $Date: 2010-01-26 18:04:19 +0900 (Tue, 26 Jan 2010) $
44   *
45   */
46  final class OioDatagramChannel extends AbstractChannel
47                                  implements DatagramChannel {
48  
49      final MulticastSocket socket;
50      final Object interestOpsLock = new Object();
51      private final DatagramChannelConfig config;
52      volatile Thread workerThread;
53      private volatile InetSocketAddress localAddress;
54      volatile InetSocketAddress remoteAddress;
55  
56      OioDatagramChannel(
57              ChannelFactory factory,
58              ChannelPipeline pipeline,
59              ChannelSink sink) {
60  
61          super(null, factory, pipeline, sink);
62  
63          try {
64              socket = new MulticastSocket(null);
65          } catch (IOException e) {
66              throw new ChannelException("Failed to open a datagram socket.", e);
67          }
68  
69          try {
70              socket.setSoTimeout(10);
71              socket.setBroadcast(false);
72          } catch (SocketException e) {
73              throw new ChannelException(
74                      "Failed to configure the datagram socket timeout.", e);
75          }
76          config = new DefaultDatagramChannelConfig(socket);
77  
78          fireChannelOpen(this);
79      }
80  
81      public DatagramChannelConfig getConfig() {
82          return config;
83      }
84  
85      public InetSocketAddress getLocalAddress() {
86          InetSocketAddress localAddress = this.localAddress;
87          if (localAddress == null) {
88              try {
89                  this.localAddress = localAddress =
90                      (InetSocketAddress) socket.getLocalSocketAddress();
91              } catch (Throwable t) {
92                  // Sometimes fails on a closed socket in Windows.
93                  return null;
94              }
95          }
96          return localAddress;
97      }
98  
99      public InetSocketAddress getRemoteAddress() {
100         InetSocketAddress remoteAddress = this.remoteAddress;
101         if (remoteAddress == null) {
102             try {
103                 this.remoteAddress = remoteAddress =
104                     (InetSocketAddress) socket.getRemoteSocketAddress();
105             } catch (Throwable t) {
106                 // Sometimes fails on a closed socket in Windows.
107                 return null;
108             }
109         }
110         return remoteAddress;
111     }
112 
113     public boolean isBound() {
114         return isOpen() && socket.isBound();
115     }
116 
117     public boolean isConnected() {
118         return isOpen() && socket.isConnected();
119     }
120 
121     @Override
122     protected boolean setClosed() {
123         return super.setClosed();
124     }
125 
126     @Override
127     protected void setInterestOpsNow(int interestOps) {
128         super.setInterestOpsNow(interestOps);
129     }
130 
131     @Override
132     public ChannelFuture write(Object message, SocketAddress remoteAddress) {
133         if (remoteAddress == null || remoteAddress.equals(getRemoteAddress())) {
134             return super.write(message, null);
135         } else {
136             return super.write(message, remoteAddress);
137         }
138     }
139 
140     public void joinGroup(InetAddress multicastAddress) {
141         ensureBound();
142         try {
143             socket.joinGroup(multicastAddress);
144         } catch (IOException e) {
145             throw new ChannelException(e);
146         }
147     }
148 
149     public void joinGroup(
150             InetSocketAddress multicastAddress, NetworkInterface networkInterface) {
151         ensureBound();
152         try {
153             socket.joinGroup(multicastAddress, networkInterface);
154         } catch (IOException e) {
155             throw new ChannelException(e);
156         }
157     }
158 
159     private void ensureBound() {
160         if (!isBound()) {
161             throw new IllegalStateException(
162                     DatagramChannel.class.getName() +
163                     " must be bound to join a group.");
164         }
165     }
166 
167     public void leaveGroup(InetAddress multicastAddress) {
168         try {
169             socket.leaveGroup(multicastAddress);
170         } catch (IOException e) {
171             throw new ChannelException(e);
172         }
173     }
174 
175     public void leaveGroup(
176             InetSocketAddress multicastAddress, NetworkInterface networkInterface) {
177         try {
178             socket.leaveGroup(multicastAddress, networkInterface);
179         } catch (IOException e) {
180             throw new ChannelException(e);
181         }
182     }
183 }