⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 af_unix.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		err = -EAGAIN;		if (!timeo)			goto out_unlock;		timeo = unix_wait_for_peer(other, timeo);		err = sock_intr_errno(timeo);		if (signal_pending(current))			goto out;		sock_put(other);		goto restart;	}	/* Latch our state.	   It is tricky place. We need to grab write lock and cannot	   drop lock on peer. It is dangerous because deadlock is	   possible. Connect to self case and simultaneous	   attempt to connect are eliminated by checking socket	   state. other is TCP_LISTEN, if sk is TCP_LISTEN we	   check this before attempt to grab lock.	   Well, and we have to recheck the state after socket locked.	 */	st = sk->sk_state;	switch (st) {	case TCP_CLOSE:		/* This is ok... continue with connect */		break;	case TCP_ESTABLISHED:		/* Socket is already connected */		err = -EISCONN;		goto out_unlock;	default:		err = -EINVAL;		goto out_unlock;	}	unix_state_lock_nested(sk);	if (sk->sk_state != st) {		unix_state_unlock(sk);		unix_state_unlock(other);		sock_put(other);		goto restart;	}	err = security_unix_stream_connect(sock, other->sk_socket, newsk);	if (err) {		unix_state_unlock(sk);		goto out_unlock;	}	/* The way is open! Fastly set all the necessary fields... */	sock_hold(sk);	unix_peer(newsk)	= sk;	newsk->sk_state		= TCP_ESTABLISHED;	newsk->sk_type		= sk->sk_type;	newsk->sk_peercred.pid	= task_tgid_vnr(current);	newsk->sk_peercred.uid	= current->euid;	newsk->sk_peercred.gid	= current->egid;	newu = unix_sk(newsk);	newsk->sk_sleep		= &newu->peer_wait;	otheru = unix_sk(other);	/* copy address information from listening to new sock*/	if (otheru->addr) {		atomic_inc(&otheru->addr->refcnt);		newu->addr = otheru->addr;	}	if (otheru->dentry) {		newu->dentry	= dget(otheru->dentry);		newu->mnt	= mntget(otheru->mnt);	}	/* Set credentials */	sk->sk_peercred = other->sk_peercred;	sock->state	= SS_CONNECTED;	sk->sk_state	= TCP_ESTABLISHED;	sock_hold(newsk);	smp_mb__after_atomic_inc();	/* sock_hold() does an atomic_inc() */	unix_peer(sk)	= newsk;	unix_state_unlock(sk);	/* take ten and and send info to listening sock */	spin_lock(&other->sk_receive_queue.lock);	__skb_queue_tail(&other->sk_receive_queue, skb);	spin_unlock(&other->sk_receive_queue.lock);	unix_state_unlock(other);	other->sk_data_ready(other, 0);	sock_put(other);	return 0;out_unlock:	if (other)		unix_state_unlock(other);out:	if (skb)		kfree_skb(skb);	if (newsk)		unix_release_sock(newsk, 0);	if (other)		sock_put(other);	return err;}static int unix_socketpair(struct socket *socka, struct socket *sockb){	struct sock *ska=socka->sk, *skb = sockb->sk;	/* Join our sockets back to back */	sock_hold(ska);	sock_hold(skb);	unix_peer(ska)=skb;	unix_peer(skb)=ska;	ska->sk_peercred.pid = skb->sk_peercred.pid = task_tgid_vnr(current);	ska->sk_peercred.uid = skb->sk_peercred.uid = current->euid;	ska->sk_peercred.gid = skb->sk_peercred.gid = current->egid;	if (ska->sk_type != SOCK_DGRAM) {		ska->sk_state = TCP_ESTABLISHED;		skb->sk_state = TCP_ESTABLISHED;		socka->state  = SS_CONNECTED;		sockb->state  = SS_CONNECTED;	}	return 0;}static int unix_accept(struct socket *sock, struct socket *newsock, int flags){	struct sock *sk = sock->sk;	struct sock *tsk;	struct sk_buff *skb;	int err;	err = -EOPNOTSUPP;	if (sock->type!=SOCK_STREAM && sock->type!=SOCK_SEQPACKET)		goto out;	err = -EINVAL;	if (sk->sk_state != TCP_LISTEN)		goto out;	/* If socket state is TCP_LISTEN it cannot change (for now...),	 * so that no locks are necessary.	 */	skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err);	if (!skb) {		/* This means receive shutdown. */		if (err == 0)			err = -EINVAL;		goto out;	}	tsk = skb->sk;	skb_free_datagram(sk, skb);	wake_up_interruptible(&unix_sk(sk)->peer_wait);	/* attach accepted sock to socket */	unix_state_lock(tsk);	newsock->state = SS_CONNECTED;	sock_graft(tsk, newsock);	unix_state_unlock(tsk);	return 0;out:	return err;}static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer){	struct sock *sk = sock->sk;	struct unix_sock *u;	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;	int err = 0;	if (peer) {		sk = unix_peer_get(sk);		err = -ENOTCONN;		if (!sk)			goto out;		err = 0;	} else {		sock_hold(sk);	}	u = unix_sk(sk);	unix_state_lock(sk);	if (!u->addr) {		sunaddr->sun_family = AF_UNIX;		sunaddr->sun_path[0] = 0;		*uaddr_len = sizeof(short);	} else {		struct unix_address *addr = u->addr;		*uaddr_len = addr->len;		memcpy(sunaddr, addr->name, *uaddr_len);	}	unix_state_unlock(sk);	sock_put(sk);out:	return err;}static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb){	int i;	scm->fp = UNIXCB(skb).fp;	skb->destructor = sock_wfree;	UNIXCB(skb).fp = NULL;	for (i=scm->fp->count-1; i>=0; i--)		unix_notinflight(scm->fp->fp[i]);}static void unix_destruct_fds(struct sk_buff *skb){	struct scm_cookie scm;	memset(&scm, 0, sizeof(scm));	unix_detach_fds(&scm, skb);	/* Alas, it calls VFS */	/* So fscking what? fput() had been SMP-safe since the last Summer */	scm_destroy(&scm);	sock_wfree(skb);}static void unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb){	int i;	for (i=scm->fp->count-1; i>=0; i--)		unix_inflight(scm->fp->fp[i]);	UNIXCB(skb).fp = scm->fp;	skb->destructor = unix_destruct_fds;	scm->fp = NULL;}/* *	Send AF_UNIX data. */static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,			      struct msghdr *msg, size_t len){	struct sock_iocb *siocb = kiocb_to_siocb(kiocb);	struct sock *sk = sock->sk;	struct unix_sock *u = unix_sk(sk);	struct sockaddr_un *sunaddr=msg->msg_name;	struct sock *other = NULL;	int namelen = 0; /* fake GCC */	int err;	unsigned hash;	struct sk_buff *skb;	long timeo;	struct scm_cookie tmp_scm;	if (NULL == siocb->scm)		siocb->scm = &tmp_scm;	err = scm_send(sock, msg, siocb->scm);	if (err < 0)		return err;	err = -EOPNOTSUPP;	if (msg->msg_flags&MSG_OOB)		goto out;	if (msg->msg_namelen) {		err = unix_mkname(sunaddr, msg->msg_namelen, &hash);		if (err < 0)			goto out;		namelen = err;	} else {		sunaddr = NULL;		err = -ENOTCONN;		other = unix_peer_get(sk);		if (!other)			goto out;	}	if (test_bit(SOCK_PASSCRED, &sock->flags)		&& !u->addr && (err = unix_autobind(sock)) != 0)		goto out;	err = -EMSGSIZE;	if (len > sk->sk_sndbuf - 32)		goto out;	skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err);	if (skb==NULL)		goto out;	memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));	if (siocb->scm->fp)		unix_attach_fds(siocb->scm, skb);	unix_get_secdata(siocb->scm, skb);	skb_reset_transport_header(skb);	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);	if (err)		goto out_free;	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);restart:	if (!other) {		err = -ECONNRESET;		if (sunaddr == NULL)			goto out_free;		other = unix_find_other(sunaddr, namelen, sk->sk_type,					hash, &err);		if (other==NULL)			goto out_free;	}	unix_state_lock(other);	err = -EPERM;	if (!unix_may_send(sk, other))		goto out_unlock;	if (sock_flag(other, SOCK_DEAD)) {		/*		 *	Check with 1003.1g - what should		 *	datagram error		 */		unix_state_unlock(other);		sock_put(other);		err = 0;		unix_state_lock(sk);		if (unix_peer(sk) == other) {			unix_peer(sk)=NULL;			unix_state_unlock(sk);			unix_dgram_disconnected(sk, other);			sock_put(other);			err = -ECONNREFUSED;		} else {			unix_state_unlock(sk);		}		other = NULL;		if (err)			goto out_free;		goto restart;	}	err = -EPIPE;	if (other->sk_shutdown & RCV_SHUTDOWN)		goto out_unlock;	if (sk->sk_type != SOCK_SEQPACKET) {		err = security_unix_may_send(sk->sk_socket, other->sk_socket);		if (err)			goto out_unlock;	}	if (unix_peer(other) != sk &&	    (skb_queue_len(&other->sk_receive_queue) >	     other->sk_max_ack_backlog)) {		if (!timeo) {			err = -EAGAIN;			goto out_unlock;		}		timeo = unix_wait_for_peer(other, timeo);		err = sock_intr_errno(timeo);		if (signal_pending(current))			goto out_free;		goto restart;	}	skb_queue_tail(&other->sk_receive_queue, skb);	unix_state_unlock(other);	other->sk_data_ready(other, len);	sock_put(other);	scm_destroy(siocb->scm);	return len;out_unlock:	unix_state_unlock(other);out_free:	kfree_skb(skb);out:	if (other)		sock_put(other);	scm_destroy(siocb->scm);	return err;}static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,			       struct msghdr *msg, size_t len){	struct sock_iocb *siocb = kiocb_to_siocb(kiocb);	struct sock *sk = sock->sk;	struct sock *other = NULL;	struct sockaddr_un *sunaddr=msg->msg_name;	int err,size;	struct sk_buff *skb;	int sent=0;	struct scm_cookie tmp_scm;	if (NULL == siocb->scm)		siocb->scm = &tmp_scm;	err = scm_send(sock, msg, siocb->scm);	if (err < 0)		return err;	err = -EOPNOTSUPP;	if (msg->msg_flags&MSG_OOB)		goto out_err;	if (msg->msg_namelen) {		err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP;		goto out_err;	} else {		sunaddr = NULL;		err = -ENOTCONN;		other = unix_peer(sk);		if (!other)			goto out_err;	}	if (sk->sk_shutdown & SEND_SHUTDOWN)		goto pipe_err;	while(sent < len)	{		/*		 *	Optimisation for the fact that under 0.01% of X		 *	messages typically need breaking up.		 */		size = len-sent;		/* Keep two messages in the pipe so it schedules better */		if (size > ((sk->sk_sndbuf >> 1) - 64))			size = (sk->sk_sndbuf >> 1) - 64;		if (size > SKB_MAX_ALLOC)			size = SKB_MAX_ALLOC;		/*		 *	Grab a buffer		 */		skb=sock_alloc_send_skb(sk,size,msg->msg_flags&MSG_DONTWAIT, &err);		if (skb==NULL)			goto out_err;		/*		 *	If you pass two values to the sock_alloc_send_skb		 *	it tries to grab the large buffer with GFP_NOFS		 *	(which can fail easily), and if it fails grab the		 *	fallback size buffer which is under a page and will		 *	succeed. [Alan]		 */		size = min_t(int, size, skb_tailroom(skb));		memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));		if (siocb->scm->fp)			unix_attach_fds(siocb->scm, skb);		if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) {			kfree_skb(skb);			goto out_err;		}		unix_state_lock(other);		if (sock_flag(other, SOCK_DEAD) ||		    (other->sk_shutdown & RCV_SHUTDOWN))			goto pipe_err_free;		skb_queue_tail(&other->sk_receive_queue, skb);		unix_state_unlock(other);		other->sk_data_ready(other, size);		sent+=size;	}	scm_destroy(siocb->scm);	siocb->scm = NULL;	return sent;pipe_err_free:	unix_state_unlock(other);	kfree_skb(skb);pipe_err:	if (sent==0 && !(msg->msg_flags&MSG_NOSIGNAL))		send_sig(SIGPIPE,current,0);	err = -EPIPE;out_err:	scm_destroy(siocb->scm);	siocb->scm = NULL;	return sent ? : err;}static int unix_seqpacket_sendmsg(struct kiocb *kiocb, struct socket *sock,				  struct msghdr *msg, size_t len){	int err;	struct sock *sk = sock->sk;	err = sock_error(sk);	if (err)		return err;	if (sk->sk_state != TCP_ESTABLISHED)		return -ENOTCONN;	if (msg->msg_namelen)		msg->msg_namelen = 0;	return unix_dgram_sendmsg(kiocb, sock, msg, len);}static void unix_copy_addr(struct msghdr *msg, struct sock *sk){	struct unix_sock *u = unix_sk(sk);	msg->msg_namelen = 0;	if (u->addr) {		msg->msg_namelen = u->addr->len;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -