Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] Annotation of /sml/trunk/src/cml/cml-lib/SMLNJ-INet/sock-util.sml
ViewVC logotype

Annotation of /sml/trunk/src/cml/cml-lib/SMLNJ-INet/sock-util.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (view) (download)

1 : monnier 2 (* sock-util-sig.sml
2 :     *
3 :     * COPYRIGHT (c) 1996 AT&T Research.
4 :     *
5 :     * Various utility functions for programming with sockets.
6 :     *)
7 :    
8 :     structure SockUtil : SOCK_UTIL =
9 :     struct
10 :    
11 :     structure C = Char
12 :     structure PC = ParserComb
13 :    
14 :     datatype port = PortNumber of int | ServName of string
15 :     (* a port can be identified by number, or by the name of a service *)
16 :    
17 :     datatype hostname = HostName of string | HostAddr of NetHostDB.in_addr
18 :    
19 :     (** This belongs in an Option structure **)
20 :     fun filterPartial pred NONE = NONE
21 :     | filterPartial pred (SOME x) = if (pred x) then SOME x else NONE
22 :    
23 :     fun scanName getc strm = let
24 :     fun isNameChr (#".", _) = true
25 :     | isNameChr (#"-", _) = true
26 :     | isNameChr (c, _) = C.isAlphaNum c
27 :     fun getName (strm, cl) = (case filterPartial isNameChr (getc strm)
28 :     of SOME(c, strm') => getName(strm', c::cl)
29 :     | NONE => SOME(implode(rev cl), strm)
30 :     (* end case *))
31 :     in
32 :     case (filterPartial (C.isAlpha o #1) (getc strm))
33 :     of SOME(c, strm) => getName(strm, [c])
34 :     | NONE => NONE
35 :     (* end case *)
36 :     end
37 :    
38 :     (* scan an address, which has the form
39 :     * addr [ ":" port ]
40 :     * where the addr may either be numeric or symbolic host name and the
41 :     * port is either a service name or a decimal number. Legal host names
42 :     * must begin with a letter, and may contain any alphanumeric character,
43 :     * the minus sign (-) and period (.), where the period is used as a
44 :     * domain separator.
45 :     *)
46 :     fun scanAddr getc strm =
47 :     PC.seqWith (fn (host, port) => {host=host, port=port}) (
48 :     PC.or (
49 :     PC.wrap (scanName, HostName),
50 :     PC.wrap (NetHostDB.scan, HostAddr)),
51 :     PC.option (
52 :     PC.seqWith #2 (
53 :     PC.eatChar (fn c => (c = #":")),
54 :     PC.or (
55 :     PC.wrap (scanName, ServName),
56 :     PC.wrap (Int.scan StringCvt.DEC, PortNumber))))) getc strm
57 :    
58 :     exception BadAddr of string
59 :    
60 :     fun resolveAddr {host, port} = let
61 :     fun err (a, b) = raise BadAddr(concat[a, " \"", b, "\" not found"])
62 :     val (name, addr) = (case host
63 :     of HostName s => (case NetHostDB.getByName s
64 :     of NONE => err ("hostname", s)
65 :     | (SOME entry) => (s, NetHostDB.addr entry)
66 :     (* end case *))
67 :     | HostAddr addr => (case NetHostDB.getByAddr addr
68 :     of NONE => err ("host address", NetHostDB.toString addr)
69 :     | (SOME entry) => (NetHostDB.name entry, addr)
70 :     (* end case *))
71 :     (* end case *))
72 :     val port = (case port
73 :     of (SOME(PortNumber n)) => SOME n
74 :     | (SOME(ServName s)) => (case NetServDB.getByName(s, NONE)
75 :     of (SOME entry) => SOME(NetServDB.port entry)
76 :     | NONE => err("service", s)
77 :     (* end case *))
78 :     | NONE => NONE
79 :     (* end case *))
80 :     in
81 :     {host = name, addr = addr, port = port}
82 :     end
83 :    
84 :     type 'a stream_sock = ('a, Socket.active Socket.stream) Socket.sock
85 :    
86 :     (* establish a client-side connection to a Unix-domain stream socket *)
87 :     fun connectUnixStrm path = let
88 :     val sock = UnixSock.Strm.socket ()
89 :     in
90 :     Socket.connect (sock, UnixSock.toAddr path);
91 :     sock
92 :     end
93 :    
94 :     (* establish a client-side connection to a INET domain stream socket *)
95 :     fun connectINetStrm {addr, port} = let
96 :     val sock = INetSock.TCP.socket ()
97 :     in
98 :     Socket.connect (sock, INetSock.toAddr(addr, port));
99 :     sock
100 :     end
101 :    
102 :     (** If the server closes the connection, do we get 0 bytes or an error??? **)
103 :     (* read exactly n bytes from a stream socket *)
104 :     fun recvVec (sock, n) = let
105 :     fun get (0, data) = Word8Vector.concat(rev data)
106 :     | get (n, data) = let
107 :     val v = Socket.recvVec (sock, n)
108 :     in
109 :     if (Word8Vector.length v = 0)
110 :     then raise OS.SysErr("closed socket", NONE)
111 :     else get (n - Word8Vector.length v, v::data)
112 :     end
113 :     in
114 :     if (n < 0) then raise Size else get (n, [])
115 :     end
116 :    
117 :     fun recvStr arg = Byte.bytesToString (recvVec arg)
118 :    
119 :     (* send the complete contents of a vector *)
120 :     fun sendVec (sock, vec) = let
121 :     val len = Word8Vector.length vec
122 :     fun send i = Socket.sendVec (sock, {buf=vec, i=i, sz=NONE})
123 :     fun put i = if (i < len)
124 :     then put(i + send i)
125 :     else ()
126 :     in
127 :     put 0
128 :     end
129 :    
130 :     fun sendStr (sock, str) = sendVec (sock, Byte.stringToBytes str)
131 :    
132 :     (* send the complete contents of an array *)
133 :     fun sendArr (sock, arr) = let
134 :     val len = Word8Array.length arr
135 :     fun send i = Socket.sendArr (sock, {buf=arr, i=i, sz=NONE})
136 :     fun put i = if (i < len)
137 :     then put(i + send i)
138 :     else ()
139 :     in
140 :     put 0
141 :     end
142 :    
143 :     end;

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0