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 |