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
let min x y = if (x:int) <= y then x else y
let buffer_len = 4096
type out_channel = {
out_fd : Unix.file_descr;
out_buf : Bytes.t;
mutable out1 : int;
}
let out_channel_of_descr fd = {
out_fd = fd;
out_buf = Bytes.create buffer_len; out1 = 0; }
let descr_of_out_channel outchan = outchan.out_fd
type in_channel = {
in_fd : Unix.file_descr;
in_buf : Bytes.t;
mutable in0 : int;
mutable in1 : int;
}
let in_channel_of_descr fd = {
in_fd = fd;
in_buf = Bytes.create buffer_len; in0 = 0; in1 = 0 }
let descr_of_in_channel inchan = inchan.in_fd
let flush_noerr oc =
let rec write i0 len =
let w = Unix.write oc.out_fd oc.out_buf i0 len in
if w < len then write (i0 + w) (len - w) in
write 0 oc.out1;
oc.out1 <- 0
let flush oc =
if oc.out1 >= 0 then flush_noerr oc
let close_out oc =
if oc.out1 >= 0 then begin
flush_noerr oc;
Unix.close oc.out_fd;
oc.out1 <- -1
end
let rec unsafe_output oc buf pos len =
let w = min len (buffer_len - oc.out1) in
Bytes.blit buf pos oc.out_buf oc.out1 w;
oc.out1 <- oc.out1 + w;
if w < len then begin
flush_noerr oc;
unsafe_output oc buf (pos + w) (len - w)
end
let output oc buf pos len =
if pos < 0 || len < 0 || pos + len > Bytes.length buf
then invalid_arg "Socket.output";
if oc.out1 < 0 then raise(Sys_error "Bad file descriptor");
unsafe_output oc buf pos len
let output_string oc s =
if oc.out1 < 0 then raise(Sys_error "Bad file descriptor");
unsafe_output oc (Bytes.unsafe_of_string s) 0 (String.length s)
let output_char oc c =
if oc.out1 < 0 then raise(Sys_error "Bad file descriptor");
if oc.out1 = buffer_len then flush_noerr oc;
Bytes.unsafe_set oc.out_buf oc.out1 c;
oc.out1 <- oc.out1 + 1
let fprintf oc =
Printf.kprintf (fun s -> output_string oc s)
let close_in chan =
if chan.in1 >= 0 then begin
Unix.close chan.in_fd;
chan.in0 <- 0;
chan.in1 <- -1
end
let fill_in_buf chan =
if chan.in0 >= chan.in1 then begin
chan.in0 <- 0;
try
chan.in1 <- Unix.read chan.in_fd chan.in_buf 0 buffer_len;
with
| Unix.Unix_error(Unix.EAGAIN, _, _)
| Unix.Unix_error(Unix.EWOULDBLOCK, _, _) -> raise Sys_blocked_io
end
let unsafe_input chan buf ofs len =
fill_in_buf chan;
let r = min len (chan.in1 - chan.in0) in
Bytes.blit chan.in_buf chan.in0 buf ofs r;
chan.in0 <- chan.in0 + r;
r
let input ic buf ofs len =
if ofs < 0 || len < 0 || ofs + len > Bytes.length buf
then invalid_arg "Socket.input";
if ic.in1 < 0 then raise(Sys_error "Bad file descriptor");
unsafe_input ic buf ofs len
let input_char ic =
if ic.in1 < 0 then raise(Sys_error "Bad file descriptor");
fill_in_buf ic;
if ic.in1 = 0 then raise End_of_file
else
let c = Bytes.unsafe_get ic.in_buf ic.in0 in
ic.in0 <- ic.in0 + 1;
c
let rec unsafe_really_input ic s ofs len =
if len > 0 then begin
let r = unsafe_input ic s ofs len in
if r = 0 then raise End_of_file
else unsafe_really_input ic s (ofs+r) (len-r)
end
let really_input ic s ofs len =
if ofs < 0 || len < 0 || ofs + len > Bytes.length s
then invalid_arg "Socket.really_input";
if ic.in1 < 0 then raise(Sys_error "Bad file descriptor");
unsafe_really_input ic s ofs len
let index_in_range i0 i1 c s =
let rec examine i =
if i < i1 then
if Bytes.unsafe_get s i = c then i
else examine (i+1)
else i1 in
examine i0
let input_till c ic buf ofs len =
if ofs < 0 || len < 0 || ofs + len > Bytes.length buf
then invalid_arg "Socket.input_till";
if ic.in1 < 0 then raise(Sys_error "Bad file descriptor");
fill_in_buf ic;
if ic.in1 = 0 then raise End_of_file;
let in1 = min (ic.in0 + len) ic.in1 in
let i = index_in_range ic.in0 in1 c ic.in_buf in
let r = i - ic.in0 in
Bytes.blit ic.in_buf ic.in0 buf ofs r;
ic.in0 <- i;
r
let rec input_till_char acc c ic =
fill_in_buf ic;
if ic.in1 = 0 then
if acc = Bytes.empty then raise End_of_file else acc
else begin
let i = index_in_range ic.in0 ic.in1 c ic.in_buf in
let line = Bytes.cat acc (Bytes.sub ic.in_buf ic.in0 (i - ic.in0)) in
ic.in0 <- i + 1;
if i = ic.in1 then input_till_char line c ic
else line
end
let input_line ic =
if ic.in1 < 0 then raise(Sys_error "Bad file descriptor");
Bytes.unsafe_to_string(input_till_char Bytes.empty '\n' ic)
let input_all_till c ic =
if ic.in1 < 0 then raise(Sys_error "Bad file descriptor");
Bytes.unsafe_to_string(input_till_char Bytes.empty c ic)
let open_connection sockaddr =
let sock =
Unix.socket (Unix.domain_of_sockaddr sockaddr) Unix.SOCK_STREAM 0 in
try
Unix.connect sock sockaddr;
(in_channel_of_descr sock, out_channel_of_descr sock)
with exn ->
Unix.close sock; raise exn
let shutdown_connection ic =
Unix.shutdown (descr_of_in_channel ic) Unix.SHUTDOWN_SEND
let select inl outl t =
let (inbuf, inempty) = List.partition (fun c -> c.in0 < c.in1) inl in
let inempty_fd = List.map (fun c -> c.in_fd) inempty in
let out_fd = List.map (fun c -> c.out_fd) outl in
let (in_ready, out_ready, _) = Unix.select inempty_fd out_fd [] t in
(inbuf @ List.filter (fun c -> List.mem c.in_fd in_ready) inempty,
List.filter (fun c -> List.mem c.out_fd out_ready) outl)
class out_channel_obj chan_init =
object
val chan = chan_init
method output buf pos len =
output chan buf pos len;
len
method flush () = flush chan
method close_out () = close_out chan
method output_string = output_string chan
method output_char = output_char chan
method fprintf : 'a. ('a, unit, string, unit) format4 -> 'a
= fprintf chan
end
class in_channel_obj chan_init =
object
val chan = chan_init
method input = input chan
method close_in() = close_in chan
method input_char () = input_char chan
method really_input = really_input chan
method input_till c = input_till c chan
method input_line () = input_line chan
method input_all_till c = input_all_till c chan
end