2
* Copyright (C) 2006-2007 XenSource Ltd.
3
* Copyright (C) 2008 Citrix Ltd.
4
* Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU Lesser General Public License as published
8
* by the Free Software Foundation; version 2.1 only. with the special
9
* exception on linking described in file LICENSE.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU Lesser General Public License for more details.
17
module Op = struct include Op end
18
module Packet = struct include Packet end
27
mmap: Mmap.mmap_interface; (* mmaped interface = xs_ring *)
28
eventchn_notify: unit -> unit; (* function to notify through eventchn *)
29
mutable work_again: bool;
37
type backend = Fd of backend_fd | Mmap of backend_mmap
39
type partial_buf = HaveHdr of Partial.pkt | NoHdr of int * string
44
pkt_in: Packet.t Queue.t;
45
pkt_out: Packet.t Queue.t;
46
mutable partial_in: partial_buf;
47
mutable partial_out: string;
50
let init_partial_in () = NoHdr
51
(Partial.header_size (), String.make (Partial.header_size()) '\000')
53
let queue con pkt = Queue.push pkt con.pkt_out
55
let read_fd back con s len =
56
let rd = Unix.read back.fd s 0 len in
61
let read_mmap back con s len =
62
let rd = Xs_ring.read back.mmap s len in
63
back.work_again <- (rd > 0);
65
back.eventchn_notify ();
69
match con.backend with
70
| Fd backfd -> read_fd backfd con s len
71
| Mmap backmmap -> read_mmap backmmap con s len
73
let write_fd back con s len =
74
Unix.write back.fd s 0 len
76
let write_mmap back con s len =
77
let ws = Xs_ring.write back.mmap s len in
79
back.eventchn_notify ();
83
match con.backend with
84
| Fd backfd -> write_fd backfd con s len
85
| Mmap backmmap -> write_mmap backmmap con s len
88
(* get the output string from a string_of(packet) or partial_out *)
89
let s = if String.length con.partial_out > 0 then
91
else if Queue.length con.pkt_out > 0 then
92
Packet.to_string (Queue.pop con.pkt_out)
95
(* send data from s, and save the unsent data to partial_out *)
97
let len = String.length s in
98
let sz = write con s len in
99
let left = String.sub s sz (len - sz) in
100
con.partial_out <- left
102
(* after sending one packet, partial is empty *)
106
let newpacket = ref false in
108
match con.partial_in with
109
| HaveHdr partial_pkt -> Partial.to_complete partial_pkt
110
| NoHdr (i, buf) -> i in
112
(* try to get more data from input stream *)
113
let s = String.make to_read '\000' in
114
let sz = if to_read > 0 then read con s to_read else 0 in
117
match con.partial_in with
118
| HaveHdr partial_pkt ->
119
(* we complete the data *)
121
Partial.append partial_pkt s sz;
122
if Partial.to_complete partial_pkt = 0 then (
123
let pkt = Packet.of_partialpkt partial_pkt in
124
con.partial_in <- init_partial_in ();
125
Queue.push pkt con.pkt_in;
129
(* we complete the partial header *)
131
String.blit s 0 buf (Partial.header_size () - i) sz;
132
con.partial_in <- if sz = i then
133
HaveHdr (Partial.of_string buf) else NoHdr (i - sz, buf)
137
let newcon backend = {
139
pkt_in = Queue.create ();
140
pkt_out = Queue.create ();
141
partial_in = init_partial_in ();
145
let open_fd fd = newcon (Fd { fd = fd; })
147
let open_mmap mmap notifyfct =
150
eventchn_notify = notifyfct;
151
work_again = false; })
154
match con.backend with
155
| Fd backend -> Unix.close backend.fd
156
| Mmap backend -> Mmap.unmap backend.mmap
159
match con.backend with
163
let is_mmap con = not (is_fd con)
165
let output_len con = Queue.length con.pkt_out
166
let has_new_output con = Queue.length con.pkt_out > 0
167
let has_old_output con = String.length con.partial_out > 0
169
let has_output con = has_new_output con || has_old_output con
171
let peek_output con = Queue.peek con.pkt_out
173
let input_len con = Queue.length con.pkt_in
174
let has_in_packet con = Queue.length con.pkt_in > 0
175
let get_in_packet con = Queue.pop con.pkt_in
176
let has_more_input con =
177
match con.backend with
179
| Mmap backend -> backend.work_again
181
let is_selectable con =
182
match con.backend with
187
match con.backend with
188
| Fd backend -> backend.fd
189
| Mmap _ -> raise (Failure "get_fd")