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

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

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

Powered by Google App Engine
This is Rietveld 408576698