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..4bd735a52252048a2a6fb472c7a76e051ae3e86e |
--- /dev/null |
+++ b/runtime/bin/sync_socket_patch.dart |
@@ -0,0 +1,347 @@ |
+// 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); |
+ |
+ 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) { |
+ if (host == null) { |
+ throw ArgumentError("Parameter host cannot be null"); |
+ } |
+ 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]; |
+ 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; |
+ } |
+ List<_InternetAddress> addresses = |
+ new List<_InternetAddress>(response.length); |
+ for (int i = 0; i < response.length; ++i) { |
+ var result = response[i]; |
+ addresses[i] = new _InternetAddress(result[1], host, result[2]); |
+ } |
+ return addresses; |
+ } |
+ |
+ 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 null"); |
+ } |
+ 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)) { |
+ throw new ArgumentError("Illegal length $len"); |
+ } |
+ if (len == 0) { |
+ return null; |
+ } |
+ var result = nativeRead(len); |
+ if (result is OSError) { |
+ throw result; |
+ } |
+ 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"; |
+} |