博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
-
static int unix_stream_recvmsg(struct kiocb *iocb, struct
socket *sock,
-
struct msghdr *msg, size_t size,
-
int flags)
-
{
-
struct sock_iocb *siocb = kiocb_to_siocb(iocb);
-
struct scm_cookie tmp_scm;
-
struct sock *sk = sock->sk;
-
struct unix_sock *u = unix_sk(sk);
-
struct sockaddr_un *sunaddr = msg->msg_name;
-
int copied = 0;
-
int check_creds = 0;
-
int target;
-
int err = 0;
-
long timeo;
-
-
err = -EINVAL;
-
if (sk->sk_state != TCP_ESTABLISHED)
-
goto out;
-
-
err = -EOPNOTSUPP;
-
if (flags&MSG_OOB)
-
goto out;
-
-
target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
-
timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
-
-
msg->msg_namelen = 0;
-
-
/* Lock the socket to prevent queue disordering
-
* while sleeps in memcpy_tomsg
-
*/
-
-
if (!siocb->scm) {
-
siocb->scm = &tmp_scm;
-
memset(&tmp_scm, 0, sizeof(tmp_scm));
-
}
-
-
mutex_lock(&u->readlock);
-
-
do {
-
int chunk;
-
struct sk_buff *skb;
-
-
unix_state_lock(sk);
-
skb = skb_dequeue(&sk->sk_receive_queue);
-
if (skb == NULL) {
-
if (copied >= target)
-
goto unlock;
-
-
/*
-
* POSIX 1003.1g mandates this order.
-
*/
-
-
err = sock_error(sk);
-
if (err)
-
goto unlock;
-
if (sk->sk_shutdown & RCV_SHUTDOWN)
-
goto unlock;
-
-
unix_state_unlock(sk);
-
err = -EAGAIN;
-
if (!timeo)
-
break;
-
mutex_unlock(&u->readlock);
-
-
timeo = unix_stream_data_wait(sk, timeo);
-
-
if (signal_pending(current)) {
-
err = sock_intr_errno(timeo);
-
goto out;
-
}
-
mutex_lock(&u->readlock);
-
continue;
-
unlock:
-
unix_state_unlock(sk);
-
break;
-
}
-
unix_state_unlock(sk);
-
-
if (check_creds) {
-
/* Never glue messages from different writers */
-
if ((UNIXCB(skb).pid != siocb->scm->pid) ||
-
(UNIXCB(skb).cred != siocb->scm->cred)) {
-
skb_queue_head(&sk->sk_receive_queue, skb);
-
break;
-
}
-
} else {
-
/* Copy credentials */
-
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
-
check_creds = 1;
-
}
-
-
/* Copy address just once */
-
if (sunaddr) {
-
unix_copy_addr(msg, skb->sk);
-
sunaddr = NULL;
-
}
-
-
chunk = min_t(unsigned int, skb->len, size);
-
if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
-
skb_queue_head(&sk->sk_receive_queue, skb);
-
if (copied == 0)
-
copied = -EFAULT;
-
break;
-
}
-
copied += chunk;
-
size -= chunk;
-
-
/* Mark read part of skb as used */
-
if (!(flags & MSG_PEEK)) {
-
skb_pull(skb, chunk);
-
-
if (UNIXCB(skb).fp)
-
unix_detach_fds(siocb->scm, skb);
-
-
/* put the skb back if we didn't
use it up.. */
-
if (skb->len) {
-
skb_queue_head(&sk->sk_receive_queue, skb);
-
break;
-
}
-
-
consume_skb(skb);
-
-
if (siocb->scm->fp)
-
break;
-
} else {
-
/* It is questionable, see
note in unix_dgram_recvmsg.
-
*/
-
if (UNIXCB(skb).fp)
-
siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp);
-
-
/* put message back and return */
-
skb_queue_head(&sk->sk_receive_queue, skb);
-
break;
-
}
-
} while (size);
-
-
mutex_unlock(&u->readlock);
-
scm_recv(sock, msg, siocb->scm, flags);
-
out:
-
return copied ? : err;
- }
- return copied ? : err;
-
err = sock_error(sk);
-
if (err)
-
goto unlock;
-
if (sk->sk_shutdown & RCV_SHUTDOWN)
- goto unlock;
-
timeo = unix_stream_data_wait(sk, timeo);
-
-
if (signal_pending(current)) {
-
err = sock_intr_errno(timeo);
-
goto out;
- }