File: Socket.sml

package info (click to toggle)
polyml 5.2.1-1.1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 19,692 kB
  • ctags: 17,567
  • sloc: cpp: 37,221; sh: 9,591; asm: 4,120; ansic: 428; makefile: 203; ml: 191; awk: 91; sed: 10
file content (646 lines) | stat: -rw-r--r-- 23,852 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
(*
    Title:      Standard Basis Library: Generic Sockets
    Author:     David Matthews
    Copyright   David Matthews 2000, 2005

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.
	
	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*)

(* G&R 2004 status: Done.  Various changes.  In particular "select" added. *)

signature SOCKET =
sig
	type ('af,'sock_type) sock
	type 'af sock_addr
	type dgram
	type 'mode stream
	type passive
	type active

    structure AF :
	sig
		type addr_family = NetHostDB.addr_family
        val list : unit -> (string * addr_family) list
        val toString   : addr_family -> string
        val fromString : string -> addr_family option
	end

    structure SOCK :
	sig
		eqtype sock_type
		val stream : sock_type
		val dgram : sock_type
		val list : unit -> (string * sock_type) list
		val toString   : sock_type -> string
		val fromString : string -> sock_type option
	end

    structure Ctl :
	sig
         val getDEBUG : ('af, 'sock_type) sock -> bool
         val setDEBUG : ('af, 'sock_type) sock * bool -> unit
         val getREUSEADDR : ('af, 'sock_type) sock -> bool
         val setREUSEADDR : ('af, 'sock_type) sock * bool -> unit
         val getKEEPALIVE : ('af, 'sock_type) sock -> bool
         val setKEEPALIVE : ('af, 'sock_type) sock * bool -> unit
         val getDONTROUTE : ('af, 'sock_type) sock -> bool
         val setDONTROUTE : ('af, 'sock_type) sock * bool -> unit
         val getLINGER : ('af, 'sock_type) sock -> Time.time option
         val setLINGER : ('af, 'sock_type) sock * Time.time option -> unit
         val getBROADCAST : ('af, 'sock_type) sock -> bool
         val setBROADCAST : ('af, 'sock_type) sock * bool -> unit
         val getOOBINLINE : ('af, 'sock_type) sock -> bool
         val setOOBINLINE : ('af, 'sock_type) sock * bool  -> unit
         val getSNDBUF : ('af, 'sock_type) sock -> int
         val setSNDBUF : ('af, 'sock_type) sock * int -> unit
         val getRCVBUF : ('af, 'sock_type) sock -> int
         val setRCVBUF : ('af, 'sock_type) sock * int -> unit
         val getTYPE : ('af, 'sock_type) sock -> SOCK.sock_type
         val getERROR : ('af, 'sock_type) sock -> bool
		 val getPeerName : ('af, 'sock_type) sock -> 'af sock_addr
         val getSockName : ('af, 'sock_type) sock -> 'af sock_addr
         val getNREAD : ('af, 'sock_type) sock -> int
         val getATMARK : ('af, active stream) sock -> bool
         end

     val sameAddr : 'af sock_addr * 'af sock_addr -> bool
     val familyOfAddr : 'af sock_addr -> AF.addr_family

	 val bind : ('af, 'sock_type) sock * 'af sock_addr -> unit
     val listen : ('af, passive stream) sock * int -> unit
     val accept : ('af, passive stream) sock
                    -> ('af, active stream) sock * 'af sock_addr
     val acceptNB : ('af, passive stream) sock
                    -> (('af, active stream) sock * 'af sock_addr) option
     val connect : ('af, 'sock_type) sock * 'af sock_addr -> unit
     val connectNB : ('af, 'sock_type) sock * 'af sock_addr -> bool
     val close : ('af, 'sock_type) sock -> unit

     datatype shutdown_mode
       = NO_RECVS
       | NO_SENDS
       | NO_RECVS_OR_SENDS

     val shutdown : ('af, 'sock_type stream) sock * shutdown_mode -> unit

	 type sock_desc
	 val sockDesc : ('af, 'sock_type) sock -> sock_desc
	 val sameDesc: sock_desc * sock_desc -> bool

	 
	 val select:
	 		{ rds: sock_desc list, wrs : sock_desc list, exs : sock_desc list, timeOut: Time.time option } ->
	 		{ rds: sock_desc list, wrs : sock_desc list, exs : sock_desc list }
	 
     val ioDesc : ('af, 'sock_type) sock -> OS.IO.iodesc

     type out_flags = {don't_route : bool, oob : bool}
     type in_flags = {peek : bool, oob : bool}

     val sendVec : ('af, active stream) sock * Word8VectorSlice.slice -> int
     val sendArr : ('af, active stream) sock * Word8ArraySlice.slice -> int
     val sendVec' : ('af, active stream) sock * Word8VectorSlice.slice
                      * out_flags -> int
     val sendArr' : ('af, active stream) sock * Word8ArraySlice.slice
                      * out_flags -> int
     val sendVecNB : ('af, active stream) sock * Word8VectorSlice.slice -> int option
     val sendArrNB : ('af, active stream) sock * Word8ArraySlice.slice -> int option
     val sendVecNB' : ('af, active stream) sock * Word8VectorSlice.slice
                      * out_flags -> int option
     val sendArrNB' : ('af, active stream) sock * Word8ArraySlice.slice
                      * out_flags -> int option
					  
     val recvVec : ('af, active stream) sock * int -> Word8Vector.vector
     val recvArr : ('af, active stream) sock  * Word8ArraySlice.slice -> int
     val recvVec' : ('af, active stream) sock * int * in_flags
                      -> Word8Vector.vector
     val recvArr' : ('af, active stream) sock * Word8ArraySlice.slice
                      * in_flags -> int
     val recvVecNB : ('af, active stream) sock * int -> Word8Vector.vector option
     val recvArrNB : ('af, active stream) sock  * Word8ArraySlice.slice -> int option
     val recvVecNB' : ('af, active stream) sock * int * in_flags
                      -> Word8Vector.vector option
     val recvArrNB' : ('af, active stream) sock * Word8ArraySlice.slice
                      * in_flags -> int option

     val sendVecTo : ('af, dgram) sock * 'af sock_addr
                       * Word8VectorSlice.slice -> unit
     val sendArrTo : ('af, dgram) sock * 'af sock_addr
                       * Word8ArraySlice.slice -> unit
     val sendVecTo' : ('af, dgram) sock * 'af sock_addr
                        * Word8VectorSlice.slice * out_flags -> unit
     val sendArrTo' : ('af, dgram) sock * 'af sock_addr
                        * Word8ArraySlice.slice * out_flags -> unit
     val sendVecToNB : ('af, dgram) sock * 'af sock_addr
                       * Word8VectorSlice.slice -> bool
     val sendArrToNB : ('af, dgram) sock * 'af sock_addr
                       * Word8ArraySlice.slice -> bool
     val sendVecToNB' : ('af, dgram) sock * 'af sock_addr
                        * Word8VectorSlice.slice * out_flags -> bool
     val sendArrToNB' : ('af, dgram) sock * 'af sock_addr
                        * Word8ArraySlice.slice * out_flags -> bool

     val recvVecFrom : ('af, dgram) sock * int
                         -> Word8Vector.vector * 'sock_type sock_addr
     val recvArrFrom : ('af, dgram) sock * Word8ArraySlice.slice
                         -> int * 'af sock_addr
     val recvVecFrom' : ('af, dgram) sock * int * in_flags
                          -> Word8Vector.vector * 'sock_type sock_addr
     val recvArrFrom' : ('af, dgram) sock * Word8ArraySlice.slice
                          * in_flags -> int * 'af sock_addr
     val recvVecFromNB : ('af, dgram) sock * int
                         -> (Word8Vector.vector * 'sock_type sock_addr) option
     val recvArrFromNB : ('af, dgram) sock * Word8ArraySlice.slice
                         -> (int * 'af sock_addr) option
     val recvVecFromNB' : ('af, dgram) sock * int * in_flags
                          -> (Word8Vector.vector * 'sock_type sock_addr) option
     val recvArrFromNB' : ('af, dgram) sock * Word8ArraySlice.slice
                          * in_flags -> (int * 'af sock_addr) option
end;

structure Socket :> SOCKET =
struct
	(* We don't really need an implementation for these.  *)
	(* TODO: We should really pull the definition of the sock type into a common structure so
	   it can be shared by the various socket structures.  In fact it doesn't matter since the
	   unary constructor here is compiled as an identity so the underlying representation of
	   "SOCK x" will be the same as "x". *)
	datatype ('af,'sock_type) sock = SOCK of OS.IO.iodesc
	and dgram = DGRAM
	and 'mode stream = STREAM
	and passive = PASSIVE
	and active = ACTIVE

	structure AF =
	struct
		type addr_family = NetHostDB.addr_family

		local
			val doCall: int*unit -> (string * addr_family) list
				 = RunCall.run_call2 RuntimeCalls.POLY_SYS_network
		in
			fun list () = doCall(11, ())
		end

		fun toString (af: addr_family) =
		let
			val afs = list()
		in
			(* Do a linear search on the list - it's small. *)
			case List.find (fn (_, af') => af=af') afs of
				NONE => raise OS.SysErr("Missing address family", NONE)
			|	SOME (s, _) => s
		end

 		fun fromString s =
		let
			val afs = list()
		in
			(* Do a linear search on the list - it's small. *)
			case List.find (fn (s', _) => s=s') afs of
				NONE => NONE
			|	SOME (_, af) => SOME af
		end
 	end

    structure SOCK =
	struct
		datatype sock_type = SOCKTYPE of int

		local
			val doCall: int*unit -> (string * sock_type) list
				 = RunCall.run_call2 RuntimeCalls.POLY_SYS_network
		in
			fun list () = doCall(12, ())
		end

		fun toString (sk: sock_type) =
		let
			val sks = list()
		in
			(* Do a linear search on the list - it's small. *)
			case List.find (fn (_, sk') => sk=sk') sks of
				NONE => raise OS.SysErr("Missing socket type", NONE)
			|	SOME (s, _) => s
		end

 		fun fromString s =
		let
			val sks = list()
		in
			(* Do a linear search on the list - it's small. *)
			case List.find (fn (s', _) => s=s') sks of
				NONE => NONE
			|	SOME (_, sk) => SOME sk
		end

		(* We assume that both of these at least are in the table. *)
		val stream =
			case fromString "STREAM" of
				NONE => raise OS.SysErr("Missing socket type", NONE)
			|	SOME s => s

		val dgram =
			case fromString "DGRAM" of
				NONE => raise OS.SysErr("Missing socket type", NONE)
			|	SOME s => s
	end

	(* Socket addresses are implemented as strings. *)
	datatype 'af sock_addr = SOCKADDR of Word8Vector.vector

	(* Note: The definition did not make these equality type variables.
	   The assumption is probably that it works much like equality on
	   references. *)
	fun sameAddr (SOCKADDR a, SOCKADDR b) = a = b

	fun familyOfAddr (sa: 'af sock_addr) =
			RunCall.run_call2 RuntimeCalls.POLY_SYS_network(39, sa)

	structure Ctl =
	struct
		local
			val doCall1 = RunCall.run_call2 RuntimeCalls.POLY_SYS_network
			val doCall2 = RunCall.run_call2 RuntimeCalls.POLY_SYS_network
		in
			fun getOpt (i:int) (SOCK s) = doCall1(i, s)
			fun setOpt (i: int) (SOCK s, b: bool) = doCall2(i, (s, b))
		end

		fun getDEBUG s = getOpt 18 s
        and setDEBUG s = setOpt 17 s
        and getREUSEADDR s = getOpt 20 s
		and setREUSEADDR s = setOpt 19 s
		and getKEEPALIVE s = getOpt 22 s
		and setKEEPALIVE s = setOpt 21 s
        and getDONTROUTE s = getOpt 24 s
        and setDONTROUTE s = setOpt 23 s
        and getBROADCAST s = getOpt 26 s
        and setBROADCAST s = setOpt 25 s
        and getOOBINLINE s = getOpt 28 s
        and setOOBINLINE s = setOpt 27 s
		and getERROR s = getOpt 34 s
        and getATMARK s = getOpt 45 s

		local
			val doCall1 = RunCall.run_call2 RuntimeCalls.POLY_SYS_network
			val doCall2 = RunCall.run_call2 RuntimeCalls.POLY_SYS_network
		in
			fun getSNDBUF (SOCK s) = doCall1(30, s)
			fun setSNDBUF (SOCK s, i: int) = doCall2(29, (s, i))
			fun getRCVBUF (SOCK s) = doCall1(32, s)
			fun setRCVBUF (SOCK s, i: int) = doCall2(31, (s, i))
			fun getTYPE (SOCK s) = SOCK.SOCKTYPE(doCall1(33, s))
					
			fun getNREAD (SOCK s) = doCall1(44, s)

			fun getLINGER (SOCK s): Time.time option =
			let
				val lTime = doCall1(36, s)
			in
				if lTime < 0 then NONE else SOME(Time.fromSeconds lTime)
			end

			fun setLINGER (SOCK s, NONE) =
				(
					doCall2(35, (s, ~1))
				)
			|	setLINGER (SOCK s, SOME t) =
				let
					val lTime = Time.toSeconds t
				in
					if lTime < 0
					then raise OS.SysErr("Invalid time", NONE)
					else doCall2(35, (s, lTime))
				end
		end

		fun getPeerName (SOCK s): 'af sock_addr =
				RunCall.run_call2 RuntimeCalls.POLY_SYS_network(37, s)

		fun getSockName (SOCK s): 'af sock_addr =
				RunCall.run_call2 RuntimeCalls.POLY_SYS_network (38, s)
		end (* Ctl *)


	(* Run an operation in non-blocking mode.  This catches EWOULDBLOCK and returns NONE,
	   otherwise returns SOME result.  Other exceptions are passed back as normal. *)
	val nonBlockingCall = LibraryIOSupport.nonBlocking

	fun accept (SOCK s) =
		RunCall.run_call2 RuntimeCalls.POLY_SYS_network (46, s)

	local
		fun acc sock = RunCall.run_call2 RuntimeCalls.POLY_SYS_network (58, sock)
	in
		fun acceptNB sock = nonBlockingCall acc sock
	end

	fun bind (SOCK s, a) =
		RunCall.run_call2 RuntimeCalls.POLY_SYS_network (47, (s, a))

 	fun connect (SOCK s, a) =
		RunCall.run_call2 RuntimeCalls.POLY_SYS_network (48, (s, a))

	local
		fun connct sa = RunCall.run_call2 RuntimeCalls.POLY_SYS_network (59, sa)
	in
		fun connectNB (SOCK s, a) =
			case nonBlockingCall connct (s,a) of SOME () => true | NONE => false
	end

 	fun listen (SOCK s, b) =
		RunCall.run_call2 RuntimeCalls.POLY_SYS_network (49, (s, b))

	(* We use the normal "close" for streams.  We can't use the normal
	   "local in" here to avoid the extra function calls at run-time
	   because of the polymorphism. *)
	fun close (SOCK strm): unit =
		RunCall.run_call3 RuntimeCalls.POLY_SYS_io_dispatch(7, strm, 0)

	datatype shutdown_mode = NO_RECVS | NO_SENDS | NO_RECVS_OR_SENDS

    fun shutdown (SOCK s, mode) =
	let
		val m =
			case mode of
				NO_RECVS => 1
			 |  NO_SENDS => 2
			 |  NO_RECVS_OR_SENDS => 3
	in
		RunCall.run_call2 RuntimeCalls.POLY_SYS_network (50, (s, m))
	end

	(* The IO descriptor is the underlying socket. *)
	fun ioDesc (SOCK s) = s;

	type out_flags = {don't_route : bool, oob : bool}
	type in_flags = {peek : bool, oob : bool}
	type 'a buf = {buf : 'a, i : int, sz : int option}

	local
		val nullOut = { don't_route = false, oob = false }
		and nullIn = { peek = false, oob = false }

		(* This implementation is copied from the implementation of
		   Word8Array.array and Word8Vector.vector. *)
		type address = LibrarySupport.address
	    datatype vector = datatype LibrarySupport.Word8Array.vector
		datatype array = datatype LibrarySupport.Word8Array.array
		val wordSize = LibrarySupport.wordSize

		(* Send the data from an array or vector.  Note: the underlying RTS function
		   deals with the special case of sending a single byte vector where the
		   "address" is actually the byte itself. *)
		local
			fun doSend i a = RunCall.run_call2 RuntimeCalls.POLY_SYS_network (i, a)
		in
			fun send (SOCK sock, base: address, offset: int, length: int, rt: bool, oob: bool): int =
				doSend 51 (sock, base, offset, length, rt, oob)
	
			fun sendNB (SOCK sock, base: address, offset: int, length: int, rt: bool, oob: bool): int option =
				nonBlockingCall (doSend 60) (sock, base, offset, length, rt, oob)
		end

		local
			(* Although the underlying call returns the number of bytes written the
			   ML functions now return unit. *)
			fun doSendTo i a = RunCall.run_call2 RuntimeCalls.POLY_SYS_network (i, a)
		in
			fun sendTo (SOCK sock, addr, base: address, offset: int, length: int, rt: bool, oob: bool): unit =
				doSendTo 52 (sock, addr, base, offset, length, rt, oob)
	
			fun sendToNB (SOCK sock, addr, base: address, offset: int, length: int, rt: bool, oob: bool): bool =
				case nonBlockingCall (doSendTo 61) (sock, addr, base, offset, length, rt, oob) of
					NONE => false | SOME _ => true
		end

		local
			fun doRecv i a = RunCall.run_call2 RuntimeCalls.POLY_SYS_network (i, a)
		in
			(* Receive the data into an array. *)
			fun recv (SOCK sock, base: address, offset: int, length: int, peek: bool, oob: bool): int =
				doRecv 53 (sock, base, offset, length, peek, oob)

			fun recvNB (SOCK sock, base: address, offset: int, length: int, peek: bool, oob: bool): int option =
				nonBlockingCall (doRecv 62) (sock, base, offset, length, peek, oob)
		end

		local
			fun doRecvFrom i a = RunCall.run_call2 RuntimeCalls.POLY_SYS_network (i, a)
		in 
			fun recvFrom (SOCK sock, base: address, offset: int, length: int, peek: bool, oob: bool) =
				doRecvFrom 54 (sock, base, offset, length, peek, oob)

			fun recvFromNB (SOCK sock, base: address, offset: int, length: int, peek: bool, oob: bool) =
				nonBlockingCall (doRecvFrom 63) (sock, base, offset, length, peek, oob)
		end
	in
		fun sendVec' (sock, slice: Word8VectorSlice.slice, {don't_route, oob}) =
		let
			val (Vector v, i, length) = Word8VectorSlice.base slice
		in
			send(sock, v, i + Word.toInt wordSize, length, don't_route, oob)
		end
		and sendVec (sock, vbuff) = sendVec'(sock, vbuff, nullOut)
		
		fun sendVecNB' (sock, slice: Word8VectorSlice.slice, {don't_route, oob}) =
		let
			val (Vector v, i, length) = Word8VectorSlice.base slice
		in
			sendNB(sock, v, i + Word.toInt wordSize, length, don't_route, oob)
		end
		and sendVecNB (sock, vbuff) = sendVecNB'(sock, vbuff, nullOut)
	
		fun sendArr' (sock, slice: Word8ArraySlice.slice, {don't_route, oob}) =
		let
			val (Array(_, v), i, length) = Word8ArraySlice.base slice
		in
			send(sock, v, i, length, don't_route, oob)
		end
		and sendArr (sock, vbuff) = sendArr'(sock, vbuff, nullOut)
		
		fun sendArrNB' (sock, slice: Word8ArraySlice.slice, {don't_route, oob}) =
		let
			val (Array(_, v), i, length) = Word8ArraySlice.base slice
		in
			sendNB(sock, v, i, length, don't_route, oob)
		end
		and sendArrNB (sock, vbuff) = sendArrNB'(sock, vbuff, nullOut)
	
		fun sendVecTo' (sock, addr, slice: Word8VectorSlice.slice, {don't_route, oob}) =
		let
			val (Vector v, i, length) = Word8VectorSlice.base slice
		in
			sendTo(sock, addr, v, i + Word.toInt wordSize, length, don't_route, oob)
		end
		and sendVecTo (sock, addr, vbuff) = sendVecTo'(sock, addr, vbuff, nullOut)

		fun sendVecToNB' (sock, addr, slice: Word8VectorSlice.slice, {don't_route, oob}) =
		let
			val (Vector v, i, length) = Word8VectorSlice.base slice
		in
			sendToNB(sock, addr, v, i + Word.toInt wordSize, length, don't_route, oob)
		end
		and sendVecToNB (sock, addr, vbuff) = sendVecToNB'(sock, addr, vbuff, nullOut)

		fun sendArrTo' (sock, addr, slice: Word8ArraySlice.slice, {don't_route, oob}) =
		let
			val (Array(_, v), i, length) = Word8ArraySlice.base slice
		in
			sendTo(sock, addr, v, i, length, don't_route, oob)
		end
		and sendArrTo (sock, addr, vbuff) = sendArrTo'(sock, addr, vbuff, nullOut)

		fun sendArrToNB' (sock, addr, slice: Word8ArraySlice.slice, {don't_route, oob}) =
		let
			val (Array(_, v), i, length) = Word8ArraySlice.base slice
		in
			sendToNB(sock, addr, v, i, length, don't_route, oob)
		end
		and sendArrToNB (sock, addr, vbuff) = sendArrToNB'(sock, addr, vbuff, nullOut)

		fun recvArr' (sock, slice: Word8ArraySlice.slice, {peek, oob}) =
		let
			val (Array(_, v), i, length) = Word8ArraySlice.base slice
		in
			recv(sock, v, i, length, peek, oob)
		end
		and recvArr (sock, vbuff) = recvArr'(sock, vbuff, nullIn)

		fun recvArrNB' (sock, slice: Word8ArraySlice.slice, {peek, oob}) =
		let
			val (Array(_, v), i, length) = Word8ArraySlice.base slice
		in
			recvNB(sock, v, i, length, peek, oob)
		end
		and recvArrNB (sock, vbuff) = recvArrNB'(sock, vbuff, nullIn)
	
		(* To receive a vector first create an array, read into it,
		   then copy it to a new vector.  This does involve extra copying
		   but it probably doesn't matter too much. *)
		fun recvVec' (sock, size, flags) =
		let
			val arr = Word8Array.array(size, 0w0);
			val recvd = recvArr'(sock, Word8ArraySlice.full arr, flags)
		in
			Word8ArraySlice.vector(Word8ArraySlice.slice(arr, 0, SOME recvd))
		end
		and recvVec (sock, size) = recvVec'(sock, size, nullIn)

		fun recvVecNB' (sock, size, flags) =
		let
			val arr = Word8Array.array(size, 0w0);
		in
			case recvArrNB'(sock, Word8ArraySlice.full arr, flags) of
				NONE => NONE
			|	SOME recvd => SOME(Word8ArraySlice.vector(Word8ArraySlice.slice(arr, 0, SOME recvd)))
		end
		and recvVecNB (sock, size) = recvVecNB'(sock, size, nullIn)

		fun recvArrFrom' (sock, slice: Word8ArraySlice.slice, {peek, oob}) =
		let
			val (Array(_, v), i, length) = Word8ArraySlice.base slice
		in
			recvFrom(sock, v, i, length, peek, oob)
		end
		and recvArrFrom (sock, abuff) = recvArrFrom'(sock, abuff, nullIn)


		fun recvArrFromNB' (sock, slice: Word8ArraySlice.slice, {peek, oob}) =
		let
			val (Array(_, v), i, length) = Word8ArraySlice.base slice
		in
			recvFromNB(sock, v, i, length, peek, oob)
		end
		and recvArrFromNB (sock, abuff) = recvArrFromNB'(sock, abuff, nullIn)

		fun recvVecFrom' (sock, size, flags) =
		let
			val arr = Word8Array.array(size, 0w0);
			val (rcvd, addr) =
				recvArrFrom'(sock, Word8ArraySlice.full arr, flags)
		in
			(Word8ArraySlice.vector(Word8ArraySlice.slice(arr, 0, SOME rcvd)), addr)
		end
		and recvVecFrom (sock, size) = recvVecFrom'(sock, size, nullIn)

		fun recvVecFromNB' (sock, size, flags) =
		let
			val arr = Word8Array.array(size, 0w0);
		in
			case recvArrFromNB'(sock, Word8ArraySlice.full arr, flags) of
				NONE => NONE
			|	SOME (rcvd, addr) =>
					SOME (Word8ArraySlice.vector(Word8ArraySlice.slice(arr, 0, SOME rcvd)), addr)			
		end
		and recvVecFromNB (sock, size) = recvVecFromNB'(sock, size, nullIn)

	end

	(* "select" call. *)
	datatype sock_desc = SOCKDESC of OS.IO.iodesc
	fun sockDesc (SOCK sock) = SOCKDESC sock (* Create a socket descriptor from a socket. *)
	fun sameDesc (SOCKDESC a, SOCKDESC b) = a = b

	local
		(* The underlying call takes three arrays and updates them with the sockets that are
		   in the appropriate state.  It sets inactive elements to ~1. *)
		val doIo: int * (OS.IO.iodesc Vector.vector * OS.IO.iodesc Vector.vector * OS.IO.iodesc Vector.vector * Time.time) ->
					OS.IO.iodesc Vector.vector * OS.IO.iodesc Vector.vector * OS.IO.iodesc Vector.vector
			 = RunCall.run_call2 RuntimeCalls.POLY_SYS_network
	in
		fun sys_select_block(rds, wrs, exs) = doIo(64, (rds, wrs, exs, Time.zeroTime))
		fun sys_select_poll(rds, wrs, exs) = doIo(65, (rds, wrs, exs, Time.zeroTime))
		(* The time parameter for a wait is the absolute time when the timeout expires. *)
		and sys_select_wait (rds, wrs, exs, t) = doIo(66, (rds, wrs, exs, t))
	end
	
	fun select { rds: sock_desc list, wrs : sock_desc list, exs : sock_desc list, timeOut: Time.time option } :
			{ rds: sock_desc list, wrs : sock_desc list, exs : sock_desc list } =
	let
		fun sockDescToDesc(SOCKDESC sock) = sock
		(* Create the initial vectors. *)
		val rdVec: OS.IO.iodesc Vector.vector = Vector.fromList(map sockDescToDesc rds)
		val wrVec: OS.IO.iodesc Vector.vector = Vector.fromList(map sockDescToDesc wrs)
		val exVec: OS.IO.iodesc Vector.vector = Vector.fromList(map sockDescToDesc exs)
		val (rdResult, wrResult, exResult) =
			(* Do the approriate select. *)
			case timeOut of
				NONE => sys_select_block(rdVec, wrVec, exVec)
			|	SOME t => if t <= Time.zeroTime
						  then sys_select_poll(rdVec, wrVec, exVec)
						  else sys_select_wait(rdVec, wrVec, exVec, t + Time.now());
		(* Function to create the results. *)
		fun getResults v = Vector.foldr (fn (sd, l) => SOCKDESC sd :: l) [] v
	in
		(* Convert the results. *)
		{ rds = getResults rdResult, wrs = getResults wrResult, exs = getResults exResult }
	end

end;

local
	(* Install the pretty printer for Socket.AF.addr_family
	   This must be done outside
	   the structure if we use opaque matching. *)
	fun printAF(p, _, _, _) _ _ x = p(Socket.AF.toString x)
	fun printSK(p, _, _, _) _ _ x = p(Socket.SOCK.toString x)
in
	val () = PolyML.install_pp printAF
	val () = PolyML.install_pp printSK
end