当前位置:首页 > 技术与方案 > Linux及应用

网络地址处理 (4)

(2012-09-26 17:25:36)

对于非EAI_SYSTEM错误码,APR并不能直接返回。正如第一章所说,APR中对于apr_status_t返回码有自己的布局和规则,因此这些错误码必须转换至APR返回码。EAI_XXXX错误码的起始偏移是APR_OS_START_EAIERR,因此返回值实际上是rc+APR_OS_START_EAIERR。不过在一些平台上比如glibc,为了防止和h_errno的值冲突,系统将使用EAI_XXXX的负值, 这正是上面的代码w的原因。

上面的代码有一个假设前提,就是系统中必须提供getnameinfo()函数。但是由于getnameinfo()是比较新的一个函数,并不是每个操作系统平台都支持该函数。目前大部分Ipv4平台上不过都提供了gethostbyaddr()函数,通过该函数也能完成从主机地址到主机名称的转换,不过该函数仅仅支持Ipv4协议,不支持Ipv6协议。具体的代码如下所示:

#else

#if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) &&

defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS)

#ifdef GETHOSTBYNAME_R_HOSTENT_DATA

struct hostent_data hd;

#else

char tmp[GETHOSTBYNAME_BUFLEN];

#endif

 

int hosterror;

struct hostent hs, *hptr;

 

#if defined(GETHOSTBYNAME_R_HOSTENT_DATA)

/* AIX, HP/UX, D/UX et alia */

gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, u

sizeof(struct in_addr), AF_INET, &hs, &hd);

hptr = &hs;

#else

#if defined(GETHOSTBYNAME_R_GLIBC2)

/* Linux glibc2+ */

gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, v

sizeof(struct in_addr), AF_INET,

&hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror);

#else

/* Solaris, Irix et alia */

hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, w

sizeof(struct in_addr), AF_INET,

&hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror);

#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */

if (!hptr) {

*hostname = NULL;

return hosterror + APR_OS_START_SYSERR;

}

#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */

#else

struct hostent *hptr;

hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, x

sizeof(struct in_addr), AF_INET);

#endif

if (hptr) {

*hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name);

return APR_SUCCESS;

}

*hostname = NULL;

#if defined(WIN32)

return apr_get_netos_error();

#elif defined(OS2)

return h_errno;

#else

return h_errno + APR_OS_START_SYSERR;

#endif

#endif

函数中众多的预定义让人眼花缭乱。不过最主要的预定义处理还在于对gethostbyaddr()函数的调用。从上面的代码中可以看出,gethostbyaddr有一个函数变形gethostbyaddr_r,而且不同平台下的gethostbyaddr_t函数的参数也不相同,要了解详细的原因,必须了解一些函数可重入的概念。

所谓可重入函数是指一个可以被多个任务调用的函数,任务在调用时候不必担心数据会出错;通常情况下下面的函数是不可重入的:

(1)、函数体内使用了静态的数据结构;

(2)、函数体内调用了malloc()或者free()函数;

(3)、函数体内调用了标准I/O函数。

通常情况下,在一个UNIX进程中发生重入问题的条件是:从主程序中和某个信号处理函数中同时调用某个不可重入函数.。另外在多线程应用中也会出现函数重入的问题。不幸的是由于历史的原因,我们经常使用的gethostbyaddr也是一个不可重入的函数,因为它们都返回指向同一个静态结构的指针。关于gethostbyaddr的重入问题,《Unix网络编程 第一卷:套接口API》中文版第二版的第207页中有一段描述,摘抄如下:

不幸的是,重入问题比他表面看起来更要严重。首先,关于gethostbyname和gethostbyaddr的重入问题无标准可循。POSIX规范声明这两个函数不必是可重入的。Unix98只说这两个函数必须是线程安全的。

其次,关于_r函数也没有标准可循。Solaris 2.X,Digital Unix 4.0和HP-UX 10.30都提供了可重入版本的gethostbyaddr_r函数,不过它们的参数并不相同,不同版本的gethostbyaddr_r函数原型如下表所示:

操作系统平台 函数原型

solaris struct hostent* gethostbyaddr_r(const char *addr, int len, int type,

struct hostent *result, char *buf, int buflen, int * h_errnop);

AIX,HP-UX,Digital Unix int gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result,

struct hostent_data *buffer);

Linux glibc2+ int gethostbyaddr_r(const char *addr,int len, int type,struct hostent *result,

char* buf, int buflen, struct hostent *hs, int* h_errnop);

 

大部分gethostbyaddr_r函数的前四个参数都相同,第一个是需要转换的地址;第二个地址的字节大小,用sizeof(struct in_addr)表示;第三个是需要转换地址的协议族,或者是AF_INET,或者是AF_INET6;第四个则是描述主机的hostent结构。区别通常在后几个参数:

对于Solaris,Irix等操作系统而言,后面还需要三个额外的参数,buf是由调用者分配的并且大小为buflen的缓冲区,该缓冲区用于存放规范主机名称,别名指针数组,各个别名字符串,地址指针数组以及各个实际地址。如果初出错,错误码通过h_errnop指针返回,注意不是我们通常所说的h_errno返回。

对于AIX,HP-UX,Digital Unix等平台而言,后面的三个参数则被组合为一个新的数据结构hostent_data,指向该结构的指针构成本函数的第三个和最后一个参数。Apache中默认的缓冲区大小为GETHOSTBYNAME_BUFLEN,即512字节。

对于Linux glibc2+而言,gethostbyaddr_r的参数与前两者又存在一定的差异,它共计有八个参数,与Solaris平台相比多了struct hostent* hs参数。

如果操作系统平台不支持可重入的gethostaddr_r函数,那么只能使用不可重入的gethostbyaddr函数,如x所示。

返回的主机名称保存在hostent结构中,如果查询成功,从hostname参数中返回即可。

9.1.3.3 IP地址解析

APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr,

char **scope_id,

apr_port_t *port,

const char *str,

apr_pool_t *p);

更多
关闭窗口 打印 
网站首页    -    联系我们    -   收藏本站    -    网站地图                                                               客户服务热线:0571-85023000
本网站所有网页信息已申请知识产权和著作权保护,版权归四海光纤公司所有,未经授权禁止任何人复制或镜像,违者必究。
公司主营:杭州光纤光缆视频会议系统,是专业的通信网络工程、视频会议系统建设专家

中华人民共和国备案号:浙ICP备10018243号