技术标签: linux socket bind 内核详解
socket系列文章都是承接第一篇socket创建,因此这里的编号和内核版本都继承了第一篇文章。
2. SYSCALL_DEFINE3函数
Bind系统调用通过SYSCALL_DEFINE3调用各个协议不同的bind函数,
SYSCALL_DEFINE3(bind,
int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
{
struct
socket *sock;
struct
sockaddr_storage address;
int
err, fput_needed;
/*根据文件描述符fd,查找到对应的套接字socket*/
sock
= sockfd_lookup_light(fd, &err, &fput_needed);
if
(sock) {
err
= move_addr_to_kernel(umyaddr, addrlen, &address);
if
(err >= 0) {
err
= security_socket_bind(sock,
(struct sockaddr *)&address,
addrlen);
if
(!err)
err = sock->ops->bind(sock,
(struct sockaddr *)
&address, addrlen);
}
fput_light(sock->file,
fput_needed);
}
return
err;
}
(1)sock->ops->bind在创建TCP类型的socket时,进行了下面的赋值初始化操作,这里的bind定位为inet_bind()函数。
onst struct proto_ops inet_stream_ops = {
.family
= PF_INET,
.owner
= THIS_MODULE,
.release =
inet_release,
.bind = inet_bind,
.connect =
inet_stream_connect,
.socketpair
= sock_no_socketpair,
.accept
= inet_accept,
.getname
= inet_getname,
.poll
= tcp_poll,
.ioctl = inet_ioctl,
.listen = inet_listen,
.shutdown
= inet_shutdown,
.setsockopt =
sock_common_setsockopt,
.getsockopt =
sock_common_getsockopt,
.sendmsg
= inet_sendmsg,
.recvmsg =
inet_recvmsg,
.mmap
= sock_no_mmap,
.sendpage
= inet_sendpage,
.splice_read =
tcp_splice_read,
#ifdef CONFIG_COMPAT
.compat_setsockopt
= compat_sock_common_setsockopt,
.compat_getsockopt
= compat_sock_common_getsockopt,
.compat_ioctl =
inet_compat_ioctl,
#endif
2.1 sockfd_lookup_light函数
static
struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
{
struct
fd f = fdget(fd);//通过fd获取到struct fd结构体,然后获取file
struct
socket *sock;
*err
= -EBADF;
if
(f.file) {
sock
= sock_from_file(f.file, err);//返回套接字所对应的指针,存储在file->private_data;在sock_alloc_file函数中对其进行赋值
if
(likely(sock)) {
*fput_needed
= f.flags;
return
sock;//返回socket结构体指针
}
fdput(f);
}
return
NULL;
}
2.2 inet_bind函数
bind系统调用通过套接口层Inet_bind(),然后便会调用传输接口层的函数,TCP中的传输层接口函数为inet_csk_get_port函数,该函数主要实现bind的作用,如果用户系统调用使用的端口号为0,系统会自动选择一个可用的端口号,这里选择可用端口号思路是:先在绑定表中选择可用的端口号,如果在绑定表中没有可用的端口号,再选择空闲的端口号。
在af_inet.c文件中。
int inet_bind(struct socket *sock, struct
sockaddr *uaddr, int addr_len)
{
struct
sockaddr_in *addr = (struct sockaddr_in *)uaddr;//要绑定的sockaddr_in结构体
struct
sock *sk = sock->sk;
struct
inet_sock *inet = inet_sk(sk);
unsigned
short snum;//要绑定的端口
int
chk_addr_ret;//地址类型
int
err;
/*
If the socket has its own bind function then use it. (RAW)对于RAW类型的socket,调用raw socket自己的bind函数raw_bind*/
if
(sk->sk_prot->bind) {
err
= sk->sk_prot->bind(sk, uaddr, addr_len);
goto
out;
}
err
= -EINVAL;
if
(addr_len < sizeof(struct sockaddr_in))//sockaddr_in长度错误
goto
out;
chk_addr_ret
= inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);//地址类型检查,看看是否回环地址,多播地址,组播地址,在下面的判断中需要使用到
/*
Not specified by any standard per-se, however it breaks too
* many applications when removed. It is unfortunate since
* allowing applications to make a non-local
bind solves
* several problems with systems using dynamic
addressing.
* (ie. your servers still start up even if
your ISDN link
* is
temporarily down)
sysctl_ip_nonlocal_bind表明是否允许绑定非本地的IP地址,默认为0,不允许绑定/proc/sys/net/ipv4# cat ip_nonlocal_bind
0
上面的那段注释说明了使用非本地地址绑定可以解决一些使用动态地址绑定的服务器程序,所以这个实现还是有实际意义的
inet->freebind是通过do_ip_setsockopt函数进行设置的,默认值为1,该值表示允许绑定一个非本地IP地址和不存在的IP地址,可以通过IP_FREEBIND设置
inet->transparent:其含义就是可以使一个服务器程序侦听所有的IP地址,哪怕不是本机的IP地址
*/
err
= -EADDRNOTAVAIL;
if
(!sysctl_ip_nonlocal_bind &&
!(inet->freebind ||
inet->transparent) &&
addr->sin_addr.s_addr !=
htonl(INADDR_ANY) &&
chk_addr_ret != RTN_LOCAL &&
chk_addr_ret != RTN_MULTICAST &&
chk_addr_ret != RTN_BROADCAST)
goto
out;
snum
= ntohs(addr->sin_port);//获取绑定的端口号
err
= -EACCES;
/*如果要绑定0-1023以下的端口号,需要用户具有CAP_NET_BIND_SERVICE权限PROT_SOCK就是1024*/
if
(snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
goto
out;
/* We keep a pair of addresses. rcv_saddr is
the one
*
used by hash lookups, and saddr is used for transmit.
*
*
In the BSD API these are the same except where it
*
would be illegal to use them (multicast/broadcast) in
*
which case the sending device address is used.
*/
lock_sock(sk);
/*
Check these errors (active socket, double bind). */
err
= -EINVAL;
if
(sk->sk_state != TCP_CLOSE || inet->num) //判断sk_state的状态是否为TCP_CLOSE,在创建socket时,sk_state初始为TCP_CLOSE,如果不等于TCP_CLOSE说明已经bind过,而num只有当rawsocket时才会不为0
goto
out_release_sock;
inet->rcv_saddr
= inet->saddr = addr->sin_addr.s_addr;//需要绑定的地址
if
(chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
inet->saddr
= 0; /* Use device */
/*
Make sure we are allowed to bind here.调用四层的bind函数,对于TCP来说就是inet_csk_get_port */
if (sk->sk_prot->get_port(sk, snum)) {
inet->saddr
= inet->rcv_saddr = 0;
err
= -EADDRINUSE;
goto
out_release_sock;
}
if
(inet->rcv_saddr)
sk->sk_userlocks
|= SOCK_BINDADDR_LOCK;//设置sk中的sk->userlocks表示绑定地址
if
(snum)
sk->sk_userlocks
|= SOCK_BINDPORT_LOCK;//设置sk中的sk->userlocks表示绑定端口
inet->sport
= htons(inet->num);
inet->daddr
= 0;
inet->dport
= 0;
sk_dst_reset(sk);
err
= 0;
out_release_sock:
release_sock(sk);
out:
return
err;
}
2.2.1在raw.c文件中的proto架构体的定义如下:
struct proto raw_prot = {
.name = "RAW",
.owner
= THIS_MODULE,
.close = raw_close,
.destroy =
raw_destroy,
.connect =
ip4_datagram_connect,
.disconnect =
udp_disconnect,
.ioctl = raw_ioctl,
.init
= raw_init,
.setsockopt =
raw_setsockopt,
.getsockopt =
raw_getsockopt,
.sendmsg
= raw_sendmsg,
.recvmsg =
raw_recvmsg,
.bind = raw_bind,
.backlog_rcv =
raw_rcv_skb,
.release_cb =
ip4_datagram_release_cb,
.hash = raw_hash_sk,
.unhash
= raw_unhash_sk,
.obj_size =
sizeof(struct raw_sock),
.h.raw_hash =
&raw_v4_hashinfo,
#ifdef CONFIG_COMPAT
.compat_setsockopt
= compat_raw_setsockopt,
.compat_getsockopt
= compat_raw_getsockopt,
.compat_ioctl =
compat_raw_ioctl,
#endif
};
对于该类型的proto没有bind函数
struct proto tcp_prot = {
.name = "TCP",
.owner = THIS_MODULE,
.close = tcp_close,
.connect = tcp_v4_connect,
.disconnect = tcp_disconnect,
.accept = inet_csk_accept,
.ioctl = tcp_ioctl,
.init = tcp_v4_init_sock,
.destroy = tcp_v4_destroy_sock,
.shutdown = tcp_shutdown,
.setsockopt = tcp_setsockopt,
.getsockopt = tcp_getsockopt,
.recvmsg = tcp_recvmsg,
.backlog_rcv = tcp_v4_do_rcv,
.hash = inet_hash,
.unhash = inet_unhash,
.get_port =
inet_csk_get_port,
.enter_memory_pressure = tcp_enter_memory_pressure,
.sockets_allocated = &tcp_sockets_allocated,
.orphan_count = &tcp_orphan_count,
.memory_allocated = &tcp_memory_allocated,
.memory_pressure = &tcp_memory_pressure,
.sysctl_mem = sysctl_tcp_mem,
.sysctl_wmem = sysctl_tcp_wmem,
.sysctl_rmem = sysctl_tcp_rmem,
.max_header = MAX_TCP_HEADER,
.obj_size = sizeof(struct tcp_sock),
.slab_flags = SLAB_DESTROY_BY_RCU,
.twsk_prot = &tcp_timewait_sock_ops,
.rsk_prot = &tcp_request_sock_ops,
.h.hashinfo =
&tcp_hashinfo,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
#endif
};
文章浏览阅读849次。原谅,这是刚开始学C#学的代码,所以比较凌乱,但是是可以运行的using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows..._c# gdal获取影像有效范围
文章浏览阅读201次。最近处理一个新板子移植问题,移植第三方库,例如x264,碰到奇怪问题。这款板子是新拿到的,据说性价比比较高,因此需要进行方案验证按道理,大点第三方库兼容性都做的不错,特别类似x264这样的。但ARM芯片不给力,导致有许多问题,也折腾了很久,现在总算搞明白来龙去脉,MARK下:一般来说,考虑到 configure 命令比较长,我们会建立一个批处理文件(比如:install.sh),并将需要命..._unrecognized option '-stack_alignment=16
文章浏览阅读1.5k次,点赞2次,收藏4次。Section 1 Core Java,就是 Java 基础、JDK 的类库,很多童鞋都会说,JDK 我懂,但是懂还不足够,知其然还要知其所以然,JDK 的源代码写的非常好,要经常查看,对使用频繁的类,比如 String,集合类(List,Map,Set)等数据结构要知道它们的实现..._10年java软件开发工程师适合看什么技术
文章浏览阅读7.6k次。1.复制文件,定义与调用用例BOOL WINAPI CopyFile( __in LPCTSTR lpExistingFileName, __in LPCTSTR lpNewFileName, __in BOOL bFailIfExists);//CopyFile(srcfilepath, dstfilepath, 0_c语言 copy 文件 api movefile
文章浏览阅读1.5k次。单个小计收起明细:报表数据->合计->按照维度小计->点击小计维度字段(折叠所选内容) 或者 点击合计字段 左侧小点。 所有小计收起明细:报表数据->合计->按照维度小计->小计->下钻总计级别->选择对应级别->回车 ..._sap小计折叠
文章浏览阅读1.6k次。我的环境:win2008R2 64位+IIS7.0从windows事件里找到错误原因:应用程序池“abc”将被自动禁用,原因是为此应用程序池提供服务的进程中出现一系列错误。这个应用程序池停止后,它就无法自动启动了,导致网站出现503错误网上搜索千篇一律的解决办法是:给IIS Admin Service添加NetWork Service用户权限(本地启动、本地激活)这种说法并不完..._iis 应用程序自动启动
文章浏览阅读721次。在规则引擎中,通常会使用某种表述性的语言(而不是编程语言)来描述规则。所以规则描述语言也是规则引擎的一个重要组成部分。目前在规则描述语言方面,并没有一个通用的标准获得规则引擎厂商的广泛支持,大部分规则描述语言都是厂商私有的。大体来说,规则语言可以分为结构化的(Structured)和基于标记的(Markup,通常为xml)。常见的规则描述语言包括:srl(Structured Rule Language) : Fair Isaac(以前是Blaze Software)定义的结构化规则描述语言_drl语言
文章浏览阅读4.7k次,点赞3次,收藏3次。【指导老师】 王津 CTO 天津千行时线科技有限公司1 前言虚拟主机和虚拟目录的用处和区别很大,需要一番深究。在windows/Linux/Mac上配置也有差异。区别这两个东西,是为了更方便的发布和部署你的项目!!!虚拟目录,你在发布的时候,会多一个project目录,去不掉,工程项目过大的时候。虚拟主机,直接是域名+index.php首页,方便发_虚拟目录和虚拟主机
文章浏览阅读333次。(1)静态工厂方法调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中.当客户端需要对象时,只需要简单地调用静态方法,而不同关心创建对象的细节.要声明通过静态方法创建的 Bean, 需要在Bean 的class 属性里指定拥有该工厂的方法的类,同时在 factory-method属性里指定工厂方法的名称.最后, 使用 元素为该方法传递_spring4 工厂方法注入bean
文章浏览阅读639次。公布Windows版Flutter构建高质量的Windows应用程序,并在移动和web上运行自从我们推出Flutter以来,我们一直专注于提供一个跨平台的解决方案,以获得漂亮的、定制的应用程序,这些应用程序被编译为机器代码,并充分利用您的设备的底层图形硬件。今天是这一愿景的重大扩展,我们首次发布了对Windows作为应用目标的支持,使Windows开发者能够受益于移动开发者所享有的同样的生产力和力量。我们在Flutter上的目标是为您提供构建良好体验所需的工具,无论您在哪个操作系统上构建。因此,我们_flutter windows ui
文章浏览阅读5.7k次。warning MSB8003: 未定义 WindowsSDKDir 属性。可能找不到某些生成工具。可能找不到某些生成工具。VS三大版本的对比分析VS运行出错用Visual Studio Installer 修复一遍就行了安装问题,修复一下,,社区版的应该没什么大问题。Visual Studio Community毕竟嘛,社区版,也可以理解为个人版。适用于学生、开源和个人等等。一些新手用来学习是个不错的选择。该版本有相对完备的免费IDE。可用于开发 Android、iOS、Windows 和_msb800未定义windows sdkir属性
文章浏览阅读4.8w次,点赞9次,收藏30次。50M/s, Onedrive直链提取+IDM实现满速下载博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议本文永久链接是:https://blog.nxingcloud.co/posts/a3ad802e.htmlOneDrive虽然嫖到了5T但是速度慢到极致是不是很不甘心,心里发痒?别急!OneDrive的真正实力远超你想象!今天,我就来教大家如何用oneindex+IDM让你的OneDrive下载速度爆表。话不多说,正文开整!!!国内网盘现状_onedrive直链