Skip to content

Commit 3d08723

Browse files
committed
LiveLink release v1.0
1 parent 48afe74 commit 3d08723

13 files changed

Lines changed: 311 additions & 61 deletions

File tree

COM3D2.LiveLink.sln

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CM3D2.Serialization", "..\C
1818
EndProject
1919
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CM3D2.Serialization.Tests", "..\CM3D2.Serialization\CM3D2.Serialization.Tests\CM3D2.Serialization.Tests.csproj", "{3A4C2284-D50C-4F0F-A6E3-9303B423595D}"
2020
EndProject
21+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B0235D70-D8D6-4AF7-8D1F-25DD22CC681C}"
22+
ProjectSection(SolutionItems) = preProject
23+
README.md = README.md
24+
EndProjectSection
25+
EndProject
2126
Global
2227
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2328
Debug|Any CPU = Debug|Any CPU

LiveLink.CLI/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("0.1.*")]
36-
[assembly: AssemblyFileVersion("1.0.0.0")]
35+
[assembly: AssemblyVersion("1.0.*")]
36+
[assembly: AssemblyFileVersion("1.0")]

LiveLink.Plugin/LiveLinkPlugin.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
// This is the major & minor version with an asterisk (*) appended to auto increment numbers.
2525
[assembly: AssemblyVersion(COM3D2.LiveLink.Plugin.PluginInfo.PLUGIN_VERSION + ".*")]
26-
[assembly: AssemblyFileVersion(COM3D2.LiveLink.Plugin.PluginInfo.PLUGIN_VERSION + ".0.0")]
26+
[assembly: AssemblyFileVersion(COM3D2.LiveLink.Plugin.PluginInfo.PLUGIN_VERSION)]
2727

2828
// These two lines tell the compiler not worry about accessing private variables/classes.
2929
[module: UnverifiableCode]
@@ -39,7 +39,7 @@ public static class PluginInfo
3939
// The name of this plugin.
4040
public const string PLUGIN_NAME = "LiveLink";
4141
// The version of this plugin.
42-
public const string PLUGIN_VERSION = "0.1";
42+
public const string PLUGIN_VERSION = "1.0";
4343
}
4444
}
4545

@@ -124,7 +124,12 @@ private void Update()
124124
}
125125
else if (m_Core.IsConnected && m_DisconnectShortcut.IsDown())
126126
{
127-
DisconnectClient();
127+
GameMain.Instance.SysDlg.Show(
128+
"⚠️ WARNING ⚠️\n" +
129+
"Disconnecting client may crash the server, the client, or both. " +
130+
"This action is only safe if the server is already disconnected.\n\n" +
131+
"Are you sure you want to try disconnecting?",
132+
SystemDialog.TYPE.YES_NO, DisconnectClient);
128133
}
129134
}
130135
}

LiveLink.Tests/LiveLinkTestBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static LiveLinkCore CreateServer()
1919
string address = GetProcessUniqueAddress();
2020
LiveLinkCore serverCore = new LiveLinkCore();
2121
serverCore.StartServer(address);
22-
Console.WriteLine($"address = {serverCore.Address}");
22+
//Console.WriteLine($"address = {serverCore.Address}");
2323
return serverCore;
2424
}
2525

LiveLink.Tests/TestCore.cs

Lines changed: 122 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using System.Diagnostics;
44
using System.IO;
55
using System.Collections.Concurrent;
6+
using System.Threading;
7+
using System.Threading.Tasks;
68

79
namespace COM3D2.LiveLink.Tests
810
{
@@ -70,27 +72,29 @@ public int StopCLIProcess(Process cliProcess)
7072
return cliProcess.ExitCode;
7173
}
7274

73-
public void StartClientCoreAndServerCLI(out LiveLinkCore clientCore, out Process serverCLI)
75+
public void StartClientCoreAndServerCLI(out LiveLinkCore clientCore, out Process serverCLI, out string address)
7476
{
75-
serverCLI = CreateServerProcess(out string address);
77+
serverCLI = CreateServerProcess(out address);
7678
Console.WriteLine($"address = {address}");
7779

7880
clientCore = new LiveLinkCore();
7981
Assert.IsTrue(clientCore.StartClient(address), "Failed to connect client to server.");
80-
clientCore.WaitForConnection();
8182

8283
serverCLI.StandardInput.WriteLine($"waitfor --connection --time 1");
8384
Assert.IsTrue(clientCore.IsConnected);
8485
}
8586

87+
public void StartClientCoreAndServerCLI(out LiveLinkCore clientCore, out Process serverCLI)
88+
{
89+
StartClientCoreAndServerCLI(out clientCore, out serverCLI, out string address);
90+
}
91+
8692
public void StartServerCoreAndClientCLI(out LiveLinkCore serverCore, out Process clientCLI)
8793
{
8894
serverCore = CreateServer();
8995
clientCLI = CreateClientProcess(serverCore.Address);
9096

91-
serverCore.WaitForConnection(1000);
92-
93-
Assert.IsTrue(serverCore.IsConnected);
97+
Assert.IsTrue(serverCore.WaitForConnection(1000), "Client did not connect to server.");
9498
}
9599

96100
[TestMethod]
@@ -104,7 +108,7 @@ public void TestClientCLI()
104108
int exitCode = -1;
105109
try
106110
{
107-
serverCore.WaitForConnection();
111+
serverCore.WaitForConnection(1000);
108112
serverCore.SendString(testString);
109113
serverCore.Flush();
110114

@@ -223,6 +227,34 @@ public void TestClientNoReadBlock()
223227
AssertContains(output, testString);
224228
}
225229

230+
[TestMethod]
231+
public void TestServerWaitForConnectionTimeout()
232+
{
233+
LiveLinkCore serverCore = CreateServer();
234+
235+
var task = Task.Run(() => serverCore.WaitForConnection(10));
236+
Assert.IsTrue(task.Wait(20));
237+
}
238+
239+
[TestMethod]
240+
public void TestServerListenForConnection()
241+
{
242+
LiveLinkCore serverCore = CreateServer();
243+
Process clientCLI = CreateClientProcess(serverCore.Address);
244+
245+
Thread.Sleep(1000);
246+
247+
try
248+
{
249+
Assert.IsTrue(serverCore.IsConnected, "serverCore.IsConnected = false");
250+
}
251+
finally
252+
{
253+
StopCLIProcess(clientCLI);
254+
}
255+
}
256+
257+
226258
[TestMethod]
227259
public void TestSendFile()
228260
{
@@ -275,14 +307,14 @@ public void TestFileCommand()
275307
serverCLI.StandardInput.WriteLine($"send --file {filePath}");
276308
serverCLI.StandardInput.WriteLine($"flush");
277309

278-
System.Threading.Thread.Sleep(100);
310+
Thread.Sleep(100);
279311

280312
bool recieved = clientCore.TryReadMessage(out MemoryStream message);
281313

282314
clientCore.Dispose();
283315
int exitCode = StopCLIProcess(serverCLI);
284316
Console.WriteLine("Server Output - - - - - - - - -");
285-
Console.Write(serverCLI.StandardOutput.ReadAllAvailable());
317+
Console.WriteLine(serverCLI.StandardOutput.ReadAllAvailable());
286318
Debug.Write(serverCLI.StandardError.ReadAllAvailable());
287319
Console.WriteLine("- - - - - - - - - - - - - - - -");
288320
Assert.That.ExitZero(serverCLI);
@@ -292,26 +324,29 @@ public void TestFileCommand()
292324
Assert.That.StreamsAreEqual(fileStream, message);
293325
}
294326
}
295-
296-
327+
297328
[TestMethod]
298-
public void TestServerCLIDisconnect()
329+
public void TestServerIsConnected()
299330
{
300-
StartClientCoreAndServerCLI(out LiveLinkCore clientCore, out Process serverCLI);
331+
StartServerCoreAndClientCLI(out LiveLinkCore serverCore, out Process clientCLI);
301332

302-
Console.WriteLine($"clientCore.IsConnected = {clientCore.IsConnected}");
333+
Console.WriteLine($"serverCore.IsConnected = {serverCore.IsConnected}");
303334

304-
serverCLI.StandardInput.WriteLine("disconnect");
335+
clientCLI.StandardInput.WriteLine("disconnect");
305336

306-
System.Threading.Thread.Sleep(100);
337+
Thread.Sleep(1000);
307338

308-
clientCore.ReadAll();
339+
Console.WriteLine("Client Output - - - - - - - - -");
340+
Console.WriteLine(clientCLI.StandardOutput.ReadAllAvailable());
341+
Console.WriteLine("- - - - - - - - - - - - - - - -");
342+
343+
StopCLIProcess(clientCLI);
344+
Assert.That.ExitZero(clientCLI);
345+
346+
Console.WriteLine($"serverCore.IsConnected = {serverCore.IsConnected}");
347+
Assert.IsFalse(serverCore.IsConnected, "serverCore.IsConnected is still still true.");
309348

310-
Console.WriteLine($"clientCore.IsConnected = {clientCore.IsConnected}");
311-
Assert.IsFalse(clientCore.IsConnected);
312349

313-
StopCLIProcess(serverCLI);
314-
Assert.That.ExitZero(serverCLI);
315350
}
316351

317352
[TestMethod]
@@ -326,7 +361,7 @@ public void TestServerCLIUnexpectedDisconnect()
326361
}
327362

328363
[TestMethod]
329-
public void TestServerCoreDisconnect()
364+
public void TestClientIsConnectedCLI()
330365
{
331366
StartServerCoreAndClientCLI(out LiveLinkCore serverCore, out Process clientCLI);
332367

@@ -348,6 +383,71 @@ public void TestServerCoreDisconnect()
348383
Assert.That.ExitZero(clientCLI);
349384
}
350385

386+
[TestMethod]
387+
public void TestServerCrashing()
388+
{
389+
StartClientCoreAndServerCLI(out LiveLinkCore clientCore, out Process serverCLI, out string address);
390+
391+
for (int i = 0; i < 1; i++)
392+
{
393+
Console.WriteLine($"Attempt {i}");
394+
395+
// Crash area
396+
serverCLI.StandardInput.WriteLine("disconnect");
397+
while (clientCore.IsConnected)
398+
{
399+
Thread.Sleep(0);
400+
}
401+
if (serverCLI.HasExited) break;
402+
403+
// Reconnect for next attempt
404+
clientCore.Disconnect();
405+
serverCLI.StandardInput.WriteLine($"start --server {address}");
406+
serverCLI.StandardInput.WriteLine($"waitfor --connection");
407+
408+
bool connected = false;
409+
for (int j = 0; j < 10; j++)
410+
{
411+
if (connected = clientCore.StartClient(address)) break;
412+
Thread.Sleep(0);
413+
}
414+
if (serverCLI.HasExited) break;
415+
Assert.IsTrue(connected, "Failed to connect client to server.");
416+
}
417+
StopCLIProcess(serverCLI);
418+
Assert.That.ExitZero(serverCLI);
419+
}
420+
421+
[TestMethod]
422+
public void TestClientCrashingCLI()
423+
{
424+
StartServerCoreAndClientCLI(out LiveLinkCore serverCore, out Process clientCLI);
425+
426+
for (int i = 0; i < 100; i++)
427+
{
428+
Console.WriteLine($"Attempt {i}");
429+
430+
// Crash area
431+
clientCLI.StandardInput.WriteLine("disconnect");
432+
int j = 0;
433+
while (serverCore.IsConnected && !clientCLI.HasExited)
434+
{
435+
if (j++ >= 300) break;
436+
Thread.Sleep(1);
437+
}
438+
if (clientCLI.HasExited) break;
439+
Assert.IsFalse(serverCore.IsConnected, "Client never disconnected");
440+
441+
// Reconnect for next attempt
442+
serverCore.Disconnect();
443+
serverCore.StartServer(serverCore.Address);
444+
clientCLI.StandardInput.WriteLine($"start --client {serverCore.Address}");
445+
Assert.IsTrue(serverCore.WaitForConnection(1000), "Client did not reconnect.");
446+
}
447+
StopCLIProcess(clientCLI);
448+
Assert.That.ExitZero(clientCLI);
449+
}
450+
351451

352452

353453
void AssertContains(string output, string mustContain)

LiveLink/ClientConnection.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ public static bool TryConnect(string serverName, string pipeName, out ClientConn
3535
m_ClientPipe = new NamedPipeClientStream(
3636
serverName,
3737
pipeName,
38-
PipeAccessRights.ReadData | PipeAccessRights.WriteAttributes,
39-
PipeOptions.Asynchronous,
38+
PipeAccessRights.Read | PipeAccessRights.Write | PipeAccessRights.Delete,
39+
PipeOptions.None,
4040
System.Security.Principal.TokenImpersonationLevel.None,
4141
HandleInheritability.None
4242
);
@@ -57,11 +57,15 @@ bool TryConnect(int timeout = 1000)
5757
{
5858
Console.Error.WriteLine($"Failed to connect to LiveLink server. (OS Error)\n{ex.Message}");
5959
}
60+
catch (IOException ex)
61+
{
62+
Console.Error.WriteLine($"Failed to connect to LiveLink server. (IO Error)\n{ex.Message}");
63+
}
6064

6165
if (m_ClientPipe.IsConnected)
6266
{
6367
Console.WriteLine("Connected to LiveLink server!");
64-
Console.WriteLine($"m_ClientPipe.ReadMode = {m_ClientPipe.ReadMode}");
68+
//Console.WriteLine($"m_ClientPipe.ReadMode = {m_ClientPipe.ReadMode}");
6569
Initialize();
6670
return true;
6771
}
@@ -141,6 +145,7 @@ protected override void OnDispose(bool disposing)
141145
if (disposing)
142146
{
143147
// Free managed resources
148+
Console.WriteLine("Closing client connection...");
144149
m_ClientPipe.Dispose();
145150
m_ClientPipe = null;
146151
m_InMessageQueue = null;

LiveLink/Concurrent/Concurrent.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.CodeDom;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace COM3D2.LiveLink.Concurrent
8+
{
9+
internal class Concurrent<T>
10+
where T : struct
11+
{
12+
public T Value
13+
{
14+
get { lock (m_ValueLock) return _value; }
15+
set { lock (m_ValueLock) _value = value; }
16+
}
17+
18+
private object m_ValueLock;
19+
private T _value;
20+
21+
public Concurrent(T value)
22+
{
23+
m_ValueLock = new object();
24+
_value = value;
25+
}
26+
27+
public static implicit operator T(Concurrent<T> x) => x.Value;
28+
29+
public override string ToString() => Value.ToString();
30+
public override bool Equals(object obj) => Value.Equals(obj);
31+
public override int GetHashCode() => Value.GetHashCode();
32+
}
33+
}

LiveLink/Connection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ internal abstract class Connection : IDisposable
1010
{
1111
protected abstract PipeStream Pipe { get; }
1212

13-
public bool IsConnected => Pipe != null && Pipe.IsConnected;
13+
public virtual bool IsConnected => Pipe != null && Pipe.IsConnected;
1414

1515
public abstract bool CanRead { get; }
1616
public abstract bool CanWrite { get; }

LiveLink/LiveLink.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
<WarningLevel>4</WarningLevel>
3434
<Prefer32Bit>false</Prefer32Bit>
3535
</PropertyGroup>
36+
<PropertyGroup>
37+
<SignAssembly>true</SignAssembly>
38+
</PropertyGroup>
3639
<ItemGroup>
3740
<Reference Include="System" />
3841
<Reference Include="System.Core" />
@@ -47,6 +50,7 @@
4750
</ItemGroup>
4851
<ItemGroup>
4952
<Compile Include="ClientConnection.cs" />
53+
<Compile Include="Concurrent\Concurrent.cs" />
5054
<Compile Include="Connection.cs" />
5155
<Compile Include="LiveLinkCore.cs" />
5256
<Compile Include="Properties\AssemblyInfo.cs" />

0 commit comments

Comments
 (0)