Skip to content

Commit 9017803

Browse files
committed
Initial commit
0 parents  commit 9017803

22 files changed

+2281
-0
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.user
2+
.idea/
3+
bin
4+
obj

DemoLoginServer/AsyncSocket.cs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.Net.Sockets;
2+
using System.Threading.Tasks;
3+
4+
namespace DemoLoginServer
5+
{
6+
/// <summary>
7+
/// Wrapper for Socket that provides awaitable asynchronous methods.
8+
/// </summary>
9+
public class AsyncSocket
10+
{
11+
private readonly Socket _socket;
12+
13+
public AsyncSocket(Socket socket)
14+
{
15+
_socket = socket;
16+
}
17+
18+
public Task<int> Send(byte[] buffer)
19+
{
20+
return Send(buffer, 0, buffer.Length);
21+
}
22+
23+
public Task<int> Send(byte[] buffer, int offset, int size)
24+
{
25+
return Task.Factory.FromAsync(
26+
_socket.BeginSend(buffer, offset, size, SocketFlags.None, null, _socket),
27+
_socket.EndSend);
28+
}
29+
30+
public Task<int> Receive(byte[] buffer)
31+
{
32+
return Receive(buffer, 0, buffer.Length);
33+
}
34+
35+
public Task<int> Receive(byte[] buffer, int offset, int size)
36+
{
37+
return Task.Factory.FromAsync(
38+
_socket.BeginReceive(buffer, offset, size, SocketFlags.None, null, _socket),
39+
_socket.EndSend);
40+
}
41+
}
42+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.1</TargetFramework>
6+
<AssemblyName>DemoLoginServer</AssemblyName>
7+
<RootNamespace>DemoLoginServer</RootNamespace>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<ProjectReference Include="..\PangCrypt\PangCrypt.csproj" />
12+
</ItemGroup>
13+
14+
</Project>

DemoLoginServer/Extensions.cs

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System;
2+
using System.IO;
3+
using System.Text;
4+
5+
namespace DemoLoginServer
6+
{
7+
public static class BinaryReaderExtensions
8+
{
9+
/// <summary>
10+
/// Reads a fixed-length string from the stream.
11+
/// </summary>
12+
/// <param name="reader">BinaryReader to use.</param>
13+
/// <param name="length">Length of string in bytes.</param>
14+
/// <param name="encoding">Encoding to use.</param>
15+
/// <returns></returns>
16+
public static string ReadFixedString(this BinaryReader reader, int length, Encoding encoding)
17+
{
18+
var bytes = reader.ReadBytes(length);
19+
for (var i = bytes.Length - 1; i >= 0; i--)
20+
if (bytes[i] != 0)
21+
Array.Resize(ref bytes, i + 1);
22+
return new string(encoding.GetChars(bytes));
23+
}
24+
25+
/// <summary>
26+
/// Reads a Pascal-style length-prefix string, stored as a Uint16
27+
/// followed by a string.
28+
/// </summary>
29+
/// <param name="reader">BinaryReader to use.</param>
30+
/// <param name="encoding"></param>
31+
/// <returns></returns>
32+
public static string ReadPString(this BinaryReader reader, Encoding encoding)
33+
{
34+
var messageLength = reader.ReadUInt16();
35+
return new string(encoding.GetChars(reader.ReadBytes(messageLength)));
36+
}
37+
}
38+
39+
public static class BinaryWriterExtensions
40+
{
41+
/// <summary>
42+
/// Writes a fixed-length string to the stream.
43+
/// </summary>
44+
/// <param name="writer">BinaryWriter to use.</param>
45+
/// <param name="str">String to write.</param>
46+
/// <param name="length">Length of string in bytes.</param>
47+
/// <param name="encoding">Encoding to use.</param>
48+
public static void WriteFixedString(this BinaryWriter writer, string str, int length, Encoding encoding)
49+
{
50+
var bytes = encoding.GetBytes(str);
51+
Array.Resize(ref bytes, length);
52+
writer.Write(bytes);
53+
}
54+
55+
/// <summary>
56+
/// Writes a Pascal-style length-prefix string, stored as a Uint16
57+
/// followed by a string.
58+
/// </summary>
59+
/// <param name="writer">BinaryWriter to use.</param>
60+
/// <param name="str">String to write.</param>
61+
/// <param name="encoding">Encoding to use.</param>
62+
public static void WritePString(this BinaryWriter writer, string str, Encoding encoding)
63+
{
64+
var bytes = encoding.GetBytes(str);
65+
writer.Write((ushort) bytes.Length);
66+
writer.Write(bytes);
67+
}
68+
}
69+
}

DemoLoginServer/LoginMessages.cs

+183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
using System.Diagnostics;
2+
using System.IO;
3+
using System.Text;
4+
5+
namespace DemoLoginServer
6+
{
7+
public class LoginMessages
8+
{
9+
// Note: PangYa does not use UTF-8.
10+
public static readonly Encoding StringEncoding = Encoding.UTF8;
11+
12+
public interface IMessage
13+
{
14+
byte[] ToBytes();
15+
}
16+
17+
public struct ClientLoginMessage : IMessage
18+
{
19+
public const ushort MessageId = 0x0001;
20+
21+
public readonly string Username;
22+
public readonly string Password;
23+
24+
public ClientLoginMessage(string username, string password)
25+
{
26+
Username = username;
27+
Password = password;
28+
}
29+
30+
public static ClientLoginMessage FromBytes(byte[] data)
31+
{
32+
using (var reader = new BinaryReader(new MemoryStream(data)))
33+
{
34+
Debug.Assert(reader.ReadUInt16() == MessageId);
35+
var username = reader.ReadPString(StringEncoding);
36+
var password = reader.ReadPString(StringEncoding);
37+
return new ClientLoginMessage(username, password);
38+
}
39+
}
40+
41+
public byte[] ToBytes()
42+
{
43+
var stream = new MemoryStream();
44+
45+
using (var writer = new BinaryWriter(stream))
46+
{
47+
writer.Write(MessageId);
48+
writer.WritePString(Username, StringEncoding);
49+
writer.WritePString(Password, StringEncoding);
50+
}
51+
52+
return stream.GetBuffer();
53+
}
54+
}
55+
56+
public struct ServerSecurity1Message : IMessage
57+
{
58+
public const ushort MessageId = 0x0010;
59+
60+
public readonly string Token;
61+
62+
public ServerSecurity1Message(string token)
63+
{
64+
Token = token;
65+
}
66+
67+
public static ServerSecurity1Message FromBytes(byte[] data)
68+
{
69+
using (var reader = new BinaryReader(new MemoryStream(data)))
70+
{
71+
Debug.Assert(reader.ReadUInt16() == MessageId);
72+
return new ServerSecurity1Message(reader.ReadPString(StringEncoding));
73+
}
74+
}
75+
76+
public byte[] ToBytes()
77+
{
78+
var stream = new MemoryStream();
79+
80+
using (var writer = new BinaryWriter(stream))
81+
{
82+
writer.Write(MessageId);
83+
writer.WritePString(Token, StringEncoding);
84+
}
85+
86+
return stream.ToArray();
87+
}
88+
}
89+
90+
public struct ServerEntry
91+
{
92+
public readonly string ServerName;
93+
public readonly ushort ServerId;
94+
public readonly ushort NumUsers;
95+
public readonly ushort MaxUsers;
96+
public readonly string IpAddress;
97+
public readonly ushort Port;
98+
public readonly ushort Flags;
99+
100+
public ServerEntry(string serverName, ushort serverId, ushort numUsers, ushort maxUsers, string ipAddress,
101+
ushort port, ushort flags)
102+
{
103+
ServerName = serverName;
104+
ServerId = serverId;
105+
NumUsers = numUsers;
106+
MaxUsers = maxUsers;
107+
IpAddress = ipAddress;
108+
Port = port;
109+
Flags = flags;
110+
}
111+
112+
public static ServerEntry FromReader(BinaryReader reader)
113+
{
114+
var serverName = reader.ReadFixedString(40, StringEncoding);
115+
var serverId = reader.ReadUInt16();
116+
var numUsers = reader.ReadUInt16();
117+
var maxUsers = reader.ReadUInt16();
118+
reader.ReadUInt32();
119+
reader.ReadUInt16();
120+
var ipAddress = reader.ReadFixedString(18, StringEncoding);
121+
var port = reader.ReadUInt16();
122+
reader.ReadUInt16();
123+
var flags = reader.ReadUInt16();
124+
reader.ReadBytes(16);
125+
return new ServerEntry(serverName, serverId, numUsers, maxUsers, ipAddress, port, flags);
126+
}
127+
128+
public void ToWriter(BinaryWriter writer)
129+
{
130+
writer.WriteFixedString(ServerName, 40, StringEncoding);
131+
writer.Write(ServerId);
132+
writer.Write(NumUsers);
133+
writer.Write(MaxUsers);
134+
writer.Write((uint) 0);
135+
writer.Write((ushort) 0);
136+
writer.WriteFixedString(IpAddress, 18, StringEncoding);
137+
writer.Write(Port);
138+
writer.Write((ushort) 0);
139+
writer.Write(Flags);
140+
writer.Write(new byte[16]);
141+
}
142+
}
143+
144+
public struct ServerListMessage : IMessage
145+
{
146+
public const ushort MessageId = 0x0002;
147+
148+
public readonly ServerEntry[] Servers;
149+
150+
public ServerListMessage(ServerEntry[] servers)
151+
{
152+
Servers = servers;
153+
}
154+
155+
public static ServerListMessage FromBytes(byte[] data)
156+
{
157+
using (var reader = new BinaryReader(new MemoryStream(data)))
158+
{
159+
Debug.Assert(reader.ReadUInt16() == MessageId);
160+
var servers = new ServerEntry[reader.ReadByte()];
161+
for (var i = 0; i < servers.Length; i++)
162+
servers[i] = ServerEntry.FromReader(reader);
163+
return new ServerListMessage(servers);
164+
}
165+
}
166+
167+
public byte[] ToBytes()
168+
{
169+
var stream = new MemoryStream();
170+
171+
using (var writer = new BinaryWriter(stream))
172+
{
173+
writer.Write(MessageId);
174+
writer.Write((byte) Servers.Length);
175+
for (var i = 0; i < Servers.Length; i++)
176+
Servers[i].ToWriter(writer);
177+
}
178+
179+
return stream.ToArray();
180+
}
181+
}
182+
}
183+
}

DemoLoginServer/LoginServer.cs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Net;
4+
using System.Net.Sockets;
5+
using System.Threading.Tasks;
6+
7+
namespace DemoLoginServer
8+
{
9+
public class LoginServer
10+
{
11+
private const int SocketBacklog = 32;
12+
13+
[SuppressMessage("ReSharper", "FunctionNeverReturns")]
14+
public void Listen(int port)
15+
{
16+
var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
17+
listener.Bind(new IPEndPoint(IPAddress.Any, port));
18+
listener.Listen(SocketBacklog);
19+
20+
Console.WriteLine($"LoginServer listening for connections on {port}");
21+
while (true)
22+
{
23+
var socket = listener.Accept();
24+
Console.WriteLine($"Connection established: {socket.RemoteEndPoint}");
25+
Task.Run(() =>
26+
{
27+
try
28+
{
29+
var connection = new LoginServerConnection(new ServerSocket(new AsyncSocket(socket), 0));
30+
#pragma warning disable 4014
31+
connection.Handle();
32+
#pragma warning restore 4014
33+
}
34+
catch (Exception exception)
35+
{
36+
Console.WriteLine(exception.ToString());
37+
}
38+
});
39+
}
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)