14 let fail fmt
= Printf.kprintf
(fun s
-> failwith s
) fmt
;;
16 let log fmt
= Printf.kprintf ignore fmt
;;
18 let r8 s o
= Char.code s
.[o
];;
19 let r16 s o
= let b1 = r8 s o
and b2
= r8 s
(o
+1) in (b1 lsl 8) lor b2
;;
20 let r16s s o
= let i = r16 s
0 in i - ((i lor 0x8000) lsl 1);;
23 and w2
= r16 s
(o
+2) in
24 Int32.logor
(Int32.shift_left
(Int32.of_int
w1) 16) (Int32.of_int w2
)
26 let rint s o
= let l = r32 s o
in Int32.to_int
l;;
27 let w8 s o
i = s
.[o
] <- Char.chr
(i land 255);;
28 let w16 s o
i = w8 s
(o
+1) i; w8 s o
(i lsr 8);;
29 let wint s o
i = w16 s
(o
+2) i; w16 s o
(i asr 16);;
31 w16 s
(o
+2) (Int32.to_int
l);
32 w16 s o
(Int32.to_int
(Int32.shift_right
l 16));
36 let b = Buffer.create
20 in
37 Buffer.add_string
b "\002xyy";
39 let nencodings = List.fold_left
40 (fun n
i -> w32 c 0 i; Buffer.add_string
b c; succ n
)
43 let s = Buffer.contents
b in
49 let s = String.create
20 in
64 let setaudiofmt ~fmt ~nchannels ~freq
=
65 let s = String.create
10 in
76 let s = String.create
4 in
83 let create_context ~w ~h ~encset
=
86 match encset
.audiofmt
with
90 | _
-> fail "invalid audiofmt %d" encset
.audiofmt
92 let _frame_size = sample_size * encset
.nchannels
in
95 { audio_running
= false
97 String.make
bytes_per_frame '
\000'
(* wrong for unsigned *)
102 let n = rint (pump#get
4) 0 in
103 let s = pump#get
n in
104 fail "Protocol failure, reason: `%S'" s;
107 let rec handshake encset pump
=
108 let s = pump#get
12 in
111 let dec a
b c = a
*100 + b*10 + c in
112 Scanf.sscanf
s "RFB %1i%1i%1i.%1i%1i%1i\n"
113 (fun a
b c d e f
-> dec a
b c, dec d e f
)
115 fail "can't parse ProtocolVersion `%S'" s
118 if maj < 3 || (maj == 3 && min
< 8)
119 then fail "Too old of a protocol %d.%d" maj min
;
121 pump#put
"RFB 003.008\n";
122 let s = let nsectypes = r8 (pump#get
1) 0 in pump#get
nsectypes in
123 (try ignore
(String.index
s '
\001'
)
124 with Not_found
-> fail "None auth not found");
126 if r32 (pump#get
4) 0 <> 0l then reason pump
;
128 serverinit encset pump
130 and serverinit encset pump
=
131 let s = pump#get
24 in
134 and namelen
= rint s 20 in
135 let name = pump#get namelen
in
137 printf
"server is `%S'@." name;
138 pump#put
(encodings encset
);
141 let context = create_context ~
w ~h ~encset
in
142 boot encset
context pump
144 and boot encset t pump
=
147 match r8 (pump#get
1) 0 with
148 | 000 -> framebuffer_update t
150 | msg
-> fail "unexpected server message %x" msg
152 and framebuffer_update t
=
153 let nrects = r16 (pump#get
3) 1 in
154 let rec loop t
i = if i = nrects then t
else
155 let s = pump#get
12 in
158 | -259l -> loop (audio_ack t
) (i+1)
159 | _
-> fail "rect with unhandled encoding %lx, %S" e s
165 let fmt = encset
.audiofmt
166 and nchannels
= encset
.nchannels
167 and freq
= Int32.of_int encset
.freq
in
168 pump#put
(setaudiofmt ~
fmt ~nchannels ~freq
);
173 match r8 (pump#get
1) 0 with
175 | msg
-> fail "unexpected aliguori message %x" msg
178 match r16 (pump#get
2) 0 with
179 | 000 -> srv1 { t with audio_running
= false }
180 | 001 -> srv1 { t with audio_running
= true }
181 | 002 -> audio_data
t
182 | msg
-> fail "unexpected audio message %x" msg
185 let nbytes = rint (pump#get
4) 0 in
186 let audio = pump#get
nbytes in
187 pump#add_audio
audio;
196 if String.length addr
> 5 && String.sub addr
0 5 = "unix:"
198 let path = String.sub addr
5 (String.length addr
- 5) in
199 let sock = Unix.socket
Unix.PF_UNIX
Unix.SOCK_STREAM
0 in
200 sock, Unix.ADDR_UNIX
path
202 let sock = Unix.socket
Unix.PF_INET
Unix.SOCK_STREAM
0 in
205 let p = String.index
addr '
:'
in
206 let s = String.sub
addr (p + 1) (String.length
addr - p - 1) in
208 try int_of_string
s with exn
->
209 fail "can't parse port in `%S': %s"
210 addr (Printexc.to_string exn
)
212 let addr = String.sub
addr 0 p in
217 let addr = (Unix.gethostbyname
addr).Unix.h_addr_list
.(0) in
218 sock, Unix.ADDR_INET
(addr, port)
220 Unix.connect
sock addr;
224 let pump encset
sock =
225 let null = Unix.openfile
"/dev/null" [] 0 in
226 let rapipe, wapipe
= Unix.pipe
() in
228 Unix.set_close_on_exec wapipe
;
229 Unix.set_close_on_exec
sock;
230 Unix.set_nonblock wapipe
;
232 let _pid = Unix.create_process
234 [| "/bin/sh"; "./acap.sh"; string_of_int
(Obj.magic
rapipe) |]
242 if n = 0 then fail "%s: end of file" c;
243 if n = l then () else loop (p + n) (l - n)
244 in loop 0 (String.length
s)
246 let rec write s fd buf pos len
() =
249 let n = Unix.write fd buf pos len
in
250 if n = 0 then fail "EOF while writing %s" s;
252 with Unix.Unix_error
(Unix.EAGAIN
, _
, _
) -> 0
254 if n = 0 then `again
else
257 else `more
(write s fd buf
(pos
+n) (len
-n))
265 let _, l, _ = Unix.select
[] [wapipe
] [] 0.0 in
266 let rec loop = function
268 let rec wrall accu
= function
269 | [] -> List.rev accu
272 | `completed
-> wrall accu tl
273 | `again
-> f
:: accu
274 | `more f
-> f
:: accu
282 method add_audio data
=
283 al
:= !al
@ [write "audio" wapipe data
0 (String.length data
)]
286 let r, _, _ = Unix.select
[sock] [] [] dur
in
289 method get
n = let s = String.create
n in rw "get" (Unix.read
sock) s; s
290 method put
s = rw "put" (Unix.write sock) s
295 let host = ref "localhost:5900" in
296 Arg.parse
(Arg.align
[])
298 "Usage: acap [host]\n";
306 let sock = vncopen !host in
307 let pump = pump encset sock in
308 handshake encset pump;
309 with Unix.Unix_error
(e, s1
, s2
) ->
310 eprintf
"%s(%s): %s@." s1 s2
(Unix.error_message
e)