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
96 final byte data[] = new byte[DEFAULT_BUFFER_SIZE];
97 final DatagramPacket packet = new DatagramPacket(data, data.length);
98 socket.receive(packet);
99
100
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 }