pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-netif/+/30722 )
Change subject: stream: Fix tx data dropped upon show socket write ......................................................................
stream: Fix tx data dropped upon show socket write
On some stream socket types like TCP it is expected that the send() syscall may return a short write, ie not all bytes being copied to the socket. In that case we need to keep the bytes not copied and attempt to submit them later.
Related: OS#5836 Change-Id: I3755aada02ceb186fb990604e3496126fe47e1fb --- M src/stream.c 1 file changed, 22 insertions(+), 12 deletions(-)
Approvals: Jenkins Builder: Verified daniel: Looks good to me, but someone else must approve dexter: Looks good to me, but someone else must approve osmith: Looks good to me, but someone else must approve laforge: Looks good to me, approved pespin: Looks good to me, but someone else must approve
diff --git a/src/stream.c b/src/stream.c index 503fe3c..feb6c22 100644 --- a/src/stream.c +++ b/src/stream.c @@ -335,16 +335,14 @@ struct sctp_sndrcvinfo sinfo; #endif struct msgb *msg; - struct llist_head *lh; int ret;
if (llist_empty(&cli->tx_queue)) { osmo_fd_write_disable(&cli->ofd); return 0; } - lh = cli->tx_queue.next; - llist_del(lh); - msg = llist_entry(lh, struct msgb, list); + msg = llist_first_entry(&cli->tx_queue, struct msgb, list); + llist_del(&msg->list);
if (!osmo_stream_cli_is_connected(cli)) { LOGSCLI(cli, LOGL_ERROR, "not connected, dropping data!\n"); @@ -379,13 +377,20 @@ default: ret = -ENOTSUP; } + + if (ret >= 0 && ret < msgb_length(msg)) { + LOGP(DLINP, LOGL_ERROR, "short send: %d < exp %u\n", ret, msgb_length(msg)); + /* Update msgb and re-add it at the start of the queue: */ + msgb_pull(msg, ret); + llist_add(&msg->list, &cli->tx_queue); + return 0; + } + if (ret < 0) { if (errno == EPIPE || errno == ENOTCONN) { osmo_stream_cli_reconnect(cli); } LOGSCLI(cli, LOGL_ERROR, "error %d to send\n", ret); - } else if (ret < msgb_length(msg)) { - LOGP(DLINP, LOGL_ERROR, "short send: %d < exp %u\n", ret, msgb_length(msg)); }
msgb_free(msg); @@ -1309,16 +1314,14 @@ struct sctp_sndrcvinfo sinfo; #endif struct msgb *msg; - struct llist_head *lh; int ret;
if (llist_empty(&conn->tx_queue)) { osmo_fd_write_disable(&conn->ofd); return; } - lh = conn->tx_queue.next; - llist_del(lh); - msg = llist_entry(lh, struct msgb, list); + msg = llist_first_entry(&conn->tx_queue, struct msgb, list); + llist_del(&msg->list);
LOGP(DLINP, LOGL_DEBUG, "sending %u bytes of data\n", msg->len);
@@ -1349,10 +1352,17 @@ ret = -1; errno = ENOTSUP; } + + if (ret >= 0 && ret < msgb_length(msg)) { + LOGP(DLINP, LOGL_ERROR, "short send: %d < exp %u\n", ret, msgb_length(msg)); + /* Update msgb and re-add it at the start of the queue: */ + msgb_pull(msg, ret); + llist_add(&msg->list, &conn->tx_queue); + return; + } + if (ret == -1) /* send(): On error -1 is returned, and errno is set appropriately */ LOGP(DLINP, LOGL_ERROR, "error to send: %s\n", strerror(errno)); - else if (ret < msgb_length(msg)) - LOGP(DLINP, LOGL_ERROR, "short send: %d < exp %u\n", ret, msgb_length(msg));
msgb_free(msg);