/*  * Default Socket Callbacks  */static void sock_def_wakeup(struct sock *sk){ struct socket_wq *wq; rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); if (wq_has_sleeper(wq)) wake_up_interruptible_all(&wq->wait); rcu_read_unlock();}void sock_init_data(struct socket *sock, struct sock *sk){ sk->sk_state_change = sock_def_wakeup;}分割线static void __inet_hash(struct sock *sk){ struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct inet_listen_hashbucket *ilb; if (sk->sk_state != TCP_LISTEN) { __inet_hash_nolisten(sk, NULL); return; } WARN_ON(!sk_unhashed(sk)); ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; spin_lock(&ilb->lock); __sk_nulls_add_node_rcu(sk, &ilb->head); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); spin_unlock(&ilb->lock);}void inet_hash(struct sock *sk){ if (sk->sk_state != TCP_CLOSE) { local_bh_disable(); __inet_hash(sk); local_bh_enable(); }}EXPORT_SYMBOL_GPL(inet_hash);struct proto tcp_prot = { .name = "TCP", .hash = inet_hash, .unhash = inet_unhash, .get_port = inet_csk_get_port, .h.hashinfo = &tcp_hashinfo, ......};EXPORT_SYMBOL(tcp_prot);------------------------------------------------------>分割线2/*  * Move a socket into listening state.  */int inet_listen(struct socket *sock, int backlog){err = inet_csk_listen_start(sk, backlog);}int inet_csk_listen_start(struct sock *sk, const int nr_table_entries){ /* There is race window here: we announce ourselves listening,   * but this transition is still not validated by get_port().   * It is OK, because this socket enters to hash table only   * after validation is complete.   */ sk->sk_state = TCP_LISTEN; if (!sk->sk_prot->get_port(sk, inet->inet_num)) { inet->inet_sport = htons(inet->inet_num); sk_dst_reset(sk); sk->sk_prot->hash(sk); return 0; }}    -----------------listen     /*  * This will accept the next outstanding connection.  */struct sock *inet_csk_accept(struct sock *sk, int flags, int *err){ /* Find already established connection */ if (reqsk_queue_empty(queue)) { long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); /* If this is a non blocking socket don't sleep */ error = -EAGAIN; if (!timeo) goto out_err; error = inet_csk_wait_for_connect(sk, timeo); if (error) goto out_err; }/*  * Wait for an incoming connection, avoid race conditions. This must be called  * with the socket locked.  */static int inet_csk_wait_for_connect(struct sock *sk, long timeo){ struct inet_connection_sock *icsk = inet_csk(sk); DEFINE_WAIT(wait); int err; /*   * True wake-one mechanism for incoming connections: only   * one process gets woken up, not the 'whole herd'.   * Since we do not 'race & poll' for established sockets   * anymore, the common case will execute the loop only once.   *   * Subtle issue: "add_wait_queue_exclusive()" will be added   * after any current non-exclusive waiters, and we know that   * it will always _stay_ after any new non-exclusive waiters   * because all non-exclusive waiters are added at the   * beginning of the wait-queue. As such, it's ok to "drop"   * our exclusiveness temporarily when we get woken up without   * having to remove and re-insert us on the wait queue.   */ for (;;) { prepare_to_wait_exclusive(sk_sleep(sk), &wait,   TASK_INTERRUPTIBLE); release_sock(sk); if (reqsk_queue_empty(&icsk->icsk_accept_queue)) timeo = schedule_timeout(timeo); lock_sock(sk); err = 0; if (!reqsk_queue_empty(&icsk->icsk_accept_queue)) break; err = -EINVAL; if (sk->sk_state != TCP_LISTEN) break; err = sock_intr_errno(timeo); if (signal_pending(current)) break; err = -EAGAIN; if (!timeo) break; } finish_wait(sk_sleep(sk), &wait); return err;}    -----------------accept/*  * From tcp_input.c  */int tcp_v4_rcv(struct sk_buff *skb){ struct sock *sk; sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); if (!sk) goto no_tcp_socket;......no_tcp_socket: if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard_it; if (skb->len doffcsum_error: TCP_INC_STATS_BH(net, TCP_MIB_CSUMERRORS);bad_packet: TCP_INC_STATS_BH(net, TCP_MIB_INERRS); } else { tcp_v4_send_reset(NULL, skb); }discard_it: /* Discard frame. */ kfree_skb(skb); return 0;}    -----------------recv------------------------------------------------------>分割线3Study总结:1.bind:绑定IP address和port num2.listen:通过sk->sk_prot->hash(sk)把绑定的IP address和port num加入tcp_hashinfo中3.accept:等待接入,休眠自己4.rcv(TCP rcv):struct sock *sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest),通过全局变量tcp_hashinfo,找到对应的sock对象,然后再进行其对应的其他操作5.(1)struct task_struct空间/全局变量tcp_hashinfo  (2)fd/file/socket (3)tcp_hashinfo/sock    (4)socket/sock6.TCP/IP的操作 socket套接字 进程空间问题:1.唤醒accept休眠的地方
11-06 06:22
查看更多