diff options
Diffstat (limited to 'lib/kernel/examples/uds_dist/src/uds.erl')
-rw-r--r-- | lib/kernel/examples/uds_dist/src/uds.erl | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/lib/kernel/examples/uds_dist/src/uds.erl b/lib/kernel/examples/uds_dist/src/uds.erl new file mode 100644 index 0000000000..ae1a78c44b --- /dev/null +++ b/lib/kernel/examples/uds_dist/src/uds.erl @@ -0,0 +1,166 @@ +-module(uds). + +-export([listen/1, connect/1, accept/1, send/2, recv/1, close/1, + get_port/1, get_status_counters/1, set_mode/2, controlling_process/2, + tick/1, get_creation/1]). + +-define(decode(A,B,C,D), (((A) bsl 24) bor + ((B) bsl 16) bor ((C) bsl 8) bor (D))). +-define(encode(N), [(((N) bsr 24) band 16#FF), (((N) bsr 16) band 16#FF), + (((N) bsr 8) band 16#FF), ((N) band 16#FF)]). +-define(check_server(), case whereis(uds_server) of + undefined -> + exit(uds_server_not_started); + _ -> + ok + end). + +listen(Name) -> + ?check_server(), + command(port(),$L,Name). + + +connect(Name) -> + ?check_server(), + command(port(),$C,Name). + +accept(Port) -> + ?check_server(), + case control(Port,$N) of + {ok, N} -> + command(port(),$A,N); + Else -> + Else + end. + +send(Port,Data) -> + ?check_server(), + command(Port, $S, Data). + +recv(Port) -> + ?check_server(), + command(Port, $R, []). + +close(Port) -> + ?check_server(), + (catch unlink(Port)), %% Avoids problem with trap exits. + case (catch erlang:port_close(Port)) of + {'EXIT', Reason} -> + {error, closed}; + _ -> + ok + end. + +get_port(Port) -> + ?check_server(), + {ok,Port}. + +get_status_counters(Port) -> + ?check_server(), + case control(Port, $S) of + {ok, {C0, C1, C2}} -> + {ok, C0, C1, C2}; + Other -> + Other + end. + +get_creation(Port) -> + ?check_server(), + case control(Port, $R) of + {ok, [A]} -> + A; + Else -> + Else + end. + + +set_mode(Port, command) -> + ?check_server(), + control(Port,$C); +set_mode(Port,intermediate) -> + ?check_server(), + control(Port,$I); +set_mode(Port,data) -> + ?check_server(), + control(Port,$D). + +tick(Port) -> + ?check_server(), + control(Port,$T). + +controlling_process(Port, Pid) -> + ?check_server(), + case (catch erlang:port_connect(Port, Pid)) of + true -> + (catch unlink(Port)), + ok; + {'EXIT', {badarg, _}} -> + {error, closed}; + Else -> + exit({unexpected_driver_response, Else}) + end. + + +control(Port, Command) -> + case (catch erlang:port_control(Port, Command, [])) of + [0] -> + ok; + [0,A] -> + {ok, [A]}; + [0,A,B,C,D] -> + {ok, [A,B,C,D]}; + [0,A1,B1,C1,D1,A2,B2,C2,D2,A3,B3,C3,D3] -> + {ok, {?decode(A1,B1,C1,D1),?decode(A2,B2,C2,D2), + ?decode(A3,B3,C3,D3)}}; + [1|Error] -> + exit({error, list_to_atom(Error)}); + {'EXIT', {badarg, _}} -> + {error, closed}; + Else -> + exit({unexpected_driver_response, Else}) + end. + + +command(Port, Command, Parameters) -> + SavedTrapExit = process_flag(trap_exit,true), + case (catch erlang:port_command(Port,[Command | Parameters])) of + true -> + receive + {Port, {data, [Command, $o, $k]}} -> + process_flag(trap_exit,SavedTrapExit), + {ok, Port}; + {Port, {data, [Command |T]}} -> + process_flag(trap_exit,SavedTrapExit), + {ok, T}; + {Port, Else} -> + process_flag(trap_exit,SavedTrapExit), + exit({unexpected_driver_response, Else}); + {'EXIT', Port, normal} -> + process_flag(trap_exit,SavedTrapExit), + {error, closed}; + {'EXIT', Port, Error} -> + process_flag(trap_exit,SavedTrapExit), + exit(Error) + end; + {'EXIT', {badarg, _}} -> + process_flag(trap_exit,SavedTrapExit), + {error, closed}; + Unexpected -> + process_flag(trap_exit,SavedTrapExit), + exit({unexpected_driver_response, Unexpected}) + end. + +port() -> + SavedTrapExit = process_flag(trap_exit,true), + case open_port({spawn, "uds_drv"},[]) of + P when port(P) -> + process_flag(trap_exit,SavedTrapExit), + P; + {'EXIT',Error} -> + process_flag(trap_exit,SavedTrapExit), + exit(Error); + Else -> + process_flag(trap_exit,SavedTrapExit), + exit({unexpected_driver_response, Else}) + end. + |