View Javadoc

    1   /***
    2    *
    3    * Copyright 2004 Hiram Chirino
    4    *
    5    * Licensed under the Apache License, Version 2.0 (the "License");
    6    * you may not use this file except in compliance with the License.
    7    * You may obtain a copy of the License at
    8    *
    9    * http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   **/
    18
    19  package org.activeio.net;
    20
    21  import java.io.IOException;
    22  import java.net.DatagramPacket;
    23  import java.net.DatagramSocket;
    24  import java.net.SocketException;
    25  import java.net.SocketTimeoutException;
    26
    27  import org.activeio.Packet;
    28  import org.activeio.SynchChannel;
    29  import org.activeio.SynchChannelServer;
    30  import org.activeio.Packet.ByteSequence;
    31  import org.activeio.packet.ByteArrayPacket;
    32  import org.activeio.packet.FilterPacket;
    33
    34  /***
    35   * A {@see org.activeio.SynchChannel}implementation that uses
    36   * TCP to talk to the network.
    37   *
    38   * @version $Revision$
    39   */
    40  final public class DatagramSocketSynchChannel implements SynchChannel {
    41
    42      private final class UDPFilterPacket extends FilterPacket {
    43          private final DatagramPacket packet;
    44
    45          private UDPFilterPacket(Packet next, DatagramPacket packet) {
    46              super(next);
    47              this.packet = packet;
    48          }
    49
    50          public Object narrow(Class target) {
    51              if( target == DatagramContext.class ) {
    52                  return new DatagramContext(packet);
    53              }
    54              return super.narrow(target);
    55          }
    56
    57          public Packet filter(Packet packet) {
    58              return new UDPFilterPacket(packet, this.packet);
    59          }
    60      }
    61
    62      private static final int DEFAULT_BUFFER_SIZE = 64 * 1024;
    63
    64      private final DatagramSocket socket;
    65
    66      private boolean disposed;
    67
    68      private int curentSoTimeout;
    69
    70      /***
    71       * Construct basic helpers
    72       *
    73       * @param wireFormat
    74       * @throws IOException
    75       */
    76      protected DatagramSocketSynchChannel(DatagramSocket socket) throws IOException {
    77          this.socket = socket;
    78          socket.setReceiveBufferSize(DEFAULT_BUFFER_SIZE);
    79          socket.setSendBufferSize(DEFAULT_BUFFER_SIZE);
    80      }
    81
    82      /***
    83       * @see org.activeio.SynchChannel#read(long)
    84       */
    85      public org.activeio.Packet read(long timeout) throws IOException {
    86          try {
    87
    88              if (timeout == SynchChannelServer.WAIT_FOREVER_TIMEOUT)
    89                  setSoTimeout(0);
    90              else if (timeout == SynchChannelServer.NO_WAIT_TIMEOUT)
    91                  setSoTimeout(1);
    92              else
    93                  setSoTimeout((int) timeout);
    94
    95              // FYI: message data is truncated if biger than this buffer.
    96              final byte data[] = new byte[DEFAULT_BUFFER_SIZE];
    97              final DatagramPacket packet = new DatagramPacket(data, data.length);
    98              socket.receive(packet);
    99
    100             // A FilterPacket is used to provide the UdpDatagramContext via narrow.
    101             return new UDPFilterPacket(new ByteArrayPacket(data, 0, packet.getLength()), packet);
    102
    103         } catch (SocketTimeoutException e) {
    104             return null;
    105         }
    106     }
    107
    108     private void setSoTimeout(int i) throws SocketException {
    109         if (curentSoTimeout != i) {
    110             socket.setSoTimeout(i);
    111             curentSoTimeout = i;
    112         }
    113     }
    114
    115     /***
    116      * @see org.activeio.Channel#write(org.activeio.channel.Packet)
    117      */
    118     public void write(org.activeio.Packet packet) throws IOException {
    119         ByteSequence sequence = packet.asByteSequence();
    120
    121         DatagramContext context = (DatagramContext) packet.narrow(DatagramContext.class);
    122         if( context!=null ) {
    123             socket.send(new DatagramPacket(sequence.getData(),sequence.getOffset(), sequence.getLength(), context.address, context.port.intValue()));
    124         } else {
    125             socket.send(new DatagramPacket(sequence.getData(),sequence.getOffset(), sequence.getLength()));
    126         }
    127     }
    128
    129     /***
    130      * @see org.activeio.Channel#flush()
    131      */
    132     public void flush() throws IOException {
    133     }
    134
    135     /***
    136      * @see org.activeio.Disposable#dispose()
    137      */
    138     public void dispose() {
    139         if (disposed)
    140             return;
    141         socket.close();
    142         disposed = true;
    143     }
    144
    145     public void start() throws IOException {
    146     }
    147
    148     public void stop(long timeout) throws IOException {
    149     }
    150
    151
    152     public Object narrow(Class target) {
    153         if( target.isAssignableFrom(getClass()) ) {
    154             return this;
    155         }
    156         return null;
    157     }
    158
    159     public String toString() {
    160         return "Datagram Connection: "+socket.getLocalSocketAddress()+" -> "+socket.getRemoteSocketAddress();
    161     }
    162 }