看了下这个库的源码,一个 FTP 的库,然后我看了下FtpConnect
方法的实现,看到用到了_REENTRANT
,不太清楚为什么要用这个宏,似乎是多线程有用
GLOBALDEF int FtpConnect(const char *host, netbuf **nControl)
{
int sControl;
struct sockaddr_in sin;
int on=1;
netbuf *ctrl;
char *lhost;
char *pnum;
memset(&sin,0,sizeof(sin));
sin.sin_family = AF_INET;
lhost = strdup(host);
pnum = strchr(lhost,':');
if (pnum == NULL)
pnum = "ftp";
else
*pnum++ = '\0';
if (isdigit(*pnum))
sin.sin_port = htons(atoi(pnum));
else
{
struct servent *pse;
#if _REENTRANT
struct servent se;
char tmpbuf[TMP_BUFSIZ];
int i;
if ( ( i = getservbyname_r(pnum,"tcp",&se,tmpbuf,TMP_BUFSIZ,&pse) ) != 0 )
{
errno = i;
if ( ftplib_debug )
perror("getservbyname_r");
free(lhost);
return 0;
}
#else
if ((pse = getservbyname(pnum,"tcp") ) == NULL )
{
if ( ftplib_debug )
perror("getservbyname");
free(lhost);
return 0;
}
#endif
sin.sin_port = pse->s_port;
}
if ((sin.sin_addr.s_addr = inet_addr(lhost)) == INADDR_NONE)
{
struct hostent *phe;
#ifdef _REENTRANT
struct hostent he;
char tmpbuf[TMP_BUFSIZ];
int i, herr;
if ( ( ( i = gethostbyname_r( lhost, &he, tmpbuf, TMP_BUFSIZ, &phe, &herr ) ) != 0 ) ||
( phe == NULL ) )
{
if ( ftplib_debug )
fprintf(stderr, "gethostbyname: %s\n", hstrerror(herr));
free(lhost);
return 0;
}
#else
if ((phe = gethostbyname(lhost)) == NULL)
{
if (ftplib_debug)
fprintf(stderr, "gethostbyname: %s\n", hstrerror(h_errno));
free(lhost);
return 0;
}
#endif
memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
}
free(lhost);
sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sControl == -1)
{
if (ftplib_debug)
perror("socket");
return 0;
}
if (setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR,
SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
{
if (ftplib_debug)
perror("setsockopt");
net_close(sControl);
return 0;
}
if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
if (ftplib_debug)
perror("connect");
net_close(sControl);
return 0;
}
ctrl = calloc(1,sizeof(netbuf));
if (ctrl == NULL)
{
if (ftplib_debug)
perror("calloc");
net_close(sControl);
return 0;
}
ctrl->buf = malloc(FTPLIB_BUFSIZ);
if (ctrl->buf == NULL)
{
if (ftplib_debug)
perror("calloc");
net_close(sControl);
free(ctrl);
return 0;
}
ctrl->handle = sControl;
ctrl->dir = FTPLIB_CONTROL;
ctrl->ctrl = NULL;
ctrl->data = NULL;
ctrl->cmode = FTPLIB_DEFMODE;
ctrl->idlecb = NULL;
ctrl->idletime.tv_sec = ctrl->idletime.tv_usec = 0;
ctrl->idlearg = NULL;
ctrl->xfered = 0;
ctrl->xfered1 = 0;
ctrl->cbbytes = 0;
if (readresp('2', ctrl) == 0)
{
net_close(sControl);
free(ctrl->buf);
free(ctrl);
return 0;
}
*nControl = ctrl;
return 1;
}
1
codehz 2020-05-11 23:30:44 +08:00 via Android
只是用作特性开关吧,某个地方定义之后就用可重入的那块,不然就普通的
|
2
shiny2017 2020-05-11 23:44:38 +08:00
主要是区分比如: getservbyname_r 与 gethostbyname 之类的接口, 不带_r 后缀的就是不可重入的, 比如 gethostbyname 使用了全局变量或者静态变量, 如果进程的多个线程同时调用又不加锁的情况下, 都更新相同的全局变量会产生问题的.
|
3
salamanderMH OP @shiny2017 谢谢,那看起来`gethostbyname`和`getservbyname`有线程安全问题。
|
4
salamanderMH OP SO 上搜了下,确实有 thread safety 的问题:
https://stackoverflow.com/questions/25951925/gethostbyname-processes-resolving-consistently-even-from-different-threads |