Copying files from one server to other via erlang code - erlang

I want to copy files from one server(Say A) to other(Say B).Scenerio is->User sends me a file(video,zip or photo) in binary.I write this to /var/www/myfolder of A.Now in next step i want this to be copied at B.I used os:cmd(scp ----) command.But it gives error like->
Permission denied, please try again.
Permission denied, please try again.
Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
I think it is asking for password of B.How can i configure password in scp command or is there any other method to do this in erlang?

You can use Erlang File I/O if you have both servers connected using erlang distribution protocol. (You can do it over TCP or UDP or any other networking as well but it is more complicated).
Let's demonstrate it using two "servers" running on the same machine (it works same over a network, but you have to connect them properly). First we make directory for each server and content of file foo to transfer:
$ mkdir a b
$ echo Hello World > a/foo
Let's start two servers each in a different directory:
$ cd a
a$ erl -sname a
Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V7.0 (abort with ^G)
(a#hynek-notebook)1>
and the second server in a different console:
$ cd b
b$ erl -sname b
Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V7.0 (abort with ^G)
(b#hynek-notebook)1>
Now we check there is nothing on the b server yet:
(b#hynek-notebook)1> ls().
ok
(b#hynek-notebook)2>
Now we can connect nodes, check if they are connected and read the file foo.
(a#hynek-notebook)1> net_kernel:connect('b#hynek-notebook').
true
(a#hynek-notebook)2> net_adm:ping('b#hynek-notebook').
pong
(a#hynek-notebook)3> ls().
foo
ok
(a#hynek-notebook)4> {ok, Bin} = file:read_file("foo").
{ok,<<"Hello World\n">>}
(a#hynek-notebook)5>
And write file to server b using rpc:call/4:
(a#hynek-notebook)5> rpc:call('b#hynek-notebook', file, write_file, ["bar", Bin]).
ok
(a#hynek-notebook)6>
Check the result on the server b:
(b#hynek-notebook)2> ls().
bar
ok
(b#hynek-notebook)3> {ok, Bin} = file:read_file("bar").
{ok,<<"Hello World\n">>}
(b#hynek-notebook)4>
For bigger files, you should not transfer a whole file in the one big binary. Unfortunately, you need at least some code support from sending or receiving side. You can transfer file handler from one node to another but the process which calls file:open/2 has to keep running. It is reason you can't just use {ok, FH} = rpc:call(Node, file, open, [FN, [write]]). It's a bummer. One way is to make a very simple server which opens a file and keeps running.
(b#hynek-notebook)4> Self = self().
<0.40.0>
(b#hynek-notebook)5> F = fun() -> Self ! file:open("baz", [write]), receive close -> ok end end.
#Fun<erl_eval.20.54118792>
(b#hynek-notebook)6> FS = spawn_link('a#hynek-notebook', F).
<7329.48.0>
(b#hynek-notebook)7> {ok, FH} = receive X -> X end.
{ok,<7329.49.0>}
(b#hynek-notebook)8> file:write(FH, Bin).
ok
(b#hynek-notebook)9> FS ! close.
close
(b#hynek-notebook)10>
And we expect file baz with proper content on the server a:
(a#hynek-notebook)6> ls().
baz foo
ok
(a#hynek-notebook)7> {ok, _} = file:read_file("baz").
{ok,<<"Hello World\n">>}
(a#hynek-notebook)8>
The other option is to write a server which will receive blocks and write them instead of sending a file handler. And there are many other options how to do it using direct TCP connection using HTTP or your own protocol and using file:send_file/2,5 and many other ways.

Related

How do unix domain sockets work in Erlang 19

I tried a few things but I'm not able to read anything from them
{ok, Port} = gen_udp:open(0, [{ifaddr,{local,"/tmp/socket2"}}]).
Then I switch to console.
echo "hi" | socat - UNIX-CONNECT:/tmp/socket2
Back to erlang
41> gen_udp:recv(Port, 2, 5000).
{error,timeout}
Any help is appreciated. I've also tried {active, true} opt and flush(). shows nothing.
I've not tried the official release 19, but I can make it work using the latest git (as of July 7th) by:
disabling active with {active, false}
using UNIX-SENDTO instead of UNIX-CONNECT
binding socat's socket to its own address (not binding creates an error on erlangs side when resolving the address.)
Demonstration:
console 1:
$ rm /tmp/socket*
$ erl
Erlang/OTP 19 [erts-8.0.1] [source-ca40008] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.0.1 (abort with ^G)
1> {ok, Port} = gen_udp:open(0, [{active, false},{ifaddr, {local,"/tmp/socket2"}}]),
1> io:format("ok~w ~w~n", [ok,Port]),
1> gen_udp:recv(Port, 2).
okok #Port<0.451>
console 2:
$ echo "hi" | socat - UNIX-SENDTO:/tmp/socket2,bind=/tmp/socket1
console 1 results:
okok #Port<0.451>
{ok,{{local,<<"/tmp/socket1">>},0,"hi\n"}}

Why does net_kernel:monitor_nodes/2 not deliver nodeup/nodedown messages for sname nodes?

I start up a master node with a short name and get it running a process to monitor for node up and down messages.
> erl -sname master -cookie monster
Erlang R15B03 (erts-5.9.3) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false] [dtrace]
Eshell V5.9.3 (abort with ^G)
(master#pencil)1> c("/tmp/monitor.erl").
{ok,monitor}
(master#pencil)2> Pid = monitor:start().
<0.44.0>
(master#pencil)3> Pid ! running.
RECV :: running
running
(master#pencil)4> net_adm:names().
{ok,[{"master",52564}]}
At this point only the master node is running. I startup the second node on the same machine:
> erl -sname client -cookie monster
Erlang R15B03 (erts-5.9.3) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false] [dtrace]
Eshell V5.9.3 (abort with ^G)
(client#pencil)1>
and wait for a minute, just incase I'm reading the docs wrong and there's a complication with the net tickrate. Nothing, so on master I force the connection:
(master#pencil)5> net_adm:names().
{ok,[{"master",52564},{"client",52579}]}
(master#pencil)6>
and nothing from my little monitor process. Now, if I do the same thing but use long names--that is -name--this works just fine. I'm surprised, though, as the net_kernel docs don't mention that. What's the deal?
Here's the monitor.erl referenced above:
-module(monitor).
-export([start/0]).
start() ->
spawn_link(fun init_loop/0).
%%%===================================================================
%%% Internal Functions
%%%===================================================================
init_loop() ->
net_kernel:monitor_nodes(true, []),
loop().
loop() ->
receive
Msg -> io:format(user, "RECV :: ~p~n", [Msg])
end,
loop().
net_kernel:monitor_nodes/2 definitely does deliver nodeup/nodedown messages for nodes with either short and long names.
However, the nodeup message is only delivered when the node is connected, as mentioned in the documentation. Why you got the nodeup message with -name is a mystery (and couldn't be reproduced here) as net_adm:names/0 does not connect nodes at all. It only connects to epmd to obtain the list of locally registered nodes. It will even list nodes with a different cookie.
If you connect the client to the master (or the other way around) with net_adm:ping/1 (or an rpc call), the monitoring process will receive the nodeup message.

Erlang UDP packet not received

I'm trying to get a client (behind a NAT) to send packet to a dedicated server.
Here's my code :
-module(udp_test).
-export([start_client/3, listen/1, send/4, start_listen/1]).
start_client(Host, Port, Packet) ->
{ok, Socket} = gen_udp:open(0, [{active, true}, binary]),
io:format("client opened socket=~p~n",[Socket]),
spawn(?MODULE, send, [Socket, Host, Port, Packet]).
start_listen(Port) ->
{ok, Socket} = gen_udp:open(Port, [binary]),
spawn(?MODULE, listen, [Socket]).
listen(Socket) ->
inet:setopts(Socket, [{active, once}]),
receive
{udp, Socket , Host, Port, Bin} ->
gen_udp:send(Socket, Host, Port, "Got Message"),
io:format("server received:~p / ~p~n",[Socket, Bin]),
listen(Socket)
end.
send(Socket, Host, Port, Packet) ->
timer:send_after(1000, tryToSend),
receive
tryToSend ->
io:fwrite("Sending: ~p / to ~p / P: ~p~n", [Packet, Host, Port]),
Val = gen_udp:send(Socket, Host, Port, Packet),
io:fwrite("Value: ~p~n", [Val]),
send(Socket, Host, Port, Packet);
_ ->
io:fwrite("???~n")
end.
on the dedicated server I launch the listen function :
# erl -pa ebin
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:4:4] [async-threads:0] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> udp_test:listen(4000).
on the client side I launch the sending loop :
$ erl -pa ebin
Erlang R15B (erts-5.9) [source] [smp:2:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9 (abort with ^G)
1> udp_test:start_client("ip.of.my.server", 4000, "HELLO !!!").
client opened socket=#Port<0.737>
<0.33.0>
Sending: "HELLO !!!" / to "ip.of.my.server" / P: 4000
Value: ok
Sending: "HELLO !!!" / to "ip.of.my.server" / P: 4000
Value: ok
Sending: "HELLO !!!" / to "ip.of.my.server" / P: 4000
Value: ok
Although gen_udp:send from the client returns ok, the server doesn't seems to receive any of these packets, as it should print "server received: "HELLO !!!"" on the console.
anyone would have an idea why this is not working.
EDIT 1 :
There is no firewall or iptable configured on the dedicated server.
The connection works fine through TCP between the client and the server, but not UDP.
When I try to run both server and client on the same device (different erlang node), it does not work either.
EDIT 2 :
changed the code for the listen part looping on itself re-creating the Socket each time a message is received... but still does not work.
Your start_client/3, send/4 loop should work as expected, although it is a slightly convoluted way to get a 1 sec delay.
Your listen/1 will not do as expected and should at most return one message:
For each loop it opens a new socket, the first time it uses the port to open the socket while in the following loops it uses the socket to open a new socket, which should generate an error.
You set the socket to {active,once} so you will at most receive one packet on the socket before you reset it to being active once.
Why try on the receiving side doing something simple like:
Erlang R15B (erts-5.9) [source] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9 (abort with ^G)
1> {ok,S}=gen_udp:open(5555,[]).
{ok,#Port<0.582>}
2> flush().
Shell got {udp,#Port<0.582>,{127,0,0,1},4444,"hej"}
Shell got {udp,#Port<0.582>,{127,0,0,1},4444,"there"}
ok
3>
as a first step to test the basic connection?
EDIT:
In your new version you call start_listen/1 which opens a UDP socket and then spawns a process to sit and listen on it. The process which opens the port is the ports controlling process. The messages sent when a packet arrives is sent to the controlling process, which in this case is not the controlling process.
There are two ways to fix this:
Spawn a process which first opens the port and and then goes into a loop receiving the UDP messages from the socket. This is how it is done in the example you referenced: start spawns a process running server which opens the port and then calls loop.
Use gen_udp:controlling_process/2 to pass control of the socket to the loop process so it will receive the packet messages.
Both work and have their place. You had the same structure in the original code but I missed it.
Found the issue, I was starting the socket, then only spawning the loop...
Either change the controlling_process to the spawned pid, or open the socket on the spawned pid.
Hope it helps someone.

Erlang. Start remote shell error

I tried to start remote shell and get a following error:
*** ERROR: Shell process terminated! (^G to start new job) ***
Details:
1. Start erlang on a computer a2-x201:
erl -sname a#a2-x201
Erlang R14B (erts-5.8.1) [source] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.8.1 (abort with ^G)
(a#a2-x201)1> nodes().
[]
Start erlang on a computer a2-asrock
erl -sname b#a2-asrock
Establish link between nodes using computer a2-x201:
(a#a2-x201)2> net_adm:ping('b#a2-asrock').
pong
(a#a2-x201)3> nodes().
['b#a2-asrock']
Everything looks ok at the moment.
Starting remote shell on a2-asrock from a2-x201
CTRL+ G
-->r 'b2#a2-asrock'
-->j
1 {shell,start,[init]}
2* {'b2#a2-asrock',shell,start,[]}
-->c
* ERROR: Shell process terminated! (^G to start new job) *
What is wrong?
You are doing remoting on 'b2#a2-asrock' instead of 'b#a2-rock' which is the name of the created node. You're pinging 'b#a2-asrock' but you're trying to connect to 'b2#a2-asrock' instead. Seems that you have a typo in there.

mnesia save out info

how to save mnesia:info() output?
I use remote sh in unix screen and can't to scroll window
Here's a function that you can put in the user_default.erl module on the remote node:
out(Fun, File) ->
G = erlang:group_leader(),
{ok, FD} = file:open(File, [write]),
erlang:group_leader(FD, self()),
Fun(),
erlang:group_leader(G, self()),
file:close(FD).
Then, you can do the following (after recompiling and loading user_default):
1> out(fun () -> mnesia:info() end, "mnesia_info.txt").
Or, just cut-and paste the following into the shell:
F = fun (Fun, File) ->
G = erlang:group_leader(),
{ok, FD} = file:open(File, [write]),
erlang:group_leader(FD, self()),
Fun(),
erlang:group_leader(G, self()),
file:close(FD)
end,
F(fun () -> mnesia:info() end, "mnesia_info.txt").
In cases where you are situated at a terminal without scrolling (if you are on a xterm and see no scrollbar simply switch it on) a tool very useful is screen: it provides virtual vt100 termials, you can switch between terminals even detach from it and come back later (nice for long running programs on remote serversthat need the occasional interaction).
And you can log transcripts to a file and scroll in the output of the virtual terminal.
If you are on a Unix like System you will probably be able to just install a pre-built package, if all else fails you can always pick up the source and build it yourself.
Also look at this article for other solutions.
If you are not able to install screen on the system, a simple but not very comfortable hack that only uses Unix built-in stuff is:
Start erlang shell with tee(1) to redirect the output:
$ erl | tee output.log
Eshell V5.7.5 (abort with ^G)
1> mnesia:info().
===> System info in version {mnesia_not_loaded,nonode#nohost,
{1301,742014,571300}}, debug level = none <===
opt_disc. Directory "/usr/home/peer/Mnesia.nonode#nohost" is NOT used.
use fallback at restart = false
running db nodes = []
stopped db nodes = [nonode#nohost]
ok
2>
Its a bit hard to get out of the shell (you probably have to type ^D to end the input file) but then you have the tty output in the file:
$ cat output.log
Eshell V5.7.5 (abort with ^G)
1> ===> System info in version {mnesia_not_loaded,nonode#nohost,
{1301,742335,572797}}, debug level = none <===
...
I believe you cant. See system_info(all).
Convert to a string:
S = io_lib:format("~p~n", [mnesia:info()]).
Then write it to disk.

Resources