mirror of
git://git.gnupg.org/gnupg.git
synced 2025-02-01 16:33:02 +01:00
Fix issue 1446: honor ports given in SRV responses.
* common/http.c (send_request, connect_server, http_open): Use a struct srv instead of a single srvtag so we can pass the chosen host and port back to the caller. (connect_server): Use the proper port in the HAVE_GETADDRINFO case. * keyserver/curl-shim.c (curl_easy_perform): Use struct srv and log chosen host and port. * keyserver/gpgkeys_hkp.c (main): Properly take the port given by SRV. Backported from ba9e974f1fd85b3dbbfb5e26d7a14f71d07c7cf2
This commit is contained in:
parent
3a51d501b9
commit
f2f12f41ef
@ -1,6 +1,6 @@
|
|||||||
/* http.h - HTTP protocol handler
|
/* http.h - HTTP protocol handler
|
||||||
* Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005,
|
* Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005,
|
||||||
* 2009 Free Software Foundation, Inc.
|
* 2009, 2012 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -73,14 +73,21 @@ struct http_context {
|
|||||||
};
|
};
|
||||||
typedef struct http_context *HTTP_HD;
|
typedef struct http_context *HTTP_HD;
|
||||||
|
|
||||||
|
struct http_srv
|
||||||
|
{
|
||||||
|
const char *srvtag;
|
||||||
|
char *used_server;
|
||||||
|
unsigned short used_port;
|
||||||
|
};
|
||||||
|
|
||||||
int http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
|
int http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
|
||||||
char *auth, unsigned int flags, const char *proxy,
|
char *auth, unsigned int flags, const char *proxy,
|
||||||
const char *srvtag, STRLIST headers );
|
struct http_srv *srv, STRLIST headers );
|
||||||
void http_start_data( HTTP_HD hd );
|
void http_start_data( HTTP_HD hd );
|
||||||
int http_wait_response( HTTP_HD hd, unsigned int *ret_status );
|
int http_wait_response( HTTP_HD hd, unsigned int *ret_status );
|
||||||
void http_close( HTTP_HD hd );
|
void http_close( HTTP_HD hd );
|
||||||
int http_open_document( HTTP_HD hd, const char *document, char *auth,
|
int http_open_document( HTTP_HD hd, const char *document, char *auth,
|
||||||
unsigned int flags, const char *proxy,
|
unsigned int flags, const char *proxy,
|
||||||
const char *srvtag, STRLIST headers );
|
struct http_srv *srv, STRLIST headers );
|
||||||
|
|
||||||
#endif /*G10_HTTP_H*/
|
#endif /*G10_HTTP_H*/
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* curl-shim.c - Implement a small subset of the curl API in terms of
|
/* curl-shim.c - Implement a small subset of the curl API in terms of
|
||||||
* the iobuf HTTP API
|
* the iobuf HTTP API
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2012 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -164,6 +164,9 @@ curl_easy_perform(CURL *curl)
|
|||||||
CURLcode err=CURLE_OK;
|
CURLcode err=CURLE_OK;
|
||||||
const char *errstr=NULL;
|
const char *errstr=NULL;
|
||||||
char *proxy=NULL;
|
char *proxy=NULL;
|
||||||
|
struct http_srv srv;
|
||||||
|
|
||||||
|
memset(&srv,0,sizeof(srv));
|
||||||
|
|
||||||
/* Emulate the libcurl proxy behavior. If the calling program set a
|
/* Emulate the libcurl proxy behavior. If the calling program set a
|
||||||
proxy, use it. If it didn't set a proxy or set it to NULL, check
|
proxy, use it. If it didn't set a proxy or set it to NULL, check
|
||||||
@ -176,10 +179,17 @@ curl_easy_perform(CURL *curl)
|
|||||||
else
|
else
|
||||||
proxy=getenv(HTTP_PROXY_ENV);
|
proxy=getenv(HTTP_PROXY_ENV);
|
||||||
|
|
||||||
|
if(curl->srvtag)
|
||||||
|
srv.srvtag=curl->srvtag;
|
||||||
|
|
||||||
if(curl->flags.verbose)
|
if(curl->flags.verbose)
|
||||||
{
|
{
|
||||||
fprintf(curl->errors,"* HTTP proxy is \"%s\"\n",proxy?proxy:"null");
|
fprintf(curl->errors,"* HTTP proxy is \"%s\"\n",proxy?proxy:"null");
|
||||||
fprintf(curl->errors,"* HTTP URL is \"%s\"\n",curl->url);
|
fprintf(curl->errors,"* HTTP URL is \"%s\"\n",curl->url);
|
||||||
|
if(srv.srvtag)
|
||||||
|
fprintf(curl->errors,
|
||||||
|
"* SRV tag is \"%s\": host and port may be overridden\n",
|
||||||
|
srv.srvtag);
|
||||||
fprintf(curl->errors,"* HTTP auth is \"%s\"\n",
|
fprintf(curl->errors,"* HTTP auth is \"%s\"\n",
|
||||||
curl->auth?curl->auth:"null");
|
curl->auth?curl->auth:"null");
|
||||||
fprintf(curl->errors,"* HTTP method is %s\n",
|
fprintf(curl->errors,"* HTTP method is %s\n",
|
||||||
@ -189,12 +199,16 @@ curl_easy_perform(CURL *curl)
|
|||||||
if(curl->flags.post)
|
if(curl->flags.post)
|
||||||
{
|
{
|
||||||
rc=http_open(&curl->hd,HTTP_REQ_POST,curl->url,curl->auth,0,proxy,
|
rc=http_open(&curl->hd,HTTP_REQ_POST,curl->url,curl->auth,0,proxy,
|
||||||
curl->srvtag,curl->headers?curl->headers->list:NULL);
|
&srv,curl->headers?curl->headers->list:NULL);
|
||||||
if(rc==0)
|
if(rc==0)
|
||||||
{
|
{
|
||||||
char content_len[50];
|
char content_len[50];
|
||||||
unsigned int post_len=strlen(curl->postfields);
|
unsigned int post_len=strlen(curl->postfields);
|
||||||
|
|
||||||
|
if(curl->flags.verbose && srv.used_server && srv.used_port)
|
||||||
|
fprintf (curl->errors, "* HTTP host:port post-SRV is \"%s:%hu\"\n",
|
||||||
|
srv.used_server, srv.used_port);
|
||||||
|
|
||||||
iobuf_writestr(curl->hd.fp_write,
|
iobuf_writestr(curl->hd.fp_write,
|
||||||
"Content-Type: application/x-www-form-urlencoded\r\n");
|
"Content-Type: application/x-www-form-urlencoded\r\n");
|
||||||
sprintf(content_len,"Content-Length: %u\r\n",post_len);
|
sprintf(content_len,"Content-Length: %u\r\n",post_len);
|
||||||
@ -211,9 +225,13 @@ curl_easy_perform(CURL *curl)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc=http_open(&curl->hd,HTTP_REQ_GET,curl->url,curl->auth,0,proxy,
|
rc=http_open(&curl->hd,HTTP_REQ_GET,curl->url,curl->auth,0,proxy,
|
||||||
curl->srvtag,curl->headers?curl->headers->list:NULL);
|
&srv,curl->headers?curl->headers->list:NULL);
|
||||||
if(rc==0)
|
if(rc==0)
|
||||||
{
|
{
|
||||||
|
if(curl->flags.verbose && srv.used_server && srv.used_port)
|
||||||
|
fprintf (curl->errors, "* HTTP host:port post-SRV is \"%s:%hu\"\n",
|
||||||
|
srv.used_server, srv.used_port);
|
||||||
|
|
||||||
rc=http_wait_response(&curl->hd,&curl->status);
|
rc=http_wait_response(&curl->hd,&curl->status);
|
||||||
if(rc==0)
|
if(rc==0)
|
||||||
{
|
{
|
||||||
@ -248,6 +266,8 @@ curl_easy_perform(CURL *curl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free (srv.used_server);
|
||||||
|
|
||||||
switch(rc)
|
switch(rc)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* gpgkeys_hkp.c - talk to an HKP keyserver
|
/* gpgkeys_hkp.c - talk to an HKP keyserver
|
||||||
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
||||||
* 2009 Free Software Foundation, Inc.
|
* 2009, 2012 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -690,6 +690,7 @@ main(int argc,char *argv[])
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Defaults */
|
||||||
if(ascii_strcasecmp(opt->scheme,"hkps")==0)
|
if(ascii_strcasecmp(opt->scheme,"hkps")==0)
|
||||||
{
|
{
|
||||||
proto="https";
|
proto="https";
|
||||||
@ -722,11 +723,9 @@ main(int argc,char *argv[])
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the user gives a :port, then disable SRV. The semantics of a
|
/* Only use SRV if the user does not provide a :port. The semantics
|
||||||
specified port and SRV do not play well together. */
|
of a specified port and SRV do not play well together. */
|
||||||
if(opt->port)
|
if(!opt->port && try_srv)
|
||||||
port=opt->port;
|
|
||||||
else if(try_srv)
|
|
||||||
{
|
{
|
||||||
char *srvtag;
|
char *srvtag;
|
||||||
|
|
||||||
@ -751,6 +750,11 @@ main(int argc,char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the user provided a port (or it came in via SRV, above),
|
||||||
|
replace the default. */
|
||||||
|
if(opt->port)
|
||||||
|
port=opt->port;
|
||||||
|
|
||||||
curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
|
curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);
|
||||||
|
|
||||||
if(opt->auth)
|
if(opt->auth)
|
||||||
|
54
util/http.c
54
util/http.c
@ -1,6 +1,6 @@
|
|||||||
/* http.c - HTTP protocol handler
|
/* http.c - HTTP protocol handler
|
||||||
* Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
* Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||||
* 2009 Free Software Foundation, Inc.
|
* 2009, 2012 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -69,12 +69,12 @@ static int insert_escapes( byte *buffer, const byte *string,
|
|||||||
const byte *special );
|
const byte *special );
|
||||||
static URI_TUPLE parse_tuple( byte *string );
|
static URI_TUPLE parse_tuple( byte *string );
|
||||||
static int send_request( HTTP_HD hd, const char *auth, const char *proxy,
|
static int send_request( HTTP_HD hd, const char *auth, const char *proxy,
|
||||||
const char *srvtag, STRLIST headers);
|
struct http_srv *srv, STRLIST headers);
|
||||||
static byte *build_rel_path( PARSED_URI uri );
|
static byte *build_rel_path( PARSED_URI uri );
|
||||||
static int parse_response( HTTP_HD hd );
|
static int parse_response( HTTP_HD hd );
|
||||||
|
|
||||||
static int connect_server( const char *server, ushort port, unsigned int flags,
|
static int connect_server( const char *server, ushort port, unsigned int flags,
|
||||||
const char *srvtag );
|
struct http_srv *srv );
|
||||||
static int write_server( int sock, const char *data, size_t length );
|
static int write_server( int sock, const char *data, size_t length );
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -150,7 +150,7 @@ make_radix64_string( const byte *data, size_t len )
|
|||||||
int
|
int
|
||||||
http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
|
http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
|
||||||
char *auth, unsigned int flags, const char *proxy,
|
char *auth, unsigned int flags, const char *proxy,
|
||||||
const char *srvtag, STRLIST headers )
|
struct http_srv *srv, STRLIST headers )
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
|
|||||||
|
|
||||||
rc = parse_uri( &hd->uri, url );
|
rc = parse_uri( &hd->uri, url );
|
||||||
if( !rc ) {
|
if( !rc ) {
|
||||||
rc = send_request( hd, auth, proxy, srvtag, headers );
|
rc = send_request( hd, auth, proxy, srv, headers );
|
||||||
if( !rc ) {
|
if( !rc ) {
|
||||||
hd->fp_write = iobuf_sockopen( hd->sock , "w" );
|
hd->fp_write = iobuf_sockopen( hd->sock , "w" );
|
||||||
if( hd->fp_write )
|
if( hd->fp_write )
|
||||||
@ -234,12 +234,12 @@ http_wait_response( HTTP_HD hd, unsigned int *ret_status )
|
|||||||
|
|
||||||
int
|
int
|
||||||
http_open_document( HTTP_HD hd, const char *document, char *auth,
|
http_open_document( HTTP_HD hd, const char *document, char *auth,
|
||||||
unsigned int flags, const char *proxy, const char *srvtag,
|
unsigned int flags, const char *proxy, struct http_srv *srv,
|
||||||
STRLIST headers )
|
STRLIST headers )
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy, srvtag,
|
rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy, srv,
|
||||||
headers );
|
headers );
|
||||||
if( rc )
|
if( rc )
|
||||||
return rc;
|
return rc;
|
||||||
@ -523,7 +523,7 @@ parse_tuple( byte *string )
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
send_request( HTTP_HD hd, const char *auth, const char *proxy,
|
send_request( HTTP_HD hd, const char *auth, const char *proxy,
|
||||||
const char *srvtag, STRLIST headers )
|
struct http_srv *srv, STRLIST headers )
|
||||||
{
|
{
|
||||||
const byte *server;
|
const byte *server;
|
||||||
byte *request, *p;
|
byte *request, *p;
|
||||||
@ -546,7 +546,7 @@ send_request( HTTP_HD hd, const char *auth, const char *proxy,
|
|||||||
return G10ERR_NETWORK;
|
return G10ERR_NETWORK;
|
||||||
}
|
}
|
||||||
hd->sock = connect_server( *uri->host? uri->host : "localhost",
|
hd->sock = connect_server( *uri->host? uri->host : "localhost",
|
||||||
uri->port? uri->port : 80, 0, NULL );
|
uri->port? uri->port : 80, 0, srv );
|
||||||
if(uri->auth)
|
if(uri->auth)
|
||||||
{
|
{
|
||||||
char *x;
|
char *x;
|
||||||
@ -560,7 +560,7 @@ send_request( HTTP_HD hd, const char *auth, const char *proxy,
|
|||||||
release_parsed_uri( uri );
|
release_parsed_uri( uri );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
hd->sock = connect_server( server, port, hd->flags, srvtag );
|
hd->sock = connect_server( server, port, hd->flags, srv );
|
||||||
|
|
||||||
if(auth || hd->uri->auth)
|
if(auth || hd->uri->auth)
|
||||||
{
|
{
|
||||||
@ -815,9 +815,9 @@ start_server(void)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
connect_server( const char *server, ushort port, unsigned int flags,
|
connect_server( const char *server, ushort port, unsigned int flags,
|
||||||
const char *srvtag )
|
struct http_srv *srv )
|
||||||
{
|
{
|
||||||
int sock=-1,srv,srvcount=0,connected=0,hostfound=0;
|
int sock=-1, srvindex, srvcount=0, connected=0, hostfound=0, chosen=-1;
|
||||||
struct srventry *srvlist=NULL;
|
struct srventry *srvlist=NULL;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -854,15 +854,15 @@ connect_server( const char *server, ushort port, unsigned int flags,
|
|||||||
|
|
||||||
#ifdef USE_DNS_SRV
|
#ifdef USE_DNS_SRV
|
||||||
/* Do the SRV thing */
|
/* Do the SRV thing */
|
||||||
if(srvtag)
|
if(srv && srv->srvtag)
|
||||||
{
|
{
|
||||||
/* We're using SRV, so append the tags */
|
/* We're using SRV, so append the tags */
|
||||||
if(1+strlen(srvtag)+6+strlen(server)+1<=MAXDNAME)
|
if(1+strlen(srv->srvtag)+6+strlen(server)+1<=MAXDNAME)
|
||||||
{
|
{
|
||||||
char srvname[MAXDNAME];
|
char srvname[MAXDNAME];
|
||||||
|
|
||||||
strcpy(srvname,"_");
|
strcpy(srvname,"_");
|
||||||
strcat(srvname,srvtag);
|
strcat(srvname,srv->srvtag);
|
||||||
strcat(srvname,"._tcp.");
|
strcat(srvname,"._tcp.");
|
||||||
strcat(srvname,server);
|
strcat(srvname,server);
|
||||||
srvcount=getsrv(srvname,&srvlist);
|
srvcount=getsrv(srvname,&srvlist);
|
||||||
@ -885,15 +885,15 @@ connect_server( const char *server, ushort port, unsigned int flags,
|
|||||||
|
|
||||||
#ifdef HAVE_GETADDRINFO
|
#ifdef HAVE_GETADDRINFO
|
||||||
|
|
||||||
for(srv=0;srv<srvcount;srv++)
|
for(srvindex=0;srvindex<srvcount;srvindex++)
|
||||||
{
|
{
|
||||||
struct addrinfo hints,*res,*ai;
|
struct addrinfo hints,*res,*ai;
|
||||||
char portstr[6];
|
char portstr[6];
|
||||||
|
|
||||||
sprintf(portstr,"%u",srvlist[srv].port);
|
sprintf(portstr,"%u",srvlist[srvindex].port);
|
||||||
memset(&hints,0,sizeof(hints));
|
memset(&hints,0,sizeof(hints));
|
||||||
hints.ai_socktype=SOCK_STREAM;
|
hints.ai_socktype=SOCK_STREAM;
|
||||||
if(getaddrinfo(srvlist[srv].target,portstr,&hints,&res)==0)
|
if(getaddrinfo(srvlist[srvindex].target,portstr,&hints,&res)==0)
|
||||||
hostfound=1;
|
hostfound=1;
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
@ -910,6 +910,7 @@ connect_server( const char *server, ushort port, unsigned int flags,
|
|||||||
if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
|
if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
|
||||||
{
|
{
|
||||||
connected=1;
|
connected=1;
|
||||||
|
chosen = srvindex;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -924,7 +925,7 @@ connect_server( const char *server, ushort port, unsigned int flags,
|
|||||||
|
|
||||||
#else /* !HAVE_GETADDRINFO */
|
#else /* !HAVE_GETADDRINFO */
|
||||||
|
|
||||||
for(srv=0;srv<srvcount;srv++)
|
for(srvindex=0; srvindex < srvcount; srv++)
|
||||||
{
|
{
|
||||||
int i=0;
|
int i=0;
|
||||||
struct hostent *host=NULL;
|
struct hostent *host=NULL;
|
||||||
@ -932,7 +933,7 @@ connect_server( const char *server, ushort port, unsigned int flags,
|
|||||||
|
|
||||||
memset(&addr,0,sizeof(addr));
|
memset(&addr,0,sizeof(addr));
|
||||||
|
|
||||||
if((host=gethostbyname(srvlist[srv].target))==NULL)
|
if((host=gethostbyname(srvlist[srvindex].target))==NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
hostfound=1;
|
hostfound=1;
|
||||||
@ -946,18 +947,18 @@ connect_server( const char *server, ushort port, unsigned int flags,
|
|||||||
addr.sin_family=host->h_addrtype;
|
addr.sin_family=host->h_addrtype;
|
||||||
if(addr.sin_family!=AF_INET)
|
if(addr.sin_family!=AF_INET)
|
||||||
{
|
{
|
||||||
log_error("%s: unknown address family\n",srvlist[srv].target);
|
log_error("%s: unknown address family\n",srvlist[srvindex].target);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr.sin_port=htons(srvlist[srv].port);
|
addr.sin_port=htons(srvlist[srvindex].port);
|
||||||
|
|
||||||
/* Try all A records until one responds. */
|
/* Try all A records until one responds. */
|
||||||
while(host->h_addr_list[i])
|
while(host->h_addr_list[i])
|
||||||
{
|
{
|
||||||
if(host->h_length!=4)
|
if(host->h_length!=4)
|
||||||
{
|
{
|
||||||
log_error("%s: illegal address length\n",srvlist[srv].target);
|
log_error("%s: illegal address length\n",srvlist[srvindex].target);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -966,6 +967,7 @@ connect_server( const char *server, ushort port, unsigned int flags,
|
|||||||
if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
|
if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
|
||||||
{
|
{
|
||||||
connected=1;
|
connected=1;
|
||||||
|
chosen = srvindex;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -979,6 +981,12 @@ connect_server( const char *server, ushort port, unsigned int flags,
|
|||||||
}
|
}
|
||||||
#endif /* !HAVE_GETADDRINFO */
|
#endif /* !HAVE_GETADDRINFO */
|
||||||
|
|
||||||
|
if(chosen>-1 && srv)
|
||||||
|
{
|
||||||
|
srv->used_server = strdup (srvlist[chosen].target);
|
||||||
|
srv->used_port = srvlist[chosen].port;
|
||||||
|
}
|
||||||
|
|
||||||
free(srvlist);
|
free(srvlist);
|
||||||
|
|
||||||
if(!connected)
|
if(!connected)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user