How to create TCP IP Server using Objective-C on iOS - objective-c

i have managed to create a client with objective-c where it can connect to any server, my app is running on an iPad.. so far a have tested the client on different servers telnet, nodejs, even a web based php server and it works fine.
But my scope has changed as i need my app to act as the server hence instead of connecting to a given socket, it should first open a socket and wait for client connection and establish communication between the two.
Here is a snippet of how my client on the ipad connects to server:
NSLog(#"Setting up connection to %# : %i", _ipAddressText.text, [_portText.text intValue]);
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef) _ipAddressText.text, [_portText.text intValue], &readStream, &writeStream);
messages = [[NSMutableArray alloc] init];
[self open];
I have tried cocoaAsyncSocket but um having trouble getting its work around:
https://github.com/robbiehanson/CocoaAsyncSocket

There are better native alternatives to CocoaAsyncSocket now, namely Apple's Network Framework.
Here is some nice sample code for a simple TCP client & server using the nw functions:
https://developer.apple.com/documentation/network/implementing_netcat_with_network_framework

Related

Why is the IP address of my remote ice candidate the same as my (Janus) WebRTC signaling server?

I am trying to make video calls with WebRTC and Janus. I am able to make calls using the video call demo page supplied by Janus as well as through an iOS app - this is all working perfectly fine.
However, when inspecting the network flow through both wireshark and chrome://webrtc-internals/ the connection does not seem to be directly to the public IP of the other device. Instead the data is directed to my Janus signaling server. It seems that the IP of the remoteIceCandidate is equal to the IP of my signaling server - shouldn't this should be equal to the public IP of device 2?
Is this correct behavior or not? If so, why is the remote IP not equal to the public IP of device 2? If not, what am I doing wrong?
This is correct behavior and a mistake on my part. The Janus video call plugin documentation says the following:
The idea is to provide a similar service as the well known AppRTC demo (https://apprtc.appspot.com), but with the media flowing through a server rather than being peer-to-peer.
Therefore, the media data is supposed to go to the server instead of over a peer-to-peer connection.

scan the network for a server while using AsyncSocket as a client

My app communicates with an external server using AsyncSocket as a Client.
(the working code can be found here)
When the app starts, the user types in the IP address of the server computer.
assuming both iOS and server is sitting on the same subnet
Question: is there a way to "scan" the network for the server thus avoiding the user manual input for server IP ?
I can iterate the IPs one by one in a loop (10.0.1.x 10.0.1.x++)
yet it seems wrong and wasteful.
is there another more elegant way to do so?
I had an iOS project doing server discovery in the current (Wi-Fi) network. The typical solution is to use UDP broadcasting to ask for server info and then listen to a UDP response. As soon as you get the response with the server address you can establish connection using TCP sockets.
CocoaAsyncSocket is good enough for this. I used GCDAsyncUdpSocket and GCDAsyncSocket.
I understand you probably need more info on the topic. I'll try to extend the answer when I have time to.

How to trigger on-Demand VPN with Objective-C on iOS

I have an iPad application which opens a socket connection to a server in Intranet using socket libraries in C . While starting the application, if the iPad is not connected to the same network (i.e. can not resolve the Domain Name of the server), I expect it to establish a VPN connection automatically. But socket calls and getaddrinfo() methods in the application can not do this. They just fail to connect to the server without trying to open the VPN connection.
With Safari, browsing to the address "http://..." works fine and succesfully starts the VPN. If I make a similar HTTP request in the beginning of the application by using the code below, I can make it start the VPN connection. But sending an additional http request is the best solution for me. VPN should start whenever iPad needs to resolve the domain name, without any dependency for the protocol or remote port number.
NSString* urlForVPN = #"http://..";
NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:urlForVPN] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
[NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
On Apple developer site it says "Avoid Resolving DNS Names Before Connecting to a Host. The preferred way to connect to a host is with an API that accepts a DNS name, such as CFHost or CFNetService" (https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/CommonPitfalls/CommonPitfalls.html). Accordingly, I was hoping that the following code should start VPN while trying to resolve the server name, but it does not work either. It just fails to get the IP address. I had to manually switch on the VPN to make it connect to the server.
NSString* hostname = #"myserver";
CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault, (CFStringRef)hostname);
BOOL isSuccess = CFHostStartInfoResolution(hostRef, kCFHostAddresses, nil);
How can I make an application understand that it needs to start the VPN?
Does "VPN on-demand" work only for URL connections?
From what I have come to understand through articles as well as first-hand reach, VPN-on-Demand will only trigger when you use Apple libraries that utilize WebKit (NSURLSession, NSURLConnection, etc.).
Therefore socket-based network requests are unable to trigger Apple's On-Demand VPN.
The documentation that appears support this is found here:
https://developer.apple.com/library/prerelease/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/CommonPitfalls/CommonPitfalls.html#//apple_ref/doc/uid/TP40010220-CH4-SW2
For those stumbling with this problem, using POSIX sockets will not trigger on-demand VPNs because those rules match by domain and those sockets don't have the domain info.
One workaround is to launch a dummy request through the usual NSURLSession / NSURLConnection to the correct domain to just trigger the VPN.
You might also want to get the reachability status and check for the "kSCNetworkReachabilityFlagsTransientConnection" which empirically turns to be there when a VPN connection is available (because many modern VPNs are based on ppp). These way you could detect when the VPN turns off in order to launch another dummy request.

Objective C - Switching from WiFi to 3G and vice versa

I'm developing an iPhone app that uses the network. The iPhone communicate with my server via HTTP request and should work on WiFi and 3G.
I currently use NSURLConnection initWithRequest to send async requests to my server and get responses (but I will soon move to work with ASIHTTPRequest library)
One thing that I'm not sure about is,
What happens when user device goes from WiFi to 3G (or vice versa)?
I know that the same connection can't be used and new connection must be established.
But do I need to do something to handle this situation, or does NSURLConnection handle it automatically?
For example if I sent a request and in the middle of getting the response the connection changes, what will happen with this request?
I saw Apple's Reachability example code, and I know I can use Reachability to detect network changes, but not sure how to handle those changes.
When the connection changes from 3G to WiFi, the current request will result in a failure status, and yes you will need to do something to re establish the connection (restart, resume, etc...)
Having said that, i am not sure, but i think ASIHTTPRequest has a mechanism to fix these issues when you for example request to download a file

noVNC connecting to VNCServer on private LAN using HTTPS only

Not sure if i'm really up-to-date, but i'm looking in a way to convert my existing project to use HTML5 websockets.
Here's my situation :
- Client runs a modified java vnc applet with extra parameter (CONNECT).
- Modified stunnel listenin on webserver (with both public, private IP) port 443
- Client connects to 443 and sends (prior to RFB) a HTTP packet like :
'CONNECT 10.0.0.1:4001'
- Stunnel opens a new stream to 10.0.0.1:4001 using SSL wrapper
- VNC Server (#10.0.0.1:4001) responds, connection is established.
Now I want to get rid of the Java Applet and switch to Websocket using NoVNC.
I want to be able to :
- Open a single port on the webserver (HTTPS preferably)
- Have client connect using HTML5 only (no more java applet)
I cannot change :
- VNCServer will still be listening on private LAN only.
- VNCServer will still listen to a bunch of ports, each corresponding to
a virtual server
Questions are :
- How to give NoVNC the notion of target HOST:PORT ?
- Is stunnel still be usable ? Or should I change to websocket proxy ?
If anyone has a starting point, i'd really appreciate !
Disclaimer: I created noVNC so my answer may be heavily biased ;-)
I'll answer you second question first:
stunnel cannot be used directly by noVNC. The issue is that the WebSockets protocol has an HTTP-like initial handshake and the messages are framed. In addition, until binary payload support is added to WebSockets, the payload is base64 encoded by the websockets proxy (websockify). Adding the necessary support to stunnel would be non-trivial but certainly doable. In fact noVNC issue #37 is an aspirational feature to add this support to stunnel.
First question:
noVNC already has a concept of HOST:PORT via the RFB.connect(host, port, password) method. The file vnc_auto.html at the top level shows how to get noVNC to automatically connect on page load based on the host, port and password specified as URL query string parameters.
However, I think what you are really asking is how do you get noVNC to connect to alternate VNC server ports on the backend. This problem is not directly addressed by noVNC and websockify. There are several ways to solve this and it usually involves an out-of-band setup/authorization mechanism so that the proxy can't be used to launch attacks by arbitrary hosts. For example, at my company we have a web based management framework that integrates noVNC and when the user wants to connect to the console, an authenticated AJAX call is used to configure the proxy for that particular user and the system they want to connect to. Our web management interface is internal only.
Ganeti Web Manager uses a similar model and the source is available. They have a fork of VNCAuthProxy that has WebSockets support. They use a control channel from the web interface to the VNCAuthProxy to setup a temporary password associated with a specific VNC server host:port.
Also OpenStack (Nova) integrates noVNC uses a similar out-of-band token based model to allow access with their nova-vncproxy.
Some links:
Ganeti Web Manager
Wiki page about how noVNC works in Ganeti Web Manager
Ganeti Web Manager sources
Ganeti Web Manager VNCAUthProxy sources
Using noVNC in Nova/OpenStack
OpenStack fork of noVNC
Old nova-vnc-proxy code
Current nova vnc proxy code