worked on error handling of network protocols,

updated remote endpoint indication in UI
master
Jonas Arnold 3 years ago
parent 9ae494e2e7
commit 6b07d1bb3c
  1. 7
      MultiTerm.Protocols/CommunicationProtocol.cs
  2. 35
      MultiTerm.Protocols/Tcp/TcpClientProtocol.cs
  3. 11
      MultiTerm.Protocols/Udp/UdpProtocol.cs
  4. 6
      MultiTerm.Wpf/View/SettingsView/NetworkSettingsView.xaml

@ -60,7 +60,7 @@ public abstract class CommunicationProtocol : ICommunicationProtocol
/// <summary> /// <summary>
/// To be called whenever the protocol detected that it is disconnected, but this is not a known fact. /// To be called whenever the protocol detected that it is disconnected, but this is not a known fact.
/// </summary> /// </summary>
protected void OnUnintentionallyDisconnected() protected void OnUnintentionallyDisconnected(bool informUser = true)
{ {
// perform all steps in a task, to prevent deadlock when this method is called from a thread that is joined. // perform all steps in a task, to prevent deadlock when this method is called from a thread that is joined.
Task.Run(() => Task.Run(() =>
@ -72,7 +72,10 @@ public abstract class CommunicationProtocol : ICommunicationProtocol
this.State = ProtocolConnectionState.UnintentionallyDisconnected; this.State = ProtocolConnectionState.UnintentionallyDisconnected;
// inform user // inform user
this.messenger.Send<IUserInterfaceMessage>(new GenericUserInterfaceMessage($"'{this.GetProtocolAndInstanceIdentifier()}' unintentionally disconnected.", MessageImportance.High)); if (informUser)
{
this.messenger.Send<IUserInterfaceMessage>(new GenericUserInterfaceMessage($"'{this.GetProtocolAndInstanceIdentifier()}' unintentionally disconnected.", MessageImportance.High));
}
}); });
} }

@ -47,7 +47,8 @@ public class TcpClientProtocol : CommunicationProtocol
// check if client is null // check if client is null
if (this.client != null) if (this.client != null)
{ {
throw new Exception($"The TCP client was not null when {nameof(InternalConnect)} was called."); this.client = null;
this.logger.LogWarn($"The TCP client was not null when {nameof(InternalConnect)} was called.", nameof(TcpClientProtocol));
} }
/* create client */ /* create client */
@ -73,7 +74,14 @@ public class TcpClientProtocol : CommunicationProtocol
// send message to inform about resolved IP address // send message to inform about resolved IP address
if (this.client.Client.RemoteEndPoint is IPEndPoint remoteEndpoint) if (this.client.Client.RemoteEndPoint is IPEndPoint remoteEndpoint)
{ {
this.messenger.Send(new TcpConnectedMessage(remoteEndpoint.Address)); IPAddress remoteEndpointAddress = remoteEndpoint.Address;
// special handling for IPv4MappedToIPv6 addresses
if (remoteEndpointAddress.IsIPv4MappedToIPv6)
{
remoteEndpointAddress = remoteEndpoint.Address.MapToIPv4();
}
this.messenger.Send(new TcpConnectedMessage(remoteEndpointAddress));
} }
return true; return true;
@ -128,25 +136,30 @@ public class TcpClientProtocol : CommunicationProtocol
catch (ObjectDisposedException objex) catch (ObjectDisposedException objex)
{ {
this.logger.LogException(objex, $"ObjectDisposedException while sending data in {nameof(InternalRead)}", nameof(TcpClientProtocol)); this.logger.LogException(objex, $"ObjectDisposedException while sending data in {nameof(InternalRead)}", nameof(TcpClientProtocol));
this.OnUnintentionallyDisconnected(); this.OnUnintentionallyDisconnected(informUser: true);
break; // break loop break; // break loop
} }
catch (IOException ioEx) catch (IOException ioEx) when (ioEx.InnerException is SocketException sockEx)
{ {
// socket exception and timeout => normal use case // socket exception timeout => normal use case => do nothing
if (ioEx.InnerException is SocketException sockEx && sockEx?.SocketErrorCode == SocketError.TimedOut) { } if (sockEx.SocketErrorCode != SocketError.TimedOut)
// other IO Exception
else
{ {
this.logger.LogException(ioEx, $"IOException while reading data in {nameof(InternalRead)}", nameof(TcpClientProtocol)); this.logger.LogException(sockEx, $"SocketException with SocketErrorCode={sockEx.SocketErrorCode} while reading data in {nameof(InternalRead)}", nameof(TcpClientProtocol));
this.messenger.Send<IUserInterfaceMessage>(new StoppedReadingUIMessage(this, ioEx.ToString())); this.messenger.Send<IUserInterfaceMessage>(new StoppedReadingUIMessage(this, $"Socket Error: {sockEx.SocketErrorCode}"));
this.OnUnintentionallyDisconnected(informUser: false);
break; // break loop break; // break loop
} }
} }
catch (IOException ioEx)
{
this.logger.LogException(ioEx, $"IOException while reading data in {nameof(InternalRead)}", nameof(TcpClientProtocol));
this.OnUnintentionallyDisconnected(informUser: true);
break; // break loop
}
catch (Exception ex) catch (Exception ex)
{ {
this.logger.LogException(ex, $"Exception while reading data in {nameof(InternalRead)}", nameof(TcpClientProtocol)); this.logger.LogException(ex, $"Exception while reading data in {nameof(InternalRead)}", nameof(TcpClientProtocol));
this.messenger.Send<IUserInterfaceMessage>(new StoppedReadingUIMessage(this, ex.Message)); this.OnUnintentionallyDisconnected(informUser: true);
break; // break loop break; // break loop
} }

@ -45,8 +45,9 @@ public class UdpProtocol : CommunicationProtocol
// check if client is null // check if client is null
if(this.udpClient != null) if(this.udpClient != null)
{ {
throw new Exception($"UDP client was not null when {nameof(InternalConnect)} was called: " + this.udpClient = null;
$"{nameof(udpClient)} isnull={this.udpClient == null},"); this.logger.LogWarn($"UDP client was not null when {nameof(InternalConnect)} was called: " +
$"{nameof(udpClient)} isnull={this.udpClient == null}", nameof(UdpProtocol));
} }
/* create udp client */ /* create udp client */
@ -135,6 +136,12 @@ public class UdpProtocol : CommunicationProtocol
// report received data // report received data
this.OnReceivedData(new ExtendedByte(b)); this.OnReceivedData(new ExtendedByte(b));
} }
// after data was processed, send update with latest connected endpoint
if(remoteEndPoint != null)
{
this.messenger.Send(new UdpConnectedMessage(remoteEndPoint.Address));
}
} }
} }
} }

@ -50,21 +50,21 @@
</StackPanel> </StackPanel>
<!-- Display for Resolved IP Address (outside of Not changeable range) --> <!-- Display for Remote Endpoint Address (outside of Not changeable range) -->
<StackPanel Orientation="Horizontal" Margin="20 0 10 0"> <StackPanel Orientation="Horizontal" Margin="20 0 10 0">
<StackPanel.Style> <StackPanel.Style>
<Style TargetType="{x:Type StackPanel}"> <Style TargetType="{x:Type StackPanel}">
<!-- Defaults to visible --> <!-- Defaults to visible -->
<Setter Property="Visibility" Value="Visible"/> <Setter Property="Visibility" Value="Visible"/>
<Style.Triggers> <Style.Triggers>
<!-- Collapsed when Resolved Address String length is 0 --> <!-- Collapsed when Remote Endpoint String length is 0 -->
<DataTrigger Binding="{Binding Path=ResolvedAddress.Length, FallbackValue=0, TargetNullValue=0}" Value="0"> <DataTrigger Binding="{Binding Path=ResolvedAddress.Length, FallbackValue=0, TargetNullValue=0}" Value="0">
<Setter Property="Visibility" Value="Collapsed"/> <Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
</StackPanel.Style> </StackPanel.Style>
<Label Margin="20 0 10 0" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="DarkGray">Resolved IP Address:</Label> <Label Margin="20 0 10 0" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="DarkGray">Remote Endpoint:</Label>
<TextBox IsReadOnly="True" VerticalContentAlignment="Center" Text="{Binding ResolvedAddress}"/> <TextBox IsReadOnly="True" VerticalContentAlignment="Center" Text="{Binding ResolvedAddress}"/>
</StackPanel> </StackPanel>

Loading…
Cancel
Save