亚洲成精品动漫久久精久,九九在线精品视频播放,黄色成人免费观看,三级成人影院,久碰久,四虎成人欧美精品在永久在线

掃一掃
關注微信公眾號

Apache源代碼全景分析:網絡地址處理 (4)
2006-06-14   

對于非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);

熱詞搜索:

上一篇:Apache源代碼全景分析:網絡地址處理 (3)
下一篇:排除使用路由器后無法使用VPN的故障

分享到: 收藏