我通过 LD_PRELOAD 变量插入 JVM。
基本上,我想构建一个虚拟路由表(VRT)。在调用 bind() 时,我将 IP 地址和端口参数修改为我的选择(我将其保存在 VRT 中)。另外,我将套接字描述符(bind() 的第一个参数)添加到链接列表中。 (到目前为止,套接字的 sin_family 类型为 AF_INET6)。
现在,当套接字关闭(close())时,我想删除虚拟路由表条目。因此,我检查我们尝试关闭的套接字描述符是否存储在链接列表中。如果是,则意味着它的记录存在于VRT中,因此我应该在关闭套接字之前删除VRT条目。我面临的问题是,在这个阶段,同一个套接字描述符的 sin_family 值为 1(我不知道它代表什么)而不是 10(AF_INET6,bind() 期间的值)。此外,我尝试在这个阶段打印套接字描述符的IP地址和端口,但它是垃圾。
我不知道我错过了什么。
更新: 我的代码没有问题。出现异常的原因是 JVM 的以下行为(我通过 strace 跟踪)
9722 socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 12
...(receive messages)...
9722 dup2(11, 12) = 12 (?!?)
9722 close(12) = 0
JVM 在我们的套接字上复制了另一个文件描述符,因此它的 sin_family 在 close() 上无法正确显示。奇怪!
最佳答案
sin_family == 1
是AF_UNIX
,即管道或域名套接字。
您确定它确实是“相同”的套接字描述符吗?但你如何识别它呢?它的整数值仅对进程是唯一的。
如果您正在 LD_PRELOAD
fork 子进程,他们也会使用您的钩子(Hook),使用与父进程相同的描述符集,并且它们的所有 sibling 和子进程都会这样做。
因此,为了解决这个歧义,请在 Hook bind()
代码中使用 getpid()
获取 PID,并将 PID 添加到您为此套接字存储的 key 中。
dup2(int fdOld, int fdNew)
在将 fdNew
复制为 fdOld
之前关闭它。但我想你不能将调用挂接到 close()
上:-(。
关于c - 通过 LD_PRELOAD 插入 JVM 时卡在关闭套接字上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10437146/