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

📄 sock.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Simple resource managers for sockets. *//*  * Write buffer destructor automatically called from kfree_skb.  */void sock_wfree(struct sk_buff *skb){	struct sock *sk = skb->sk;	/* In case it might be waiting for more memory. */	atomic_sub(skb->truesize, &sk->wmem_alloc);	sk->write_space(sk);}/*  * Read buffer destructor automatically called from kfree_skb.  */void sock_rfree(struct sk_buff *skb){	struct sock *sk = skb->sk;	atomic_sub(skb->truesize, &sk->rmem_alloc);}/* * Allocate a skb from the socket's send buffer. */struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority){	if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) {		struct sk_buff * skb = alloc_skb(size, priority);		if (skb) {			atomic_add(skb->truesize, &sk->wmem_alloc);			skb->destructor = sock_wfree;			skb->sk = sk;			return skb;		}	}	return NULL;}/* * Allocate a skb from the socket's receive buffer. */ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority){	if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) {		struct sk_buff *skb = alloc_skb(size, priority);		if (skb) {			atomic_add(skb->truesize, &sk->rmem_alloc);			skb->destructor = sock_rfree;			skb->sk = sk;			return skb;		}	}	return NULL;}/*  * Allocate a memory block from the socket's option memory buffer. */ void *sock_kmalloc(struct sock *sk, int size, int priority){	if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) {		void *mem;		/* First do the add, to avoid the race if kmalloc 		 * might sleep.		 */		atomic_add(size, &sk->omem_alloc);		mem = kmalloc(size, priority);		if (mem)			return mem;		atomic_sub(size, &sk->omem_alloc);	}	return NULL;}/* * Free an option memory block. */void sock_kfree_s(struct sock *sk, void *mem, int size){	kfree_s(mem, size); 	atomic_sub(size, &sk->omem_alloc);}/* FIXME: this is insane. We are trying suppose to be controlling how * how much space we have for data bytes, not packet headers. * This really points out that we need a better system for doing the * receive buffer. -- erics * WARNING: This is currently ONLY used in tcp. If you need it else where * this will probably not be what you want. Possibly these two routines * should move over to the ipv4 directory. */unsigned long sock_rspace(struct sock *sk){	int amt = 0;	if (sk != NULL) {		/* This used to have some bizarre complications that		 * to attempt to reserve some amount of space. This doesn't	 	 * make sense, since the number returned here does not		 * actually reflect allocated space, but rather the amount		 * of space we committed to. We gamble that we won't		 * run out of memory, and returning a smaller number does		 * not change the gamble. If we lose the gamble tcp still		 * works, it may just slow down for retransmissions.		 */		amt = sk->rcvbuf - atomic_read(&sk->rmem_alloc);		if (amt < 0) 			amt = 0;	}	return amt;}/* It is almost wait_for_tcp_memory minus release_sock/lock_sock.   I think, these locks should be removed for datagram sockets. */static void sock_wait_for_wmem(struct sock * sk){	struct wait_queue wait = { current, NULL };	sk->socket->flags &= ~SO_NOSPACE;	add_wait_queue(sk->sleep, &wait);	for (;;) {		if (signal_pending(current))			break;		current->state = TASK_INTERRUPTIBLE;		if (atomic_read(&sk->wmem_alloc) < sk->sndbuf)			break;		if (sk->shutdown & SEND_SHUTDOWN)			break;		if (sk->err)			break;		schedule();	}	current->state = TASK_RUNNING;	remove_wait_queue(sk->sleep, &wait);}/* *	Generic send/receive buffer handlers */struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, 			unsigned long fallback, int noblock, int *errcode){	int err;	struct sk_buff *skb;	while (1) {		unsigned long try_size = size;		err = sock_error(sk);		if (err != 0)			goto failure;		/*		 *	We should send SIGPIPE in these cases according to		 *	1003.1g draft 6.4. If we (the user) did a shutdown()		 *	call however we should not. 		 *		 *	Note: This routine isnt just used for datagrams and		 *	anyway some datagram protocols have a notion of		 *	close down.		 */		err = -EPIPE;		if (sk->shutdown&SEND_SHUTDOWN)			goto failure;		if (fallback) {			/* The buffer get won't block, or use the atomic queue.			 * It does produce annoying no free page messages still.			 */			skb = sock_wmalloc(sk, size, 0, GFP_BUFFER);			if (skb)				break;			try_size = fallback;		}		skb = sock_wmalloc(sk, try_size, 0, sk->allocation);		if (skb)			break;		/*		 *	This means we have too many buffers for this socket already.		 */		sk->socket->flags |= SO_NOSPACE;		err = -EAGAIN;		if (noblock)			goto failure;		err = -ERESTARTSYS;		if (signal_pending(current))			goto failure;		sock_wait_for_wmem(sk);	}	return skb;failure:	*errcode = err;	return NULL;}void __release_sock(struct sock *sk){#ifdef CONFIG_INET	if (!sk->prot || !sk->backlog_rcv)		return;			/* See if we have any packets built up. */	start_bh_atomic();	while (!skb_queue_empty(&sk->back_log)) {		struct sk_buff * skb = sk->back_log.next;		__skb_unlink(skb, &sk->back_log);		sk->backlog_rcv(sk, skb);	}	end_bh_atomic();#endif  }/* *	Generic socket manager library. Most simpler socket families *	use this to manage their socket lists. At some point we should *	hash these. By making this generic we get the lot hashed for free. */ void sklist_remove_socket(struct sock **list, struct sock *sk){	struct sock *s;	start_bh_atomic();	s= *list;	if(s==sk)	{		*list = s->next;		end_bh_atomic();		return;	}	while(s && s->next)	{		if(s->next==sk)		{			s->next=sk->next;			break;		}		s=s->next;	}	end_bh_atomic();}void sklist_insert_socket(struct sock **list, struct sock *sk){	start_bh_atomic();	sk->next= *list;	*list=sk;	end_bh_atomic();}/* *	This is only called from user mode. Thus it protects itself against *	interrupt users but doesn't worry about being called during work. *	Once it is removed from the queue no interrupt or bottom half will *	touch it and we are (fairly 8-) ) safe. */void sklist_destroy_socket(struct sock **list, struct sock *sk);/* *	Handler for deferred kills. */static void sklist_destroy_timer(unsigned long data){	struct sock *sk=(struct sock *)data;	sklist_destroy_socket(NULL,sk);}/* *	Destroy a socket. We pass NULL for a list if we know the *	socket is not on a list. */ void sklist_destroy_socket(struct sock **list,struct sock *sk){	struct sk_buff *skb;	if(list)		sklist_remove_socket(list, sk);	while((skb=skb_dequeue(&sk->receive_queue))!=NULL)	{		kfree_skb(skb);	}	if(atomic_read(&sk->wmem_alloc) == 0 &&	   atomic_read(&sk->rmem_alloc) == 0 &&	   sk->dead)	{		sk_free(sk);	}	else	{		/*		 *	Someone is using our buffers still.. defer		 */		init_timer(&sk->timer);		sk->timer.expires=jiffies+SOCK_DESTROY_TIME;		sk->timer.function=sklist_destroy_timer;		sk->timer.data = (unsigned long)sk;		add_timer(&sk->timer);	}}/* * Set of default routines for initialising struct proto_ops when * the protocol does not support a particular function. In certain * cases where it makes no sense for a protocol to have a "do nothing" * function, some default processing is provided. */int sock_no_dup(struct socket *newsock, struct socket *oldsock){	struct sock *sk = oldsock->sk;	return net_families[sk->family]->create(newsock, sk->protocol);}int sock_no_release(struct socket *sock, struct socket *peersock){	return 0;}int sock_no_bind(struct socket *sock, struct sockaddr *saddr, int len){	return -EOPNOTSUPP;}int sock_no_connect(struct socket *sock, struct sockaddr *saddr, 		    int len, int flags){	return -EOPNOTSUPP;}int sock_no_socketpair(struct socket *sock1, struct socket *sock2){	return -EOPNOTSUPP;}int sock_no_accept(struct socket *sock, struct socket *newsock, int flags){	return -EOPNOTSUPP;}int sock_no_getname(struct socket *sock, struct sockaddr *saddr, 		    int *len, int peer){	return -EOPNOTSUPP;}unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt){	return 0;}int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	return -EOPNOTSUPP;}int sock_no_listen(struct socket *sock, int backlog){	return -EOPNOTSUPP;}int sock_no_shutdown(struct socket *sock, int how){	return -EOPNOTSUPP;}int sock_no_setsockopt(struct socket *sock, int level, int optname,		    char *optval, int optlen){	return -EOPNOTSUPP;}int sock_no_getsockopt(struct socket *sock, int level, int optname,		    char *optval, int *optlen){	return -EOPNOTSUPP;}/*  * Note: if you add something that sleeps here then change sock_fcntl() *       to do proper fd locking. */int sock_no_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	switch(cmd)	{		case F_SETOWN:			/*			 * This is a little restrictive, but it's the only			 * way to make sure that you can't send a sigurg to			 * another process.			 */			if (current->pgrp != -arg &&				current->pid != arg &&				!capable(CAP_KILL)) return(-EPERM);			sk->proc = arg;			return(0);		case F_GETOWN:			return(sk->proc);		default:			return(-EINVAL);	}}int sock_no_sendmsg(struct socket *sock, struct msghdr *m, int flags,		    struct scm_cookie *scm){	return -EOPNOTSUPP;}int sock_no_recvmsg(struct socket *sock, struct msghdr *m, int flags,		    struct scm_cookie *scm){	return -EOPNOTSUPP;}/* *	Default Socket Callbacks */void sock_def_wakeup(struct sock *sk){	if(!sk->dead)		wake_up_interruptible(sk->sleep);}void sock_def_error_report(struct sock *sk){	if (!sk->dead) {		wake_up_interruptible(sk->sleep);		sock_wake_async(sk->socket,0); 	}}void sock_def_readable(struct sock *sk, int len){	if(!sk->dead) {		wake_up_interruptible(sk->sleep);		sock_wake_async(sk->socket,1);	}}void sock_def_write_space(struct sock *sk){	/* Do not wake up a writer until he can make "significant"	 * progress.  --DaveM	 */	if(!sk->dead &&	   ((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf)) {		wake_up_interruptible(sk->sleep);		/* Should agree with poll, otherwise some programs break */		if (sock_writeable(sk))			sock_wake_async(sk->socket, 2);	}}void sock_def_destruct(struct sock *sk){	if (sk->protinfo.destruct_hook)		kfree(sk->protinfo.destruct_hook);}void sock_init_data(struct socket *sock, struct sock *sk){	skb_queue_head_init(&sk->receive_queue);	skb_queue_head_init(&sk->write_queue);	skb_queue_head_init(&sk->back_log);	skb_queue_head_init(&sk->error_queue);		init_timer(&sk->timer);		sk->allocation	=	GFP_KERNEL;	sk->rcvbuf	=	sysctl_rmem_default;	sk->sndbuf	=	sysctl_wmem_default;	sk->state 	= 	TCP_CLOSE;	sk->zapped	=	1;	sk->socket	=	sock;	if(sock)	{		sk->type	=	sock->type;		sk->sleep	=	&sock->wait;		sock->sk	=	sk;	}	sk->state_change	=	sock_def_wakeup;	sk->data_ready		=	sock_def_readable;	sk->write_space		=	sock_def_write_space;	sk->error_report	=	sock_def_error_report;	sk->destruct            =       sock_def_destruct;	sk->peercred.pid 	=	0;	sk->peercred.uid	=	-1;	sk->peercred.gid	=	-1;}

⌨️ 快捷键说明

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