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

在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,取决于具体的协议。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值