新闻  |   论坛  |   博客  |   在线研讨会
Linux内核跟踪函数sys_listen的学习
hikesoso2010 | 2011-04-30 20:23:43    阅读:2111   发布文章

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技术资料免费下载。

if ($ != jQuery) { $ = jQuery.noConflict(); } var isLogined = true; var cb_blogId = 79468; var cb_entryId = 2033542; var cb_blogApp = "Javalove"; var cb_blogUserGuid = "84f12d22-cef6-df11-ac81-842b2b196315"; var cb_entryCreatedDate = '2011/4/30 20:09:00';

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
嵌入式系统,Linux,WinCE,单片机,ARM,DSP,EDA,FPGA,CPLD,PLC,数电,模电,PCB,硬件设计,软件编程,应用电子技术,视频教程、培训视频、教程资料、学习教程,海量资源下载中心, 海科资源
推荐文章
最近访客