Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: runtime/bin/tls_socket_impl.dart

Issue 10828320: Revert "Start adding TLS (SSL) sockets to dart:io." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/tls_socket_android.cc ('k') | runtime/bin/tls_socket_linux.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 class _TlsSocket implements TlsSocket {
6 static final int _BUFFER_SIZE = 2048;
7
8 // Status states
9 static final int NOT_CONNECTED = 200;
10 static final int HANDSHAKE = 201;
11 static final int CONNECTED = 202;
12 static final int CLOSED = 203;
13
14 // Buffer identifiers.
15 static final int kReadPlaintext = 0;
16 static final int kWritePlaintext = 1;
17 static final int kReadEncrypted = 2;
18 static final int kWriteEncrypted = 3;
19 static final int kNumBuffers = 4;
20
21 // Constructs a new secure client socket.
22 _TlsSocket(String host,
23 int port)
24 : _socket = new Socket(host, port),
25 _tlsFilter = new _TlsFilter() {
26 _socket.onConnect = _tlsConnectHandler;
27 _socket.onWrite = _tlsWriteHandler;
28 _socket.onData = _tlsDataHandler;
29 _socket.onClosed = _tlsCloseHandler;
30 _tlsFilter.init();
31 _tlsFilter.registerHandshakeCallbacks(_tlsHandshakeStartHandler,
32 _tlsHandshakeFinishHandler);
33 }
34
35 void set onConnect(void callback()) {
36 _socketConnectHandler = callback;
37 }
38
39 void set onWrite(void callback()) {
40 _socketWriteHandler = callback;
41 // Reset the one-shot onWrite handler.
42 _socket.onWrite = _tlsWriteHandler;
43 }
44
45 void set onData(void callback()) {
46 _socketDataHandler = callback;
47 }
48
49 void set onClosed(void callback()) {
50 _socketCloseHandler = callback;
51 }
52
53 void _tlsConnectHandler() {
54 _tlsFilter.connect();
55 _connectPending = true;
56 }
57
58 void _tlsWriteHandler() {
59 if (_status == HANDSHAKE) {
60 _writeEncryptedData();
61 _readEncryptedData();
62 _tlsFilter.connect();
63 // Only do this if we have more data to write.
64 if (_tlsFilter.buffers[kWriteEncrypted].length > 0) {
65 _socket.onWrite = _tlsWriteHandler;
66 }
67 } else if (_status == CONNECTED) {
68 if (_socketWriteHandler != null) {
69 _socketWriteHandler();
70 }
71 }
72 }
73
74 void _tlsDataHandler() {
75 if (_status == HANDSHAKE) {
76 _readEncryptedData();
77 _writeEncryptedData();
78 _tlsFilter.connect();
79 _socket.onWrite = _tlsWriteHandler;
80 } else {
81 if (scheduledDataEvent != null) {
82 scheduledDataEvent.cancel();
83 scheduledDataEvent = null;
84 }
85 if (_socketDataHandler != null) {
86 _readEncryptedData();
87 _socketDataHandler();
88 }
89 }
90 }
91
92 void _tlsCloseHandler() {
93 _socketClosed = true;
94 _status = CLOSED;
95 _socket.close();
96 if (_filterEmpty) {
97 _fireCloseEvent();
98 } else {
99 _fireCloseEventPending = true;
100 }
101 }
102
103 void _tlsHandshakeStartHandler() {
104 _status = HANDSHAKE;
105 _socket.onWrite = _tlsWriteHandler;
106 }
107
108 void _tlsHandshakeFinishHandler() {
109 _status = CONNECTED;
110 if (_connectPending && _socketConnectHandler != null) {
111 _connectPending = false;
112 _socketConnectHandler();
113 }
114 }
115
116 void _fireCloseEvent() {
117 _fireCloseEventPending = false;
118 _tlsFilter.destroy();
119 _tlsFilter = null;
120 if (scheduledDataEvent != null) {
121 scheduledDataEvent.cancel();
122 }
123 if (_socketCloseHandler != null) {
124 _socketCloseHandler();
125 }
126 }
127
128 void close([bool halfClose]) {
129 _socket.close(halfClose);
130 }
131
132 int readList(List<int> data, int offset, int bytes) {
133 _readEncryptedData();
134 if (offset < 0 || bytes < 0 || offset + bytes > data.length) {
135 throw new IllegalArgumentException(
136 "Invalid offset or bytes in TlsSocket.readList");
137 }
138 int bytesRead = 0;
139 var buffer = _tlsFilter.buffers[kReadPlaintext];
140 if (buffer.length == 0 && buffer.start != 0) {
141 throw "Unexpected buffer state in TlsSocket.readList";
142 }
143 if (buffer.length > 0) {
144 int toRead = Math.min(bytes, buffer.length);
145 data.setRange(offset, toRead, buffer.data, buffer.start);
146 buffer.advanceStart(toRead);
147 bytesRead += toRead;
148 }
149 int newBytes = _tlsFilter.processBuffer(kReadPlaintext);
150 if (newBytes > 0) {
151 buffer.length += newBytes;
152 }
153 if (bytes - bytesRead > 0 && buffer.length > 0) {
154 int toRead = Math.min(bytes - bytesRead, buffer.length);
155 data.setRange(offset + bytesRead, toRead, buffer.data, buffer.start);
156 buffer.advanceStart(toRead);
157 bytesRead += toRead;
158 }
159
160 // If bytesRead is 0, then something is blocked or empty, and
161 // we are guaranteed an event when it becomes unblocked.
162 // Otherwise, give an event if there is data available, and
163 // there has been a read call since the last data event.
164 // This gives the invariant that:
165 // If there is data available, and there has been a read after the
166 // last data event (or no previous one fired), then we are guaranteed
167 // to get a data event.
168 _filterEmpty = (bytesRead == 0);
169 if (bytesRead > 0 && scheduledDataEvent == null) {
170 scheduledDataEvent = new Timer(0, (_) => _tlsDataHandler());
171 } else if (bytesRead == 0) {
172 if (_fireCloseEventPending) {
173 _fireCloseEvent();
174 } else if (scheduledDataEvent != null) {
175 scheduledDataEvent.cancel();
176 scheduledDataEvent = null;
177 }
178 }
179 return bytesRead;
180 }
181
182
183 // Write the data to the socket, and flush it as much as possible
184 // without blocking. If not all the data is written, enable the
185 // onWrite event. If data is not all flushed, add handlers to all
186 // relevant events.
187 int writeList(List<int> data, int offset, int bytes) {
188 _writeEncryptedData(); // Tries to flush all post-filter stages.
189 var buffer = _tlsFilter.buffers[kWritePlaintext];
190 if (bytes > buffer.free) {
191 bytes = buffer.free;
192 }
193 if (bytes > 0) {
194 buffer.data.setRange(buffer.start + buffer.length, bytes, data, offset);
195 buffer.length += bytes;
196 }
197 int bytesWritten = _tlsFilter.processBuffer(kWritePlaintext);
198 buffer.advanceStart(bytesWritten);
199 _readEncryptedData();
200 _writeEncryptedData();
201 return bytes;
202 }
203
204 void _readEncryptedData() {
205 // Read from the socket and write to the filter.
206 var buffer = _tlsFilter.buffers[kReadEncrypted];
207 while (true) {
208 if (buffer.length > 0) {
209 int bytes = _tlsFilter.processBuffer(kReadEncrypted);
210 if (bytes > 0) {
211 buffer.advanceStart(bytes);
212 } else {
213 break;
214 }
215 } else if (!_socketClosed) {
216 int bytes = _socket.readList(buffer.data,
217 buffer.start + buffer.length,
218 buffer.free);
219 if (bytes <= 0) break;
220 buffer.length += bytes;
221 } else {
222 break; // Socket is closed and read buffer is empty.
223 }
224 }
225 }
226
227 void _writeEncryptedData() {
228 // Write from the filter to the socket.
229 var buffer = _tlsFilter.buffers[kWriteEncrypted];
230 while (true) {
231 if (buffer.length > 0) {
232 int bytes = _socket.writeList(buffer.data, buffer.start, buffer.length);
233 if (bytes <= 0) break;
234 buffer.advanceStart(bytes);
235 } else {
236 if (buffer.start != 0 || buffer.length != 0) {
237 throw "Unexpected state in _writeEncryptedData";
238 }
239 int bytes = _tlsFilter.processBuffer(kWriteEncrypted);
240 if (bytes <= 0) break;
241 buffer.length += bytes;
242 }
243 }
244 }
245
246 // _TlsSocket cannot extend _Socket and use _Socket's factory constructor.
247 Socket _socket;
248
249 var _status = NOT_CONNECTED;
250 bool _socketClosed = false;
251 bool _filterEmpty = false;
252 bool _connectPending = false;
253 bool _fireCloseEventPending = false;
254 Function _socketConnectHandler;
255 Function _socketWriteHandler;
256 Function _socketDataHandler;
257 Function _socketCloseHandler;
258 Timer scheduledDataEvent;
259
260 var _tlsFilter;
261 }
262
263 class _TlsExternalBuffer {
264 static final int kSize = 8 * 1024;
265 _TlsExternalBuffer() : start = 0, length = 0;
266
267 void advanceStart(int numBytes) {
268 start += numBytes;
269 length -= numBytes;
270 if (length == 0) {
271 start = 0;
272 }
273 }
274
275 int get free() => kSize - start - length;
276
277 List data; // This will be a ExternalByteArray, backed by C allocated data.
278 int start;
279 int length;
280 }
281
282 /**
283 * _TlsFilter wraps a filter that encrypts and decrypts data travelling
284 * over a TLS encrypted socket. The filter also handles the handshaking
285 * and certificate verification.
286 *
287 * The filter exposes its input and output buffers as Dart objects that
288 * are backed by an external C array of bytes, so that both Dart code and
289 * native code can access the same data.
290 */
291 class _TlsFilter extends NativeFieldWrapperClass1 {
292 _TlsFilter() {
293 buffers = new List<_TlsExternalBuffer>(_TlsSocket.kNumBuffers);
294 for (int i = 0; i < _TlsSocket.kNumBuffers; ++i) {
295 buffers[i] = new _TlsExternalBuffer();
296 }
297 }
298
299 void init() native "TlsSocket_Init";
300
301 void connect() native "TlsSocket_Connect";
302
303 void registerHandshakeCallbacks(Function startHandshakeHandler,
304 Function finishHandshakeHandler)
305 native "TlsSocket_RegisterHandshakeCallbacks";
306 int processBuffer(int bufferIndex) native "TlsSocket_ProcessBuffer";
307 void destroy() native "TlsSocket_Destroy";
308
309 List<_TlsExternalBuffer> buffers;
310 }
OLDNEW
« no previous file with comments | « runtime/bin/tls_socket_android.cc ('k') | runtime/bin/tls_socket_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698