Skip to content

Commit 3f14439

Browse files
committed
add "dual mode" socket for possible fix ios problems.
1 parent 17acdd9 commit 3f14439

File tree

6 files changed

+95
-37
lines changed

6 files changed

+95
-37
lines changed

LibSample/BroadcastTest.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,11 @@ public void Run()
112112
//Server
113113
_serverListener = new ServerListener();
114114

115-
NetManager server = new NetManager(_serverListener);
116-
server.BroadcastReceiveEnabled = true;
115+
NetManager server = new NetManager(_serverListener)
116+
{
117+
BroadcastReceiveEnabled = true,
118+
IPv6Enabled = IPv6Mode.DualMode
119+
};
117120
if (!server.Start(9050))
118121
{
119122
Console.WriteLine("Server start failed");
@@ -129,7 +132,8 @@ public void Run()
129132
{
130133
UnconnectedMessagesEnabled = true,
131134
SimulateLatency = true,
132-
SimulationMaxLatency = 1500
135+
SimulationMaxLatency = 1500,
136+
IPv6Enabled = IPv6Mode.DualMode
133137
};
134138
_clientListener1.Client = client1;
135139
if (!client1.Start())
@@ -144,7 +148,8 @@ public void Run()
144148
{
145149
UnconnectedMessagesEnabled = true,
146150
SimulateLatency = true,
147-
SimulationMaxLatency = 1500
151+
SimulationMaxLatency = 1500,
152+
IPv6Enabled = IPv6Mode.DualMode
148153
};
149154

150155
_clientListener2.Client = client2;

LibSample/HolePunchServerTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,23 +122,23 @@ public void Run()
122122

123123
_c1 = new NetManager(clientListener)
124124
{
125-
IPv6Enabled = false,
125+
IPv6Enabled = IPv6Mode.DualMode,
126126
NatPunchEnabled = true
127127
};
128128
_c1.NatPunchModule.Init(natPunchListener1);
129129
_c1.Start();
130130

131131
_c2 = new NetManager(clientListener)
132132
{
133-
IPv6Enabled = false,
133+
IPv6Enabled = IPv6Mode.DualMode,
134134
NatPunchEnabled = true
135135
};
136136
_c2.NatPunchModule.Init(natPunchListener2);
137137
_c2.Start();
138138

139139
_puncher = new NetManager(clientListener)
140140
{
141-
IPv6Enabled = false,
141+
IPv6Enabled = IPv6Mode.DualMode,
142142
NatPunchEnabled = true
143143
};
144144
_puncher.Start(ServerPort);

LiteNetLib/NetManager.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010

1111
namespace LiteNetLib
1212
{
13+
public enum IPv6Mode
14+
{
15+
Disabled,
16+
SeparateSocket,
17+
DualMode
18+
}
19+
1320
public sealed class NetPacketReader : NetDataReader
1421
{
1522
private NetPacket _packet;
@@ -284,7 +291,7 @@ private struct IncomingData
284291
/// <summary>
285292
/// IPv6 support
286293
/// </summary>
287-
public bool IPv6Enabled = true;
294+
public IPv6Mode IPv6Enabled = IPv6Mode.SeparateSocket;
288295

289296
/// <summary>
290297
/// First peer. Useful for Client mode

LiteNetLib/NetSocket.cs

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class UnitySocketFix : MonoBehaviour
2121
internal IPAddress BindAddrIPv4;
2222
internal IPAddress BindAddrIPv6;
2323
internal bool Reuse;
24-
internal bool IPv6;
24+
internal IPv6Mode IPv6;
2525
internal int Port;
2626
internal bool Paused;
2727
internal NetSocket Socket;
@@ -68,7 +68,7 @@ internal sealed class NetSocket
6868
private Thread _threadv6;
6969
private readonly INetSocketListener _listener;
7070
private const int SioUdpConnreset = -1744830452; //SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12
71-
private static readonly IPAddress MulticastAddressV6 = IPAddress.Parse("FF02:0:0:0:0:0:0:1");
71+
private static readonly IPAddress MulticastAddressV6 = IPAddress.Parse("ff02::1");
7272
internal static readonly bool IPv6Support;
7373
#if UNITY_IOS && !UNITY_EDITOR
7474
private UnitySocketFix _unitySocketFix;
@@ -84,8 +84,19 @@ public void OnErrorRestore()
8484

8585
public short Ttl
8686
{
87-
get { return _udpSocketv4.Ttl; }
88-
set { _udpSocketv4.Ttl = value; }
87+
get
88+
{
89+
if (_udpSocketv4.AddressFamily == AddressFamily.InterNetworkV6)
90+
return (short)_udpSocketv4.GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
91+
return _udpSocketv4.Ttl;
92+
}
93+
set
94+
{
95+
if (_udpSocketv4.AddressFamily == AddressFamily.InterNetworkV6)
96+
_udpSocketv4.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
97+
else
98+
_udpSocketv4.Ttl = value;
99+
}
89100
}
90101

91102
static NetSocket()
@@ -174,13 +185,18 @@ private void ReceiveLogic(object state)
174185
}
175186
}
176187

177-
public bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool reuseAddress, bool ipv6)
188+
public bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool reuseAddress, IPv6Mode ipv6Mode)
178189
{
179190
if (IsActive())
180191
return false;
192+
bool dualMode = ipv6Mode == IPv6Mode.DualMode && IPv6Support;
181193

182-
_udpSocketv4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
183-
if (!BindSocket(_udpSocketv4, new IPEndPoint(addressIPv4, port), reuseAddress))
194+
_udpSocketv4 = new Socket(
195+
dualMode ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork,
196+
SocketType.Dgram,
197+
ProtocolType.Udp);
198+
199+
if (!BindSocket(_udpSocketv4, new IPEndPoint(dualMode ? addressIPv6 : addressIPv4, port), reuseAddress, ipv6Mode))
184200
return false;
185201
#if UNITY_IOS && !UNITY_EDITOR
186202
if (_unitySocketFix == null)
@@ -193,11 +209,13 @@ public bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool re
193209
_unitySocketFix.BindAddrIPv6 = addressIPv6;
194210
_unitySocketFix.Reuse = reuseAddress;
195211
_unitySocketFix.Port = port;
196-
_unitySocketFix.IPv6 = ipv6;
212+
_unitySocketFix.IPv6 = ipv6Mode;
197213
}
198214
#endif
215+
if (dualMode)
216+
_udpSocketv6 = _udpSocketv4;
199217

200-
LocalPort = ((IPEndPoint)_udpSocketv4.LocalEndPoint).Port;
218+
LocalPort = ((IPEndPoint) _udpSocketv4.LocalEndPoint).Port;
201219
IsRunning = true;
202220
_threadv4 = new Thread(ReceiveLogic)
203221
{
@@ -207,27 +225,13 @@ public bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool re
207225
_threadv4.Start(_udpSocketv4);
208226

209227
//Check IPv6 support
210-
if (!IPv6Support || !ipv6)
228+
if (!IPv6Support || ipv6Mode != IPv6Mode.SeparateSocket)
211229
return true;
212230

213231
_udpSocketv6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
214232
//Use one port for two sockets
215-
if (BindSocket(_udpSocketv6, new IPEndPoint(addressIPv6, LocalPort), reuseAddress))
233+
if (BindSocket(_udpSocketv6, new IPEndPoint(addressIPv6, LocalPort), reuseAddress, ipv6Mode))
216234
{
217-
try
218-
{
219-
#if !UNITY
220-
_udpSocketv6.SetSocketOption(
221-
SocketOptionLevel.IPv6,
222-
SocketOptionName.AddMembership,
223-
new IPv6MulticastOption(MulticastAddressV6));
224-
#endif
225-
}
226-
catch (Exception)
227-
{
228-
// Unity3d throws exception - ignored
229-
}
230-
231235
_threadv6 = new Thread(ReceiveLogic)
232236
{
233237
Name = "SocketThreadv6(" + LocalPort + ")",
@@ -239,7 +243,7 @@ public bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool re
239243
return true;
240244
}
241245

242-
private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress)
246+
private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress, IPv6Mode ipv6Mode)
243247
{
244248
//Setup socket
245249
socket.ReceiveTimeout = 500;
@@ -271,7 +275,7 @@ private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress)
271275
}
272276
if (socket.AddressFamily == AddressFamily.InterNetwork)
273277
{
274-
socket.Ttl = NetConstants.SocketTTL;
278+
Ttl = NetConstants.SocketTTL;
275279

276280
#if NETSTANDARD || NETCOREAPP
277281
if(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
@@ -288,23 +292,57 @@ private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress)
288292
NetDebug.WriteError("[B]Broadcast error: {0}", e.SocketErrorCode);
289293
}
290294
}
295+
else //IPv6 specific
296+
{
297+
if (ipv6Mode == IPv6Mode.DualMode)
298+
{
299+
try
300+
{
301+
//Disable IPv6 only mode
302+
socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
303+
}
304+
catch(Exception e)
305+
{
306+
NetDebug.WriteError("[B]Bind exception (dualmode setting): {0}", e.ToString());
307+
}
308+
}
309+
}
291310

292311
//Bind
293312
try
294313
{
295314
socket.Bind(ep);
296315
NetDebug.Write(NetLogLevel.Trace, "[B]Successfully binded to port: {0}", ((IPEndPoint)socket.LocalEndPoint).Port);
316+
317+
//join multicast
318+
if (socket.AddressFamily == AddressFamily.InterNetworkV6)
319+
{
320+
try
321+
{
322+
#if !UNITY
323+
socket.SetSocketOption(
324+
SocketOptionLevel.IPv6,
325+
SocketOptionName.AddMembership,
326+
new IPv6MulticastOption(MulticastAddressV6));
327+
#endif
328+
}
329+
catch (Exception)
330+
{
331+
// Unity3d throws exception - ignored
332+
}
333+
}
297334
}
298335
catch (SocketException bindException)
299336
{
300337
switch (bindException.SocketErrorCode)
301338
{
302339
//IPv6 bind fix
303340
case SocketError.AddressAlreadyInUse:
304-
if (socket.AddressFamily == AddressFamily.InterNetworkV6)
341+
if (socket.AddressFamily == AddressFamily.InterNetworkV6 && ipv6Mode != IPv6Mode.DualMode)
305342
{
306343
try
307344
{
345+
//Set IPv6Only
308346
socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, true);
309347
socket.Bind(ep);
310348
}
@@ -412,6 +450,9 @@ public void Close(bool suspend)
412450
_unitySocketFix = null;
413451
#endif
414452
}
453+
//cleanup dual mode
454+
if (_udpSocketv4 == _udpSocketv6)
455+
_udpSocketv6 = null;
415456

416457
if (_udpSocketv4 != null)
417458
_udpSocketv4.Close();

LiteNetLib/Utils/NtpRequest.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ private NtpRequest(IPEndPoint endPoint, Action<NtpPacket> onRequestComplete)
3737

3838
// Create and start socket
3939
_socket = new NetSocket(this);
40-
_socket.Bind(IPAddress.Any, IPAddress.IPv6Any, 0, false, endPoint.AddressFamily == AddressFamily.InterNetworkV6);
40+
_socket.Bind(
41+
IPAddress.Any,
42+
IPAddress.IPv6Any,
43+
0,
44+
false,
45+
endPoint.AddressFamily == AddressFamily.InterNetworkV6 ? IPv6Mode.SeparateSocket : IPv6Mode.Disabled);
4146
}
4247

4348
/// <summary>
512 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)