unix: Support peeking offset for datagram and seqpacket sockets
[deliverable/linux.git] / net / unix / af_unix.c
index 85d3bb7490aabcb26fd10b08adfcddebb5cbeb59..3d9481de031f0de59e9925128d5c0ac81411729c 100644 (file)
@@ -530,6 +530,16 @@ static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,
 static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *,
                                  struct msghdr *, size_t, int);
 
+static void unix_set_peek_off(struct sock *sk, int val)
+{
+       struct unix_sock *u = unix_sk(sk);
+
+       mutex_lock(&u->readlock);
+       sk->sk_peek_off = val;
+       mutex_unlock(&u->readlock);
+}
+
+
 static const struct proto_ops unix_stream_ops = {
        .family =       PF_UNIX,
        .owner =        THIS_MODULE,
@@ -570,6 +580,7 @@ static const struct proto_ops unix_dgram_ops = {
        .recvmsg =      unix_dgram_recvmsg,
        .mmap =         sock_no_mmap,
        .sendpage =     sock_no_sendpage,
+       .set_peek_off = unix_set_peek_off,
 };
 
 static const struct proto_ops unix_seqpacket_ops = {
@@ -591,6 +602,7 @@ static const struct proto_ops unix_seqpacket_ops = {
        .recvmsg =      unix_seqpacket_recvmsg,
        .mmap =         sock_no_mmap,
        .sendpage =     sock_no_sendpage,
+       .set_peek_off = unix_set_peek_off,
 };
 
 static struct proto unix_proto = {
@@ -1756,6 +1768,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
        int noblock = flags & MSG_DONTWAIT;
        struct sk_buff *skb;
        int err;
+       int peeked, skip;
 
        err = -EOPNOTSUPP;
        if (flags&MSG_OOB)
@@ -1769,7 +1782,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
                goto out;
        }
 
-       skb = skb_recv_datagram(sk, flags, noblock, &err);
+       skip = sk_peek_offset(sk, flags);
+
+       skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err);
        if (!skb) {
                unix_state_lock(sk);
                /* Signal EOF on disconnected non-blocking SEQPACKET socket. */
@@ -1786,12 +1801,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (msg->msg_name)
                unix_copy_addr(msg, skb->sk);
 
-       if (size > skb->len)
-               size = skb->len;
-       else if (size < skb->len)
+       if (size > skb->len - skip)
+               size = skb->len - skip;
+       else if (size < skb->len - skip)
                msg->msg_flags |= MSG_TRUNC;
 
-       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size);
+       err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size);
        if (err)
                goto out_free;
 
@@ -1808,6 +1823,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (!(flags & MSG_PEEK)) {
                if (UNIXCB(skb).fp)
                        unix_detach_fds(siocb->scm, skb);
+
+               sk_peek_offset_bwd(sk, skb->len);
        } else {
                /* It is questionable: on PEEK we could:
                   - do not return fds - good, but too simple 8)
@@ -1821,6 +1838,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
                   clearly however!
 
                */
+
+               sk_peek_offset_fwd(sk, size);
+
                if (UNIXCB(skb).fp)
                        siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp);
        }
This page took 0.02781 seconds and 5 git commands to generate.