Skip to content

Commit 76bc281

Browse files
committed
- CS 101 TCP client/server: improved connection handling
1 parent 8f9f194 commit 76bc281

File tree

6 files changed

+140
-31
lines changed

6 files changed

+140
-31
lines changed

examples/cs101-master-tcp/Program.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public static void Main (string[] args)
6262
running = false;
6363
};
6464

65-
string hostname = "localhost";
65+
string hostname = "127.0.0.1";
6666
int tcpPort = 2404;
6767

6868
if (args.Length > 0)
@@ -73,18 +73,18 @@ public static void Main (string[] args)
7373

7474
// Setup virtual serial port
7575
TcpClientVirtualSerialPort port = new TcpClientVirtualSerialPort(hostname, tcpPort);
76-
76+
port.DebugOutput = false;
7777
port.Start ();
7878

7979
// Setup balanced CS101 master
8080
LinkLayerParameters llParameters = new LinkLayerParameters();
8181
llParameters.AddressLength = 1;
82-
llParameters.UseSingleCharACK = false;
82+
llParameters.UseSingleCharACK = true;
8383

8484
CS101Master master = new CS101Master (port, LinkLayerMode.BALANCED, llParameters);
8585
master.DebugOutput = false;
8686
master.OwnAddress = 1;
87-
master.SlaveAddress = 2;
87+
master.SlaveAddress = 3;
8888
master.SetASDUReceivedHandler (asduReceivedHandler, null);
8989
master.SetLinkLayerStateChangedHandler (linkLayerStateChanged, null);
9090
master.SetReceivedRawMessageHandler (rcvdRawMessageHandler, null);

examples/cs101-slave-balanced/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
using lib60870.CS101;
2727
using System.Collections.Generic;
2828
using lib60870.linklayer;
29+
using System.Threading;
2930

3031
namespace cs101_slave_balanced
3132
{
@@ -163,6 +164,8 @@ public static void Main (string[] args)
163164
slave.EnqueueUserDataClass1 (newAsdu);
164165
}
165166
}
167+
168+
Thread.Sleep(1);
166169
}
167170

168171
}

examples/cs101-slave-tcp/Program.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
using lib60870.CS101;
2727
using System.Collections.Generic;
2828
using lib60870.linklayer;
29+
using System.Threading;
2930

3031
namespace cs101_slave_tcp
3132
{
@@ -93,8 +94,8 @@ public static void Main (string[] args)
9394

9495
CS101Slave slave = new CS101Slave (port, llParameters);
9596
slave.DebugOutput = true;
96-
slave.LinkLayerAddress = 1;
97-
slave.LinkLayerAddressOtherStation = 3;
97+
slave.LinkLayerAddress = 3;
98+
slave.LinkLayerAddressOtherStation = 1;
9899

99100
slave.LinkLayerMode = lib60870.linklayer.LinkLayerMode.BALANCED;
100101

@@ -157,6 +158,8 @@ public static void Main (string[] args)
157158
slave.EnqueueUserDataClass1 (newAsdu);
158159
}
159160
}
161+
162+
Thread.Sleep(1);
160163
}
161164

162165
port.Stop ();

lib60870/LinkLayer/LinkLayer.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,6 @@ public void HandleMessageBalancedAndPrimaryUnbalanced(byte[] msg, int msgSize)
665665

666666
}
667667

668-
669668
void HandleMessageAction(byte[] msg, int msgSize)
670669
{
671670
DebugLog ("RECV " + BitConverter.ToString (msg, 0, msgSize));
@@ -690,8 +689,7 @@ void HandleMessageAction(byte[] msg, int msgSize)
690689
} else
691690
DebugLog ("Message ignored because of raw message handler");
692691
}
693-
694-
692+
695693
public void Run()
696694
{
697695
transceiver.ReadNextMessage (buffer, HandleMessageAction);
@@ -700,7 +698,6 @@ public void Run()
700698
primaryLinkLayer.RunStateMachine ();
701699
secondaryLinkLayer.RunStateMachine ();
702700
} else {
703-
//TODO avoid redirection by LinkLayer class
704701
if (primaryLinkLayer != null)
705702
primaryLinkLayer.RunStateMachine ();
706703
else if (secondaryLinkLayer != null)

lib60870/LinkLayer/TcpClientVirtualSerialPort.cs

Lines changed: 92 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828

2929
namespace lib60870.linklayer
3030
{
31+
32+
/// <summary>
33+
/// TCP client virtual serial port. Can be used to tunnel CS 101 protocol over TCP/IP.
34+
/// </summary>
3135
public class TcpClientVirtualSerialPort : Stream
3236
{
3337
private int readTimeout = 0;
@@ -54,6 +58,17 @@ private void DebugLog(string msg)
5458
}
5559
}
5660

61+
62+
/// <summary>
63+
/// Gets a value indicating whether this <see cref="lib60870.linklayer.TcpClientVirtualSerialPort"/> is connected to a server
64+
/// </summary>
65+
/// <value><c>true</c> if connected; otherwise, <c>false</c>.</value>
66+
public bool Connected {
67+
get {
68+
return this.connected;
69+
}
70+
}
71+
5772
public bool DebugOutput {
5873
get {
5974
return this.debugOutput;
@@ -63,6 +78,11 @@ public bool DebugOutput {
6378
}
6479
}
6580

81+
/// <summary>
82+
/// Initializes a new instance of the <see cref="lib60870.linklayer.TcpClientVirtualSerialPort"/> class.
83+
/// </summary>
84+
/// <param name="hostname">IP address of the server</param>
85+
/// <param name="tcpPort">TCP port of the server</param>
6686
public TcpClientVirtualSerialPort(String hostname, int tcpPort = 2404)
6787
{
6888
this.hostname = hostname;
@@ -84,18 +104,22 @@ private void ConnectSocketWithTimeout()
84104
throw new SocketException(87); // wrong argument
85105
}
86106

107+
if (!running)
108+
return;
109+
87110
// Create a TCP/IP socket.
88111
conSocket = new Socket(AddressFamily.InterNetwork,
89112
SocketType.Stream, ProtocolType.Tcp);
90113

91114
var result = conSocket.BeginConnect(remoteEP, null, null);
92115

93-
bool success = result.AsyncWaitHandle.WaitOne(connectTimeoutInMs, true);
94-
if (success)
95-
{
96-
try
97-
{
98-
conSocket.EndConnect(result);
116+
if (!running)
117+
return;
118+
119+
bool success = result.AsyncWaitHandle.WaitOne (connectTimeoutInMs, true);
120+
if (success) {
121+
try {
122+
conSocket.EndConnect (result);
99123
conSocket.NoDelay = true;
100124
}
101125
catch (ObjectDisposedException)
@@ -138,24 +162,46 @@ private void ConnectionThread()
138162
if (conSocket.Connected == false)
139163
break;
140164

165+
if (running == false)
166+
break;
167+
141168
Thread.Sleep(10);
142169
}
143170

144-
connected = false;
145-
socketStream = null;
146-
conSocket.Close();
147-
conSocket = null;
171+
connected = false;
172+
173+
if (!this.running)
174+
return;
175+
176+
if (socketStream != null) {
177+
socketStream.Close();
178+
conSocket.Dispose();
179+
socketStream = null;
180+
}
181+
182+
183+
if (conSocket != null) {
184+
conSocket.Close();
185+
conSocket.Dispose();
186+
conSocket = null;
187+
188+
}
148189

149-
} catch (SocketException) {
190+
} catch (SocketException e) {
191+
DebugLog("Failed to connect: " + e.Message);
150192
connected = false;
151193
socketStream = null;
152194
conSocket = null;
153195
}
154196

155-
Thread.Sleep (waitRetryConnect);
197+
if (running)
198+
Thread.Sleep (waitRetryConnect);
156199
}
157200
}
158201

202+
/// <summary>
203+
/// Start the virtual serial port (connect to server)
204+
/// </summary>
159205
public void Start()
160206
{
161207
if (running == false) {
@@ -165,14 +211,33 @@ public void Start()
165211
}
166212
}
167213

168-
214+
/// <summary>
215+
/// Stop the virtual serial port
216+
/// </summary>
169217
public void Stop()
170218
{
171219
if (running == true) {
172220
running = false;
221+
this.connected = false;
222+
223+
if (socketStream != null) {
224+
socketStream.Close ();
225+
socketStream.Dispose ();
226+
socketStream = null;
227+
}
228+
229+
if (conSocket != null) {
230+
231+
try {
232+
conSocket.Shutdown(SocketShutdown.Both);
233+
}
234+
catch (SocketException) {
235+
}
173236

174-
if (conSocket != null)
175237
conSocket.Close ();
238+
conSocket.Dispose();
239+
conSocket = null;
240+
}
176241

177242
connectionThread.Join ();
178243
}
@@ -187,13 +252,21 @@ public override int Read (byte[] buffer, int offset, int count)
187252
{
188253
if (socketStream != null) {
189254

190-
if (conSocket.Poll (ReadTimeout, SelectMode.SelectRead)) {
191-
if (connected)
192-
return socketStream.Read (buffer, offset, count);
193-
else
255+
try {
256+
if (conSocket.Poll (ReadTimeout, SelectMode.SelectRead)) {
257+
if (connected)
258+
return socketStream.Read (buffer, offset, count);
259+
else
260+
return 0;
261+
} else
194262
return 0;
195-
} else
263+
}
264+
catch (Exception e) {
265+
Console.WriteLine (e.ToString ());
266+
this.connected = false;
196267
return 0;
268+
}
269+
197270
}
198271
else
199272
return 0;

lib60870/LinkLayer/TcpServerVirtualSerialPort.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@
2828

2929
namespace lib60870.linklayer
3030
{
31+
32+
/// <summary>
33+
/// Connection event handler. Can be used to track connections and accept/deny specific clients.
34+
/// </summary>
35+
/// <param name="parameter">User provided paramter</param>
36+
/// <param name="ipAddress">IP address of the client</param>
37+
/// <param name="connect">true when client is connecting, false when disconnected</param>
38+
/// <returns>true when connection is accepted, false otherwise</returns>
39+
public delegate bool TcpConnectionEventHandler(object parameter, IPAddress ipAddress, bool connect);
40+
3141
public class TcpServerVirtualSerialPort : Stream
3242
{
3343
private int readTimeout = 0;
@@ -44,6 +54,9 @@ public class TcpServerVirtualSerialPort : Stream
4454
Stream socketStream = null;
4555
Thread acceptThread;
4656

57+
TcpConnectionEventHandler connectionEventHandler = null;
58+
object connectionEventHandlerParameter;
59+
4760
private void DebugLog(string msg)
4861
{
4962
if (debugOutput) {
@@ -65,6 +78,16 @@ public TcpServerVirtualSerialPort()
6578
{
6679
}
6780

81+
public void SetConnectionRequestHandler(TcpConnectionEventHandler handler, object parameter)
82+
{
83+
this.connectionEventHandler = handler;
84+
this.connectionEventHandlerParameter = parameter;
85+
}
86+
87+
/// <summary>
88+
/// Sets the local address to used
89+
/// </summary>
90+
/// <param name="localAddress">Local address. Use "0.0.0.0" for all interfaces(default)</param>
6891
public void SetLocalAddress(string localAddress)
6992
{
7093
localHostname = localAddress;
@@ -96,6 +119,9 @@ private void ServerAcceptThread()
96119

97120
bool acceptConnection = true;
98121

122+
if (connectionEventHandler != null)
123+
acceptConnection = connectionEventHandler(connectionEventHandlerParameter, ipEndPoint.Address, true);
124+
99125
if (acceptConnection) {
100126

101127
conSocket = newSocket;
@@ -111,10 +137,16 @@ private void ServerAcceptThread()
111137
}
112138

113139
connected = false;
140+
141+
if (connectionEventHandler != null)
142+
connectionEventHandler(connectionEventHandlerParameter, ipEndPoint.Address, false);
143+
144+
socketStream.Close();
114145
socketStream = null;
146+
conSocket.Close();
115147
conSocket = null;
116148

117-
DebugLog("Connection from " + ipEndPoint.Address.ToString() + "closed");
149+
DebugLog("Connection from " + ipEndPoint.Address.ToString() + " closed");
118150
}
119151
else
120152
newSocket.Close();
@@ -139,7 +171,7 @@ public void Start()
139171

140172
listeningSocket.Bind (localEP);
141173

142-
listeningSocket.Listen (100);
174+
listeningSocket.Listen (1);
143175

144176
acceptThread = new Thread (ServerAcceptThread);
145177

@@ -151,6 +183,7 @@ public void Stop()
151183
{
152184
if (running == true) {
153185
running = false;
186+
connected = false;
154187
listeningSocket.Close ();
155188

156189
acceptThread.Join ();

0 commit comments

Comments
 (0)