[MLton] BUG in Socket.Ctl.setLINGER
Ray Racine
rracine@adelphia.net
Sat, 19 Mar 2005 12:51:31 -0500
I have completed a port of the Swerve HTTP server to MLton to the point
where it a) compiles and b) serves simple html. Its capable of much
more but I haven't tested various aspects yet. [a) was last weekend and
b) was 20 minutes ago]
The purpose of the port was so I can embed a small, yet robust http
server in an SML application. Code release coming soon.
The following bug was the issue in preventing the server from serving
simple html that I found this morning. A call to Socket.Ctl.setLinger
errors with a Subscript exception. I used D Wang's Shootout submission
of a simple TCP echo program as the test case to reproduce the bug.
Consider this a bug report without a fix at this time. I'm done'fer the
weekend and may get to tracking down the cause sporadically during the
upcoming work week. If the issue is still open by next weekend I'll try
and track it down and get a fix.
Ray
(* -*- mode: sml -*-
: echo-smlnj.code,v 1.4 2004/11/13 07:41:31 bfulgham Exp $
* http://www.bagley.org/~doug/shootout/
* from Daniel Wang
*)
structure Test : sig
val main : (string * string list) -> OS.Process.status
end =
struct
exception Error of string
val data = "Hello there sailor\n"
fun mkSocks () = let
val server = INetSock.TCP.socket()
val client = INetSock.TCP.socket()
val _ = Socket.bind(server,INetSock.any 0)
val saddr = INetSock.fromAddr(Socket.Ctl.getSockName server)
val _ = Socket.listen(server,2)
val _ = Socket.connect(client,INetSock.toAddr saddr)
val _ = INetSock.TCP.setNODELAY(server,true)
val _ = INetSock.TCP.setNODELAY(client,true)
in
{ client=client,server=server }
end
fun readString (s,n) = let
fun loop(0) = []
| loop(n) = let
val data = Byte.unpackStringVec (Word8VectorSlice.full
(Socket.recvVec(s,n)))
val len = String.size data
in if len = 0 then []
else (data::(loop(n - len)))
end
in
String.concat (loop n)
end
fun writeString (out,str) =
Socket.sendVec(out, Word8VectorSlice.full( Byte.stringToBytes
str))
(* Socket.sendVec(out,{buf=Byte.stringToBytes str,i=0,sz=NONE}) *)
fun closeSock s =
(Socket.shutdown(s,Socket.NO_RECVS_OR_SENDS);
Socket.close s)
fun main (_,args) = let
val num =
case args of
nil => 1
| n::_ => valOf (Int.fromString n)
val {client=client_sock,server=server_sock} = mkSocks()
fun server () = let
val (sock,_) = Socket.accept(server_sock)
(* COMMENT OUT LINGER TO WORK *)
val _ = Socket.Ctl.setLINGER (sock, SOME (Time.fromSeconds 2 ))
fun s b =
case readString(sock,19) of
"" => (Posix.Process.wait ();
TextIO.output(TextIO.stdOut,
concat ["server processed ",
Int.toString b,
" bytes\n"]);
TextIO.flushOut(TextIO.stdOut))
| i =>(writeString(sock,i);
s (b + 19))
in s 0
end
fun client () = let
fun c 0 = closeSock(client_sock)
| c n = let
val _ = writeString(client_sock,data);
val reply = readString(client_sock,19)
in if reply = data then c(n - 1)
else raise Error "Didn't receive the same data"
end
in c num
end
in
case Posix.Process.fork () of
SOME pid => server ()
| NONE => client ();
OS.Process.success
end
end
val _ = Test.main (CommandLine.name (), CommandLine.arguments ())