mirror of
https://github.com/status-im/miniupnp.git
synced 2025-02-20 17:58:19 +00:00
miniupnpc-async: work to support several devices.
This commit is contained in:
parent
e362e84e9e
commit
3e89381fba
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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 */,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user