Linux源代码解析之——传输控制块诞生

本文原创为freas_1990,转载请标明出处:http://blog.csdn.net/freas_1990/article/details/23795587


在Linux 2.6以前(不包括2.6,具体版本没仔细调查),还没有使用传输控制块的概念,各种协议的状态管理还出于比较混乱的状态。

Linux 2.6以后,传输控制块机制使代码看起来比较规整了。

创建传输控制块:

/*
 *	Create an inet socket.
 */

static int inet_create(struct socket *sock, int protocol)
{
	struct sock *sk;
	struct list_head *p;
	struct inet_protosw *answer;
	struct inet_opt *inet;
	int err = -ENOBUFS;

	sock->state = SS_UNCONNECTED;
	sk = sk_alloc(PF_INET, GFP_KERNEL, inet_sk_size(protocol),
		      inet_sk_slab(protocol));
	if (!sk)
		goto out;

	/* Look for the requested type/protocol pair. */
	answer = NULL;
	rcu_read_lock();
	list_for_each_rcu(p, &inetsw[sock->type]) {
		answer = list_entry(p, struct inet_protosw, list);

		/* Check the non-wild match. */
		if (protocol == answer->protocol) {
			if (protocol != IPPROTO_IP)
				break;
		} else {
			/* Check for the two wild cases. */
			if (IPPROTO_IP == protocol) {
				protocol = answer->protocol;
				break;
			}
			if (IPPROTO_IP == answer->protocol)
				break;
		}
		answer = NULL;
	}

	err = -ESOCKTNOSUPPORT;
	if (!answer)
		goto out_sk_free;
	err = -EPERM;
	if (answer->capability > 0 && !capable(answer->capability))
		goto out_sk_free;
	err = -EPROTONOSUPPORT;
	if (!protocol)
		goto out_sk_free;
	err = 0;
	sock->ops = answer->ops;
	sk->sk_prot = answer->prot;
	sk->sk_no_check = answer->no_check;
	if (INET_PROTOSW_REUSE & answer->flags)
		sk->sk_reuse = 1;
	rcu_read_unlock();

	inet = inet_sk(sk);

	if (SOCK_RAW == sock->type) {
		inet->num = protocol;
		if (IPPROTO_RAW == protocol)
			inet->hdrincl = 1;
	}

	if (ipv4_config.no_pmtu_disc)
		inet->pmtudisc = IP_PMTUDISC_DONT;
	else
		inet->pmtudisc = IP_PMTUDISC_WANT;

	inet->id = 0;

	sock_init_data(sock, sk);
	sk_set_owner(sk, THIS_MODULE);

	sk->sk_destruct	   = inet_sock_destruct;
	sk->sk_zapped	   = 0;
	sk->sk_family	   = PF_INET;
	sk->sk_protocol	   = protocol;
	sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;

	inet->uc_ttl	= -1;
	inet->mc_loop	= 1;
	inet->mc_ttl	= 1;
	inet->mc_index	= 0;
	inet->mc_list	= NULL;

#ifdef INET_REFCNT_DEBUG
	atomic_inc(&inet_sock_nr);
#endif

	if (inet->num) {
		/* It assumes that any protocol which allows
		 * the user to assign a number at socket
		 * creation time automatically
		 * shares.
		 */
		inet->sport = htons(inet->num);
		/* Add to protocol hash chains. */
		sk->sk_prot->hash(sk);
	}

	if (sk->sk_prot->init) {
		err = sk->sk_prot->init(sk);
		if (err)
			inet_sock_release(sk);
	}
out:
	return err;
out_sk_free:
	rcu_read_unlock();
	sk_free(sk);
	goto out;
}

这里的sk_alloc是重点:

sk = sk_alloc(PF_INET, GFP_KERNEL, inet_sk_size(protocol),
		      inet_sk_slab(protocol));

inet_sk_size定义如下:

static __inline__ int inet_sk_size(int protocol)
{
	int rc = sizeof(struct tcp_sock);

	if (protocol == IPPROTO_UDP)
		rc = sizeof(struct udp_sock);
	else if (protocol == IPPROTO_RAW)
		rc = sizeof(struct raw_sock);
	return rc;
}

它会根据具体的传输层协议定义返回相应的传输控制块的大小。

在socket里,sock指针只是一个“泛型”,它可能指向struct sock,struct tcp_sock,struct udp_sock,取决于具体的协议。

Linux源代码解析之——传输控制块诞生,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。