首页 > 其他 > 详细

Socket与系统调用深度分析

时间:2019-12-19 19:49:58      阅读:88      评论:0      收藏:0      [点我收藏+]

Socket与系统调用深度分析

1.linux系统调用

     本次实验的主要内容是从socket接口入手,通过跟踪相关函数在内核中的运行过程了解socket相关的系统调用是如何工作的。操作系统分为用户态和内核态,应用程序一般工作在用户态,而操作系统则通过系统调用为工作在其上的进程提供服务。系统调用是操作系统提供给用户程序访问内核的桥梁,通过系统调用,运行于用户态的用户程序能够调用到运行于内核态的系统内核提供的功能。系统调用一般是由软中断实现的,在Linux上该功能是由中断号为0x80的系统调用处理程序system_call提供。下面以Linux socket API为例,探究Linux中系统调用是如何进行的。

网络相关的主要的系统调用

 1 系统调用号 函数名  系统调用           所在文件
 2 41    socket    sys_socket    net/socket.c
 3 42    connect    sys_connect    net/socket.c
 4 43    accept    sys_accept    net/socket.c
 5 44    sendto    sys_sendto    net/socket.c
 6 45    recvfrom    sys_recvfrom    net/socket.c
 7 46    sendmsg    sys_sendmsg    net/socket.c
 8 47    recvmsg    sys_recvmsg    net/socket.c
 9 48    shutdown    sys_shutdown    net/socket.c
10 49    bind    sys_bind    net/socket.c
11 50    listen    sys_listen    net/socket.c
12 51    getsockname    sys_getsockname    net/socket.c
13 52    getpeername    sys_getpeername    net/socket.c
14 53    socketpair    sys_socketpair    net/socket.c
15 54    setsockopt    sys_setsockopt    net/socket.c
16 55    getsockopt    sys_getsockopt    net/socket.c

2.跟踪socketcall系统调用

     lab3中的main.c文件

    MenuConfig("replyhi", "Reply hi TCP Service", StartReplyhi);
    MenuConfig("hello", "Hello TCP Client", Hello);

     syswrapper.h中代码

 
#include<arpa/inet.h> /* internet socket */

/**/

#define PrepareSocket(addr,port) int sockfd = -1; struct sockaddr_in serveraddr; struct sockaddr_in clientaddr; socklen_t addr_len = sizeof(struct sockaddr); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(port); serveraddr.sin_addr.s_addr = inet_addr(addr); memset(&serveraddr.sin_zero, 0, 8); sockfd = socket(PF_INET,SOCK_STREAM,0); #define InitServer() int ret = bind( sockfd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr)); if(ret == -1) { fprintf(stderr,"Bind Error,%s:%d\n", __FILE__,__LINE__); close(sockfd); return -1; } listen(sockfd,MAX_CONNECT_QUEUE);

/**/
#define InitializeService()                             \
        PrepareSocket(IP_ADDR,PORT);                    \
        InitServer();
 

  socket(),listen(),bind()以及close()等函数

 

#启动qemu 加载内核,不加-S,因为跟踪的系统调用,不是启动过程
qemu -kernel ../linux-5.4.2/arch/x86/boot/bzImage -initrd ../rootfs.img -append  nokaslr -s 
#打开一个新的终端
gdb
file ~/linux-5.4.2/vmlinux
b sys_socketcall   
target remote:1234
c
#在qume中输入
replyhi

 技术分享图片

技术分享图片

     在sys_socketcall打了断点后,运行我们的replyhi程序,即在断点处停止了,我们查看其函数调用栈,发现其进入系统调用的顺序是 entry_SYSENTER_32() ---> do_syscall_32_irqs_on()---->sys_socketcall()。内核中为 socket 设置的总入口为 sys_socketcall(),其代码在 net/socket.c 中,而该函数实际上则调用的是SYSCALL_DEFINE2

 1 /*与socket相关的系统调用总入口。 */
 2 /*
 3 *函数的第一个参数 call 即为具体的操作码,而参数 args 为指向一个数组的指针,可以根据具体操作码的不同,确定从用户空间复制参数的数量;
 4 */
 5 asmlinkage long sys_socketcall(int call, unsigned long __user *args)
 6 {
 7     unsigned long a[6];
 8     unsigned long a0,a1;
 9     int err;
10 
11     if(call<1||call>SYS_RECVMSG)
12         return -EINVAL;
13 
14     /* copy_from_user should be SMP safe. */
15     if (copy_from_user(a, args, nargs[call]))
16         return -EFAULT;
17 
18     a0=a[0];
19     a1=a[1];
20 
21     switch(call) 
22     {
23         case SYS_SOCKET:
24             err = sys_socket(a0,a1,a[2]);
25             break;
26         case SYS_BIND:
27             err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]);
28             break;
29         case SYS_CONNECT:
30             err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
31             break;
32         case SYS_LISTEN:
33             err = sys_listen(a0,a1);
34             break;
35         case SYS_ACCEPT:
36             err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
37             break;
38         case SYS_GETSOCKNAME:
39             err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
40             break;
41         case SYS_GETPEERNAME:
42             err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]);
43             break;
44         case SYS_SOCKETPAIR:
45             err = sys_socketpair(a0,a1, a[2], (int __user *)a[3]);
46             break;
47         case SYS_SEND:
48             err = sys_send(a0, (void __user *)a1, a[2], a[3]);
49             break;
50         case SYS_SENDTO:
51             err = sys_sendto(a0,(void __user *)a1, a[2], a[3],
52                      (struct sockaddr __user *)a[4], a[5]);
53             break;
54         case SYS_RECV:
55             err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
56             break;
57         case SYS_RECVFROM:
58             err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
59                        (struct sockaddr __user *)a[4], (int __user *)a[5]);
60             break;
61         case SYS_SHUTDOWN:
62             err = sys_shutdown(a0,a1);
63             break;
64         case SYS_SETSOCKOPT:
65             err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);
66             break;
67         case SYS_GETSOCKOPT:
68             err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]);
69             break;
70         case SYS_SENDMSG:
71             err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]);
72             break;
73         case SYS_RECVMSG:
74             err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]);
75             break;
76         default:
77             err = -EINVAL;
78             break;
79     }
80     return err;
 

      涉及到socket的系统调用都使用统一的入口sys_socketcall,再通过SYSCALL_DEFINE2进入不同的分支,调用不同的系统调用,如在本次实验中,就包括sys_socket,sys_bind,sys_listen,sys_connect,sys_accept4等等。

Socket与系统调用深度分析

原文:https://www.cnblogs.com/yongjason/p/12069682.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!