diff --git a/Documentation/FLAGS.md b/Documentation/FLAGS.md new file mode 100644 index 0000000..2086aa1 --- /dev/null +++ b/Documentation/FLAGS.md @@ -0,0 +1,104 @@ +# BP Socket Flags Documentation + +This document describes the flags available for use with BP (Bundle Protocol) sockets in both `sendmsg()` and `recvmsg()` operations. + +## Receive Message Flags + +Applications can use the following flags with `recvmsg()`: + +| Flag | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `MSG_PEEK` | Peeks at the incoming datagram without removing it from the queue. Useful for inspecting message size or content before full reception. | +| `MSG_TRUNC` | Returns the full size of the message, even if the provided buffer is too small. The datagram is consumed from the queue, and only the portion that fits is copied to the buffer. The MSG_TRUNC flag is set in msg_flags. | + +### Combined Usage + +The most efficient way to determine message size without consuming it: + +```c +ssize_t need = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC); +``` + +This combination allows you to: + +1. Get the exact message size +2. Keep the message in the queue for later consumption +3. Allocate the proper buffer size dynamically + +## Send Message Flags + +The following flags can be used with `sendmsg()` to tune message delivery, reporting, priority, and custody: + +### Acknowledgment + +| Flag | Description | +| ------------------- | ------------------------------------------ | +| `MSG_ACK_REQUESTED` | Requests an acknowledgment for the message | + +### Status Reports (combinable) + +These flags can be combined using the bitwise OR operator (`|`): + +| Flag | Description | +| ------------------- | ---------------------------------------------------- | +| `MSG_RECEIVED_RPT` | Request a report when the message is received | +| `MSG_CUSTODY_RPT` | Request a report when custody of the message changes | +| `MSG_FORWARDED_RPT` | Request a report when the message is forwarded | +| `MSG_DELIVERED_RPT` | Request a report when the message is delivered | +| `MSG_DELETED_RPT` | Request a report when the message is deleted | + +### Priority (mutually exclusive) + +Only one of these priority flags can be used at a time: + +| Flag | Description | +| --------------------------- | -------------------------------------------- | +| `MSG_BP_BULK_PRIORITY` | Assigns a bulk priority to the message | +| `MSG_BP_STD_PRIORITY` | Assigns a standard priority to the message | +| `MSG_BP_EXPEDITED_PRIORITY` | Assigns an expedited priority to the message | + +### Custody (mutually exclusive) + +Only one of these custody flags can be used at a time: + +| Flag | Description | +| ----------------------------- | ---------------------------------------------------- | +| `MSG_SOURCE_CUSTODY_REQUIRED` | Requires the source to retain custody of the message | +| `MSG_SOURCE_CUSTODY_OPTIONAL` | Source custody is optional | +| `MSG_NO_CUSTODY_REQUIRED` | No custody is required | + +## Usage Examples + +### Receiving Messages with Dynamic Buffer Allocation + +```c +// Step 1: Get message size without consuming +ssize_t message_size = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC); + +// Step 2: Allocate proper buffer and receive +char *buffer = malloc(message_size + 1); +struct iovec iov = { .iov_base = buffer, .iov_len = message_size }; +msg.msg_iov = &iov; +msg.msg_iovlen = 1; + +ssize_t received = recvmsg(fd, &msg, 0); +buffer[received] = '\0'; +``` + +### Sending Messages with Flags + +```c +// Send with acknowledgment request and no custody requirement +ssize_t sent = sendmsg(fd, &msg, MSG_ACK_REQUESTED | MSG_NO_CUSTODY_REQUIRED); + +// Send with status reports and expedited priority +ssize_t sent = sendmsg(fd, &msg, + MSG_RECEIVED_RPT | MSG_DELIVERED_RPT | MSG_BP_EXPEDITED_PRIORITY); +``` + +## Implementation Notes + +- All BP-specific flags are defined in `include/bp_socket.h` +- Standard socket flags (MSG_PEEK, MSG_TRUNC) are available through system headers +- Flag values are designed to avoid conflicts with standard socket flags +- The kernel implementation properly handles all flag combinations diff --git a/Documentation/OPTIONS.md b/Documentation/OPTIONS.md new file mode 100644 index 0000000..05e262a --- /dev/null +++ b/Documentation/OPTIONS.md @@ -0,0 +1,57 @@ +# BP Socket Options Documentation + +This document describes the socket options available for BP (Bundle Protocol) sockets using `setsockopt()` and `getsockopt()`. + +## Overview + +BP sockets support standard socket options at the `SOL_SOCKET` level, with specific implementations for timeout handling. All other socket levels are passed through to the common socket implementation. + +## Supported Socket Options + +### Receive Timeout Options + +BP sockets support the standard POSIX receive timeout option: + +| Option Name | Type | Description | +| ------------- | ---------------- | ------------------------------ | +| `SO_RCVTIMEO` | `struct timeval` | Standard POSIX receive timeout | + +### Timeout Behavior + +- **Default**: No timeout (`MAX_SCHEDULE_TIMEOUT`) +- **Zero timeout**: Immediate timeout (non-blocking behavior) +- **Non-zero timeout**: Block for specified duration before timing out +- **Timeout units**: seconds and microseconds (standard POSIX) + +## Usage Examples + +### Setting Receive Timeout + +```c +#include +#include + +struct timeval timeout; +timeout.tv_sec = 5; // 5 seconds +timeout.tv_usec = 0; // 0 microseconds + +if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { + perror("setsockopt failed"); + return -1; +} +``` + +### Getting Current Timeout + +```c +struct timeval timeout; +socklen_t len = sizeof(timeout); + +if (getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, &len) < 0) { + perror("getsockopt failed"); + return -1; +} + +printf("Current timeout: %ld.%06ld seconds\n", + timeout.tv_sec, timeout.tv_usec); +``` diff --git a/bp_socket/af_bp.c b/bp_socket/af_bp.c index 67939ef..6fdc850 100644 --- a/bp_socket/af_bp.c +++ b/bp_socket/af_bp.c @@ -325,6 +325,7 @@ int bp_recvmsg(struct socket* sock, struct msghdr* msg, size_t size, int flags) struct sk_buff* skb = NULL; struct sockaddr_bp* src_addr; long timeo; + size_t copy_len; int ret; sk = sock->sk; @@ -358,7 +359,11 @@ int bp_recvmsg(struct socket* sock, struct msghdr* msg, size_t size, int flags) } mutex_lock(&bp->rx_mutex); - skb = skb_dequeue(&bp->rx_queue); + if (flags & MSG_PEEK) { + skb = skb_peek(&bp->rx_queue); + } else { + skb = skb_dequeue(&bp->rx_queue); + } if (!skb) { pr_info("bp_recvmsg: no messages in the queue for ipn:%u.%u\n", bp->bp_node_id, bp->bp_service_id); @@ -369,11 +374,16 @@ int bp_recvmsg(struct socket* sock, struct msghdr* msg, size_t size, int flags) mutex_unlock(&bp->rx_mutex); if (skb->len > size) { - pr_err("bp_recvmsg: buffer too small for message (required=%u, " - "provided=%zu)\n", - skb->len, size); - ret = -EMSGSIZE; - goto out; + if (flags & MSG_TRUNC) { + msg->msg_flags |= MSG_TRUNC; + } else { + pr_err("bp_recvmsg: buffer too small for message " + "(required=%u, " + "provided=%zu)\n", + skb->len, size); + ret = -EMSGSIZE; + goto out; + } } if (msg->msg_name) { @@ -386,22 +396,25 @@ int bp_recvmsg(struct socket* sock, struct msghdr* msg, size_t size, int flags) msg->msg_namelen = sizeof(struct sockaddr_bp); } - if (copy_to_iter(skb->data, skb->len, &msg->msg_iter) != skb->len) { + copy_len = (skb->len > size) ? size : skb->len; + if (copy_to_iter(skb->data, copy_len, &msg->msg_iter) != copy_len) { pr_err("bp_recvmsg: failed to copy data to user space\n"); ret = -EFAULT; goto out; } - ret = destroy_bundle_doit(BP_SKB_CB(skb)->adu, 8443); - if (ret < 0) { - pr_warn( - "bp_recvmsg: failed to destroy bundle, bundle may leak\n"); + if (!(flags & MSG_PEEK)) { + ret = destroy_bundle_doit(BP_SKB_CB(skb)->adu, 8443); + if (ret < 0) { + pr_warn("bp_recvmsg: failed to destroy bundle, bundle " + "may leak\n"); + } } ret = skb->len; out: - if (skb) + if (skb && !(flags & MSG_PEEK)) kfree_skb(skb); release_sock(sk); return ret;