一种结构如何通过 "return (struct a *) b" 之类的东西映射到另一种结构
How is one structure mapped to another by something like "return (struct a *) b"
我正在尝试理解 linux 内核网络代码,我遇到了很多函数,例如
static inline struct tcp_sock *tcp_sk(const struct sock *sk)
{
return (struct tcp_sock *)sk;
}
结构sock
和tcp_sock
的内容大不相同。这种映射究竟是如何发生的?具有相同名称和类型的结构成员是否相互映射?
编辑 1: 更具体地说,在函数 tcp_v4_connect
struct tcp_sock *tp = tcp_sk(sk);
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
inet->inet_daddr,
inet->inet_sport,
usin->sin_port);
err = tcp_connect(sk);
然后在上面调用的函数tcp_connect
中,
struct tcp_sock *tp = tcp_sk(sk);
tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
变量 write_seq
仅存在于 struct tcp_sock
中,那么当只有 struct sock *sk
传递给它时,它的值如何传递给函数 tcp_connect
?
谢谢。
由于构造只是一个 cast,"mapped" 没有任何内容,sk
指向的内存位置实际上没有任何更改。
这仅在结构相似或至少以相同偏移量的相同字段开始时才有效。
在 linux 内核代码中,您可以看到 struct sock
和 struct tcp_sock
具有 struct sock
的所有共同字段(tcp_sock
包含一个 inet_connection_sock
其中包含一个 inet_sock
,后者又分别包含一个 sock
作为第一个元素)。所以,“结构的内容...完全不同”,并不完全正确。它们实际上是相同的(至少对于 struct sock
的大小)。
为了能够正确执行此操作,系统以某种方式 "must know" 可以安全地将 struct sock
转换为 struct tcp_sock
- 此信息通常隐藏在常见 header,在本例中是 struct sock
部分(我最近没有检查,但我猜这里的信息在 sk_family
)
编辑后:
实际传递给您的函数的是指向内存区域的指针。无论以前发生过什么,都没有被演员改变(正如我上面所说的)。如果我们可以安全地假设 sk
之前某个时间是指向 struct tcp_sock
的指针,我们就可以安全地将它转换回这样的野兽。这通常在代码中完成,该代码围绕具有 generic 和 specific 部分的数据移动(如本例所示)。所有套接字(TCP、UDP、通用、Unix 套接字...)数据都有公共数据,这些数据收集在所有特定套接字结构开头的 struct sock
中。因此,在传入的套接字数据上,该结构的所有通用部分首先由处理 struct sock
的函数处理,后面必须有一些大的 switch...case
查看特定部分,然后传递特定 指针类型。
这允许一种 layered
编程方法,其中所有内容首先转换为通用 struct sock
,然后通用部分由所有套接字类型通用的函数处理,稍后,指针是恢复到 原来的状态 ,具体部分由专门的函数处理。一直以来,基本上用作 struct sock
上的 "backpack" 来保存特定数据的内存区域只是保持不变。
具有相同名称和类型的结构成员是否相互映射?
没有
struct sock sk; /* our sock struct */
struct tcp_sock *tcp_sk = (struct tcp_sock *)&sk;
tcp_sk
指针现在简单地指向 &sk
指向的内存。现在通过访问 tcp_sk
字段,您将访问分配给该指针的内存,但为了获得预期结果,存储在两个地址的数据应该有效。
现在,struct sock
(套接字的网络层表示)的第一个成员是 struct sock_common
:
306 struct sock {
307 /*
308 * Now struct inet_timewait_sock also uses sock_common, so please just
309 * don't add nothing before this first member (__sk_common) --acme
310 */
311 struct sock_common __sk_common;
并且 struct tcp_sock
有 struct inet_connection_sock
作为第一个成员
struct tcp_sock {
138 /* inet_connection_sock has to be the first member of tcp_sock */
139 struct inet_connection_sock inet_conn;
并且此结构的第一个成员为 struct inet_sock
:
90 struct inet_connection_sock {
91 /* inet_sock has to be the first member! */
92 struct inet_sock icsk_inet;
猜猜 inet_sock
的第一个成员是什么结构...它是 struct sock
:
172 struct inet_sock {
173 /* sk and pinet6 has to be the first two members of inet_sock */
174 struct sock sk;
因此,通过访问 tcp_sk.inet_conn.icsk_inet.sk
,您正在访问我们的 sock
结构。
我正在尝试理解 linux 内核网络代码,我遇到了很多函数,例如
static inline struct tcp_sock *tcp_sk(const struct sock *sk)
{
return (struct tcp_sock *)sk;
}
结构sock
和tcp_sock
的内容大不相同。这种映射究竟是如何发生的?具有相同名称和类型的结构成员是否相互映射?
编辑 1: 更具体地说,在函数 tcp_v4_connect
struct tcp_sock *tp = tcp_sk(sk);
tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
inet->inet_daddr,
inet->inet_sport,
usin->sin_port);
err = tcp_connect(sk);
然后在上面调用的函数tcp_connect
中,
struct tcp_sock *tp = tcp_sk(sk);
tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
变量 write_seq
仅存在于 struct tcp_sock
中,那么当只有 struct sock *sk
传递给它时,它的值如何传递给函数 tcp_connect
?
谢谢。
由于构造只是一个 cast,"mapped" 没有任何内容,sk
指向的内存位置实际上没有任何更改。
这仅在结构相似或至少以相同偏移量的相同字段开始时才有效。
在 linux 内核代码中,您可以看到 struct sock
和 struct tcp_sock
具有 struct sock
的所有共同字段(tcp_sock
包含一个 inet_connection_sock
其中包含一个 inet_sock
,后者又分别包含一个 sock
作为第一个元素)。所以,“结构的内容...完全不同”,并不完全正确。它们实际上是相同的(至少对于 struct sock
的大小)。
为了能够正确执行此操作,系统以某种方式 "must know" 可以安全地将 struct sock
转换为 struct tcp_sock
- 此信息通常隐藏在常见 header,在本例中是 struct sock
部分(我最近没有检查,但我猜这里的信息在 sk_family
)
编辑后:
实际传递给您的函数的是指向内存区域的指针。无论以前发生过什么,都没有被演员改变(正如我上面所说的)。如果我们可以安全地假设 sk
之前某个时间是指向 struct tcp_sock
的指针,我们就可以安全地将它转换回这样的野兽。这通常在代码中完成,该代码围绕具有 generic 和 specific 部分的数据移动(如本例所示)。所有套接字(TCP、UDP、通用、Unix 套接字...)数据都有公共数据,这些数据收集在所有特定套接字结构开头的 struct sock
中。因此,在传入的套接字数据上,该结构的所有通用部分首先由处理 struct sock
的函数处理,后面必须有一些大的 switch...case
查看特定部分,然后传递特定 指针类型。
这允许一种 layered
编程方法,其中所有内容首先转换为通用 struct sock
,然后通用部分由所有套接字类型通用的函数处理,稍后,指针是恢复到 原来的状态 ,具体部分由专门的函数处理。一直以来,基本上用作 struct sock
上的 "backpack" 来保存特定数据的内存区域只是保持不变。
具有相同名称和类型的结构成员是否相互映射?
没有
struct sock sk; /* our sock struct */
struct tcp_sock *tcp_sk = (struct tcp_sock *)&sk;
tcp_sk
指针现在简单地指向 &sk
指向的内存。现在通过访问 tcp_sk
字段,您将访问分配给该指针的内存,但为了获得预期结果,存储在两个地址的数据应该有效。
现在,struct sock
(套接字的网络层表示)的第一个成员是 struct sock_common
:
306 struct sock {
307 /*
308 * Now struct inet_timewait_sock also uses sock_common, so please just
309 * don't add nothing before this first member (__sk_common) --acme
310 */
311 struct sock_common __sk_common;
并且 struct tcp_sock
有 struct inet_connection_sock
作为第一个成员
struct tcp_sock {
138 /* inet_connection_sock has to be the first member of tcp_sock */
139 struct inet_connection_sock inet_conn;
并且此结构的第一个成员为 struct inet_sock
:
90 struct inet_connection_sock {
91 /* inet_sock has to be the first member! */
92 struct inet_sock icsk_inet;
猜猜 inet_sock
的第一个成员是什么结构...它是 struct sock
:
172 struct inet_sock {
173 /* sk and pinet6 has to be the first two members of inet_sock */
174 struct sock sk;
因此,通过访问 tcp_sk.inet_conn.icsk_inet.sk
,您正在访问我们的 sock
结构。