Tigase and xmpp, 1st offline message not getting received - xmpp

hi I am using Tigase and xmpp for chat application, everything is working fine except i am not receiving first offline message.
Eg: there are 2 users A and B, A send 3 messages to B but B is offline(i.e. app is in Not running state), but when B comes online he receive only 2 messages(last 2), first message always get missed.
Help me to solve this issue.

I faced the similar problem, on client side we can't do anything for that as XMPP(Tigase) server automatically returns all the offline messages when user comes online. There might be some problem in Tigase server which is not returning the first message. Because all the offline messages you will receive in
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
and it can be checked first offline message is not returned by server.

Related

Ejabberd Message delivery while application is terminated

I am developing a chat app using ejabberd server for both IOS and Android. I also wrote a module for ejabberd to get the offline messages sent to my own server api .
my own server api will send notifications to the IOS/Android platforms using FCM.
On the client side , if the application is in the foreground or the background , it will stay connected to ejabberd and if the client receives the message then ejabberd will send the message delivery status.
I am facing an issue while the app is terminated ( service is not running ) which means it is not connected to ejabberd (offline) . if i send a message to this app while it is not terminated , it will receive a notification but the message still undelivered . how can mark the messages as delivered when receiving the notification while the app is terminated.
to explain it more , the same functionality is working fine with whatsapp :
device A has whatsapp installed and whatsapp was turned off (terminated)
Device B has whatsapp running
Device B sends a message to device A
Device A receives a whatsapp notification
Without doing anything on Device A , the message status on Device B is marked as delivered .
How can I implement this scenario with ejabberd ?
In case someone went into this issue , here is the solution that I implemented with help of #Mickaël Rémond from his answer.
I configured ejabberd to send the offline messages to an http service ( your own server) please refer to this link for further on how to do it
your server should catch the above call and generate a notification message (FCM ) in my case and send it to recipient device
recipient device will catch the notification which includes the message
recipient device will call http service (your own server backend)that responsible for sending the deliver ack to the original sender . you need to pass from, to , stanzaId , vhost with this call
backend server will use ejabberd-api (set of exposed apis to manage ejabberd through rest apis calls) to send delivery message using this api
please note the following notes also :
sending the delivery message from your own server to ejabberd will not delete them from ejabberd database
if the user re-connected to the ejabberd server then the recipient will receive the message again from ejabberd .
It is probably too complex for a simple Stack Overflow question, as you need to integrate several moving part on client and server:
You need to execute code in background when receiving push notifications on iOS (you need that property set on your app in your app provisioning profile and have code to handle that). The client will initiate an HTTPS query to let the server know that the message was delivered.
You need to have an endpoint that will get the delivered HTTPS calls and generate either a message ack or a chat marker on behalf of the user and route it in ejabberd.
In real world, this is not enough if you want to take into account the fact that you can only have 1 push in the queue on APNS. If you have several messages sent while the device is not on the network, you will need to have the device check all received messages while offline on the server, otherwise you will lose messaging.
You need to rely on XMPP Message Archive Management (MAM) to handle that history.
As you see, this is not a simple few tens of line of codes but need real design and involved work.

swift HTTP Requests

I have created an instant messenger chat application where by messages are posted to my server via a php service and stored in a mysql backed.
If a user has their 'inbox' page open and a new message is received I would need to update the table to show any new messages. The way I am doing this at the moment is by sending an http request to the server every 5 seconds.
As you can imagine this is pretty inefficient. What methods are available which would be more suitable and less resource heavy?
I have looked at keep alive connections and web sockets but Im not sure which direction I should be going in?
any help much appreciated!
Your approach is called polling, which is not efficient because it consumes more electricity from your phone and you have extra load to your server. The correct way of doing it is though Apple's push notification. Here is the tutorial for that. Basically your server will send request to Apple's push notification center when a new message is received.
However in your case it's a bit more complicated. You want this notification only after user entering the mail page. So you need to tweak your php server to send notification only after user entered the mail page. In this case you are sending only one request to your server telling it to start sending notifications, instead of constantly polling your server

xmpp messages are lost when client connection lost suddently

I am using ejabberd server and ios xmppframework.
there are two clients, A and B.
When A and B are online, A can send message to B successfully.
If B is offline, B can receive the message when B is online again.
But when B is suddenly/unexpectedly lost connection, such as manually close wi-fi, the message sent by A is lost. B will never
receive this message.
I guess the reason is that B lost connection suddenly and the server still think B is online. Thus the offline message does work under this condition.
So my question is how to ensure the message that sent by A will be received by B? To ensure there is no messages lost.
I've spent the last week trying to track down missing messages in my XMPPFramework and eJabberd messaging app. Here are the full steps I went through to guarantee message delivery and what the effects of each step are.
Mod_offline
In the ejabberd.yml config file ensure that you have this in the access rules:
max_user_offline_messages:
admin: 5000
all: 100
and this in the modules section:
mod_offline:
access_max_user_messages: max_user_offline_messages
When the server knows the recipient of a message is offline they will store it and deliver it when they re-connect.
Ping (XEP-199)
xmppPing = XMPPPing()
xmppPing.respondsToQueries = true
xmppPing.activate(xmppStream)
xmppAutoPing = XMPPAutoPing()
xmppAutoPing.pingInterval = 2 * 60
xmppAutoPing.pingTimeout = 10.0
xmppAutoPing.activate(xmppStream)
Ping acts like a heartbeat so the server knows when the user is offline but didn't disconnect normally. It's a good idea to not rely on this by disconnecting on applicationDidEnterBackground but when the client looses connectivity or the stream disconnects for unknown reasons there is a window of time where a client is offline but the server doesn't know it yet because the ping wasn't expected until sometime in the future. In this scenario the message isn't delivered and isn't stored for offline delivery.
Stream Management (XEP-198)
xmppStreamManagement = XMPPStreamManagement(storage: XMPPStreamManagementMemoryStorage(), dispatchQueue: dispatch_get_main_queue())
xmppStreamManagement.autoResume = true
xmppStreamManagement.addDelegate(self, delegateQueue: dispatch_get_main_queue())
xmppStreamManagement.activate(xmppStream)
and then in xmppStreamDidAuthenticate
xmppStreamManagement.enableStreamManagementWithResumption(true, maxTimeout: 100)
Nearly there. The final step is to go back to the ejabberd.yml and add this line to the listening ports section underneath access: c2s:
resend_on_timeout: true
Stream Management adds req/akn handshakes after each message delivery. On it's own it won't have any effect on the server side unless that resend_on_timeout is set (which it isn't by default on eJabberd).
There is a final edge case which needs to be considered when the acknowledgement of a received message doesn't get to the server and it decides to hold it for offline delivery. The next time the client logs in they are likely to get a duplicate message. To handle this we set that delegate for the XMPPStreamManager. Implement the xmppStreamManagement getIsHandled: and if the message has a chat body set the isHandledPtr to false. When you construct an outbound message add an xmppElement with a unique id:
let xmppMessage = XMPPMessage(type: "chat", to: partnerJID)
let xmppElement = DDXMLElement(name: "message")
xmppElement.addAttributeWithName("id", stringValue: xmppStream.generateUUID())
xmppElement.addAttributeWithName("type", stringValue: "chat")
xmppElement.addAttributeWithName("to", stringValue: partnerJID.bare())
xmppMessage.addBody(message)
xmppMessage.addChild(xmppElement)
xmppMessage.addReceiptRequest()
xmppStream.sendElement(xmppMessage)
Then when you receive a message, inform the stream manager that the message has been handled with xmppStreamManager.markHandledStanzaId(message.from().resource)
The purpose of this final step is to establish a unique identifier that you can add to the XMPPMessageArchivingCoreDataStorage and check for duplicates before displaying.
I guess the reason is that B lost connection suddenly and the server
still think B is online. Thus the offline message does work under this
condition
Yes you are absolutely correct,this is well known limitation of TCP connections.
There are two approaches to your problem
1 Server side
As I can see you are using ejabbed as XMPP server you can implement
mod_ping , Enabling this module will enables server side
heartbeat[ping] ,in case of broken connection to server[ejabbed] will
try to send heartbeat to connection and will detect connection is lost
between server and client. Use of this approach has one
drawback,module mod_ping has property called ping_interval which
states how often to send heartbeat to connected clients, here lower
limit is 32 seconds any value below 32 is ignored by ejabbed,means
you have 32 seconds black window in which messages can be lost if user
is sowing as online
2 Client side
From client side you can implement Message Delivery Receipts
mechanism .With each Chat message send a receipt to receiver user of
as soon as receiver user receives message send back this receipt
id. This way you can detect that your message is actually delivered to
receiver. If you don't receive such acknowledgement between certain
time interval you can show user as offline locally(on mobile
phone),store any further messages to this user as offline message
locally[in SQLLight database ],and wait for offline presence stanza for that user
,as soon as you receive offline presence stanza it means that server
has finally detected connection to that user is lost and makes user
status as offline ,now you can send all messages to that user ,which
will be again stored as offline messages on server.This is best
approach to avoid black-window.
Conclusion
You can either use Approach 2 and design you client such way ,you can also use Approach 1 along with approach 2 to minimize server broken connection detraction time.
If B goes offline suddenly then user A have to check if B is online/offline while sending message to user B. If user B is offline then user A have to upload that message on Server using Web service. And user B have to call web service on below function.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
So user B will get that all offline message which was lost due to connection Lost.
At last, I use Ping together with Stream Management:
http://xmpp.org/extensions/xep-0198.html
This problem is solved.

XMPP offline message(s) received every time user logs in

I am working with XMPP server, backend enabled with BuddyCloud. Everything is working fine.
My only issue is, when someone sends me an offline message (means when I am offline), so when I logs in again and send my Presence all the offline message start receiving.
Scenario:
If I am offline, and someone sends me the message, I should not receive it and it happens correctly. And when I came online, I should receive that message. Which I receives and it is correct till this point.
Now when I come online any next time, I always receive that message, which I have received already. Tell me If I am still not clear with my issue.
Can anyone help me?

Possible reasons for QSSLSocket to stop sending/receiving data

Can anybody give me a possible reason why my QSSLSocket would stop sending and receiving data without firing a stateChanged or disconnected signal.
My app starts a thread which connects to Facebooks XMPP server, authenticates and then goes into a while loop calling waitForReadyReady(10000) and then if this returns true it will read the data. Sometimes, After a while this call to waitForReadyReady will never return true even though there should be something to read and if I try to send data at this point the server won't receive anything.
I am sending pings to the XMPP server and can detect when this has happened after not receiving a reply to my ping but it's not really usable as an app until I get to the bottom of why communication is sometimes just breaking down between client and server.
Can anybody offer any insights please?