-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
socket.dart
1303 lines (1152 loc) · 49 KB
/
socket.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) 2013, 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.
part of dart.io;
/// The type, or address family, of an [InternetAddress].
///
/// Currently, IP version 4 (IPv4), IP version 6 (IPv6)
/// and Unix domain address are supported.
/// Unix domain sockets are available only on Linux, MacOS and Android.
final class InternetAddressType {
static const InternetAddressType IPv4 = const InternetAddressType._(0);
static const InternetAddressType IPv6 = const InternetAddressType._(1);
@Since("2.8")
static const InternetAddressType unix = const InternetAddressType._(2);
static const InternetAddressType any = const InternetAddressType._(-1);
final int _value;
const InternetAddressType._(this._value);
factory InternetAddressType._from(int value) {
if (value == IPv4._value) return IPv4;
if (value == IPv6._value) return IPv6;
if (value == unix._value) return unix;
throw new ArgumentError("Invalid type: $value");
}
/// Get the name of the type, e.g. "IPv4" or "IPv6".
String get name => const ["ANY", "IPv4", "IPv6", "Unix"][_value + 1];
String toString() => "InternetAddressType: $name";
}
/// An internet address or a Unix domain address.
///
/// This object holds an internet address. If this internet address
/// is the result of a DNS lookup, the address also holds the hostname
/// used to make the lookup.
/// An Internet address combined with a port number represents an
/// endpoint to which a socket can connect or a listening socket can
/// bind.
abstract interface class InternetAddress {
/// IP version 4 loopback address.
///
/// Use this address when listening on or connecting
/// to the loopback adapter using IP version 4 (IPv4).
external static InternetAddress get loopbackIPv4;
/// IP version 6 loopback address.
///
/// Use this address when listening on or connecting to
/// the loopback adapter using IP version 6 (IPv6).
external static InternetAddress get loopbackIPv6;
/// IP version 4 any address.
///
/// Use this address when listening on the addresses
/// of all adapters using IP version 4 (IPv4).
external static InternetAddress get anyIPv4;
/// IP version 6 any address.
///
/// Use this address when listening on the addresses
/// of all adapters using IP version 6 (IPv6).
external static InternetAddress get anyIPv6;
/// The address family of the [InternetAddress].
InternetAddressType get type;
/// The numeric address of the host.
///
/// For IPv4 addresses this is using the dotted-decimal notation.
/// For IPv6 it is using the hexadecimal representation.
/// For Unix domain addresses, this is a file path.
String get address;
/// The host used to lookup the address.
///
/// If there is no host associated with the address this returns the [address].
String get host;
/// The raw address of this [InternetAddress].
///
/// For an IP address, the result is either a 4 or 16 byte long list.
/// For a Unix domain address, UTF-8 encoded byte sequences that represents
/// [address] is returned.
///
/// The returned list is a fresh copy, making it possible to change the list without
/// modifying the [InternetAddress].
Uint8List get rawAddress;
/// Whether the [InternetAddress] is a loopback address.
bool get isLoopback;
/// Whether the scope of the [InternetAddress] is a link-local.
bool get isLinkLocal;
/// Whether the scope of the [InternetAddress] is multicast.
bool get isMulticast;
/// Creates a new [InternetAddress] from a numeric address or a file path.
///
/// If [type] is [InternetAddressType.IPv4], [address] must be a numeric IPv4
/// address (dotted-decimal notation).
/// If [type] is [InternetAddressType.IPv6], [address] must be a numeric IPv6
/// address (hexadecimal notation).
/// If [type] is [InternetAddressType.unix], [address] must be a valid file
/// path.
/// If [type] is omitted, [address] must be either a numeric IPv4 or IPv6
/// address and the type is inferred from the format.
external factory InternetAddress(String address,
{@Since("2.8") InternetAddressType? type});
/// Creates a new [InternetAddress] from the provided raw address bytes.
///
/// If the [type] is [InternetAddressType.IPv4], the [rawAddress] must have
/// length 4.
/// If the [type] is [InternetAddressType.IPv6], the [rawAddress] must have
/// length 16.
/// If the [type] is [InternetAddressType.unix], the [rawAddress] must be a
/// valid UTF-8 encoded file path.
///
/// If [type] is omitted, the [rawAddress] must have a length of either 4 or
/// 16, in which case the type defaults to [InternetAddressType.IPv4] or
/// [InternetAddressType.IPv6] respectively.
external factory InternetAddress.fromRawAddress(Uint8List rawAddress,
{@Since("2.8") InternetAddressType? type});
/// Performs a reverse DNS lookup on this [address]
///
/// Returns a new [InternetAddress] with the same address, but where the [host]
/// field set to the result of the lookup.
///
/// If this address is Unix domain addresses, no lookup is performed and this
/// address is returned directly.
Future<InternetAddress> reverse();
/// Looks up the addresses of a host.
///
/// If [type] is [InternetAddressType.any], it will lookup both
/// IP version 4 (IPv4) and IP version 6 (IPv6) addresses.
/// If [type] is either [InternetAddressType.IPv4] or
/// [InternetAddressType.IPv6] it will only lookup addresses of the
/// specified type. The order of the list can, and most likely will,
/// change over time.
external static Future<List<InternetAddress>> lookup(String host,
{InternetAddressType type = InternetAddressType.any});
/// Clones the given [address] with the new [host].
///
/// The [address] must be an [InternetAddress] that was created with one
/// of the static methods of this class.
external static InternetAddress _cloneWithNewHost(
InternetAddress address, String host);
/// Attempts to parse [address] as a numeric address.
///
/// Returns `null` If [address] is not a numeric IPv4 (dotted-decimal
/// notation) or IPv6 (hexadecimal representation) address.
external static InternetAddress? tryParse(String address);
}
/// A [NetworkInterface] represents an active network interface on the current
/// system. It contains a list of [InternetAddress]es that are bound to the
/// interface.
abstract interface class NetworkInterface {
/// The name of the [NetworkInterface].
String get name;
/// The index of the [NetworkInterface].
int get index;
/// The list of [InternetAddress]es currently bound to this
/// [NetworkInterface].
List<InternetAddress> get addresses;
/// Whether the [list] method is supported.
///
/// The [list] method is supported on all platforms supported by Dart so this
/// property is always true.
@Deprecated("listSupported is always true.")
external static bool get listSupported;
/// Query the system for [NetworkInterface]s.
///
/// If [includeLoopback] is `true`, the returned list will include the
/// loopback device. Default is `false`.
///
/// If [includeLinkLocal] is `true`, the list of addresses of the returned
/// [NetworkInterface]s, may include link local addresses. Default is `false`.
///
/// If [type] is either [InternetAddressType.IPv4] or
/// [InternetAddressType.IPv6] it will only lookup addresses of the
/// specified type. Default is [InternetAddressType.any].
external static Future<List<NetworkInterface>> list(
{bool includeLoopback = false,
bool includeLinkLocal = false,
InternetAddressType type = InternetAddressType.any});
}
/// A listening socket.
///
/// A `RawServerSocket` and provides a stream of low-level [RawSocket] objects,
/// one for each connection made to the listening socket.
///
/// See [RawSocket] for more information.
abstract interface class RawServerSocket implements Stream<RawSocket> {
/// Listens on a given address and port.
///
/// When the returned future completes the server socket is bound
/// to the given [address] and [port] and has started listening on it.
///
/// The [address] can either be a [String] or an
/// [InternetAddress]. If [address] is a [String], [bind] will
/// perform a [InternetAddress.lookup] and use the first value in the
/// list. To listen on the loopback adapter, which will allow only
/// incoming connections from the local host, use the value
/// [InternetAddress.loopbackIPv4] or
/// [InternetAddress.loopbackIPv6]. To allow for incoming
/// connection from the network use either one of the values
/// [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
/// bind to all interfaces or the IP address of a specific interface.
///
/// If an IP version 6 (IPv6) address is used, both IP version 6
/// (IPv6) and version 4 (IPv4) connections will be accepted. To
/// restrict this to version 6 (IPv6) only, use [v6Only] to set
/// version 6 only.
///
/// If [port] has the value `0` an ephemeral port will
/// be chosen by the system. The actual port used can be retrieved
/// using the `port` getter.
///
/// The optional argument [backlog] can be used to specify the listen
/// backlog for the underlying OS listen setup. If [backlog] has the
/// value of `0` (the default) a reasonable value will be chosen by
/// the system.
///
/// The optional argument [shared] specifies whether additional RawServerSocket
/// objects can bind to the same combination of [address], [port] and [v6Only].
/// If [shared] is `true` and more [RawServerSocket]s from this isolate or
/// other isolates are bound to the port, then the incoming connections will be
/// distributed among all the bound [RawServerSocket]s. Connections can be
/// distributed over multiple isolates this way.
external static Future<RawServerSocket> bind(address, int port,
{int backlog = 0, bool v6Only = false, bool shared = false});
/// The port used by this socket.
int get port;
/// The address used by this socket.
InternetAddress get address;
/// Closes the socket.
///
/// The returned future completes when the socket
/// is fully closed and is no longer bound.
Future<RawServerSocket> close();
}
/// A listening socket.
///
/// A [ServerSocket] provides a stream of [Socket] objects,
/// one for each connection made to the listening socket.
///
/// See [Socket] for more info.
abstract interface class ServerSocket implements ServerSocketBase<Socket> {
/// Listens on a given address and port.
///
/// When the returned future completes the server socket is bound
/// to the given [address] and [port] and has started listening on it.
///
/// The [address] can either be a [String] or an
/// [InternetAddress]. If [address] is a [String], [bind] will
/// perform a [InternetAddress.lookup] and use the first value in the
/// list. To listen on the loopback adapter, which will allow only
/// incoming connections from the local host, use the value
/// [InternetAddress.loopbackIPv4] or
/// [InternetAddress.loopbackIPv6]. To allow for incoming
/// connection from the network use either one of the values
/// [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to
/// bind to all interfaces or the IP address of a specific interface.
///
/// If an IP version 6 (IPv6) address is used, both IP version 6
/// (IPv6) and version 4 (IPv4) connections will be accepted. To
/// restrict this to version 6 (IPv6) only, use [v6Only] to set
/// version 6 only.
///
/// If [port] has the value `0` an ephemeral port will be chosen by
/// the system. The actual port used can be retrieved using the
/// [port] getter.
///
/// The optional argument [backlog] can be used to specify the listen
/// backlog for the underlying OS listen setup. If [backlog] has the
/// value of `0` (the default) a reasonable value will be chosen by
/// the system.
///
/// The optional argument [shared] specifies whether additional ServerSocket
/// objects can bind to the same combination of [address], [port] and
/// [v6Only]. If [shared] is `true` and more server sockets from this
/// isolate or other isolates are bound to the port, then the incoming
/// connections will be distributed among all the bound server sockets.
/// Connections can be distributed over multiple isolates this way.
static Future<ServerSocket> bind(address, int port,
{int backlog = 0, bool v6Only = false, bool shared = false}) {
final IOOverrides? overrides = IOOverrides.current;
if (overrides == null) {
return ServerSocket._bind(address, port,
backlog: backlog, v6Only: v6Only, shared: shared);
}
return overrides.serverSocketBind(address, port,
backlog: backlog, v6Only: v6Only, shared: shared);
}
external static Future<ServerSocket> _bind(address, int port,
{int backlog = 0, bool v6Only = false, bool shared = false});
/// The port used by this socket.
int get port;
/// The address used by this socket.
InternetAddress get address;
/// Closes the socket.
///
/// The returned future completes when the socket
/// is fully closed and is no longer bound.
Future<ServerSocket> close();
}
/// The [SocketDirection] is used as a parameter to [Socket.close] and
/// [RawSocket.close] to close a socket in the specified direction(s).
final class SocketDirection {
static const SocketDirection receive = const SocketDirection._(0);
static const SocketDirection send = const SocketDirection._(1);
static const SocketDirection both = const SocketDirection._(2);
final _value;
const SocketDirection._(this._value);
}
/// An option for a socket which is configured using [Socket.setOption].
///
/// The [SocketOption] is used as a parameter to [Socket.setOption] and
/// [RawSocket.setOption] to customize the behaviour of the underlying
/// socket.
final class SocketOption {
/// Enable or disable no-delay on the socket. If tcpNoDelay is enabled, the
/// socket will not buffer data internally, but instead write each data chunk
/// as an individual TCP packet.
///
/// tcpNoDelay is disabled by default.
static const SocketOption tcpNoDelay = const SocketOption._(0);
static const SocketOption _ipMulticastLoop = const SocketOption._(1);
static const SocketOption _ipMulticastHops = const SocketOption._(2);
static const SocketOption _ipMulticastIf = const SocketOption._(3);
static const SocketOption _ipBroadcast = const SocketOption._(4);
final _value;
const SocketOption._(this._value);
}
// Must be kept in sync with enum in socket.cc
enum _RawSocketOptions {
SOL_SOCKET, // 0
IPPROTO_IP, // 1
IP_MULTICAST_IF, // 2
IPPROTO_IPV6, // 3
IPV6_MULTICAST_IF, // 4
IPPROTO_TCP, // 5
IPPROTO_UDP, // 6
}
/// The [RawSocketOption] is used as a parameter to [Socket.setRawOption] and
/// [RawSocket.setRawOption] to customize the behaviour of the underlying
/// socket.
///
/// It allows for fine grained control of the socket options, and its values
/// will be passed to the underlying platform's implementation of setsockopt and
/// getsockopt.
@Since("2.2")
final class RawSocketOption {
/// Creates a [RawSocketOption] for [RawSocket.getRawOption]
/// and [RawSocket.setRawOption].
///
/// The [level] and [option] arguments correspond to `level` and `optname` arguments
/// on the `getsockopt()` and `setsockopt()` native calls.
///
/// The value argument and its length correspond to the optval and length
/// arguments on the native call.
///
/// For a [RawSocket.getRawOption] call, the value parameter will be updated
/// after a successful call (although its length will not be changed).
///
/// For a [RawSocket.setRawOption] call, the value parameter will be used set
/// the option.
const RawSocketOption(this.level, this.option, this.value);
/// Convenience constructor for creating an integer based [RawSocketOption].
factory RawSocketOption.fromInt(int level, int option, int value) {
final Uint8List list = Uint8List(4);
final buffer = ByteData.view(list.buffer, list.offsetInBytes);
buffer.setInt32(0, value, Endian.host);
return RawSocketOption(level, option, list);
}
/// Convenience constructor for creating a boolean based [RawSocketOption].
factory RawSocketOption.fromBool(int level, int option, bool value) =>
RawSocketOption.fromInt(level, option, value ? 1 : 0);
/// The level for the option to set or get.
///
/// See also:
/// * [RawSocketOption.levelSocket]
/// * [RawSocketOption.levelIPv4]
/// * [RawSocketOption.levelIPv6]
/// * [RawSocketOption.levelTcp]
/// * [RawSocketOption.levelUdp]
final int level;
/// The numeric ID of the option to set or get.
final int option;
/// The raw data to set, or the array to write the current option value into.
///
/// This list must be the correct length for the expected option. For most
/// options that take [int] or [bool] values, the length should be 4. For options
/// that expect a struct (such as an in_addr_t), the length should be the
/// correct length for that struct.
final Uint8List value;
/// Socket level option for `SOL_SOCKET`.
static int get levelSocket =>
_getOptionValue(_RawSocketOptions.SOL_SOCKET.index);
/// Socket level option for `IPPROTO_IP`.
static int get levelIPv4 =>
_getOptionValue(_RawSocketOptions.IPPROTO_IP.index);
/// Socket option for `IP_MULTICAST_IF`.
static int get IPv4MulticastInterface =>
_getOptionValue(_RawSocketOptions.IP_MULTICAST_IF.index);
/// Socket level option for `IPPROTO_IPV6`.
static int get levelIPv6 =>
_getOptionValue(_RawSocketOptions.IPPROTO_IPV6.index);
/// Socket option for `IPV6_MULTICAST_IF`.
static int get IPv6MulticastInterface =>
_getOptionValue(_RawSocketOptions.IPV6_MULTICAST_IF.index);
/// Socket level option for `IPPROTO_TCP`.
static int get levelTcp =>
_getOptionValue(_RawSocketOptions.IPPROTO_TCP.index);
/// Socket level option for `IPPROTO_UDP`.
static int get levelUdp =>
_getOptionValue(_RawSocketOptions.IPPROTO_UDP.index);
external static int _getOptionValue(int key);
}
/// Events for the [RawDatagramSocket], [RawSecureSocket], and [RawSocket].
///
/// These event objects are used by the [Stream] behavior of the sockets
/// (for example [RawSocket.listen], [RawSocket.forEach])
/// when the socket's state change.
///
/// ```dart
/// import 'dart:convert';
/// import 'dart:io';
///
/// void main() async {
/// final socket = await RawSocket.connect("example.com", 80);
///
/// socket.listen((event) {
/// switch (event) {
/// case RawSocketEvent.read:
/// final data = socket.read();
/// if (data != null) {
/// print(ascii.decode(data));
/// }
/// break;
/// case RawSocketEvent.write:
/// socket.write(ascii.encode('GET /\r\nHost: example.com\r\n\r\n'));
/// socket.writeEventsEnabled = false;
/// break;
/// case RawSocketEvent.readClosed:
/// socket.close();
/// break;
/// case RawSocketEvent.closed:
/// break;
/// default:
/// throw "Unexpected event $event";
/// }
/// });
/// }
/// ```
class RawSocketEvent {
/// An event indicates the socket is ready to be read.
static const RawSocketEvent read = const RawSocketEvent._(0);
/// An event indicates the socket is ready to write.
static const RawSocketEvent write = const RawSocketEvent._(1);
/// An event indicates the reading from the socket is closed
static const RawSocketEvent readClosed = const RawSocketEvent._(2);
/// An event indicates the socket is closed.
static const RawSocketEvent closed = const RawSocketEvent._(3);
final int _value;
const RawSocketEvent._(this._value);
String toString() {
return const [
'RawSocketEvent.read',
'RawSocketEvent.write',
'RawSocketEvent.readClosed',
'RawSocketEvent.closed'
][_value];
}
}
/// A cancelable connection attempt.
///
/// Returned by the `startConnect` methods on client-side socket types `S`,
/// `ConnectionTask<S>` allows cancelling an attempt to connect to a host.
final class ConnectionTask<S> {
/// A `Future` that completes with value that `S.connect()` would return
/// unless [cancel] is called on this [ConnectionTask].
///
/// If [cancel] is called, the future completes with a [SocketException]
/// error whose message indicates that the connection attempt was cancelled.
final Future<S> socket;
final void Function() _onCancel;
ConnectionTask._(Future<S> this.socket, void Function() onCancel)
: _onCancel = onCancel;
/// Cancels the connection attempt.
///
/// This also causes the [socket] `Future` to complete with a
/// [SocketException] error.
void cancel() {
_onCancel();
}
}
/// A TCP connection.
///
/// A *socket connection* connects a *local* socket to a *remote* socket.
/// Data, as [Uint8List]s, is received by the local socket and made
/// available by the [read] method, and can be sent to the remote socket
/// through the [write] method.
///
/// The [Stream] interface of this class provides event notification about when
/// a certain change has happened, for example when data has become available
/// ([RawSocketEvent.read]) or when the remote end has stopped listening
/// ([RawSocketEvent.closed]).
abstract interface class RawSocket implements Stream<RawSocketEvent> {
/// Set or get, if the [RawSocket] should listen for [RawSocketEvent.read]
/// events. Default is `true`.
abstract bool readEventsEnabled;
/// Set or get, if the [RawSocket] should listen for [RawSocketEvent.write]
/// events. Default is `true`.
/// This is a one-shot listener, and writeEventsEnabled must be set
/// to true again to receive another write event.
abstract bool writeEventsEnabled;
/// Creates a new socket connection to the host and port.
///
/// Returns a [Future] that will complete with either a [RawSocket]
/// once connected, or an error if the host-lookup or connection failed.
///
/// The [host] can either be a [String] or an [InternetAddress]. If [host] is a
/// [String], [connect] will perform a [InternetAddress.lookup] and try
/// all returned [InternetAddress]es, until connected. If IPv4 and IPv6
/// addresses are both availble then connections over IPv4 are preferred. If
/// no connection can be establed then the error from the first failing
/// connection is returned.
///
/// The argument [sourceAddress] can be used to specify the local
/// address to bind when making the connection. The [sourceAddress] can either
/// be a [String] or an [InternetAddress]. If a [String] is passed it must
/// hold a numeric IP address.
///
/// The [sourcePort] defines the local port to bind to. If [sourcePort] is
/// not specified or zero, a port will be chosen.
///
/// The argument [timeout] is used to specify the maximum allowed time to wait
/// for a connection to be established. If [timeout] is longer than the system
/// level timeout duration, a timeout may occur sooner than specified in
/// [timeout]. On timeout, a [SocketException] is thrown and all ongoing
/// connection attempts to [host] are cancelled.
external static Future<RawSocket> connect(host, int port,
{sourceAddress, int sourcePort = 0, Duration? timeout});
/// Like [connect], but returns a [Future] that completes with a
/// [ConnectionTask] that can be cancelled if the [RawSocket] is no
/// longer needed.
external static Future<ConnectionTask<RawSocket>> startConnect(host, int port,
{sourceAddress, int sourcePort = 0});
/// The number of received and non-read bytes in the socket that can be read.
int available();
/// Read up to [len] bytes from the socket.
///
/// This function is non-blocking and will only return data
/// if data is available.
/// The number of bytes read can be less than [len] if fewer bytes are
/// available for immediate reading. If no data is available `null`
/// is returned.
Uint8List? read([int? len]);
/// Reads a message containing up to [count] bytes from the socket.
///
/// This function differs from [read] in that it will also return any
/// [SocketControlMessage] that have been sent.
///
/// This function is non-blocking and will only return data
/// if data is available.
/// The number of bytes read can be less than [count] if fewer bytes are
/// available for immediate reading.
/// Length of data buffer in [SocketMessage] indicates number of bytes read.
///
/// Returns `null` if no data is available.
///
/// Unsupported by [RawSecureSocket].
///
/// Unsupported on Android, Fuchsia, Windows.
@Since("2.15")
SocketMessage? readMessage([int? count]);
/// Writes up to [count] bytes of the buffer from [offset] buffer offset to
/// the socket.
///
/// The number of successfully written bytes is returned. This function is
/// non-blocking and will only write data if buffer space is available in
/// the socket. This means that the number of successfully written bytes may
/// be less than `count` or even 0.
///
/// Transmission of the buffer may be delayed unless
/// [SocketOption.tcpNoDelay] is set with [RawSocket.setOption].
///
/// The default value for [offset] is 0, and the default value for [count] is
/// `buffer.length - offset`.
int write(List<int> buffer, [int offset = 0, int? count]);
/// Writes socket control messages and data bytes to the socket.
///
/// Writes [controlMessages] and up to [count] bytes of [data],
/// starting at [offset], to the socket. If [count] is not provided,
/// as many bytes as possible are written. Use [write] instead if no control
/// messages are required to be sent.
///
/// When sent control messages are received, they are retained until the
/// next call to [readMessage], where all currently available control messages
/// are provided as part of the returned [SocketMessage].
/// Calling [read] will read only data bytes, and will not affect control
/// messages.
///
/// The [count] must be positive (greater than zero).
///
/// Returns the number of bytes written, which cannot be greater than
/// [count], nor greater than `data.length - offset`.
/// Return value of zero indicates that control messages were not sent.
///
/// This function is non-blocking and will only write data
/// if buffer space is available in the socket.
///
/// Throws an [OSError] if message could not be sent out.
///
/// Unsupported by [RawSecureSocket].
///
/// Unsupported on Android, Fuchsia, Windows.
@Since("2.15")
int sendMessage(List<SocketControlMessage> controlMessages, List<int> data,
[int offset = 0, int? count]);
/// The port used by this socket.
///
/// Throws a [SocketException] if the socket is closed.
int get port;
/// The remote port connected to by this socket.
///
/// Throws a [SocketException] if the socket is closed.
int get remotePort;
/// The [InternetAddress] used to connect this socket.
///
/// Throws a [SocketException] if the socket is closed.
InternetAddress get address;
/// The remote [InternetAddress] connected to by this socket.
///
/// Throws a [SocketException] if the socket is closed.
InternetAddress get remoteAddress;
/// Closes the socket.
///
/// Returns a future that completes with this socket when the
/// underlying connection is completely destroyed.
///
/// Calling [close] will never throw an exception
/// and calling it several times is supported. Calling [close] can result in
/// a [RawSocketEvent.readClosed] event.
Future<RawSocket> close();
/// Shuts down the socket in the [direction].
///
/// Calling [shutdown] will never throw an exception
/// and calling it several times is supported. Calling
/// shutdown with either [SocketDirection.both] or [SocketDirection.receive]
/// can result in a [RawSocketEvent.readClosed] event.
void shutdown(SocketDirection direction);
/// Customize the [RawSocket].
///
/// See [SocketOption] for available options.
///
/// Returns `true` if the option was set successfully, `false` otherwise.
bool setOption(SocketOption option, bool enabled);
/// Reads low level information about the [RawSocket].
///
/// See [RawSocketOption] for available options.
///
/// Returns the [RawSocketOption.value] on success.
///
/// Throws an [OSError] on failure.
@Since("2.2")
Uint8List getRawOption(RawSocketOption option);
/// Customizes the [RawSocket].
///
/// See [RawSocketOption] for available options.
///
/// Throws an [OSError] on failure.
@Since("2.2")
void setRawOption(RawSocketOption option);
}
/// A TCP connection between two sockets.
///
/// A *socket connection* connects a *local* socket to a *remote* socket.
/// Data, as [Uint8List]s, is received by the local socket, made available
/// by the [Stream] interface of this class, and can be sent to the remote
/// socket through the [IOSink] interface of this class.
///
/// Transmission of the data sent through the [IOSink] interface may be
/// delayed unless [SocketOption.tcpNoDelay] is set with
/// [Socket.setOption].
abstract interface class Socket implements Stream<Uint8List>, IOSink {
/// Creates a new socket connection to the host and port and returns a [Future]
/// that will complete with either a [Socket] once connected or an error
/// if the host-lookup or connection failed.
///
/// [host] can either be a [String] or an [InternetAddress]. If [host] is a
/// [String], [connect] will perform a [InternetAddress.lookup] and try
/// all returned [InternetAddress]es, until connected. Unless a
/// connection was established, the error from the first failing connection is
/// returned.
///
/// The argument [sourceAddress] can be used to specify the local
/// address to bind when making the connection. The [sourceAddress] can either
/// be a [String] or an [InternetAddress]. If a [String] is passed it must
/// hold a numeric IP address.
///
/// The [sourcePort] defines the local port to bind to. If [sourcePort] is
/// not specified or zero, a port will be chosen.
///
/// The argument [timeout] is used to specify the maximum allowed time to wait
/// for a connection to be established. If [timeout] is longer than the system
/// level timeout duration, a timeout may occur sooner than specified in
/// [timeout]. On timeout, a [SocketException] is thrown and all ongoing
/// connection attempts to [host] are cancelled.
static Future<Socket> connect(host, int port,
{sourceAddress, int sourcePort = 0, Duration? timeout}) {
final IOOverrides? overrides = IOOverrides.current;
if (overrides == null) {
return Socket._connect(host, port,
sourceAddress: sourceAddress,
sourcePort: sourcePort,
timeout: timeout);
}
return overrides.socketConnect(host, port,
sourceAddress: sourceAddress, sourcePort: sourcePort, timeout: timeout);
}
/// Like [connect], but returns a [Future] that completes with a
/// [ConnectionTask] that can be cancelled if the [Socket] is no
/// longer needed.
static Future<ConnectionTask<Socket>> startConnect(host, int port,
{sourceAddress, int sourcePort = 0}) {
final IOOverrides? overrides = IOOverrides.current;
if (overrides == null) {
return Socket._startConnect(host, port,
sourceAddress: sourceAddress, sourcePort: sourcePort);
}
return overrides.socketStartConnect(host, port,
sourceAddress: sourceAddress, sourcePort: sourcePort);
}
external static Future<Socket> _connect(host, int port,
{sourceAddress, int sourcePort = 0, Duration? timeout});
external static Future<ConnectionTask<Socket>> _startConnect(host, int port,
{sourceAddress, int sourcePort = 0});
Future<List<Object?>> _detachRaw();
/// Destroys the socket in both directions.
///
/// Calling [destroy] will make the send a close event on the stream
/// and will no longer react on data being piped to it.
///
/// Call [close] (inherited from [IOSink]) to only close the [Socket]
/// for sending data.
void destroy();
/// Customizes the [RawSocket].
///
/// See [SocketOption] for available options.
///
/// Returns `true` if the option was set successfully, false otherwise.
///
/// Throws a [SocketException] if the socket has been destroyed or upgraded to
/// a secure socket.
bool setOption(SocketOption option, bool enabled);
/// Reads low level information about the [RawSocket].
///
/// See [RawSocketOption] for available options.
///
/// Returns the [RawSocketOption.value] on success.
///
/// Throws an [OSError] on failure and a [SocketException] if the socket has
/// been destroyed or upgraded to a secure socket.
Uint8List getRawOption(RawSocketOption option);
/// Customizes the [RawSocket].
///
/// See [RawSocketOption] for available options.
///
/// Throws an [OSError] on failure and a [SocketException] if the socket has
/// been destroyed or upgraded to a secure socket.
void setRawOption(RawSocketOption option);
/// The port used by this socket.
///
/// Throws a [SocketException] if the socket is closed.
/// The port is 0 if the socket is a Unix domain socket.
int get port;
/// The remote port connected to by this socket.
///
/// Throws a [SocketException] if the socket is closed.
/// The port is 0 if the socket is a Unix domain socket.
int get remotePort;
/// The [InternetAddress] used to connect this socket.
///
/// Throws a [SocketException] if the socket is closed.
InternetAddress get address;
/// The remote [InternetAddress] connected to by this socket.
///
/// Throws a [SocketException] if the socket is closed.
InternetAddress get remoteAddress;
Future close();
Future get done;
}
/// A data packet received by a [RawDatagramSocket].
final class Datagram {
/// The actual bytes of the message.
Uint8List data;
/// The address of the socket which sends the data.
InternetAddress address;
/// The port of the socket which sends the data.
int port;
Datagram(this.data, this.address, this.port);
}
/// A wrapper around OS resource handle so it can be passed via Socket
/// as part of [SocketMessage].
abstract interface class ResourceHandle {
/// Creates wrapper around opened file.
external factory ResourceHandle.fromFile(RandomAccessFile file);
/// Creates wrapper around opened socket.
external factory ResourceHandle.fromSocket(Socket socket);
/// Creates wrapper around opened raw socket.
external factory ResourceHandle.fromRawSocket(RawSocket socket);
/// Creates wrapper around opened raw datagram socket.
external factory ResourceHandle.fromRawDatagramSocket(
RawDatagramSocket socket);
/// Creates wrapper around current stdin.
external factory ResourceHandle.fromStdin(Stdin stdin);
/// Creates wrapper around current stdout.
external factory ResourceHandle.fromStdout(Stdout stdout);
// Creates wrapper around a readable pipe.
external factory ResourceHandle.fromReadPipe(ReadPipe pipe);
// Creates wrapper around a writeable pipe.
external factory ResourceHandle.fromWritePipe(WritePipe pipe);
/// Extracts opened file from resource handle.
///
/// This can also be used when receiving stdin and stdout handles and read
/// and write pipes.
///
/// Since the [ResourceHandle] represents a single OS resource,
/// none of [toFile], [toSocket], [toRawSocket], or [toRawDatagramSocket],
/// [toReadPipe], [toWritePipe], can be called after a call to this method.
///
/// If this resource handle is not a file or stdio handle, the behavior of the
/// returned [RandomAccessFile] is completely unspecified.
/// Be very careful to avoid using a handle incorrectly.
RandomAccessFile toFile();
/// Extracts opened socket from resource handle.
///
/// Since the [ResourceHandle] represents a single OS resource,
/// none of [toFile], [toSocket], [toRawSocket], or [toRawDatagramSocket],
/// [toReadPipe], [toWritePipe], can be called after a call to this method.
//
/// If this resource handle is not a socket handle, the behavior of the
/// returned [Socket] is completely unspecified.
/// Be very careful to avoid using a handle incorrectly.
Socket toSocket();
/// Extracts opened raw socket from resource handle.
///
/// Since the [ResourceHandle] represents a single OS resource,
/// none of [toFile], [toSocket], [toRawSocket], or [toRawDatagramSocket],
/// [toReadPipe], [toWritePipe], can be called after a call to this method.
///
/// If this resource handle is not a socket handle, the behavior of the
/// returned [RawSocket] is completely unspecified.
/// Be very careful to avoid using a handle incorrectly.
RawSocket toRawSocket();
/// Extracts opened raw datagram socket from resource handle.
///
/// Since the [ResourceHandle] represents a single OS resource,
/// none of [toFile], [toSocket], [toRawSocket], or [toRawDatagramSocket],
/// [toReadPipe], [toWritePipe], can be called after a call to this method.
///
/// If this resource handle is not a datagram socket handle, the behavior of
/// the returned [RawDatagramSocket] is completely unspecified.
/// Be very careful to avoid using a handle incorrectly.
RawDatagramSocket toRawDatagramSocket();
/// Extracts a read pipe from resource handle.
///
/// Since the [ResourceHandle] represents a single OS resource,
/// none of [toFile], [toSocket], [toRawSocket], or [toRawDatagramSocket],
/// [toReadPipe], [toWritePipe], can be called after a call to this method.
///
/// If this resource handle is not a readable pipe, the behavior of the
/// returned [ReadPipe] is completely unspecified.
/// Be very careful to avoid using a handle incorrectly.
ReadPipe toReadPipe();
/// Extracts a write pipe from resource handle.
///
/// Since the [ResourceHandle] represents a single OS resource,
/// none of [toFile], [toSocket], [toRawSocket], or [toRawDatagramSocket],
/// [toReadPipe], [toWritePipe], can be called after a call to this method.
///
/// If this resource handle is not a writeable pipe, the behavior of the
/// returned [ReadPipe] is completely unspecified.
/// Be very careful to avoid using a handle incorrectly.
WritePipe toWritePipe();
}
/// Control message part of the [SocketMessage] received by a call to
/// [RawSocket.readMessage].
///
/// Control messages could carry different information including
/// [ResourceHandle]. If [ResourceHandle]s are available as part of this message,