|
65 | 65 | mut dst: Destination<'a, Self::Item, Self::Buffer>, |
66 | 66 | finish: bool, |
67 | 67 | ) -> Poll<wasmtime::Result<StreamResult>> { |
| 68 | + // If the destination buffer is empty then this is a request on |
| 69 | + // behalf of the guest to wait for this socket to be ready to accept |
| 70 | + // without actually accepting something. The `TcpListener` in Tokio does |
| 71 | + // not have this capability so we're forced to lie here and say instead |
| 72 | + // "yes we're ready to accept" as a fallback. |
| 73 | + // |
| 74 | + // See WebAssembly/component-model#561 for some more information. |
| 75 | + if dst.remaining(&mut store) == Some(0) { |
| 76 | + return Poll::Ready(Ok(StreamResult::Completed)); |
| 77 | + } |
68 | 78 | let res = match self.listener.poll_accept(cx) { |
69 | 79 | Poll::Ready(res) => res.map(|(stream, _)| stream), |
70 | 80 | Poll::Pending if finish => return Poll::Ready(Ok(StreamResult::Cancelled)), |
@@ -116,37 +126,37 @@ impl<D> StreamProducer<D> for ReceiveStreamProducer { |
116 | 126 | finish: bool, |
117 | 127 | ) -> Poll<wasmtime::Result<StreamResult>> { |
118 | 128 | let res = 'result: { |
119 | | - if let Some(0) = dst.remaining(store.as_context_mut()) { |
120 | | - match self.stream.poll_read_ready(cx) { |
121 | | - Poll::Ready(Ok(())) => return Poll::Ready(Ok(StreamResult::Completed)), |
| 129 | + // 0-length reads are an indication that we should wait for |
| 130 | + // readiness here, so use `poll_read_ready`. |
| 131 | + if dst.remaining(store.as_context_mut()) == Some(0) { |
| 132 | + return match self.stream.poll_read_ready(cx) { |
| 133 | + Poll::Ready(Ok(())) => Poll::Ready(Ok(StreamResult::Completed)), |
122 | 134 | Poll::Ready(Err(err)) => break 'result Err(err.into()), |
123 | | - Poll::Pending if finish => { |
124 | | - return Poll::Ready(Ok(StreamResult::Cancelled)); |
| 135 | + Poll::Pending if finish => Poll::Ready(Ok(StreamResult::Cancelled)), |
| 136 | + Poll::Pending => Poll::Pending, |
| 137 | + }; |
| 138 | + } |
| 139 | + |
| 140 | + let mut dst = dst.as_direct(store, DEFAULT_BUFFER_CAPACITY); |
| 141 | + let buf = dst.remaining(); |
| 142 | + loop { |
| 143 | + match self.stream.try_read(buf) { |
| 144 | + Ok(0) => break 'result Ok(()), |
| 145 | + Ok(n) => { |
| 146 | + dst.mark_written(n); |
| 147 | + return Poll::Ready(Ok(StreamResult::Completed)); |
125 | 148 | } |
126 | | - Poll::Pending => return Poll::Pending, |
127 | | - } |
128 | | - } else { |
129 | | - let mut dst = dst.as_direct(store, DEFAULT_BUFFER_CAPACITY); |
130 | | - let buf = dst.remaining(); |
131 | | - loop { |
132 | | - match self.stream.try_read(buf) { |
133 | | - Ok(0) => break 'result Ok(()), |
134 | | - Ok(n) => { |
135 | | - dst.mark_written(n); |
136 | | - return Poll::Ready(Ok(StreamResult::Completed)); |
137 | | - } |
138 | | - Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { |
139 | | - match self.stream.poll_read_ready(cx) { |
140 | | - Poll::Ready(Ok(())) => continue, |
141 | | - Poll::Ready(Err(err)) => break 'result Err(err.into()), |
142 | | - Poll::Pending if finish => { |
143 | | - return Poll::Ready(Ok(StreamResult::Cancelled)); |
144 | | - } |
145 | | - Poll::Pending => return Poll::Pending, |
| 149 | + Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { |
| 150 | + match self.stream.poll_read_ready(cx) { |
| 151 | + Poll::Ready(Ok(())) => continue, |
| 152 | + Poll::Ready(Err(err)) => break 'result Err(err.into()), |
| 153 | + Poll::Pending if finish => { |
| 154 | + return Poll::Ready(Ok(StreamResult::Cancelled)); |
146 | 155 | } |
| 156 | + Poll::Pending => return Poll::Pending, |
147 | 157 | } |
148 | | - Err(err) => break 'result Err(err.into()), |
149 | 158 | } |
| 159 | + Err(err) => break 'result Err(err.into()), |
150 | 160 | } |
151 | 161 | } |
152 | 162 | }; |
@@ -190,13 +200,15 @@ impl<D> StreamConsumer<D> for SendStreamConsumer { |
190 | 200 | ) -> Poll<wasmtime::Result<StreamResult>> { |
191 | 201 | let mut src = src.as_direct(store); |
192 | 202 | let res = 'result: { |
| 203 | + // A 0-length write is a request to wait for readiness so use |
| 204 | + // `poll_write_ready` to wait for the underlying object to be ready. |
193 | 205 | if src.remaining().is_empty() { |
194 | | - match self.stream.poll_write_ready(cx) { |
195 | | - Poll::Ready(Ok(())) => return Poll::Ready(Ok(StreamResult::Completed)), |
| 206 | + return match self.stream.poll_write_ready(cx) { |
| 207 | + Poll::Ready(Ok(())) => Poll::Ready(Ok(StreamResult::Completed)), |
196 | 208 | Poll::Ready(Err(err)) => break 'result Err(err.into()), |
197 | | - Poll::Pending if finish => return Poll::Ready(Ok(StreamResult::Cancelled)), |
198 | | - Poll::Pending => return Poll::Pending, |
199 | | - } |
| 209 | + Poll::Pending if finish => Poll::Ready(Ok(StreamResult::Cancelled)), |
| 210 | + Poll::Pending => Poll::Pending, |
| 211 | + }; |
200 | 212 | } |
201 | 213 | loop { |
202 | 214 | match self.stream.try_write(src.remaining()) { |
|
0 commit comments