linux1.2.13源码中,管理sock结构体的数据结构及操作函数

本文深入解析了TCP/IP协议中Socket的管理机制,包括如何利用哈希链表存储和检索Socket结构体,以及一系列操作函数如端口检查、端口分配、Socket添加和移除等。同时,详细介绍了如何在系统中创建、使用和销毁Socket。

tcp和udp等协议在传输层都对应一个sock结构,该结构是实现协议的重要结构体,而传输层实现的就是对该结构体的管理。利用一个哈希链表根据端口号保存sock结构体。有了保存sock结构的数据结构后,还需要一系列的操作函数。代码如下。



/*
 *	See if a socket number is in use.
 */
// 看socket的端口是否在使用 
static int sk_inuse(struct proto *prot, int num)
{
	struct sock *sk;
	// 根据端口号取得哈希链表中的一个链表
	for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )];
		sk != NULL;  sk=sk->next) 
	{
		if (sk->num == num) 
			return(1);
	}
	return(0);
}


/*
 *	Pick a new socket number
 */
// 随机获取一个端口
unsigned short get_new_socknum(struct proto *prot, unsigned short base)
{
	static int start=0;

	/*
	 * Used to cycle through the port numbers so the
	 * chances of a confused connection drop.
	 */
	 
	int i, j;
	int best = 0;
	int size = 32767; /* a big num. */
	struct sock *sk;
	// 大于1024
	if (base == 0) 
		base = PROT_SOCK+1+(start % 1024);
	if (base <= PROT_SOCK) 
	{
		base += PROT_SOCK+(start % 1024);
	}

	/* Now look through the entire array and try to find an empty ptr. */
	for(i=0; i < SOCK_ARRAY_SIZE; i++) 
	{
		j = 0;
		// 找到一条链表
		sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)];
		// 找到链表中的最后一个节点
		while(sk != NULL) 
		{
			sk = sk->next;
			j++;
		}
		// 该链表上还没有节点,说明这个端口还没有被使用过,返回该端口号,更新start变量
		if (j == 0) 
		{
			start =(i+1+start )%1024;
			return(i+base+1);
		}
		/*
			j为本次循环的队列的节点数,best记录新端口所属队列的索引,
			size为本次循环为止节点数最少的队列的节点数,为了避免单个队列过长,
			找可用端口的时候,不仅要找到一个可用的端口,而且尽量保证端口所对
			应的队列不会过长,避免查找的时候比较慢,所以for循环是为了找出哈希链表
			中节点数最少的队列对应的索引。然后往该队列插入一个新的端口节点
		*/
		if (j < size) 
		{
			best = i;
			size = j;
		}
	}

	/* Now make sure the one we want is not in use. */
	// 在一条队列中找到一个未使用的端口号,SOCK_ARRAY_SIZE保证哈希后对应的是同一个队列
	while(sk_inuse(prot, base +best+1)) 
	{
		best += SOCK_ARRAY_SIZE;
	}
	return(best+base+1);
}

/*
 *	Add a socket into the socket tables by number.
 */

void put_sock(unsigned short num, struct sock *sk)
{
	struct sock *sk1;
	struct sock *sk2;
	int mask;
	unsigned long flags;

	sk->num = num;
	sk->next = NULL;
	num = num &(SOCK_ARRAY_SIZE -1);

	/* We can't have an interrupt re-enter here. */
	save_flags(flags);
	cli();
	// 使用的socket数
	sk->prot->inuse += 1;
	// 最多使用的socket数
	if (sk->prot->highestinuse < sk->prot->inuse)
		sk->prot->highestinuse = sk->prot->inuse;
	// 链表为空,sk成为第一个节点
	if (sk->prot->sock_array[num] == NULL) 
	{
		sk->prot->sock_array[num] = sk;
		restore_flags(flags);
		return;
	}
	restore_flags(flags);
	// mask为0xff000000 => 0xffff0000 => 0xffffff00 => 0xffffffff
	for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask) 
	{
		if ((mask & sk->saddr) &&
		    (mask & sk->saddr) != (mask & 0xffffffff)) 
		{
			mask = mask << 8;
			break;
		}
	}
	cli();
	// 根据端口找到对应的链表,找到对应的位置插入队列
	sk1 = sk->prot->sock_array[num];
	for(sk2 = sk1; sk2 != NULL; sk2=sk2->next) 
	{
		if (!(sk2->saddr & mask)) 
		{
			if (sk2 == sk1) 
			{
				sk->next = sk->prot->sock_array[num];
				sk->prot->sock_array[num] = sk;
				sti();
				return;
			}
			sk->next = sk2;
			sk1->next= sk;
			sti();
			return;
		}
		sk1 = sk2;
	}

	/* Goes at the end. */
	sk->next = NULL;
	sk1->next = sk;
	sti();
}

/*
 *	Remove a socket from the socket tables.
 */

static void remove_sock(struct sock *sk1)
{
	struct sock *sk2;
	unsigned long flags;

	if (!sk1->prot) 
	{
		printk("sock.c: remove_sock: sk1->prot == NULL\n");
		return;
	}

	/* We can't have this changing out from under us. */
	save_flags(flags);
	cli();
	sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)];
	// 是队列的第一个节点
	if (sk2 == sk1) 
	{
		sk1->prot->inuse -= 1;
		sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next;
		restore_flags(flags);
		return;
	}
	// 找sk1
	while(sk2 && sk2->next != sk1) 
	{
		sk2 = sk2->next;
	}
	// 找到
	if (sk2) 
	{
		sk1->prot->inuse -= 1;
		sk2->next = sk1->next;
		restore_flags(flags);
		return;
	}
	restore_flags(flags);
}

/*
 *	Destroy an AF_INET socket
 */
 
void destroy_sock(struct sock *sk)
{
	struct sk_buff *skb;

  	sk->inuse = 1;			/* just to be safe. */

  	/* In case it's sleeping somewhere. */
  	if (!sk->dead) 
  		sk->write_space(sk);

  	remove_sock(sk);
  
  	/* Now we can no longer get new packets. */
  	delete_timer(sk);
  	/* Nor send them */
	del_timer(&sk->retransmit_timer);
	
	while ((skb = tcp_dequeue_partial(sk)) != NULL) {
		IS_SKB(skb);
		kfree_skb(skb, FREE_WRITE);
	}

	/* Cleanup up the write buffer. */
  	while((skb = skb_dequeue(&sk->write_queue)) != NULL) {
		IS_SKB(skb);
		kfree_skb(skb, FREE_WRITE);
  	}
  	
  	/*
  	 *	Don't discard received data until the user side kills its
  	 *	half of the socket.
  	 */

	if (sk->dead) 
	{
  		while((skb=skb_dequeue(&sk->receive_queue))!=NULL) 
  		{
		/*
		 * This will take care of closing sockets that were
		 * listening and didn't accept everything.
		 */
			// 处理listen型的socket,监听套接字接收队列里的skb关联的sock结构是一个新建的而不是sk
			if (skb->sk != NULL && skb->sk != sk) 
			{
				IS_SKB(skb);
				skb->sk->dead = 1;
				// 关闭连接
				skb->sk->prot->close(skb->sk, 0);
			}
			IS_SKB(skb);
			kfree_skb(skb, FREE_READ);
		}
	}	

	/* Now we need to clean up the send head. */
	cli();
	// 清空为了重传而缓存的数据包
	for(skb = sk->send_head; skb != NULL; )
	{
		struct sk_buff *skb2;

		/*
		 * We need to remove skb from the transmit queue,
		 * or maybe the arp queue.
		 */
		if (skb->next  && skb->prev) {
/*			printk("destroy_sock: unlinked skb\n");*/
			IS_SKB(skb);
			skb_unlink(skb);
		}
		skb->dev = NULL;
		// unlink后link3指针仍然指向下一个skb节点
		skb2 = skb->link3;
		kfree_skb(skb, FREE_WRITE);
		skb = skb2;
	}
	sk->send_head = NULL;
	sti();

  	/* And now the backlog. */
	// 还没来得及移到receive_queue队列的而缓存在back_log队列的skb
  	while((skb=skb_dequeue(&sk->back_log))!=NULL) 
  	{
		/* this should never happen. */
/*		printk("cleaning back_log\n");*/
		kfree_skb(skb, FREE_READ);
	}

	/* Now if it has a half accepted/ closed socket. */
	if (sk->pair) 
	{
		sk->pair->dead = 1;
		sk->pair->prot->close(sk->pair, 0);
		sk->pair = NULL;
  	}

	/*
	 * Now if everything is gone we can free the socket
	 * structure, otherwise we need to keep it around until
	 * everything is gone.
	 */

	  if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0) 
	  {
		kfree_s((void *)sk,sizeof(*sk));
	  } 
	  else 
	  {
		/* this should never happen. */
		/* actually it can if an ack has just been sent. */
		sk->destroy = 1;
		sk->ack_backlog = 0;
		sk->inuse = 0;
		reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
  	}
}


struct sock *get_sock(struct proto *prot, unsigned short num,
				unsigned long raddr,
				unsigned short rnum, unsigned long laddr)
{
	struct sock *s;
	struct sock *result = NULL;
	int badness = -1;
	unsigned short hnum;

	hnum = ntohs(num);

	/*
	 * SOCK_ARRAY_SIZE must be a power of two.  This will work better
	 * than a prime unless 3 or more sockets end up using the same
	 * array entry.  This should not be a problem because most
	 * well known sockets don't overlap that much, and for
	 * the other ones, we can just be careful about picking our
	 * socket number when we choose an arbitrary one.
	 */

	for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
			s != NULL; s = s->next) 
	{
		int score = 0;

		if (s->num != hnum) 
			continue;

		if(s->dead && (s->state == TCP_CLOSE))
			continue;
		/* local address matches? */
		if (s->saddr) {
			if (s->saddr != laddr)
				continue;
			score++;
		}
		/* remote address matches? */
		if (s->daddr) {
			if (s->daddr != raddr)
				continue;
			score++;
		}
		/* remote port matches? */
		if (s->dummy_th.dest) {
			if (s->dummy_th.dest != rnum)
				continue;
			score++;
		}
		/* perfect match? */
		// 全匹配,直接返回
		if (score == 3)
			return s;
		/* no, check if this is the best so far.. */
		if (score <= badness)
			continue;
		// 记录最好的匹配项
		result = s;
		badness = score;
  	}
  	return result;
}

协议每次新建一个socket的时候就会在底层生成一个sock结构体,然后插入大到哈希链表中,收到数据时候根据ip和端口从哈希链表中找到对应的sock结构体。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值