osmo_io: Factor out and use common send function from backend

This handles reenqueuing a message on EAGAIN and incomplete write

Change-Id: I6da2653d32aedd0e7872be0cf90a841b56462e59
diff --git a/src/core/osmo_io.c b/src/core/osmo_io.c
index 8507f46..e059f87 100644
--- a/src/core/osmo_io.c
+++ b/src/core/osmo_io.c
@@ -344,6 +344,46 @@
 	}
 }
 
+/*! completion handler: Calld by osmo_io backend after a given I/O operation has completed
+ *  \param[in] iofd I/O file-descriptor on which I/O has completed
+ *  \param[in] rc return value of the I/O operation
+ *  \param[in] msghdr serialized msghdr containing state of completed I/O
+ */
+void iofd_handle_send_completion(struct osmo_io_fd *iofd, int rc, struct iofd_msghdr *msghdr)
+{
+	struct msgb *msg = msghdr->msg;
+
+	/* Incomplete write */
+	if (rc > 0 && rc < msgb_length(msg)) {
+		/* Re-enqueue remaining data */
+		msgb_pull(msg, rc);
+		msghdr->iov[0].iov_len = msgb_length(msg);
+		iofd_txqueue_enqueue_front(iofd, msghdr);
+		return;
+	}
+
+	/* Reenqueue the complete msgb */
+	if (rc == -EAGAIN) {
+		iofd_txqueue_enqueue_front(iofd, msghdr);
+		return;
+	}
+
+	/* All other failure and success cases are handled here */
+	switch (msghdr->action) {
+	case IOFD_ACT_WRITE:
+		iofd->io_ops.write_cb(iofd, rc, msg);
+		break;
+	case IOFD_ACT_SENDTO:
+		iofd->io_ops.sendto_cb(iofd, rc, msg, &msghdr->osa);
+		break;
+	default:
+		OSMO_ASSERT(0);
+	}
+
+	msgb_free(msghdr->msg);
+	iofd_msghdr_free(msghdr);
+}
+
 /* Public functions */
 
 /*! Send a message through a connected socket.