Linux核心跟蹤函數sys_listen的學習

來源:互聯網
上載者:User

asmlinkage long sys_socketcall(int call, unsigned long __user *args);

{
unsigned long a[6];
/* 從使用者空間得到資訊,該函數是SMP安全的 */
if (copy_from_user(a, args, nargs[call]))
return -EFAULT;

switch (call) {
case SYS_SOCKET:
err = sys_socket(a[0], a[1], a[2]);
break;
case SYS_BIND:
err = sys_bind(a[0], (struct sockaddr __user *)a[1], a[2]);
break;
case SYS_CONNECT:
err = sys_connect(a[0], (struct sockaddr __user *)a[1], a[2]);
break;

....
}
}

/*
* 下面跟蹤sys_listen函數
*
* 該函數首先通過調用sockfd_lookup_light函數,
* 根據描述符獲得擁有該描述符的struct file *file結構, 然後根據該file結構獲得struct socket *sock結構
* 從使用者空間得到fd和backlog
* 調用sock->ops->listen()函數, 該函數在tcp中是inet_listen[net/ipv4/af_inet.c]
* 如果是udp, 則sock->ops->listen = sock_no_listen,直接返回
*/

asmlinkage long sys_listen(int fd, int backlog)
{
struct socket *sock;
int err, fput_needed;

/*
* 尋找到具有該描述符的struct socket *sock結構
*/
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (sock) {
if ((unsigned)backlog > sysctl_somaxconn)
backlog = sysctl_somaxconn;
/*
* sock->ops = &inet_stream_ops || &inet_dgram_ops,
*
* TCP: sock->ops->listen = inet_listen
* UDP: sock->ops->listen = sock_no_listen
*/
err = sock->ops->listen(sock, backlog);

fput_light(sock->file, fput_needed);
}
return err;
}

/*
* inet_listen函數中,首先判斷該sock的狀態是否SS_UNCONNECTED 且類型 是否是SOCK_STREAM, 否的話直接退出
* 然後 判斷該sock->sk是否是已偵聽狀態, 如果是就直接設定backlog, 退出
* 否則調用 inet_csk_listen_start[net/ipv4/inet_connection_sock.c]
*/
int inet_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
unsigned char old_state;
int err;

lock_sock(sk);

err = -EINVAL;
if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)
goto out;

old_state = sk->sk_state;
if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN)))
goto out;

/* Really, if the socket is already in listen state
* we can only allow the backlog to be adjusted.
*/
if (old_state != TCP_LISTEN) {
err = inet_csk_listen_start(sk, backlog);
if (err)
goto out;
}
sk->sk_max_ack_backlog = backlog;
err = 0;

out:
release_sock(sk);
return err;
}

/*
* inet_csk_listen_start[net/ipv4/inet_connection_sock.c]
* 該函數首先調用reqsk_queue_alloc[net/core/request_sock.c]申請一塊記憶體, 存放偵聽 隊列 for accept;
* 然後設定偵聽狀態,並把該struct sock *sk放入tcp_hashinfo.ehash中
*/

int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
{
struct inet_sock *inet = inet_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
int rc = reqsk_queue_alloc(&icsk->icsk_accept_queue, nr_table_entries);

if (rc != 0)
return rc;

sk->sk_max_ack_backlog = 0;
sk->sk_ack_backlog = 0;
/*
* only memset
* memset(&inet_csk(sk)->icsk_ack, 0, sizeof(inet_csk(sk)->icsk_ack));
*/
inet_csk_delack_init(sk);

/*
* 設定偵聽狀態, 並且判斷該連接埠沒有被使用
* 然後 加入到tcp_hashinfo.ehash中
* return 0;
*/
sk->sk_state = TCP_LISTEN;
if (!sk->sk_prot->get_port(sk, inet->num)) {
inet->sport = htons(inet->num);

sk_dst_reset(sk);
sk->sk_prot->hash(sk);

return 0;
}

sk->sk_state = TCP_CLOSE;
__reqsk_queue_destroy(&icsk->icsk_accept_queue);
return -EADDRINUSE;
}

        Linux好學堂, www.linuxhao.com,Linux應用開發綜合性技術網站,提供Linux視頻教程,Linux培訓教程,Linux技術資料免費下載。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.