utils.c: Remove all usages of ast_gethostbyname()
gethostbyname() and gethostbyname_r() are deprecated in favor of getaddrinfo() which we use in the ast_sockaddr family of functions. ASTERISK-29819 #close Change-Id: Ie277c0ef768d753b169c121ef570a71665692ab7
This commit is contained in:
parent
262a4053ff
commit
0d62735f99
|
@ -537,8 +537,6 @@ int ooPDWrite(struct pollfd *pfds, int nfds, int fd)
|
||||||
int ooGetLocalIPAddress(char * pIPAddrs)
|
int ooGetLocalIPAddress(char * pIPAddrs)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct hostent *hp;
|
|
||||||
struct ast_hostent phost;
|
|
||||||
char hostname[100];
|
char hostname[100];
|
||||||
|
|
||||||
if(pIPAddrs == NULL)
|
if(pIPAddrs == NULL)
|
||||||
|
@ -546,20 +544,11 @@ int ooGetLocalIPAddress(char * pIPAddrs)
|
||||||
ret = gethostname(hostname, 100);
|
ret = gethostname(hostname, 100);
|
||||||
if(ret == 0)
|
if(ret == 0)
|
||||||
{
|
{
|
||||||
if ((hp = ast_gethostbyname(hostname, &phost))) {
|
struct ast_sockaddr addr = { {0,} };
|
||||||
if (hp->h_addrtype == AF_INET6) {
|
if (ast_sockaddr_resolve_first_af(&addr, hostname, PARSE_PORT_FORBID, AF_UNSPEC)) {
|
||||||
struct in6_addr i;
|
|
||||||
memcpy(&i, hp->h_addr, sizeof(i));
|
|
||||||
strcpy(pIPAddrs, (inet_ntop(AF_INET6, &i,
|
|
||||||
hostname, sizeof(hostname))) == NULL ? "::1" :
|
|
||||||
inet_ntop(AF_INET6, &i, hostname, sizeof(hostname)));
|
|
||||||
} else {
|
|
||||||
struct in_addr i;
|
|
||||||
memcpy(&i, hp->h_addr, sizeof(i));
|
|
||||||
strcpy(pIPAddrs, (ast_inet_ntoa(i) == NULL) ? "127.0.0.1" : ast_inet_ntoa(i));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return -1;
|
return -1;
|
||||||
|
} else {
|
||||||
|
strcpy(pIPAddrs, ast_sockaddr_stringify_addr(&addr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|
|
@ -281,8 +281,6 @@ static int festival_exec(struct ast_channel *chan, const char *vdata)
|
||||||
int usecache;
|
int usecache;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
struct sockaddr_in serv_addr;
|
struct sockaddr_in serv_addr;
|
||||||
struct hostent *serverhost;
|
|
||||||
struct ast_hostent ahp;
|
|
||||||
int fd;
|
int fd;
|
||||||
FILE *fs;
|
FILE *fs;
|
||||||
const char *host;
|
const char *host;
|
||||||
|
@ -398,15 +396,17 @@ static int festival_exec(struct ast_channel *chan, const char *vdata)
|
||||||
|
|
||||||
if ((serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) {
|
if ((serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) {
|
||||||
/* its a name rather than an ipnum */
|
/* its a name rather than an ipnum */
|
||||||
serverhost = ast_gethostbyname(host, &ahp);
|
struct ast_sockaddr addr = { {0,} };
|
||||||
|
|
||||||
if (serverhost == NULL) {
|
if (ast_sockaddr_resolve_first_af(&addr, host, PARSE_PORT_FORBID, AF_INET)) {
|
||||||
ast_log(LOG_WARNING, "festival_client: gethostbyname failed\n");
|
ast_log(LOG_WARNING, "festival_client: ast_sockaddr_resolve_first_af() failed\n");
|
||||||
ast_config_destroy(cfg);
|
ast_config_destroy(cfg);
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memmove(&serv_addr.sin_addr, serverhost->h_addr, serverhost->h_length);
|
|
||||||
|
/* We'll overwrite port and family in a sec */
|
||||||
|
ast_sockaddr_to_sin(&addr, &serv_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
serv_addr.sin_family = AF_INET;
|
serv_addr.sin_family = AF_INET;
|
||||||
|
|
|
@ -1949,10 +1949,8 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
|
||||||
int portno;
|
int portno;
|
||||||
struct ast_format_cap *peercap;
|
struct ast_format_cap *peercap;
|
||||||
int peerNonCodecCapability;
|
int peerNonCodecCapability;
|
||||||
struct sockaddr_in sin;
|
struct ast_sockaddr addr = { {0,} };
|
||||||
struct ast_sockaddr sin_tmp;
|
|
||||||
char *codecs;
|
char *codecs;
|
||||||
struct ast_hostent ahp; struct hostent *hp;
|
|
||||||
int codec, codec_count=0;
|
int codec, codec_count=0;
|
||||||
int iterator;
|
int iterator;
|
||||||
struct mgcp_endpoint *p = sub->parent;
|
struct mgcp_endpoint *p = sub->parent;
|
||||||
|
@ -1972,8 +1970,7 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* XXX This could block for a long time, and block the main thread! XXX */
|
/* XXX This could block for a long time, and block the main thread! XXX */
|
||||||
hp = ast_gethostbyname(host, &ahp);
|
if (ast_sockaddr_resolve_first_af(&addr, host, PARSE_PORT_FORBID, AF_INET)) {
|
||||||
if (!hp) {
|
|
||||||
ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
|
ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1981,12 +1978,9 @@ static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
|
||||||
ast_log(LOG_WARNING, "Malformed media stream descriptor: %s\n", m);
|
ast_log(LOG_WARNING, "Malformed media stream descriptor: %s\n", m);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sin.sin_family = AF_INET;
|
ast_sockaddr_set_port(&addr, portno);
|
||||||
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
|
ast_rtp_instance_set_remote_address(sub->rtp, &addr);
|
||||||
sin.sin_port = htons(portno);
|
ast_debug(3, "Peer RTP is at port %s\n", ast_sockaddr_stringify(&addr));
|
||||||
ast_sockaddr_from_sin(&sin_tmp, &sin);
|
|
||||||
ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
|
|
||||||
ast_debug(3, "Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
|
||||||
/* Scan through the RTP payload types specified in a "m=" line: */
|
/* Scan through the RTP payload types specified in a "m=" line: */
|
||||||
codecs = ast_strdupa(m + len);
|
codecs = ast_strdupa(m + len);
|
||||||
while (!ast_strlen_zero(codecs)) {
|
while (!ast_strlen_zero(codecs)) {
|
||||||
|
@ -4651,6 +4645,30 @@ static struct ast_variable *copy_vars(struct ast_variable *src)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Resolve the given hostname and save its IPv4 address.
|
||||||
|
*
|
||||||
|
* \param[in] hostname The hostname to resolve.
|
||||||
|
* \param[out] sin_addr Pointer to a <tt>struct in_addr</tt> in which to
|
||||||
|
* store the resolved IPv4 address. \c sin_addr will
|
||||||
|
* not be changed if resolution fails.
|
||||||
|
*
|
||||||
|
* \retval 0 if successful
|
||||||
|
* \retval 1 on failure
|
||||||
|
*/
|
||||||
|
static int resolve_first_addr(const char *hostname, struct in_addr *sin_addr)
|
||||||
|
{
|
||||||
|
struct ast_sockaddr addr = { {0,} };
|
||||||
|
struct sockaddr_in tmp;
|
||||||
|
|
||||||
|
if (ast_sockaddr_resolve_first_af(&addr, hostname, PARSE_PORT_FORBID, AF_INET)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_sockaddr_to_sin(&addr, &tmp);
|
||||||
|
*sin_addr = tmp.sin_addr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int reload_config(int reload)
|
static int reload_config(int reload)
|
||||||
{
|
{
|
||||||
|
@ -4659,8 +4677,6 @@ static int reload_config(int reload)
|
||||||
struct mgcp_gateway *g;
|
struct mgcp_gateway *g;
|
||||||
struct mgcp_endpoint *e;
|
struct mgcp_endpoint *e;
|
||||||
char *cat;
|
char *cat;
|
||||||
struct ast_hostent ahp;
|
|
||||||
struct hostent *hp;
|
|
||||||
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
|
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
|
||||||
|
|
||||||
if (gethostname(ourhost, sizeof(ourhost)-1)) {
|
if (gethostname(ourhost, sizeof(ourhost)-1)) {
|
||||||
|
@ -4694,10 +4710,8 @@ static int reload_config(int reload)
|
||||||
|
|
||||||
/* Create the interface list */
|
/* Create the interface list */
|
||||||
if (!strcasecmp(v->name, "bindaddr")) {
|
if (!strcasecmp(v->name, "bindaddr")) {
|
||||||
if (!(hp = ast_gethostbyname(v->value, &ahp))) {
|
if (resolve_first_addr(v->value, &bindaddr.sin_addr)) {
|
||||||
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
|
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
|
||||||
} else {
|
|
||||||
memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
|
|
||||||
}
|
}
|
||||||
} else if (!strcasecmp(v->name, "allow")) {
|
} else if (!strcasecmp(v->name, "allow")) {
|
||||||
ast_format_cap_update_by_allow_disallow(global_capability, v->value, 1);
|
ast_format_cap_update_by_allow_disallow(global_capability, v->value, 1);
|
||||||
|
@ -4765,13 +4779,11 @@ static int reload_config(int reload)
|
||||||
if (ntohl(bindaddr.sin_addr.s_addr)) {
|
if (ntohl(bindaddr.sin_addr.s_addr)) {
|
||||||
memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
|
memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
|
||||||
} else {
|
} else {
|
||||||
hp = ast_gethostbyname(ourhost, &ahp);
|
if (resolve_first_addr(ourhost, &__ourip)) {
|
||||||
if (!hp) {
|
|
||||||
ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
|
ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
|
||||||
ast_config_destroy(cfg);
|
ast_config_destroy(cfg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
|
|
||||||
}
|
}
|
||||||
if (!ntohs(bindaddr.sin_port))
|
if (!ntohs(bindaddr.sin_port))
|
||||||
bindaddr.sin_port = htons(DEFAULT_MGCP_CA_PORT);
|
bindaddr.sin_port = htons(DEFAULT_MGCP_CA_PORT);
|
||||||
|
|
|
@ -1235,8 +1235,6 @@ static struct sockaddr_in bindaddr;
|
||||||
static char ourhost[256];
|
static char ourhost[256];
|
||||||
static int ourport;
|
static int ourport;
|
||||||
static struct in_addr __ourip;
|
static struct in_addr __ourip;
|
||||||
static struct ast_hostent ahp;
|
|
||||||
static struct hostent *hp;
|
|
||||||
static int skinnysock = -1;
|
static int skinnysock = -1;
|
||||||
static pthread_t accept_t;
|
static pthread_t accept_t;
|
||||||
static int callnums = 1;
|
static int callnums = 1;
|
||||||
|
@ -7759,6 +7757,31 @@ static struct ast_channel *skinny_request(const char *type, struct ast_format_ca
|
||||||
return tmpc;
|
return tmpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Resolve the given hostname and save its IPv4 address.
|
||||||
|
*
|
||||||
|
* \param[in] hostname The hostname to resolve.
|
||||||
|
* \param[out] sin_addr Pointer to a <tt>struct in_addr</tt> in which to
|
||||||
|
* store the resolved IPv4 address. \c sin_addr will
|
||||||
|
* not be changed if resolution fails.
|
||||||
|
*
|
||||||
|
* \retval 0 if successful
|
||||||
|
* \retval 1 on failure
|
||||||
|
*/
|
||||||
|
static int resolve_first_addr(const char *hostname, struct in_addr *sin_addr)
|
||||||
|
{
|
||||||
|
struct ast_sockaddr addr = { {0,} };
|
||||||
|
struct sockaddr_in tmp;
|
||||||
|
|
||||||
|
if (ast_sockaddr_resolve_first_af(&addr, hostname, PARSE_PORT_FORBID, AF_INET)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_sockaddr_to_sin(&addr, &tmp);
|
||||||
|
*sin_addr = tmp.sin_addr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define TYPE_GENERAL 1
|
#define TYPE_GENERAL 1
|
||||||
#define TYPE_DEF_DEVICE 2
|
#define TYPE_DEF_DEVICE 2
|
||||||
#define TYPE_DEF_LINE 4
|
#define TYPE_DEF_LINE 4
|
||||||
|
@ -7790,10 +7813,8 @@ static void config_parse_variables(int type, void *item, struct ast_variable *vp
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcasecmp(v->name, "bindaddr")) {
|
if (!strcasecmp(v->name, "bindaddr")) {
|
||||||
if (!(hp = ast_gethostbyname(v->value, &ahp))) {
|
if (resolve_first_addr(v->value, &bindaddr.sin_addr)) {
|
||||||
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
|
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
|
||||||
} else {
|
|
||||||
memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if (!strcasecmp(v->name, "keepalive")) {
|
} else if (!strcasecmp(v->name, "keepalive")) {
|
||||||
|
@ -8480,13 +8501,11 @@ static int config_load(void)
|
||||||
if (ntohl(bindaddr.sin_addr.s_addr)) {
|
if (ntohl(bindaddr.sin_addr.s_addr)) {
|
||||||
__ourip = bindaddr.sin_addr;
|
__ourip = bindaddr.sin_addr;
|
||||||
} else {
|
} else {
|
||||||
hp = ast_gethostbyname(ourhost, &ahp);
|
if (resolve_first_addr(ourhost, &__ourip)) {
|
||||||
if (!hp) {
|
|
||||||
ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
|
ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
|
||||||
ast_config_destroy(cfg);
|
ast_config_destroy(cfg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
|
|
||||||
}
|
}
|
||||||
if (!ntohs(bindaddr.sin_port)) {
|
if (!ntohs(bindaddr.sin_port)) {
|
||||||
bindaddr.sin_port = htons(DEFAULT_SKINNY_PORT);
|
bindaddr.sin_port = htons(DEFAULT_SKINNY_PORT);
|
||||||
|
|
|
@ -6847,8 +6847,6 @@ static int reload_config(void)
|
||||||
{
|
{
|
||||||
struct ast_config *cfg;
|
struct ast_config *cfg;
|
||||||
struct ast_variable *v;
|
struct ast_variable *v;
|
||||||
struct ast_hostent ahp;
|
|
||||||
struct hostent *hp;
|
|
||||||
struct sockaddr_in bindaddr = { 0, };
|
struct sockaddr_in bindaddr = { 0, };
|
||||||
char *config = "unistim.conf";
|
char *config = "unistim.conf";
|
||||||
char *cat;
|
char *cat;
|
||||||
|
@ -6916,11 +6914,11 @@ static int reload_config(void)
|
||||||
}
|
}
|
||||||
} else if (!strcasecmp(v->name, "public_ip")) {
|
} else if (!strcasecmp(v->name, "public_ip")) {
|
||||||
if (!ast_strlen_zero(v->value)) {
|
if (!ast_strlen_zero(v->value)) {
|
||||||
if (!(hp = ast_gethostbyname(v->value, &ahp))) {
|
struct ast_sockaddr addr = { {0,} };
|
||||||
|
if (ast_sockaddr_resolve_first_af(&addr, v->value, PARSE_PORT_FORBID, AF_INET)) {
|
||||||
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
|
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
|
||||||
} else {
|
} else {
|
||||||
memcpy(&public_ip.sin_addr, hp->h_addr, sizeof(public_ip.sin_addr));
|
ast_sockaddr_to_sin(&addr, &public_ip);
|
||||||
public_ip.sin_family = AF_INET;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,9 +285,6 @@ static int iax_template_parse(struct iax_template *cur, struct ast_config *cfg,
|
||||||
int foundportno = 0;
|
int foundportno = 0;
|
||||||
int foundserverportno = 0;
|
int foundserverportno = 0;
|
||||||
int x;
|
int x;
|
||||||
struct in_addr ia;
|
|
||||||
struct hostent *hp;
|
|
||||||
struct ast_hostent h;
|
|
||||||
struct iax_template *src, tmp;
|
struct iax_template *src, tmp;
|
||||||
const char *t;
|
const char *t;
|
||||||
if (def) {
|
if (def) {
|
||||||
|
@ -335,15 +332,15 @@ static int iax_template_parse(struct iax_template *cur, struct ast_config *cfg,
|
||||||
} else
|
} else
|
||||||
ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno);
|
ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno);
|
||||||
} else if (!strcasecmp(v->name, "server") || !strcasecmp(v->name, "altserver")) {
|
} else if (!strcasecmp(v->name, "server") || !strcasecmp(v->name, "altserver")) {
|
||||||
hp = ast_gethostbyname(v->value, &h);
|
struct ast_sockaddr addr = { {0,} };
|
||||||
if (hp) {
|
if (ast_sockaddr_resolve_first_af(&addr, v->value, PARSE_PORT_FORBID, AF_INET)) {
|
||||||
memcpy(&ia, hp->h_addr, sizeof(ia));
|
|
||||||
if (!strcasecmp(v->name, "server"))
|
|
||||||
cur->server = ntohl(ia.s_addr);
|
|
||||||
else
|
|
||||||
cur->altserver = ntohl(ia.s_addr);
|
|
||||||
} else
|
|
||||||
ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno);
|
ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno);
|
||||||
|
} else {
|
||||||
|
if (!strcasecmp(v->name, "server"))
|
||||||
|
cur->server = ast_sockaddr_ipv4(&addr);
|
||||||
|
else
|
||||||
|
cur->altserver = ast_sockaddr_ipv4(&addr);
|
||||||
|
}
|
||||||
} else if (!strcasecmp(v->name, "codec")) {
|
} else if (!strcasecmp(v->name, "codec")) {
|
||||||
struct ast_format *tmpfmt;
|
struct ast_format *tmpfmt;
|
||||||
if ((tmpfmt = ast_format_cache_get(v->value))) {
|
if ((tmpfmt = ast_format_cache_get(v->value))) {
|
||||||
|
|
|
@ -3863,8 +3863,7 @@ double_done:
|
||||||
/* default is either the supplied value or the result itself */
|
/* default is either the supplied value or the result itself */
|
||||||
struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
|
struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
|
||||||
va_arg(ap, struct sockaddr_in *) : sa;
|
va_arg(ap, struct sockaddr_in *) : sa;
|
||||||
struct hostent *hp;
|
struct ast_sockaddr addr = { {0,} };
|
||||||
struct ast_hostent ahp;
|
|
||||||
|
|
||||||
memset(&_sa_buf, '\0', sizeof(_sa_buf)); /* clear buffer */
|
memset(&_sa_buf, '\0', sizeof(_sa_buf)); /* clear buffer */
|
||||||
/* duplicate the string to strip away the :port */
|
/* duplicate the string to strip away the :port */
|
||||||
|
@ -3890,12 +3889,13 @@ double_done:
|
||||||
error = 1;
|
error = 1;
|
||||||
}
|
}
|
||||||
/* Now deal with host part, even if we have errors before. */
|
/* Now deal with host part, even if we have errors before. */
|
||||||
hp = ast_gethostbyname(buf, &ahp);
|
if (ast_sockaddr_resolve_first_af(&addr, buf, PARSE_PORT_FORBID, AF_INET)) {
|
||||||
if (hp) /* resolved successfully */
|
|
||||||
memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
|
|
||||||
else {
|
|
||||||
error = 1;
|
error = 1;
|
||||||
sa->sin_addr = def->sin_addr;
|
sa->sin_addr = def->sin_addr;
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in tmp;
|
||||||
|
ast_sockaddr_to_sin(&addr, &tmp);
|
||||||
|
sa->sin_addr = tmp.sin_addr;
|
||||||
}
|
}
|
||||||
ast_debug(3,
|
ast_debug(3,
|
||||||
"extract inaddr from [%s] gives [%s:%d](%d)\n",
|
"extract inaddr from [%s] gives [%s:%d](%d)\n",
|
||||||
|
|
Loading…
Reference in New Issue