A mock APN server in #erlang
The number of apps people install on their smartphones is increasing day by day. One of the most interesting technologies a developer may employ when developing his own app consists in using push notifications.
Nowadays the biggest companies out there are providing some service in this sense: Apple has Apple Push Notification, Google has Google Cloud Messaging, Nokia has Nokia Notifications and Microsoft has Push Notification for Windows Phone.
Some time ago I had to work with Apple Push Notification, which does not provide a REST interface to the service as the other platforms but instead provides a protocol for exchanging streams between client and server.
Most of the stuff I had to deal with when working with APN was fairly easy and this is true specially because I was working with Erlang: I do believe that Erlang and in particular binary sintax can be really helpful when you have to build a packet following the Apple specifications, and in fact a lot of resources are available online in this sense as for example the tutorial you may find in this blog.
During my initial implementation and trobuleshooting I didn’t want to test my own software on the real APN server. Yes I know, you may use the sandbox for testing purposes, but if you are running a test with hundred thousands of notifications in order to stress your backend it is not a good idea to spam APN, moreover APN can be tricky some times so I did prefer to test my software on a controlled environment.
For this reason I implemented mockapn a mock server that provides very basic functionalities but that may be very helpful when you want to test your implementation of an APN client.
mockapn was built using the strategy proposed by Fred in the fantastic book LYSE: the supervisor (mock_apn_sup) starts a set of acceptors and whenever a connection is handled a new acceptor is spawned so that we have always n acceptors ready. Of course mockapn is built using ssl module and not gen_tcp, but still the implementation is almost the same, you have only to remember to change in the supervisor the values for certicate, key and password according to your needs.
Any incoming connection to mockapn is handled using a module (mock_apn_server) implemented on top of the gen_server behaviour: this module parses the incoming binaries looking for APN packets built using simple or enhanced formats and prints on screen the token and the JSON received.
Only for enhanced format mock_apn_server checks whether the token is invalid (invalid tokens are specified in the macro INVALID_TOKENS) and if so sends back an error message to the client and closes the connection. Since in my experience this is the most common error I did’t implement any other kind of error check in mockapn, but you are free to fork and adapt the code according to your needs. You may want to see the README file for more information on how to compile and run mockapn.
Now you may ask: “Paolo, is APN so easy as you say?“. No. some parts of APN are indeed tricky.
For example it is obvious that you can’t start an SSL connection to APN only to send a single notification and then close the connection. You can’t do it because:
- if you do it very often you may bother APN servers that may see you as a DOS attacker
- most of the times you want to send multiple push notification as a bulk over the same SSL connection.
If all your notifications in the aforesaid bulk are correct then no problem, APN will forward them to the clients and everybody will be happy.
But what happens if one of the notifications in the middle of the bulk is wrong? Well, for what I have experienced I may say that if one of the notifications is not valid (e.g., it has an invalid token) the connection will be closed and you will receive an error message (if you are using the enhanced format) but all the notifications sent on the same socket after the wrong one are lost in a limbo, and you will not know whether they were right or wrong. In Erlang this means that if you send in a fast way your notifications you will get an ok message all the notifications and eventually at some point you will get a message representing the fact that the socket was closed by the peer.
mockapn behaves in a similar way and you may test it using the file mock_apn_test.erl (which you have to compile using the old good erlc). In mock_apn_test I do send three notifications to mockapn (you have to change the tokens according to you needs), the second one should have a wrong token (i.e., one of the tokens you speficied previously in the list INVALID_TOKENS in mock_apn_server).
Running this code you will receive to the client an error message from mockapn for the second packet, but the third push will be never delivered and will be lost even though it was correct.
Ok, let me know if you need any more specific question!
Last thing! I want to add this nice youtube video I foud in an online tutorial (sadly I lost the link to it). In the tutorial the author states that coding a bullet proof APN interface is easy as the action you will see in the video 😀