socket系统调用

 1 SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
 2 {
 3     int retval;
 4     struct socket *sock;
 5     int flags;
 6
 7     /* Check the SOCK_* constants for consistency.  */
 8     BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);
 9     BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);
10     BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);
11     BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);
12
13     /* 取得标志 */
14     flags = type & ~SOCK_TYPE_MASK;
15
16     /* 除此标记之外还有标记,错误 */
17     if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
18         return -EINVAL;
19
20     /* 取得类型 */
21     type &= SOCK_TYPE_MASK;
22
23
24     /* 标记以O_NONBLOCK为准 */
25     if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
26         flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
27
28     /* 创建socket */
29     retval = sock_create(family, type, protocol, &sock);
30     if (retval < 0)
31         goto out;
32
33     /* 创建socket文件并绑定描述符 */
34     retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
35     if (retval < 0)
36         goto out_release;
37
38 out:
39     /* It may be already another descriptor 8) Not kernel problem. */
40     return retval;
41
42 out_release:
43     sock_release(sock);
44     return retval;
45 }
 1 /* 套接口与文件描述符绑定 */
 2 static int sock_map_fd(struct socket *sock, int flags)
 3 {
 4     struct file *newfile;
 5     /* 获取未使用的文件描述符 */
 6     int fd = get_unused_fd_flags(flags);
 7     if (unlikely(fd < 0))
 8         return fd;
 9
10     /* 分配socket文件 */
11     newfile = sock_alloc_file(sock, flags, NULL);
12     if (likely(!IS_ERR(newfile))) {
13         /* fd和文件进行绑定 */
14         fd_install(fd, newfile);
15         return fd;
16     }
17
18     /* 释放fd */
19     put_unused_fd(fd);
20     return PTR_ERR(newfile);
21 }
1 int sock_create(int family, int type, int protocol, struct socket **res)
2 {
3     return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
4 }
  1 /* 创建socket */
  2 int __sock_create(struct net *net, int family, int type, int protocol,
  3              struct socket **res, int kern)
  4 {
  5     int err;
  6     struct socket *sock;
  7     const struct net_proto_family *pf;
  8
  9     /*
 10      *      Check protocol is in range
 11      */
 12     /* 检查协议族 */
 13     if (family < 0 || family >= NPROTO)
 14         return -EAFNOSUPPORT;
 15
 16     /* 检查类型 */
 17     if (type < 0 || type >= SOCK_MAX)
 18         return -EINVAL;
 19
 20     /* Compatibility.
 21
 22        This uglymoron is moved from INET layer to here to avoid
 23        deadlock in module load.
 24      */
 25     /* ipv4协议族的packet已经废除,检测到,则替换成packet协议族 */
 26     if (family == PF_INET && type == SOCK_PACKET) {
 27         pr_info_once("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
 28                  current->comm);
 29         family = PF_PACKET;
 30     }
 31
 32     /* 安全模块检查套接口 */
 33     err = security_socket_create(family, type, protocol, kern);
 34     if (err)
 35         return err;
 36
 37     /*
 38      *    Allocate the socket and allow the family to set things up. if
 39      *    the protocol is 0, the family is instructed to select an appropriate
 40      *    default.
 41      */
 42     /* 分配socket,内部和inode已经绑定 */
 43     sock = sock_alloc();
 44     if (!sock) {
 45         net_warn_ratelimited("socket: no more sockets\n");
 46         return -ENFILE;    /* Not exactly a match, but its the
 47                    closest posix thing */
 48     }
 49
 50     /* 设定类型 */
 51     sock->type = type;
 52
 53 #ifdef CONFIG_MODULES
 54     /* Attempt to load a protocol module if the find failed.
 55      *
 56      * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
 57      * requested real, full-featured networking support upon configuration.
 58      * Otherwise module support will break!
 59      */
 60     if (rcu_access_pointer(net_families[family]) == NULL)
 61         request_module("net-pf-%d", family);
 62 #endif
 63
 64     rcu_read_lock();
 65     /* 找到协议族 */
 66     pf = rcu_dereference(net_families[family]);
 67     err = -EAFNOSUPPORT;
 68     if (!pf)
 69         goto out_release;
 70
 71     /*
 72      * We will call the ->create function, that possibly is in a loadable
 73      * module, so we have to bump that loadable module refcnt first.
 74      */
 75      /* 增加模块的引用计数 */
 76     if (!try_module_get(pf->owner))
 77         goto out_release;
 78
 79     /* Now protected by module ref count */
 80     rcu_read_unlock();
 81
 82     /* 调用协议族的创建函数 */
 83     err = pf->create(net, sock, protocol, kern);
 84     if (err < 0)
 85         goto out_module_put;
 86
 87     /*
 88      * Now to bump the refcnt of the [loadable] module that owns this
 89      * socket at sock_release time we decrement its refcnt.
 90      */
 91     if (!try_module_get(sock->ops->owner))
 92         goto out_module_busy;
 93
 94     /*
 95      * Now that we‘re done with the ->create function, the [loadable]
 96      * module can have its refcnt decremented
 97      */
 98     module_put(pf->owner);
 99     err = security_socket_post_create(sock, family, type, protocol, kern);
100     if (err)
101         goto out_sock_release;
102     *res = sock;
103
104     return 0;
105
106 out_module_busy:
107     err = -EAFNOSUPPORT;
108 out_module_put:
109     sock->ops = NULL;
110     module_put(pf->owner);
111 out_sock_release:
112     sock_release(sock);
113     return err;
114
115 out_release:
116     rcu_read_unlock();
117     goto out_sock_release;
118 }
119 EXPORT_SYMBOL(__sock_create);

上述红色create代码处,如PF_INET协议族,实际是调用下面结构中的inet_create

1 static const struct net_proto_family inet_family_ops = {
2     .family = PF_INET,
3     .create = inet_create,
4     .owner    = THIS_MODULE,
5 };
  1 /*
  2  *    Create an inet socket.
  3  */
  4
  5 /* 创建与该接口对应的传输控制块并关联 */
  6 static int inet_create(struct net *net, struct socket *sock, int protocol,
  7                int kern)
  8 {
  9     struct sock *sk;
 10     struct inet_protosw *answer;
 11     struct inet_sock *inet;
 12     struct proto *answer_prot;
 13     unsigned char answer_flags;
 14     int try_loading_module = 0;
 15     int err;
 16
 17     /* 检查协议 */
 18     if (protocol < 0 || protocol >= IPPROTO_MAX)
 19         return -EINVAL;
 20
 21     /* 设置接口的状态为未连接 */
 22     sock->state = SS_UNCONNECTED;
 23
 24     /* Look for the requested type/protocol pair. */
 25 lookup_protocol:
 26     err = -ESOCKTNOSUPPORT;
 27     rcu_read_lock();
 28     list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {
 29
 30         err = 0;
 31         /* Check the non-wild match. */
 32         /* 匹配协议成功 */
 33         if (protocol == answer->protocol) {
 34             /* 传入为某指定协议,成功*/
 35             if (protocol != IPPROTO_IP)
 36                 break;
 37
 38             /* 未指定协议,继续查找 */
 39
 40         }
 41         /* 未指定协议或者未匹配成功的分支 */
 42         else {
 43             /* Check for the two wild cases. */
 44             /* 如果传入为未指定协议 */
 45             if (IPPROTO_IP == protocol) {
 46                 /* 则指定为当前协议,成功 */
 47                 protocol = answer->protocol;
 48                 break;
 49             }
 50
 51             /* 指定了传入协议,但是均未匹配成功 */
 52
 53             /* 当前正在匹配的协议通用协议,则使用之 */
 54             if (IPPROTO_IP == answer->protocol)
 55                 break;
 56         }
 57
 58         /* 循环查找结束了,还未找到 */
 59         /* 传入了某指定协议,未找到匹配,并且没有通用协议 */
 60         err = -EPROTONOSUPPORT;
 61     }
 62
 63     /*
 64         未找到对应inet_protosw实例
 65         加载对应的协议模块,重新查找
 66     */
 67     if (unlikely(err)) {
 68         /* 尝试加载的模块不超过2次 */
 69         if (try_loading_module < 2) {
 70             rcu_read_unlock();
 71             /*
 72              * Be more specific, e.g. net-pf-2-proto-132-type-1
 73              * (net-pf-PF_INET-proto-IPPROTO_SCTP-type-SOCK_STREAM)
 74              */
 75             /* 第一次,加载指定协议和类型的模块 */
 76             if (++try_loading_module == 1)
 77                 request_module("net-pf-%d-proto-%d-type-%d",
 78                            PF_INET, protocol, sock->type);
 79             /*
 80              * Fall back to generic, e.g. net-pf-2-proto-132
 81              * (net-pf-PF_INET-proto-IPPROTO_SCTP)
 82              */
 83             /* 第二次,加载只指定协议的模块 */
 84             else
 85                 request_module("net-pf-%d-proto-%d",
 86                            PF_INET, protocol);
 87             goto lookup_protocol;
 88         }
 89         /* 超过2次,则查找失败 */
 90         else
 91             goto out_rcu_unlock;
 92     }
 93
 94     err = -EPERM;
 95
 96     /* 判断是否允许创建sock-raw套接口 */
 97     if (sock->type == SOCK_RAW && !kern &&
 98         !ns_capable(net->user_ns, CAP_NET_RAW))
 99         goto out_rcu_unlock;
100
101     /* 设置套接口操作 */
102     sock->ops = answer->ops;
103     /* 临时存储协议的操作和标志 */
104     answer_prot = answer->prot;
105     answer_flags = answer->flags;
106     rcu_read_unlock();
107
108     WARN_ON(!answer_prot->slab);
109
110     err = -ENOBUFS;
111     /* 分配传输控制块 */
112     sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern);
113     if (!sk)
114         goto out;
115
116     err = 0;
117     /* 设置重用地址和端口标记 */
118     if (INET_PROTOSW_REUSE & answer_flags)
119         sk->sk_reuse = SK_CAN_REUSE;
120
121     inet = inet_sk(sk);
122
123     /* 设置是否为面向连接的控制块 */
124     inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
125
126     inet->nodefrag = 0;
127
128     /* 如果类型是原始套接字 */
129     if (SOCK_RAW == sock->type) {
130         /* 设置本地端口为协议号 */
131         inet->inet_num = protocol;
132
133         /* 协议为ipproto_raw */
134         if (IPPROTO_RAW == protocol)
135             /* 标记需要自己构建ip首部 */
136             inet->hdrincl = 1;
137     }
138
139     /* 设置是否支持pmtu */
140     if (net->ipv4.sysctl_ip_no_pmtu_disc)
141         inet->pmtudisc = IP_PMTUDISC_DONT;
142     else
143         inet->pmtudisc = IP_PMTUDISC_WANT;
144
145     /* 出事连接控制块 */
146     inet->inet_id = 0;
147
148     /* 连接控制块的初始化 */
149     sock_init_data(sock, sk);
150
151     sk->sk_destruct       = inet_sock_destruct;
152     sk->sk_protocol       = protocol;
153     sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
154
155     inet->uc_ttl    = -1;
156     inet->mc_loop    = 1;
157     inet->mc_ttl    = 1;
158     inet->mc_all    = 1;
159     inet->mc_index    = 0;
160     inet->mc_list    = NULL;
161     inet->rcv_tos    = 0;
162
163     sk_refcnt_debug_inc(sk);
164
165     /* 设置了本地端口 */
166     if (inet->inet_num) {
167         /* It assumes that any protocol which allows
168          * the user to assign a number at socket
169          * creation time automatically
170          * shares.
171          */
172
173         /* 设置网络序的源端口 */
174         inet->inet_sport = htons(inet->inet_num);
175         /* Add to protocol hash chains. */
176         /* 加入到hash */
177         err = sk->sk_prot->hash(sk);
178         if (err) {
179             sk_common_release(sk);
180             goto out;
181         }
182     }
183
184     /* 如果有init则调用init初始化 */
185     if (sk->sk_prot->init) {
186         err = sk->sk_prot->init(sk);
187         if (err) {
188             sk_common_release(sk);
189             goto out;
190         }
191     }
192
193     if (!kern) {
194         err = BPF_CGROUP_RUN_PROG_INET_SOCK(sk);
195         if (err) {
196             sk_common_release(sk);
197             goto out;
198         }
199     }
200 out:
201     return err;
202 out_rcu_unlock:
203     rcu_read_unlock();
204     goto out;
205 }
时间: 2024-10-31 14:02:31

socket系统调用的相关文章

linux:socket 系统调用在linux内核中的实现流程图

socket 系统调用在linux内核中的实现:

Pin截获socket系统调用初步分析

Pin截获socket系统调用初步分析 根据为知笔记中上传的Pin tool for tracing system calls,修改代码过滤出socket相关的系统调用,并进行初步的分析.主要有2点: - 过滤socket相关的系统调用 - 分析得到的系统调用参数 过滤socket相关的系统调用 socket编程中与访问网络相关的主要关注socket().accept().然后在PinTool中过滤出这两个系统调用,对他们的参数进行初步的分析.下面先看一下这两个函数: int socket(in

socket系统调用深度分析

1.系统调用过程 1.1用户态和内核态以及系统调用机制 1.进程的地址空间 linux进程有4GB地址空间,如图所示: 3G-4G大部分是共享的,是内核态的地址空间.这里存放整个内核的代码和所有的内核模块以及内核所维护的数据. 2.特权级别 对于任何操作系统来说,创建一个进程是核心功能.创建进程要做很多工作,会消耗很多物理资源.比如分配物理内存,父子进程拷贝信息,拷贝设置页目录页表等等,这些工作得由特定的进程去做,所以就有了特权级别的概念.最关键的工作必须交给特权级最高的进程去执行,这样可以做到

【Socket系统调用】Socket与系统调用深度分析

Socket与系统调用深度分析 系统调用 在一开始,应用程序是可以直接控制硬件的,这就需要程序员有很高的编程能力,否则一旦程序出了问题,会将整个系统Crash. 在现在的操作系统中,用户程序运行在用户态,而要进行诸如Socket.磁盘I/O这样的一些操作,这需要切换到内核态,再进行进行相应的操作,而这一过程则是系统调用system call.有了操作系统分离了内核和用户态,应用程序就无法直接进行硬件资源的访问,需要经过系统调用来进行. 每次的系统调用,都会从用户态转换到内核态,运行完任务后,回到

linux socket编程系统调用栈

目录 一.网络协议参考模型简介 二.SOCKET概述 三.SOCKET基本数据结构 1.TCP通信编程 2.服务器端实例代码 3.客户端实例代码 4.头文件socketwrapper.h 5.程序实现功能 6.探究socket系统调用 @(linux socket编程实现原理) 一.网络协议参考模型简介 国际标准组织(ISO)制定了OSI模型.这个模型把网络通信的工作分为7层,从上至下为应用层.表示层.会话层. 传输层.网络层.数据链路层.物理层. 而TCP/IP协议将OSI的7层模型简化为4层

Socket与系统调用深度分析

Socket与系统调用深度分析 可以想象的是,当应用程序调用socket()接口,请求操作系统提供服务时,必然会系统调用,内核根据发起系统调用时传递的系统调用号,判断要执行的程序,若为socket对应的编号,则执行socket对应的中断服务程序.服务程序内部,又根据你要请求的不同服务,来执行不同服务对应的处理程序.当处理结束,执行返回,从中断服务程序到发起中断的int 0x80,再到用户态我们执行的用户程序,层层返回,socket()也就执行完毕了. 本次,我们关心三个问题: 1.应用程序如何如

Socket与系统调用深度分析 ——X86 64环境下Linux5.0以上的内核中

1.Socket与系统调用——概述 Socket API编程接口之上可以编写基于不同网络协议的应用程序: Socket接口在用户态通过系统调用机制进入内核: 内核中将系统调用作为一个特殊的中断来处理,以socket相关系统调用为例进行分析: socket相关系统调用的内核处理函数内部通过“多态机制”对不同的网络协议进行的封装方法: 下面会将Socket API编程接口.系统调用机制及内核中系统调用相关源代码. socket相关系统调用的内核处理函数结合起来分析,并在X86 64环境下Linux5

linux下socket编程-进程间通信

一.什么是Socket Socket接口是TCP/IP网络通信的API,Socket接口定义了许多函数或例程,可以用它们来开发TCP/IP网络上的应用程序. Socket类型有两种:流式Socket (SOCK_STREAM)和数据报式Socket(SOCK_DGRAM).流式是一种面向连接针对于面向连接的TCP服务应用:数据报式Socket是一种无连接针对无连接的UDP服务应用.sock通信的基本过程如下: 二.Socket建立 程序可以调用Socket函数建立socket,该函数返回一个类似

socket相关函数

socket() 我们使用系统调用socket()来获得文件描述符:#include<sys/types.h>#include<sys/socket.h>int socket(int domain,int type,int protocol);第一个参数domain设置为"AF_INET".第二个参数是套接口的类型:SOCK_STREAM或SOCK_DGRAM.第三个参数设置为0.系统调用socket()只返回一个套接口描述符,如果出错,则返回-1 setsoc