| 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([bool halfClose]) => 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 /** |
| 316 * _closed is used by SocketInputStream and SocketOutputStream. |
| 317 * It is true if the underlying socket is closed and the filter |
| 318 * has been emptied of all data, and the close event has been fired. |
| 319 */ |
| 320 get _closed => _socketClosed && !_fireCloseEventPending; |
| 321 |
| 255 void _fireCloseEvent() { | 322 void _fireCloseEvent() { |
| 256 _fireCloseEventPending = false; | 323 _fireCloseEventPending = false; |
| 257 _tlsFilter.destroy(); | 324 _tlsFilter.destroy(); |
| 258 _tlsFilter = null; | 325 _tlsFilter = null; |
| 259 if (scheduledDataEvent != null) { | 326 if (scheduledDataEvent != null) { |
| 260 scheduledDataEvent.cancel(); | 327 scheduledDataEvent.cancel(); |
| 261 } | 328 } |
| 262 if (_socketCloseHandler != null) { | 329 if (_socketCloseHandler != null) { |
| 263 _socketCloseHandler(); | 330 _socketCloseHandler(); |
| 264 } | 331 } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 } | 416 } |
| 350 | 417 |
| 351 // _TlsSocket cannot extend _Socket and use _Socket's factory constructor. | 418 // _TlsSocket cannot extend _Socket and use _Socket's factory constructor. |
| 352 Socket _socket; | 419 Socket _socket; |
| 353 String _host; | 420 String _host; |
| 354 int _port; | 421 int _port; |
| 355 bool _is_server; | 422 bool _is_server; |
| 356 String _certificateName; | 423 String _certificateName; |
| 357 | 424 |
| 358 var _status = NOT_CONNECTED; | 425 var _status = NOT_CONNECTED; |
| 426 _SocketInputStream _inputStream; |
| 427 _SocketOutputStream _outputStream; |
| 359 bool _socketClosed = false; | 428 bool _socketClosed = false; |
| 360 bool _filterEmpty = false; | 429 bool _filterEmpty = false; |
| 361 bool _connectPending = false; | 430 bool _connectPending = false; |
| 362 bool _fireCloseEventPending = false; | 431 bool _fireCloseEventPending = false; |
| 363 Function _socketConnectHandler; | 432 Function _socketConnectHandler; |
| 364 Function _socketWriteHandler; | 433 Function _socketWriteHandler; |
| 365 Function _socketDataHandler; | 434 Function _socketDataHandler; |
| 366 Function _socketCloseHandler; | 435 Function _socketCloseHandler; |
| 367 Timer scheduledDataEvent; | 436 Timer scheduledDataEvent; |
| 368 | 437 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 399 bool is_server, | 468 bool is_server, |
| 400 String certificateName); | 469 String certificateName); |
| 401 void destroy(); | 470 void destroy(); |
| 402 void handshake(); | 471 void handshake(); |
| 403 void init(); | 472 void init(); |
| 404 int processBuffer(int bufferIndex); | 473 int processBuffer(int bufferIndex); |
| 405 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); | 474 void registerHandshakeCompleteCallback(Function handshakeCompleteHandler); |
| 406 | 475 |
| 407 List<_TlsExternalBuffer> get buffers; | 476 List<_TlsExternalBuffer> get buffers; |
| 408 } | 477 } |
| OLD | NEW |