| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 patch class RawServerSocket { | 5 patch class RawServerSocket { |
| 6 /* patch */ static Future<RawServerSocket> bind(address, | 6 /* patch */ static Future<RawServerSocket> bind(address, |
| 7 int port, | 7 int port, |
| 8 {int backlog: 0, | 8 {int backlog: 0, |
| 9 bool v6Only: false}) { | 9 bool v6Only: false}) { |
| 10 return _RawServerSocket.bind(address, port, backlog, v6Only); | 10 return _RawServerSocket.bind(address, port, backlog, v6Only); |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 final List<InternetAddress> addresses = []; | 200 final List<InternetAddress> addresses = []; |
| 201 | 201 |
| 202 _NetworkInterface(this.name, this.index); | 202 _NetworkInterface(this.name, this.index); |
| 203 | 203 |
| 204 String toString() { | 204 String toString() { |
| 205 return "NetworkInterface('$name', $addresses)"; | 205 return "NetworkInterface('$name', $addresses)"; |
| 206 } | 206 } |
| 207 } | 207 } |
| 208 | 208 |
| 209 | 209 |
| 210 class _Rate { | |
| 211 final int buckets; | |
| 212 final data; | |
| 213 int lastValue = 0; | |
| 214 int nextBucket = 0; | |
| 215 | |
| 216 _Rate(int buckets) : buckets = buckets, data = new List.filled(buckets, 0); | |
| 217 | |
| 218 void update(int value) { | |
| 219 data[nextBucket] = value - lastValue; | |
| 220 lastValue = value; | |
| 221 nextBucket = (nextBucket + 1) % buckets; | |
| 222 } | |
| 223 | |
| 224 int get rate { | |
| 225 int sum = data.fold(0, (prev, element) => prev + element); | |
| 226 return sum ~/ buckets; | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 // Statics information for the observatory. | |
| 231 class _SocketStat { | |
| 232 _Rate readRate = new _Rate(5); | |
| 233 _Rate writeRate = new _Rate(5); | |
| 234 | |
| 235 void update(_NativeSocket socket) { | |
| 236 readRate.update(socket.totalRead); | |
| 237 writeRate.update(socket.totalWritten); | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 class _SocketsObservatory { | |
| 242 static int socketCount = 0; | |
| 243 static Map sockets = new Map<_NativeSocket, _SocketStat>(); | |
| 244 static Timer timer; | |
| 245 | |
| 246 static add(_NativeSocket socket) { | |
| 247 if (socketCount == 0) startTimer(); | |
| 248 sockets[socket] = new _SocketStat(); | |
| 249 socketCount++; | |
| 250 } | |
| 251 | |
| 252 static remove(_NativeSocket socket) { | |
| 253 _SocketStat stats = sockets.remove(socket); | |
| 254 assert(stats != null); | |
| 255 socketCount--; | |
| 256 if (socketCount == 0) stopTimer(); | |
| 257 } | |
| 258 | |
| 259 static update(_) { | |
| 260 sockets.forEach((socket, stat) { | |
| 261 stat.update(socket); | |
| 262 }); | |
| 263 } | |
| 264 | |
| 265 static startTimer() { | |
| 266 if (timer != null) return; | |
| 267 // TODO(sgjesse): Enable the rate timer. | |
| 268 // timer = new Timer.periodic(new Duration(seconds: 1), update); | |
| 269 } | |
| 270 | |
| 271 static stopTimer() { | |
| 272 if (timer == null) return; | |
| 273 timer.cancel(); | |
| 274 timer = null; | |
| 275 } | |
| 276 | |
| 277 static String generateResponse() { | |
| 278 var response = new Map(); | |
| 279 response['type'] = 'SocketList'; | |
| 280 var members = new List(); | |
| 281 response['members'] = members; | |
| 282 sockets.forEach((socket, stat) { | |
| 283 var kind = | |
| 284 socket.isListening ? "LISTENING" : | |
| 285 socket.isPipe ? "PIPE" : | |
| 286 socket.isInternal ? "INTERNAL" : "NORMAL"; | |
| 287 var protocol = | |
| 288 socket.isTcp ? "tcp" : | |
| 289 socket.isUdp ? "udp" : ""; | |
| 290 var localAddress; | |
| 291 var localPort; | |
| 292 var remoteAddress; | |
| 293 var remotePort; | |
| 294 try { | |
| 295 localAddress = socket.address.address; | |
| 296 } catch (e) { | |
| 297 localAddress = "n/a"; | |
| 298 } | |
| 299 try { | |
| 300 localPort = socket.port; | |
| 301 } catch (e) { | |
| 302 localPort = "n/a"; | |
| 303 } | |
| 304 try { | |
| 305 remoteAddress = socket.remoteAddress.address; | |
| 306 } catch (e) { | |
| 307 remoteAddress = "n/a"; | |
| 308 } | |
| 309 try { | |
| 310 remotePort = socket.remotePort; | |
| 311 } catch (e) { | |
| 312 remotePort = "n/a"; | |
| 313 } | |
| 314 members.add({'type': 'Socket', 'kind': kind, 'protocol': protocol, | |
| 315 'localAddress': localAddress, 'localPort': localPort, | |
| 316 'remoteAddress': remoteAddress, 'remotePort': remotePort, | |
| 317 'totalRead': socket.totalRead, | |
| 318 'totalWritten': socket.totalWritten, | |
| 319 'readPerSec': stat.readRate.rate, | |
| 320 'writePerSec': stat.writeRate.rate}); | |
| 321 }); | |
| 322 return JSON.encode(response);; | |
| 323 } | |
| 324 | |
| 325 static String toJSON() { | |
| 326 try { | |
| 327 return generateResponse(); | |
| 328 } catch (e, s) { | |
| 329 return '{"type":"Error","text":"$e","stacktrace":"$s"}'; | |
| 330 } | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 | |
| 335 // The NativeFieldWrapperClass1 can not be used with a mixin, due to missing | 210 // The NativeFieldWrapperClass1 can not be used with a mixin, due to missing |
| 336 // implicit constructor. | 211 // implicit constructor. |
| 337 class _NativeSocketNativeWrapper extends NativeFieldWrapperClass1 {} | 212 class _NativeSocketNativeWrapper extends NativeFieldWrapperClass1 {} |
| 338 | 213 |
| 339 | 214 |
| 340 // The _NativeSocket class encapsulates an OS socket. | 215 // The _NativeSocket class encapsulates an OS socket. |
| 341 class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { | 216 class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { |
| 342 // Bit flags used when communicating between the eventhandler and | 217 // Bit flags used when communicating between the eventhandler and |
| 343 // dart code. The EVENT flags are used to indicate events of | 218 // dart code. The EVENT flags are used to indicate events of |
| 344 // interest when sending a message from dart code to the | 219 // interest when sending a message from dart code to the |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 | 300 |
| 426 int tokens = 0; | 301 int tokens = 0; |
| 427 | 302 |
| 428 bool sendReadEvents = false; | 303 bool sendReadEvents = false; |
| 429 bool readEventIssued = false; | 304 bool readEventIssued = false; |
| 430 | 305 |
| 431 bool sendWriteEvents = false; | 306 bool sendWriteEvents = false; |
| 432 bool writeEventIssued = false; | 307 bool writeEventIssued = false; |
| 433 bool writeAvailable = false; | 308 bool writeAvailable = false; |
| 434 | 309 |
| 310 static final Stopwatch sw = new Stopwatch()..start(); |
| 435 // Statistics. | 311 // Statistics. |
| 436 int totalRead = 0; | 312 int totalRead = 0; |
| 437 int totalWritten = 0; | 313 int totalWritten = 0; |
| 314 int readCount = 0; |
| 315 int writeCount = 0; |
| 316 double lastRead; |
| 317 double lastWrite; |
| 438 | 318 |
| 439 // The owner object is the object that the Socket is being used by, e.g. | 319 // The owner object is the object that the Socket is being used by, e.g. |
| 440 // a HttpServer, a WebSocket connection, a process pipe, etc. | 320 // a HttpServer, a WebSocket connection, a process pipe, etc. |
| 441 Object owner; | 321 Object owner; |
| 442 | 322 |
| 323 static double get timestamp => sw.elapsedMicroseconds / 1000000.0; |
| 324 |
| 443 static Future<List<InternetAddress>> lookup( | 325 static Future<List<InternetAddress>> lookup( |
| 444 String host, {InternetAddressType type: InternetAddressType.ANY}) { | 326 String host, {InternetAddressType type: InternetAddressType.ANY}) { |
| 445 return _IOService.dispatch(_SOCKET_LOOKUP, [host, type._value]) | 327 return _IOService.dispatch(_SOCKET_LOOKUP, [host, type._value]) |
| 446 .then((response) { | 328 .then((response) { |
| 447 if (isErrorResponse(response)) { | 329 if (isErrorResponse(response)) { |
| 448 throw createError(response, "Failed host lookup: '$host'"); | 330 throw createError(response, "Failed host lookup: '$host'"); |
| 449 } else { | 331 } else { |
| 450 return response.skip(1).map((result) { | 332 return response.skip(1).map((result) { |
| 451 var type = new InternetAddressType._from(result[0]); | 333 var type = new InternetAddressType._from(result[0]); |
| 452 return new _InternetAddress(result[1], host, result[2]); | 334 return new _InternetAddress(result[1], host, result[2]); |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 if (len == 0) return null; | 519 if (len == 0) return null; |
| 638 var result = nativeRead(len); | 520 var result = nativeRead(len); |
| 639 if (result is OSError) { | 521 if (result is OSError) { |
| 640 reportError(result, "Read failed"); | 522 reportError(result, "Read failed"); |
| 641 return null; | 523 return null; |
| 642 } | 524 } |
| 643 if (result != null) { | 525 if (result != null) { |
| 644 available -= result.length; | 526 available -= result.length; |
| 645 totalRead += result.length; | 527 totalRead += result.length; |
| 646 } | 528 } |
| 529 readCount++; |
| 530 lastRead = timestamp; |
| 647 return result; | 531 return result; |
| 648 } | 532 } |
| 649 | 533 |
| 650 Datagram receive() { | 534 Datagram receive() { |
| 651 if (isClosing || isClosed) return null; | 535 if (isClosing || isClosed) return null; |
| 652 var result = nativeRecvFrom(); | 536 var result = nativeRecvFrom(); |
| 653 if (result is OSError) { | 537 if (result is OSError) { |
| 654 reportError(result, "Receive failed"); | 538 reportError(result, "Receive failed"); |
| 655 return null; | 539 return null; |
| 656 } | 540 } |
| 657 if (result != null) { | 541 if (result != null) { |
| 658 if (Platform.isMacOS) { | 542 if (Platform.isMacOS) { |
| 659 // Mac includes the header size, so we need to query the actual | 543 // Mac includes the header size, so we need to query the actual |
| 660 // available. | 544 // available. |
| 661 available = nativeAvailable(); | 545 available = nativeAvailable(); |
| 662 } else { | 546 } else { |
| 663 available -= result.data.length; | 547 available -= result.data.length; |
| 664 } | 548 } |
| 549 totalRead += result.data.length; |
| 665 } | 550 } |
| 551 readCount++; |
| 552 lastRead = timestamp; |
| 666 return result; | 553 return result; |
| 667 } | 554 } |
| 668 | 555 |
| 669 int write(List<int> buffer, int offset, int bytes) { | 556 int write(List<int> buffer, int offset, int bytes) { |
| 670 if (buffer is! List) throw new ArgumentError(); | 557 if (buffer is! List) throw new ArgumentError(); |
| 671 if (offset == null) offset = 0; | 558 if (offset == null) offset = 0; |
| 672 if (bytes == null) { | 559 if (bytes == null) { |
| 673 if (offset > buffer.length) { | 560 if (offset > buffer.length) { |
| 674 throw new RangeError.value(offset); | 561 throw new RangeError.value(offset); |
| 675 } | 562 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 695 } | 582 } |
| 696 // The result may be negative, if we forced a short write for testing | 583 // The result may be negative, if we forced a short write for testing |
| 697 // purpose. In such case, don't mark writeAvailable as false, as we don't | 584 // purpose. In such case, don't mark writeAvailable as false, as we don't |
| 698 // know if we'll receive an event. It's better to just retry. | 585 // know if we'll receive an event. It's better to just retry. |
| 699 if (result >= 0 && result < bytes) { | 586 if (result >= 0 && result < bytes) { |
| 700 writeAvailable = false; | 587 writeAvailable = false; |
| 701 } | 588 } |
| 702 // Negate the result, as stated above. | 589 // Negate the result, as stated above. |
| 703 if (result < 0) result = -result; | 590 if (result < 0) result = -result; |
| 704 totalWritten += result; | 591 totalWritten += result; |
| 592 writeCount++; |
| 593 lastWrite = timestamp; |
| 705 return result; | 594 return result; |
| 706 } | 595 } |
| 707 | 596 |
| 708 int send(List<int> buffer, int offset, int bytes, | 597 int send(List<int> buffer, int offset, int bytes, |
| 709 InternetAddress address, int port) { | 598 InternetAddress address, int port) { |
| 710 if (isClosing || isClosed) return 0; | 599 if (isClosing || isClosed) return 0; |
| 711 _BufferAndStart bufferAndStart = | 600 _BufferAndStart bufferAndStart = |
| 712 _ensureFastAndSerializableByteData( | 601 _ensureFastAndSerializableByteData( |
| 713 buffer, offset, bytes); | 602 buffer, offset, bytes); |
| 714 var result = nativeSendTo( | 603 var result = nativeSendTo( |
| 715 bufferAndStart.buffer, bufferAndStart.start, bytes, | 604 bufferAndStart.buffer, bufferAndStart.start, bytes, |
| 716 address._in_addr, port); | 605 address._in_addr, port); |
| 717 if (result is OSError) { | 606 if (result is OSError) { |
| 718 scheduleMicrotask(() => reportError(result, "Send failed")); | 607 scheduleMicrotask(() => reportError(result, "Send failed")); |
| 719 result = 0; | 608 result = 0; |
| 720 } | 609 } |
| 610 totalWritten += result; |
| 611 writeCount++; |
| 612 lastWrite = timestamp; |
| 721 return result; | 613 return result; |
| 722 } | 614 } |
| 723 | 615 |
| 724 _NativeSocket accept() { | 616 _NativeSocket accept() { |
| 725 // Don't issue accept if we're closing. | 617 // Don't issue accept if we're closing. |
| 726 if (isClosing || isClosed) return null; | 618 if (isClosing || isClosed) return null; |
| 727 assert(available > 0); | 619 assert(available > 0); |
| 728 available--; | 620 available--; |
| 729 tokens++; | 621 tokens++; |
| 730 returnTokens(LISTENING_TOKEN_BATCH_SIZE); | 622 returnTokens(LISTENING_TOKEN_BATCH_SIZE); |
| 731 var socket = new _NativeSocket.normal(); | 623 var socket = new _NativeSocket.normal(); |
| 732 if (nativeAccept(socket) != true) return null; | 624 if (nativeAccept(socket) != true) return null; |
| 733 socket.localPort = localPort; | 625 socket.localPort = localPort; |
| 734 socket.address = address; | 626 socket.address = address; |
| 735 totalRead += 1; | 627 totalRead += 1; |
| 628 lastRead = timestamp; |
| 736 return socket; | 629 return socket; |
| 737 } | 630 } |
| 738 | 631 |
| 739 int get port { | 632 int get port { |
| 740 if (localPort != 0) return localPort; | 633 if (localPort != 0) return localPort; |
| 741 var result = nativeGetPort(); | 634 var result = nativeGetPort(); |
| 742 if (result is OSError) throw result; | 635 if (result is OSError) throw result; |
| 743 return localPort = result; | 636 return localPort = result; |
| 744 } | 637 } |
| 745 | 638 |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1085 'name': name, | 978 'name': name, |
| 1086 'user_name': name, | 979 'user_name': name, |
| 1087 'kind': _JSONKind(), | 980 'kind': _JSONKind(), |
| 1088 }; | 981 }; |
| 1089 if (ref) { | 982 if (ref) { |
| 1090 return r; | 983 return r; |
| 1091 } | 984 } |
| 1092 r['readClosed'] = isClosedRead; | 985 r['readClosed'] = isClosedRead; |
| 1093 r['writeClosed'] = isClosedWrite; | 986 r['writeClosed'] = isClosedWrite; |
| 1094 r['closing'] = isClosing; | 987 r['closing'] = isClosing; |
| 1095 r['listening'] = isListening; | |
| 1096 r['fd'] = nativeGetSocketId(); | 988 r['fd'] = nativeGetSocketId(); |
| 1097 if (owner != null) { | 989 if (owner != null) { |
| 1098 r['owner'] = owner._toJSON(true); | 990 r['owner'] = owner._toJSON(true); |
| 991 } |
| 992 return r; |
| 993 } |
| 994 |
| 995 Map _toJSONInternal(bool ref) { |
| 996 var name = 'Internal'; |
| 997 var r = { |
| 998 'id': _servicePath, |
| 999 'type': _serviceType(ref), |
| 1000 'name': name, |
| 1001 'user_name': name, |
| 1002 'kind': _JSONKind(), |
| 1003 }; |
| 1004 if (ref) { |
| 1005 return r; |
| 1006 } |
| 1007 r['closing'] = isClosing; |
| 1008 r['fd'] = nativeGetSocketId(); |
| 1009 if (owner != null) { |
| 1010 r['owner'] = owner._toJSON(true); |
| 1099 } | 1011 } |
| 1100 return r; | 1012 return r; |
| 1101 } | 1013 } |
| 1102 | 1014 |
| 1103 Map _toJSONNetwork(bool ref) { | 1015 Map _toJSONNetwork(bool ref) { |
| 1104 var name = '${address.host}:$port'; | 1016 var name = '${address.host}:$port'; |
| 1105 if (isTcp && !isListening) name += " <-> ${remoteAddress.host}:$remotePort"; | 1017 if (isTcp && !isListening) name += " <-> ${remoteAddress.host}:$remotePort"; |
| 1106 var r = { | 1018 var r = { |
| 1107 'id': _servicePath, | 1019 'id': _servicePath, |
| 1108 'type': _serviceType(ref), | 1020 'type': _serviceType(ref), |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1140 r['closing'] = isClosing; | 1052 r['closing'] = isClosing; |
| 1141 r['listening'] = isListening; | 1053 r['listening'] = isListening; |
| 1142 r['fd'] = nativeGetSocketId(); | 1054 r['fd'] = nativeGetSocketId(); |
| 1143 if (owner != null) { | 1055 if (owner != null) { |
| 1144 r['owner'] = owner._toJSON(true); | 1056 r['owner'] = owner._toJSON(true); |
| 1145 } | 1057 } |
| 1146 return r; | 1058 return r; |
| 1147 } | 1059 } |
| 1148 | 1060 |
| 1149 Map _toJSON(bool ref) { | 1061 Map _toJSON(bool ref) { |
| 1062 var map; |
| 1150 if (isPipe) { | 1063 if (isPipe) { |
| 1151 return _toJSONPipe(ref); | 1064 map = _toJSONPipe(ref); |
| 1065 } else if (isInternal) { |
| 1066 map = _toJSONInternal(ref); |
| 1067 } else { |
| 1068 map = _toJSONNetwork(ref); |
| 1152 } | 1069 } |
| 1153 return _toJSONNetwork(ref); | 1070 if (!ref) { |
| 1071 map['available'] = available; |
| 1072 map['totalRead'] = totalRead; |
| 1073 map['totalWritten'] = totalWritten; |
| 1074 map['readCount'] = totalWritten; |
| 1075 map['writeCount'] = writeCount; |
| 1076 map['lastRead'] = lastRead; |
| 1077 map['lastWrite'] = lastWrite; |
| 1078 } |
| 1079 return map; |
| 1154 } | 1080 } |
| 1155 | 1081 |
| 1156 void nativeSetSocketId(int id) native "Socket_SetSocketId"; | 1082 void nativeSetSocketId(int id) native "Socket_SetSocketId"; |
| 1157 nativeAvailable() native "Socket_Available"; | 1083 nativeAvailable() native "Socket_Available"; |
| 1158 nativeRead(int len) native "Socket_Read"; | 1084 nativeRead(int len) native "Socket_Read"; |
| 1159 nativeRecvFrom() native "Socket_RecvFrom"; | 1085 nativeRecvFrom() native "Socket_RecvFrom"; |
| 1160 nativeWrite(List<int> buffer, int offset, int bytes) | 1086 nativeWrite(List<int> buffer, int offset, int bytes) |
| 1161 native "Socket_WriteList"; | 1087 native "Socket_WriteList"; |
| 1162 nativeSendTo(List<int> buffer, int offset, int bytes, | 1088 nativeSendTo(List<int> buffer, int offset, int bytes, |
| 1163 List<int> address, int port) | 1089 List<int> address, int port) |
| (...skipping 808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1972 String address, | 1898 String address, |
| 1973 List<int> in_addr, | 1899 List<int> in_addr, |
| 1974 int port) { | 1900 int port) { |
| 1975 return new Datagram( | 1901 return new Datagram( |
| 1976 data, | 1902 data, |
| 1977 new _InternetAddress(address, null, in_addr), | 1903 new _InternetAddress(address, null, in_addr), |
| 1978 port); | 1904 port); |
| 1979 } | 1905 } |
| 1980 | 1906 |
| 1981 String _socketsStats() => _SocketsObservatory.toJSON(); | 1907 String _socketsStats() => _SocketsObservatory.toJSON(); |
| OLD | NEW |