To reiterate the problem, we're using the TNET sample menu included with the TNET package. On iOS with a device with both a WiFi and cell data network connection it will start up a server fine and will show up in the lobby list for all devices. However, when you try to connect to the server it starts using either itself or another device (that can see it in the lobby server) it will time out or not connect. This affects both iPhones and iPads have active cellular data networks when you use the cell data NIC. If you turn off the cell data network it will work fine, but asking users to do this in order to host a LAN game is not a desirable user experience.
We tested the same thing on an Android phone with Cell Data active (and WiFi disabled) and it doesn't have a problem hosting through the cell network. This leads us to believe that it might be a Mono bug with the iOS implementation.
A co-worker of mine was able to spend a significant amount of time trying to track down a problem. We determined a workaround for this problem but not the underlying problem.
He created a test script:
using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.Net;
using System.Threading;
public class TestScript : MonoBehaviour {
private int kListenPort = 5129;
private TcpListener _listener;
// Use this for initialization
void Start () {
StartCoroutine (CoroutineStartTest ());
}
private IEnumerator CoroutineStartTest() {
StartServer ();
yield return new WaitForSeconds
(1); ClientConnect
(new IPEndPoint
(TNet
.Tools.localAddress, kListenPort
)); //LOCAL ADDRESS[0] IS CELL DATA ClientConnect
(new IPEndPoint
(TNet
.Tools.localAddresses[1], kListenPort
)); //WILL WORK AS [1] IS WIFI }
private void StartServer() {
_listener
= new TcpListener
(IPAddress
.Any, kListenPort
); Debug.Log ("Starting listener...");
_listener.Start(5);
Thread thread
= new Thread
(ThreadFunc
); thread.Start ();
}
private void ThreadFunc() {
Debug.Log ("Starting Thread function...");
Socket socketConnect = null;
while (true) {
if (_listener.Pending()) {
socketConnect = _listener.AcceptSocket();
Debug.Log ("Socket Connection established: " + socketConnect.LocalEndPoint);
}
}
}
private void ClientConnect(IPEndPoint endPoint) {
if (endPoint != null) {
string error = "(None)";
try {
Debug.Log("Creating client socket...");
Socket socket
= new Socket
(AddressFamily
.InterNetwork, SocketType
.Stream, ProtocolType
.Tcp); Debug.Log("Connecting at " + endPoint + "...");
socket.Connect (endPoint);
} catch (System.Exception ex) {
error = ex.Message;
} finally {
Debug.Log("Finished Connect. Error: " + error);
}
}
}
}
It seems that there might be a iOS mono bug with connecting to a cell data's IP address, that goes into unmanaged code and becomes very difficult to track down.
The workaround that he came up with is the network interface type will return UNKNOWN for cell data, and we ignore all network interfaces with UNKNOWN so that we can make sure that we don't include the cell data IP in the list of local addresses. So to work around this problem we put this code into the TNTools.localAddresses property.
for (int i = 0; i < list.size; ++i)
{
NetworkInterface ni = list[i];
if (ni == null) continue;
IPInterfaceProperties props = ni.GetIPProperties();
if (props == null) continue;
if(ni.NetworkInterfaceType == NetworkInterfaceType.Unknown) {
continue;
}
….
}
This will prevent the local addresses from using the cell data network and require WIFI to prevent this from happening.
Curiously, the iPad with cellular that we tested exhibited the same problem, but the order of the network interfaces was different so that it put the WiFi network adapter in index 0 which works fine. However, to be clear, the iPad would exhibit the same connection problems if we disabled the WiFi and it was forced to use the cell data's IP.
Please let me know if you have any further questions or if you need additional clarification.