How can I send messages to an existing Unix socket from Erlang? - 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).

Related

Modem AT commands, unable to get into data mode (PPP)

I have a simcom7600 modem which I am trying out via AT commands.
I was able to use AT commands to setup the modem, and connect to an MQTT broker and exchange messages. Now I am trying to figure out how I can do something similar, but then with my own TCP/IP stack. Before diving into the deep there, I would like to confirm that I can get into data mode (PPP) which I am not able to, it seems.
I attached my modem (AT+CGATT=1), and activated it (AT+ACACT=1,1). I verified that I have a carrier/provider (AT+COPS?).
So I thought I was all set to send the ATO (online) commands. But it returns NO_CARRIER every time I try. I have no idea what I am doing wrong.
The logging that confirms above statements:
AT+COPS?
Sending command: AT+COPS?
AT+COPS?[CR][CR][LF]+COPS: 0,0,"NL KPN simyo",7[CR][LF][CR][LF]OK[CR][LF]
AT+cgatt?
Sending command: AT+cgatt?
AT+cgatt?[CR][CR][LF]+CGATT: 1[CR][LF][CR][LF]OK[CR][LF]
AT+cgact?
Sending command: AT+cgact?
AT+cgact?[CR][CR][LF]+CGACT: 1,1[CR][LF]+CGACT: 2,0[CR][LF]+CGACT: 3,0[CR][LF][CR][LF]OK[CR][LF]
ATO
Sending command: ATO
ATO[CR][CR][LF]NO CARRIER[CR][LF]
PS: the [CR][LF] stand for resp. \r and \n, I replace them before I log for ease of reading.
I obviously have to supply more info to the modem, but from this manual I can't seem to figure out which commands I miss, and how I could validate step by step that I am on the right track.
I found this nice document. I'll share it here in case somebody else struggles with this as well.
When I send the following commands:
ATZ (reset)
ATE0 (disable echo)
AT+CGREG? (check registration to PDP network)
AT+CGDCONT=1,"IP","internet" (set APN for my provider, they expect the string "internet")
ATD*99# (start data mode, aka PPP)
then I can break out and move back into PPP with the following commands:
+++ (send + character, wait for 700ms, send + character, wait for 700ms, send + character) => back to AT command mode
ATO (back to data mode)
NOTE: the APN your provider expects, is I think in all cases an easy Google. Your provider will most likely explain how to manually set your APN in case your phone won't do it automatically.

How To Use Erlang ssl:close/2

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"),

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);

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!

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