Reputation: 1791
I have a Xamarin forms application. The application programmatically connects to a an access to point to communicate via sockets with a host machine connected to that same access point. The access point is not required to have internet access. When testing my code in iOS - I get a socket error stating that the 'Destination is unreachable'. However, if I go to settings and click on the wifi connection I want to use - I am taken to the login page for the access point. If I click cancel I get the option to 'Use without Internet'. If I select that option, then go back to my application, I am able to connect to the host. Is there a way to programmatically tell iOS to use the connecting even though it does not have internet? I looked at the Zone property but that is read only. Here is the code I am using. Any assistance would be appreciated.
public async Task<WifiConfiguredEventArgs> ConnectToWifi()
{
try
{
var tobj_WifiManager = new NEHotspotConfigurationManager();
var tobj_SSIDs = await tobj_WifiManager.GetConfiguredSsidsAsync();
if (tobj_SSIDs != null && tobj_SSIDs.Contains(App.gvm_AppSettings.WifiSSID))
{
// We are already connected -- just return
lobj_WifiConfiguredEventArgs.ConnectionStatus = FlexConnectionStatus.eAlreadyConnected;
}
else
{
var tobj_WifiConfig = new NEHotspotConfiguration(App.gvm_AppSettings.WifiSSID, App.gvm_AppSettings.WifiPassword, false);
tobj_WifiManager.ApplyConfiguration(tobj_WifiConfig, async (error) =>
{
if (error != null)
{
lobj_WifiConfiguredEventArgs.ConnectionStatus = FlexConnectionStatus.eErrorEstablishingConnection;
lobj_WifiConfiguredEventArgs.ErrorMessage = error.ToString();
}
else
{
lobj_WifiConfiguredEventArgs.ConnectionStatus = FlexConnectionStatus.eConnectionEstablished;
}
});
}
}
catch(Exception ex)
{
lobj_WifiConfiguredEventArgs.ConnectionStatus = FlexConnectionStatus.eErrorEstablishingConnection;
lobj_WifiConfiguredEventArgs.ErrorMessage = ex.Message;
lobj_WifiConfiguredEventArgs.ErrorException = ex;
App.ProcessException(ex);
}
return lobj_WifiConfiguredEventArgs;
}
}
Someone asked for the socket code so here it is. To be clear, the socket code connects and communicates fine in iOS when the access point has an internet connection. It also works fine in all the android calls.
using FCISelfCheckIn;
using FCISelfCheckIn.Resources;
using FCISharedAll.FCICommObjects;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using static FCISharedAll.FCIEnums.FlexEnums;
namespace FCISelfCheckIn
{
// This template use base socket syntax to change Pattern. (like Send, Receive, and so on)
// Convert to Task-based Asynchronous Pattern. (TAP)
public static class AsynchronousClientSocket
{
private static bool ib_IsConnected = false;
private static Socket iobj_Client = null;
public static async Task<MasterDataObject> SendMessage(string ps_IPAddress, int pi_Port, ge_CommunicationType pe_CommicationType,
string JSONData)
{
MasterDataObject lobj_response = new MasterDataObject();
try
{
//We should already be connected by the time we get here so just continue
//However if we are not - try to connect again
if (!ib_IsConnected)
{
// Establish the remote endpoint for the socket.
IPAddress ipAddress = IPAddress.Parse(ps_IPAddress);
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, pi_Port);
// Create a TCP/IP socket.
iobj_Client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
ib_IsConnected = await iobj_Client.ConnectAsync(remoteEndPoint).ConfigureAwait(false);
}
if (ib_IsConnected)
{
var bytesSent = await iobj_Client.SendAsync(JSONData).ConfigureAwait(false);
// Receive the response from the remote device.
var ls_MasterDataObject = await iobj_Client.ReceiveAsync(60).ConfigureAwait(false);
if (ls_MasterDataObject == null)
{
lobj_response = new MasterDataObject();
lobj_response.CommunicationType = ge_CommunicationType.e_Error;
}
else
{
//deserialize the master data object in order to return it to the client
lobj_response = App.gvm_CommunicationHelper.DeserializeMasterDataObject(ls_MasterDataObject);
iobj_Client.Shutdown(SocketShutdown.Both);
}
}
else
{
lobj_response.CommunicationType = ge_CommunicationType.e_Error;
lobj_response.JSONDataObject = JsonConvert.SerializeObject(AppResources.ServerConnectionError);
}
// Release the socket.
iobj_Client.Close();
}
catch (Exception ex)
{
App.ProcessException(ex);
}
return lobj_response;
}
private static Task<bool> ConnectAsync(this Socket client, IPEndPoint remoteEndPoint)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (remoteEndPoint == null) throw new ArgumentNullException(nameof(remoteEndPoint));
return Task.Run(() => Connect(client, remoteEndPoint));
}
private static bool Connect(this Socket client, EndPoint remoteEndPoint)
{
bool lb_ReturnValue = true;
try
{
if (client == null || remoteEndPoint == null)
{
lb_ReturnValue = false;
}
else
{
client.Connect(remoteEndPoint);
}
}
catch (System.Net.Sockets.SocketException Socketex)
{
lb_ReturnValue = false;
if (Socketex.ErrorCode != 10061 && Socketex.ErrorCode != 10065)
{
//Dont log if the host is not running.
App.ProcessException(Socketex);
}
}
catch (Exception ex)
{
App.ProcessException(ex);
lb_ReturnValue = false;
}
return lb_ReturnValue;
}
private static async Task<string> ReceiveAsync(this Socket client, int waitForFirstDelaySeconds = 10)
{
if (client == null) throw new ArgumentNullException(nameof(client));
Debug.WriteLine("Receive Message 1");
// Timeout for wait to receive and prepare data.
for (var i = 0; i < waitForFirstDelaySeconds; i++)
{
if (client.Available > 0)
break;
await Task.Delay(3000).ConfigureAwait(false);
}
// return null If data is not available.
if (client.Available < 1)
return null;
Debug.WriteLine("Receive Message 2");
// Size of receive buffer.
const int bufferSize = 1024;
var buffer = new byte[bufferSize];
// Get data
var response = new StringBuilder(bufferSize);
do
{
var size = Math.Min(bufferSize, client.Available);
await Task.Run(() => client.Receive(buffer)).ConfigureAwait(false);
var ts_CurrentSegment = Encoding.ASCII.GetString(buffer, 0, size);
if (ts_CurrentSegment.Length > 0)
{
response.Append(Encoding.ASCII.GetString(buffer, 0, size));
}
} while (!response.ToString().EndsWith(FCIEndOfFile));
// Return result.
return response.ToString().Replace(FCIEndOfFile, "");
}
private static async Task<int> SendAsync(this Socket client, string data)
{
var byteData = Encoding.ASCII.GetBytes(data);
return await SendAsync(client, byteData, 0, byteData.Length, 0).ConfigureAwait(false);
}
private static Task<int> SendAsync(this Socket client, byte[] buffer, int offset,
int size, SocketFlags socketFlags)
{
if (client == null) throw new ArgumentNullException(nameof(client));
return Task.Run(() => client.Send(buffer, offset, size, socketFlags));
}
public async static Task<bool> ForcePermissions(string ps_IPAddress, int pi_Port)
{
bool lb_ReturnValue = false;
try
{
IPAddress ipAddress = IPAddress.Parse(ps_IPAddress);
//This is only done to force the local network permissions access in iOS 14.
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, pi_Port);
// Create a TCP/IP socket.
iobj_Client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
ib_IsConnected = await iobj_Client.ConnectAsync(remoteEndPoint).ConfigureAwait(false);
if (ib_IsConnected)
{
Debug.WriteLine("GEORGE Permissions Connected");
//client.Shutdown(SocketShutdown.Both);
//client.Close();
lb_ReturnValue = true;
}
else
{
Debug.WriteLine("George Permissions not Connected");
}
}
catch (Exception ex)
{
//Just skip if there is an exception
App.ProcessException(ex);
}
return lb_ReturnValue;
}
}
}
Upvotes: 0
Views: 196