@HUST张友东 work@taobao zyd_com@126.com
分类: LINUX
2010-07-14 09:34:38
在项目中遇到一个问题,当客户端通过SUN RPC进行远程过程调用时,服务器如何获取调用方的IP地址,由于RPC是socket的封装,在send/recv的调用中都能获取数据包的源IP地址,故RPC肯定又能提供这样的接口。
最开始的需求源于DNFS的存储节点周期性的向元数据服务器发送心跳信息,当收到心跳信息后,服务器需要辨别心跳信息来自哪一个存储节点,WCW师兄的方法是在调用参数中增加IP地址一项,这种方法是可以的,但获取本地IP地址的方法需要指明网卡接口名,导致程序从一台以eth0为网卡接口名的机器移到一台以eth1为网卡接口名的机器上都需要更改存储节点的配置文件,但存储节点很多时,使用起来很不方便。
N个月前曾经就寻求过RPC服务器获取调用方IP地址的方法,以为RPC库会提供这样的借口,大致浏览了下man手册里的一些接口,发现svc_getcaller似乎能提供我需要的功能,其原型为struct sockaddr_in *svc_getcaller(SVCXPRT *xprt),但实现RPC服务器函数时,我们只能操作第三个参数struct svc_req,而SVCXPRT只显示出现在rpcgen自动生成的svc文件中,然后我就放弃了。
今天coding的时候,又碰到这个需求,于是我想修改rpc的认证方式能否达到这个目的,于是又回过头看了一下RPC的Unix认证方式,可通过AUTH *authunix_create(char *host, int uid, int gid, int len, int *aup_gids)构造unix认证(包含主机名,uid,gid的信息)的内容,使用unix认证方式后,服务器能获取unix认证方式传递过来的内容,通过这种方式获取客户端信息跟将信息放到调用参数中差不多,基本上没有任何帮助。
虽然这条路没有成功,但在测试unix认证的时候,发现struct svc_req中除了包含程序号,版本号,认证方式等信息,还有一个指向SVCXPRT传输点的指针,于是问题迎刃而解,svc_getcaller也就派上用场了。
在RPC服务器实现中加入如下代码即可打印出RPC调用方的IP地址。
struct sockaddr_in *si = svc_getcaller(rqstp->rq_xprt);
char *ipp = inet_ntoa(si->sin_addr);
printf("%s\n", ipp);