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

📄 af_unix.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	unix_state_runlock(other);	other->data_ready(other, len);	sock_put(other);	return len;out_unlock:	unix_state_runlock(other);out_free:	kfree_skb(skb);out:	if (other)		sock_put(other);	return err;}		static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int len,			       struct scm_cookie *scm){	struct sock *sk = sock->sk;	unix_socket *other = NULL;	struct sockaddr_un *sunaddr=msg->msg_name;	int err,size;	struct sk_buff *skb;	int limit=0;	int sent=0;	err = -EOPNOTSUPP;	if (msg->msg_flags&MSG_OOB)		goto out_err;	if (msg->msg_namelen) {		err = (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->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->sndbuf/2 - 16)			size = sk->sndbuf/2 - 16;		/*		 *	Keep to page sized kmalloc()'s as various people		 *	have suggested. Big mallocs stress the vm too		 *	much.		 */		if (size > PAGE_SIZE-16)			limit = PAGE_SIZE-16; /* Fall back to a page if we can't grab a big buffer this instant */		else			limit = 0;	/* Otherwise just grab and wait */		/*		 *	Grab a buffer		 */		 		skb=sock_alloc_send_skb(sk,size,limit,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_BUFFER		 *	(which can fail easily), and if it fails grab the		 *	fallback size buffer which is under a page and will		 *	succeed. [Alan]		 */		size = min(size, skb_tailroom(skb));		memcpy(UNIXCREDS(skb), &scm->creds, sizeof(struct ucred));		if (scm->fp)			unix_attach_fds(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 (other->dead || (other->shutdown & RCV_SHUTDOWN))			goto pipe_err_free;		skb_queue_tail(&other->receive_queue, skb);		unix_state_runlock(other);		other->data_ready(other, size);		sent+=size;	}	sock_put(other);	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);	return sent ? : err;}static void unix_copy_addr(struct msghdr *msg, struct sock *sk){	msg->msg_namelen = sizeof(short);	if (sk->protinfo.af_unix.addr) {		msg->msg_namelen=sk->protinfo.af_unix.addr->len;		memcpy(msg->msg_name,		       sk->protinfo.af_unix.addr->name,		       sk->protinfo.af_unix.addr->len);	}}static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int size,			      int flags, struct scm_cookie *scm){	struct sock *sk = sock->sk;	int noblock = flags & MSG_DONTWAIT;	struct sk_buff *skb;	int err;	err = -EOPNOTSUPP;	if (flags&MSG_OOB)		goto out;	msg->msg_namelen = 0;	skb = skb_recv_datagram(sk, flags, noblock, &err);	if (!skb)		goto out;	wake_up_interruptible(&sk->protinfo.af_unix.peer_wait);	if (msg->msg_name)		unix_copy_addr(msg, skb->sk);	if (size > skb->len)		size = skb->len;	else if (size < skb->len)		msg->msg_flags |= MSG_TRUNC;	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size);	if (err)		goto out_free;	scm->creds = *UNIXCREDS(skb);	if (!(flags & MSG_PEEK))	{		if (UNIXCB(skb).fp)			unix_detach_fds(scm, skb);	}	else 	{		/* It is questionable: on PEEK we could:		   - do not return fds - good, but too simple 8)		   - return fds, and do not return them on read (old strategy,		     apparently wrong)		   - clone fds (I choosed it for now, it is the most universal		     solution)			           POSIX 1003.1g does not actually define this clearly	           at all. POSIX 1003.1g doesn't define a lot of things	           clearly however!		     		   		*/		if (UNIXCB(skb).fp)			scm->fp = scm_fp_dup(UNIXCB(skb).fp);	}	err = size;out_free:	skb_free_datagram(sk,skb);out:	return err;}/* *	Sleep until data has arrive. But check for races.. */ static long unix_stream_data_wait(unix_socket * sk, long timeo){	DECLARE_WAITQUEUE(wait, current);	unix_state_rlock(sk);	add_wait_queue(sk->sleep, &wait);	for (;;) {		set_current_state(TASK_INTERRUPTIBLE);		if (skb_queue_len(&sk->receive_queue) ||		    sk->err ||		    (sk->shutdown & RCV_SHUTDOWN) ||		    signal_pending(current) ||		    !timeo)			break;		set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);		unix_state_runlock(sk);		timeo = schedule_timeout(timeo);		unix_state_rlock(sk);		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);	}	__set_current_state(TASK_RUNNING);	remove_wait_queue(sk->sleep, &wait);	unix_state_runlock(sk);	return timeo;}static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size,			       int flags, struct scm_cookie *scm){	struct sock *sk = sock->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->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	 */	down(&sk->protinfo.af_unix.readsem);	do	{		int chunk;		struct sk_buff *skb;		skb=skb_dequeue(&sk->receive_queue);		if (skb==NULL)		{			if (copied >= target)				break;			/*			 *	POSIX 1003.1g mandates this order.			 */			 			if ((err = sock_error(sk)) != 0)				break;			if (sk->shutdown & RCV_SHUTDOWN)				break;			err = -EAGAIN;			if (!timeo)				break;			up(&sk->protinfo.af_unix.readsem);			timeo = unix_stream_data_wait(sk, timeo);			if (signal_pending(current)) {				err = sock_intr_errno(timeo);				goto out;			}			down(&sk->protinfo.af_unix.readsem);			continue;		}		if (check_creds) {			/* Never glue messages from different writers */			if (memcmp(UNIXCREDS(skb), &scm->creds, sizeof(scm->creds)) != 0) {				skb_queue_head(&sk->receive_queue, skb);				break;			}		} else {			/* Copy credentials */			scm->creds = *UNIXCREDS(skb);			check_creds = 1;		}		/* Copy address just once */		if (sunaddr)		{			unix_copy_addr(msg, skb->sk);			sunaddr = NULL;		}		chunk = min(skb->len, size);		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {			skb_queue_head(&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(scm, skb);			/* put the skb back if we didn't use it up.. */			if (skb->len)			{				skb_queue_head(&sk->receive_queue, skb);				break;			}			kfree_skb(skb);			if (scm->fp)				break;		}		else		{			/* It is questionable, see note in unix_dgram_recvmsg.			 */			if (UNIXCB(skb).fp)				scm->fp = scm_fp_dup(UNIXCB(skb).fp);			/* put message back and return */			skb_queue_head(&sk->receive_queue, skb);			break;		}	} while (size);	up(&sk->protinfo.af_unix.readsem);out:	return copied ? : err;}static int unix_shutdown(struct socket *sock, int mode){	struct sock *sk = sock->sk;	unix_socket *other;	mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN);	if (mode) {		unix_state_wlock(sk);		sk->shutdown |= mode;		other=unix_peer(sk);		if (other)			sock_hold(other);		unix_state_wunlock(sk);		sk->state_change(sk);		if (other && sk->type == SOCK_STREAM) {			int peer_mode = 0;			if (mode&RCV_SHUTDOWN)				peer_mode |= SEND_SHUTDOWN;			if (mode&SEND_SHUTDOWN)				peer_mode |= RCV_SHUTDOWN;			unix_state_wlock(other);			other->shutdown |= peer_mode;			unix_state_wunlock(other);			other->state_change(other);			read_lock(&other->callback_lock);			if (peer_mode == SHUTDOWN_MASK)				sk_wake_async(other,1,POLL_HUP);			else if (peer_mode & RCV_SHUTDOWN)				sk_wake_async(other,1,POLL_IN);			read_unlock(&other->callback_lock);		}		if (other)			sock_put(other);	}	return 0;}static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	long amount=0;	int err;	switch(cmd)	{		case SIOCOUTQ:			amount = atomic_read(&sk->wmem_alloc);			err = put_user(amount, (int *)arg);			break;		case SIOCINQ:		{			struct sk_buff *skb;			if (sk->state==TCP_LISTEN) {				err = -EINVAL;				break;			}			spin_lock(&sk->receive_queue.lock);			if((skb=skb_peek(&sk->receive_queue))!=NULL)				amount=skb->len;			spin_unlock(&sk->receive_queue.lock);			err = put_user(amount, (int *)arg);			break;		}		default:			err = dev_ioctl(cmd, (void *)arg);			break;	}	return err;}static unsigned int unix_poll(struct file * file, struct socket *sock, poll_table *wait){	struct sock *sk = sock->sk;	unsigned int mask;	poll_wait(file, sk->sleep, wait);	mask = 0;	/* exceptional events? */	if (sk->err)		mask |= POLLERR;	if (sk->shutdown == SHUTDOWN_MASK)		mask |= POLLHUP;	/* readable? */	if (!skb_queue_empty(&sk->receive_queue) || (sk->shutdown&RCV_SHUTDOWN))		mask |= POLLIN | POLLRDNORM;	/* Connection-based need to check for termination and startup */	if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)		mask |= POLLHUP;	/*	 * we set writable also when the other side has shut down the	 * connection. This prevents stuck sockets.	 */	if (unix_writable(sk))		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;	return mask;}#ifdef CONFIG_PROC_FSstatic int unix_read_proc(char *buffer, char **start, off_t offset,			  int length, int *eof, void *data){	off_t pos=0;	off_t begin=0;	int len=0;	int i;	unix_socket *s;		len+= sprintf(buffer,"Num       RefCount Protocol Flags    Type St "	    "Inode Path\n");	read_lock(&unix_table_lock);	forall_unix_sockets (i,s)	{		unix_state_rlock(s);		len+=sprintf(buffer+len,"%p: %08X %08X %08X %04X %02X %5ld",			s,			atomic_read(&s->refcnt),			0,			s->state == TCP_LISTEN ? __SO_ACCEPTCON : 0,			s->type,			s->socket ?			(s->state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) :			(s->state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING),			sock_i_ino(s));		if (s->protinfo.af_unix.addr)		{			buffer[len++] = ' ';			memcpy(buffer+len, s->protinfo.af_unix.addr->name->sun_path,			       s->protinfo.af_unix.addr->len-sizeof(short));			if (!UNIX_ABSTRACT(s))				len--;			else				buffer[len] = '@';			len += s->protinfo.af_unix.addr->len - sizeof(short);		}		unix_state_runlock(s);		buffer[len++]='\n';				pos = begin + len;		if(pos<offset)		{			len=0;			begin=pos;		}		if(pos>offset+length)			goto done;	}	*eof = 1;done:	read_unlock(&unix_table_lock);	*start=buffer+(offset-begin);	len-=(offset-begin);	if(len>length)		len=length;	if (len < 0)		len = 0;	return len;}#endifstruct proto_ops unix_stream_ops = {	family:		PF_UNIX,		release:	unix_release,	bind:		unix_bind,	connect:	unix_stream_connect,	socketpair:	unix_socketpair,	accept:		unix_accept,	getname:	unix_getname,	poll:		unix_poll,	ioctl:		unix_ioctl,	listen:		unix_listen,	shutdown:	unix_shutdown,	setsockopt:	sock_no_setsockopt,	getsockopt:	sock_no_getsockopt,	sendmsg:	unix_stream_sendmsg,	recvmsg:	unix_stream_recvmsg,	mmap:		sock_no_mmap,};struct proto_ops unix_dgram_ops = {	family:		PF_UNIX,		release:	unix_release,	bind:		unix_bind,	connect:	unix_dgram_connect,	socketpair:	unix_socketpair,	accept:		sock_no_accept,	getname:	unix_getname,	poll:		datagram_poll,	ioctl:		unix_ioctl,	listen:		sock_no_listen,	shutdown:	unix_shutdown,	setsockopt:	sock_no_setsockopt,	getsockopt:	sock_no_getsockopt,	sendmsg:	unix_dgram_sendmsg,	recvmsg:	unix_dgram_recvmsg,	mmap:		sock_no_mmap,};struct net_proto_family unix_family_ops = {	PF_UNIX,	unix_create};#ifdef CONFIG_SYSCTLextern void unix_sysctl_register(void);extern void unix_sysctl_unregister(void);#endifstatic int __init af_unix_init(void){	struct sk_buff *dummy_skb;		printk(KERN_INFO "NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.\n");	if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb))	{		printk(KERN_CRIT "unix_proto_init: panic\n");		return -1;	}	sock_register(&unix_family_ops);#ifdef CONFIG_PROC_FS	create_proc_read_entry("net/unix", 0, 0, unix_read_proc, NULL);#endif#ifdef CONFIG_SYSCTL	unix_sysctl_register();#endif	return 0;}static void __exit af_unix_exit(void){	sock_unregister(PF_UNIX);#ifdef CONFIG_SYSCTL	unix_sysctl_unregister();#endif#ifdef CONFIG_PROC_FS	remove_proc_entry("net/unix", 0);#endif}module_init(af_unix_init);module_exit(af_unix_exit);/* * Local variables: *  compile-command: "gcc -g -D__KERNEL__ -Wall -O6 -I/usr/src/linux/include -c af_unix.c" * End: */

⌨️ 快捷键说明

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