Force iOS device app to talk through the local WIFI network - ios

I'm building an application that will run in a museum with a local area wifi network without internet access, for some strange reason I'm not able to fully "join" this network with an iOS device. Enabling internet access on this network solves the problem...
The network should provide only a web server and a DNS server, the access point has a DHCP server, android devices can connect to the network without problems.
When I try to join the network with the device it remains in a "spinning wheel" status, the DHCP server log on the debian server says it has assigned an address to the iOS device, and if I check for the wifi address with an application (like iSys o SBSettings) I see the WIFI DHCP assigned address.
But when my app (or safari) tries to connect to the web server the request is routed through the 3G connection and not completed.
In my app I'm using the standard "Reachability" framework from Apple to check the reachability of a provided host name through the wifi connection and I get 0 on the SCNetworkReachabilityFlags mask....
I'm quite sure the problem is due to the fact iOS (5.1 in my case) tries to check the reachability for some "standard" host in the network, before routing traffic through the WIFI connection.
Anyone knows what an iOS device do to "validate" a WIFI network? I can add hostnames or simple dummy services to the server machine if this can help me connect the device to a LOCAL-only network :)

It seems that iOS doesn't like to join networks without a gateway, also if the network is local you have to setup a correct gateway address.
Setting the gateway as the server itself did the trick and the device started to route TCP/IP over my local area wifi network.

Related

GCDAsyncSocket client/server not working over iOS access point

I have a very simple TCP client/server implementation using GCDAsyncSocket (7.5.0) and I'm using NSNetService for service discovery.
It's used only on a local wifi network and it works for 2 years with no problem (just to say : I have a proper use of GCDAsyncSocket).
...Until I tried using a third iOS device as access point providing the wifi network to which the client and server connect.
Same when the third iOS device connects both client and server by sharing its connection via Bluetooth.
The service discovery is OK, but once I get the ip address and port, I can't connect and get this error :
Error Domain=NSPOSIXErrorDomain Code=64 "Host is down" UserInfo={NSLocalizedDescription=Host is down, NSLocalizedFailureReason=Error in connect() function}
I tried restricting to IPv4 and IPv6 (both are provided by the service discovery), I also tried using the ipv6 git branch of the GCDAsyncSocket repository and various parameters.
My primary question is : is establishing a simple TCP connexion over a wifi or bluetooth iOS access point possible, if so how ?
My secondary question is : why does the NSNetService service discovery work and not the simple TCP connection ? I know that the protocols are not comparable but still, it confuses me.
It sounds like to me, that your problem lies in connection from the cellular network. When connected to cell network, it causes issues with ip address. Refer to this discussion from the Cocoaasyncsocket Github page.

GCDAsyncSocket: [socket acceptOnPort: error:] not accepting

So I have been trying to create two GCDAsyncSocket's in my project, one (socket) that uploads a file to my server and the other (listenSocket) waits for another process from the server to communicate with it. In my ViewController I have initialized them in viewDidLoad method and setup delegate to self for both sockets.
socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
listenSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
I then made the listenSocket start listening by
NSError *err = nil;
if (![listenSocket acceptOnPort:19920 error:&err]) {
NSLog(#"listenSocket failed to accept: %#", err);
}
I then made socket to connect to remote server and start uploading files.
The problem is that socket works fine and can upload and also read response from my server, but it seems that I can't access the accepting listenSocket by any way. Not by the other process on server, nor by using telnet or by typing the ip address and port number into browser. Why is this and how do I fix it?
Edit:
Here's what I am doing with my app:
I am working on an app that programs for Arduino on iPhone. Due to App Store policy the compiling and uploading process has to be on server, so I'm using socket to upload the code to server to get it compiled. In order to upload the compiled binaries to Arduino, I have to run avrdude which fortunately would accept an ip + port address instead of a usb connection as target. avrdude is implemented so that it connects to the address as a client, so I have to open a listening socket on my app.
I imagine your issue relates to your device not having a routable IP address from the outside world. I have assumed here that you are not testing on a local network with your server and phone both using this network via wifi/cable.
When you are on your device using a mobile network, it is assigned an IP address from the mobile operator. This address is more than likely an address which is part of their internal mobile network. When you connect outside of the mobile network to a server, the address the server sees for your device is not the address you see on the device. The addresses are mapped in transit as your IP packet passes through the various gateways while on its way to the server. Thus when you server sees a connection requested on a listen socket, it has a reply address which when used allows the reply to traverse back to your device.
A similar issue occurs when your device is on WiFi behind a NAT router. Connections made outgoing are seen by the router and it changes the from IP address to be that of the router. Since it sees the start of the conversation, it know where return packets with a given port and sequencing should be routed. However if somebody wants to connect to your device from outside, you have to have set up port forwarding on the router for a known port telling it where to send connection packets.
So applying this to your situation:
Outgoing Works (Why):
Your outgoing socket works, because you are connecting to an externally visible IP. When you connect, the network knows exactly where the packet has to go and the reply address is provided in the packet by the network.
Incoming Does Not Work (Why):
Your listen socket will not be working because the address you are sending to does not exist on the open internet. To make a connection from the server or anywhere else to your device you would need an IP which has a routing mapped through to your device. If the device is on a mobile network, you need an external IP for the mobile network which maps to your device. If the device was behind a NAT router, you would need port forwarding set up.
Solution:
Unfortunately, there is no easy solution as your need an IP address for your device in the outside world. Much depends on your use case which you have not mentioned. You either need an external IP which is reliable or you need to use an intermediate server to handle messaging or you need to change your approach and have the device poll every so often for information.
This is a problem which has existed for a long time and is why peer to peer companies have smart algoithms for connecting peer to peer services which use clever techniques like hole punching to connect devices.
IMHO I would move to a model where your device always initiates the connection if you can.

Is there a way to programmatically change network routes on an iOS device?

Scenario: I want to have an iOS device connect to a LAN that has no upstream Internet connection, yet still retain and use its cellular data connection.
Theoretically, it strikes me that the iOS wifi NIC and the cellular data NIC are similar enough to dual NICs in a PC that I should be able to set up routing such that any request to, say, 192.168.. goes through the wifi connection, and any other request goes through the cellular data connection.
I did a test to see if both NICs are active when the iOS device is connected to wifi by the following steps.
Ensure that my iPhone's wifi is off and that I have a good cellular data connection.
Disconnect my wifi router's Ethernet cable to my cable modem.
Connect my iPhone to the wifi router.
Use another iPhone that's connected only via cellular data to create a game of Words with Friends.
As soon as the other iPhone completed the first move, my iPhone received a notification that there was a new game to play.
This confirmed that the cellular data connection was indeed alive and well enough to receive push notifications despite the wifi NIC's being connected.
The question becomes, then, can an app programmatically connect to a given wifi network, set the cellular data network to be the default route, and route any requests to, say, 192.168.. to go through the wifi network?
I know this post is old, but I happen to have done some work on using multiple network interfaces on iOS.
My experiments showed that accessing via hostname results in iOS choosing the network interface it wants to use, and not trying any further interfaces if the host cannot be resolved.
If you know the DNS Server IP address for any Ethernet/WiFi based network, you can send a DNS request yourself, convert the hostname into an IP address and access via IP address. iOS will then use the correct interface.
My guess is, that if you have the private class IP address space accessible over both connections, there's probably nothing you can do to specify which network interface should be used.

iOS enterprise vpn connectivity

In an iOS application if you had to access corporate remote services, through VPN, what would be your pattern to ensure you have connectivity and inform the user if that's not the case:
check that your network and VPN are working (by checking if some host like google.com and some private enterprise host are reachable) and if that's the case then call the remote service?
or call directly the remote service, and if there is a network exception, then check if both a network host and an enterprise host are reachable? (to find-out what's going on and inform the user)
or you would do it differently?
Usual approach:
1)User opens VPN client enables VPN connectivity
2)User uses the app.
Alternative approach:
If you are developing an enterprise application
then you could possibly start and stop VPN connection right from the app using apple's private api.
Advantages of the approach:
So that all the network connections from the app are routed through VPN and user doesn't have to enable VPN connection every time he uses the app.
Reference:
You could find some hot discussions on this topic in the following threads.
Thread 1
Thread 2
Thread 3

How bonjour works on IOS?

I created an application using bonjour and I am able to send files from one device to another. But the question is: I am not able to discover the devices on the LAN without running both the applications on the device. Do I need to run the application using bonjour to get it detected using bonjour.
Yes you do. Running the application registers the appropriate entries into the iOS multicast DNS service. Once you shut the app down I expect it removes itself from the multicast DNS registry (which it is correct to do, because it is no longer available), so you can't find it from other devices.
EDIT: (Very roughly) Bonjour is multicast DNS. The Bonjour service runs a multicast DNS server. When your application starts up it communicates with the local multicast DNS server and creates a number of entries that identify the service it is making available, the ports it is available on and other relevant attributes. It also registers itself as interested in learning about any other network device that is running the service.
The local multicast DNS server makes announcements that signal to any one else listening on the network that a new service is available. Your app (on a different machine) is notified by the Bonjour service that another client has appeared, and that is more or less how the magic is done. Longer multicast DNS writeups are all around: Google is your friend.

Resources