How to send a push notification using Erlang? - erlang

I'm trying to send a push notification to APNs using Erlang.
This is the code I came up with so far:
-module(apnstest2).
-export([connect/0]).
connect() ->
application:start(ssl),
ssl:seed("someseedstring"),
Address = "gateway.sandbox.push.apple.com",
Port = 2195,
Cert = "/path/to/Certificate.pem",
Key = "/path/to/Key.unenc.pem",
Options = [{certfile, Cert}, {keyfile, Key}, {mode, binary}],
Timeout = 1000,
{ok, Socket} = ssl:connect(Address, Port, Options, Timeout),
Token = "195ec05a962b24954693c0b638b6216579a0d1d74b3e1c6f534c6f8fd0d50d03",
Payload = "{\"aps\":{\"alert\":\"Just testing.\",\"sound\":\"chime\", \"badge\":10}}",
TokenLength = length(Token),
PayloadLength = length(Payload),
Packet = [<<0:8, TokenLength, Token, PayloadLength, Payload>>],
ssl:send(Socket, list_to_binary(Packet)),
ssl:close(Socket).
The code doesn't take advantage of Erlang's concurrency but is just a prototype. I only want to test if I can send the push in the most simple way.
I think the problem is in the packet being sent to the APNs.
This is the binary format of a push notification:
alt text http://developer.apple.com/IPhone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Art/aps_provider_binary.jpg
How should I create such a packet in Erlang?
Could someone please take a look at my code and tell me where the problem is?
Also I used Erlang's SSL application to create the connection and send the data and I don't know if this is the problem or the packet.
Thanks!

To start with, there is no need for creating a list of a single binary and then calling list_to_binary/1 on it. You can just send the binary itself.
Also, make sure the field lengths and values are appropriate according to the protocol:
TokenLength = 32 = length(Token),
Packet = <<0:8, TokenLength:16/big, Token, PayloadLength:16/big, Payload>>,
ssl:send(Socket, Packet),
Now that we have gotten this far, we will see that length(Token) is in fact 64, not 32:
You forgot to convert the hex string for Token to a binary, so you are sending a 64 byte hex character string instead of 32 binary bytes.
So... making Payload a binary from the start, and making Token a numeric constant, you can do something like the following:
Payload = <<"{\"aps\":{\"alert\":\"Just testing.\",\"sound\":\"chime\", \"badge\":10}}">>,
PayloadLength = size(Payload),
Packet = <<0:8, 32:16/big,
16#195ec05a962b24954693c0b638b6216579a0d1d74b3e1c6f534c6f8fd0d50d03:256/big,
PayloadLength:16/big, Payload/binary>>,
ssl:send(Socket, Packet),
Thanks to Christian for pointing out a number of mistakes in the former revisions of this answer.

I see two mistakes:
Token should be passed in binary and not in hex ascii.
You can't use the binary syntax to turn lists into binaries.
For parsing hex to an integer and then down to binary use something like this:
Token = "dead",
TokenNum = erlang:list_to_integer(Token, 16),
TokenBin = <<TokenNum:32/integer-unit:8>>,
Build the protocol packet with something like this:
TokenBin = ...,
Payload = <<"Payload">>,
PayloadSize = byte_size(Payload),
Packet = <<0:8, 32:16, TokenBin/binary, PayloadSize:16, Payload/binary>>,

Try use a simple library epns(Erlang Push Notifications)
This library can send push notification as APNS and FCM by Erlang side. How use epns(Erlang Push Notifications) library - you can read in README.md. This liblary can used as 3-rd party in project, or you can run it locally for see how this library works:
$ git clone https://github.com/vkatsuba/epns.git
$ cd epns
$ make
Retested on Erlang 20~21

Related

How to create a custom JMeter Pre-Processor to convert a json payload into MQTT Binary packet

I need a JMeter Pre Processor which will convert a JSON String into a MQTT packet i.e binary data. The binary data will then be sent over the web socket using the JMeter web socket plugin - https://github.com/ptrd/jmeter-websocket-samplers
I am relatively new to JMeter and would appreciate any help on this. Please refer to my earlier question for the project scenario :
Testing a MQTT Client using JMeter
You kindly provided the link to the documentation which says:
The request-response sampler, as well as the single-read and single-write samplers, support both text and binary frames. For binary frames, enter the payload in hexadecimal format, e.g. 0xca 0xfe or ba be
So
Text data can be sent as they are (JSON is more or less plain text)
Binary (non-text) data needs to be converted to hex first
So you need to determine what exactly you need because your current requirement is a little bit vague and contraversial.
If you're looking for a function to convert string to hex - you can go for JSR223 PreProcessor and something like:
def hex(byte[] data) {
def rv = new StringBuilder();
data.each { aByte ->
rv.append('0x').append(String.format("%02x", aByte)).append(' ');
}
return rv.toString();
}
Demo:
More information on Groovy scripting in JMeter: Apache Groovy - Why and How You Should Use It

change trace log format in emqtt message broker

I am using emqtt message broker for mqtt.
I am not a erlang developer and has zero knowledge on that.
I have used this erlang based broker, because after searching many open source broker online and suggestions from people about the advantage of erlang based server.
Now i am kind of stuck with the out put of the emqttd_cli trace command.
Its not json type and if i use a perl parser to convert to json type i am getting delayed output.
I want to know, in which file i could change the trace log output format.
I looked on the trace code of the broker and found a file src/emqttd_protocol.erl. An exported function named trace/3 has the code that you need.
Second argument of this function, named Packet, has the information of receive & send data via broker. You can fetch required data from it and format according to how you want to print.
Edit : Sample modified code added
trace(recv, Packet, ProtoState) ->
PacketHeader = Packet#mqtt_packet.header,
HostInfo = esockd_net:format(ProtoState#proto_state.peername),
%% PacketInfo = {ClientId, Username, ClientIP, ClientPort, Payload, QoS, Retain}
PacketInfo = {ProtoState#proto_state.client_id, ProtoState#proto_state.username, lists:nth(1, HostInfo), lists:nth(3, HostInfo), Packet#mqtt_packet.payload, PacketHeader#mqtt_packet_header.qos, PacketHeader#mqtt_packet_header.retain},
?LOG(info, "Data Received ~s", [PacketInfo], ProtoState);

Apple Push Notifications (APN) service server side Python 2 script in iOS

I have configured my iOS application with Apple Push Notification (APN) service enabled. I was able to send notifications to devices with PHP and Python 3 scripts. I tested both on local server with local machine. But now I need to write the script in Python2.
Below is the script I've written and when I run this I get nothing. Neither a notification to my device nor error in command line.
import socket, ssl, json, struct
import binascii
import os
deviceToken = 'my_device_tocken_without_spaces'
thePayLoad = {
'aps': {
'alert':'My first push notification!',
'sound':'default'
}
}
theCertfile = 'ck3_2.pem'
theHost = ( 'gateway.sandbox.push.apple.com', 2195 )
data = json.dumps( thePayLoad )
theFormat = '!BH32sH%ds' % len(data)
theNotification = struct.pack( theFormat, 0, 32, deviceToken, len(data), data )
ssl_sock = ssl.wrap_socket( socket.socket( socket.AF_INET, socket.SOCK_STREAM ), certfile = theCertfile )
ssl_sock.connect( theHost )
ssl_sock.write( theNotification )
ssl_sock.close()
What did I miss? How can I check where is the mistake happen?
I ran PHP script in localhost using XAMPP and I ran Python script in command line because I was unable to set-up Python with XAMPP which I already posted a question here.
you may consider https://github.com/djacobs/PyAPNs that wrapped lot of useful features, including:
error handling
support enhanced message format and auto resend messages which are sent before error response
non-blocking ssl socket connection with great performance
I think there's nothing wrong with your code. You can try adding following lines after ssl_sock.connect( theHost )
print repr(ssl_sock.getpeername())
print ssl_sock.cipher()
print pprint.pformat(ssl_sock.getpeercert())
Which will print information about ssl of your connection.
Alternatively you can create a sample server and change the connections in your client and test against the server. http://carlo-hamalainen.net/blog/2013/1/24/python-ssl-socket-echo-test-with-self-signed-certificate
You imported binascii, but you forgot to use it.
Convert the token and json data to byte arrays, e.g.:
deviceToken = binascii.a2b_hex('my_device_tocken_without_spaces')
and
data = json.dumps(thePayLoad, separators=(',', ':'), ensure_ascii=False).encode('utf-8')

Measuring data traffic flow over server/client socket in delphi?

i am making a program that sends data between a server program and its clients. They all use the server and client socket components found in Delphi! I have looked on the Internet and cannot find a way on how to measure how much data has been transferred through a socket!
Any help, especially some code (pascal/Delphi), would be very much appreciated!
here you have a full example http://delphi.about.com/od/fullcodeprojects/l/aa112903a.htm
If you use win/*nix API sockets (not a special libraries) you have to count returns from recv and send functions.
total_data = 0;
...
...
get_data = recv(...)
total_data = total_data + get_data
...
send_data = send(...)
total_data = total_data + send_data
Magenta Systems has a free set of components that can monitor network traffic using either raw sockets or WinPcap.
Update:
From your comment to RBA's response: The Magenta components let you identify and differentiate between different IP addresses and services (ports).
I keep stats on all my TCP traffic to the byte. Every time I send data I update the stats and every time I receieve data I update the stats. This is accurate to one byte and requires only a few lines of code. And it does not rely on any particular TCP components. Why is doing it this way so hard?

Encoding a JMS TextMessage

I'm receiving messages from a JMS MQ queue which are supposedly utf-8 encoded. However on reading the out using msgText = ((TextMessage)msg).getText();
I get question marks where non standard characters were present. It seems possible to specify the encoding when using a bytemessage, but I cant find a way to specify encoding while reading out the TextMessage. Is there a way to solve this, or should I press for bytemessages?
We tried adding Dfile.encoding="UTF-8" to Websphere's jvm and we added
source = new StreamSource(new ByteArrayInputStream(
((TextMessage) msg).getText().getBytes("UTF-8")));
In our MessageListener. This worked for us, so then we took out the Dfile.encoding bit away and it still works for us.
Due to preferred minimum configuration for Websphere we decided to leave it this way, also taking into account that we may easier switch the UTF-8 string by a setting from file or database.
If the text is not decoded correctly, then probably the client is not sending the message with the utf-8 codec; this should work:
byte[] by = ((TextMessage) msg).getText().getBytes("ISO-8859-1");
String text = new String(by,"UTF-8");

Resources