osmo_io: Improve handling and documentation of segmentation_cb
The read length is not needed in the segmentation callback, msgb
already has all the necessary information, the parameter previously was
just msgb_length(msg).
Also handle negative return values (except -EAGAIN) of the callback as
errors which cause the msg to be dropped. -EAGAIN will defer the msg.
Change-Id: I6a0eebb8d4490f09a3cc6eb97d4ff47b4a8fd377
diff --git a/src/core/osmo_io.c b/src/core/osmo_io.c
index b06e63c..857644d 100644
--- a/src/core/osmo_io.c
+++ b/src/core/osmo_io.c
@@ -219,7 +219,7 @@
*/
static enum iofd_seg_act iofd_handle_segmentation(struct osmo_io_fd *iofd, struct msgb *msg, struct msgb **pending_out)
{
- int pending_len, msg_len;
+ int extra_len, msg_len;
struct msgb *msg_pending;
msg_len = msgb_length(msg);
@@ -229,27 +229,41 @@
return IOFD_SEG_ACT_HANDLE_ONE;
}
- int len = iofd->io_ops.segmentation_cb(msg, msg_len);
-
- pending_len = msg_len - len;
- /* No segmentation needed, return */
- if (pending_len == 0) {
+ int len = iofd->io_ops.segmentation_cb(msg);
+ if (len == -EAGAIN) {
+ goto defer;
+ } else if (len < 0) {
+ /* Something is wrong, skip this msgb */
+ LOGPIO(iofd, LOGL_ERROR, "segmentation_cb returned error (%d), skipping msg of size %d\n", len, msg_len);
*pending_out = NULL;
- return IOFD_SEG_ACT_HANDLE_ONE;
- } else if (pending_len < 0) {
- *pending_out = msg;
+ msgb_free(msg);
return IOFD_SEG_ACT_DEFER;
}
- /* Copy the pending data over */
+ extra_len = msg_len - len;
+ /* No segmentation needed, return the whole msgb */
+ if (extra_len == 0) {
+ *pending_out = NULL;
+ return IOFD_SEG_ACT_HANDLE_ONE;
+ /* segment is incomplete */
+ } else if (extra_len < 0) {
+ goto defer;
+ }
+
+ /* msgb contains more than one segment */
+ /* Copy the trailing data over */
msg_pending = iofd_msgb_alloc(iofd);
- memcpy(msgb_data(msg_pending), msgb_data(msg) + len, pending_len);
- msgb_put(msg_pending, pending_len);
+ memcpy(msgb_data(msg_pending), msgb_data(msg) + len, extra_len);
+ msgb_put(msg_pending, extra_len);
*pending_out = msg_pending;
/* Trim the original msgb to size */
msgb_trim(msg, len);
return IOFD_SEG_ACT_HANDLE_MORE;
+
+defer:
+ *pending_out = msg;
+ return IOFD_SEG_ACT_DEFER;
}
/*! Restore message boundaries on read() and pass individual messages to the read callback