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

📄 af_unix.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
	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_wlock(sk);	if (sk->sk_state != st) {		unix_state_wunlock(sk);		unix_state_runlock(other);		sock_put(other);		goto restart;	}	err = security_unix_stream_connect(sock, other->sk_socket, newsk);	if (err) {		unix_state_wunlock(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	= current->tgid;	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_hold(newsk);	unix_peer(sk)	= newsk;	sock->state	= SS_CONNECTED;	sk->sk_state	= TCP_ESTABLISHED;	unix_state_wunlock(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);	/* Undo artificially decreased inflight after embrion	 * is installed to listening socket. */	atomic_inc(&newu->inflight);	spin_unlock(&other->sk_receive_queue.lock);	unix_state_runlock(other);	other->sk_data_ready(other, 0);	sock_put(other);	return 0;out_unlock:	if (other)		unix_state_runlock(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 = current->tgid;	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_wlock(tsk);	newsock->state = SS_CONNECTED;	sock_graft(tsk, newsock);	unix_state_wunlock(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_rlock(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_runlock(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 (sock->passcred && !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);	skb->h.raw = skb->data;	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_rlock(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_runlock(other);		sock_put(other);		err = 0;		unix_state_wlock(sk);		if (unix_peer(sk) == other) {			unix_peer(sk)=NULL;			unix_state_wunlock(sk);			unix_dgram_disconnected(sk, other);			sock_put(other);			err = -ECONNREFUSED;		} else {			unix_state_wunlock(sk);		}		other = NULL;		if (err)			goto out_free;		goto restart;	}	err = -EPIPE;	if (other->sk_shutdown & RCV_SHUTDOWN)		goto out_unlock;	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_runlock(other);	other->sk_data_ready(other, len);	sock_put(other);	scm_destroy(siocb->scm);	return len;out_unlock:	unix_state_runlock(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_get(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 / 2 - 64)			size = sk->sk_sndbuf / 2 - 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_rlock(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_runlock(other);		other->sk_data_ready(other, size);		sent+=size;	}	sock_put(other);	scm_destroy(siocb->scm);	siocb->scm = NULL;	return sent;pipe_err_free:	unix_state_runlock(other);	kfree_skb(skb);pipe_err:	if (sent==0 && !(msg->msg_flags&MSG_NOSIGNAL))		send_sig(SIGPIPE,current,0);	err = -EPIPE;out_err:        if (other)		sock_put(other);	scm_destroy(siocb->scm);	siocb->scm = NULL;	return sent ? : err;}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;		memcpy(msg->msg_name, u->addr->name, u->addr->len);	}}static int unix_dgram_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);	int noblock = flags & MSG_DONTWAIT;	struct sk_buff *skb;	int err;	err = -EOPNOTSUPP;	if (flags&MSG_OOB)		goto out;	msg->msg_namelen = 0;

⌨️ 快捷键说明

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