dope_session/pool/server/
write.rs1use super::super::Pool;
2use super::super::core::{CodecAck, PushError, WriteDispatch};
3use super::super::slot::{ConnFlags, CoreSlot};
4use super::Server;
5use super::state::SlotEgress;
6use crate::CodecLayer;
7use crate::SlotId;
8use crate::WriteBufStorage;
9use crate::protocol::server::ServerProtocol;
10use dope_core::IoVec;
11use dope_core::driver::{DriverOps, PoolDriver};
12use dope_core::profile::Profile;
13use dope_transport::Transport;
14
15enum WriteEventOutcome {
16 Idle,
17 More,
18 Close,
19}
20
21impl<H: ServerProtocol, T: Transport, F: Profile, B: PoolDriver> super::super::PoolWrite<B>
22 for Pool<Server<H, T>, F, B>
23{
24 fn on_write_event(
25 &mut self,
26 driver: &mut B::Driver,
27 token: B::Token,
28 result: i32,
29 notif: bool,
30 ) {
31 let (slot_idx, result) = match self.core.classify_write(token, result, notif) {
32 WriteDispatch::Skipped => return,
33 WriteDispatch::Ready { slot_idx, result } => (slot_idx, result),
34 };
35 if <H::CodecLayer as CodecLayer>::IS_PASSTHROUGH {
36 if !self.core.slots[slot_idx]
37 .conn
38 .flags
39 .contains(ConnFlags::LIVE)
40 {
41 return;
42 }
43 if result < 0 {
44 self.core.free_slot(driver, slot_idx);
45 return;
46 }
47 let n = result as u32;
48 match self.advance_write_state(slot_idx, n) {
49 WriteEventOutcome::Close => self.core.free_slot(driver, slot_idx),
50 WriteEventOutcome::More => self.submit_slot_write(driver, slot_idx),
51 WriteEventOutcome::Idle => {}
52 }
53 } else {
54 self.handle_write_event_codec(driver, slot_idx, result);
55 }
56 }
57}
58
59impl<H: ServerProtocol, T: Transport, F: Profile, B: PoolDriver> Pool<Server<H, T>, F, B> {
60 fn handle_write_event_codec(&mut self, driver: &mut B::Driver, slot_idx: usize, result: i32) {
61 match self.core.handle_codec_inflight(slot_idx, result) {
62 CodecAck::NoOp => {}
63 CodecAck::Err => self.core.free_slot(driver, slot_idx),
64 CodecAck::Progressed => {
65 self.submit_slot_write(driver, slot_idx);
66 let close = self.core.slots[slot_idx]
67 .conn
68 .flags
69 .contains(ConnFlags::CLOSE_AFTER)
70 || self.core.codec_close_pending(slot_idx);
71 if self.core.codec_idle(slot_idx) && close {
72 self.core.free_slot(driver, slot_idx);
73 }
74 }
75 }
76 }
77
78 #[inline(always)]
79 fn advance_write_state(&mut self, slot_idx: usize, n: u32) -> WriteEventOutcome {
80 let CoreSlot { conn, user, .. } = &mut self.core.slots[slot_idx];
81 let user = user.get_mut();
82
83 if user.egress.is_stream() {
84 if conn.write_tail < conn.write_inflight_end {
85 let new_tail = (conn.write_tail as u32).saturating_add(n);
86 conn.write_tail = new_tail.min(u16::MAX as u32) as u16;
87 if conn.write_tail >= conn.write_inflight_end {
88 conn.write_head = 0;
89 conn.write_tail = 0;
90 conn.write_inflight_end = 0;
91 return WriteEventOutcome::More;
92 }
93 return WriteEventOutcome::Idle;
94 }
95 let SlotEgress::Stream(stream_state) = &mut user.egress else {
96 return WriteEventOutcome::Close;
97 };
98 stream_state.advance(n);
99 if stream_state.eof && stream_state.cur_chunk.is_none() {
100 user.egress = SlotEgress::Idle;
101 if conn.flags.contains(ConnFlags::CLOSE_AFTER) {
102 return WriteEventOutcome::Close;
103 }
104 return WriteEventOutcome::Idle;
105 }
106 return WriteEventOutcome::More;
107 }
108
109 if !conn.pending_body_ptr.is_null() {
110 let new_tail = conn.large_tail.saturating_add(n);
111 conn.large_tail = new_tail;
112 if conn.large_tail >= conn.large_inflight {
113 conn.write_head = 0;
114 conn.write_tail = 0;
115 conn.write_inflight_end = 0;
116 conn.pending_body_ptr = std::ptr::null();
117 conn.pending_body_len = 0;
118 conn.large_inflight = 0;
119 conn.large_tail = 0;
120 if conn.flags.contains(ConnFlags::CLOSE_AFTER) {
121 return WriteEventOutcome::Close;
122 }
123 }
124 return WriteEventOutcome::Idle;
125 }
126
127 if conn.large_inflight > 0 {
128 let new_tail = conn.large_tail.saturating_add(n);
129 conn.large_tail = new_tail;
130 if conn.large_tail >= conn.large_inflight {
131 conn.large_inflight = 0;
132 conn.large_tail = 0;
133 if conn.flags.contains(ConnFlags::CLOSE_AFTER) {
134 return WriteEventOutcome::Close;
135 }
136 if user.egress.gather_iov_count().is_some() {
137 return WriteEventOutcome::More;
138 }
139 }
140 return WriteEventOutcome::Idle;
141 }
142
143 let new_tail = (conn.write_tail as u32).saturating_add(n);
144 conn.write_tail = new_tail.min(u16::MAX as u32) as u16;
145 if conn.write_tail >= conn.write_inflight_end {
146 conn.write_head = 0;
147 conn.write_tail = 0;
148 conn.write_inflight_end = 0;
149 if conn.flags.contains(ConnFlags::CLOSE_AFTER) {
150 return WriteEventOutcome::Close;
151 }
152 }
153 WriteEventOutcome::Idle
154 }
155
156 #[inline(always)]
157 fn try_submit_gather(&mut self, driver: &mut B::Driver, slot_idx: usize) -> bool {
158 let Some(iov_count) = self.core.slots[slot_idx]
159 .user
160 .get()
161 .egress
162 .gather_iov_count()
163 else {
164 return false;
165 };
166 if self.core.slots[slot_idx].io.write.has_in_flight {
167 return true;
168 }
169 let entry = &mut self.core.slots[slot_idx];
170 entry.buf.pending_msghdr.msg_iovlen = iov_count as _;
171 let msg_ptr: *const libc::msghdr = &entry.buf.pending_msghdr;
172 let submitted = unsafe { self.driver_submit_send_msg(driver, slot_idx, msg_ptr) };
173 if submitted {
174 self.core.slots[slot_idx].user.get_mut().egress = SlotEgress::Idle;
175 }
176 true
177 }
178
179 pub fn push_response(
180 &mut self,
181 driver: &mut B::Driver,
182 conn_id: SlotId,
183 bytes: &[u8],
184 close_after: bool,
185 ) -> Result<(), PushError> {
186 debug_assert!(
187 H::SUPPORTS_PARK,
188 "push_response requires ServerProtocol::SUPPORTS_PARK = true",
189 );
190 let slot_idx = self.core.resolve_live_slot(conn_id)?;
191 let entry = &mut self.core.slots[slot_idx];
192 let head = entry.conn.write_head as usize;
193 let room = entry.buf.write_buf.as_slice().len().saturating_sub(head);
194 if bytes.len() > room {
195 return Err(PushError::BufferFull);
196 }
197 entry.buf.write_buf.as_mut_slice()[head..head + bytes.len()].copy_from_slice(bytes);
198 entry.conn.write_head = (head + bytes.len()) as u16;
199 if close_after {
200 entry.conn.flags.set(ConnFlags::CLOSE_AFTER, true);
201 }
202 entry.conn.flags.set(ConnFlags::PARKED, false);
203 self.submit_slot_write(driver, slot_idx);
204 Ok(())
205 }
206
207 #[inline(always)]
208 pub(super) fn submit_slot_write(&mut self, driver: &mut B::Driver, slot_idx: usize) {
209 if !<H::CodecLayer as CodecLayer>::IS_PASSTHROUGH {
210 return self.submit_slot_write_codec(driver, slot_idx);
211 }
212 if self.try_submit_gather(driver, slot_idx) {
213 return;
214 }
215 self.submit_slot_write_plain(driver, slot_idx);
216 }
217
218 fn submit_slot_write_plain(&mut self, driver: &mut B::Driver, slot_idx: usize) {
219 if self.core.slots[slot_idx].user.get().egress.is_stream()
220 && self.core.slots[slot_idx].conn.pending_body_ptr.is_null()
221 {
222 self.encode_stream_chunks_to_buf(slot_idx);
223 }
224
225 let stream_in_progress = self.core.slots[slot_idx].user.get().egress.is_stream();
226 let CoreSlot { conn, buf, io, .. } = &mut self.core.slots[slot_idx];
227 let head = conn.write_head as usize;
228 let inflight_end = conn.write_inflight_end as usize;
229 if head <= inflight_end {
230 if stream_in_progress {
231 return self.submit_stream_write(driver, slot_idx);
232 }
233 return;
234 }
235 if io.write.has_in_flight {
236 return;
237 }
238
239 if !conn.pending_body_ptr.is_null() {
240 let hdr_ptr = buf.write_buf.as_mut_slice()[inflight_end..head].as_ptr();
241 let hdr_len = head - inflight_end;
242 let body_ptr = conn.pending_body_ptr;
243 let body_len = conn.pending_body_len as usize;
244 buf.pending_iovs[0] = IoVec::raw(hdr_ptr, hdr_len);
245 buf.pending_iovs[1] = IoVec::raw(body_ptr, body_len);
246 buf.pending_msghdr.msg_iovlen = 2;
247 let msg_ptr: *const libc::msghdr = &buf.pending_msghdr;
248 conn.large_inflight = (hdr_len as u32).saturating_add(body_len as u32);
249 conn.large_tail = 0;
250 conn.write_inflight_end = head as u16;
251 let _ = unsafe { self.driver_submit_send_msg(driver, slot_idx, msg_ptr) };
252 } else {
253 let bytes_ptr = buf.write_buf.as_mut_slice()[inflight_end..head].as_ptr();
254 let bytes_len = (head - inflight_end) as u32;
255 let _ = self.driver_submit_send(driver, slot_idx, bytes_ptr, bytes_len);
256 self.core.slots[slot_idx].conn.write_inflight_end = head as u16;
257 }
258 }
259
260 #[inline(always)]
261 pub(super) fn driver_submit_send(
262 &mut self,
263 driver: &mut B::Driver,
264 slot_idx: usize,
265 ptr: *const u8,
266 len: u32,
267 ) -> bool {
268 let external = self.core.slot_id_base + slot_idx;
269 let conn_fd = self.core.slots[slot_idx].conn.fd;
270 let write_slot = &mut self.core.slots[slot_idx].io.write;
271 let (token, epoch) = write_slot.next_token::<B::Token>(external);
272 if driver.submit_send_tagged(token, conn_fd, ptr, len) {
273 self.core.slots[slot_idx].io.write.mark_inflight(epoch);
274 true
275 } else {
276 false
277 }
278 }
279
280 #[inline(always)]
281 pub(super) unsafe fn driver_submit_send_msg(
282 &mut self,
283 driver: &mut B::Driver,
284 slot_idx: usize,
285 msg: *const libc::msghdr,
286 ) -> bool {
287 let external = self.core.slot_id_base + slot_idx;
288 let conn_fd = self.core.slots[slot_idx].conn.fd;
289 let write_slot = &mut self.core.slots[slot_idx].io.write;
290 let (token, epoch) = write_slot.next_token::<B::Token>(external);
291 if unsafe { driver.submit_send_msg_tagged(token, conn_fd, msg) } {
292 self.core.slots[slot_idx].io.write.mark_inflight(epoch);
293 true
294 } else {
295 false
296 }
297 }
298
299 fn submit_slot_write_codec(&mut self, driver: &mut B::Driver, slot_idx: usize) {
300 let stream_in_progress = self.core.slots[slot_idx].user.get().egress.is_stream();
301 if stream_in_progress && self.core.slots[slot_idx].conn.pending_body_ptr.is_null() {
302 self.encode_stream_chunks_to_buf(slot_idx);
303 }
304
305 self.core.encrypt_write_buf(slot_idx);
306
307 if !self.core.slots[slot_idx].conn.pending_body_ptr.is_null() {
308 let body_ptr = self.core.slots[slot_idx].conn.pending_body_ptr;
309 let body_len = self.core.slots[slot_idx].conn.pending_body_len as usize;
310
311 let body = unsafe { std::slice::from_raw_parts(body_ptr, body_len) };
312 <H::CodecLayer as CodecLayer>::process_outbound(
313 self.core.slots[slot_idx].codec_state.get_mut(),
314 body,
315 );
316 self.core.slots[slot_idx].conn.pending_body_ptr = std::ptr::null();
317 self.core.slots[slot_idx].conn.pending_body_len = 0;
318 self.core.slots[slot_idx].conn.large_inflight = 0;
319 self.core.slots[slot_idx].conn.large_tail = 0;
320 }
321
322 self.core.try_submit_codec(driver, slot_idx);
323 }
324}