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 /smlnj-lib/trunk/INet/sock-util.sml
ViewVC logotype

Annotation of /smlnj-lib/trunk/INet/sock-util.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2144 - (view) (download)

1 : monnier 409 (* 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 : jhr 967 val addrFromString = StringCvt.scanString scanAddr
59 :    
60 : monnier 409 exception BadAddr of string
61 :    
62 :     fun resolveAddr {host, port} = let
63 :     fun err (a, b) = raise BadAddr(concat[a, " \"", b, "\" not found"])
64 :     val (name, addr) = (case host
65 :     of HostName s => (case NetHostDB.getByName s
66 :     of NONE => err ("hostname", s)
67 :     | (SOME entry) => (s, NetHostDB.addr entry)
68 :     (* end case *))
69 :     | HostAddr addr => (case NetHostDB.getByAddr addr
70 :     of NONE => err ("host address", NetHostDB.toString addr)
71 :     | (SOME entry) => (NetHostDB.name entry, addr)
72 :     (* end case *))
73 :     (* end case *))
74 :     val port = (case port
75 :     of (SOME(PortNumber n)) => SOME n
76 :     | (SOME(ServName s)) => (case NetServDB.getByName(s, NONE)
77 :     of (SOME entry) => SOME(NetServDB.port entry)
78 :     | NONE => err("service", s)
79 :     (* end case *))
80 :     | NONE => NONE
81 :     (* end case *))
82 :     in
83 :     {host = name, addr = addr, port = port}
84 :     end
85 :    
86 :     type 'a stream_sock = ('a, Socket.active Socket.stream) Socket.sock
87 :    
88 :     (* establish a client-side connection to a INET domain stream socket *)
89 :     fun connectINetStrm {addr, port} = let
90 :     val sock = INetSock.TCP.socket ()
91 :     in
92 :     Socket.connect (sock, INetSock.toAddr(addr, port));
93 :     sock
94 :     end
95 :    
96 :     (** If the server closes the connection, do we get 0 bytes or an error??? **)
97 :     (* read exactly n bytes from a stream socket *)
98 :     fun recvVec (sock, n) = let
99 :     fun get (0, data) = Word8Vector.concat(rev data)
100 :     | get (n, data) = let
101 :     val v = Socket.recvVec (sock, n)
102 :     in
103 :     if (Word8Vector.length v = 0)
104 :     then raise OS.SysErr("closed socket", NONE)
105 :     else get (n - Word8Vector.length v, v::data)
106 :     end
107 :     in
108 :     if (n < 0) then raise Size else get (n, [])
109 :     end
110 :    
111 :     fun recvStr arg = Byte.bytesToString (recvVec arg)
112 :    
113 :     (* send the complete contents of a vector *)
114 :     fun sendVec (sock, vec) = let
115 :     val len = Word8Vector.length vec
116 : mblume 1381 fun send i = Socket.sendVec (sock,
117 :     Word8VectorSlice.slice (vec, i, NONE))
118 : monnier 409 fun put i = if (i < len)
119 :     then put(i + send i)
120 :     else ()
121 :     in
122 :     put 0
123 :     end
124 :    
125 :     fun sendStr (sock, str) = sendVec (sock, Byte.stringToBytes str)
126 :    
127 :     (* send the complete contents of an array *)
128 :     fun sendArr (sock, arr) = let
129 :     val len = Word8Array.length arr
130 : mblume 1381 fun send i = Socket.sendArr (sock,
131 :     Word8ArraySlice.slice (arr, i, NONE))
132 : monnier 409 fun put i = if (i < len)
133 :     then put(i + send i)
134 :     else ()
135 :     in
136 :     put 0
137 :     end
138 :    
139 :     end;

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