Skip to content

Commit a0e4285

Browse files
authored
Merge pull request #21 from atsign-foundation/gkc/2.3.0
2 parents 1304018 + 4ff7ab9 commit a0e4285

File tree

3 files changed

+152
-50
lines changed

3 files changed

+152
-50
lines changed

CHANGELOG.md

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
1+
## 2.3.0
2+
3+
- feat: Add `authTimeout` property to SocketConnector. Previously this was
4+
- hard-coded to 5 seconds which is a bit restrictive for slow network
5+
connections. It now defaults to 30 seconds but may be set at time of
6+
construction
7+
- feat: added `authTimeout` parameter to `serverToServer`; this is provided
8+
to the SocketConnector constructor
9+
- feat: added `backlog` parameter to `serverToServer`; this is provided to
10+
the ServerSocket.bind call
11+
- feat: added `backlog` parameter to `serverToSocket`; this is provided to
12+
the ServerSocket.bind call
13+
- fix: reordered some code in `_destroySide` so it handles internal state
14+
before trying to destroy sockets
15+
- fix: added `catchError` blocks for everywhere we're calling
16+
`handleSingleConnection` when wrapped in `unawaited`
17+
- More logging (when in verbose mode)
18+
119
## 2.2.0
220

321
- feat: Enhance serverToSocket adding optional parameter `beforeJoining` which
422
will be called before a socket pair is actually joined together. Thus,
523
different transformers can be used for each socket pair.
624

725
## 2.1.0
26+
827
- Added `multi` parameter to `SocketConnector.serverToSocket` - whether to
928
create new connections on the "B" side every time there is a new "A" side
1029
connection to the bound server port. Also added `onConnect` parameter,
@@ -15,12 +34,14 @@
1534
is zero or has dropped to zero
1635

1736
## 2.0.1
37+
1838
- Removed an unnecessary dependency
1939

2040
## 2.0.0
21-
- Added support for requiring client sockets to be authenticated in some
41+
42+
- Added support for requiring client sockets to be authenticated in some
2243
app-defined way before they will be connected to the other side
23-
- Added support for app-defined data transformers which can be used to
44+
- Added support for app-defined data transformers which can be used to
2445
transform the data while sending from A to B, and vice versa. Useful for
2546
adding traffic encryption, for example.
2647
- Refactored for readability
@@ -29,32 +50,40 @@
2950
- More tests
3051

3152
## 1.0.11
53+
3254
- Added close function to SocketConnector
3355

3456
## 1.0.10
57+
3558
- Small format error to get to 140/140 on pub.dev
3659

3760
## 1.0.9
61+
3862
- Improved network throughput of socket_connector
3963

4064
## 1.0.8
4165

4266
- Added connection timeout if only one side connects
67+
4368
## 1.0.7
4469

4570
- fix change log
71+
4672
## 1.0.6
4773

48-
- Bug fix with cloing sockets.
74+
- Bug fix with closing sockets.
75+
4976
## 1.0.5
5077

5178
- Ready for isolates
79+
5280
## 1.0.4
5381

54-
- Formated with dart format 140/140 (I hope)
82+
- Formatted with dart format 140/140 (I hope)
83+
5584
## 1.0.3
5685

57-
- Included dart docs and formated with dart format
86+
- Included dart docs and formatted with dart format
5887

5988
## 1.0.2
6089

lib/src/socket_connector.dart

Lines changed: 117 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class SocketConnector {
2727
this.verbose = false,
2828
this.logTraffic = false,
2929
this.timeout = defaultTimeout,
30+
this.authTimeout = defaultTimeout,
3031
IOSink? logger,
3132
}) {
3233
this.logger = logger ?? stderr;
@@ -82,6 +83,9 @@ class SocketConnector {
8283

8384
final Completer _closedCompleter = Completer();
8485

86+
/// How long to wait for a client to authenticate its self
87+
final Duration authTimeout;
88+
8589
/// Add a [Side] with optional [SocketAuthVerifier] and
8690
/// [DataTransformer]
8791
/// - If [socketAuthVerifier] provided, wait for socket to be authenticated
@@ -101,7 +105,7 @@ class SocketConnector {
101105
try {
102106
(authenticated, stream) = await thisSide.socketAuthVerifier!
103107
(thisSide.socket)
104-
.timeout(Duration(seconds: 5));
108+
.timeout(authTimeout);
105109
thisSide.authenticated = authenticated;
106110
if (thisSide.authenticated) {
107111
thisSide.stream = stream!;
@@ -128,6 +132,8 @@ class SocketConnector {
128132
if (pendingA.isNotEmpty && pendingB.isNotEmpty) {
129133
Connection c = Connection(pendingA.removeAt(0), pendingB.removeAt(0));
130134
connections.add(c);
135+
_log(chalk.brightBlue(
136+
'Added connection. There are now ${connections.length} connections.'));
131137

132138
for (final side in [thisSide, thisSide.farSide!]) {
133139
if (side.transformer != null) {
@@ -165,37 +171,35 @@ class SocketConnector {
165171
return;
166172
}
167173
side.state = SideState.closing;
174+
Connection? connectionToRemove;
175+
for (final c in connections) {
176+
if (c.sideA == side || c.sideB == side) {
177+
_log(chalk.brightBlue('Will remove established connection'));
178+
connectionToRemove = c;
179+
break;
180+
}
181+
}
182+
if (connectionToRemove != null) {
183+
connections.remove(connectionToRemove);
184+
_log(chalk
185+
.brightBlue('Removed connection. ${connections.length} remaining.'));
186+
if (connections.isEmpty && gracePeriodPassed) {
187+
_log(chalk.brightBlue('No established connections remain'
188+
' and grace period has passed - '
189+
' will close connector'));
190+
close();
191+
}
192+
}
193+
side.state = SideState.closed;
168194
try {
169195
_log(chalk.brightBlue('Destroying socket on side ${side.name}'));
170196
side.socket.destroy();
171197
if (side.farSide != null) {
172198
_log(chalk.brightBlue(
173199
'Destroying socket on far side (${side.farSide?.name})'));
174-
side.farSide?.socket.destroy();
175-
}
176-
177-
Connection? connectionToRemove;
178-
for (final c in connections) {
179-
if (c.sideA == side || c.sideB == side) {
180-
_log(chalk.brightBlue('Will remove established connection'));
181-
connectionToRemove = c;
182-
break;
183-
}
200+
_destroySide(side.farSide!);
184201
}
185-
if (connectionToRemove != null) {
186-
connections.remove(connectionToRemove);
187-
_log(chalk.brightBlue('Removed connection'));
188-
if (connections.isEmpty && gracePeriodPassed) {
189-
_log(chalk.brightBlue('No established connections remain'
190-
' and grace period has passed - '
191-
' will close connector'));
192-
close();
193-
}
194-
}
195-
} catch (_) {
196-
} finally {
197-
side.state = SideState.closed;
198-
}
202+
} catch (_) {}
199203
}
200204

201205
void close() {
@@ -241,7 +245,9 @@ class SocketConnector {
241245
SocketAuthVerifier? socketAuthVerifierA,
242246
SocketAuthVerifier? socketAuthVerifierB,
243247
Duration timeout = SocketConnector.defaultTimeout,
248+
Duration authTimeout = SocketConnector.defaultTimeout,
244249
IOSink? logger,
250+
int backlog = 0,
245251
}) async {
246252
IOSink logSink = logger ?? stderr;
247253
addressA ??= InternetAddress.anyIPv4;
@@ -251,10 +257,19 @@ class SocketConnector {
251257
verbose: verbose,
252258
logTraffic: logTraffic,
253259
timeout: timeout,
260+
authTimeout: authTimeout,
254261
logger: logSink,
255262
);
256-
connector._serverSocketA = await ServerSocket.bind(addressA, portA);
257-
connector._serverSocketB = await ServerSocket.bind(addressB, portB);
263+
connector._serverSocketA = await ServerSocket.bind(
264+
addressA,
265+
portA,
266+
backlog: backlog,
267+
);
268+
connector._serverSocketB = await ServerSocket.bind(
269+
addressB,
270+
portB,
271+
backlog: backlog,
272+
);
258273
if (verbose) {
259274
logSink.writeln(
260275
'${DateTime.now()} | serverToServer | Bound ports A: ${connector.sideAPort}, B: ${connector.sideBPort}');
@@ -269,7 +284,18 @@ class SocketConnector {
269284
'${DateTime.now()} | serverToServer | Connection on serverSocketA: ${connector._serverSocketA!.port}');
270285
}
271286
Side sideA = Side(socket, true, socketAuthVerifier: socketAuthVerifierA);
272-
unawaited(connector.handleSingleConnection(sideA));
287+
unawaited(connector.handleSingleConnection(sideA).catchError((err) {
288+
logSink
289+
.writeln('ERROR $err from handleSingleConnection on sideA $sideA');
290+
}));
291+
}, onError: (error) {
292+
logSink.writeln(
293+
'${DateTime.now()} | serverToServer | ERROR on serverSocketA: ${connector._serverSocketA?.port} : $error');
294+
connector.close();
295+
}, onDone: () {
296+
logSink.writeln(
297+
'${DateTime.now()} | serverToServer | onDone called on serverSocketA: ${connector._serverSocketA?.port}');
298+
connector.close();
273299
});
274300

275301
// listen for connections to the side 'B' server
@@ -279,7 +305,18 @@ class SocketConnector {
279305
'${DateTime.now()} | serverToServer | Connection on serverSocketB: ${connector._serverSocketB!.port}');
280306
}
281307
Side sideB = Side(socket, false, socketAuthVerifier: socketAuthVerifierB);
282-
unawaited(connector.handleSingleConnection(sideB));
308+
unawaited(connector.handleSingleConnection(sideB).catchError((err) {
309+
logSink
310+
.writeln('ERROR $err from handleSingleConnection on sideB $sideB');
311+
}));
312+
}, onError: (error) {
313+
logSink.writeln(
314+
'${DateTime.now()} | serverToServer | ERROR on serverSocketB: ${connector._serverSocketB?.port} : $error');
315+
connector.close();
316+
}, onDone: () {
317+
logSink.writeln(
318+
'${DateTime.now()} | serverToServer | onDone called on serverSocketB: ${connector._serverSocketB?.port}');
319+
connector.close();
283320
});
284321

285322
return (connector);
@@ -319,15 +356,20 @@ class SocketConnector {
319356
// Create socket to an address and port
320357
Socket socket = await Socket.connect(addressA, portA);
321358
Side sideA = Side(socket, true, transformer: transformAtoB);
322-
unawaited(connector.handleSingleConnection(sideA));
359+
unawaited(connector.handleSingleConnection(sideA).catchError((err) {
360+
logSink.writeln('ERROR $err from handleSingleConnection on sideA $sideA');
361+
}));
323362

324363
// bind to side 'B' port
325364
connector._serverSocketB = await ServerSocket.bind(addressB, portB);
326365

327366
// listen for connections to the 'B' side port
328367
connector._serverSocketB?.listen((socketB) {
329368
Side sideB = Side(socketB, false, transformer: transformBtoA);
330-
unawaited(connector.handleSingleConnection(sideB));
369+
unawaited(connector.handleSingleConnection(sideB).catchError((err) {
370+
logSink
371+
.writeln('ERROR $err from handleSingleConnection on sideB $sideB');
372+
}));
331373
});
332374
return (connector);
333375
}
@@ -361,14 +403,18 @@ class SocketConnector {
361403
}
362404
Socket sideASocket = await Socket.connect(addressA, portA);
363405
Side sideA = Side(sideASocket, true, transformer: transformAtoB);
364-
unawaited(connector.handleSingleConnection(sideA));
406+
unawaited(connector.handleSingleConnection(sideA).catchError((err) {
407+
logSink.writeln('ERROR $err from handleSingleConnection on sideA $sideA');
408+
}));
365409

366410
if (verbose) {
367411
logSink.writeln('socket_connector: Connecting to $addressB:$portB');
368412
}
369413
Socket sideBSocket = await Socket.connect(addressB, portB);
370414
Side sideB = Side(sideBSocket, false, transformer: transformBtoA);
371-
unawaited(connector.handleSingleConnection(sideB));
415+
unawaited(connector.handleSingleConnection(sideB).catchError((err) {
416+
logSink.writeln('ERROR $err from handleSingleConnection on sideB $sideB');
417+
}));
372418

373419
if (verbose) {
374420
logSink.writeln('socket_connector: started');
@@ -408,7 +454,8 @@ class SocketConnector {
408454
bool multi = false,
409455
@Deprecated("use beforeJoining instead")
410456
Function(Socket socketA, Socket socketB)? onConnect,
411-
Function(Side sideA, Side sideB)? beforeJoining}) async {
457+
Function(Side sideA, Side sideB)? beforeJoining,
458+
int backlog = 0}) async {
412459
IOSink logSink = logger ?? stderr;
413460
addressA ??= InternetAddress.anyIPv4;
414461

@@ -421,27 +468,53 @@ class SocketConnector {
421468

422469
int connections = 0;
423470
// bind to a local port for side 'A'
424-
connector._serverSocketA = await ServerSocket.bind(addressA, portA);
425-
// listen on the local port and connect the inbound socket
426-
connector._serverSocketA?.listen((sideASocket) async {
427-
if (!multi) {
428-
unawaited(connector._serverSocketA?.close());
429-
}
471+
connector._serverSocketA = await ServerSocket.bind(
472+
addressA,
473+
portA,
474+
backlog: backlog,
475+
);
476+
477+
StreamController<Socket> ssc = StreamController();
478+
ssc.stream.listen((sideASocket) async {
430479
Side sideA = Side(sideASocket, true, transformer: transformAtoB);
431-
unawaited(connector.handleSingleConnection(sideA));
480+
unawaited(connector.handleSingleConnection(sideA).catchError((err) {
481+
logSink
482+
.writeln('ERROR $err from handleSingleConnection on sideA $sideA');
483+
}));
432484

433485
if (verbose) {
434-
logSink.writeln('Making connection ${++connections} to the "B" side');
486+
logSink.writeln('Creating socket #${++connections} to the "B" side');
435487
}
436488
// connect to the side 'B' address and port
437489
Socket sideBSocket = await Socket.connect(addressB, portB);
490+
if (verbose) {
491+
logSink.writeln('"B" side socket #$connections created');
492+
}
438493
Side sideB = Side(sideBSocket, false, transformer: transformBtoA);
439-
beforeJoining?.call(sideA, sideB);
440-
unawaited(connector.handleSingleConnection(sideB));
494+
if (verbose) {
495+
logSink.writeln('Calling the beforeJoining callback');
496+
}
497+
await beforeJoining?.call(sideA, sideB);
498+
unawaited(connector.handleSingleConnection(sideB).catchError((err) {
499+
logSink
500+
.writeln('ERROR $err from handleSingleConnection on sideB $sideB');
501+
}));
441502

442503
onConnect?.call(sideASocket, sideBSocket);
443504
});
444505

506+
// listen on the local port and connect the inbound socket
507+
connector._serverSocketA?.listen((sideASocket) {
508+
if (!multi) {
509+
try {
510+
connector._serverSocketA?.close();
511+
} catch (e) {
512+
logSink.writeln('Error while closing serverSocketA: $e');
513+
}
514+
}
515+
ssc.add(sideASocket);
516+
});
517+
445518
return (connector);
446519
}
447520
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: socket_connector
22
description: Package for joining sockets together to create socket relays.
33

4-
version: 2.2.0
4+
version: 2.3.0
55
repository: https://github.com/cconstab/socket_connector
66

77
environment:

0 commit comments

Comments
 (0)