Chromium Code Reviews| 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 class _SocketBase { | 6 class _SocketBase extends NativeFieldWrapperClass1 { |
| 7 // Bit flags used when communicating between the eventhandler and | 7 // Bit flags used when communicating between the eventhandler and |
| 8 // dart code. The EVENT flags are used to indicate events of | 8 // dart code. The EVENT flags are used to indicate events of |
| 9 // interest when sending a message from dart code to the | 9 // interest when sending a message from dart code to the |
| 10 // eventhandler. When receiving a message from the eventhandler the | 10 // eventhandler. When receiving a message from the eventhandler the |
| 11 // EVENT flags indicate the events that actually happened. The | 11 // EVENT flags indicate the events that actually happened. The |
| 12 // COMMAND flags are used to send commands from dart to the | 12 // COMMAND flags are used to send commands from dart to the |
| 13 // eventhandler. COMMAND flags are never received from the | 13 // eventhandler. COMMAND flags are never received from the |
| 14 // eventhandler. Additional flags are used to communicate other | 14 // eventhandler. Additional flags are used to communicate other |
| 15 // information. | 15 // information. |
| 16 static const int _IN_EVENT = 0; | 16 static const int _IN_EVENT = 0; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 30 static const int _FIRST_EVENT = _IN_EVENT; | 30 static const int _FIRST_EVENT = _IN_EVENT; |
| 31 static const int _LAST_EVENT = _CLOSE_EVENT; | 31 static const int _LAST_EVENT = _CLOSE_EVENT; |
| 32 | 32 |
| 33 static const int _FIRST_COMMAND = _CLOSE_COMMAND; | 33 static const int _FIRST_COMMAND = _CLOSE_COMMAND; |
| 34 static const int _LAST_COMMAND = _SHUTDOWN_WRITE_COMMAND; | 34 static const int _LAST_COMMAND = _SHUTDOWN_WRITE_COMMAND; |
| 35 | 35 |
| 36 _SocketBase () { | 36 _SocketBase () { |
| 37 _handlerMap = new List(_LAST_EVENT + 1); | 37 _handlerMap = new List(_LAST_EVENT + 1); |
| 38 _handlerMask = 0; | 38 _handlerMask = 0; |
| 39 _canActivateHandlers = true; | 39 _canActivateHandlers = true; |
| 40 _id = -1; | 40 _closed = true; |
|
Søren Gjesse
2012/09/21 06:47:06
We could consider making this a state with 3 value
Mads Ager (google)
2012/09/21 08:18:25
Yes, we could do that to give better error message
| |
| 41 _EventHandler._start(); | 41 _EventHandler._start(); |
| 42 _hashCode = _nextHashCode; | 42 _hashCode = _nextHashCode; |
| 43 _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF; | 43 _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF; |
| 44 } | 44 } |
| 45 | 45 |
| 46 // Multiplexes socket events to the socket handlers. | 46 // Multiplexes socket events to the socket handlers. |
| 47 void _multiplex(int event_mask) { | 47 void _multiplex(int event_mask) { |
| 48 _canActivateHandlers = false; | 48 _canActivateHandlers = false; |
| 49 for (int i = _FIRST_EVENT; i <= _LAST_EVENT; i++) { | 49 for (int i = _FIRST_EVENT; i <= _LAST_EVENT; i++) { |
| 50 if (((event_mask & (1 << i)) != 0)) { | 50 if (((event_mask & (1 << i)) != 0)) { |
| 51 if ((i == _CLOSE_EVENT) && this is _Socket && _id >= 0) { | 51 if ((i == _CLOSE_EVENT) && this is _Socket && !_closed) { |
| 52 _closedRead = true; | 52 _closedRead = true; |
| 53 if (_closedWrite) _close(); | 53 if (_closedWrite) _close(); |
| 54 } | 54 } |
| 55 | 55 |
| 56 var eventHandler = _handlerMap[i]; | 56 var eventHandler = _handlerMap[i]; |
| 57 if (eventHandler != null || i == _ERROR_EVENT) { | 57 if (eventHandler != null || i == _ERROR_EVENT) { |
| 58 // Unregister the out handler before executing it. | 58 // Unregister the out handler before executing it. |
| 59 if (i == _OUT_EVENT) _setHandler(i, null); | 59 if (i == _OUT_EVENT) _setHandler(i, null); |
| 60 | 60 |
| 61 // Don't call the in handler if there is no data available | 61 // Don't call the in handler if there is no data available |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 } | 97 } |
| 98 | 98 |
| 99 OSError _getError() native "Socket_GetError"; | 99 OSError _getError() native "Socket_GetError"; |
| 100 int _getPort() native "Socket_GetPort"; | 100 int _getPort() native "Socket_GetPort"; |
| 101 | 101 |
| 102 void set onError(void callback(e)) { | 102 void set onError(void callback(e)) { |
| 103 _setHandler(_ERROR_EVENT, callback); | 103 _setHandler(_ERROR_EVENT, callback); |
| 104 } | 104 } |
| 105 | 105 |
| 106 void _activateHandlers() { | 106 void _activateHandlers() { |
| 107 if (_canActivateHandlers && (_id >= 0)) { | 107 if (_canActivateHandlers && !_closed) { |
| 108 if (_handlerMask == 0) { | 108 if (_handlerMask == 0) { |
| 109 if (_handler != null) { | 109 if (_handler != null) { |
| 110 _handler.close(); | 110 _handler.close(); |
| 111 _handler = null; | 111 _handler = null; |
| 112 } | 112 } |
| 113 return; | 113 return; |
| 114 } | 114 } |
| 115 int data = _handlerMask; | 115 int data = _handlerMask; |
| 116 if (_isListenSocket()) { | 116 if (_isListenSocket()) { |
| 117 data |= (1 << _LISTENING_SOCKET); | 117 data |= (1 << _LISTENING_SOCKET); |
| 118 } else { | 118 } else { |
| 119 if (_closedRead) { data &= ~(1 << _IN_EVENT); } | 119 if (_closedRead) { data &= ~(1 << _IN_EVENT); } |
| 120 if (_closedWrite) { data &= ~(1 << _OUT_EVENT); } | 120 if (_closedWrite) { data &= ~(1 << _OUT_EVENT); } |
| 121 if (_isPipe()) data |= (1 << _PIPE); | 121 if (_isPipe()) data |= (1 << _PIPE); |
| 122 } | 122 } |
| 123 _sendToEventHandler(data); | 123 _sendToEventHandler(data); |
| 124 } | 124 } |
| 125 } | 125 } |
| 126 | 126 |
| 127 int get port { | 127 int get port { |
| 128 if (_port === null) { | 128 if (_port === null) { |
| 129 _port = _getPort(); | 129 _port = _getPort(); |
| 130 } | 130 } |
| 131 return _port; | 131 return _port; |
| 132 } | 132 } |
| 133 | 133 |
| 134 void close([bool halfClose = false]) { | 134 void close([bool halfClose = false]) { |
| 135 if (_id >= 0) { | 135 if (!_closed) { |
| 136 if (halfClose) { | 136 if (halfClose) { |
| 137 _closeWrite(); | 137 _closeWrite(); |
| 138 } else { | 138 } else { |
| 139 _close(); | 139 _close(); |
| 140 } | 140 } |
| 141 } else if (_handler != null) { | 141 } else if (_handler != null) { |
| 142 // This is to support closing sockets created but never assigned | 142 // This is to support closing sockets created but never assigned |
| 143 // any actual socket. | 143 // any actual socket. |
| 144 _handler.close(); | 144 _handler.close(); |
| 145 _handler = null; | 145 _handler = null; |
| 146 } | 146 } |
| 147 } | 147 } |
| 148 | 148 |
| 149 void _closeWrite() { | 149 void _closeWrite() { |
| 150 if (_id >= 0) { | 150 if (!_closed) { |
| 151 if (_closedRead) { | 151 if (_closedRead) { |
| 152 _close(); | 152 _close(); |
| 153 } else { | 153 } else { |
| 154 _sendToEventHandler(1 << _SHUTDOWN_WRITE_COMMAND); | 154 _sendToEventHandler(1 << _SHUTDOWN_WRITE_COMMAND); |
| 155 } | 155 } |
| 156 _closedWrite = true; | 156 _closedWrite = true; |
| 157 } | 157 } |
| 158 } | 158 } |
| 159 | 159 |
| 160 void _closeRead() { | 160 void _closeRead() { |
| 161 if (_id >= 0) { | 161 if (!_closed) { |
| 162 if (_closedWrite) { | 162 if (_closedWrite) { |
| 163 _close(); | 163 _close(); |
| 164 } else { | 164 } else { |
| 165 _sendToEventHandler(1 << _SHUTDOWN_READ_COMMAND); | 165 _sendToEventHandler(1 << _SHUTDOWN_READ_COMMAND); |
| 166 } | 166 } |
| 167 _closedRead = true; | 167 _closedRead = true; |
| 168 } | 168 } |
| 169 } | 169 } |
| 170 | 170 |
| 171 void _close() { | 171 void _close() { |
| 172 if (_id >= 0) { | 172 if (!_closed) { |
| 173 _sendToEventHandler(1 << _CLOSE_COMMAND); | 173 _sendToEventHandler(1 << _CLOSE_COMMAND); |
| 174 _handler.close(); | 174 _handler.close(); |
| 175 _handler = null; | 175 _handler = null; |
| 176 _id = -1; | 176 _closed = true; |
| 177 } | 177 } |
| 178 } | 178 } |
| 179 | 179 |
| 180 void _sendToEventHandler(int data) { | 180 void _sendToEventHandler(int data) { |
| 181 if (_handler === null) { | 181 if (_handler === null) { |
| 182 _handler = new ReceivePort(); | 182 _handler = new ReceivePort(); |
| 183 _handler.receive((var message, ignored) { _multiplex(message); }); | 183 _handler.receive((var message, ignored) { _multiplex(message); }); |
| 184 } | 184 } |
| 185 assert(_id >= 0); | 185 assert(!_closed); |
| 186 _EventHandler._sendData(_id, _handler, data); | 186 _EventHandler._sendData(this, _handler, data); |
| 187 } | 187 } |
| 188 | 188 |
| 189 bool _reportError(error, String message) { | 189 bool _reportError(error, String message) { |
| 190 void doReportError(Exception e) { | 190 void doReportError(Exception e) { |
| 191 // Invoke the socket error callback if any. | 191 // Invoke the socket error callback if any. |
| 192 bool reported = false; | 192 bool reported = false; |
| 193 if (_handlerMap[_ERROR_EVENT] != null) { | 193 if (_handlerMap[_ERROR_EVENT] != null) { |
| 194 _handlerMap[_ERROR_EVENT](e); | 194 _handlerMap[_ERROR_EVENT](e); |
| 195 reported = true; | 195 reported = true; |
| 196 } | 196 } |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 223 } | 223 } |
| 224 } | 224 } |
| 225 | 225 |
| 226 int hashCode() => _hashCode; | 226 int hashCode() => _hashCode; |
| 227 | 227 |
| 228 bool _propagateError(Exception e) => false; | 228 bool _propagateError(Exception e) => false; |
| 229 | 229 |
| 230 abstract bool _isListenSocket(); | 230 abstract bool _isListenSocket(); |
| 231 abstract bool _isPipe(); | 231 abstract bool _isPipe(); |
| 232 | 232 |
| 233 // Socket id is set from native. -1 indicates that the socket was closed. | 233 // Is this socket closed. |
| 234 int _id; | 234 bool _closed; |
| 235 | 235 |
| 236 // Dedicated ReceivePort for socket events. | 236 // Dedicated ReceivePort for socket events. |
| 237 ReceivePort _handler; | 237 ReceivePort _handler; |
| 238 | 238 |
| 239 // Poll event to handler map. | 239 // Poll event to handler map. |
| 240 List _handlerMap; | 240 List _handlerMap; |
| 241 | 241 |
| 242 // Indicates for which poll events the socket registered handlers. | 242 // Indicates for which poll events the socket registered handlers. |
| 243 int _handlerMask; | 243 int _handlerMask; |
| 244 | 244 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 262 // is called which creates a file descriptor and binds the given address | 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 | 263 // and port to the socket. Null is returned if file descriptor creation or |
| 264 // bind failed. | 264 // bind failed. |
| 265 factory _ServerSocket(String bindAddress, int port, int backlog) { | 265 factory _ServerSocket(String bindAddress, int port, int backlog) { |
| 266 _ServerSocket socket = new _ServerSocket._internal(); | 266 _ServerSocket socket = new _ServerSocket._internal(); |
| 267 var result = socket._createBindListen(bindAddress, port, backlog); | 267 var result = socket._createBindListen(bindAddress, port, backlog); |
| 268 if (result is OSError) { | 268 if (result is OSError) { |
| 269 socket.close(); | 269 socket.close(); |
| 270 throw new SocketIOException("Failed to create server socket", result); | 270 throw new SocketIOException("Failed to create server socket", result); |
| 271 } | 271 } |
| 272 socket._closed = false; | |
| 272 assert(result); | 273 assert(result); |
| 273 if (port != 0) { | 274 if (port != 0) { |
| 274 socket._port = port; | 275 socket._port = port; |
| 275 } | 276 } |
| 276 return socket; | 277 return socket; |
| 277 } | 278 } |
| 278 | 279 |
| 279 _ServerSocket._internal(); | 280 _ServerSocket._internal(); |
| 280 | 281 |
| 281 _accept(Socket socket) native "ServerSocket_Accept"; | 282 _accept(Socket socket) native "ServerSocket_Accept"; |
| 282 | 283 |
| 283 _createBindListen(String bindAddress, int port, int backlog) | 284 _createBindListen(String bindAddress, int port, int backlog) |
| 284 native "ServerSocket_CreateBindListen"; | 285 native "ServerSocket_CreateBindListen"; |
| 285 | 286 |
| 286 void set onConnection(void callback(Socket connection)) { | 287 void set onConnection(void callback(Socket connection)) { |
| 287 _clientConnectionHandler = callback; | 288 _clientConnectionHandler = callback; |
| 288 _setHandler(_SocketBase._IN_EVENT, | 289 _setHandler(_SocketBase._IN_EVENT, |
| 289 _clientConnectionHandler != null ? _connectionHandler : null); | 290 _clientConnectionHandler != null ? _connectionHandler : null); |
| 290 } | 291 } |
| 291 | 292 |
| 292 void _connectionHandler() { | 293 void _connectionHandler() { |
| 293 if (_id >= 0) { | 294 if (!_closed) { |
| 294 _Socket socket = new _Socket._internal(); | 295 _Socket socket = new _Socket._internal(); |
| 295 var result = _accept(socket); | 296 var result = _accept(socket); |
| 296 if (result is OSError) { | 297 if (result is OSError) { |
| 297 _reportError(result, "Accept failed"); | 298 _reportError(result, "Accept failed"); |
| 298 } else if (result) { | 299 } else if (result) { |
| 300 socket._closed = false; | |
| 299 _clientConnectionHandler(socket); | 301 _clientConnectionHandler(socket); |
| 300 } else { | 302 } else { |
| 301 // Temporary failure accepting the connection. Ignoring | 303 // Temporary failure accepting the connection. Ignoring |
| 302 // temporary failures lets us retry when we wake up with data | 304 // temporary failures lets us retry when we wake up with data |
| 303 // on the listening socket again. | 305 // on the listening socket again. |
| 304 } | 306 } |
| 305 } | 307 } |
| 306 } | 308 } |
| 307 | 309 |
| 308 bool _isListenSocket() => true; | 310 bool _isListenSocket() => true; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 326 request[1] = host; | 328 request[1] = host; |
| 327 _socketService.call(request).then((response) { | 329 _socketService.call(request).then((response) { |
| 328 if (socket._isErrorResponse(response)) { | 330 if (socket._isErrorResponse(response)) { |
| 329 socket._reportError(response, "Failed host name lookup"); | 331 socket._reportError(response, "Failed host name lookup"); |
| 330 } else{ | 332 } else{ |
| 331 var result = socket._createConnect(response, port); | 333 var result = socket._createConnect(response, port); |
| 332 if (result is OSError) { | 334 if (result is OSError) { |
| 333 socket.close(); | 335 socket.close(); |
| 334 socket._reportError(result, "Connection failed"); | 336 socket._reportError(result, "Connection failed"); |
| 335 } else { | 337 } else { |
| 338 socket._closed = false; | |
| 336 socket._activateHandlers(); | 339 socket._activateHandlers(); |
| 337 } | 340 } |
| 338 } | 341 } |
| 339 }); | 342 }); |
| 340 return socket; | 343 return socket; |
| 341 } | 344 } |
| 342 | 345 |
| 343 _Socket._internal(); | 346 _Socket._internal(); |
| 344 _Socket._internalReadOnly() : _pipe = true { super._closedWrite = true; } | 347 _Socket._internalReadOnly() : _pipe = true { super._closedWrite = true; } |
| 345 _Socket._internalWriteOnly() : _pipe = true { super._closedRead = true; } | 348 _Socket._internalWriteOnly() : _pipe = true { super._closedRead = true; } |
| 346 | 349 |
| 347 int available() { | 350 int available() { |
| 348 if (_id >= 0) { | 351 if (!_closed) { |
| 349 var result = _available(); | 352 var result = _available(); |
| 350 if (result is OSError) { | 353 if (result is OSError) { |
| 351 _reportError(result, "Available failed"); | 354 _reportError(result, "Available failed"); |
| 352 return 0; | 355 return 0; |
| 353 } else { | 356 } else { |
| 354 return result; | 357 return result; |
| 355 } | 358 } |
| 356 } | 359 } |
| 357 throw new | 360 throw new |
| 358 SocketIOException("Error: available failed - invalid socket handle"); | 361 SocketIOException("Error: available failed - invalid socket handle"); |
| 359 } | 362 } |
| 360 | 363 |
| 361 _available() native "Socket_Available"; | 364 _available() native "Socket_Available"; |
| 362 | 365 |
| 363 int readList(List<int> buffer, int offset, int bytes) { | 366 int readList(List<int> buffer, int offset, int bytes) { |
| 364 if (_id >= 0) { | 367 if (!_closed) { |
| 365 if (bytes == 0) { | 368 if (bytes == 0) { |
| 366 return 0; | 369 return 0; |
| 367 } | 370 } |
| 368 if (offset < 0) { | 371 if (offset < 0) { |
| 369 throw new IndexOutOfRangeException(offset); | 372 throw new IndexOutOfRangeException(offset); |
| 370 } | 373 } |
| 371 if (bytes < 0) { | 374 if (bytes < 0) { |
| 372 throw new IndexOutOfRangeException(bytes); | 375 throw new IndexOutOfRangeException(bytes); |
| 373 } | 376 } |
| 374 if ((offset + bytes) > buffer.length) { | 377 if ((offset + bytes) > buffer.length) { |
| 375 throw new IndexOutOfRangeException(offset + bytes); | 378 throw new IndexOutOfRangeException(offset + bytes); |
| 376 } | 379 } |
| 377 var result = _readList(buffer, offset, bytes); | 380 var result = _readList(buffer, offset, bytes); |
| 378 if (result is OSError) { | 381 if (result is OSError) { |
| 379 _reportError(result, "Read failed"); | 382 _reportError(result, "Read failed"); |
| 380 return -1; | 383 return -1; |
| 381 } | 384 } |
| 382 return result; | 385 return result; |
| 383 } | 386 } |
| 384 throw new | 387 throw new |
| 385 SocketIOException("Error: readList failed - invalid socket handle"); | 388 SocketIOException("Error: readList failed - invalid socket handle"); |
| 386 } | 389 } |
| 387 | 390 |
| 388 _readList(List<int> buffer, int offset, int bytes) | 391 _readList(List<int> buffer, int offset, int bytes) native "Socket_ReadList"; |
| 389 native "Socket_ReadList"; | |
| 390 | 392 |
| 391 int writeList(List<int> buffer, int offset, int bytes) { | 393 int writeList(List<int> buffer, int offset, int bytes) { |
| 392 if (_id >= 0) { | 394 if (!_closed) { |
| 393 if (bytes == 0) { | 395 if (bytes == 0) { |
| 394 return 0; | 396 return 0; |
| 395 } | 397 } |
| 396 if (offset < 0) { | 398 if (offset < 0) { |
| 397 throw new IndexOutOfRangeException(offset); | 399 throw new IndexOutOfRangeException(offset); |
| 398 } | 400 } |
| 399 if (bytes < 0) { | 401 if (bytes < 0) { |
| 400 throw new IndexOutOfRangeException(bytes); | 402 throw new IndexOutOfRangeException(bytes); |
| 401 } | 403 } |
| 402 if ((offset + bytes) > buffer.length) { | 404 if ((offset + bytes) > buffer.length) { |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 585 bool _seenFirstOutEvent = false; | 587 bool _seenFirstOutEvent = false; |
| 586 bool _pipe = false; | 588 bool _pipe = false; |
| 587 Function _clientConnectHandler; | 589 Function _clientConnectHandler; |
| 588 Function _clientWriteHandler; | 590 Function _clientWriteHandler; |
| 589 SocketInputStream _inputStream; | 591 SocketInputStream _inputStream; |
| 590 SocketOutputStream _outputStream; | 592 SocketOutputStream _outputStream; |
| 591 String _remoteHost; | 593 String _remoteHost; |
| 592 int _remotePort; | 594 int _remotePort; |
| 593 static SendPort _socketService; | 595 static SendPort _socketService; |
| 594 } | 596 } |
| OLD | NEW |