How to reliably keep a voip app alive in ios? - ios

I have a voip app for ios, based on webrtc. I also have a signaling server made with nodejs. I can connect to the server and make calls without a problem. But tracking presence (online/offline) accurately is a problem.
Just for the record, here is a list of everything I did to ensure a stable connection:
Set the background mode "Voice over IP"
Flag the inputstream as a voip stream with "[inputStream setProperty:NSStreamNetworkServiceTypeVoIP
forKey:NSStreamNetworkServiceType];"
Turned on persistent wifi by setting "UIRequiresPersistentWiFi" to YES in the plist file
I implemented "setKeepAliveTimeout:handler:" and I use it to send a ping to the server (unnecessary, but you never know...)
I created a small test app that does nothing more than connect to the server and respond to "ping" with the message "pong". This app sends "ping" to the server when the keep alive timeout handler fires and the server replies with "pong". I also created a simple test server that does nothing more than let clients connect, send "ping" to a client when I send "send_ping" to it via telnet and responds to "ping" with the message "pong".
Here is my client code
What I expect is the following:
Starting the app and signing in should create a persistent connection to the server (works)
Telnetting into the server and typing send_ping makes the server send "ping" to the client and the client should send "pong" back (works)
Putting the device in standby should have no effect on the above ping-pong mechanism (doesn't work)
Putting the device in standby and unlocking it after a few hours, then sending a ping to it should make the client send a pong back (works)
Turning off wifi on the client (without cellular enabled) should be detected on the server-side and kill the socket (doesn't work)
I log all messages from the server in a textview on the client with a timestamp, and sometimes when I put the device in standby the pings I send from the server just don't arrive at all. Sometimes it takes over a minute for the app to receive the ping message, sometimes it responds immediately. I don't understand why it is so random. Sometimes this undesired behaviour starts after mere minutes in standby mode, sometimes it goes alright for a while but breaks after 20+ minutes, sometimes all messages from the server arrive at once as soon as I unlock the device.
Push notifications and voip push notifications could be a solution, but they are also slightly unreliable. There should be a way to make this work 100% of the time.

Related

NodeMCU resest with mqtt.client:close()), or mqtt.client:connect()

I have an application that uses mqtt for communication between modules and with a mobile terminal.
In some situations when the messages do not arrive, the node performs a self test of MQTT (sending a msg to itself), and when the selftest fails, tries to reconnect to the broker (mqtt offline not always arrives). And then two problems may arise:
If I perform a mqtt.client:close() to assure that the client is closed (to avoid the second problem) and the client is already closed, the node resets.
If I perform a mqtt.client:connect() and the client is still connected, an exception and a restet occurs.
is there a way to know if the mqtt client is connected or not?
Thanks for your comment. I am going to describe what I am doing, to see if you can help me:
I have two independent system, a master and a slave. The master publish a test message every 10 minutes. If there is no answer from the slave. it publish a test message to itself. If this self test does not arrive, a disconnection from the broker is assumed, and a reconnection is initiated.
And here is where the problem comes, sometimes the client is disconnected and everything go well, but sometimes it is still connected but unresponsive, and the node resets with an exception "already connected".
Performing a mqtt:close() previously to the reconnection, should be safe, but if I send it and the client is truly disconnected, the node resets without any reason (known to me).
All this is happening without receiving any offline message.
Instead of waiting for messages manually sent by the master client (which could fail to send for various reasons, leading a listening device to the wrong conclusion about the state of its connection to the broker), I recommend using MQTT's built-in connection management.
First, you can make sure that each client's initial connection has succeeded by including an error handler in :connect(). If the client really opens, nothing in the NodeMCU documentation indicates that it will close itself; it may go offline.
Once connected, the client only knows that something is wrong when it sends a message and does not receive a response. It sounds like you are not calling :publish() much (which would otherwise let you know by returning false), so pinging may be best. If you expect to receive a message from the broker every n seconds, set a keepalive time slightly higher than that on the client.
Then, failure to get a response to those messages should trigger an event that you can respond to. That might be something like the following (not tested, may work better called outside the callback):
m:on("offline", function(client) m:close() end)

If a BLE can't force a disconnect, how can we authenticate a connection?

I believe I read that the peripheral side cannot terminate a connection?
terminate a connection CBPeripheralManager side
How then, can we authenticate a connection at the application level? We are making an iOS app connect to another iOS app, we only want them to connect to each other. After connection they exchange private-key-based challenge/response questions, and a failure should result in a refusal of the connection. This of course works fine on the central side, if it doesn't get the correct reply it closes the connection. But if the peripheral cant cancel the connection, then how do we prevent a different central from connecting, and staying connected to the peripheral?
When a central connects but does not authenticate correctly, do not respond to requests from it. Every CBATTRequest includes the requesting central, and updateValue(_for:onSubscribedCentrals:) lets you control which centrals you respond to.
If they're not authenticated. Don't talk to them. Or more correctly, send them .insufficientAuthentication to all their requests. If they are well behaved, they will disconnect. If they are badly behaved, there is nothing you can do about that (this is always true; even if you could disconnect them, they could still flood you with connection requests).
You cannot force them to disconnect, however. They may be communicating with another app, and you are not allowed to stop that. You can only refuse to talk to them yourself or send them errors.

XMPP client network failure and Openfire offline message

I have configured XMPP client (iOS) and Openfire , everything works just fine except that i am not able to handle the following situation.
iOS client disconnects because of network failure.
User is still logged in on the server because there is no way to disconnect(no network).
Further messages are not stored in server because server thinks that the user is still logged in. Hence the messages are lost.
Unable to send push notification by sender because the receiver(User) status is still online ( no network to send presence ).
How can i solve this issue?
I found a solution, not sure if it is efficient.
In Openfire admin portal, under Client Connection Settings->Idle Connections Policy, there is an option to disconnect the client if it is idle for x seconds. By default it is 360 seconds, i have changed it to 5 seconds so that the messages won't get lost.
I am not sure if its a good idea to ping the clients every 5 seconds.

iOS Methodology: should I listen to a socket?

I know almost nothing about server/sockets programming. Pardon my ignorance.
I'm making an iOS app that needs to integrate with my web server. The function is analogous to a chat room - multiple clients will be 'connected' and 'listening' to a server session, any one client can send a 'bit', and all clients will receive the 'bit'.
Should I use low-level socket listening and callbacks for this? Is there a better, more power-efficient way? A cool framework I should use?
There are many options for this:
Use a socket to your server and roll your own protocol
Use web sockets and long polling from your app. This means you will fire a HTTP request and your server will keep it open for, let's say, one minute waiting for messages. Take a look here to start: What are Long-Polling, Websockets, Server-Sent Events (SSE) and Comet?
Use a chat server like Openfire or Ejabberd, which use XMPP, and on your client use XMPPFramework (https://github.com/robbiehanson/XMPPFramework)
Depending on the complexity of your app (authentication? blocking contacts? one-to-many and one-to-one chat?) you can decide on any of the above options. With more details I may be able to help you more.
If you want to be able to receive data while the app is not in the foreground, you will need to use Apple's push notification feature, which is implemented in hardware and the only way to make network connections to a device that is in power saving mode.
There's plenty of documentation how it works, basically the device registers with your server (after asking the user for permission), you use the token it gives you to send a ping to Apple's server, which forwards the ping on to the device. The device can then contact your server and download the actual data you want to send to it.
If you're OK with the server only communicating with your app while the app is running, you have a few options. The easiest is "long polling" where the app sends a HTTP request to the server, using something like this:
NSURL *serverUrl = [NSURL URLWithString:#"http://example.com/"];
NSString *response = [NSString stringWithContentsOfURL:serverUrl usedEncoding:NULL error:NULL];
NSLog(#"%#", response);
Instead of the server responding instantly, it can wait around for a long time (for example 45 seconds) until it has something to send to the device, then it responds with the information.
If 45 seconds are reached without having anything to send, it just sends a nothing response and the phone immediately opens up a new URL request to the same URL. This keeps the server from having a bunch of old/abandoned connections open. Typically connections are dropped after 60 seconds, so you want to respond before that time limit is reached. Obviously you'll want to do the request on a background queue with NSOperationQueue.
There are other options, you could use sockets, you could start a web server on a custom HTTP port on the phone (eg: https://github.com/robbiehanson/CocoaHTTPServer). But long polling is often the easiest choice.
Most apps use a combination of push notifications and something else.

Losing messages over lost connection xmpp

i went through this question
Lost messages over XMPP on device disconnected
but there is no answer.
When a connection is lost due to some network issue then the server is not able to recognize it and keeps on sending messages to disconnected receiver which are permanently lost.
I have a workaround in which i ping the client from server and when the client gets disconnected server is able to recognize it after 10 sec and save further messages in queue preventing them from being lost.
my question is can 100% fail save message delivery be achieved by using some other way i know psi and many other xmpp client are doing it.
on ios side i am using xmppframework
One way is to employ the Advanced Message Processing (AMP) on your server; another one is to employ the Message Delivery Receipts on your clients.
The former one requires an AMP-enabled server implementation and the initiating client has to be able to tell the server what kind of delivery status reports it wants (it wants an error to be returned if the delivery is not possible). Note that this is not bullet-proof anyway as there is a window between the moment the target client losts its connectivity with the server and the moment the TCP stack on the server's machine detects this and tells the server about it: during this window, everything sent to the client is considered by the server to be sent okay because there's no concept of message boundaries in the TCP layer and hence if the server process managed to stuff a message stanza's XML into the system buffers of its TCP connection, it considers that stanza to be sent—there's no way for it to know which bits of its stream did not get to the receiver once the TCP stack says the connection is lost.
The latter one is bullet-proof as the clients rely on explicit notifications about message reception. This does increase chattiness though. In return, no server support for this feature is required—it's implemented solely in the clients.
go with XEP-0198 and enjoy...
http://xmpp.org/extensions/xep-0198.html
For a XMPP client I'm working on, the following mechanism is used:
Add Reachability to the project, to detect quickly when the phone is having connectivity problems.
Use a modified version of XEP-0198, adding a confirmation sent by the server. So, the client sends a message, the server confirms with a receipt. Later on, the receiving user will also confirm with a receipt. For each message you send, you get two confirmations, one from the server, one from the client. This requires modifications on the server of course.
When the app is not connected to the XMPP server, messages are queued.
When the app is logged in again to the XMPP server, the app takes all messages which were not confirmed by the server and sends them again.
For this to work, you have to locally store the messages in the app with three possible states: "Not sent", "Confirmed by server", "Confirmed by user"

Resources