1 /*
2  * JBoss, Home of Professional Open Source
3  *
4  * Copyright 2013 Red Hat, Inc. and/or its affiliates.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * 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, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

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 /**
33  * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
34  */

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