*/
struct xprt_ops {
int (*rcv_buf)(struct connection *conn, struct buffer *buf, int count); /* recv callback */
- int (*snd_buf)(struct connection *conn, struct buffer *buf, int flags); /* send callback */
+ size_t (*snd_buf)(struct connection *conn, const struct buffer *buf, size_t count, int flags); /* send callback */
int (*rcv_pipe)(struct connection *conn, struct pipe *pipe, unsigned int count); /* recv-to-pipe callback */
int (*snd_pipe)(struct connection *conn, struct pipe *pipe); /* send-to-pipe callback */
void (*shutr)(struct connection *, int); /* shutr function */
if (h2c->flags & (H2_CF_MUX_MFULL | H2_CF_DEM_MBUSY | H2_CF_DEM_MROOM))
flags |= CO_SFL_MSG_MORE;
- if (h2c->mbuf->o && conn->xprt->snd_buf(conn, h2c->mbuf, flags) <= 0)
- break;
+ if (h2c->mbuf->o) {
+ int ret = conn->xprt->snd_buf(conn, h2c->mbuf, h2c->mbuf->o, flags);
+ if (!ret)
+ break;
+ b_del(h2c->mbuf, ret);
+ b_realign_if_empty(h2c->mbuf);
+ }
/* wrote at least one byte, the buffer is not full anymore */
h2c->flags &= ~(H2_CF_MUX_MFULL | H2_CF_DEM_MROOM);
if (h2c_send_goaway_error(h2c, NULL) <= 0)
h2c->flags |= H2_CF_GOAWAY_FAILED;
- if (h2c->mbuf->o && !(h2c->flags & H2_CF_GOAWAY_FAILED) && conn_xprt_ready(h2c->conn))
- h2c->conn->xprt->snd_buf(h2c->conn, h2c->mbuf, 0);
+ if (h2c->mbuf->o && !(h2c->flags & H2_CF_GOAWAY_FAILED) && conn_xprt_ready(h2c->conn)) {
+ int ret = h2c->conn->xprt->snd_buf(h2c->conn, h2c->mbuf, h2c->mbuf->o, 0);
+ if (ret > 0) {
+ b_del(h2c->mbuf, ret);
+ b_realign_if_empty(h2c->mbuf);
+ }
+ }
/* either we can release everything now or it will be done later once
* the last stream closes.
/* Called from the upper layer, to send data */
static int mux_pt_snd_buf(struct conn_stream *cs, struct buffer *buf, int flags)
{
- return (cs->conn->xprt->snd_buf(cs->conn, buf, flags));
+ int ret = cs->conn->xprt->snd_buf(cs->conn, buf, buf->o, flags);
+
+ if (ret > 0)
+ b_del(buf, ret);
+
+ b_realign_if_empty(buf);
+ return ret;
}
#if defined(CONFIG_HAP_LINUX_SPLICE)
}
-/* Send all pending bytes from buffer <buf> to connection <conn>'s socket.
- * <flags> may contain some CO_SFL_* flags to hint the system about other
- * pending data for example.
+/* Send up to <count> pending bytes from buffer <buf> to connection <conn>'s
+ * socket. <flags> may contain some CO_SFL_* flags to hint the system about
+ * other pending data for example, but this flag is ignored at the moment.
* Only one call to send() is performed, unless the buffer wraps, in which case
* a second call may be performed. The connection's flags are updated with
* whatever special event is detected (error, empty). The caller is responsible
* for taking care of those events and avoiding the call if inappropriate. The
* function does not call the connection's polling update function, so the caller
- * is responsible for this.
+ * is responsible for this. It's up to the caller to update the buffer's contents
+ * based on the return value.
*/
-static int raw_sock_from_buf(struct connection *conn, struct buffer *buf, int flags)
+static size_t raw_sock_from_buf(struct connection *conn, const struct buffer *buf, size_t count, int flags)
{
- int ret, try, done, send_flag;
+ ssize_t ret;
+ size_t try, done;
+ int send_flag;
if (!conn_ctrl_ready(conn))
return 0;
* to send() unless the buffer wraps and we exactly fill the first hunk,
* in which case we accept to do it once again.
*/
- while (buf->o) {
- try = buf->o;
- /* outgoing data may wrap at the end */
- if (buf->data + try > buf->p)
- try = buf->data + try - buf->p;
+ while (count) {
+ try = b_contig_data(buf, done);
+ if (try > count)
+ try = count;
send_flag = MSG_DONTWAIT | MSG_NOSIGNAL;
- if (try < buf->o || flags & CO_SFL_MSG_MORE)
+ if (try < count || flags & CO_SFL_MSG_MORE)
send_flag |= MSG_MORE;
- ret = send(conn->handle.fd, b_head(buf), try, send_flag);
+ ret = send(conn->handle.fd, b_peek(buf, done), try, send_flag);
if (ret > 0) {
- buf->o -= ret;
+ count -= ret;
done += ret;
- if (likely(buffer_empty(buf)))
- /* optimize data alignment in the buffer */
- buf->p = buf->data;
-
/* if the system buffer is full, don't insist */
if (ret < try)
break;
}
-/* Send all pending bytes from buffer <buf> to connection <conn>'s socket.
- * <flags> may contain some CO_SFL_* flags to hint the system about other
- * pending data for example, but this flag is ignored at the moment.
+/* Send up to <count> pending bytes from buffer <buf> to connection <conn>'s
+ * socket. <flags> may contain some CO_SFL_* flags to hint the system about
+ * other pending data for example, but this flag is ignored at the moment.
* Only one call to send() is performed, unless the buffer wraps, in which case
* a second call may be performed. The connection's flags are updated with
* whatever special event is detected (error, empty). The caller is responsible
* for taking care of those events and avoiding the call if inappropriate. The
* function does not call the connection's polling update function, so the caller
- * is responsible for this.
+ * is responsible for this. The buffer's output is not adjusted, it's up to the
+ * caller to take care of this. It's up to the caller to update the buffer's
+ * contents based on the return value.
*/
-static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int flags)
+static size_t ssl_sock_from_buf(struct connection *conn, const struct buffer *buf, size_t count, int flags)
{
- int ret, try, done;
+ ssize_t ret;
+ size_t try, done;
done = 0;
conn_refresh_polling_flags(conn);
* to send() unless the buffer wraps and we exactly fill the first hunk,
* in which case we accept to do it once again.
*/
- while (buf->o) {
+ while (count) {
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
size_t written_data;
#endif
- try = b_contig_data(buf, 0);
- if (try > buf->o)
- try = buf->o;
+ try = b_contig_data(buf, done);
+ if (try > count)
+ try = count;
if (!(flags & CO_SFL_STREAMER) &&
!(conn->xprt_st & SSL_SOCK_SEND_UNLIMITED) &&
break;
}
}
- ret = SSL_write_early_data(conn->xprt_ctx, b_head(buf), try, &written_data);
+ ret = SSL_write_early_data(conn->xprt_ctx, b_peek(buf, done), try, &written_data);
if (ret == 1) {
ret = written_data;
conn->sent_early_data += ret;
} else
#endif
- ret = SSL_write(conn->xprt_ctx, b_head(buf), try);
+ ret = SSL_write(conn->xprt_ctx, b_peek(buf, done), try);
if (conn->flags & CO_FL_ERROR) {
/* CO_FL_ERROR may be set by ssl_sock_infocbk */
}
if (ret > 0) {
conn->xprt_st &= ~SSL_SOCK_SEND_UNLIMITED;
-
- buf->o -= ret;
+ count -= ret;
done += ret;
-
- if (likely(buffer_empty(buf)))
- /* optimize data alignment in the buffer */
- buf->p = buf->data;
}
else {
ret = SSL_get_error(conn->xprt_ctx, ret);