Joe Williams home
Lately I have been working on a TCP server that works similar to D. J. Bernstein's ucspi-tcp. Basically, it is a TCP server that sits in front of a executable of some sort and plays a middleman between the TCP client and the actual code that is performing functions on the data sent to the TCP server. More on ucspi-tcp in later post(s). The first portion of my TCP server code can be found here and blog post here. The portion of code for today is for sending and receiving messages to/from the executable in Erlang. This is done using an Erlang port, the Erlang docs have a good interoperability tutorial that should help anyone start out. erl_portc.erl
-module(erl_portc). -export([start/1, call_port/1, init/1, port_loop/1]). start(Cmd) -> % spawn a process connected to the executable spawn(?MODULE, init, [Cmd]). init(Cmd) -> % register it and set things up register(port, self()), process_flag(trap_exit, true), Port = open_port({spawn, Cmd}, []), port_loop(Port). call_port(Msg) -> % send messages to the executable port ! {call, self(), Msg}, receive {port, Result} -> Result end. port_loop(Port) -> % recieve results from the executable receive {call, Caller, Msg} -> Port ! {self(), {command, Msg}}, receive {Port, {data, Data}} -> Caller ! {port, Data}; stop -> Port ! {self(), close}, receive {Port, closed} -> exit(normal) end; {'EXIT', Port, Reason} -> exit(port_terminated) end, port_loop(Port) end.
Here is an example of its usage using DJB's qmail-smtpd executable.
[joe@box01 ~]$ erl Erlang (BEAM) emulator version 5.6.3 [source] [smp:4] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.6.3 (abort with ^G) 1> erl_portc:start('/var/qmail/bin/qmail-smtpd'). <0.32.0> 2> erl_portc:call_port(""). "220 ESMTP\r\n" 3> erl_portc:call_port("HELO\r\n"). "250\r\n" 4> erl_portc:call_port("MAIL FROM:\r\n"). "250 ok\r\n" 5> erl_portc:call_port("RCPT TO:\r\n"). CHKUSER accepted rcpt: from remote rcpt : found existing recipient "250 ok\r\n" 6> erl_portc:call_port("DATA\r\n"). "354 go ahead\r\n" 7> erl_portc:call_port("Subject: TEST123\r\n.\r\n"). "250 ok 1229721933 qp 10176\r\n" 8> erl_portc:call_port("QUIT\r\n"). "221\r\n"
Shortly after running the above directives I received an email in my inbox with the subject "TEST123". So it seems to be interfacing with the executable properly. As with most of the code on this blog, this example can be checked out from subversion and viewed in WebSVN. Enjoy!
Fork me on GitHub