| OLD | NEW |
| (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 } | |
| OLD | NEW |