fixed peer learning from first package (race condition)
This commit is contained in:
@@ -28,6 +28,11 @@ import 'mlrs_network_controller.dart';
|
|||||||
/// mit ansteigender Wartezeit (Doku Abschnitt 8) ist noch nicht
|
/// mit ansteigender Wartezeit (Doku Abschnitt 8) ist noch nicht
|
||||||
/// umgesetzt - der Nutzer stoesst es aktuell ueber "Connect" erneut an.
|
/// umgesetzt - der Nutzer stoesst es aktuell ueber "Connect" erneut an.
|
||||||
class UdpTransport implements LinkTransport {
|
class UdpTransport implements LinkTransport {
|
||||||
|
/// Bekannte Standard-IP der mLRS-WLAN-Bruecke im AP-Modus - letzter
|
||||||
|
/// Rueckfall, wenn weder ein Host konfiguriert noch eine Gateway-Adresse
|
||||||
|
/// vom Netz gemeldet wurde (siehe [connect]).
|
||||||
|
static const _defaultMlrsHost = '192.168.4.55';
|
||||||
|
|
||||||
UdpTransport({
|
UdpTransport({
|
||||||
required Future<String?> Function() getHost,
|
required Future<String?> Function() getHost,
|
||||||
required Future<int> Function() getPort,
|
required Future<int> Function() getPort,
|
||||||
@@ -157,16 +162,36 @@ class UdpTransport implements LinkTransport {
|
|||||||
|
|
||||||
final configuredHost = await _getHost();
|
final configuredHost = await _getHost();
|
||||||
final configuredPort = await _getPort();
|
final configuredPort = await _getPort();
|
||||||
|
// Reihenfolge: explizit konfigurierter Host > vom Netz gemeldete
|
||||||
|
// Gateway-Adresse (bei der hier verwendeten lokalen, internetlosen
|
||||||
|
// WifiNetworkSpecifier-Anfrage in der Praxis meist gar nicht gesetzt,
|
||||||
|
// da solche Netze i.d.R. keine Default-Route haben) > fest hinterlegte
|
||||||
|
// Standard-IP der mLRS-Bruecke. Diese Vorbelegung wird durch das erste
|
||||||
|
// tatsaechlich empfangene Paket in [_onPacket] ueberschrieben - sie
|
||||||
|
// greift also nur, solange (noch) kein Paket gelernt wurde, z.B. wenn
|
||||||
|
// die Bruecke ihr erstes Paket nicht zuverlaessig sendet oder es durch
|
||||||
|
// die unten beschriebene Startup-Race verpasst wuerde.
|
||||||
final prefillHost = (configuredHost != null && configuredHost.isNotEmpty)
|
final prefillHost = (configuredHost != null && configuredHost.isNotEmpty)
|
||||||
? configuredHost
|
? configuredHost
|
||||||
: available.gatewayAddress;
|
: (available.gatewayAddress ?? _defaultMlrsHost);
|
||||||
if (prefillHost != null) {
|
|
||||||
final parsed = InternetAddress.tryParse(prefillHost);
|
final parsed = InternetAddress.tryParse(prefillHost);
|
||||||
if (parsed != null) {
|
if (parsed != null) {
|
||||||
_peerAddress = parsed;
|
_peerAddress = parsed;
|
||||||
_peerPort = configuredPort;
|
_peerPort = configuredPort;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// WICHTIG: Auf eingehende Pakete lauschen, BEVOR der native Socket
|
||||||
|
// geoeffnet wird, nicht danach. MlrsNetworkPlugin.kt startet seine
|
||||||
|
// Empfangsschleife (startReceiveLoop) direkt nach dem Binden des
|
||||||
|
// Sockets - noch bevor das openSocket()-Ergebnis ueberhaupt an Dart
|
||||||
|
// zurueckgemeldet wird. Wuerden wir wie zuvor erst NACH openSocket()
|
||||||
|
// abonnieren, koennte die mLRS-Bruecke ihr erstes (fuer das
|
||||||
|
// IP-Lernen entscheidendes) Paket in genau diesem Fenster senden,
|
||||||
|
// waehrend der native socketEventSink noch null ist - das Paket waere
|
||||||
|
// dann unwiderruflich verloren (kein Buffering auf der Event-Channel-
|
||||||
|
// Seite). Durch das vorgezogene Abonnement ist der Sink so gut wie
|
||||||
|
// immer gesetzt, bevor die Empfangsschleife ueberhaupt starten kann.
|
||||||
|
_packetSub = _networkController.incomingPackets.listen(_onPacket);
|
||||||
|
|
||||||
// Nativer, socket-genau gebundener UDP-Socket statt Prozessbindung
|
// Nativer, socket-genau gebundener UDP-Socket statt Prozessbindung
|
||||||
// (siehe Klassendoku) - der eigentliche RawDatagramSocket lebt in
|
// (siehe Klassendoku) - der eigentliche RawDatagramSocket lebt in
|
||||||
@@ -179,7 +204,6 @@ class UdpTransport implements LinkTransport {
|
|||||||
_lastErrorMessage = 'Port ${bindResult.fallbackFromPort} in use, '
|
_lastErrorMessage = 'Port ${bindResult.fallbackFromPort} in use, '
|
||||||
'fell back to ${bindResult.boundPort}.';
|
'fell back to ${bindResult.boundPort}.';
|
||||||
}
|
}
|
||||||
_packetSub = _networkController.incomingPackets.listen(_onPacket);
|
|
||||||
|
|
||||||
_staConcurrencySupported =
|
_staConcurrencySupported =
|
||||||
await _networkController.isStaConcurrencySupported();
|
await _networkController.isStaConcurrencySupported();
|
||||||
|
|||||||
@@ -188,6 +188,19 @@ void main() {
|
|||||||
transport.dispose();
|
transport.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'falls back to the default mLRS bridge IP when neither a host is '
|
||||||
|
'configured nor a gateway address is reported',
|
||||||
|
() async {
|
||||||
|
final fake = FakeMlrsNetworkController();
|
||||||
|
final transport = await connectWithFake(fake);
|
||||||
|
|
||||||
|
expect(transport.peerDescription, startsWith('192.168.4.55'));
|
||||||
|
|
||||||
|
transport.dispose();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
test('a configured host overrides the reported gateway address', () async {
|
test('a configured host overrides the reported gateway address', () async {
|
||||||
final fake = FakeMlrsNetworkController();
|
final fake = FakeMlrsNetworkController();
|
||||||
final transport = await connectWithFake(
|
final transport = await connectWithFake(
|
||||||
@@ -223,9 +236,17 @@ void main() {
|
|||||||
transport.dispose();
|
transport.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('send() without a known peer throws LinkConnectException', () async {
|
test('send() before the socket is open throws LinkConnectException',
|
||||||
|
() async {
|
||||||
final fake = FakeMlrsNetworkController();
|
final fake = FakeMlrsNetworkController();
|
||||||
final transport = await connectWithFake(fake);
|
final transport = UdpTransport(
|
||||||
|
getHost: () async => null,
|
||||||
|
getPort: () async => 0,
|
||||||
|
getSsidPrefix: () async => 'mLRS-',
|
||||||
|
getRememberedSsid: () async => null,
|
||||||
|
rememberSsid: (_) async {},
|
||||||
|
networkController: fake,
|
||||||
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
() => transport.send(Uint8List.fromList([1])),
|
() => transport.send(Uint8List.fromList([1])),
|
||||||
@@ -235,6 +256,22 @@ void main() {
|
|||||||
transport.dispose();
|
transport.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'send() works with the default mLRS bridge IP even before any packet '
|
||||||
|
'has been received',
|
||||||
|
() async {
|
||||||
|
final fake = FakeMlrsNetworkController();
|
||||||
|
final transport = await connectWithFake(fake);
|
||||||
|
|
||||||
|
await transport.send(Uint8List.fromList([1, 2, 3]));
|
||||||
|
|
||||||
|
expect(fake.sentPackets, hasLength(1));
|
||||||
|
expect(fake.sentPackets.single.host, '192.168.4.55');
|
||||||
|
|
||||||
|
transport.dispose();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
test('send() forwards bytes to the learned peer via the native socket',
|
test('send() forwards bytes to the learned peer via the native socket',
|
||||||
() async {
|
() async {
|
||||||
final fake = FakeMlrsNetworkController();
|
final fake = FakeMlrsNetworkController();
|
||||||
|
|||||||
Reference in New Issue
Block a user