Socket与系统调用深度分析
Posted gfsh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Socket与系统调用深度分析相关的知识,希望对你有一定的参考价值。
废话不多说,直接动手实战。
本次实验追踪有关Socket的系统调用中非常重要的两个bind()和listen(),步骤如下:
1.修改menu中的Makefile文件。
我的主目录为MenuOS,该目录下的文件如下:
cd ~/MenuOS/menu #进入menu文件夹
sudo su # 切换至root用户以修改Makefile文件
gedit Makefile
接着做如下红框中的修改:
接着,仍然在menu文件夹下,执行
make rootfs
此时切不可关闭该终端和QEMU,打开另一个终端,输入如下命令:
gdb file ~/MenuOS/linux-5.0.1/vmlinux target remote:1234 break __sys_bind break __sys_listen
此时,gdb已经给__sys_bind和__sys_listen两个Socket系统调用设定了断点,gdb响应如下:
说明gdb已找到这两条系统调用的函数定义所在。
然后开始对MenuOS的运行:
c #在gdb终端输入,接下来两条命令在QEMU中输入
replyhi
hello
当我们在qemu中输入replyhi时,gdb终端显示停在了bind函数。
我们可以利用list命令来查看bind的源代码,但是list查看行数默认有限,所以:
set listsize 60 #设置一次list可查看60行代码 list #查看bind函数源代码
/* * Bind a name to a socket. Nothing much to do here since it‘s * the protocol‘s responsibility to handle the local address. * * We move the socket address to kernel space before we call * the protocol layer (having also checked the address is ok). */ /* *上面一段话的大概意思是,bind()系统调用仅负责将进程的名字与socket绑定; *此外,bind()也负责将该socket转入内核处理; *至于处理本地地址,这是网络协议所需要做的事情。 */ int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) { struct socket *sock; struct sockaddr_storage address; int err, fput_needed; /* *以fd为索引从当前进程的文件描述符表中,找到对应的file实例, *然后从file实例的private_data中,获取socket实例 */ sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { /* * 将用户空间的地址拷贝到内核空间的缓冲区中 */ err = move_addr_to_kernel(umyaddr, addrlen, &address); if (!err) { /* * SELinux相关,不需要关心。 */ err = security_socket_bind(sock, (struct sockaddr *)&address, addrlen); /* * 如果是TCP套接字,sock->ops指向的是inet_stream_ops, * sock->ops是在inet_create()函数中初始化,所以bind接口 * 调用的是inet_bind()函数。 */ if (!err) err = sock->ops->bind(sock, (struct sockaddr *) &address, addrlen); } fput_light(sock->file, fput_needed); } return err; } SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) { return __sys_bind(fd, umyaddr, addrlen); }
接着在gdb终端下按c,程序继续执行,然后停在了listen函数。
同样的list一下,
/* * Perform a listen. Basically, we allow the protocol to do anything * necessary for a listen, and if that works, we mark the socket as * ready for listening. */ /* *上述解释的大致含义是,该系统调用的作用是将端口置为监听状态; *具体操作视协议而定 */ int __sys_listen(int fd, int backlog) { struct socket *sock; int err, fput_needed; int somaxconn; sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { /* * sysctl_somaxconn存储的是服务器监听时,允许每个套接字连接队列长度 * 的最大值,默认值是128 */ somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; /* * 如果指定的最大连接数超过系统限制,则使用系统当前允许的连接队列 * 中连接的最大数。 */ if ((unsigned int)backlog > somaxconn) backlog = somaxconn; err = security_socket_listen(sock, backlog); if (!err) /* * 从这里开始,socket以后所用的函数将根据TCP/UDP而视协议而定 */ err = sock->ops->listen(sock, backlog); fput_light(sock->file, fput_needed); } return err; } SYSCALL_DEFINE2(listen, int, fd, int, backlog) { return __sys_listen(fd, backlog); }
以上是关于Socket与系统调用深度分析的主要内容,如果未能解决你的问题,请参考以下文章