1 (* Title: Pure/System/system_channel.ML
4 Portable system channel for inter-process communication, based on
5 named pipes or sockets.
8 signature SYSTEM_CHANNEL =
11 val input_line: T -> string option
12 val inputN: T -> int -> string
13 val output: T -> string -> unit
15 val fifo_rendezvous: string -> string -> T
16 val socket_rendezvous: string -> T
19 structure System_Channel: SYSTEM_CHANNEL =
22 datatype T = System_Channel of
23 {input_line: unit -> string option,
24 inputN: int -> string,
25 output: string -> unit,
28 fun input_line (System_Channel {input_line = f, ...}) = f ();
29 fun inputN (System_Channel {inputN = f, ...}) n = f n;
30 fun output (System_Channel {output = f, ...}) s = f s;
31 fun flush (System_Channel {flush = f, ...}) = f ();
36 fun fifo_rendezvous fifo1 fifo2 =
38 val in_stream = TextIO.openIn fifo1;
39 val out_stream = TextIO.openOut fifo2;
40 val _ = TextIO.StreamIO.setBufferMode (TextIO.getOutstream out_stream, IO.BLOCK_BUF);
43 {input_line = fn () => TextIO.inputLine in_stream,
44 inputN = fn n => TextIO.inputN (in_stream, n),
45 output = fn s => TextIO.output (out_stream, s),
46 flush = fn () => TextIO.flushOut out_stream}
50 (* sockets *) (* FIXME proper buffering via BinIO (after Poly/ML 5.4.1) *)
58 val s = Byte.bytesToString (Socket.recvVec (socket, n - i));
61 val buf' = Buffer.add s buf;
62 in if m > 0 andalso n > i' then read i' buf' else Buffer.content buf' end;
63 in read 0 Buffer.empty end;
65 fun read_line socket =
67 fun result cs = implode (rev ("\n" :: cs));
69 (case readN socket 1 of
70 "" => if null cs then NONE else SOME (result cs)
71 | "\n" => SOME (result cs)
72 | c => read (c :: cs));
78 if Word8VectorSlice.isEmpty buf then ()
81 val n = Int.min (Word8VectorSlice.length buf, 4096);
82 val m = Socket.sendVec (socket, Word8VectorSlice.subslice (buf, 0, SOME n));
83 val buf' = Word8VectorSlice.subslice (buf, m, NONE);
85 in fn s => send (Word8VectorSlice.full (Byte.stringToBytes s)) end;
89 fun socket_rendezvous name =
91 fun err () = error ("Bad socket name: " ^ quote name);
93 (case space_explode ":" name of
95 (case NetHostDB.getByName h of SOME host => host | NONE => err (),
96 case Int.fromString p of SOME port => port | NONE => err ())
98 val socket: Socket.active INetSock.stream_sock = INetSock.TCP.socket ();
99 val _ = Socket.connect (socket, INetSock.toAddr (NetHostDB.addr host, port));
102 {input_line = fn () => read_line socket,
103 inputN = fn n => readN socket n,
104 output = fn s => write socket s,