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,取決於具體的協議。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章