View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.transport.socket.nio;
    21
    22  import java.net.Inet4Address;
    23  import java.net.Inet6Address;
    24  import java.net.InetAddress;
    25  import java.net.InetSocketAddress;
    26  import java.net.SocketAddress;
    27  import java.nio.channels.DatagramChannel;
    28  import java.nio.channels.SelectionKey;
    29  import java.nio.channels.Selector;
    30  import java.util.Set;
    31  import java.util.concurrent.Executor;
    32
    33  import org.apache.mina.core.buffer.IoBuffer;
    34  import org.apache.mina.core.polling.AbstractPollingConnectionlessIoAcceptor;
    35  import org.apache.mina.core.service.IoAcceptor;
    36  import org.apache.mina.core.service.IoProcessor;
    37  import org.apache.mina.core.service.TransportMetadata;
    38  import org.apache.mina.transport.socket.DatagramAcceptor;
    39  import org.apache.mina.transport.socket.DatagramSessionConfig;
    40  import org.apache.mina.transport.socket.DefaultDatagramSessionConfig;
    41
    42  /**
    43   * {@link IoAcceptor} for datagram transport (UDP/IP).
    44   *
    45   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    46   * @org.apache.xbean.XBean
    47   */
    48  public final class NioDatagramAcceptor extends AbstractPollingConnectionlessIoAcceptor<NioSession, DatagramChannel>
    49          implements DatagramAcceptor {
    50
    51      private volatile Selector selector;
    52
    53      /**
    54       * Creates a new instance.
    55       */
    56      public NioDatagramAcceptor() {
    57          super(new DefaultDatagramSessionConfig());
    58      }
    59
    60      /**
    61       * Creates a new instance.
    62       */
    63      public NioDatagramAcceptor(Executor executor) {
    64          super(new DefaultDatagramSessionConfig(), executor);
    65      }
    66
    67      @Override
    68      protected void init() throws Exception {
    69          this.selector = Selector.open();
    70      }
    71
    72      @Override
    73      protected void destroy() throws Exception {
    74          if (selector != null) {
    75              selector.close();
    76          }
    77      }
    78
    79      public TransportMetadata getTransportMetadata() {
    80          return NioDatagramSession.METADATA;
    81      }
    82
    83      @Override
    84      public DatagramSessionConfig getSessionConfig() {
    85          return (DatagramSessionConfig) super.getSessionConfig();
    86      }
    87
    88      @Override
    89      public InetSocketAddress getLocalAddress() {
    90          return (InetSocketAddress) super.getLocalAddress();
    91      }
    92
    93      @Override
    94      public InetSocketAddress getDefaultLocalAddress() {
    95          return (InetSocketAddress) super.getDefaultLocalAddress();
    96      }
    97
    98      public void setDefaultLocalAddress(InetSocketAddress localAddress) {
    99          setDefaultLocalAddress((SocketAddress) localAddress);
    100     }
    101
    102     @Override
    103     protected DatagramChannel open(SocketAddress localAddress) throws Exception {
    104         final DatagramChannel c = DatagramChannel.open();
    105         boolean success = false;
    106         try {
    107             new NioDatagramSessionConfig(c).setAll(getSessionConfig());
    108             c.configureBlocking(false);
    109             c.socket().bind(localAddress);
    110             c.register(selector, SelectionKey.OP_READ);
    111             success = true;
    112         } finally {
    113             if (!success) {
    114                 close(c);
    115             }
    116         }
    117
    118         return c;
    119     }
    120
    121     @Override
    122     protected boolean isReadable(DatagramChannel handle) {
    123         SelectionKey key = handle.keyFor(selector);
    124
    125         if ((key == null) || (!key.isValid())) {
    126             return false;
    127         }
    128
    129         return key.isReadable();
    130     }
    131
    132     @Override
    133     protected boolean isWritable(DatagramChannel handle) {
    134         SelectionKey key = handle.keyFor(selector);
    135
    136         if ((key == null) || (!key.isValid())) {
    137             return false;
    138         }
    139
    140         return key.isWritable();
    141     }
    142
    143     @Override
    144     protected SocketAddress localAddress(DatagramChannel handle) throws Exception {
    145         InetSocketAddress inetSocketAddress = (InetSocketAddress) handle.socket().getLocalSocketAddress();
    146         InetAddress inetAddress = inetSocketAddress.getAddress();
    147
    148         if ((inetAddress instanceof Inet6Address) && (((Inet6Address) inetAddress).isIPv4CompatibleAddress())) {
    149             // Ugly hack to workaround a problem on linux : the ANY address is always converted to IPV6
    150             // even if the original address was an IPV4 address. We do store the two IPV4 and IPV6
    151             // ANY address in the map.
    152             byte[] ipV6Address = ((Inet6Address) inetAddress).getAddress();
    153             byte[] ipV4Address = new byte[4];
    154
    155             for (int i = 0; i < 4; i++) {
    156                 ipV4Address[i] = ipV6Address[12 + i];
    157             }
    158
    159             InetAddress inet4Adress = Inet4Address.getByAddress(ipV4Address);
    160             return new InetSocketAddress(inet4Adress, inetSocketAddress.getPort());
    161         } else {
    162             return inetSocketAddress;
    163         }
    164     }
    165
    166     @Override
    167     protected NioSession newSession(IoProcessor<NioSession> processor, DatagramChannel handle,
    168             SocketAddress remoteAddress) {
    169         SelectionKey key = handle.keyFor(selector);
    170
    171         if ((key == null) || (!key.isValid())) {
    172             return null;
    173         }
    174
    175         NioDatagramSession newSession = new NioDatagramSession(this, handle, processor, remoteAddress);
    176         newSession.setSelectionKey(key);
    177
    178         return newSession;
    179     }
    180
    181     @Override
    182     protected SocketAddress receive(DatagramChannel handle, IoBuffer buffer) throws Exception {
    183         return handle.receive(buffer.buf());
    184     }
    185
    186     @Override
    187     protected int select() throws Exception {
    188         return selector.select();
    189     }
    190
    191     @Override
    192     protected int select(long timeout) throws Exception {
    193         return selector.select(timeout);
    194     }
    195
    196     @Override
    197     protected Set<SelectionKey> selectedHandles() {
    198         return selector.selectedKeys();
    199     }
    200
    201     @Override
    202     protected int send(NioSession session, IoBuffer buffer, SocketAddress remoteAddress) throws Exception {
    203         return ((DatagramChannel) session.getChannel()).send(buffer.buf(), remoteAddress);
    204     }
    205
    206     @Override
    207     protected void setInterestedInWrite(NioSession session, boolean isInterested) throws Exception {
    208         SelectionKey key = session.getSelectionKey();
    209
    210         if (key == null) {
    211             return;
    212         }
    213
    214         int newInterestOps = key.interestOps();
    215
    216         if (isInterested) {
    217             newInterestOps |= SelectionKey.OP_WRITE;
    218             //newInterestOps &= ~SelectionKey.OP_READ;
    219         } else {
    220             newInterestOps &= ~SelectionKey.OP_WRITE;
    221             //newInterestOps |= SelectionKey.OP_READ;
    222         }
    223
    224         key.interestOps(newInterestOps);
    225     }
    226
    227     @Override
    228     protected void close(DatagramChannel handle) throws Exception {
    229         SelectionKey key = handle.keyFor(selector);
    230
    231         if (key != null) {
    232             key.cancel();
    233         }
    234
    235         handle.disconnect();
    236         handle.close();
    237     }
    238
    239     @Override
    240     protected void wakeup() {
    241         selector.wakeup();
    242     }
    243 }