pespin submitted this change.
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(-)
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);
To view, visit change 30722. To unsubscribe, or for help writing mail filters, visit settings.