Re: Netcat in E?
Mark S. Miller <markm@...
2006-01-15 21:33:44 GMT
Steve Johnston wrote:
> I set out to write a simple netcat like E program. It would accept a
> connection on one socket, connect outbound on another, and route data
> from one to the other in both directions.
> It would be relatively straightforward to write the E code to use unsafe
> java Socket 's to poll for packets and route the data as it arrives.
> This seems to fly in the face of the spirit of E, however.
> Using the blocking read() methods of the InputStream doesn't achieve the
> goal : forward data immediately upon it's arrival. Immediately may be
> the wrong word. The condition is forwarding a packet in one direction
> cannot wait until the arrival of a packet in the other direction.
> As near as I can tell the only way to get an E program to accept an
> arbitrary TCP connection is to use a java class. Please correct me if I
> am wrong. I was excited when I thought that I could use elib.EIO to
> turn the Streams I get from the Socket class into an E Stream. But EIO
> does not seem to be implemented yet.
For E-on-Java, this is currently correct. OTOH, E-on-CL
<http://homepage.mac.com/kpreid/elang/e-on-cl/> has made much progress on
Kevin, is E-on-CL's EIO ready for writing such a netcat?
> I would appreciate commentary on the following:
> 1) Can E accept arbitrary TCP connections without appealing directly to
> the Java/ CL libraries, even locally? I think the answer is no.
> 2) Given two connections on two sockets, can E Shuffle data between the
> two efficiently without polling a java class(or using java NIO)?
> As near as I can tell the answer is no, without EIO.
The situation is not quite this bad. Given a Java class, like java.net.Socket,
which blocks but is otherwise tamed, the following code shows a generic
technique for turning blocking Java operations into non-blocking E operations.
Import and authorize a seedVat function, for running E code in new vats.
? def seedVat := <elang:interp.seedVatAuthor>(<unsafe>)
# value: <seedVat>
Evaluate the E expression "<unsafe:java.net.Socket>()" in the privileged scope
of a new vat. Returns a pair of a reference to the result of evaluating the
expression (farSock) and the new vat (sockVat, running in its own new thread)
in which this expression is evaluated. (The two argument form of seedVat lets
you pass in a pre-existing vat rather than having it make a new one.)
? def [farSock, sockVat] := seedVat("<unsafe:java.net.Socket>()")
# value: [<Remote Promise>, <Vat newSeedVat in <runs in newSeedVat>>]
If you now ask farSock to do a blocking operation, it will, which will block
its own vat, and so violate the E computational model. However, so long as
each blocking device is given its own vat/thread to block, they won't block
each other or computation happening in normal non-blocking vats. From the
perspective of normal non-blocking vats, they can just interact with these
"remote" devices as if they are non-blocking devices conforming to the E
The following example isn't actually a blocking operation, but you get the idea:
? def x := farSock <- getSoTimeout()
# value: <Remote Promise>
# value: 0
Unfortunately, this seedVat technique is not sufficient for implementing EIO
on top of Java streams, because of the "Preserve Immediacy" requirement at the
bottom of <http://www.erights.org//elib/concurrency/eio/goals.html>. Instead,
I expect that an EIO implementation for E-on-Java will wrap Java's
non-blocking NIO operations. An NIO-based implementation should also be *much*
more efficient, as it doesn't create a vat/thread per device.
Text by me above is hereby placed in the public domain