How To Use Erlang ssl:close/2 - erlang

I have an SSL server, and I want to downgrade this after receiving the first ssl:recv to a raw gen_tcp. Assuming this can be used to do that I can not find an example on how to use this. And I am not so good at using the Erlang/OTP documentation yet http://erlang.org/doc/man/ssl.html#close-2
I am a bit confused with NewController::pid() from the documentation:
How = timeout() | {NewController::pid(), timeout()}

NewController::pid() here refers to the process you want to set as the "controlling process" for the downgraded TCP socket. gen_tcp functions on the socket will only work if called from that process. You'll want to send self() here unless you want to use the downgraded TCP socket from another process.
The only example I could find of ssl:close/2 being used with a tuple as the second argument is this test. Here's a simplified version of that code to get you started:
% Assuming `SSLSocket` is the SSL socket.
{ok, TCPSocket} = ssl:close(SSLSocket, {self(), 10000}),
% You can use `TCPSocket` with `gen_tcp` now.
gen_tcp:send(TCPSocket, "foo"),

Related

How can I send messages to an existing Unix socket from Erlang?

I see that gen_udp has support for Unix sockets, and this example shows creating an using one in Erlang.
I want to send messages to an existing Unix socket (to control mpv via its JSON IPC interface). I see there was a self-answered question on the Erlang mailing list about this, but the answer doesn't make sense to me, as Sock2 is used without previous assignment.
I see in the gen_udp docs this option:
{fd, integer() >= 0}
If a socket has somehow been opened without using gen_udp,
use this option to pass the file descriptor for it.
But when I try to open the socket as a file with file:open/2, I get {error,eopnotsupp}.
How can I send messages to an existing Unix socket?
Answer for my case
This will not be a canonical and thorough answer, because I'm not super familiar with sockets. However, I emailed Joe from the mailing list link above, and he said:
As far as I understand, the unix socket type to erlang module mapping
is as follows:
SOCK_STREAM -> gen_tcp
SOCK_DGRAM -> gen_udp
SOCK_SEQPACKET -> gen_sctp
He suggested using gen_tcp:connect in my case, and it worked! Apparently, mpv created a SOCK_STREAM socket.
So, having started mpv like:
mpv /Users/me/playlist.m3u --input-ipc-server=/tmp/mpv.sock --idle yes --no-audio-display
... so that it expects commands on the socket /tmp/mpv.sock, I could send it a "play a different playlist" command like this in erl:
{ok, Port} = gen_tcp:connect({local, "/tmp/mpv.sock"}, 0, [local]).
Msg = "{ \"command\": [\"loadlist\", \"/Users/me/playlist2.m3u\", \"replace\"] }\n".
gen_tcp:send(Port, Msg).

Erlang and wavecom

I want to create something similar to Kannel, for my wavecom GSM modem using Erlang.
I found a erlang-serial project in Github, but it seems there isn't any easy tutorial for a newbee like me.
I really need an Erlang lib that can send data to a serial port and sending AT command to my GSM modem.
Please help.
erlang-serial has pretty easy example in terminal.erl, basically you start the connection:
SerialPort = serial:start([{speed,Speed},{open,?DEVICE}]),
serial_listener()
Where ?DEVICE is path to linux device in /dev and serial_listener is a receive-loop like this:
serial_listner() ->
receive
{data, Bytes} ->
%% Do something with bytes
serial_listner()
end.
And to send data you just send message to that process:
SerialPort ! {send, Bytes}
That's it!

Erlang Bit Syntax pattern matching works in shell but not as passed argument

I am trying to make a simple UDP packet decoder.
packet_decoder(Packet)->
<<Opts:8,MobIdLength:8,MobId:64,MobIdType:8,MgeType:8,SeqNum:16,Rest/binary>> = Packet,
io:format("Options:~p~n",Opts),
io:format("MobIdLength:~p~n",MobIdLength),
io:format("MobId:~p~n",MobId),
io:format("MobIdType:~p~n",MobIdType),
io:format("MgeType:~p~n",MgeType),
io:format("SeqNum:~p~n",SeqNum).
Packet is passed by a receive loop:
rcv_loop(Socket) ->
inet:setopts(Socket, [{active, once}, binary]),
io:format("rcvr started:~n"),
receive
{udp, Socket, Host, Port, Bin} ->
packet_decoder(Bin),
rcv_loop(Socket)
end.
I keep getting(following error edited 9/7/12 9:30 EST):
** exception error: no match of right hand side value
<<131,8,53,134,150,4,149,0,80,15,1,2,1,2,0,16,80,71,115,
52,80,71,115,53,24,63,227,197,211,...>>
in function udp_server:packet_decoder/1
called as udp_server:packet_decoder(<<131,8,53,134,150,4,149,0,80,15,
1,2,1,2,0,16,80,71,115,52,80,71,
115,53,24,63,227,197,...>>)
in call from udp_server:rcv_loop/1
in call from udp_server:init/0
If I create the same variable in the Erlang shell as a binary, i.e.
Packet = <<131,8,53,134,150,4,149,0,80,15,1,2,1,2,0,16,80,71,115,52,80,71,115,53,24,63,227,197,211,228,89,72,0,0,0,0,0,0,0,16,0,5,5,32,1,4,255,159,15,18,28,0,34,62,2,0,0,0,0,0,0,0,47,67>>.
<<Opts:8,MobIdLength:8,MobId:64,MobIdType:8,MgeType:8,SeqNum:16,Rest/binary>> = Packet.
It works just fine. Is there some subtlety in passing this to a function that I am missing? I have tried what I think is everything(except the right way). I tried setting the type and size. I also just tried
<<Rest/binary>> = Packet.
To no avail. Any help much appreciated.
The error you are getting when you run your code does not match your code. The error you are getting:
** exception error: no match of right hand side value ...
is a badmatch error and comes from an explicit = match where the pattern does not match the value from the RHS. There is no = in the code for rcv_loop/1. This implies that the loop you are running is not this code. So there are some questions to be asked:
When you have recompiled the module containing rcv_loop/1 have you restarted the loop so you run the new code? This is not done automagically.
Are you sure you are loading/running the code you think you are? I know this question sounds stupid but it is very easy, and not uncommon, to work on one version of the code and load another. You need to get the paths right.
The other things about mentioned about your code would not give this error. The calls to io:format/2 are wrong but would result in errors when you make the actual calls to io:format/2. Using the variable Socket as you do is not an error, it just means that you only want to receive UDP packets from just that socket.
EDIT : the first part of my answer was completely wrong so in order to not mislead, I deleted it.
Like spotted Alexey Kachayev io:format takes as second parameter a list, so :
packet_decoder(Packet)->
<<Opts:8,MobIdLength:8,MobId:64,MobIdType:8,MgeType:8,SeqNum:16,Rest/binary>> = Packet,
io:format("Options:~p~n",[Opts]),
io:format("MobIdLength:~p~n",[MobIdLength]),
io:format("MobId:~p~n",[MobId]),
io:format("MobIdType:~p~n",[MobIdType]),
io:format("MgeType:~p~n",[MgeType]),
io:format("SeqNum:~p~n",[SeqNum]).
I figured it out(kinda). I had been working on this in erlide in eclipse which had worked fine for all of the other parts of the. I tried compiling it from the erl shell and it worked fine. There must be some minor difference in the way eclipse is representing the source or the way it invokes the erlang compiler and shell. I will take it up with erlide.org. Thanks for the help!

Can my gen_server become a bottleneck?

I'm currently writing a piece of software in erlang, which is now based on gen_server behaviour. This gen_server should export a function (let's call it update/1) which should connect using ssl to another service online and send to it the value passed as argument to the function.
Currently update/1 is like this:
update(Value) ->
gen_server:call(?SERVER, {update, Value}).
So once it is called, there is a call to ?SERVER which is handled as:
handle_call({update, Value}, _From, State) ->
{ok, Socket} = ssl:connect("remoteserver.com", 5555, [], 3000).
Reply = ssl:send(Socket, Value).
{ok, Reply, State}.
Once the packet is sent to the remote server, the peer should severe the connection.
Now, this works fine with my tests in shell, but what happens if we have to call 1000 times mymod:update(Value) and ssl:connect/4 is not working well (i.e. is reaching its timeout)?
At this point, my gen_server will have a very large amount of values and they can be processed only one by one, leading to the point that the 1000th update will be done only 1000*3000 milliseconds after its value was updated using update/1.
Using a cast instead of a call would leave to the same problem. How can I solve this problem? Should I use a normal function and not a gen_server call?
From personal experience I can say that 1000 messages per gen_server process wont be a problem unless you are queuing big messages.
If from your testing it seems that your gen_server is not able to handle this much load, then you must create multiple instances of your gen_server preferably under a supervisor process at the boot time (or run-time) of your application.
Besides that, I really don't understand the requirement of making a new connection for each update!! you should consider some optimization like cached connections/ pre-connections to the server..no?

How to filter messages in Ejabberd

I have Ejabberd up and running with test users, and its working fine. I want to write a module that can intercept messages and modify them, as follows :
intercept "messages"
send them to a php file
get the result from the same php file (immediate)
Modify the message stanza and send it down the wire to the recipient
The ejabberd documentation is weak and tutorials are non-existent. Can you give me some sample code that does this. I can then figure how to configure it for my needs.
Thanks a bundle!
Adil
Here's the basic example of such module:
-module(packet_interceptor).
-behaviour(gen_mod).
-export([start/2,
stop/1]).
-export([on_filter_packet/1]).
start(Host, _Opts) ->
ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 0).
on_filter_packet({From, To, XML} = Packet) ->
%% does something with a packet
%% should return modified Packet or atom `drop` to drop the packet
Packet.
And make sure to add this module into ejabberd's configuration into module section:
{modules,
[...
...
...
{packet_interceptor, []}
]}.
Just extend on_filter_packet/1 the way you want and return appropriately modified packet.
gleber's example is excellent. I also wrote a more complex example of packet manipulation that I built for Chesspark called
mod_sunshine.
How can send this XML data to php (via ?xml=) and retrieve the resulting XML and then pass it to the recipient?
If you have a recent version of ejabberd that uses exmpp, you can use exmpp_xml:node_to_binary/1 or exmpp_xml:node_to_list/1 to turn the internal representation of the XML to a binary or a string respectively.
There were similarly named functions in the older ejabberd, but within the xml module.
It seems that what you want to do there is to create an XMPP server component. Lots of things has already been said on that post Which XMPP server to experiment developing a server component.
I can link you some useful links:
Jabber Component Protocol
An Echo-Bot in Python from metajack.im, a very nice blog from an XMPP guru. This bot listen for any message stanzas and reply to some of them.
Gleber's solution is really "ejabberd" oriented (certainly the easiest one in your case), whereas this one can scale with other XMPP servers.
There is the interface:
ejabberd_router:register_route(MyHost)
which I have used in the past and works well. Once the MyHost is registered with ejabberd, the module will receive the communications intended to MyHost through info messages (assuming gen_server).
As noted by #gleber, don't forget to add your module to the configuration file.

Resources