OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * TlsSocket provides a secure (SSL or TLS) client connection to a server. | 6 * TlsSocket provides a secure (SSL or TLS) client connection to a server. |
7 * The certificate provided by the server is checked | 7 * The certificate provided by the server is checked |
8 * using the certificate database provided in setCertificateDatabase. | 8 * using the certificate database provided in setCertificateDatabase. |
9 */ | 9 */ |
10 abstract class TlsSocket implements Socket { | 10 abstract class TlsSocket implements Socket { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 if (_socket == null) { | 75 if (_socket == null) { |
76 _socket = new Socket(host, port); | 76 _socket = new Socket(host, port); |
77 } | 77 } |
78 _socket.onConnect = _tlsConnectHandler; | 78 _socket.onConnect = _tlsConnectHandler; |
79 _socket.onData = _tlsDataHandler; | 79 _socket.onData = _tlsDataHandler; |
80 _socket.onClosed = _tlsCloseHandler; | 80 _socket.onClosed = _tlsCloseHandler; |
81 _tlsFilter.init(); | 81 _tlsFilter.init(); |
82 _tlsFilter.registerHandshakeCompleteCallback(_tlsHandshakeCompleteHandler); | 82 _tlsFilter.registerHandshakeCompleteCallback(_tlsHandshakeCompleteHandler); |
83 } | 83 } |
84 | 84 |
85 InputStream get inputStream { | |
86 // TODO(6701): Implement stream interfaces on TlsSocket. | |
87 throw new UnimplementedError("TlsSocket.inputStream not implemented yet"); | |
88 } | |
89 | |
90 int get port => _socket.port; | 85 int get port => _socket.port; |
91 | 86 |
92 String get remoteHost => _socket.remoteHost; | 87 String get remoteHost => _socket.remoteHost; |
93 | 88 |
94 int get remotePort => _socket.remotePort; | 89 int get remotePort => _socket.remotePort; |
95 | 90 |
96 void set onClosed(void callback()) { | 91 void set onClosed(void callback()) { |
92 if (_inputStream != null) { | |
93 throw new StreamException( | |
94 "Cannot set close handler when input stream is used"); | |
95 } | |
96 _onClosed = callback; | |
97 } | |
98 | |
99 void set _onClosed(void callback()) { | |
97 _socketCloseHandler = callback; | 100 _socketCloseHandler = callback; |
98 } | 101 } |
99 | 102 |
100 void set onConnect(void callback()) { | 103 void set onConnect(void callback()) { |
104 if (_outputStream != null) { | |
105 throw new StreamException( | |
106 "Cannot set connect handler when output stream is used"); | |
107 } | |
108 if (_status == CONNECTED || _status == CLOSED) { | |
109 throw new StreamException( | |
110 "Cannot set connect handler when already connected"); | |
111 } | |
112 _onConnect = callback; | |
113 } | |
114 | |
115 void set _onConnect(void callback()) { | |
101 _socketConnectHandler = callback; | 116 _socketConnectHandler = callback; |
102 } | 117 } |
103 | 118 |
104 void set onData(void callback()) { | 119 void set onData(void callback()) { |
120 if (_outputStream != null) { | |
121 throw new StreamException( | |
122 "Cannot set data handler when input stream is used"); | |
123 } | |
124 _onData = callback; | |
125 } | |
126 | |
127 void set _onData(void callback()) { | |
105 _socketDataHandler = callback; | 128 _socketDataHandler = callback; |
106 } | 129 } |
107 | 130 |
108 void set onWrite(void callback()) { | 131 void set onWrite(void callback()) { |
132 if (_outputStream != null) { | |
133 throw new StreamException( | |
134 "Cannot set write handler when output stream is used"); | |
135 } | |
136 _onWrite = callback; | |
137 } | |
138 | |
139 void set _onWrite(void callback()) { | |
109 _socketWriteHandler = callback; | 140 _socketWriteHandler = callback; |
110 // Reset the one-shot onWrite handler. | 141 // Reset the one-shot onWrite handler. |
111 _socket.onWrite = _tlsWriteHandler; | 142 _socket.onWrite = _tlsWriteHandler; |
112 } | 143 } |
113 | 144 |
145 InputStream get inputStream { | |
146 if (_inputStream == null) { | |
147 if (_socketDataHandler != null || _socketCloseHandler != null) { | |
148 throw new StreamException( | |
149 "Cannot get input stream when socket handlers are used"); | |
150 } | |
151 _inputStream = new _SocketInputStream(this); | |
152 } | |
153 return _inputStream; | |
154 } | |
155 | |
114 OutputStream get outputStream { | 156 OutputStream get outputStream { |
115 // TODO(6701): Implement stream interfaces on TlsSocket. | 157 if (_outputStream == null) { |
116 throw new UnimplementedError("TlsSocket.inputStream not implemented yet"); | 158 if (_socketConnectHandler != null || _socketWriteHandler != null) { |
159 throw new StreamException( | |
160 "Cannot get output stream when socket handlers are used"); | |
161 } | |
162 _outputStream = new _SocketOutputStream(this); | |
163 } | |
164 return _outputStream; | |
117 } | 165 } |
118 | 166 |
119 int available() { | 167 int available() { |
120 throw new UnimplementedError("TlsSocket.available not implemented yet"); | 168 throw new UnimplementedError("TlsSocket.available not implemented yet"); |
121 } | 169 } |
122 | 170 |
123 void close([bool halfClose]) { | 171 void close([bool halfClose]) { |
124 _socket.close(halfClose); | 172 _socket.close(halfClose); |
125 } | 173 } |
126 | 174 |
175 void _closeWrite() => close(true); | |
176 | |
127 List<int> read([int len]) { | 177 List<int> read([int len]) { |
178 if (_status != CONNECTED && _status != CLOSED) { | |
179 return new List<int>(0); | |
180 } | |
128 var buffer = _tlsFilter.buffers[READ_PLAINTEXT]; | 181 var buffer = _tlsFilter.buffers[READ_PLAINTEXT]; |
129 _readEncryptedData(); | 182 _readEncryptedData(); |
130 int toRead = buffer.length; | 183 int toRead = buffer.length; |
131 if (len != null) { | 184 if (len != null) { |
132 if (len is! int || len < 0) { | 185 if (len is! int || len < 0) { |
133 throw new ArgumentError( | 186 throw new ArgumentError( |
134 "Invalid len parameter in TlsSocket.read (len: $len)"); | 187 "Invalid len parameter in TlsSocket.read (len: $len)"); |
135 } | 188 } |
136 if (len < toRead) { | 189 if (len < toRead) { |
137 toRead = len; | 190 toRead = len; |
138 } | 191 } |
139 } | 192 } |
140 List<int> result = buffer.data.getRange(buffer.start, toRead); | 193 List<int> result = buffer.data.getRange(buffer.start, toRead); |
141 buffer.advanceStart(toRead); | 194 buffer.advanceStart(toRead); |
142 _setHandlersAfterRead(); | 195 _setHandlersAfterRead(); |
143 return result; | 196 return result; |
144 } | 197 } |
145 | 198 |
146 int readList(List<int> data, int offset, int bytes) { | 199 int readList(List<int> data, int offset, int bytes) { |
147 if (offset < 0 || bytes < 0 || offset + bytes > data.length) { | 200 if (offset < 0 || bytes < 0 || offset + bytes > data.length) { |
148 throw new ArgumentError( | 201 throw new ArgumentError( |
149 "Invalid offset or bytes in TlsSocket.readList"); | 202 "Invalid offset or bytes in TlsSocket.readList"); |
150 } | 203 } |
204 if (_status != CONNECTED && _status != CLOSED) { | |
205 return 0; | |
206 } | |
151 | 207 |
152 int bytesRead = 0; | 208 int bytesRead = 0; |
153 var buffer = _tlsFilter.buffers[READ_PLAINTEXT]; | 209 var buffer = _tlsFilter.buffers[READ_PLAINTEXT]; |
154 // TODO(whesse): Currently this fails if the if is turned into a while loop. | 210 // TODO(whesse): Currently this fails if the if is turned into a while loop. |
155 // Fix it so that it can loop and read more than one buffer's worth of data. | 211 // Fix it so that it can loop and read more than one buffer's worth of data. |
156 if (bytes > bytesRead) { | 212 if (bytes > bytesRead) { |
157 _readEncryptedData(); | 213 _readEncryptedData(); |
158 if (buffer.length > 0) { | 214 if (buffer.length > 0) { |
159 int toRead = min(bytes - bytesRead, buffer.length); | 215 int toRead = min(bytes - bytesRead, buffer.length); |
160 data.setRange(offset, toRead, buffer.data, buffer.start); | 216 data.setRange(offset, toRead, buffer.data, buffer.start); |
161 buffer.advanceStart(toRead); | 217 buffer.advanceStart(toRead); |
162 bytesRead += toRead; | 218 bytesRead += toRead; |
163 offset += toRead; | 219 offset += toRead; |
164 } | 220 } |
165 } | 221 } |
166 | 222 |
167 _setHandlersAfterRead(); | 223 _setHandlersAfterRead(); |
168 return bytesRead; | 224 return bytesRead; |
169 } | 225 } |
170 | 226 |
171 // Write the data to the socket, and flush it as much as possible | 227 // Write the data to the socket, and flush it as much as possible |
172 // until it would block. If the write would block, _writeEncryptedData sets | 228 // until it would block. If the write would block, _writeEncryptedData sets |
173 // up handlers to flush the pipeline when possible. | 229 // up handlers to flush the pipeline when possible. |
174 int writeList(List<int> data, int offset, int bytes) { | 230 int writeList(List<int> data, int offset, int bytes) { |
231 if (_status != CONNECTED) return 0; | |
175 var buffer = _tlsFilter.buffers[WRITE_PLAINTEXT]; | 232 var buffer = _tlsFilter.buffers[WRITE_PLAINTEXT]; |
176 if (bytes > buffer.free) { | 233 if (bytes > buffer.free) { |
177 bytes = buffer.free; | 234 bytes = buffer.free; |
178 } | 235 } |
179 if (bytes > 0) { | 236 if (bytes > 0) { |
180 buffer.data.setRange(buffer.start + buffer.length, bytes, data, offset); | 237 buffer.data.setRange(buffer.start + buffer.length, bytes, data, offset); |
181 buffer.length += bytes; | 238 buffer.length += bytes; |
182 } | 239 } |
183 _writeEncryptedData(); // Tries to flush all pipeline stages. | 240 _writeEncryptedData(); // Tries to flush all pipeline stages. |
184 return bytes; | 241 return bytes; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 _socket.onWrite = _tlsWriteHandler; | 300 _socket.onWrite = _tlsWriteHandler; |
244 } | 301 } |
245 } | 302 } |
246 | 303 |
247 void _tlsHandshakeCompleteHandler() { | 304 void _tlsHandshakeCompleteHandler() { |
248 _status = CONNECTED; | 305 _status = CONNECTED; |
249 if (_connectPending && _socketConnectHandler != null) { | 306 if (_connectPending && _socketConnectHandler != null) { |
250 _connectPending = false; | 307 _connectPending = false; |
251 _socketConnectHandler(); | 308 _socketConnectHandler(); |
252 } | 309 } |
310 if (_socketWriteHandler != null) { | |
311 _socket.onWrite = _tlsWriteHandler; | |
312 } | |
253 } | 313 } |
254 | 314 |
315 // True if the underlying socket is closed, the filter has been emptied of | |
Bill Hesse
2012/11/20 18:42:55
Should we use doc comments for private methods?
Søren Gjesse
2012/11/20 21:13:07
Normally we don't.
| |
316 // all data, and the close event has been fired. | |
317 get _closed => _socketClosed && !_fireCloseEventPending; | |
318 | |
255 void _fireCloseEvent() { | 319 void _fireCloseEvent() { |
256 _fireCloseEventPending = false; | 320 _fireCloseEventPending = false; |
257 _tlsFilter.destroy(); | 321 _tlsFilter.destroy(); |
258 _tlsFilter = null; | 322 _tlsFilter = null; |
259 if (scheduledDataEvent != null) { | 323 if (scheduledDataEvent != null) { |
260 scheduledDataEvent.cancel(); | 324 scheduledDataEvent.cancel(); |
261 } | 325 } |
262 if (_socketCloseHandler != null) { | 326 if (_socketCloseHandler != null) { |
263 _socketCloseHandler(); | 327 _socketCloseHandler(); |
264 } | 328 } |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
349 } | 413 } |
350 | 414 |
351 // _TlsSocket cannot extend _Socket and use _Socket's factory constructor. | 415 // _TlsSocket cannot extend _Socket and use _Socket's factory constructor. |
352 Socket _socket; | 416 Socket _socket; |
353 String _host; | 417 String _host; |
354 int _port; | 418 int _port; |
355 bool _is_server; | 419 bool _is_server; |
356 String _certificateName; | 420 String _certificateName; |
357 | 421 |
358 var _status = NOT_CONNECTED; | 422 var _status = NOT_CONNECTED; |
423 _SocketInputStream _inputStream; | |
424 _SocketOutputStream _outputStream; | |
359 bool _socketClosed = false; | 425 bool _socketClosed = false; |
360 bool _filterEmpty = false; | 426 bool _filterEmpty = false; |
361 bool _connectPending = false; | 427 bool _connectPending = false; |
362 bool _fireCloseEventPending = false; | 428 bool _fireCloseEventPending = false; |
363 Function _socketConnectHandler; | 429 Function _socketConnectHandler; |
364 Function _socketWriteHandler; | 430 Function _socketWriteHandler; |
365 Function _socketDataHandler; | 431 Function _socketDataHandler; |
366 Function _socketCloseHandler; | 432 Function _socketCloseHandler; |
367 Timer scheduledDataEvent; | 433 Timer scheduledDataEvent; |
368 | 434 |
(...skipping 30 matching lines...) Expand all Loading... | |
399 bool is_server, | 465 bool is_server, |
400 String certificateName); | 466 String certificateName); |
401 void destroy(); | 467 void destroy(); |
402 void handshake(); | 468 void handshake(); |
403 void init(); | 469 void init(); |
404 int processBuffer(int bufferIndex); | 470 int processBuffer(int bufferIndex); |
405 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); | 471 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); |
406 | 472 |
407 List<_TlsExternalBuffer> get buffers; | 473 List<_TlsExternalBuffer> get buffers; |
408 } | 474 } |
OLD | NEW |