1
18
19 package org.xnio.nio;
20
21 import java.io.IOException;
22 import java.net.InetSocketAddress;
23 import java.net.Socket;
24 import java.net.SocketAddress;
25 import java.nio.channels.ClosedChannelException;
26 import java.nio.channels.SelectionKey;
27 import java.nio.channels.SocketChannel;
28 import java.util.Set;
29 import org.xnio.Option;
30 import org.xnio.Options;
31
32
35 final class NioSocketStreamConnection extends AbstractNioStreamConnection {
36
37 private final ChannelClosed closedHandle;
38 private final NioSocketConduit conduit;
39
40 NioSocketStreamConnection(final WorkerThread workerThread, final SelectionKey key, final ChannelClosed closedHandle) {
41 super(workerThread);
42 conduit = new NioSocketConduit(workerThread, key, this);
43 key.attach(conduit);
44 this.closedHandle = closedHandle;
45 setSinkConduit(conduit);
46 setSourceConduit(conduit);
47 }
48
49 public SocketAddress getPeerAddress() {
50 final Socket socket = conduit.getSocketChannel().socket();
51 return new InetSocketAddress(socket.getInetAddress(), socket.getPort());
52 }
53
54 public SocketAddress getLocalAddress() {
55 final Socket socket = conduit.getSocketChannel().socket();
56 return new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
57 }
58
59 private static final Set<Option<?>> OPTIONS = Option.setBuilder()
60 .add(Options.CLOSE_ABORT)
61 .add(Options.IP_TRAFFIC_CLASS)
62 .add(Options.KEEP_ALIVE)
63 .add(Options.READ_TIMEOUT)
64 .add(Options.RECEIVE_BUFFER)
65 .add(Options.SEND_BUFFER)
66 .add(Options.TCP_NODELAY)
67 .add(Options.TCP_OOB_INLINE)
68 .add(Options.WRITE_TIMEOUT)
69 .create();
70
71 public boolean supportsOption(final Option<?> option) {
72 return OPTIONS.contains(option);
73 }
74
75 public <T> T getOption(final Option<T> option) throws IOException {
76 if (option == Options.CLOSE_ABORT) {
77 return option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getSoLinger() == 0));
78 } else if (option == Options.IP_TRAFFIC_CLASS) {
79 return option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getTrafficClass()));
80 } else if (option == Options.KEEP_ALIVE) {
81 return option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getKeepAlive()));
82 } else if (option == Options.READ_TIMEOUT) {
83 return option.cast(Integer.valueOf(conduit.getReadTimeout()));
84 } else if (option == Options.RECEIVE_BUFFER) {
85 return option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getReceiveBufferSize()));
86 } else if (option == Options.SEND_BUFFER) {
87 return option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getSendBufferSize()));
88 } else if (option == Options.TCP_NODELAY) {
89 return option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getTcpNoDelay()));
90 } else if (option == Options.TCP_OOB_INLINE) {
91 return option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getOOBInline()));
92 } else if (option == Options.WRITE_TIMEOUT) {
93 return option.cast(Integer.valueOf(conduit.getWriteTimeout()));
94 } else {
95 return null;
96 }
97 }
98
99 public <T> T setOption(final Option<T> option, final T value) throws IllegalArgumentException, IOException {
100 T result;
101 if (option == Options.CLOSE_ABORT) {
102 result = option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getSoLinger() == 0));
103 conduit.getSocketChannel().socket().setSoLinger(Options.CLOSE_ABORT.cast(value, Boolean.FALSE).booleanValue(), 0);
104 } else if (option == Options.IP_TRAFFIC_CLASS) {
105 result = option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getTrafficClass()));
106 conduit.getSocketChannel().socket().setTrafficClass(Options.IP_TRAFFIC_CLASS.cast(value).intValue());
107 } else if (option == Options.KEEP_ALIVE) {
108 result = option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getKeepAlive()));
109 conduit.getSocketChannel().socket().setKeepAlive(Options.KEEP_ALIVE.cast(value, Boolean.FALSE).booleanValue());
110 } else if (option == Options.READ_TIMEOUT) {
111 result = option.cast(Integer.valueOf(conduit.getAndSetReadTimeout(value == null ? 0 : Options.READ_TIMEOUT.cast(value).intValue())));
112 } else if (option == Options.RECEIVE_BUFFER) {
113 result = option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getReceiveBufferSize()));
114 conduit.getSocketChannel().socket().setReceiveBufferSize(Options.RECEIVE_BUFFER.cast(value).intValue());
115 } else if (option == Options.SEND_BUFFER) {
116 result = option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getSendBufferSize()));
117 conduit.getSocketChannel().socket().setSendBufferSize(Options.SEND_BUFFER.cast(value).intValue());
118 } else if (option == Options.TCP_NODELAY) {
119 result = option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getTcpNoDelay()));
120 conduit.getSocketChannel().socket().setTcpNoDelay(Options.TCP_NODELAY.cast(value, Boolean.FALSE).booleanValue());
121 } else if (option == Options.TCP_OOB_INLINE) {
122 result = option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getOOBInline()));
123 conduit.getSocketChannel().socket().setOOBInline(Options.TCP_OOB_INLINE.cast(value, Boolean.FALSE).booleanValue());
124 } else if (option == Options.WRITE_TIMEOUT) {
125 result = option.cast(Integer.valueOf(conduit.getAndSetWriteTimeout(value == null ? 0 : Options.WRITE_TIMEOUT.cast(value).intValue())));
126 } else {
127 return null;
128 }
129 return result;
130 }
131
132 protected void closeAction() throws IOException {
133 try {
134 conduit.cancelKey(false);
135 conduit.getSocketChannel().close();
136 } catch (ClosedChannelException ignored) {
137 } finally {
138 final ChannelClosed closedHandle = this.closedHandle;
139 if (closedHandle!= null) closedHandle.channelClosed();
140 }
141 }
142
143 protected void notifyWriteClosed() {
144 conduit.writeTerminated();
145 }
146
147 protected void notifyReadClosed() {
148 conduit.readTerminated();
149 }
150
151 SocketChannel getChannel() {
152 return conduit.getSocketChannel();
153 }
154
155 NioSocketConduit getConduit() {
156 return conduit;
157 }
158 }
159