1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.client.io;
20
21 import java.io.IOException;
22 import java.net.InetSocketAddress;
23 import java.net.SocketAddress;
24 import java.net.URI;
25 import java.nio.channels.SocketChannel;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.Locale;
29 import java.util.Queue;
30 import java.util.concurrent.ConcurrentLinkedQueue;
31
32 import org.eclipse.jetty.util.component.ContainerLifeCycle;
33 import org.eclipse.jetty.util.log.Log;
34 import org.eclipse.jetty.util.log.Logger;
35 import org.eclipse.jetty.websocket.api.StatusCode;
36 import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
37 import org.eclipse.jetty.websocket.client.WebSocketClient;
38 import org.eclipse.jetty.websocket.common.WebSocketSession;
39 import org.eclipse.jetty.websocket.common.events.EventDriver;
40
41
42
43
44
45 public class ConnectionManager extends ContainerLifeCycle
46 {
47 private class PhysicalConnect extends ConnectPromise
48 {
49 private SocketAddress bindAddress;
50
51 public PhysicalConnect(WebSocketClient client, EventDriver driver, ClientUpgradeRequest request)
52 {
53 super(client,driver,request);
54 this.bindAddress = client.getBindAddress();
55 }
56
57 @Override
58 public void run()
59 {
60 SocketChannel channel = null;
61 try
62 {
63 channel = SocketChannel.open();
64 if (bindAddress != null)
65 {
66 channel.bind(bindAddress);
67 }
68
69 URI wsUri = getRequest().getRequestURI();
70
71 channel.socket().setTcpNoDelay(true);
72 channel.configureBlocking(false);
73
74 InetSocketAddress address = toSocketAddress(wsUri);
75
76 if (channel.connect(address))
77 {
78 getSelector().accept(channel, this);
79 }
80 else
81 {
82 getSelector().connect(channel, this);
83 }
84 }
85 catch (Throwable t)
86 {
87
88 if (channel != null)
89 {
90 try
91 {
92 channel.close();
93 }
94 catch (IOException ignore)
95 {
96 LOG.ignore(ignore);
97 }
98 }
99
100
101 failed(t);
102 }
103 }
104 }
105
106 private static final Logger LOG = Log.getLogger(ConnectionManager.class);
107
108 public static InetSocketAddress toSocketAddress(URI uri)
109 {
110 if (!uri.isAbsolute())
111 {
112 throw new IllegalArgumentException("Cannot get InetSocketAddress of non-absolute URIs");
113 }
114
115 int port = uri.getPort();
116 String scheme = uri.getScheme().toLowerCase(Locale.ENGLISH);
117 if ("ws".equals(scheme))
118 {
119 if (port == (-1))
120 {
121 port = 80;
122 }
123 }
124 else if ("wss".equals(scheme))
125 {
126 if (port == (-1))
127 {
128 port = 443;
129 }
130 }
131 else
132 {
133 throw new IllegalArgumentException("Only support ws:// and wss:// URIs");
134 }
135
136 return new InetSocketAddress(uri.getHost(),port);
137 }
138
139 private final Queue<WebSocketSession> sessions = new ConcurrentLinkedQueue<>();
140 private final WebSocketClient client;
141 private WebSocketClientSelectorManager selector;
142
143 public ConnectionManager(WebSocketClient client)
144 {
145 this.client = client;
146 }
147
148 public void addSession(WebSocketSession session)
149 {
150 sessions.add(session);
151 }
152
153 private void shutdownAllConnections()
154 {
155 for (WebSocketSession session : sessions)
156 {
157 if (session.getConnection() != null)
158 {
159 try
160 {
161 session.getConnection().close(
162 StatusCode.SHUTDOWN,
163 "Shutdown");
164 }
165 catch (Throwable t)
166 {
167 LOG.debug("During Shutdown All Connections",t);
168 }
169 }
170 }
171 }
172
173 public ConnectPromise connect(WebSocketClient client, EventDriver driver, ClientUpgradeRequest request)
174 {
175 return new PhysicalConnect(client,driver,request);
176 }
177
178 @Override
179 protected void doStart() throws Exception
180 {
181 selector = newWebSocketClientSelectorManager(client);
182 selector.setSslContextFactory(client.getSslContextFactory());
183 selector.setConnectTimeout(client.getConnectTimeout());
184 addBean(selector);
185
186 super.doStart();
187 }
188
189 @Override
190 protected void doStop() throws Exception
191 {
192 shutdownAllConnections();
193 sessions.clear();
194 super.doStop();
195 removeBean(selector);
196 }
197
198 public WebSocketClientSelectorManager getSelector()
199 {
200 return selector;
201 }
202
203 public Collection<WebSocketSession> getSessions()
204 {
205 return Collections.unmodifiableCollection(sessions);
206 }
207
208
209
210
211
212
213
214
215 protected WebSocketClientSelectorManager newWebSocketClientSelectorManager(WebSocketClient client)
216 {
217 return new WebSocketClientSelectorManager(client);
218 }
219
220 public void removeSession(WebSocketSession session)
221 {
222 sessions.remove(session);
223 }
224 }