1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.common.io;
20
21 import java.io.IOException;
22 import java.util.concurrent.atomic.AtomicBoolean;
23
24 import org.eclipse.jetty.util.log.Log;
25 import org.eclipse.jetty.util.log.Logger;
26 import org.eclipse.jetty.websocket.common.ConnectionState;
27
28
29
30
31 public class IOState
32 {
33 private static final Logger LOG = Log.getLogger(IOState.class);
34 private ConnectionState state;
35 private final AtomicBoolean inputClosed;
36 private final AtomicBoolean outputClosed;
37
38 private final AtomicBoolean cleanClose;
39 private final AtomicBoolean remoteCloseInitiated;
40 private final AtomicBoolean localCloseInitiated;
41
42 public IOState()
43 {
44 this.state = ConnectionState.CONNECTING;
45 this.inputClosed = new AtomicBoolean(false);
46 this.outputClosed = new AtomicBoolean(false);
47 this.remoteCloseInitiated = new AtomicBoolean(false);
48 this.localCloseInitiated = new AtomicBoolean(false);
49 this.cleanClose = new AtomicBoolean(false);
50 }
51
52 public void assertInputOpen() throws IOException
53 {
54 if (isInputClosed())
55 {
56 throw new IOException("Connection input is closed");
57 }
58 }
59
60 public void assertOutputOpen() throws IOException
61 {
62 if (isOutputClosed())
63 {
64 throw new IOException("Connection output is closed");
65 }
66 }
67
68 public boolean awaitClosed(long duration)
69 {
70 return (isInputClosed() && isOutputClosed());
71 }
72
73 public ConnectionState getConnectionState()
74 {
75 return state;
76 }
77
78 public ConnectionState getState()
79 {
80 return state;
81 }
82
83 public boolean isClosed()
84 {
85 return (isInputClosed() && isOutputClosed());
86 }
87
88 public boolean isCloseInitiated()
89 {
90 return remoteCloseInitiated.get() || localCloseInitiated.get();
91 }
92
93 public boolean isInputClosed()
94 {
95 return inputClosed.get();
96 }
97
98 public boolean isOpen()
99 {
100 return (getState() != ConnectionState.CLOSED);
101 }
102
103 public boolean isOutputClosed()
104 {
105 return outputClosed.get();
106 }
107
108
109
110
111
112
113
114
115
116
117 public boolean onCloseHandshake(boolean incoming)
118 {
119 boolean in = inputClosed.get();
120 boolean out = outputClosed.get();
121 if (incoming)
122 {
123 in = true;
124 this.inputClosed.set(true);
125
126 if (!localCloseInitiated.get())
127 {
128 remoteCloseInitiated.set(true);
129 }
130 }
131 else
132 {
133 out = true;
134 this.outputClosed.set(true);
135
136 if ( !remoteCloseInitiated.get() )
137 {
138 localCloseInitiated.set(true);
139 }
140 }
141
142 LOG.debug("onCloseHandshake({}), input={}, output={}",incoming,in,out);
143
144 if (in && out)
145 {
146 LOG.debug("Close Handshake satisfied, disconnecting");
147 cleanClose.set(true);
148 return true;
149 }
150
151 return false;
152 }
153
154 public void setConnectionState(ConnectionState connectionState)
155 {
156 this.state = connectionState;
157 }
158
159 public void setState(ConnectionState state)
160 {
161 this.state = state;
162 }
163
164 public boolean wasCleanClose()
165 {
166 return cleanClose.get();
167 }
168
169 public boolean wasLocalCloseInitiated()
170 {
171 return localCloseInitiated.get();
172 }
173
174 public boolean wasRemoteCloseInitiated()
175 {
176 return remoteCloseInitiated.get();
177 }
178 }