| 187 | } |
| 188 | |
| 189 | static int send_all(cbm_http_conn_t *connection, const void *data, size_t len, int64_t deadline) { |
| 190 | const char *p = data; |
| 191 | size_t off = 0; |
| 192 | while (off < len) { |
| 193 | if (wait_connection_ready(connection, true, deadline) != 1) |
| 194 | return -1; |
| 195 | size_t available = len - off; |
| 196 | /* Bounded slices: a single nonblocking send() on Windows is absorbed |
| 197 | * wholesale into AFD kernel buffers regardless of SO_SNDBUF, so one |
| 198 | * giant call can never observe backpressure (and pins its full size |
| 199 | * in nonpaged pool). Slicing keeps absorption bounded by the send |
| 200 | * buffer so a non-reading peer hits EWOULDBLOCK deterministically. */ |
| 201 | if (available > CBM_HTTP_SEND_SLICE_BYTES) |
| 202 | available = CBM_HTTP_SEND_SLICE_BYTES; |
| 203 | #ifdef _WIN32 |
| 204 | int n = send(connection->fd, p + off, (int)available, CBM_SEND_FLAGS); |
| 205 | #else |
| 206 | ssize_t n = send(connection->fd, p + off, available, CBM_SEND_FLAGS); |
| 207 | #endif |
| 208 | if (n < 0 && socket_would_block()) |
| 209 | continue; |
| 210 | if (n <= 0) |
| 211 | return -1; |
| 212 | off += (size_t)n; |
| 213 | } |
| 214 | return 0; |
| 215 | } |
| 216 | |
| 217 | /* ── Listener ─────────────────────────────────────────────────── */ |
| 218 |
no test coverage detected