1
18
19 package org.xnio;
20
21 import java.io.IOException;
22 import java.net.SocketAddress;
23 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
24 import org.xnio.channels.CloseableChannel;
25 import org.xnio.channels.ConnectedChannel;
26
27 import static org.xnio.Bits.allAreClear;
28 import static org.xnio.Bits.allAreSet;
29 import static org.xnio.Bits.anyAreClear;
30
31
36 public abstract class Connection implements CloseableChannel, ConnectedChannel {
37
38 protected final XnioIoThread thread;
39 @SuppressWarnings("unused")
40 private volatile int state;
41
42 private static final int FLAG_READ_CLOSED = 0b0001;
43 private static final int FLAG_WRITE_CLOSED = 0b0010;
44
45 private static final AtomicIntegerFieldUpdater<Connection> stateUpdater = AtomicIntegerFieldUpdater.newUpdater(Connection.class, "state");
46
47
52 protected Connection(final XnioIoThread thread) {
53 this.thread = thread;
54 }
55
56 private static <A extends SocketAddress> A castAddress(final Class<A> type, SocketAddress address) {
57 return type.isInstance(address) ? type.cast(address) : null;
58 }
59
60 public final <A extends SocketAddress> A getPeerAddress(final Class<A> type) {
61 return castAddress(type, getPeerAddress());
62 }
63
64 public final <A extends SocketAddress> A getLocalAddress(final Class<A> type) {
65 return castAddress(type, getLocalAddress());
66 }
67
68 public final XnioWorker getWorker() {
69 return thread.getWorker();
70 }
71
72 public XnioIoThread getIoThread() {
73 return thread;
74 }
75
76
81 protected boolean readClosed() {
82 int oldVal, newVal;
83 do {
84 oldVal = state;
85 if (allAreSet(oldVal, FLAG_READ_CLOSED)) {
86 return false;
87 }
88 newVal = oldVal | FLAG_READ_CLOSED;
89 } while (! stateUpdater.compareAndSet(this, oldVal, newVal));
90 if (allAreSet(newVal, FLAG_READ_CLOSED | FLAG_WRITE_CLOSED)) {
91 try {
92 closeAction();
93 } catch (Throwable ignored) {}
94 invokeCloseListener();
95 }
96 return true;
97 }
98
99
104 protected boolean writeClosed() {
105 int oldVal, newVal;
106 do {
107 oldVal = state;
108 if (allAreSet(oldVal, FLAG_WRITE_CLOSED)) {
109 return false;
110 }
111 newVal = oldVal | FLAG_WRITE_CLOSED;
112 } while (! stateUpdater.compareAndSet(this, oldVal, newVal));
113 if (allAreSet(newVal, FLAG_READ_CLOSED | FLAG_WRITE_CLOSED)) {
114 try {
115 closeAction();
116 } catch (Throwable ignored) {}
117 invokeCloseListener();
118 }
119 return true;
120 }
121
122 public final void close() throws IOException {
123 int oldVal, newVal;
124 do {
125 oldVal = state;
126 if (allAreSet(oldVal, FLAG_WRITE_CLOSED | FLAG_READ_CLOSED)) {
127 return;
128 }
129 newVal = oldVal | FLAG_READ_CLOSED | FLAG_WRITE_CLOSED;
130 } while (! stateUpdater.compareAndSet(this, oldVal, newVal));
131 try {
132 closeAction();
133 } finally {
134 if (allAreClear(oldVal, FLAG_WRITE_CLOSED)) try {
135 notifyWriteClosed();
136 } catch (Throwable ignored) {
137 }
138 if (allAreClear(oldVal, FLAG_READ_CLOSED)) try {
139 notifyReadClosed();
140 } catch (Throwable ignored) {
141 }
142 invokeCloseListener();
143 }
144 }
145
146
151 public boolean isReadShutdown() {
152 return allAreSet(state, FLAG_READ_CLOSED);
153 }
154
155
160 public boolean isWriteShutdown() {
161 return allAreSet(state, FLAG_WRITE_CLOSED);
162 }
163
164 public boolean isOpen() {
165 return anyAreClear(state, FLAG_READ_CLOSED | FLAG_WRITE_CLOSED);
166 }
167
168
171 protected abstract void notifyWriteClosed();
172
173
176 protected abstract void notifyReadClosed();
177
178 abstract void invokeCloseListener();
179
180
185 protected void closeAction() throws IOException {}
186
187 public boolean supportsOption(final Option<?> option) {
188 return false;
189 }
190
191 public <T> T getOption(final Option<T> option) throws IOException {
192 return null;
193 }
194
195 public <T> T setOption(final Option<T> option, final T value) throws IllegalArgumentException, IOException {
196 return null;
197 }
198 }
199