miniupnpc: parseURL()/miniwget() : IPv6 addresses scope

This commit is contained in:
Thomas Bernard 2012-06-24 00:55:31 +02:00
parent 0e85a91784
commit c585986d2f
8 changed files with 92 additions and 44 deletions

View File

@ -4,6 +4,8 @@ miniUPnP client Changelog.
2012/06/23: 2012/06/23:
More error return checks in upnpc.c More error return checks in upnpc.c
#define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id
parseURL() now parses IPv6 addresses scope
new parameter for miniwget() : IPv6 address scope
increment API_VERSION to 9 increment API_VERSION to 9
2012/06/20: 2012/06/20:

View File

@ -1,4 +1,4 @@
/* $Id: connecthostport.c,v 1.6 2012/01/21 13:30:31 nanard Exp $ */ /* $Id: connecthostport.c,v 1.8 2012/06/23 22:32:33 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2010-2012 Thomas Bernard * Copyright (c) 2010-2012 Thomas Bernard
@ -52,7 +52,8 @@
/* connecthostport() /* connecthostport()
* return a socket connected (TCP) to the host and port * return a socket connected (TCP) to the host and port
* or -1 in case of error */ * or -1 in case of error */
int connecthostport(const char * host, unsigned short port) int connecthostport(const char * host, unsigned short port,
unsigned int scope_id)
{ {
int s, n; int s, n;
#ifdef USE_GETHOSTBYNAME #ifdef USE_GETHOSTBYNAME
@ -145,10 +146,12 @@ int connecthostport(const char * host, unsigned short port)
if(host[0] == '[') if(host[0] == '[')
{ {
/* literal ip v6 address */ /* literal ip v6 address */
int i; int i, j;
for(i = 0; host[i+1] && (host[i+1] != ']') && i < MAXHOSTNAMELEN; i++) for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++)
{ {
tmp_host[i] = host[i+1]; tmp_host[i] = host[j];
if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */
j+=2; /* skip "25" */
} }
tmp_host[i] = '\0'; tmp_host[i] = '\0';
} }
@ -173,6 +176,10 @@ int connecthostport(const char * host, unsigned short port)
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if(s < 0) if(s < 0)
continue; continue;
if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) {
struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr;
addr6->sin6_scope_id = scope_id;
}
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
/* setting a 3 seconds timeout for the connect() call */ /* setting a 3 seconds timeout for the connect() call */
timeout.tv_sec = 3; timeout.tv_sec = 3;

View File

@ -1,8 +1,8 @@
/* $Id: connecthostport.h,v 1.1 2010/04/04 23:21:03 nanard Exp $ */ /* $Id: connecthostport.h,v 1.2 2012/06/23 22:32:33 nanard Exp $ */
/* Project: miniupnp /* Project: miniupnp
* http://miniupnp.free.fr/ * http://miniupnp.free.fr/
* Author: Thomas Bernard * Author: Thomas Bernard
* Copyright (c) 2010 Thomas Bernard * Copyright (c) 2010-2012 Thomas Bernard
* This software is subjects to the conditions detailed * This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */ * in the LICENCE file provided within this distribution */
#ifndef __CONNECTHOSTPORT_H__ #ifndef __CONNECTHOSTPORT_H__
@ -11,7 +11,8 @@
/* connecthostport() /* connecthostport()
* return a socket connected (TCP) to the host and port * return a socket connected (TCP) to the host and port
* or -1 in case of error */ * or -1 in case of error */
int connecthostport(const char * host, unsigned short port); int connecthostport(const char * host, unsigned short port,
unsigned int scope_id);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $Id: miniupnpc.c,v 1.106 2012/06/11 16:08:17 nanard Exp $ */ /* $Id: miniupnpc.c,v 1.107 2012/06/23 22:36:35 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Web : http://miniupnp.free.fr/ * Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD * Author : Thomas BERNARD
@ -189,12 +189,11 @@ char * simpleUPnPcommand2(int s, const char * url, const char * service,
strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
soapbody + sizeof(soapbody) - p); soapbody + sizeof(soapbody) - p);
} }
if(!parseURL(url, hostname, &port, &path)) return NULL; if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
if(s<0) if(s < 0) {
{ s = connecthostport(hostname, port, 0);
s = connecthostport(hostname, port); if(s < 0) {
if(s < 0) /* failed to connect */
{
return NULL; return NULL;
} }
} }
@ -686,6 +685,7 @@ upnpDiscover(int delay, const char * multicastif,
tmp->buffer[urlsize] = '\0'; tmp->buffer[urlsize] = '\0';
memcpy(tmp->buffer + urlsize + 1, st, stsize); memcpy(tmp->buffer + urlsize + 1, st, stsize);
tmp->buffer[urlsize+1+stsize] = '\0'; tmp->buffer[urlsize+1+stsize] = '\0';
tmp->scope_id = scope_id;
devlist = tmp; devlist = tmp;
} }
} }
@ -873,7 +873,8 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
if(state == 1) if(state == 1)
{ {
desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
lanaddr, lanaddrlen); lanaddr, lanaddrlen,
dev->scope_id);
#ifdef DEBUG #ifdef DEBUG
if(!desc[i].xml) if(!desc[i].xml)
{ {
@ -944,7 +945,7 @@ UPNP_GetIGDFromUrl(const char * rootdescurl,
char * descXML; char * descXML;
int descXMLsize = 0; int descXMLsize = 0;
descXML = miniwget_getaddr(rootdescurl, &descXMLsize, descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
lanaddr, lanaddrlen); lanaddr, lanaddrlen, 0);
if(descXML) { if(descXML) {
memset(data, 0, sizeof(struct IGDdatas)); memset(data, 0, sizeof(struct IGDdatas));
memset(urls, 0, sizeof(struct UPNPUrls)); memset(urls, 0, sizeof(struct UPNPUrls));

View File

@ -37,6 +37,7 @@ struct UPNPDev {
struct UPNPDev * pNext; struct UPNPDev * pNext;
char * descURL; char * descURL;
char * st; char * st;
unsigned int scope_id;
char buffer[2]; char buffer[2];
}; };

View File

@ -1,4 +1,4 @@
/* $Id: miniwget.c,v 1.56 2012/05/01 16:16:08 nanard Exp $ */ /* $Id: miniwget.c,v 1.57 2012/06/23 22:35:58 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Website : http://miniupnp.free.fr/ * Website : http://miniupnp.free.fr/
* Author : Thomas Bernard * Author : Thomas Bernard
@ -36,6 +36,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <net/if.h>
#include <netdb.h> #include <netdb.h>
#define closesocket close #define closesocket close
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions /* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
@ -289,7 +290,7 @@ static void *
miniwget3(const char * host, miniwget3(const char * host,
unsigned short port, const char * path, unsigned short port, const char * path,
int * size, char * addr_str, int addr_str_len, int * size, char * addr_str, int addr_str_len,
const char * httpversion) const char * httpversion, unsigned int scope_id)
{ {
char buf[2048]; char buf[2048];
int s; int s;
@ -299,7 +300,7 @@ miniwget3(const char * host,
void * content; void * content;
*size = 0; *size = 0;
s = connecthostport(host, port); s = connecthostport(host, port, scope_id);
if(s < 0) if(s < 0)
return NULL; return NULL;
@ -392,22 +393,27 @@ miniwget3(const char * host,
static void * static void *
miniwget2(const char * host, miniwget2(const char * host,
unsigned short port, const char * path, unsigned short port, const char * path,
int * size, char * addr_str, int addr_str_len) int * size, char * addr_str, int addr_str_len,
unsigned int scope_id)
{ {
char * respbuffer; char * respbuffer;
respbuffer = miniwget3(host, port, path, size, addr_str, addr_str_len, "1.1"); #if 1
/* respbuffer = miniwget3(host, port, path, size,
respbuffer = miniwget3(host, port, path, size, addr_str, addr_str_len, "1.0"); addr_str, addr_str_len, "1.1", scope_id);
#else
respbuffer = miniwget3(host, port, path, size,
addr_str, addr_str_len, "1.0", scope_id);
if (*size == 0) if (*size == 0)
{ {
#ifdef DEBUG #ifdef DEBUG
printf("Retrying with HTTP/1.1\n"); printf("Retrying with HTTP/1.1\n");
#endif #endif
free(respbuffer); free(respbuffer);
respbuffer = miniwget3(host, port, path, size, addr_str, addr_str_len, "1.1"); respbuffer = miniwget3(host, port, path, size,
addr_str, addr_str_len, "1.1", scope_id);
} }
*/ #endif
return respbuffer; return respbuffer;
} }
@ -424,7 +430,10 @@ miniwget2(const char * host,
* Return values : * Return values :
* 0 - Failure * 0 - Failure
* 1 - Success */ * 1 - Success */
int parseURL(const char * url, char * hostname, unsigned short * port, char * * path) int
parseURL(const char * url,
char * hostname, unsigned short * port,
char * * path, unsigned int * scope_id)
{ {
char * p1, *p2, *p3; char * p1, *p2, *p3;
if(!url) if(!url)
@ -440,7 +449,29 @@ int parseURL(const char * url, char * hostname, unsigned short * port, char * *
if(*p1 == '[') if(*p1 == '[')
{ {
/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */
char * scope;
scope = strchr(p1, '%');
p2 = strchr(p1, ']'); p2 = strchr(p1, ']');
if(p2 && scope && scope < p2 && scope_id) {
/* parse scope */
#ifdef IF_NAMESIZE
char tmp[IF_NAMESIZE];
int l;
scope++;
/* "%25" is just '%' in URL encoding */
if(scope[0] == '2' && scope[1] == '5')
scope += 2; /* skip "25" */
l = p2 - scope;
if(l >= IF_NAMESIZE)
l = IF_NAMESIZE - 1;
memcpy(tmp, scope, l);
tmp[l] = '\0';
*scope_id = if_nametoindex(tmp);
if(*scope_id == 0) {
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
}
#endif
}
p3 = strchr(p1, '/'); p3 = strchr(p1, '/');
if(p2 && p3) if(p2 && p3)
{ {
@ -490,22 +521,26 @@ int parseURL(const char * url, char * hostname, unsigned short * port, char * *
return 1; return 1;
} }
void * miniwget(const char * url, int * size) void *
miniwget(const char * url, int * size, unsigned int scope_id)
{ {
unsigned short port; unsigned short port;
char * path; char * path;
/* protocol://host:port/chemin */ /* protocol://host:port/chemin */
char hostname[MAXHOSTNAMELEN+1]; char hostname[MAXHOSTNAMELEN+1];
*size = 0; *size = 0;
if(!parseURL(url, hostname, &port, &path)) if(!parseURL(url, hostname, &port, &path, &scope_id))
return NULL; return NULL;
#ifdef DEBUG #ifdef DEBUG
printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
hostname, port, path, scope_id);
#endif #endif
return miniwget2(hostname, port, path, size, 0, 0); return miniwget2(hostname, port, path, size, 0, 0, scope_id);
} }
void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen) void *
miniwget_getaddr(const char * url, int * size,
char * addr, int addrlen, unsigned int scope_id)
{ {
unsigned short port; unsigned short port;
char * path; char * path;
@ -514,11 +549,12 @@ void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen)
*size = 0; *size = 0;
if(addr) if(addr)
addr[0] = '\0'; addr[0] = '\0';
if(!parseURL(url, hostname, &port, &path)) if(!parseURL(url, hostname, &port, &path, &scope_id))
return NULL; return NULL;
#ifdef DEBUG #ifdef DEBUG
printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
hostname, port, path, scope_id);
#endif #endif
return miniwget2(hostname, port, path, size, addr, addrlen); return miniwget2(hostname, port, path, size, addr, addrlen, scope_id);
} }

View File

@ -1,7 +1,7 @@
/* $Id: miniwget.h,v 1.6 2010/12/09 16:11:33 nanard Exp $ */ /* $Id: miniwget.h,v 1.7 2012/06/23 22:35:59 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005 Thomas Bernard * Copyright (c) 2005-2012 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
@ -16,11 +16,11 @@ extern "C" {
LIBSPEC void * getHTTPResponse(int s, int * size); LIBSPEC void * getHTTPResponse(int s, int * size);
LIBSPEC void * miniwget(const char *, int *); LIBSPEC void * miniwget(const char *, int *, unsigned int);
LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int); LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int);
int parseURL(const char *, char *, unsigned short *, char * *); int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,7 +1,7 @@
/* $Id: testminiwget.c,v 1.3 2011/05/06 16:33:53 nanard Exp $ */ /* $Id: testminiwget.c,v 1.4 2012/06/23 22:35:59 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2011 Thomas Bernard * Copyright (c) 2005-2012 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
@ -20,13 +20,13 @@ int main(int argc, char * * argv)
int size, writtensize; int size, writtensize;
FILE *f; FILE *f;
char addr[64]; char addr[64];
if(argc < 3) { if(argc < 3) {
fprintf(stderr, "Usage:\t%s url file\n", argv[0]); fprintf(stderr, "Usage:\t%s url file\n", argv[0]);
fprintf(stderr, "Example:\t%s http://www.google.com/ out.html\n", argv[0]); fprintf(stderr, "Example:\t%s http://www.google.com/ out.html\n", argv[0]);
return 1; return 1;
} }
/*data = miniwget(argv[1], &size);*/ data = miniwget_getaddr(argv[1], &size, addr, sizeof(addr), 0);
data = miniwget_getaddr(argv[1], &size, addr, sizeof(addr));
if(!data) { if(!data) {
fprintf(stderr, "Error fetching %s\n", argv[1]); fprintf(stderr, "Error fetching %s\n", argv[1]);
return 1; return 1;