(* Title: Pure/General/socket_io.ML
Author: Timothy Bourke, NICTA
Author: Makarius
Stream IO over TCP sockets. Following example 10.2 in "The Standard
ML Basis Library" by Emden R. Gansner and John H. Reppy.
*)
signature SOCKET_IO =
sig
val make_streams: Socket.active INetSock.stream_sock -> BinIO.instream * BinIO.outstream
val open_streams: string * int -> BinIO.instream * BinIO.outstream
end;
structure Socket_IO: SOCKET_IO =
struct
fun make_streams socket =
let
val (host, port) = INetSock.fromAddr (Socket.Ctl.getSockName socket);
val name = NetHostDB.toString host ^ ":" ^ string_of_int port;
val rd =
BinPrimIO.RD {
name = name,
chunkSize = Socket.Ctl.getRCVBUF socket,
readVec = SOME (fn n => Socket.recvVec (socket, n)),
readArr = SOME (fn buffer => Socket.recvArr (socket, buffer)),
readVecNB = NONE,
readArrNB = NONE,
block = NONE,
canInput = NONE,
avail = fn () => NONE,
getPos = NONE,
setPos = NONE,
endPos = NONE,
verifyPos = NONE,
close = fn () => Socket.close socket,
ioDesc = NONE
};
val wr =
BinPrimIO.WR {
name = name,
chunkSize = Socket.Ctl.getSNDBUF socket,
writeVec = SOME (fn buffer => Socket.sendVec (socket, buffer)),
writeArr = SOME (fn buffer => Socket.sendArr (socket, buffer)),
writeVecNB = NONE,
writeArrNB = NONE,
block = NONE,
canOutput = NONE,
getPos = NONE,
setPos = NONE,
endPos = NONE,
verifyPos = NONE,
close = fn () => Socket.close socket,
ioDesc = NONE
};
val in_stream =
BinIO.mkInstream
(BinIO.StreamIO.mkInstream (rd, Word8Vector.fromList []));
val out_stream =
BinIO.mkOutstream
(BinIO.StreamIO.mkOutstream (wr, IO.BLOCK_BUF));
in (in_stream, out_stream) end;
fun open_streams (hostname, port) =
let
val host =
(case NetHostDB.getByName hostname of
NONE => error ("Bad host name: " ^ quote hostname)
| SOME host => host);
val addr = INetSock.toAddr (NetHostDB.addr host, port);
val socket: Socket.active INetSock.stream_sock = INetSock.TCP.socket ();
val _ = Socket.connect (socket, addr);
in make_streams socket end;
end;