| Index: runtime/bin/socket_patch.dart
|
| diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
|
| index be459ba164dd2c653ae3b0e4ee2d8175db0d197e..94285aaaa02ed59b6eb0905770a60a066762bdf3 100644
|
| --- a/runtime/bin/socket_patch.dart
|
| +++ b/runtime/bin/socket_patch.dart
|
| @@ -280,6 +280,9 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| static const Duration _RETRY_DURATION_LOOPBACK =
|
| const Duration(milliseconds: 25);
|
|
|
| + // Use default Map so we keep order.
|
| + static Map<int, _NativeSocket> _sockets = new Map<int, _NativeSocket>();
|
| +
|
| // Socket close state
|
| bool isClosed = false;
|
| bool isClosing = false;
|
| @@ -314,9 +317,13 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| bool writeAvailable = false;
|
|
|
| static final Stopwatch sw = new Stopwatch()..start();
|
| -
|
| - static bool connectedResourceHandler = false;
|
| - _ReadWriteResourceInfo resourceInfo;
|
| + // Statistics.
|
| + int totalRead = 0;
|
| + int totalWritten = 0;
|
| + int readCount = 0;
|
| + int writeCount = 0;
|
| + double lastRead;
|
| + double lastWrite;
|
|
|
| // The owner object is the object that the Socket is being used by, e.g.
|
| // a HttpServer, a WebSocket connection, a process pipe, etc.
|
| @@ -434,8 +441,6 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| _RETRY_DURATION_LOOPBACK :
|
| _RETRY_DURATION;
|
| var timer = new Timer(duration, connectNext);
|
| - setupResourceInfo(socket);
|
| -
|
| connecting[socket] = timer;
|
| // Setup handlers for receiving the first write event which
|
| // indicate that the socket is fully connected.
|
| @@ -487,6 +492,7 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| .then((address) {
|
| var socket = new _NativeSocket.listen();
|
| socket.localAddress = address;
|
| +
|
| var result = socket.nativeCreateBindListen(address._in_addr,
|
| port,
|
| backlog,
|
| @@ -499,16 +505,11 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| port: port);
|
| }
|
| if (port != 0) socket.localPort = port;
|
| - setupResourceInfo(socket);
|
| socket.connectToEventHandler();
|
| return socket;
|
| });
|
| }
|
|
|
| - static void setupResourceInfo(_NativeSocket socket) {
|
| - socket.resourceInfo = new _SocketResourceInfo(socket);
|
| - }
|
| -
|
| static Future<_NativeSocket> bindDatagram(
|
| host, int port, bool reuseAddress) {
|
| return new Future.value(host)
|
| @@ -533,7 +534,6 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| port: port);
|
| }
|
| if (port != 0) socket.localPort = port;
|
| - setupResourceInfo(socket);
|
| return socket;
|
| });
|
| }
|
| @@ -575,18 +575,10 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| }
|
| if (result != null) {
|
| available -= result.length;
|
| - // TODO(ricow): Remove when we track internal and pipe uses.
|
| - assert(resourceInfo != null || isPipe || isInternal);
|
| - if (resourceInfo != null) {
|
| - resourceInfo.totalRead += result.length;
|
| - }
|
| - }
|
| - // TODO(ricow): Remove when we track internal and pipe uses.
|
| - assert(resourceInfo != null || isPipe || isInternal);
|
| - if (resourceInfo != null) {
|
| - resourceInfo.readCount++;
|
| - resourceInfo.lastRead = timestamp;
|
| + totalRead += result.length;
|
| }
|
| + readCount++;
|
| + lastRead = timestamp;
|
| return result;
|
| }
|
|
|
| @@ -603,18 +595,10 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| // receive. If available becomes > 0, the _NativeSocket will continue to
|
| // emit read events.
|
| available = nativeAvailable();
|
| - // TODO(ricow): Remove when we track internal and pipe uses.
|
| - assert(resourceInfo != null || isPipe || isInternal);
|
| - if (resourceInfo != null) {
|
| - resourceInfo.totalRead += result.data.length;
|
| - }
|
| - }
|
| - // TODO(ricow): Remove when we track internal and pipe uses.
|
| - assert(resourceInfo != null || isPipe || isInternal);
|
| - if (resourceInfo != null) {
|
| - resourceInfo.readCount++;
|
| - resourceInfo.lastRead = timestamp;
|
| + totalRead += result.data.length;
|
| }
|
| + readCount++;
|
| + lastRead = timestamp;
|
| return result;
|
| }
|
|
|
| @@ -653,13 +637,9 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| }
|
| // Negate the result, as stated above.
|
| if (result < 0) result = -result;
|
| - // TODO(ricow): Remove when we track internal and pipe uses.
|
| - assert(resourceInfo != null || isPipe || isInternal);
|
| - if (resourceInfo != null) {
|
| - resourceInfo.totalWritten += result;
|
| - resourceInfo.writeCount++;
|
| - resourceInfo.lastWrite = timestamp;
|
| - }
|
| + totalWritten += result;
|
| + writeCount++;
|
| + lastWrite = timestamp;
|
| return result;
|
| }
|
|
|
| @@ -676,13 +656,9 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| scheduleMicrotask(() => reportError(result, "Send failed"));
|
| result = 0;
|
| }
|
| - // TODO(ricow): Remove when we track internal and pipe uses.
|
| - assert(resourceInfo != null || isPipe || isInternal);
|
| - if (resourceInfo != null) {
|
| - resourceInfo.totalWritten += result;
|
| - resourceInfo.writeCount++;
|
| - resourceInfo.lastWrite = timestamp;
|
| - }
|
| + totalWritten += result;
|
| + writeCount++;
|
| + lastWrite = timestamp;
|
| return result;
|
| }
|
|
|
| @@ -697,13 +673,8 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| if (nativeAccept(socket) != true) return null;
|
| socket.localPort = localPort;
|
| socket.localAddress = address;
|
| - setupResourceInfo(socket);
|
| - // TODO(ricow): Remove when we track internal and pipe uses.
|
| - assert(resourceInfo != null || isPipe || isInternal);
|
| - if (resourceInfo != null) {
|
| - resourceInfo.totalRead += 1;
|
| - resourceInfo.lastRead = timestamp;
|
| - }
|
| + totalRead += 1;
|
| + lastRead = timestamp;
|
| return socket;
|
| }
|
|
|
| @@ -816,11 +787,6 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| if (i == DESTROYED_EVENT) {
|
| assert(isClosing);
|
| assert(!isClosed);
|
| - // TODO(ricow): Remove/update when we track internal and pipe uses.
|
| - assert(resourceInfo != null || isPipe || isInternal);
|
| - if (resourceInfo != null) {
|
| - _SocketResourceInfo.SocketClosed(resourceInfo);
|
| - }
|
| isClosed = true;
|
| closeCompleter.complete();
|
| disconnectFromEventHandler();
|
| @@ -938,14 +904,7 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| assert(!isClosed);
|
| if (eventPort == null) {
|
| eventPort = new RawReceivePort(multiplex);
|
| - }
|
| - if (!connectedResourceHandler) {
|
| - registerExtension('__getOpenSockets',
|
| - _SocketResourceInfo.getOpenSockets);
|
| - registerExtension('__getSocketByID',
|
| - _SocketResourceInfo.getSocketInfoMapByID);
|
| -
|
| - connectedResourceHandler = true;
|
| + _sockets[_serviceId] = this;
|
| }
|
| }
|
|
|
| @@ -953,6 +912,7 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| assert(eventPort != null);
|
| eventPort.close();
|
| eventPort = null;
|
| + _sockets.remove(_serviceId);
|
| // Now that we don't track this Socket anymore, we can clear the owner
|
| // field.
|
| owner = null;
|
| @@ -1057,6 +1017,123 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
| if (result is OSError) throw result;
|
| }
|
|
|
| + String get _serviceTypePath => 'io/sockets';
|
| + String get _serviceTypeName => 'Socket';
|
| +
|
| + String _JSONKind() {
|
| + return isListening ? "Listening" :
|
| + isPipe ? "Pipe" :
|
| + isInternal ? "Internal" : "Normal";
|
| + }
|
| +
|
| + Map _toJSONPipe(bool ref) {
|
| + var name = 'Anonymous Pipe';
|
| + var r = {
|
| + 'id': _servicePath,
|
| + 'type': _serviceType(ref),
|
| + 'name': name,
|
| + 'user_name': name,
|
| + 'kind': _JSONKind(),
|
| + };
|
| + if (ref) {
|
| + return r;
|
| + }
|
| + r['readClosed'] = isClosedRead;
|
| + r['writeClosed'] = isClosedWrite;
|
| + r['closing'] = isClosing;
|
| + r['fd'] = nativeGetSocketId();
|
| + if (owner != null) {
|
| + r['owner'] = owner._toJSON(true);
|
| + }
|
| + return r;
|
| + }
|
| +
|
| + Map _toJSONInternal(bool ref) {
|
| + var name = 'Internal';
|
| + var r = {
|
| + 'id': _servicePath,
|
| + 'type': _serviceType(ref),
|
| + 'name': name,
|
| + 'user_name': name,
|
| + 'kind': _JSONKind(),
|
| + };
|
| + if (ref) {
|
| + return r;
|
| + }
|
| + r['closing'] = isClosing;
|
| + r['fd'] = nativeGetSocketId();
|
| + if (owner != null) {
|
| + r['owner'] = owner._toJSON(true);
|
| + }
|
| + return r;
|
| + }
|
| +
|
| + Map _toJSONNetwork(bool ref) {
|
| + var name = '${address.host}:$port';
|
| + if (isTcp && !isListening) name += " <-> ${remoteAddress.host}:$remotePort";
|
| + var r = {
|
| + 'id': _servicePath,
|
| + 'type': _serviceType(ref),
|
| + 'name': name,
|
| + 'user_name': name,
|
| + 'kind': _JSONKind(),
|
| + };
|
| + if (ref) {
|
| + return r;
|
| + }
|
| + var protocol = isTcp ? "TCP" : isUdp ? "UDP" : null;
|
| + var localAddress;
|
| + var localPort;
|
| + var rAddress;
|
| + var rPort;
|
| + try {
|
| + localAddress = address.address;
|
| + } catch (e) { }
|
| + try {
|
| + localPort = port;
|
| + } catch (e) { }
|
| + try {
|
| + rAddress = this.remoteAddress.address;
|
| + } catch (e) { }
|
| + try {
|
| + rPort = remotePort;
|
| + } catch (e) { }
|
| + r['localAddress'] = localAddress;
|
| + r['localPort'] = localPort;
|
| + r['remoteAddress'] = rAddress;
|
| + r['remotePort'] = rPort;
|
| + r['protocol'] = protocol;
|
| + r['readClosed'] = isClosedRead;
|
| + r['writeClosed'] = isClosedWrite;
|
| + r['closing'] = isClosing;
|
| + r['listening'] = isListening;
|
| + r['fd'] = nativeGetSocketId();
|
| + if (owner != null) {
|
| + r['owner'] = owner._toJSON(true);
|
| + }
|
| + return r;
|
| + }
|
| +
|
| + Map _toJSON(bool ref) {
|
| + var map;
|
| + if (isPipe) {
|
| + map = _toJSONPipe(ref);
|
| + } else if (isInternal) {
|
| + map = _toJSONInternal(ref);
|
| + } else {
|
| + map = _toJSONNetwork(ref);
|
| + }
|
| + if (!ref) {
|
| + map['available'] = available;
|
| + map['totalRead'] = totalRead;
|
| + map['totalWritten'] = totalWritten;
|
| + map['readCount'] = totalWritten;
|
| + map['writeCount'] = writeCount;
|
| + map['lastRead'] = lastRead;
|
| + map['lastWrite'] = lastWrite;
|
| + }
|
| + return map;
|
| + }
|
|
|
| void nativeSetSocketId(int id) native "Socket_SetSocketId";
|
| nativeAvailable() native "Socket_Available";
|
| @@ -1209,6 +1286,8 @@ class _RawServerSocket extends Stream<RawSocket>
|
| return new _RawServerSocketReference(_referencePort.sendPort);
|
| }
|
|
|
| + Map _toJSON(bool ref) => _socket._toJSON(ref);
|
| +
|
| void set _owner(owner) { _socket.owner = owner; }
|
| }
|
|
|
| @@ -1386,6 +1465,7 @@ class _RawSocket extends Stream<RawSocketEvent>
|
| }
|
| }
|
|
|
| + Map _toJSON(bool ref) => _socket._toJSON(ref);
|
| void set _owner(owner) { _socket.owner = owner; }
|
| }
|
|
|
| @@ -1448,6 +1528,8 @@ class _ServerSocket extends Stream<Socket>
|
| return new _ServerSocketReference(_socket.reference);
|
| }
|
|
|
| + Map _toJSON(bool ref) => _socket._toJSON(ref);
|
| +
|
| void set _owner(owner) { _socket._owner = owner; }
|
| }
|
|
|
| @@ -1761,6 +1843,7 @@ class _Socket extends Stream<List<int>> implements Socket {
|
| }
|
| }
|
|
|
| + Map _toJSON(bool ref) => _raw._toJSON(ref);
|
| void set _owner(owner) { _raw._owner = owner; }
|
| }
|
|
|
| @@ -1916,3 +1999,4 @@ Datagram _makeDatagram(List<int> data,
|
| port);
|
| }
|
|
|
| +String _socketsStats() => _SocketsObservatory.toJSON();
|
|
|