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

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

Issue 11337019: Use patching for dart:io. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments Created 8 years, 1 month 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
6 class _SocketBase extends NativeFieldWrapperClass1 {
7 // Bit flags used when communicating between the eventhandler and
8 // dart code. The EVENT flags are used to indicate events of
9 // interest when sending a message from dart code to the
10 // eventhandler. When receiving a message from the eventhandler the
11 // EVENT flags indicate the events that actually happened. The
12 // COMMAND flags are used to send commands from dart to the
13 // eventhandler. COMMAND flags are never received from the
14 // eventhandler. Additional flags are used to communicate other
15 // information.
16 static const int _IN_EVENT = 0;
17 static const int _OUT_EVENT = 1;
18 static const int _ERROR_EVENT = 2;
19 static const int _CLOSE_EVENT = 3;
20
21 static const int _CLOSE_COMMAND = 8;
22 static const int _SHUTDOWN_READ_COMMAND = 9;
23 static const int _SHUTDOWN_WRITE_COMMAND = 10;
24
25 // Flag send to the eventhandler providing additional information on
26 // the type of the file descriptor.
27 static const int _LISTENING_SOCKET = 16;
28 static const int _PIPE = 17;
29
30 static const int _FIRST_EVENT = _IN_EVENT;
31 static const int _LAST_EVENT = _CLOSE_EVENT;
32
33 static const int _FIRST_COMMAND = _CLOSE_COMMAND;
34 static const int _LAST_COMMAND = _SHUTDOWN_WRITE_COMMAND;
35
36 _SocketBase () {
37 _handlerMap = new List(_LAST_EVENT + 1);
38 _handlerMask = 0;
39 _canActivateHandlers = true;
40 _closed = true;
41 _EventHandler._start();
42 _hashCode = _nextHashCode;
43 _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF;
44 }
45
46 // Multiplexes socket events to the socket handlers.
47 void _multiplex(int event_mask) {
48 _canActivateHandlers = false;
49 for (int i = _FIRST_EVENT; i <= _LAST_EVENT; i++) {
50 if (((event_mask & (1 << i)) != 0)) {
51 if ((i == _CLOSE_EVENT) && this is _Socket && !_closed) {
52 _closedRead = true;
53 if (_closedWrite) _close();
54 }
55
56 var eventHandler = _handlerMap[i];
57 if (eventHandler != null || i == _ERROR_EVENT) {
58 // Unregister the out handler before executing it.
59 if (i == _OUT_EVENT) _setHandler(i, null);
60
61 // Don't call the in handler if there is no data available
62 // after all.
63 if ((i == _IN_EVENT) && (this is _Socket) && (available() == 0)) {
64 continue;
65 }
66 if (i == _ERROR_EVENT) {
67 _reportError(_getError(), "");
68 close();
69 } else {
70 eventHandler();
71 }
72 }
73 }
74 }
75 _canActivateHandlers = true;
76 _activateHandlers();
77 }
78
79 void _setHandler(int event, Function callback) {
80 if (callback == null) {
81 _handlerMask &= ~(1 << event);
82 } else {
83 _handlerMask |= (1 << event);
84 }
85 _handlerMap[event] = callback;
86 // If the socket is only for writing then close the receive port
87 // when not waiting for any events.
88 if (this is _Socket &&
89 _closedRead &&
90 _handlerMask == 0 &&
91 _handler != null) {
92 _handler.close();
93 _handler = null;
94 } else {
95 _activateHandlers();
96 }
97 }
98
99 OSError _getError() native "Socket_GetError";
100 int _getPort() native "Socket_GetPort";
101
102 void set onError(void callback(e)) {
103 _setHandler(_ERROR_EVENT, callback);
104 }
105
106 void _activateHandlers() {
107 if (_canActivateHandlers && !_closed) {
108 if (_handlerMask == 0) {
109 if (_handler != null) {
110 _handler.close();
111 _handler = null;
112 }
113 return;
114 }
115 int data = _handlerMask;
116 if (_isListenSocket()) {
117 data |= (1 << _LISTENING_SOCKET);
118 } else {
119 if (_closedRead) { data &= ~(1 << _IN_EVENT); }
120 if (_closedWrite) { data &= ~(1 << _OUT_EVENT); }
121 if (_isPipe()) data |= (1 << _PIPE);
122 }
123 _sendToEventHandler(data);
124 }
125 }
126
127 int get port {
128 if (_port === null) {
129 _port = _getPort();
130 }
131 return _port;
132 }
133
134 void close([bool halfClose = false]) {
135 if (!_closed) {
136 if (halfClose) {
137 _closeWrite();
138 } else {
139 _close();
140 }
141 } else if (_handler != null) {
142 // This is to support closing sockets created but never assigned
143 // any actual socket.
144 _handler.close();
145 _handler = null;
146 }
147 }
148
149 void _closeWrite() {
150 if (!_closed) {
151 if (_closedRead) {
152 _close();
153 } else {
154 _sendToEventHandler(1 << _SHUTDOWN_WRITE_COMMAND);
155 }
156 _closedWrite = true;
157 }
158 }
159
160 void _closeRead() {
161 if (!_closed) {
162 if (_closedWrite) {
163 _close();
164 } else {
165 _sendToEventHandler(1 << _SHUTDOWN_READ_COMMAND);
166 }
167 _closedRead = true;
168 }
169 }
170
171 void _close() {
172 if (!_closed) {
173 _sendToEventHandler(1 << _CLOSE_COMMAND);
174 _handler.close();
175 _handler = null;
176 _closed = true;
177 }
178 }
179
180 void _sendToEventHandler(int data) {
181 if (_handler === null) {
182 _handler = new ReceivePort();
183 _handler.receive((var message, ignored) { _multiplex(message); });
184 }
185 assert(!_closed);
186 _EventHandler._sendData(this, _handler, data);
187 }
188
189 bool _reportError(error, String message) {
190 void doReportError(Exception e) {
191 // Invoke the socket error callback if any.
192 bool reported = false;
193 if (_handlerMap[_ERROR_EVENT] != null) {
194 _handlerMap[_ERROR_EVENT](e);
195 reported = true;
196 }
197 // Propagate the error to any additional listeners.
198 reported = reported || _propagateError(e);
199 if (!reported) throw e;
200 }
201
202 // For all errors we close the socket, call the error handler and
203 // disable further calls of the error handler.
204 close();
205 if (error is OSError) {
206 doReportError(new SocketIOException(message, error));
207 } else if (error is List) {
208 assert(_isErrorResponse(error));
209 switch (error[0]) {
210 case _ILLEGAL_ARGUMENT_RESPONSE:
211 doReportError(new ArgumentError());
212 break;
213 case _OSERROR_RESPONSE:
214 doReportError(new SocketIOException(
215 message, new OSError(error[2], error[1])));
216 break;
217 default:
218 doReportError(new Exception("Unknown error"));
219 break;
220 }
221 } else {
222 doReportError(new SocketIOException(message));
223 }
224 }
225
226 int get hashCode => _hashCode;
227
228 bool _propagateError(Exception e) => false;
229
230 abstract bool _isListenSocket();
231 abstract bool _isPipe();
232
233 // Is this socket closed.
234 bool _closed;
235
236 // Dedicated ReceivePort for socket events.
237 ReceivePort _handler;
238
239 // Poll event to handler map.
240 List _handlerMap;
241
242 // Indicates for which poll events the socket registered handlers.
243 int _handlerMask;
244
245 // Indicates if native interrupts can be activated.
246 bool _canActivateHandlers;
247
248 // Holds the port of the socket, null if not known.
249 int _port;
250
251 // Hash code for the socket. Currently this is just a counter.
252 int _hashCode;
253 static int _nextHashCode = 0;
254 bool _closedRead = false;
255 bool _closedWrite = false;
256 }
257
258
259 class _ServerSocket extends _SocketBase implements ServerSocket {
260 // Constructor for server socket. First a socket object is allocated
261 // in which the native socket is stored. After that _createBind
262 // is called which creates a file descriptor and binds the given address
263 // and port to the socket. Null is returned if file descriptor creation or
264 // bind failed.
265 factory _ServerSocket(String bindAddress, int port, int backlog) {
266 _ServerSocket socket = new _ServerSocket._internal();
267 var result = socket._createBindListen(bindAddress, port, backlog);
268 if (result is OSError) {
269 socket.close();
270 throw new SocketIOException("Failed to create server socket", result);
271 }
272 socket._closed = false;
273 assert(result);
274 if (port != 0) {
275 socket._port = port;
276 }
277 return socket;
278 }
279
280 _ServerSocket._internal();
281
282 _accept(Socket socket) native "ServerSocket_Accept";
283
284 _createBindListen(String bindAddress, int port, int backlog)
285 native "ServerSocket_CreateBindListen";
286
287 void set onConnection(void callback(Socket connection)) {
288 _clientConnectionHandler = callback;
289 _setHandler(_SocketBase._IN_EVENT,
290 _clientConnectionHandler != null ? _connectionHandler : null);
291 }
292
293 void _connectionHandler() {
294 if (!_closed) {
295 _Socket socket = new _Socket._internal();
296 var result = _accept(socket);
297 if (result is OSError) {
298 _reportError(result, "Accept failed");
299 } else if (result) {
300 socket._closed = false;
301 _clientConnectionHandler(socket);
302 } else {
303 // Temporary failure accepting the connection. Ignoring
304 // temporary failures lets us retry when we wake up with data
305 // on the listening socket again.
306 }
307 }
308 }
309
310 bool _isListenSocket() => true;
311 bool _isPipe() => false;
312
313 var _clientConnectionHandler;
314 }
315
316
317 class _Socket extends _SocketBase implements Socket {
318 static const HOST_NAME_LOOKUP = 0;
319
320 // Constructs a new socket. During the construction an asynchronous
321 // host name lookup is initiated. The returned socket is not yet
322 // connected but ready for registration of callbacks.
323 factory _Socket(String host, int port) {
324 Socket socket = new _Socket._internal();
325 _ensureSocketService();
326 List request = new List(2);
327 request[0] = HOST_NAME_LOOKUP;
328 request[1] = host;
329 _socketService.call(request).then((response) {
330 if (socket._isErrorResponse(response)) {
331 socket._reportError(response, "Failed host name lookup");
332 } else{
333 var result = socket._createConnect(response, port);
334 if (result is OSError) {
335 socket.close();
336 socket._reportError(result, "Connection failed");
337 } else {
338 socket._closed = false;
339 socket._activateHandlers();
340 }
341 }
342 });
343 return socket;
344 }
345
346 _Socket._internal();
347 _Socket._internalReadOnly() : _pipe = true { super._closedWrite = true; }
348 _Socket._internalWriteOnly() : _pipe = true { super._closedRead = true; }
349
350 int available() {
351 if (!_closed) {
352 var result = _available();
353 if (result is OSError) {
354 _reportError(result, "Available failed");
355 return 0;
356 } else {
357 return result;
358 }
359 }
360 throw new
361 SocketIOException("Error: available failed - invalid socket handle");
362 }
363
364 _available() native "Socket_Available";
365
366 int readList(List<int> buffer, int offset, int bytes) {
367 if (!_closed) {
368 if (bytes == 0) {
369 return 0;
370 }
371 if (offset < 0) {
372 throw new IndexOutOfRangeException(offset);
373 }
374 if (bytes < 0) {
375 throw new IndexOutOfRangeException(bytes);
376 }
377 if ((offset + bytes) > buffer.length) {
378 throw new IndexOutOfRangeException(offset + bytes);
379 }
380 var result = _readList(buffer, offset, bytes);
381 if (result is OSError) {
382 _reportError(result, "Read failed");
383 return -1;
384 }
385 return result;
386 }
387 throw new
388 SocketIOException("Error: readList failed - invalid socket handle");
389 }
390
391 _readList(List<int> buffer, int offset, int bytes) native "Socket_ReadList";
392
393 int writeList(List<int> buffer, int offset, int bytes) {
394 if (buffer is! List || offset is! int || bytes is! int) {
395 throw new ArgumentError(
396 "Invalid arguments to writeList on Socket");
397 }
398 if (!_closed) {
399 if (bytes == 0) {
400 return 0;
401 }
402 if (offset < 0) {
403 throw new IndexOutOfRangeException(offset);
404 }
405 if (bytes < 0) {
406 throw new IndexOutOfRangeException(bytes);
407 }
408 if ((offset + bytes) > buffer.length) {
409 throw new IndexOutOfRangeException(offset + bytes);
410 }
411 _BufferAndOffset bufferAndOffset =
412 _ensureFastAndSerializableBuffer(buffer, offset, bytes);
413 var result =
414 _writeList(bufferAndOffset.buffer, bufferAndOffset.offset, bytes);
415 if (result is OSError) {
416 _reportError(result, "Write failed");
417 // If writing fails we return 0 as the number of bytes and
418 // report the error on the error handler.
419 result = 0;
420 }
421 return result;
422 }
423 throw new SocketIOException("writeList failed - invalid socket handle");
424 }
425
426 _writeList(List<int> buffer, int offset, int bytes)
427 native "Socket_WriteList";
428
429 bool _isErrorResponse(response) {
430 return response is List && response[0] != _SUCCESS_RESPONSE;
431 }
432
433 bool _createConnect(String host, int port) native "Socket_CreateConnect";
434
435 void set onWrite(void callback()) {
436 if (_outputStream != null) throw new StreamException(
437 "Cannot set write handler when output stream is used");
438 _clientWriteHandler = callback;
439 _updateOutHandler();
440 }
441
442 void set onConnect(void callback()) {
443 if (_seenFirstOutEvent || _outputStream != null) {
444 throw new StreamException(
445 "Cannot set connect handler when already connected");
446 }
447 if (_outputStream != null) {
448 throw new StreamException(
449 "Cannot set connect handler when output stream is used");
450 }
451 _clientConnectHandler = callback;
452 _updateOutHandler();
453 }
454
455 void set onData(void callback()) {
456 if (_inputStream != null) throw new StreamException(
457 "Cannot set data handler when input stream is used");
458 _onData = callback;
459 }
460
461 void set onClosed(void callback()) {
462 if (_inputStream != null) throw new StreamException(
463 "Cannot set close handler when input stream is used");
464 _onClosed = callback;
465 }
466
467 bool _isListenSocket() => false;
468
469 bool _isPipe() => _pipe;
470
471 InputStream get inputStream {
472 if (_inputStream == null) {
473 if (_handlerMap[_SocketBase._IN_EVENT] !== null ||
474 _handlerMap[_SocketBase._CLOSE_EVENT] !== null) {
475 throw new StreamException(
476 "Cannot get input stream when socket handlers are used");
477 }
478 _inputStream = new _SocketInputStream(this);
479 }
480 return _inputStream;
481 }
482
483 OutputStream get outputStream {
484 if (_outputStream == null) {
485 if (_handlerMap[_SocketBase._OUT_EVENT] !== null) {
486 throw new StreamException(
487 "Cannot get input stream when socket handlers are used");
488 }
489 _outputStream = new _SocketOutputStream(this);
490 }
491 return _outputStream;
492 }
493
494 void set _onWrite(void callback()) {
495 _setHandler(_SocketBase._OUT_EVENT, callback);
496 }
497
498 void set _onData(void callback()) {
499 _setHandler(_SocketBase._IN_EVENT, callback);
500 }
501
502 void set _onClosed(void callback()) {
503 _setHandler(_SocketBase._CLOSE_EVENT, callback);
504 }
505
506 bool _propagateError(Exception e) {
507 bool reported = false;
508 if (_inputStream != null) {
509 reported = reported || _inputStream._onSocketError(e);
510 }
511 if (_outputStream != null) {
512 reported = reported || _outputStream._onSocketError(e);
513 }
514 return reported;
515 }
516
517 void _updateOutHandler() {
518 void firstWriteHandler() {
519 assert(!_seenFirstOutEvent);
520 _seenFirstOutEvent = true;
521
522 // From now on the write handler is only the client write
523 // handler (connect handler cannot be called again). Change this
524 // before calling any handlers as handlers can change the
525 // handlers.
526 if (_clientWriteHandler === null) _onWrite = _clientWriteHandler;
527
528 // First out event is socket connected event.
529 if (_clientConnectHandler !== null) _clientConnectHandler();
530 _clientConnectHandler = null;
531
532 // Always (even for the first out event) call the write handler.
533 if (_clientWriteHandler !== null) _clientWriteHandler();
534 }
535
536 if (_clientConnectHandler === null && _clientWriteHandler === null) {
537 _onWrite = null;
538 } else {
539 if (_seenFirstOutEvent) {
540 _onWrite = _clientWriteHandler;
541 } else {
542 _onWrite = firstWriteHandler;
543 }
544 }
545 }
546
547 int get remotePort {
548 if (_remotePort === null) {
549 remoteHost;
550 }
551 return _remotePort;
552 }
553
554 String get remoteHost {
555 if (_remoteHost === null) {
556 List peer = _getRemotePeer();
557 _remoteHost = peer[0];
558 _remotePort = peer[1];
559 }
560 return _remoteHost;
561 }
562
563 List _getRemotePeer() native "Socket_GetRemotePeer";
564
565 static SendPort _newServicePort() native "Socket_NewServicePort";
566
567 static void _ensureSocketService() {
568 if (_socketService == null) {
569 _socketService = _Socket._newServicePort();
570 }
571 }
572
573 bool _seenFirstOutEvent = false;
574 bool _pipe = false;
575 Function _clientConnectHandler;
576 Function _clientWriteHandler;
577 _SocketInputStream _inputStream;
578 _SocketOutputStream _outputStream;
579 String _remoteHost;
580 int _remotePort;
581 static SendPort _socketService;
582 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698