mrDoctorWho/ejabberd_mod_apns

I get error trying to start ejabberd after installing mod_apns

Closed this issue · 21 comments

These are the steps I followed:

  1. I copied mod_apns.elr file to ejabberd/bin folder
  2. from ejabberd module installer I compiled the file:

./erlc -I ejabberd/include mod_apns.erl

  1. It produced some warnings:
mod_apns.erl:26: Warning: function hexstr_to_bin/1 is unused
mod_apns.erl:28: Warning: function hexstr_to_bin/2 is unused
mod_apns.erl:127: Warning: variable 'From' is unused
mod_apns.erl:127: Warning: variable 'To' is unused
mod_apns.erl:127: Warning: variable 'Type' is unused
mod_apns.erl:157: Warning: variable 'Opts' is unused
mod_apns.erl:164: Warning: variable 'Host' is unused
  1. I ignored the warnings(?!) and copied .beam file to ejabberd/lib/ejabberd/ebin folder
  2. I copied my cert.pem and key.pem files to ejabberd/conf folder
  3. I configured ejabberd.yml file as follows:
mod_apns:
  address: "gateway.push.apple.com"
  port: 2195
  certfile: "cert.pem"
  keyfile: "key.pem"

I even tried:

mod_apns: {}

  1. start ejabberd

But the ejabberd won't start and the error file shows this error:
Problem starting the module mod_apns for host..

Any help is greatly appreciated..

Hello,

What ejabberd version are you using? Are you sure you didn't miss any dependencies?

I was unable to compile the way you did, but I was able to do it with the ejabberd source (15.10):

erlc -I build/lib/ejabberd/include/ -I deps/ -pa build/lib/ejabberd/ebin/ src/mod_apns.erl

But module was unable to start, mainly because of undefined macro INFO_MSG:

20:57:02.377 [critical] Problem starting the module mod_apns for host <<"localhost">> 
 options: [{address,<<"gateway.push.apple.com">>},
           {port,2195},
           {certfile,<<"/tmp/cert.pem">>},
           {keyfile,<<"/tmp/key.pem">>}]
 error: undef
[{p1_logger,info_msg,
            [mod_apns,162,"mod_apns Has started successfully!",[]],
            []},
 {mod_apns,start,2,[{file,"src/mod_apns.erl"},{line,162}]},
 {gen_mod,start_module,3,[{file,"src/gen_mod.erl"},{line,98}]},
 {lists,foreach,2,[{file,"lists.erl"},{line,1337}]},
 {ejabberd_app,start,2,[{file,"src/ejabberd_app.erl"},{line,73}]},
 {application_master,start_it_old,4,
                     [{file,"application_master.erl"},{line,273}]}]

That's why I recommend to compile the module within ejabberd source (doing make makes it possible to run the module). Anyways thank you for pointing out the compile warnings. They're just warnings, I'll fix them in the near future.

Please try to compile the module within ejabberd source. Unfortunately I don't know the way how to compile the module right. Ejabberd had a very poor documentation at the time I was writing the module.

Thank you very much for your reply. I really appreciate it.

My ejabberd version is 15.10 . I solved the issue by adding these lines of code to your source code:

-ifndef(LAGER).
-define(LAGER, 1).
-endif.

right after:

-export([start/2, stop/1, message/3, iq/3]).

I had to restart ejabberd to make it work. However, I cannot make the module to send the notification though. my ejabberd.yml configuration is like this:

 mod_apns: 
    address: "gateway.sandbox.push.apple.com"
    port: 2195
    certfile: "/Applications/ejabberd-15.10/conf/cert.pem"
    keyfile: "/Applications/ejabberd-15.10/conf/key.pem"
    password: "myPassword"

the address is sandbox since I am still in development phase. And I have tested my cert.pem and key.pem and they are valid and working.
I send my device token to ejabberd server like this:

<iq type="set" to="myEjabberdServer.com"> <register xmlns="https://apple.com/push"> <token>myDeviceTokenWithoutAnySpace</token> </register> </iq>

I can see my device token is saved in apns_users database.
But I still do not get notifications when my user is offline.

Am I doing anything wrong?
Does it work with gateway.sandbox.push.apple.com?
should my device token be without space and only characters?

I appreciate your help..

Am I doing anything wrong?

Are you sending messages to the registered user? I mean, the one who registered their token. Do the sender and the receiver have subscription both?

Does it work with gateway.sandbox.push.apple.com?

I can't say for sure, since I have no apple device. I tested the module remotely with the man who has his own device. It was about a half of a year ago and since then I haven't even looked at this module, so it can be even broken. So I'm trying to say that you should try without sandbox.

Are you sending messages to the registered user? I mean, the one who registered their token. Do the sender and the receiver have subscription both?

Yes, Both users are registered and can send messages to each other. Sender and the receiver have subscription both.

So I'm trying to say that you should try without sandbox.
I will check this with gateway.sandbox.push.apple.com

I will try to figure out the problem and I will post the solution here if I figured it out.

Thanks again for your help :)

I missed that question:

should my device token be without space and only characters?

As far as I remember the token was hexadecimal string 64 chars long. No spaces.

I will try to figure out the problem and I will post the solution here if I figured it out.

Please ensure your key and cert are the key and cert you got from Apple. And check also if your issue has anything to do with #1. And as you are using key, then you don't need the password field.

It's been two weeks since the last comment. Any progress around this issue?

Thanks for the follow up.
No, unfortunately I could not solve the problem! and I cannot figure out what could be the source of this problem!

I'm not aware of anything you've done, but I can suggest you to print out Reason from here.

If code comes to this line and you are one hundred percent sure that the key and certificate you're using you've got from Apple, then the module isn't working anymore and needs to be fixed.

Please check it out and report me of any result.

If code comes to this line and you are one hundred percent sure that the key and certificate you're using you've got from Apple, then the module isn't working anymore and needs to be fixed.

Yes, I am sure. Beside I have tested it with another tool and it works just fine.

I'm not aware of anything you've done, but I can suggest you to print out Reason from here.

I am not familiar with Erlang. How can I do that?

I think it doesn't even get to the send_payload

I get this error in my ejabberd log:

@mod_apns:message:88 FORMAT ERROR: "Offline message ~s" [{jid,<<"testuser10">>,<<"ejabberd.binnj.com">>,<<"7197603961456335197393496">>,<<"testuser10">>,<<"ejabberd.binnj.com">>,<<"7197603961456335197393496">>}]

I am not familiar with Erlang. How can I do that?

Try the following code (replace this line by the lines below):

Result = send_payload(ToServer, JSON, Token),
?DEBUG("Payload sent. Result: ~p", Result)

With this, you might get FORMAT ERROR again, though it doesn't really matter, lager will print contents of Result in any case.

As I suspected it does not even get there!
It does not print "payload sent.." on ejabberd log nor "mod_apns: No such record found for..." Message body if not null and subscription is both so maybe it has sth to do with type?!!
I try to add debug note to each section to see which one is the problem.

THANKS!

So I added info message to each section and I can see that the problem should be here:

case ssl:connect(Address, Port, Options, Timeout) of
        {ok, Socket} ->
            ?INFO_MSG("6666666666", []),
            Payload = list_to_binary(Payload),
            PayloadLength = size(Payload),
            Packet = <<
                0:8,
                32:16/big,
                Token/binary,
                PayloadLength:16/big,
                Payload/binary
            >>,
            ssl:send(Socket, Packet),
            ssl:close(Socket),
            ok;
        {error, Reason} ->
            ?INFO_MSG("7777777777", []),
            Reason
    end.

since it prints 7777777777 but not 6666666666

Seems Apple changed something in their services. Module hasn't changed since summer '15.

So I will look in the problem and search for the solution. It would be great if you could help me on this.

It seems also that @neeraj022 has ran in the same problem in #1.

I really appreciate it.
Sure, I'll do whatever I can :)

All the things around this module have been happening with the help of @naeems, who was so kind that provided me Apple certificate & key & device token (the module was also created by his request). Unfortunately, he doesn't respond anymore for some reason. The last time we had it tested, all was working fine.

I'm not sure if I need those things, because I tested the module with fake certificate which I generated by myself and got the same error, but also this error could happen when we use such certificate.

So if there's a way to get a valid certificate for tests which expires, say, in a week, it could really help.

Anyways, I will try to fix it. I'll be free at this weekend, so that time I will spend on this module then. That's no good to have something broken in the repository.

I checked payload that the module is trying to send and it is like this:

{"aps":{"alert":"Message","sound":"default"}, "source":"testuser10@myserver.com","destination":"testuser6@myserver.com"}

what are source and destination?

Source is the who sent the message and destination is to whom it was sent.

When you're getting this, your app may need to determine which JID the PUSH was sent to and who is the message sender (e.g. to show their name).

this is the error I get:

@mod_apns:send_payload:73 Error: {options,{socket_options,[{mode,binary}]}}

in this line of code:

{error, Reason} -> ?INFO_MSG("Error: ~p", [Reason]), Reason

Hi, I think that a good choice should be to integrate this library: https://github.com/inaka/apns4erl.

As @BesatZardosht said, Apple has changed the service and its API.

This library is updated and ready to work with the last version/API of the APNS.

Hello @joanlopez,

No doubt, that might be a good choice. But I'm trying to follow the KISS principle which has simplicity as it's main goal.

If there was no @BesatZardosht who has helped me a lot with testing and even modifying the module, that could be our choice. But since the module now works well, we don't need it here.