miniupnpc-async: work to support several devices.

This commit is contained in:
Thomas Bernard 2017-05-19 17:45:26 +02:00
parent e362e84e9e
commit 3e89381fba
3 changed files with 186 additions and 94 deletions

View File

@ -1,6 +1,6 @@
/* $Id: miniupnpc-async.c,v 1.19 2014/11/07 12:05:40 nanard Exp $ */ /* $Id: miniupnpc-async.c,v 1.19 2014/11/07 12:05:40 nanard Exp $ */
/* miniupnpc-async /* miniupnpc-async
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr> * Copyright (c) 2008-2017, Thomas BERNARD <miniupnp@free.fr>
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
@ -72,8 +72,8 @@ struct upnp_args {
/* private functions */ /* private functions */
static int upnpc_connect(upnpc_t * p, const char * url); static int upnpc_connect(upnpc_device_t * p, const char * url);
static int upnpc_send_request(upnpc_t * p); static int upnpc_send_request(upnpc_device_t * p);
/* parse_msearch_reply() /* parse_msearch_reply()
@ -83,8 +83,8 @@ static int upnpc_send_request(upnpc_t * p);
* The strings are NOT null terminated */ * The strings are NOT null terminated */
static void static void
parse_msearch_reply(const char * reply, int size, parse_msearch_reply(const char * reply, int size,
const char * * location, int * locationsize, const char * * location, unsigned int * locationsize,
const char * * st, int * stsize) const char * * st, unsigned int * stsize)
{ {
int a, b, i; int a, b, i;
i = 0; /* current character index */ i = 0; /* current character index */
@ -157,16 +157,16 @@ static int upnpc_send_ssdp_msearch(upnpc_t * p, const char * device, unsigned in
return 0; return 0;
} }
static int upnpc_set_root_desc_location(upnpc_t * p, const char * location, int locationsize) static int upnpc_set_root_desc_location(upnpc_device_t * d, const char * location, int locationsize)
{ {
char * tmp; char * tmp;
tmp = realloc(p->root_desc_location, locationsize + 1); tmp = realloc(d->root_desc_location, locationsize + 1);
if(tmp == 0) { if(tmp == 0) {
return -1; return -1;
} }
memcpy(tmp, location, locationsize); memcpy(tmp, location, locationsize);
tmp[locationsize] = '\0'; tmp[locationsize] = '\0';
p->root_desc_location = tmp; d->root_desc_location = tmp;
return 0; return 0;
} }
@ -181,20 +181,38 @@ static int upnpc_receive_and_parse_ssdp(upnpc_t * p)
debug_printf("empty packet received\n"); debug_printf("empty packet received\n");
} else { } else {
const char * location = NULL; const char * location = NULL;
int locationsize; unsigned int locationsize;
const char * st = NULL; const char * st = NULL;
int stsize; unsigned int stsize;
debug_printf("%.*s", n, bufr); debug_printf("%.*s", n, bufr);
parse_msearch_reply(bufr, n, &location, &locationsize, &st, &stsize); parse_msearch_reply(bufr, n, &location, &locationsize, &st, &stsize);
debug_printf("location = '%.*s'\n", locationsize, location); debug_printf("location = '%.*s'\n", locationsize, location);
debug_printf("st = '%.*s'\n", stsize, st); debug_printf("st = '%.*s'\n", stsize, st);
if(location != NULL) { if(location != NULL) {
if(upnpc_set_root_desc_location(p, location, locationsize) < 0) { upnpc_device_t * dev = p->device_list;
while(dev != NULL) {
if(dev->root_desc_location != NULL
&& strlen(dev->root_desc_location) == locationsize
&& memcmp(dev->root_desc_location, location, locationsize) == 0) {
debug_printf("device already in list (location='%s')\n", dev->root_desc_location);
return -1;
}
dev = dev->next;
}
dev = calloc(1, sizeof(upnpc_device_t));
if(dev == NULL) {
p->state = EError; p->state = EError;
return -1; return -1;
} }
p->state = EGetDescConnect; if(upnpc_set_root_desc_location(dev, location, locationsize) < 0) {
upnpc_connect(p, p->root_desc_location); free(dev);
p->state = EError;
return -1;
}
dev->next = p->device_list;
p->device_list = dev;
dev->state = EGetDescConnect;
upnpc_connect(dev, dev->root_desc_location);
} else { } else {
/* or do nothing ? */ /* or do nothing ? */
p->state = EError; p->state = EError;
@ -298,7 +316,7 @@ parseURL(const char * url,
return 1; return 1;
} }
static int upnpc_connect(upnpc_t * p, const char * url) static int upnpc_connect(upnpc_device_t * p, const char * url)
{ {
int r; int r;
char hostname[MAXHOSTNAMELEN+1]; char hostname[MAXHOSTNAMELEN+1];
@ -308,10 +326,10 @@ static int upnpc_connect(upnpc_t * p, const char * url)
struct sockaddr_in addr; struct sockaddr_in addr;
socklen_t addrlen; socklen_t addrlen;
if(p->root_desc_location == 0) { /*if(p->root_desc_location == 0) {
p->state = EError; p->state = EError;
return -1; return -1;
} }*/
if(!parseURL(url/*p->root_desc_location*/, hostname, &port, if(!parseURL(url/*p->root_desc_location*/, hostname, &port,
&path, &scope_id)) { &path, &scope_id)) {
p->state = EError; p->state = EError;
@ -353,7 +371,7 @@ static int upnpc_connect(upnpc_t * p, const char * url)
return 0; return 0;
} }
static int upnpc_complete_connect(upnpc_t * p) static int upnpc_complete_connect(upnpc_device_t * p)
{ {
socklen_t len; socklen_t len;
int err; int err;
@ -376,7 +394,7 @@ static int upnpc_complete_connect(upnpc_t * p)
return 0; return 0;
} }
static int upnpc_send_request(upnpc_t * p) static int upnpc_send_request(upnpc_device_t * p)
{ {
ssize_t n; ssize_t n;
static const char reqfmt[] = "GET %s HTTP/1.1\r\n" static const char reqfmt[] = "GET %s HTTP/1.1\r\n"
@ -440,7 +458,7 @@ static int upnpc_send_request(upnpc_t * p)
return 0; return 0;
} }
static int upnpc_parse_headers(upnpc_t * p) static int upnpc_parse_headers(upnpc_device_t * p)
{ {
/* search for CR LF CR LF (end of headers) /* search for CR LF CR LF (end of headers)
* recognize also LF LF */ * recognize also LF LF */
@ -547,7 +565,7 @@ static char * build_url_string(const char * urlbase, const char * root_desc_url,
return s; return s;
} }
static int upnpc_get_response(upnpc_t * p) static int upnpc_get_response(upnpc_device_t * p)
{ {
ssize_t n; ssize_t n;
ssize_t count; ssize_t count;
@ -643,7 +661,7 @@ static int upnpc_get_response(upnpc_t * p)
#define SERVICEPREFIX "u" #define SERVICEPREFIX "u"
#define SERVICEPREFIX2 'u' #define SERVICEPREFIX2 'u'
static int upnpc_build_soap_request(upnpc_t * p, const char * url, static int upnpc_build_soap_request(upnpc_device_t * p, const char * url,
const char * service, const char * service,
const char * action, const char * action,
const struct upnp_args * args, int arg_count) const struct upnp_args * args, int arg_count)
@ -789,30 +807,35 @@ int upnpc_init(upnpc_t * p, const char * multicastif)
int upnpc_finalize(upnpc_t * p) int upnpc_finalize(upnpc_t * p)
{ {
if(!p) return UPNPC_ERR_INVALID_ARGS; if(!p) return UPNPC_ERR_INVALID_ARGS;
free(p->root_desc_location);
p->root_desc_location = NULL;
free(p->http_request);
p->http_request = NULL;
free(p->http_response);
p->http_response = NULL;
free(p->control_cif_url);
p->control_cif_url = NULL;
free(p->control_conn_url);
p->control_conn_url = NULL;
if(p->ssdp_socket >= 0) { if(p->ssdp_socket >= 0) {
close(p->ssdp_socket); close(p->ssdp_socket);
p->ssdp_socket = -1; p->ssdp_socket = -1;
} }
if(p->http_socket >= 0) { while(p->device_list) {
close(p->http_socket); upnpc_device_t * next = p->device_list->next;
p->http_socket = -1; free(p->device_list->root_desc_location);
p->device_list->root_desc_location = NULL;
free(p->device_list->http_request);
p->device_list->http_request = NULL;
free(p->device_list->http_response);
p->device_list->http_response = NULL;
free(p->device_list->control_cif_url);
p->device_list->control_cif_url = NULL;
free(p->device_list->control_conn_url);
p->device_list->control_conn_url = NULL;
if(p->device_list->http_socket >= 0) {
close(p->device_list->http_socket);
p->device_list->http_socket = -1;
}
ClearNameValueList(&p->device_list->soap_response_data);
free(p->device_list);
p->device_list = next;
} }
ClearNameValueList(&p->soap_response_data);
p->state = EFinalized; p->state = EFinalized;
return UPNPC_OK; return UPNPC_OK;
} }
int upnpc_get_external_ip_address(upnpc_t * p) int upnpc_get_external_ip_address(upnpc_device_t * p)
{ {
upnpc_build_soap_request(p, p->control_conn_url, upnpc_build_soap_request(p, p->control_conn_url,
"urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANIPConnection:1",
@ -822,7 +845,7 @@ int upnpc_get_external_ip_address(upnpc_t * p)
return 0; return 0;
} }
int upnpc_get_link_layer_max_rate(upnpc_t * p) int upnpc_get_link_layer_max_rate(upnpc_device_t * p)
{ {
upnpc_build_soap_request(p, p->control_cif_url, upnpc_build_soap_request(p, p->control_cif_url,
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1", "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
@ -832,7 +855,7 @@ int upnpc_get_link_layer_max_rate(upnpc_t * p)
return 0; return 0;
} }
int upnpc_add_port_mapping(upnpc_t * p, int upnpc_add_port_mapping(upnpc_device_t * p,
const char * remote_host, unsigned short ext_port, const char * remote_host, unsigned short ext_port,
unsigned short int_port, const char * int_client, unsigned short int_port, const char * int_client,
const char * proto, const char * description, const char * proto, const char * description,
@ -876,8 +899,32 @@ int upnpc_add_port_mapping(upnpc_t * p,
#ifdef UPNPC_USE_SELECT #ifdef UPNPC_USE_SELECT
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds) int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds)
{ {
upnpc_device_t * d;
int n = 0; int n = 0;
if(!p) return UPNPC_ERR_INVALID_ARGS; if(!p) return UPNPC_ERR_INVALID_ARGS;
for(d = p->device_list; d != NULL; d = d->next) {
switch(d->state) {
case EGetDescConnect:
case EGetDescRequest:
case ESoapConnect:
case ESoapRequest:
FD_SET(d->http_socket, writefds);
if(*nfds < d->http_socket)
*nfds = d->http_socket;
n++;
break;
case EGetDescResponse:
case ESoapResponse:
FD_SET(d->http_socket, readfds);
if(*nfds < d->http_socket)
*nfds = d->http_socket;
n++;
break;
default:
break;
}
}
switch(p->state) { switch(p->state) {
case ESendSSDP: case ESendSSDP:
FD_SET(p->ssdp_socket, writefds); FD_SET(p->ssdp_socket, writefds);
@ -886,32 +933,35 @@ int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefd
n++; n++;
break; break;
case EReceiveSSDP: case EReceiveSSDP:
default:
/* still receive SSDP responses when processing Description, etc. */
FD_SET(p->ssdp_socket, readfds); FD_SET(p->ssdp_socket, readfds);
if(*nfds < p->ssdp_socket) if(*nfds < p->ssdp_socket)
*nfds = p->ssdp_socket; *nfds = p->ssdp_socket;
n++; n++;
break; break;
case EGetDescConnect:
case EGetDescRequest:
case ESoapConnect:
case ESoapRequest:
FD_SET(p->http_socket, writefds);
if(*nfds < p->http_socket)
*nfds = p->http_socket;
n++;
break;
case EGetDescResponse:
case ESoapResponse:
FD_SET(p->http_socket, readfds);
if(*nfds < p->http_socket)
*nfds = p->http_socket;
n++;
break;
default:
return 0;
} }
return n; return n;
} }
void upnpc_check_select_fds(upnpc_t * p, const fd_set * readfds, const fd_set * writefds)
{
upnpc_device_t * d;
p->socket_flags = 0;
if(FD_ISSET(p->ssdp_socket, readfds))
p->socket_flags = UPNPC_SSDP_READABLE;
if(FD_ISSET(p->ssdp_socket, writefds))
p->socket_flags = UPNPC_SSDP_WRITEABLE;
for(d = p->device_list; d != NULL; d = d->next) {
d->socket_flags = 0;
if(FD_ISSET(d->http_socket, readfds))
d->socket_flags = UPNPC_HTTP_READABLE;
if(FD_ISSET(d->http_socket, writefds))
d->socket_flags = UPNPC_HTTP_WRITEABLE;
}
}
#endif #endif
static const char * devices_to_search[] = { static const char * devices_to_search[] = {
@ -924,6 +974,7 @@ static const char * devices_to_search[] = {
int upnpc_process(upnpc_t * p) int upnpc_process(upnpc_t * p)
{ {
upnpc_device_t * d;
/* /*
1) Envoyer les paquets de discovery SSDP 1) Envoyer les paquets de discovery SSDP
2) Recevoir et traiter les reponses 2) Recevoir et traiter les reponses
@ -931,7 +982,36 @@ int upnpc_process(upnpc_t * p)
4) tester les etats 4) tester les etats
*/ */
if(!p) return UPNPC_ERR_INVALID_ARGS; if(!p) return UPNPC_ERR_INVALID_ARGS;
debug_printf("state=%d\n", (int)p->state); debug_printf("state=%d socket_flags=0x%04x\n", (int)p->state, p->socket_flags);
for(d = p->device_list; d != NULL; d = d->next) {
switch(d->state) {
case EGetDescConnect:
case ESoapConnect:
upnpc_complete_connect(d);
break;
case EGetDescRequest:
case ESoapRequest:
upnpc_send_request(d);
break;
case EGetDescResponse:
case ESoapResponse:
upnpc_get_response(d);
break;
default:
break;
}
}
/* all devices ready => ready */
if(p->device_list != NULL) {
d = p->device_list;
while(d && d->state == EReady) d = d->next;
p->state = (d == NULL) ? EReady : EProcessing;
}
if(p->socket_flags & UPNPC_SSDP_READABLE) {
upnpc_receive_and_parse_ssdp(p);
}
switch(p->state) { switch(p->state) {
case EInit: case EInit:
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2); upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
@ -940,22 +1020,13 @@ int upnpc_process(upnpc_t * p)
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2); upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
break; break;
case EReceiveSSDP: case EReceiveSSDP:
upnpc_receive_and_parse_ssdp(p); /*upnpc_receive_and_parse_ssdp(p);*/
break; break;
/*case EGetDesc: /*case EGetDesc:
upnpc_connect(p); upnpc_connect(p);
break;*/ break;*/
case EGetDescConnect: case EReady:
case ESoapConnect: case EProcessing:
upnpc_complete_connect(p);
break;
case EGetDescRequest:
case ESoapRequest:
upnpc_send_request(p);
break;
case EGetDescResponse:
case ESoapResponse:
upnpc_get_response(p);
break; break;
default: default:
return UPNPC_ERR_UNKNOWN_STATE; return UPNPC_ERR_UNKNOWN_STATE;

View File

@ -1,6 +1,6 @@
/* $Id: miniupnpc-async.h,v 1.13 2014/11/07 11:25:52 nanard Exp $ */ /* $Id: miniupnpc-async.h,v 1.13 2014/11/07 11:25:52 nanard Exp $ */
/* miniupnpc-async /* miniupnpc-async
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr> * Copyright (c) 2008-2017, Thomas BERNARD <miniupnp@free.fr>
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
@ -30,12 +30,15 @@ extern "C" {
#define UPNPC_ERR_BIND_FAILED (-3) #define UPNPC_ERR_BIND_FAILED (-3)
#define UPNPC_ERR_UNKNOWN_STATE (-4) #define UPNPC_ERR_UNKNOWN_STATE (-4)
typedef struct { #define UPNPC_SSDP_READABLE 0x0001
#define UPNPC_SSDP_WRITEABLE 0x0100
#define UPNPC_HTTP_READABLE 0x0002
#define UPNPC_HTTP_WRITEABLE 0x0200
typedef struct upnpc_device {
struct upnpc_device * next;
enum { enum {
EInit = 1, EInit = 1,
ESendSSDP,
EReceiveSSDP,
/*EGetDesc,*/
EGetDescConnect, EGetDescConnect,
EGetDescRequest, EGetDescRequest,
EGetDescResponse, EGetDescResponse,
@ -46,9 +49,11 @@ typedef struct {
EFinalized = 99, EFinalized = 99,
EError = 1000 EError = 1000
} state; } state;
int ssdp_socket;
char * root_desc_location; char * root_desc_location;
char * control_cif_url;
char * control_conn_url;
int http_socket; int http_socket;
int socket_flags; /* see UPNPC_*_READABLE, etc. */
char * http_request; char * http_request;
int http_request_len; int http_request_len;
int http_request_sent; int http_request_sent;
@ -58,20 +63,34 @@ typedef struct {
int http_response_content_length; int http_response_content_length;
int http_response_chunked; int http_response_chunked;
int http_response_code; int http_response_code;
char * control_cif_url;
char * control_conn_url;
struct NameValueParserData soap_response_data; struct NameValueParserData soap_response_data;
} upnpc_device_t;
typedef struct {
enum {
EInit = 1,
ESendSSDP,
EReceiveSSDP,
EGetDesc,
EReady,
EProcessing,
EFinalized = 99,
EError = 1000
} state;
int socket_flags; /* see UPNPC_*_READABLE, etc. */
int ssdp_socket;
upnpc_device_t * device_list;
} upnpc_t; } upnpc_t;
int upnpc_init(upnpc_t * p, const char * multicastif); int upnpc_init(upnpc_t * p, const char * multicastif);
int upnpc_finalize(upnpc_t * p); int upnpc_finalize(upnpc_t * p);
int upnpc_get_external_ip_address(upnpc_t * p); int upnpc_get_external_ip_address(upnpc_device_t * p);
int upnpc_get_link_layer_max_rate(upnpc_t * p); int upnpc_get_link_layer_max_rate(upnpc_device_t * p);
int upnpc_add_port_mapping(upnpc_t * p, int upnpc_add_port_mapping(upnpc_device_t * p,
const char * remote_host, unsigned short ext_port, const char * remote_host, unsigned short ext_port,
unsigned short int_port, const char * int_client, unsigned short int_port, const char * int_client,
const char * proto, const char * description, const char * proto, const char * description,
@ -79,6 +98,7 @@ int upnpc_add_port_mapping(upnpc_t * p,
#ifdef UPNPC_USE_SELECT #ifdef UPNPC_USE_SELECT
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds); int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds);
void upnpc_check_select_fds(upnpc_t * p, const fd_set * readfds, const fd_set * writefds);
#endif /* UPNPC_USE_SELECT */ #endif /* UPNPC_USE_SELECT */
int upnpc_process(upnpc_t * p); int upnpc_process(upnpc_t * p);

View File

@ -1,6 +1,6 @@
/* $Id: testasync.c,v 1.14 2014/11/07 12:07:38 nanard Exp $ */ /* $Id: testasync.c,v 1.14 2014/11/07 12:07:38 nanard Exp $ */
/* miniupnpc-async /* miniupnpc-async
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr> * Copyright (c) 2008-2017, Thomas BERNARD <miniupnp@free.fr>
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
@ -43,7 +43,7 @@ int main(int argc, char * * argv)
} }
r = upnpc_process(&upnp); r = upnpc_process(&upnp);
printf("upnpc_process returned %d\n", r); printf("upnpc_process returned %d\n", r);
while((upnp.state != EReady) && (upnp.state != EError)) { while(upnp.state != EError) {
int nfds; int nfds;
fd_set readfds; fd_set readfds;
fd_set writefds; fd_set writefds;
@ -68,6 +68,7 @@ int main(int argc, char * * argv)
perror("select"); perror("select");
return 1; return 1;
} }
upnpc_check_select_fds(&upnp, &readfds, &writefds);
r = upnpc_process(&upnp); r = upnpc_process(&upnp);
#if DEBUG #if DEBUG
printf("upnpc_process returned %d\n", r); printf("upnpc_process returned %d\n", r);
@ -76,18 +77,18 @@ int main(int argc, char * * argv)
break; break;
if(upnp.state == EReady) { if(upnp.state == EReady) {
char * p; char * p;
printf("Process UPnP IGD Method results : HTTP %d\n", upnp.http_response_code); printf("Process UPnP IGD Method results : HTTP %d\n", upnp.device_list->http_response_code); /* XXX */
if(upnp.http_response_code == 200) { if(upnp.device_list->http_response_code == 200) {
switch(last_method) { switch(last_method) {
case EGetExternalIP: case EGetExternalIP:
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewExternalIPAddress"); p = GetValueFromNameValueList(&upnp.device_list->soap_response_data, "NewExternalIPAddress");
printf("ExternalIPAddress = %s\n", p); printf("ExternalIPAddress = %s\n", p);
/* p = GetValueFromNameValueList(&pdata, "errorCode");*/ /* p = GetValueFromNameValueList(&pdata, "errorCode");*/
break; break;
case EGetRates: case EGetRates:
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewLayer1DownstreamMaxBitRate"); p = GetValueFromNameValueList(&upnp.device_list->soap_response_data, "NewLayer1DownstreamMaxBitRate");
printf("DownStream MaxBitRate = %s\t", p); printf("DownStream MaxBitRate = %s\t", p);
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewLayer1UpstreamMaxBitRate"); p = GetValueFromNameValueList(&upnp.device_list->soap_response_data, "NewLayer1UpstreamMaxBitRate");
printf("UpStream MaxBitRate = %s\n", p); printf("UpStream MaxBitRate = %s\n", p);
break; break;
case EAddPortMapping: case EAddPortMapping:
@ -98,10 +99,10 @@ int main(int argc, char * * argv)
} }
} else { } else {
printf("SOAP error :\n"); printf("SOAP error :\n");
printf(" faultcode='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "faultcode")); printf(" faultcode='%s'\n", GetValueFromNameValueList(&upnp.device_list->soap_response_data, "faultcode"));
printf(" faultstring='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "faultstring")); printf(" faultstring='%s'\n", GetValueFromNameValueList(&upnp.device_list->soap_response_data, "faultstring"));
printf(" errorCode=%s\n", GetValueFromNameValueList(&upnp.soap_response_data, "errorCode")); printf(" errorCode=%s\n", GetValueFromNameValueList(&upnp.device_list->soap_response_data, "errorCode"));
printf(" errorDescription='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "errorDescription")); printf(" errorDescription='%s'\n", GetValueFromNameValueList(&upnp.device_list->soap_response_data, "errorDescription"));
} }
if(next_method_to_call == ENothing) if(next_method_to_call == ENothing)
break; break;
@ -110,17 +111,17 @@ int main(int argc, char * * argv)
switch(next_method_to_call) { switch(next_method_to_call) {
case EGetExternalIP: case EGetExternalIP:
printf("GetExternalIPAddress\n"); printf("GetExternalIPAddress\n");
upnpc_get_external_ip_address(&upnp); upnpc_get_external_ip_address(upnp.device_list);
next_method_to_call = EGetRates; next_method_to_call = EGetRates;
break; break;
case EGetRates: case EGetRates:
printf("GetCommonLinkProperties\n"); printf("GetCommonLinkProperties\n");
upnpc_get_link_layer_max_rate(&upnp); upnpc_get_link_layer_max_rate(upnp.device_list);
next_method_to_call = EAddPortMapping; next_method_to_call = EAddPortMapping;
break; break;
case EAddPortMapping: case EAddPortMapping:
printf("AddPortMapping\n"); printf("AddPortMapping\n");
upnpc_add_port_mapping(&upnp, upnpc_add_port_mapping(upnp.device_list, /* XXX */
NULL /* remote_host */, 40002 /* ext_port */, NULL /* remote_host */, 40002 /* ext_port */,
42042 /* int_port */, "192.168.1.202" /* int_client */, 42042 /* int_port */, "192.168.1.202" /* int_client */,
"TCP" /* proto */, "this is a test" /* description */, "TCP" /* proto */, "this is a test" /* description */,