SCM Repository
Annotation of /sml/trunk/src/smlnj-lib/INet/sock-util.sml
Parent Directory
|
Revision Log
Revision 409 - (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 : | 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 INET domain stream socket *) | ||
87 : | fun connectINetStrm {addr, port} = let | ||
88 : | val sock = INetSock.TCP.socket () | ||
89 : | in | ||
90 : | Socket.connect (sock, INetSock.toAddr(addr, port)); | ||
91 : | sock | ||
92 : | end | ||
93 : | |||
94 : | (** If the server closes the connection, do we get 0 bytes or an error??? **) | ||
95 : | (* read exactly n bytes from a stream socket *) | ||
96 : | fun recvVec (sock, n) = let | ||
97 : | fun get (0, data) = Word8Vector.concat(rev data) | ||
98 : | | get (n, data) = let | ||
99 : | val v = Socket.recvVec (sock, n) | ||
100 : | in | ||
101 : | if (Word8Vector.length v = 0) | ||
102 : | then raise OS.SysErr("closed socket", NONE) | ||
103 : | else get (n - Word8Vector.length v, v::data) | ||
104 : | end | ||
105 : | in | ||
106 : | if (n < 0) then raise Size else get (n, []) | ||
107 : | end | ||
108 : | |||
109 : | fun recvStr arg = Byte.bytesToString (recvVec arg) | ||
110 : | |||
111 : | (* send the complete contents of a vector *) | ||
112 : | fun sendVec (sock, vec) = let | ||
113 : | val len = Word8Vector.length vec | ||
114 : | fun send i = Socket.sendVec (sock, {buf=vec, i=i, sz=NONE}) | ||
115 : | fun put i = if (i < len) | ||
116 : | then put(i + send i) | ||
117 : | else () | ||
118 : | in | ||
119 : | put 0 | ||
120 : | end | ||
121 : | |||
122 : | fun sendStr (sock, str) = sendVec (sock, Byte.stringToBytes str) | ||
123 : | |||
124 : | (* send the complete contents of an array *) | ||
125 : | fun sendArr (sock, arr) = let | ||
126 : | val len = Word8Array.length arr | ||
127 : | fun send i = Socket.sendArr (sock, {buf=arr, i=i, sz=NONE}) | ||
128 : | fun put i = if (i < len) | ||
129 : | then put(i + send i) | ||
130 : | else () | ||
131 : | in | ||
132 : | put 0 | ||
133 : | end | ||
134 : | |||
135 : | end; |
root@smlnj-gforge.cs.uchicago.edu | ViewVC Help |
Powered by ViewVC 1.0.0 |