Chinaunix首页 | 论坛 | 博客
  • 博客访问: 417019
  • 博文数量: 124
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 872
  • 用 户 组: 普通用户
  • 注册时间: 2018-03-29 14:38
个人简介

默默的一块石头

文章分类

全部博文(124)

文章存档

2022年(26)

2021年(10)

2020年(28)

2019年(60)

我的朋友

分类: LINUX

2020-06-11 10:59:42

/*
 * 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 < (th->doff << 2) || tcp_checksum_complete(skb)) {
csum_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
<-------------------------------------------------------------------------------->分割线3
Study总结:
1.bind:绑定IP address和port num
2.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/sock
6.TCP/IP的操作 socket套接字 进程空间
问题:
1.唤醒accept休眠的地方
阅读(1493) | 评论(0) | 转发(0) |
0

上一篇:Linux 信号机制

下一篇:tcp_output

给主人留下些什么吧!~~