can't add multicast group - erlang

Trying to add multicast group for ipv6, but it returns error. don't understand the problem. with ipv4 it works fine
(test_client#127.0.0.1)1> {ok, S} = gen_udp:open(3333, [binary, {active, false}, {ip, {65342,0,0,0,0,0,34048,9029}}, inet6, {multicast_loop, false}]).
{ok,#Port<0.1587>}
(test_client#127.0.0.1)4> inet:setopts(S, [{add_membership, {{65342,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}}}]).
{error,einval}
unfortunately this topic in erlang docs is badly documented
also have tried with addrreses like ff3c: , ff32:
UPDATE
i've looked into Erlang/OTP 18.2 source code, there is using function prim_inet:is_sockopt_val(add_membership, {{65280,0,0,0,0,0,34048,9029}, {0,0,0,0,0,0,0,0}})
and it always return false, because in prim_inet:type_value_2/2 we have type ip, value {_,_,_,_,_,_,_,_} and it waits only for ipv4 {_,_,_,_}.
on the one hand i know why can't add membership with ipv6 when open socket, but on other hand what to do is opened question

It doesn't look like Erlang's driver has implemented IPV6_ADD_MEMBERSHIP, but it does have raw support so you could construct it yourself. A problem with this approach is that you are hard coding things usually defined in header files, so your solution wont be very portable.
-module(unssmraw).
-export([test/0]).
test() ->
Port = 57100,
Mad = <<65340:16,0:16,0:16,0:16,0:16,0:16,34048:16,9029:16>>,
Ifindx = <<3:64/native>>,
Ip6 = 41,
Ip6am = 20,
{ok, Sock} = gen_udp:open(Port, [{reuseaddr,true}, inet6, binary]),
R3 = inet:setopts(Sock, [{raw, Ip6, Ip6am, <<Mad/binary, Ifindx/binary>> }]),
io:format("ssm ok? ~w ~n", [R3]),
receive
{udp, S, A, Pr, Pk} -> io:format("watcher sees: Socket ~p Address ~p Port ~p Packet ~p ~n", [S, A, Pr, Pk]) end.
Example test sender:
echo hi | socat - UDP6-SENDTO:\"ff3c::8500:2345\":57100
Example run:
$ erl
Erlang/OTP 19 [erts-8.0.1] [source-761e467] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.0.1 (abort with ^G)
1> unssmraw:test().
ssm ok? ok
watcher sees: Socket #Port<0.453> Address {65152,0,0,0,47734,16383,65066,
19977} Port 43511 Packet <<"hi\n">>
ok
Notes on my hardcoded values
How to find the interface index used in Ifindx:
As of OTP 22 net:if_name2index is available to call. A language neutral description is here. I used a 64-bit since that is the size of an int on my system and it is an int in mreq in my in6.h.)
Ip6's value is from in.h
Ip6am is IPV6_ADD_MEMBERSHIP from in6.h.

Related

Erlang: programmatically get application version

I have an OTP application. The version of this application is found in two places: the src/application_name.src file (standard with OTP applications), and in my rebar.config.
Is there an "official" way for an application to get it's own version, or does this need to be hacked via sed/grep etc? I want to have an "info" endpoint in my application that prints it's own version. Of course I can always do something like grep the version out of my rebar.config, but it seems hacky.
According to the Erlang documentation you can use API of application module.
Example:
Erlang/OTP 19 [erts-8.2.2] [source-1ca84a4] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.2.2 (abort with ^G)
1> application:loaded_applications().
[{stdlib,"ERTS CXC 138 10","3.2"},
{kernel,"ERTS CXC 138 10","5.1.1"}]
2> GetVer =
fun(App) ->
case lists:keyfind(App, 1, application:loaded_applications()) of
{_, _, Ver} ->
Ver;
false ->
not_found
end
end.
#Fun<erl_eval.6.52032458>
3> GetVer(stdlib).
"3.2"
4> GetVer(eunit).
not_found
5> application:load(eunit).
ok
6> GetVer(eunit).
"2.3.2"
7>
If it is properly packaged as an application, you can get it using application:which_applications(). I have some sample code, but basically you'd do something like this:
vsn() -> vsn(your_application_atom_name).
vsn(Application) -> vsn(Application, application:which_applications()).
vsn(_Application, []) -> undefined;
vsn(Application, [{Application,_,Vsn}|_]) -> Vsn;
vsn(Application, [_|Rest]) -> vsn(Application, Rest).
The downside is that you do have to hardcode the name of your application (as an atom). I never found a way around this, but you might be able to cook something up.
application:get_key/1,2 can give you the version number of the application.
1> application:get_key(tfs, vsn).
{ok,"94a3d72"}
2> application:get_key(mnesia, vsn).
{ok,"4.16.1"}

Why does my simple Erlang server not close?

Source file:
-module(biu_server).
-export([start_server/0]).
start_server() ->
{ok, Listen} = gen_tcp:listen(1332,
[binary, {packet, 4},{reuseaddr, true}, {active, true}]),
spawn(fun() -> par_connect(Listen) end).
par_connect(Listen) ->
{ok,Socket} = gen_tcp:accept(Listen),
spawn(fun() -> par_connect(Listen) end),
loop(Socket).
loop(Socket) ->
receive
{tcp, Socket, Request} ->
gen_tcp:send(Socket, term_to_binary(Request)),
loop(Socket);
{tcp_closed, Socket} ->
io:format("Server socket closed~n")
end.
Inside shell:
1> c(biu_server).
{ok,biu_server}
2> biu_server:start_server().
<0.40.0>
3> q().
ok
4> {error_logger,{{2016,1,9},{18,40,28}},"Error in process ~p with exit value:~n~p~n",[<0.40.0>,{{badmatch,{error,closed}},[{biu_server,par_connect,1,[{file,"biu_server.erl"},{line,11}]}]}]}
I want to write a echo server, but when I quit erlang shell, the error_logger is warning badmatch, but the client process is already closed.
Why does my server close fail? What happens?
There are a few wonky things in there. The easiest way to talk through them is probably to just show a different version:
-module(biu_server).
-export([start_server/0,start/0]).
start() ->
spawn(fun() -> start_server() end).
start_server() ->
Options = [list, {reuseaddr, true}],
{ok, Listen} = gen_tcp:listen(1337, Options),
par_connect(Listen).
par_connect(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
% The line below is a whole different universe of confusion for now.
% Get sequential stuff figured out first.
% spawn(fun() -> par_connect(Listen) end),
loop(Socket).
loop(Socket) ->
ok = inet:setopts(Socket, [{active, once}]),
receive
{tcp, Socket, Request} ->
ok = io:format("Received TCP message: ~tp~n", [Request]),
Response = io_lib:format("You said: ~tp\r\n", [Request]),
gen_tcp:send(Socket, Response),
loop(Socket);
{tcp_closed, Socket} ->
io:format("Server socket closed~n");
quit ->
ok = io:format("Fine! I QUIT!~n");
Unexpected ->
ok = io:format("Unexpected message: ~tp~n", [Unexpected]),
loop(Socket)
end.
Note that above I commented out the call to spawn a new process to handle the connection. One of the problems the original version had was that the remaining listener had no way to be terminated because it was always blocking on TCP accept -- forever.
There are also some socket control issues there -- the easiest way around that is to have each listener spawn the next listener and move on to handle its newly acquired connection. Another way is to do what you've done, but there are some details that need to be managed to make it work smoothly. (Example (don't worry, still easy): https://github.com/zxq9/erlmud/blob/master/erlmud-0.1/tcplistener.erl).
I also added two new clauses to the receive in your main loop: one that lets us tell the process to kill itself from within Erlang, and another that handles unexpected messages from within the system. The "Unexpected" clause is important for two reasons: it tells us what is going on (you shouldn't normally be receiving mysterious messages, but it can happen and its not always your fault), and it prevents the process mailbox from stacking up with unmatched-but-unmanageable messages.
Just sticking with the version above, here is what happens during my first session...
In the Erlang shell:
1> c(biu_server).
{ok,biu_server}
2> {Pid, Ref} = spawn_monitor(biu_server, start_server, []).
{<0.40.0>,#Ref<0.0.2.89>}
Received TCP message: "foo\r\n"
Received TCP message: "bar\r\n"
Received TCP message: "Yay! It works!\r\n"
Server socket closed
3> flush().
Shell got {'DOWN',#Ref<0.0.2.89>,process,<0.40.0>,normal}
ok
4> f().
ok
And in a telnet session:
ceverett#changa:~/Code/erlang$ telnet localhost 1337
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
foo
You said: "foo\r\n"
bar
You said: "bar\r\n"
Yay! It works!
You said: "Yay! It works!\r\n"
^]
telnet> quit
Connection closed.
As we can see, the closed connection from the client side terminated as expected. The shell's process was monitoring the TCP server process, so when I flush() at the end we see the 'DOWN' monitor message as expected -- with a normal exit.
Now let's do a similar session, but we'll use the Erlang-side quit message:
5> {Pid, Ref} = spawn_monitor(biu_server, start_server, []).
{<0.43.0>,#Ref<0.0.2.103>}
Received TCP message: "Still works.\r\n"
6> Pid ! "Launch the missiles!".
Unexpected message: "Launch the missiles!"
"Launch the missiles!"
7> Pid ! quit.
Fine! I QUIT!
quit
8> flush().
Shell got {'DOWN',#Ref<0.0.2.103>,process,<0.43.0>,normal}
ok
And on the telnet side:
ceverett#changa:~/Code/erlang$ telnet localhost 1337
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Still works.
You said: "Still works.\r\n"
Connection closed by foreign host.
You notice the "\r\n" in there. That is coming from the client's original message -- all telnet messages are terminated with "\r\n" (so this is what you split the stream on usually -- which is a topic we aren't addressing yet; this code actually is pretending that TCP works like UDP datagrams, but that's not true...). The "\r\n" that are in the server's return message are being interpreted correctly by the telnet client and breaking to the next line.
Writing telnet (or datagram) games is a very pleasant way to explore the Erlang networking modules, by the way.
i solve this question,but i don't know why...
http://erlang.2086793.n4.nabble.com/parallel-tcp-server-closed-once-spawned-td2099538.html
code:
-module(biu_server).
-export([start_server/0,start/0]).
start() ->
spawn(fun() -> start_server() end).
start_server() ->
{ok, Listen} = gen_tcp:listen(1332,
[binary, {packet, 4},{reuseaddr, true}, {active, true}]),
par_connect(Listen).
par_connect(Listen) ->
{ok,Socket} = gen_tcp:accept(Listen),
spawn(fun() -> par_connect(Listen) end),
loop(Socket).
loop(Socket) ->
receive
{tcp, Socket, Request} ->
gen_tcp:send(Socket, term_to_binary(Request)),
loop(Socket);
{tcp_closed, Socket} ->
io:format("Server socket closed~n")
end.
When you call q() from shell, it calls init:stop/0. What it does based on documentation is:
All applications are taken down smoothly, all code is unloaded, and all ports are closed before the system terminates.
When you call start_server/0, it spawns a process and that process opens a port for TCP connection. Because you start your server from inside the shell, so it is linked to the shell, so when the shell gets an exit signal, it sends it again to all the linked processes, then the following error report will be produced by the error_logger module.
1> biu:start_server().
<0.35.0>
2> exit(normal).
=ERROR REPORT==== 9-Jan-2016::16:40:29 ===
Error in process <0.35.0> with exit value: {{badmatch,{error,closed}},[{biu,par_connect,1,[{file,"biu.erl"},{line,12}]}]}
** exception exit: normal
3>
With knowing this, when you call q() before closing the port, all the modules are unloaded and ports are closed one by one, so the unwanted behaviour will result.

How to get Ephemeral port for UDP in Erlang?

I'm trying to find a way to open an ephemeral port (https://en.wikipedia.org/wiki/Ephemeral_port basic one without having to provide a specific port number, and from the ephemeral range of ports). This is for client requests via UDP protocol. I know how to open a specific port for UDP communications via:
{ok,Socket} = gen_udp:open(8000).
But prefer not to have to know an available port number ahead of time and just have the system provide one if this is even possible.
Any suggestion or thought of how best to do this in Erlang?
Do it the same way you would in C: specify port 0.
1> {ok, S1} = gen_udp:open(0).
{ok,#Port<0.541>}
2> {ok, S2} = gen_udp:open(0).
{ok,#Port<0.547>}
3> {ok, S3} = gen_udp:open(0).
{ok,#Port<0.548>}
4> inet:port(S1).
{ok,55398}
5> inet:port(S2).
{ok,44963}
6> inet:port(S3).
{ok,58993}

Does Erlang's open_port call link to resulting process?

I've got some C code that I'm executing as an external process using Erlang's Port capability. I want the process that starts the C code, via open_port, to detect if the C code crashes. The documentation isn't completely clear to me, but as I understand it, a two-way link is established between the Erlang process and the external code. If one dies, the other is notified.
Here is a slightly modified version of the code in the "Erlang Interoperability Tutorial Guide" (http://www.erlang.org/doc/tutorial/c_port.html):
init(ExtPrg) ->
register(cport, self()),
process_flag(trap_exit, true),
Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
PInfo = erlang:port_info(Port),
io:format("Port: ~p PInfo: ~p~n", [Port, PInfo]),
RVal = link(Port),
io:format("link? ~p~n", [RVal]),
loop(Port).
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, encode(Msg)}},
receive
{Port, {data, Data}} ->
Caller ! {cport, decode(Data)}
end,
loop(Port);
stop ->
Port ! {self(), close},
receive
{Port, closed} ->
exit(normal)
end;
{'EXIT', Port, Reason} ->
exit(port_terminated)
end.
The init call correctly executes the C code, and as you can see sets trap_exit, but the EXTT message is not received when I kill the C code using kill -HUP from the Unix shell. I've tried with and without the link call (the Erlang documentation does not use it). The printing code I've added generates:
Eshell V5.9.1 (abort with ^G)
1> cport:start("./cport 22").
Port: #Port<0.630> PInfo: [{name,"./cport 22"},
{links,[<0.38.0>]},
{id,630},
{connected,<0.38.0>},
{input,0},
{output,0}]
<0.38.0>
link? true
It appears that a link is registered but I'm not catching the trap. What am I missing?
Try the extra option exit_status when calling open_port().
I did a similar Erlang program for supervising game servers.
When the external game server crashed I wanted to restart it from my central Erlang monitoring system.
This was the code that worked for me:
erlang:open_port({spawn_executable, "<Path to my game server start script>"},
[ exit_status ]),
When the external process is killed you will get a message of type
{Port,{exit_status,Status}}

Hot code replacement in erlang

I am working on my first real project in erlang, however, this code is simplified for brevity. I want to be able to load a newer version of a file into my project remotely while it's running. I've read about using a behavior like gen_server or gen_fsm which has this for free. While that might achieve the result, I want to use this to learn how to do it, not just get it done. I've read the docs about code replacement, and LYSE's bit about Hot Code Loving, among other things, but I haven't been able to find anything that works for what I'm doing, so here is the basic idea.
-module(reloading).
-export([loop/0]).
loop() ->
receive
upgrade ->
?MODULE:loop();
hello ->
io:format("This is a test~n"),
loop();
_ ->
loop()
end.
I am simply looping with the idea that I can send the message upgrade and it will load a newer version of the code.
$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> c(reloading).
{ok,reloading}
2> Loop = spawn(reloading, loop, []).
<0.39.0>
3> Loop ! hello.
This is a test
hello
At this point I change 10 line to io:format("I have changed this!~n"),
4> Loop ! upgrade.
upgrade
5> Loop ! hello.
This is a test
hello
I am expecting this hello call to print I have changed this! not This is a test. I know I can simply call c(reloading). and have this work the way expected, but I'm looking to send the actual project a message rather than manually updating the code. So where is my disconnect? What am I doing wrong, that I should be doing in order to hot load this code? As mentioned before, I am looking for a non-OTP solution for the sake of education.
For the sake of having an explicit answer, I am posting this.
Using #rvirding's suggestion of using the code module, I've modified it to look like this:
-module(reloading).
-export([loop/0]).
loop() ->
receive
upgrade ->
code:purge(?MODULE),
compile:file(?MODULE),
code:load_file(?MODULE),
?MODULE:loop();
hello ->
io:format("This is a test~n"),
loop();
_ ->
loop()
end.
First code:purge the old ?MODULE, then compile:file the new file, and finally, code:load_file the new ?MODULE.
This works as I originally intended.
$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> Loop = spawn(reloading, loop, []).
<0.34.0>
2> Loop ! hello.
This is a test
hello
Change line to io:format("I have changed this!~n"),
3> Loop ! upgrade.
upgrade
4> Loop ! hello.
I have changed this!
hello
While erlang can handle two versions of a module and calling a function with mod:func(...) will always call the latest version of a module (if the function is exported) you still have to load the new version of the module into Erlang system. You can't expect it automagically detect that you happen to have a new version of the module somewhere, find it, compile it and load it.
N.B. compiling and loading are two separate things. So c(mod). both compiles and loads the module, while l(mod). just loads the object code (.beam file) of the already compiled module. The Erlang compiler is called from the module compile and it just compiles and generates a .beam file while the code loading is handled by the module code.
In addition to the above I'd like to notice that some tools that reload code automatically for you exist.
You should have a look at sync or active projects.
Compile *.beam locally, then send it to your server and reload it as mentioned in man pages:
http://erlang.org/documentation/doc-1/reference_manual/code_loading.html#id86381
-module(m).
-export([loop/0]).
loop() ->
receive
code_switch ->
m:loop();
Msg ->
...
loop()
end.

Resources