Chromium Code Reviews| Index: runtime/bin/sync_socket_patch.dart |
| diff --git a/runtime/bin/sync_socket_patch.dart b/runtime/bin/sync_socket_patch.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..cd21b6a9a0a777b17cb5adc8d500adcf32af8707 |
| --- /dev/null |
| +++ b/runtime/bin/sync_socket_patch.dart |
| @@ -0,0 +1,343 @@ |
| +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +@patch |
| +class RawSynchronousSocket { |
| + @patch |
| + static RawSynchronousSocket connectSync(host, int port) { |
| + return _RawSynchronousSocket.connectSync(host, port); |
| + } |
| +} |
| + |
| +class _RawSynchronousSocket implements RawSynchronousSocket { |
| + final _NativeSynchronousSocket _socket; |
| + |
| + _RawSynchronousSocket(this._socket) {} |
|
zra
2017/04/10 21:39:43
{} not needed.
bkonyi
2017/04/11 01:30:51
Done.
|
| + |
| + static RawSynchronousSocket connectSync(host, int port) { |
| + _throwOnBadPort(port); |
| + return new _RawSynchronousSocket( |
| + _NativeSynchronousSocket.connectSync(host, port)); |
| + } |
| + |
| + InternetAddress get address => _socket.address; |
| + int get port => _socket.port; |
| + InternetAddress get remoteAddress => _socket.remoteAddress; |
| + int get remotePort => _socket.remotePort; |
| + |
| + int available() => _socket.available; |
| + |
| + void closeSync() => _socket.closeSync(); |
| + |
| + int readIntoSync(List<int> buffer, [int start = 0, int end]) => |
| + _socket.readIntoSync(buffer, start, end); |
| + |
| + List<int> readSync(int bytes) => _socket.readSync(bytes); |
| + |
| + void shutdown(SocketDirection direction) => _socket.shutdown(direction); |
| + |
| + void writeFromSync(List<int> buffer, [int start = 0, int end]) => |
| + _socket.writeFromSync(buffer, start, end); |
| +} |
| + |
| +// The NativeFieldWrapperClass1 can not be used with a mixin, due to missing |
| +// implicit constructor. |
| +class _NativeSynchronousSocketNativeWrapper extends NativeFieldWrapperClass1 {} |
| + |
| +// The _NativeSynchronousSocket class encapsulates a synchronous OS socket. |
| +class _NativeSynchronousSocket extends _NativeSynchronousSocketNativeWrapper { |
| + // Socket close state. |
| + bool isClosed = false; |
| + bool isClosedRead = false; |
| + bool isClosedWrite = false; |
| + |
| + // Holds the address used to connect the socket. |
| + InternetAddress localAddress; |
| + |
| + // Holds the port of the socket, 0 if not known. |
| + int localPort = 0; |
| + |
| + _ReadWriteResourceInfo resourceInfo; |
| + |
| + static _NativeSynchronousSocket connectSync(host, int port) { |
| + List<_InternetAddress> addresses = null; |
| + var error = null; |
| + if (host is _InternetAddress) { |
| + addresses = [host]; |
| + } else { |
| + try { |
| + addresses = lookup(host); |
| + } catch (e) { |
| + error = e; |
| + } |
| + if (error != null || addresses == null || addresses.isEmpty) { |
| + throw createError(error, "Failed host lookup: '$host'"); |
| + } |
| + } |
| + assert(addresses is List); |
| + var it = addresses.iterator; |
| + _NativeSynchronousSocket connectNext() { |
| + if (!it.moveNext()) { |
| + // Could not connect. Throw the first connection error we encountered. |
| + assert(error != null); |
| + throw error; |
| + } |
| + var address = it.current; |
| + var socket = new _NativeSynchronousSocket(); |
| + socket.localAddress = address; |
| + var result = socket.nativeCreateConnectSync(address._in_addr, port); |
| + if (result is OSError) { |
| + // Keep first error, if present. |
| + if (error == null) { |
| + error = createError(result, "Connection failed", address, port); |
| + } |
| + return connectNext(); |
| + } else { |
| + // Query the local port, for error messages. |
| + try { |
| + socket.port; |
| + } catch (e) { |
| + if (error == null) { |
| + error = createError(e, "Connection failed", address, port); |
| + } |
| + return connectNext(); |
| + } |
| + setupResourceInfo(socket); |
| + } |
| + return socket; |
| + } |
| + |
| + return connectNext(); |
| + } |
| + |
| + InternetAddress get address => localAddress; |
| + int get available => nativeAvailable(); |
| + |
| + int get port { |
| + if (localPort != 0) { |
| + return localPort; |
| + } |
| + if (isClosed) { |
| + throw const SocketException.closed(); |
| + } |
| + var result = nativeGetPort(); |
| + if (result is OSError) { |
| + throw result; |
| + } |
| + return localPort = result; |
| + } |
| + |
| + InternetAddress get remoteAddress { |
| + if (isClosed) { |
| + throw const SocketException.closed(); |
| + } |
| + var result = nativeGetRemotePeer(); |
| + if (result is OSError) { |
| + throw result; |
| + } |
| + var addr = result[0]; |
| + var type = new InternetAddressType._from(addr[0]); |
|
zra
2017/04/10 21:39:43
type is unused.
bkonyi
2017/04/11 01:30:51
Done.
|
| + return new _InternetAddress(addr[1], null, addr[2]); |
| + } |
| + |
| + int get remotePort { |
| + if (isClosed) { |
| + throw const SocketException.closed(); |
| + } |
| + var result = nativeGetRemotePeer(); |
| + if (result is OSError) { |
| + throw result; |
| + } |
| + return result[1]; |
| + } |
| + |
| + void closeSync() { |
| + if (!isClosed) { |
| + nativeCloseSync(); |
| + _SocketResourceInfo.SocketClosed(resourceInfo); |
| + isClosed = true; |
| + } |
| + } |
| + |
| + // Create the appropriate error/exception from different returned |
| + // error objects. |
| + static createError(error, String message, |
| + [InternetAddress address, int port]) { |
| + if (error is OSError) { |
| + return new SocketException(message, |
| + osError: error, address: address, port: port); |
| + } else { |
| + return new SocketException(message, address: address, port: port); |
| + } |
| + } |
| + |
| + static List<InternetAddress> lookup(String host, |
| + {InternetAddressType type: InternetAddressType.ANY}) { |
| + var response = nativeLookupRequest(host, type._value); |
| + if (response is OSError) { |
| + throw response; |
| + } |
| + return response.map((result) { |
|
zra
2017/04/10 21:39:43
A for-loop that adds elements to a preallocated li
bkonyi
2017/04/11 01:30:51
Done.
|
| + var type = new InternetAddressType._from(result[0]); |
|
zra
2017/04/10 21:39:43
type is unused.
bkonyi
2017/04/11 01:30:51
Done.
|
| + return new _InternetAddress(result[1], host, result[2]); |
| + }).toList(); |
| + } |
| + |
| + int readIntoSync(List<int> buffer, int start, int end) { |
| + _checkAvailable(); |
| + if (isClosedRead) { |
| + throw new SocketException("Socket is closed for reading"); |
| + } |
| + |
| + if ((buffer is! List) || |
| + ((start != null) && (start is! int)) || |
| + ((end != null) && (end is! int))) { |
| + throw new ArgumentError("Invalid arguments to readIntoSync"); |
| + } |
| + if (start == null) { |
| + throw new ArgumentError("start cannot be equal to null"); |
|
zra
2017/04/10 21:39:43
strike "equal to"
bkonyi
2017/04/11 01:30:51
Done.
|
| + } |
| + end = RangeError.checkValidRange(start, end, buffer.length); |
| + if (end == start) { |
| + return 0; |
| + } |
| + var result = nativeReadInto(buffer, start, (end - start)); |
| + if (result is OSError) { |
| + throw new SocketException("readIntoSync failed", osError: result); |
| + } |
| + resourceInfo.addRead(result); |
| + return result; |
| + } |
| + |
| + List<int> readSync(int len) { |
| + _checkAvailable(); |
| + if (isClosedRead) { |
| + throw new SocketException("Socket is closed for reading"); |
| + } |
| + |
| + if (len != null && len < 0) { |
|
zra
2017/04/10 21:39:43
Please put () around clauses.
bkonyi
2017/04/11 01:30:51
Done.
|
| + throw new ArgumentError("Illegal length $len"); |
| + } |
| + if (len == 0) { |
| + return null; |
| + } |
| + var result = nativeRead(len); |
| + if (result is OSError) { |
| + throw result; |
| + return null; |
|
zra
2017/04/10 21:39:43
this statement is unreachable.
bkonyi
2017/04/11 01:30:51
Done.
|
| + } |
| + assert(resourceInfo != null); |
| + if (result != null) { |
| + if (resourceInfo != null) { |
| + resourceInfo.totalRead += result.length; |
| + } |
| + } |
| + if (resourceInfo != null) { |
| + resourceInfo.didRead(); |
| + } |
| + return result; |
| + } |
| + |
| + static void setupResourceInfo(_NativeSynchronousSocket socket) { |
| + socket.resourceInfo = new _SocketResourceInfo(socket); |
| + } |
| + |
| + void shutdown(SocketDirection direction) { |
| + if (isClosed) { |
| + return; |
| + } |
| + switch (direction) { |
| + case SocketDirection.RECEIVE: |
| + shutdownRead(); |
| + break; |
| + case SocketDirection.SEND: |
| + shutdownWrite(); |
| + break; |
| + case SocketDirection.BOTH: |
| + closeSync(); |
| + break; |
| + default: |
| + throw new ArgumentError(direction); |
| + } |
| + } |
| + |
| + void shutdownRead() { |
| + if (isClosed || isClosedRead) { |
| + return; |
| + } |
| + if (isClosedWrite) { |
| + closeSync(); |
| + } else { |
| + nativeShutdownRead(); |
| + } |
| + isClosedRead = true; |
| + } |
| + |
| + void shutdownWrite() { |
| + if (isClosed || isClosedWrite) { |
| + return; |
| + } |
| + if (isClosedRead) { |
| + closeSync(); |
| + } else { |
| + nativeShutdownWrite(); |
| + } |
| + isClosedWrite = true; |
| + } |
| + |
| + void writeFromSync(List<int> buffer, int start, int end) { |
| + _checkAvailable(); |
| + if (isClosedWrite) { |
| + throw new SocketException("Socket is closed for writing"); |
| + } |
| + if ((buffer is! List) || |
| + ((start != null) && (start is! int)) || |
| + ((end != null) && (end is! int))) { |
| + throw new ArgumentError("Invalid arguments to writeFromSync"); |
| + } |
| + if (start == null) { |
| + throw new ArgumentError("start cannot be equal to null"); |
| + } |
| + |
| + end = RangeError.checkValidRange(start, end, buffer.length); |
| + if (end == start) { |
| + return; |
| + } |
| + |
| + _BufferAndStart bufferAndStart = |
| + _ensureFastAndSerializableByteData(buffer, start, end); |
| + var result = nativeWrite(bufferAndStart.buffer, bufferAndStart.start, |
| + end - (start - bufferAndStart.start)); |
| + if (result is OSError) { |
| + throw new SocketException("writeFromSync failed", osError: result); |
| + } |
| + assert(resourceInfo != null); |
| + if (resourceInfo != null) { |
| + resourceInfo.addWrite(result); |
| + } |
| + } |
| + |
| + void _checkAvailable() { |
| + if (isClosed) { |
| + throw const SocketException.closed(); |
| + } |
| + } |
| + |
| + // Native method declarations. |
| + static nativeLookupRequest(host, int type) |
| + native "SynchronousSocket_LookupRequest"; |
| + nativeCreateConnectSync(host, int port) |
| + native "SynchronousSocket_CreateConnectSync"; |
| + nativeAvailable() native "SynchronousSocket_Available"; |
| + nativeCloseSync() native "SynchronousSocket_CloseSync"; |
| + int nativeGetPort() native "SynchronousSocket_GetPort"; |
| + List nativeGetRemotePeer() native "SynchronousSocket_GetRemotePeer"; |
| + nativeRead(int len) native "SynchronousSocket_Read"; |
| + nativeReadInto(List<int> buffer, int offset, int bytes) |
| + native "SynchronousSocket_ReadList"; |
| + nativeShutdownRead() native "SynchronousSocket_ShutdownRead"; |
| + nativeShutdownWrite() native "SynchronousSocket_ShutdownWrite"; |
| + nativeWrite(List<int> buffer, int offset, int bytes) |
| + native "SynchronousSocket_WriteList"; |
| +} |