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

📄 af_unix.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
	.sendmsg =	unix_dgram_sendmsg,	.recvmsg =	unix_dgram_recvmsg,	.mmap =		sock_no_mmap,	.sendpage =	sock_no_sendpage,};static struct proto_ops unix_seqpacket_ops = {	.family =	PF_UNIX,	.owner =	THIS_MODULE,	.release =	unix_release,	.bind =		unix_bind,	.connect =	unix_stream_connect,	.socketpair =	unix_socketpair,	.accept =	unix_accept,	.getname =	unix_getname,	.poll =		datagram_poll,	.ioctl =	unix_ioctl,	.listen =	unix_listen,	.shutdown =	unix_shutdown,	.setsockopt =	sock_no_setsockopt,	.getsockopt =	sock_no_getsockopt,	.sendmsg =	unix_dgram_sendmsg,	.recvmsg =	unix_dgram_recvmsg,	.mmap =		sock_no_mmap,	.sendpage =	sock_no_sendpage,};static struct sock * unix_create1(struct socket *sock){	struct sock *sk = NULL;	struct unix_sock *u;	if (atomic_read(&unix_nr_socks) >= 2*files_stat.max_files)		goto out;	sk = sk_alloc(PF_UNIX, GFP_KERNEL, sizeof(struct unix_sock),		      unix_sk_cachep);	if (!sk)		goto out;	atomic_inc(&unix_nr_socks);	sock_init_data(sock,sk);	sk_set_owner(sk, THIS_MODULE);	sk->sk_write_space	= unix_write_space;	sk->sk_max_ack_backlog	= sysctl_unix_max_dgram_qlen;	sk->sk_destruct		= unix_sock_destructor;	u	  = unix_sk(sk);	u->dentry = NULL;	u->mnt	  = NULL;	rwlock_init(&u->lock);	atomic_set(&u->inflight, sock ? 0 : -1);	init_MUTEX(&u->readsem); /* single task reading lock */	init_waitqueue_head(&u->peer_wait);	unix_insert_socket(unix_sockets_unbound, sk);out:	return sk;}static int unix_create(struct socket *sock, int protocol){	if (protocol && protocol != PF_UNIX)		return -EPROTONOSUPPORT;	sock->state = SS_UNCONNECTED;	switch (sock->type) {	case SOCK_STREAM:		sock->ops = &unix_stream_ops;		break;		/*		 *	Believe it or not BSD has AF_UNIX, SOCK_RAW though		 *	nothing uses it.		 */	case SOCK_RAW:		sock->type=SOCK_DGRAM;	case SOCK_DGRAM:		sock->ops = &unix_dgram_ops;		break;	case SOCK_SEQPACKET:		sock->ops = &unix_seqpacket_ops;		break;	default:		return -ESOCKTNOSUPPORT;	}	return unix_create1(sock) ? 0 : -ENOMEM;}static int unix_release(struct socket *sock){	struct sock *sk = sock->sk;	if (!sk)		return 0;	sock->sk = NULL;	return unix_release_sock (sk, 0);}static int unix_autobind(struct socket *sock){	struct sock *sk = sock->sk;	struct unix_sock *u = unix_sk(sk);	static u32 ordernum = 1;	struct unix_address * addr;	int err;	down(&u->readsem);	err = 0;	if (u->addr)		goto out;	err = -ENOMEM;	addr = kmalloc(sizeof(*addr) + sizeof(short) + 16, GFP_KERNEL);	if (!addr)		goto out;	memset(addr, 0, sizeof(*addr) + sizeof(short) + 16);	addr->name->sun_family = AF_UNIX;	atomic_set(&addr->refcnt, 1);retry:	addr->len = sprintf(addr->name->sun_path+1, "%05x", ordernum) + 1 + sizeof(short);	addr->hash = unix_hash_fold(csum_partial((void*)addr->name, addr->len, 0));	write_lock(&unix_table_lock);	ordernum = (ordernum+1)&0xFFFFF;	if (__unix_find_socket_byname(addr->name, addr->len, sock->type,				      addr->hash)) {		write_unlock(&unix_table_lock);		/* Sanity yield. It is unusual case, but yet... */		if (!(ordernum&0xFF))			yield();		goto retry;	}	addr->hash ^= sk->sk_type;	__unix_remove_socket(sk);	u->addr = addr;	__unix_insert_socket(&unix_socket_table[addr->hash], sk);	write_unlock(&unix_table_lock);	err = 0;out:	up(&u->readsem);	return err;}static struct sock *unix_find_other(struct sockaddr_un *sunname, int len,				    int type, unsigned hash, int *error){	struct sock *u;	struct nameidata nd;	int err = 0;		if (sunname->sun_path[0]) {		err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd);		if (err)			goto fail;		err = permission(nd.dentry->d_inode,MAY_WRITE, &nd);		if (err)			goto put_fail;		err = -ECONNREFUSED;		if (!S_ISSOCK(nd.dentry->d_inode->i_mode))			goto put_fail;		u=unix_find_socket_byinode(nd.dentry->d_inode);		if (!u)			goto put_fail;		if (u->sk_type == type)			touch_atime(nd.mnt, nd.dentry);		path_release(&nd);		err=-EPROTOTYPE;		if (u->sk_type != type) {			sock_put(u);			goto fail;		}	} else {		err = -ECONNREFUSED;		u=unix_find_socket_byname(sunname, len, type, hash);		if (u) {			struct dentry *dentry;			dentry = unix_sk(u)->dentry;			if (dentry)				touch_atime(unix_sk(u)->mnt, dentry);		} else			goto fail;	}	return u;put_fail:	path_release(&nd);fail:	*error=err;	return NULL;}static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sock *sk = sock->sk;	struct unix_sock *u = unix_sk(sk);	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;	struct dentry * dentry = NULL;	struct nameidata nd;	int err;	unsigned hash;	struct unix_address *addr;	struct hlist_head *list;	err = -EINVAL;	if (sunaddr->sun_family != AF_UNIX)		goto out;	if (addr_len==sizeof(short)) {		err = unix_autobind(sock);		goto out;	}	err = unix_mkname(sunaddr, addr_len, &hash);	if (err < 0)		goto out;	addr_len = err;	down(&u->readsem);	err = -EINVAL;	if (u->addr)		goto out_up;	err = -ENOMEM;	addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);	if (!addr)		goto out_up;	memcpy(addr->name, sunaddr, addr_len);	addr->len = addr_len;	addr->hash = hash ^ sk->sk_type;	atomic_set(&addr->refcnt, 1);	if (sunaddr->sun_path[0]) {		unsigned int mode;		err = 0;		/*		 * Get the parent directory, calculate the hash for last		 * component.		 */		err = path_lookup(sunaddr->sun_path, LOOKUP_PARENT, &nd);		if (err)			goto out_mknod_parent;		/*		 * Yucky last component or no last component at all?		 * (foo/., foo/.., /////)		 */		err = -EEXIST;		if (nd.last_type != LAST_NORM)			goto out_mknod;		/*		 * Lock the directory.		 */		down(&nd.dentry->d_inode->i_sem);		/*		 * Do the final lookup.		 */		dentry = lookup_hash(&nd.last, nd.dentry);		err = PTR_ERR(dentry);		if (IS_ERR(dentry))			goto out_mknod_unlock;		err = -ENOENT;		/*		 * Special case - lookup gave negative, but... we had foo/bar/		 * From the vfs_mknod() POV we just have a negative dentry -		 * all is fine. Let's be bastards - you had / on the end, you've		 * been asking for (non-existent) directory. -ENOENT for you.		 */		if (nd.last.name[nd.last.len] && !dentry->d_inode)			goto out_mknod_dput;		/*		 * All right, let's create it.		 */		mode = S_IFSOCK |		       (SOCK_INODE(sock)->i_mode & ~current->fs->umask);		err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0);		if (err)			goto out_mknod_dput;		up(&nd.dentry->d_inode->i_sem);		dput(nd.dentry);		nd.dentry = dentry;		addr->hash = UNIX_HASH_SIZE;	}	write_lock(&unix_table_lock);	if (!sunaddr->sun_path[0]) {		err = -EADDRINUSE;		if (__unix_find_socket_byname(sunaddr, addr_len,					      sk->sk_type, hash)) {			unix_release_addr(addr);			goto out_unlock;		}		list = &unix_socket_table[addr->hash];	} else {		list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];		u->dentry = nd.dentry;		u->mnt    = nd.mnt;	}	err = 0;	__unix_remove_socket(sk);	u->addr = addr;	__unix_insert_socket(list, sk);out_unlock:	write_unlock(&unix_table_lock);out_up:	up(&u->readsem);out:	return err;out_mknod_dput:	dput(dentry);out_mknod_unlock:	up(&nd.dentry->d_inode->i_sem);out_mknod:	path_release(&nd);out_mknod_parent:	if (err==-EEXIST)		err=-EADDRINUSE;	unix_release_addr(addr);	goto out_up;}static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,			      int alen, int flags){	struct sock *sk = sock->sk;	struct sockaddr_un *sunaddr=(struct sockaddr_un*)addr;	struct sock *other;	unsigned hash;	int err;	if (addr->sa_family != AF_UNSPEC) {		err = unix_mkname(sunaddr, alen, &hash);		if (err < 0)			goto out;		alen = err;		if (sock->passcred && !unix_sk(sk)->addr &&		    (err = unix_autobind(sock)) != 0)			goto out;		other=unix_find_other(sunaddr, alen, sock->type, hash, &err);		if (!other)			goto out;		unix_state_wlock(sk);		err = -EPERM;		if (!unix_may_send(sk, other))			goto out_unlock;		err = security_unix_may_send(sk->sk_socket, other->sk_socket);		if (err)			goto out_unlock;	} else {		/*		 *	1003.1g breaking connected state with AF_UNSPEC		 */		other = NULL;		unix_state_wlock(sk);	}	/*	 * If it was connected, reconnect.	 */	if (unix_peer(sk)) {		struct sock *old_peer = unix_peer(sk);		unix_peer(sk)=other;		unix_state_wunlock(sk);		if (other != old_peer)			unix_dgram_disconnected(sk, old_peer);		sock_put(old_peer);	} else {		unix_peer(sk)=other;		unix_state_wunlock(sk);	} 	return 0;out_unlock:	unix_state_wunlock(sk);	sock_put(other);out:	return err;}static long unix_wait_for_peer(struct sock *other, long timeo){	struct unix_sock *u = unix_sk(other);	int sched;	DEFINE_WAIT(wait);	prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE);	sched = !sock_flag(other, SOCK_DEAD) &&		!(other->sk_shutdown & RCV_SHUTDOWN) &&		(skb_queue_len(&other->sk_receive_queue) >		 other->sk_max_ack_backlog);	unix_state_runlock(other);	if (sched)		timeo = schedule_timeout(timeo);	finish_wait(&u->peer_wait, &wait);	return timeo;}static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,			       int addr_len, int flags){	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;	struct sock *sk = sock->sk;	struct unix_sock *u = unix_sk(sk), *newu, *otheru;	struct sock *newsk = NULL;	struct sock *other = NULL;	struct sk_buff *skb = NULL;	unsigned hash;	int st;	int err;	long timeo;	err = unix_mkname(sunaddr, addr_len, &hash);	if (err < 0)		goto out;	addr_len = err;	if (sock->passcred && !u->addr && (err = unix_autobind(sock)) != 0)		goto out;	timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);	/* First of all allocate resources.	   If we will make it after state is locked,	   we will have to recheck all again in any case.	 */	err = -ENOMEM;	/* create new sock for complete connection */	newsk = unix_create1(NULL);	if (newsk == NULL)		goto out;	/* Allocate skb for sending to listening sock */	skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL);	if (skb == NULL)		goto out;restart:	/*  Find listening sock. */	other = unix_find_other(sunaddr, addr_len, sk->sk_type, hash, &err);	if (!other)		goto out;	/* Latch state of peer */	unix_state_rlock(other);	/* Apparently VFS overslept socket death. Retry. */	if (sock_flag(other, SOCK_DEAD)) {		unix_state_runlock(other);		sock_put(other);		goto restart;	}	err = -ECONNREFUSED;	if (other->sk_state != TCP_LISTEN)		goto out_unlock;	if (skb_queue_len(&other->sk_receive_queue) >	    other->sk_max_ack_backlog) {		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;

⌨️ 快捷键说明

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