mupnp 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +13 -0
- data/Rakefile +80 -0
- data/ext/Changelog.txt +188 -0
- data/ext/LICENSE +27 -0
- data/ext/README +53 -0
- data/ext/declspec.h +15 -0
- data/ext/extconf.rb +5 -0
- data/ext/igd_desc_parse.c +115 -0
- data/ext/igd_desc_parse.h +38 -0
- data/ext/minisoap.c +112 -0
- data/ext/minisoap.h +15 -0
- data/ext/minissdpc.c +107 -0
- data/ext/minissdpc.h +15 -0
- data/ext/miniupnpc.c +751 -0
- data/ext/miniupnpc.h +108 -0
- data/ext/miniwget.c +219 -0
- data/ext/miniwget.h +28 -0
- data/ext/minixml.c +191 -0
- data/ext/minixml.h +37 -0
- data/ext/upnp.i +13 -0
- data/ext/upnp_wrap.c +5207 -0
- data/ext/upnpcommands.c +569 -0
- data/ext/upnpcommands.h +179 -0
- data/ext/upnperrors.c +55 -0
- data/ext/upnperrors.h +16 -0
- data/ext/upnpreplyparse.c +127 -0
- data/ext/upnpreplyparse.h +62 -0
- data/lib/UPnP.rb +400 -0
- data/test/UPnP/tc_upnp.rb +20 -0
- metadata +83 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
/* $Id: igd_desc_parse.h,v 1.5 2007/04/11 15:21:09 nanard Exp $ */
|
2
|
+
/* Project : miniupnp
|
3
|
+
* http://miniupnp.free.fr/
|
4
|
+
* Author : Thomas Bernard
|
5
|
+
* Copyright (c) 2005 Thomas Bernard
|
6
|
+
* This software is subject to the conditions detailed in the
|
7
|
+
* LICENCE file provided in this distribution.
|
8
|
+
* */
|
9
|
+
#ifndef __IGD_DESC_PARSE_H__
|
10
|
+
#define __IGD_DESC_PARSE_H__
|
11
|
+
|
12
|
+
/* Structure to store the result of the parsing of UPnP
|
13
|
+
* descriptions of Internet Gateway Devices */
|
14
|
+
#define MINIUPNPC_URL_MAXSIZE (128)
|
15
|
+
struct IGDdatas {
|
16
|
+
char cureltname[MINIUPNPC_URL_MAXSIZE];
|
17
|
+
char urlbase[MINIUPNPC_URL_MAXSIZE];
|
18
|
+
int level;
|
19
|
+
int state;
|
20
|
+
char controlurl_CIF[MINIUPNPC_URL_MAXSIZE];
|
21
|
+
char eventsuburl_CIF[MINIUPNPC_URL_MAXSIZE];
|
22
|
+
char scpdurl_CIF[MINIUPNPC_URL_MAXSIZE];
|
23
|
+
char servicetype_CIF[MINIUPNPC_URL_MAXSIZE];
|
24
|
+
char devicetype_CIF[MINIUPNPC_URL_MAXSIZE];
|
25
|
+
char controlurl[MINIUPNPC_URL_MAXSIZE];
|
26
|
+
char eventsuburl[MINIUPNPC_URL_MAXSIZE];
|
27
|
+
char scpdurl[MINIUPNPC_URL_MAXSIZE];
|
28
|
+
char servicetype[MINIUPNPC_URL_MAXSIZE];
|
29
|
+
char devicetype[MINIUPNPC_URL_MAXSIZE];
|
30
|
+
};
|
31
|
+
|
32
|
+
void IGDstartelt(void *, const char *, int);
|
33
|
+
void IGDendelt(void *, const char *, int);
|
34
|
+
void IGDdata(void *, const char *, int);
|
35
|
+
void printIGD(struct IGDdatas *);
|
36
|
+
|
37
|
+
#endif
|
38
|
+
|
data/ext/minisoap.c
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
/* $Id: minisoap.c,v 1.15 2008/02/17 17:57:07 nanard Exp $ */
|
2
|
+
/* Project : miniupnp
|
3
|
+
* Author : Thomas Bernard
|
4
|
+
* Copyright (c) 2005 Thomas Bernard
|
5
|
+
* This software is subject to the conditions detailed in the
|
6
|
+
* LICENCE file provided in this distribution.
|
7
|
+
*
|
8
|
+
* Minimal SOAP implementation for UPnP protocol.
|
9
|
+
*/
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <string.h>
|
12
|
+
#ifdef WIN32
|
13
|
+
#include <io.h>
|
14
|
+
#include <winsock2.h>
|
15
|
+
#define snprintf _snprintf
|
16
|
+
#else
|
17
|
+
#include <unistd.h>
|
18
|
+
#include <sys/types.h>
|
19
|
+
#include <sys/socket.h>
|
20
|
+
#endif
|
21
|
+
#include "minisoap.h"
|
22
|
+
|
23
|
+
/* only for malloc */
|
24
|
+
#include <stdlib.h>
|
25
|
+
|
26
|
+
#ifdef WIN32
|
27
|
+
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
|
28
|
+
#else
|
29
|
+
#define PRINT_SOCKET_ERROR(x) perror(x)
|
30
|
+
#endif
|
31
|
+
|
32
|
+
/* httpWrite sends the headers and the body to the socket
|
33
|
+
* and returns the number of bytes sent */
|
34
|
+
static int
|
35
|
+
httpWrite(int fd, const char * body, int bodysize,
|
36
|
+
const char * headers, int headerssize)
|
37
|
+
{
|
38
|
+
int n = 0;
|
39
|
+
/*n = write(fd, headers, headerssize);*/
|
40
|
+
/*if(bodysize>0)
|
41
|
+
n += write(fd, body, bodysize);*/
|
42
|
+
/* Note : my old linksys router only took into account
|
43
|
+
* soap request that are sent into only one packet */
|
44
|
+
char * p;
|
45
|
+
/* TODO: AVOID MALLOC */
|
46
|
+
p = malloc(headerssize+bodysize);
|
47
|
+
if(!p)
|
48
|
+
return 0;
|
49
|
+
memcpy(p, headers, headerssize);
|
50
|
+
memcpy(p+headerssize, body, bodysize);
|
51
|
+
/*n = write(fd, p, headerssize+bodysize);*/
|
52
|
+
n = send(fd, p, headerssize+bodysize, 0);
|
53
|
+
if(n<0) {
|
54
|
+
PRINT_SOCKET_ERROR("send");
|
55
|
+
}
|
56
|
+
/* disable send on the socket */
|
57
|
+
/* draytek routers dont seems to like that... */
|
58
|
+
#if 0
|
59
|
+
#ifdef WIN32
|
60
|
+
if(shutdown(fd, SD_SEND)<0) {
|
61
|
+
#else
|
62
|
+
if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/
|
63
|
+
#endif
|
64
|
+
PRINT_SOCKET_ERROR("shutdown");
|
65
|
+
}
|
66
|
+
#endif
|
67
|
+
free(p);
|
68
|
+
return n;
|
69
|
+
}
|
70
|
+
|
71
|
+
/* self explanatory */
|
72
|
+
int soapPostSubmit(int fd,
|
73
|
+
const char * url,
|
74
|
+
const char * host,
|
75
|
+
unsigned short port,
|
76
|
+
const char * action,
|
77
|
+
const char * body)
|
78
|
+
{
|
79
|
+
int bodysize;
|
80
|
+
char headerbuf[512];
|
81
|
+
int headerssize;
|
82
|
+
char portstr[8];
|
83
|
+
bodysize = (int)strlen(body);
|
84
|
+
/* We are not using keep-alive HTTP connections.
|
85
|
+
* HTTP/1.1 needs the header Connection: close to do that.
|
86
|
+
* This is the default with HTTP/1.0 */
|
87
|
+
/* Connection: Close is normally there only in HTTP/1.1 but who knows */
|
88
|
+
portstr[0] = '\0';
|
89
|
+
if(port != 80)
|
90
|
+
snprintf(portstr, sizeof(portstr), ":%hu", port);
|
91
|
+
headerssize = snprintf(headerbuf, sizeof(headerbuf),
|
92
|
+
"POST %s HTTP/1.1\r\n"
|
93
|
+
/* "POST %s HTTP/1.0\r\n"*/
|
94
|
+
"Host: %s%s\r\n"
|
95
|
+
"User-Agent: POSIX, UPnP/1.0, miniUPnPc/1.0\r\n"
|
96
|
+
"Content-Length: %d\r\n"
|
97
|
+
"Content-Type: text/xml\r\n"
|
98
|
+
"SOAPAction: \"%s\"\r\n"
|
99
|
+
"Connection: Close\r\n"
|
100
|
+
"Cache-Control: no-cache\r\n" /* ??? */
|
101
|
+
"Pragma: no-cache\r\n"
|
102
|
+
"\r\n",
|
103
|
+
url, host, portstr, bodysize, action);
|
104
|
+
#ifdef DEBUG
|
105
|
+
printf("SOAP request : headersize=%d bodysize=%d\n",
|
106
|
+
headerssize, bodysize);
|
107
|
+
/*printf("%s", headerbuf);*/
|
108
|
+
#endif
|
109
|
+
return httpWrite(fd, body, bodysize, headerbuf, headerssize);
|
110
|
+
}
|
111
|
+
|
112
|
+
|
data/ext/minisoap.h
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
/* $Id: minisoap.h,v 1.3 2006/11/19 22:32:34 nanard Exp $ */
|
2
|
+
/* Project : miniupnp
|
3
|
+
* Author : Thomas Bernard
|
4
|
+
* Copyright (c) 2005 Thomas Bernard
|
5
|
+
* This software is subject to the conditions detailed in the
|
6
|
+
* LICENCE file provided in this distribution. */
|
7
|
+
#ifndef __MINISOAP_H__
|
8
|
+
#define __MINISOAP_H__
|
9
|
+
|
10
|
+
/*int httpWrite(int, const char *, int, const char *);*/
|
11
|
+
int soapPostSubmit(int, const char *, const char *, unsigned short,
|
12
|
+
const char *, const char *);
|
13
|
+
|
14
|
+
#endif
|
15
|
+
|
data/ext/minissdpc.c
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
/* $Id: minissdpc.c,v 1.4 2007/12/19 14:56:58 nanard Exp $ */
|
2
|
+
/* Project : miniupnp
|
3
|
+
* Author : Thomas BERNARD
|
4
|
+
* copyright (c) 2005-2007 Thomas Bernard
|
5
|
+
* This software is subjet to the conditions detailed in the
|
6
|
+
* provided LICENCE file. */
|
7
|
+
/*#include <syslog.h>*/
|
8
|
+
#include <stdio.h>
|
9
|
+
#include <string.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <unistd.h>
|
12
|
+
#include <sys/types.h>
|
13
|
+
#include <sys/socket.h>
|
14
|
+
#include <sys/un.h>
|
15
|
+
|
16
|
+
#include "minissdpc.h"
|
17
|
+
#include "miniupnpc.h"
|
18
|
+
|
19
|
+
#define DECODELENGTH(n, p) n = 0; \
|
20
|
+
do { n = (n << 7) | (*p & 0x7f); } \
|
21
|
+
while(*(p++)&0x80);
|
22
|
+
#define CODELENGTH(n, p) do { *p = (n & 0x7f) | ((n > 0x7f) ? 0x80 : 0); \
|
23
|
+
p++; n >>= 7; } while(n);
|
24
|
+
|
25
|
+
struct UPNPDev *
|
26
|
+
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
|
27
|
+
{
|
28
|
+
struct UPNPDev * tmp;
|
29
|
+
struct UPNPDev * devlist = NULL;
|
30
|
+
unsigned char buffer[2048];
|
31
|
+
ssize_t n;
|
32
|
+
unsigned char * p;
|
33
|
+
unsigned char * url;
|
34
|
+
unsigned int i;
|
35
|
+
unsigned int urlsize, stsize, usnsize, l;
|
36
|
+
int s;
|
37
|
+
struct sockaddr_un addr;
|
38
|
+
|
39
|
+
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
40
|
+
if(s < 0)
|
41
|
+
{
|
42
|
+
/*syslog(LOG_ERR, "socket(unix): %m");*/
|
43
|
+
perror("socket(unix)");
|
44
|
+
return NULL;
|
45
|
+
}
|
46
|
+
addr.sun_family = AF_UNIX;
|
47
|
+
strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
|
48
|
+
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
|
49
|
+
{
|
50
|
+
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
|
51
|
+
close(s);
|
52
|
+
return NULL;
|
53
|
+
}
|
54
|
+
stsize = strlen(devtype);
|
55
|
+
buffer[0] = 1;
|
56
|
+
p = buffer + 1;
|
57
|
+
l = stsize; CODELENGTH(l, p);
|
58
|
+
memcpy(p, devtype, stsize);
|
59
|
+
p += stsize;
|
60
|
+
if(write(s, buffer, p - buffer) < 0)
|
61
|
+
{
|
62
|
+
/*syslog(LOG_ERR, "write(): %m");*/
|
63
|
+
perror("minissdpc.c: write()");
|
64
|
+
close(s);
|
65
|
+
return NULL;
|
66
|
+
}
|
67
|
+
n = read(s, buffer, sizeof(buffer));
|
68
|
+
if(n<=0)
|
69
|
+
{
|
70
|
+
perror("minissdpc.c: read()");
|
71
|
+
close(s);
|
72
|
+
return NULL;
|
73
|
+
}
|
74
|
+
p = buffer + 1;
|
75
|
+
for(i = 0; i < buffer[0]; i++)
|
76
|
+
{
|
77
|
+
if(p+2>=buffer+sizeof(buffer))
|
78
|
+
break;
|
79
|
+
DECODELENGTH(urlsize, p);
|
80
|
+
if(p+urlsize+2>=buffer+sizeof(buffer))
|
81
|
+
break;
|
82
|
+
url = p;
|
83
|
+
p += urlsize;
|
84
|
+
DECODELENGTH(stsize, p);
|
85
|
+
if(p+stsize+2>=buffer+sizeof(buffer))
|
86
|
+
break;
|
87
|
+
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
|
88
|
+
tmp->pNext = devlist;
|
89
|
+
tmp->descURL = tmp->buffer;
|
90
|
+
tmp->st = tmp->buffer + 1 + urlsize;
|
91
|
+
memcpy(tmp->buffer, url, urlsize);
|
92
|
+
tmp->buffer[urlsize] = '\0';
|
93
|
+
memcpy(tmp->buffer + urlsize + 1, p, stsize);
|
94
|
+
p += stsize;
|
95
|
+
tmp->buffer[urlsize+1+stsize] = '\0';
|
96
|
+
devlist = tmp;
|
97
|
+
/* added for compatibility with recent versions of MiniSSDPd
|
98
|
+
* >= 2007/12/19 */
|
99
|
+
DECODELENGTH(usnsize, p);
|
100
|
+
p += usnsize;
|
101
|
+
if(p>buffer + sizeof(buffer))
|
102
|
+
break;
|
103
|
+
}
|
104
|
+
close(s);
|
105
|
+
return devlist;
|
106
|
+
}
|
107
|
+
|
data/ext/minissdpc.h
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
/* $Id: minissdpc.h,v 1.1 2007/08/31 15:15:33 nanard Exp $ */
|
2
|
+
/* Project: miniupnp
|
3
|
+
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
4
|
+
* Author: Thomas Bernard
|
5
|
+
* Copyright (c) 2005-2007 Thomas Bernard
|
6
|
+
* This software is subjects to the conditions detailed
|
7
|
+
* in the LICENCE file provided within this distribution */
|
8
|
+
#ifndef __MINISSDPC_H__
|
9
|
+
#define __MINISSDPC_H__
|
10
|
+
|
11
|
+
struct UPNPDev *
|
12
|
+
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath);
|
13
|
+
|
14
|
+
#endif
|
15
|
+
|
data/ext/miniupnpc.c
ADDED
@@ -0,0 +1,751 @@
|
|
1
|
+
/* $Id: miniupnpc.c,v 1.52 2008/02/18 13:28:33 nanard Exp $ */
|
2
|
+
/* Project : miniupnp
|
3
|
+
* Author : Thomas BERNARD
|
4
|
+
* copyright (c) 2005-2007 Thomas Bernard
|
5
|
+
* This software is subjet to the conditions detailed in the
|
6
|
+
* provided LICENCE file. */
|
7
|
+
#include <stdio.h>
|
8
|
+
#include <stdlib.h>
|
9
|
+
#include <string.h>
|
10
|
+
#ifdef WIN32
|
11
|
+
#include <winsock2.h>
|
12
|
+
#include <Ws2tcpip.h>
|
13
|
+
#include <io.h>
|
14
|
+
#define snprintf _snprintf
|
15
|
+
#define strncasecmp memicmp
|
16
|
+
#define MAXHOSTNAMELEN 64
|
17
|
+
#else
|
18
|
+
#include <unistd.h>
|
19
|
+
#include <sys/socket.h>
|
20
|
+
#include <sys/types.h>
|
21
|
+
#include <sys/param.h>
|
22
|
+
#include <netinet/in.h>
|
23
|
+
#include <arpa/inet.h>
|
24
|
+
#include <poll.h>
|
25
|
+
#include <netdb.h>
|
26
|
+
#define closesocket close
|
27
|
+
#endif
|
28
|
+
#include "miniupnpc.h"
|
29
|
+
#include "minissdpc.h"
|
30
|
+
#include "miniwget.h"
|
31
|
+
#include "minisoap.h"
|
32
|
+
#include "minixml.h"
|
33
|
+
#include "upnpcommands.h"
|
34
|
+
|
35
|
+
/* Uncomment the following to transmit the msearch from the same port
|
36
|
+
* as the UPnP multicast port. With WinXP this seems to result in the
|
37
|
+
* responses to the msearch being lost, thus if things dont work then
|
38
|
+
* comment this out. */
|
39
|
+
/* #define TX_FROM_UPNP_PORT */
|
40
|
+
|
41
|
+
#ifdef WIN32
|
42
|
+
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
|
43
|
+
#else
|
44
|
+
#define PRINT_SOCKET_ERROR(x) perror(x)
|
45
|
+
#endif
|
46
|
+
|
47
|
+
/* root description parsing */
|
48
|
+
void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
|
49
|
+
{
|
50
|
+
struct xmlparser parser;
|
51
|
+
/* xmlparser object */
|
52
|
+
parser.xmlstart = buffer;
|
53
|
+
parser.xmlsize = bufsize;
|
54
|
+
parser.data = data;
|
55
|
+
parser.starteltfunc = IGDstartelt;
|
56
|
+
parser.endeltfunc = IGDendelt;
|
57
|
+
parser.datafunc = IGDdata;
|
58
|
+
parser.attfunc = 0;
|
59
|
+
parsexml(&parser);
|
60
|
+
#ifndef NDEBUG
|
61
|
+
printIGD(data);
|
62
|
+
#endif
|
63
|
+
}
|
64
|
+
|
65
|
+
/* Content-length: nnn */
|
66
|
+
static int getcontentlenfromline(const char * p, int n)
|
67
|
+
{
|
68
|
+
static const char contlenstr[] = "content-length";
|
69
|
+
const char * p2 = contlenstr;
|
70
|
+
int a = 0;
|
71
|
+
while(*p2)
|
72
|
+
{
|
73
|
+
if(n==0)
|
74
|
+
return -1;
|
75
|
+
if(*p2 != *p && *p2 != (*p + 32))
|
76
|
+
return -1;
|
77
|
+
p++; p2++; n--;
|
78
|
+
}
|
79
|
+
if(n==0)
|
80
|
+
return -1;
|
81
|
+
if(*p != ':')
|
82
|
+
return -1;
|
83
|
+
p++; n--;
|
84
|
+
while(*p == ' ')
|
85
|
+
{
|
86
|
+
if(n==0)
|
87
|
+
return -1;
|
88
|
+
p++; n--;
|
89
|
+
}
|
90
|
+
while(*p >= '0' && *p <= '9')
|
91
|
+
{
|
92
|
+
if(n==0)
|
93
|
+
return -1;
|
94
|
+
a = (a * 10) + (*p - '0');
|
95
|
+
p++; n--;
|
96
|
+
}
|
97
|
+
return a;
|
98
|
+
}
|
99
|
+
|
100
|
+
static void
|
101
|
+
getContentLengthAndHeaderLength(char * p, int n,
|
102
|
+
int * contentlen, int * headerlen)
|
103
|
+
{
|
104
|
+
char * line;
|
105
|
+
int linelen;
|
106
|
+
int r;
|
107
|
+
line = p;
|
108
|
+
while(line < p + n)
|
109
|
+
{
|
110
|
+
linelen = 0;
|
111
|
+
while(line[linelen] != '\r' && line[linelen] != '\r')
|
112
|
+
{
|
113
|
+
if(line+linelen >= p+n)
|
114
|
+
return;
|
115
|
+
linelen++;
|
116
|
+
}
|
117
|
+
r = getcontentlenfromline(line, linelen);
|
118
|
+
if(r>0)
|
119
|
+
*contentlen = r;
|
120
|
+
line = line + linelen + 2;
|
121
|
+
if(line[0] == '\r' && line[1] == '\n')
|
122
|
+
{
|
123
|
+
*headerlen = (line - p) + 2;
|
124
|
+
return;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
/* simpleUPnPcommand :
|
130
|
+
* not so simple !
|
131
|
+
* return values :
|
132
|
+
* 0 - OK
|
133
|
+
* -1 - error */
|
134
|
+
int simpleUPnPcommand(int s, const char * url, const char * service,
|
135
|
+
const char * action, struct UPNParg * args,
|
136
|
+
char * buffer, int * bufsize)
|
137
|
+
{
|
138
|
+
struct sockaddr_in dest;
|
139
|
+
char hostname[MAXHOSTNAMELEN+1];
|
140
|
+
unsigned short port = 0;
|
141
|
+
char * path;
|
142
|
+
char soapact[128];
|
143
|
+
char soapbody[2048];
|
144
|
+
int soapbodylen;
|
145
|
+
char * buf;
|
146
|
+
int buffree;
|
147
|
+
int n;
|
148
|
+
int contentlen, headerlen; /* for the response */
|
149
|
+
snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
|
150
|
+
if(args==NULL)
|
151
|
+
{
|
152
|
+
/*soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
153
|
+
"<?xml version=\"1.0\"?>\r\n"
|
154
|
+
"<SOAP-ENV:Envelope "
|
155
|
+
"xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
156
|
+
"SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
157
|
+
"<SOAP-ENV:Body>"
|
158
|
+
"<m:%s xmlns:m=\"%s\"/>"
|
159
|
+
"</SOAP-ENV:Body></SOAP-ENV:Envelope>"
|
160
|
+
"\r\n", action, service);*/
|
161
|
+
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
162
|
+
"<?xml version=\"1.0\"?>\r\n"
|
163
|
+
"<s:Envelope "
|
164
|
+
"xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
165
|
+
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
166
|
+
"<s:Body>"
|
167
|
+
"<m:%s xmlns:m=\"%s\">"
|
168
|
+
"</m:%s>"
|
169
|
+
"</s:Body></s:Envelope>"
|
170
|
+
"\r\n", action, service, action);
|
171
|
+
}
|
172
|
+
else
|
173
|
+
{
|
174
|
+
char * p;
|
175
|
+
const char * pe, * pv;
|
176
|
+
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
177
|
+
"<?xml version=\"1.0\"?>\r\n"
|
178
|
+
"<SOAP-ENV:Envelope "
|
179
|
+
"xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
180
|
+
"SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
181
|
+
"<SOAP-ENV:Body>"
|
182
|
+
"<m:%s xmlns:m=\"%s\">",
|
183
|
+
action, service);
|
184
|
+
p = soapbody + soapbodylen;
|
185
|
+
while(args->elt)
|
186
|
+
{
|
187
|
+
/* check that we are never overflowing the string... */
|
188
|
+
if(soapbody + sizeof(soapbody) <= p + 100)
|
189
|
+
{
|
190
|
+
/* we keep a margin of at least 100 bytes */
|
191
|
+
*bufsize = 0;
|
192
|
+
return -1;
|
193
|
+
}
|
194
|
+
*(p++) = '<';
|
195
|
+
pe = args->elt;
|
196
|
+
while(*pe)
|
197
|
+
*(p++) = *(pe++);
|
198
|
+
*(p++) = '>';
|
199
|
+
if((pv = args->val))
|
200
|
+
{
|
201
|
+
while(*pv)
|
202
|
+
*(p++) = *(pv++);
|
203
|
+
}
|
204
|
+
*(p++) = '<';
|
205
|
+
*(p++) = '/';
|
206
|
+
pe = args->elt;
|
207
|
+
while(*pe)
|
208
|
+
*(p++) = *(pe++);
|
209
|
+
*(p++) = '>';
|
210
|
+
args++;
|
211
|
+
}
|
212
|
+
*(p++) = '<';
|
213
|
+
*(p++) = '/';
|
214
|
+
*(p++) = 'm';
|
215
|
+
*(p++) = ':';
|
216
|
+
pe = action;
|
217
|
+
while(*pe)
|
218
|
+
*(p++) = *(pe++);
|
219
|
+
strncpy(p, "></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n",
|
220
|
+
soapbody + sizeof(soapbody) - p);
|
221
|
+
}
|
222
|
+
if(!parseURL(url, hostname, &port, &path)) return -1;
|
223
|
+
if(s<0)
|
224
|
+
{
|
225
|
+
s = socket(PF_INET, SOCK_STREAM, 0);
|
226
|
+
if(s<0)
|
227
|
+
{
|
228
|
+
PRINT_SOCKET_ERROR("socket");
|
229
|
+
*bufsize = 0;
|
230
|
+
return -1;
|
231
|
+
}
|
232
|
+
dest.sin_family = AF_INET;
|
233
|
+
dest.sin_port = htons(port);
|
234
|
+
dest.sin_addr.s_addr = inet_addr(hostname);
|
235
|
+
if(connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0)
|
236
|
+
{
|
237
|
+
PRINT_SOCKET_ERROR("connect");
|
238
|
+
closesocket(s);
|
239
|
+
*bufsize = 0;
|
240
|
+
return -1;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
244
|
+
n = soapPostSubmit(s, path, hostname, port, soapact, soapbody);
|
245
|
+
if(n<=0) {
|
246
|
+
#ifdef DEBUG
|
247
|
+
printf("Error sending SOAP request\n");
|
248
|
+
#endif
|
249
|
+
closesocket(s);
|
250
|
+
return -1;
|
251
|
+
}
|
252
|
+
|
253
|
+
contentlen = -1;
|
254
|
+
headerlen = -1;
|
255
|
+
buf = buffer;
|
256
|
+
buffree = *bufsize;
|
257
|
+
*bufsize = 0;
|
258
|
+
while ((n = ReceiveData(s, buf, buffree, 5000)) > 0) {
|
259
|
+
buffree -= n;
|
260
|
+
buf += n;
|
261
|
+
*bufsize += n;
|
262
|
+
getContentLengthAndHeaderLength(buffer, *bufsize,
|
263
|
+
&contentlen, &headerlen);
|
264
|
+
#ifdef DEBUG
|
265
|
+
printf("received n=%dbytes bufsize=%d ContLen=%d HeadLen=%d\n",
|
266
|
+
n, *bufsize, contentlen, headerlen);
|
267
|
+
#endif
|
268
|
+
/* break if we received everything */
|
269
|
+
if(contentlen > 0 && headerlen > 0 && *bufsize >= contentlen+headerlen)
|
270
|
+
break;
|
271
|
+
}
|
272
|
+
|
273
|
+
closesocket(s);
|
274
|
+
return 0;
|
275
|
+
}
|
276
|
+
|
277
|
+
/* parseMSEARCHReply()
|
278
|
+
* the last 4 arguments are filled during the parsing :
|
279
|
+
* - location/locationsize : "location:" field of the SSDP reply packet
|
280
|
+
* - st/stsize : "st:" field of the SSDP reply packet.
|
281
|
+
* The strings are NOT null terminated */
|
282
|
+
static void
|
283
|
+
parseMSEARCHReply(const char * reply, int size,
|
284
|
+
const char * * location, int * locationsize,
|
285
|
+
const char * * st, int * stsize)
|
286
|
+
{
|
287
|
+
int a, b, i;
|
288
|
+
i = 0;
|
289
|
+
a = i; /* start of the line */
|
290
|
+
b = 0;
|
291
|
+
while(i<size)
|
292
|
+
{
|
293
|
+
switch(reply[i])
|
294
|
+
{
|
295
|
+
case ':':
|
296
|
+
if(b==0)
|
297
|
+
{
|
298
|
+
b = i; /* end of the "header" */
|
299
|
+
/*for(j=a; j<b; j++)
|
300
|
+
{
|
301
|
+
putchar(reply[j]);
|
302
|
+
}
|
303
|
+
*/
|
304
|
+
}
|
305
|
+
break;
|
306
|
+
case '\x0a':
|
307
|
+
case '\x0d':
|
308
|
+
if(b!=0)
|
309
|
+
{
|
310
|
+
/*for(j=b+1; j<i; j++)
|
311
|
+
{
|
312
|
+
putchar(reply[j]);
|
313
|
+
}
|
314
|
+
putchar('\n');*/
|
315
|
+
do { b++; } while(reply[b]==' ');
|
316
|
+
if(0==strncasecmp(reply+a, "location", 8))
|
317
|
+
{
|
318
|
+
*location = reply+b;
|
319
|
+
*locationsize = i-b;
|
320
|
+
}
|
321
|
+
else if(0==strncasecmp(reply+a, "st", 2))
|
322
|
+
{
|
323
|
+
*st = reply+b;
|
324
|
+
*stsize = i-b;
|
325
|
+
}
|
326
|
+
b = 0;
|
327
|
+
}
|
328
|
+
a = i+1;
|
329
|
+
break;
|
330
|
+
default:
|
331
|
+
break;
|
332
|
+
}
|
333
|
+
i++;
|
334
|
+
}
|
335
|
+
}
|
336
|
+
|
337
|
+
/* port upnp discover : SSDP protocol */
|
338
|
+
#define PORT (1900)
|
339
|
+
#define UPNP_MCAST_ADDR "239.255.255.250"
|
340
|
+
|
341
|
+
/* upnpDiscover() :
|
342
|
+
* return a chained list of all devices found or NULL if
|
343
|
+
* no devices was found.
|
344
|
+
* It is up to the caller to free the chained list
|
345
|
+
* delay is in millisecond (poll) */
|
346
|
+
struct UPNPDev * upnpDiscover(int delay, const char * multicastif,
|
347
|
+
const char * minissdpdsock)
|
348
|
+
{
|
349
|
+
struct UPNPDev * tmp;
|
350
|
+
struct UPNPDev * devlist = 0;
|
351
|
+
int opt = 1;
|
352
|
+
static const char MSearchMsgFmt[] =
|
353
|
+
"M-SEARCH * HTTP/1.1\r\n"
|
354
|
+
"HOST: " UPNP_MCAST_ADDR ":" "1900" "\r\n"
|
355
|
+
"ST: %s\r\n"
|
356
|
+
"MAN: \"ssdp:discover\"\r\n"
|
357
|
+
"MX: 3\r\n"
|
358
|
+
"\r\n";
|
359
|
+
static const char * const deviceList[] = {
|
360
|
+
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
|
361
|
+
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
362
|
+
"urn:schemas-upnp-org:service:WANPPPConnection:1",
|
363
|
+
"upnp:rootdevice",
|
364
|
+
0
|
365
|
+
};
|
366
|
+
int deviceIndex = 0;
|
367
|
+
char bufr[1536]; /* reception and emission buffer */
|
368
|
+
int sudp;
|
369
|
+
int n;
|
370
|
+
struct sockaddr_in sockudp_r, sockudp_w;
|
371
|
+
|
372
|
+
#ifndef WIN32
|
373
|
+
/* first try to get infos from minissdpd ! */
|
374
|
+
if(!minissdpdsock)
|
375
|
+
minissdpdsock = "/var/run/minissdpd.sock";
|
376
|
+
while(!devlist && deviceList[deviceIndex]) {
|
377
|
+
devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex],
|
378
|
+
minissdpdsock);
|
379
|
+
/* We return what we have found if it was not only a rootdevice */
|
380
|
+
if(devlist && !strstr(deviceList[deviceIndex], "rootdevice"))
|
381
|
+
return devlist;
|
382
|
+
deviceIndex++;
|
383
|
+
}
|
384
|
+
deviceIndex = 0;
|
385
|
+
#endif
|
386
|
+
/* fallback to direct discovery */
|
387
|
+
#ifdef WIN32
|
388
|
+
sudp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
389
|
+
#else
|
390
|
+
sudp = socket(PF_INET, SOCK_DGRAM, 0);
|
391
|
+
#endif
|
392
|
+
if(sudp < 0)
|
393
|
+
{
|
394
|
+
PRINT_SOCKET_ERROR("socket");
|
395
|
+
return NULL;
|
396
|
+
}
|
397
|
+
/* reception */
|
398
|
+
memset(&sockudp_r, 0, sizeof(struct sockaddr_in));
|
399
|
+
sockudp_r.sin_family = AF_INET;
|
400
|
+
#ifdef TX_FROM_UPNP_PORT
|
401
|
+
sockudp_r.sin_port = htons(PORT);
|
402
|
+
#endif
|
403
|
+
sockudp_r.sin_addr.s_addr = INADDR_ANY;
|
404
|
+
/* emission */
|
405
|
+
memset(&sockudp_w, 0, sizeof(struct sockaddr_in));
|
406
|
+
sockudp_w.sin_family = AF_INET;
|
407
|
+
sockudp_w.sin_port = htons(PORT);
|
408
|
+
sockudp_w.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
|
409
|
+
|
410
|
+
#ifdef WIN32
|
411
|
+
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
|
412
|
+
#else
|
413
|
+
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
|
414
|
+
#endif
|
415
|
+
{
|
416
|
+
PRINT_SOCKET_ERROR("setsockopt");
|
417
|
+
return NULL;
|
418
|
+
}
|
419
|
+
|
420
|
+
if(multicastif)
|
421
|
+
{
|
422
|
+
struct in_addr mc_if;
|
423
|
+
mc_if.s_addr = inet_addr(multicastif);
|
424
|
+
sockudp_r.sin_addr.s_addr = mc_if.s_addr;
|
425
|
+
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
|
426
|
+
{
|
427
|
+
PRINT_SOCKET_ERROR("setsockopt");
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
431
|
+
/* Avant d'envoyer le paquet on bind pour recevoir la reponse */
|
432
|
+
if (bind(sudp, (struct sockaddr *)&sockudp_r, sizeof(struct sockaddr_in)) != 0)
|
433
|
+
{
|
434
|
+
PRINT_SOCKET_ERROR("bind");
|
435
|
+
closesocket(sudp);
|
436
|
+
return NULL;
|
437
|
+
}
|
438
|
+
|
439
|
+
/* receiving SSDP response packet */
|
440
|
+
for(n = 0;;)
|
441
|
+
{
|
442
|
+
if(n == 0)
|
443
|
+
{
|
444
|
+
/* sending the SSDP M-SEARCH packet */
|
445
|
+
n = snprintf(bufr, sizeof(bufr),
|
446
|
+
MSearchMsgFmt, deviceList[deviceIndex++]);
|
447
|
+
/*printf("Sending %s", bufr);*/
|
448
|
+
n = sendto(sudp, bufr, n, 0,
|
449
|
+
(struct sockaddr *)&sockudp_w, sizeof(struct sockaddr_in));
|
450
|
+
if (n < 0) {
|
451
|
+
PRINT_SOCKET_ERROR("sendto");
|
452
|
+
closesocket(sudp);
|
453
|
+
return devlist;
|
454
|
+
}
|
455
|
+
}
|
456
|
+
/* Waiting for SSDP REPLY packet to M-SEARCH */
|
457
|
+
n = ReceiveData(sudp, bufr, sizeof(bufr), delay);
|
458
|
+
if (n < 0) {
|
459
|
+
/* error */
|
460
|
+
closesocket(sudp);
|
461
|
+
return devlist;
|
462
|
+
} else if (n == 0) {
|
463
|
+
/* no data or Time Out */
|
464
|
+
if (devlist || (deviceList[deviceIndex] == 0)) {
|
465
|
+
/* no more device type to look for... */
|
466
|
+
closesocket(sudp);
|
467
|
+
return devlist;
|
468
|
+
}
|
469
|
+
} else {
|
470
|
+
const char * descURL=NULL;
|
471
|
+
int urlsize=0;
|
472
|
+
const char * st=NULL;
|
473
|
+
int stsize=0;
|
474
|
+
/*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
|
475
|
+
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
|
476
|
+
if(st&&descURL)
|
477
|
+
{
|
478
|
+
/*printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
|
479
|
+
stsize, st, urlsize, descURL); */
|
480
|
+
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
|
481
|
+
tmp->pNext = devlist;
|
482
|
+
tmp->descURL = tmp->buffer;
|
483
|
+
tmp->st = tmp->buffer + 1 + urlsize;
|
484
|
+
memcpy(tmp->buffer, descURL, urlsize);
|
485
|
+
tmp->buffer[urlsize] = '\0';
|
486
|
+
memcpy(tmp->buffer + urlsize + 1, st, stsize);
|
487
|
+
tmp->buffer[urlsize+1+stsize] = '\0';
|
488
|
+
devlist = tmp;
|
489
|
+
}
|
490
|
+
}
|
491
|
+
}
|
492
|
+
}
|
493
|
+
|
494
|
+
/* freeUPNPDevlist() should be used to
|
495
|
+
* free the chained list returned by upnpDiscover() */
|
496
|
+
void freeUPNPDevlist(struct UPNPDev * devlist)
|
497
|
+
{
|
498
|
+
struct UPNPDev * next;
|
499
|
+
while(devlist)
|
500
|
+
{
|
501
|
+
next = devlist->pNext;
|
502
|
+
free(devlist);
|
503
|
+
devlist = next;
|
504
|
+
}
|
505
|
+
}
|
506
|
+
|
507
|
+
static void
|
508
|
+
url_cpy_or_cat(char * dst, const char * src, int n)
|
509
|
+
{
|
510
|
+
if( (src[0] == 'h')
|
511
|
+
&&(src[1] == 't')
|
512
|
+
&&(src[2] == 't')
|
513
|
+
&&(src[3] == 'p')
|
514
|
+
&&(src[4] == ':')
|
515
|
+
&&(src[5] == '/')
|
516
|
+
&&(src[6] == '/'))
|
517
|
+
{
|
518
|
+
strncpy(dst, src, n);
|
519
|
+
}
|
520
|
+
else
|
521
|
+
{
|
522
|
+
int l = strlen(dst);
|
523
|
+
if(src[0] != '/')
|
524
|
+
dst[l++] = '/';
|
525
|
+
if(l<=n)
|
526
|
+
strncpy(dst + l, src, n - l);
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
/* Prepare the Urls for usage...
|
531
|
+
*/
|
532
|
+
void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
|
533
|
+
const char * descURL)
|
534
|
+
{
|
535
|
+
char * p;
|
536
|
+
int n1, n2, n3;
|
537
|
+
n1 = strlen(data->urlbase);
|
538
|
+
if(n1==0)
|
539
|
+
n1 = strlen(descURL);
|
540
|
+
n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */
|
541
|
+
n2 = n1; n3 = n1;
|
542
|
+
n1 += strlen(data->scpdurl);
|
543
|
+
n2 += strlen(data->controlurl);
|
544
|
+
n3 += strlen(data->controlurl_CIF);
|
545
|
+
|
546
|
+
urls->ipcondescURL = (char *)malloc(n1);
|
547
|
+
urls->controlURL = (char *)malloc(n2);
|
548
|
+
urls->controlURL_CIF = (char *)malloc(n3);
|
549
|
+
/* maintenant on chope la desc du WANIPConnection */
|
550
|
+
if(data->urlbase[0] != '\0')
|
551
|
+
strncpy(urls->ipcondescURL, data->urlbase, n1);
|
552
|
+
else
|
553
|
+
strncpy(urls->ipcondescURL, descURL, n1);
|
554
|
+
p = strchr(urls->ipcondescURL+7, '/');
|
555
|
+
if(p) p[0] = '\0';
|
556
|
+
strncpy(urls->controlURL, urls->ipcondescURL, n2);
|
557
|
+
strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
|
558
|
+
|
559
|
+
url_cpy_or_cat(urls->ipcondescURL, data->scpdurl, n1);
|
560
|
+
|
561
|
+
url_cpy_or_cat(urls->controlURL, data->controlurl, n2);
|
562
|
+
|
563
|
+
url_cpy_or_cat(urls->controlURL_CIF, data->controlurl_CIF, n3);
|
564
|
+
|
565
|
+
#ifdef DEBUG
|
566
|
+
printf("urls->ipcondescURL='%s' %d n1=%d\n", urls->ipcondescURL,
|
567
|
+
strlen(urls->ipcondescURL), n1);
|
568
|
+
printf("urls->controlURL='%s' %d n2=%d\n", urls->controlURL,
|
569
|
+
strlen(urls->controlURL), n2);
|
570
|
+
printf("urls->controlURL_CIF='%s' %d n3=%d\n", urls->controlURL_CIF,
|
571
|
+
strlen(urls->controlURL_CIF), n3);
|
572
|
+
#endif
|
573
|
+
}
|
574
|
+
|
575
|
+
void
|
576
|
+
FreeUPNPUrls(struct UPNPUrls * urls)
|
577
|
+
{
|
578
|
+
if(!urls)
|
579
|
+
return;
|
580
|
+
free(urls->controlURL);
|
581
|
+
urls->controlURL = 0;
|
582
|
+
free(urls->ipcondescURL);
|
583
|
+
urls->ipcondescURL = 0;
|
584
|
+
free(urls->controlURL_CIF);
|
585
|
+
urls->controlURL_CIF = 0;
|
586
|
+
}
|
587
|
+
|
588
|
+
|
589
|
+
int ReceiveData(int socket, char * data, int length, int timeout)
|
590
|
+
{
|
591
|
+
int n;
|
592
|
+
#ifndef WIN32
|
593
|
+
struct pollfd fds[1]; /* for the poll */
|
594
|
+
fds[0].fd = socket;
|
595
|
+
fds[0].events = POLLIN;
|
596
|
+
n = poll(fds, 1, timeout);
|
597
|
+
if(n < 0)
|
598
|
+
{
|
599
|
+
PRINT_SOCKET_ERROR("poll");
|
600
|
+
return -1;
|
601
|
+
}
|
602
|
+
else if(n == 0)
|
603
|
+
{
|
604
|
+
return 0;
|
605
|
+
}
|
606
|
+
#else
|
607
|
+
fd_set socketSet;
|
608
|
+
TIMEVAL timeval;
|
609
|
+
FD_ZERO(&socketSet);
|
610
|
+
FD_SET(socket, &socketSet);
|
611
|
+
timeval.tv_sec = timeout / 1000;
|
612
|
+
timeval.tv_usec = (timeout % 1000) * 1000;
|
613
|
+
/*n = select(0, &socketSet, NULL, NULL, &timeval);*/
|
614
|
+
n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval);
|
615
|
+
if(n < 0)
|
616
|
+
{
|
617
|
+
PRINT_SOCKET_ERROR("select");
|
618
|
+
return -1;
|
619
|
+
}
|
620
|
+
else if(n == 0)
|
621
|
+
{
|
622
|
+
return 0;
|
623
|
+
}
|
624
|
+
#endif
|
625
|
+
n = recv(socket, data, length, 0);
|
626
|
+
if(n<0)
|
627
|
+
{
|
628
|
+
PRINT_SOCKET_ERROR("recv");
|
629
|
+
}
|
630
|
+
return n;
|
631
|
+
}
|
632
|
+
|
633
|
+
int
|
634
|
+
UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
|
635
|
+
{
|
636
|
+
char status[64];
|
637
|
+
unsigned int uptime;
|
638
|
+
status[0] = '\0';
|
639
|
+
UPNP_GetStatusInfo(urls->controlURL, data->servicetype,
|
640
|
+
status, &uptime, NULL);
|
641
|
+
if(0 == strcmp("Connected", status))
|
642
|
+
{
|
643
|
+
return 1;
|
644
|
+
}
|
645
|
+
else
|
646
|
+
return 0;
|
647
|
+
}
|
648
|
+
|
649
|
+
|
650
|
+
/* UPNP_GetValidIGD() :
|
651
|
+
* return values :
|
652
|
+
* 0 = NO IGD found
|
653
|
+
* 1 = A valid connected IGD has been found
|
654
|
+
* 2 = A valid IGD has been found but it reported as
|
655
|
+
* not connected
|
656
|
+
* 3 = an UPnP device has been found but was not recognized as an IGD
|
657
|
+
*
|
658
|
+
* In any non zero return case, the urls and data structures
|
659
|
+
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
660
|
+
* free allocated memory.
|
661
|
+
*/
|
662
|
+
int
|
663
|
+
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
664
|
+
struct UPNPUrls * urls,
|
665
|
+
struct IGDdatas * data,
|
666
|
+
char * lanaddr, int lanaddrlen)
|
667
|
+
{
|
668
|
+
char * descXML;
|
669
|
+
int descXMLsize = 0;
|
670
|
+
struct UPNPDev * dev;
|
671
|
+
int ndev = 0;
|
672
|
+
int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
|
673
|
+
if(!devlist)
|
674
|
+
{
|
675
|
+
#ifdef DEBUG
|
676
|
+
printf("Empty devlist\n");
|
677
|
+
#endif
|
678
|
+
return 0;
|
679
|
+
}
|
680
|
+
for(state = 1; state <= 3; state++)
|
681
|
+
{
|
682
|
+
for(dev = devlist; dev; dev = dev->pNext)
|
683
|
+
{
|
684
|
+
/* we should choose an internet gateway device.
|
685
|
+
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
|
686
|
+
descXML = miniwget_getaddr(dev->descURL, &descXMLsize,
|
687
|
+
lanaddr, lanaddrlen);
|
688
|
+
if(descXML)
|
689
|
+
{
|
690
|
+
ndev++;
|
691
|
+
memset(data, 0, sizeof(struct IGDdatas));
|
692
|
+
memset(urls, 0, sizeof(struct UPNPUrls));
|
693
|
+
parserootdesc(descXML, descXMLsize, data);
|
694
|
+
free(descXML);
|
695
|
+
descXML = NULL;
|
696
|
+
if(0==strcmp(data->servicetype_CIF,
|
697
|
+
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")
|
698
|
+
|| state >= 3 )
|
699
|
+
{
|
700
|
+
GetUPNPUrls(urls, data, dev->descURL);
|
701
|
+
|
702
|
+
#ifdef DEBUG
|
703
|
+
printf("UPNPIGD_IsConnected(%s) = %d\n",
|
704
|
+
urls->controlURL,
|
705
|
+
UPNPIGD_IsConnected(urls, data));
|
706
|
+
#endif
|
707
|
+
if((state >= 2) || UPNPIGD_IsConnected(urls, data))
|
708
|
+
return state;
|
709
|
+
FreeUPNPUrls(urls);
|
710
|
+
}
|
711
|
+
memset(data, 0, sizeof(struct IGDdatas));
|
712
|
+
}
|
713
|
+
#ifdef DEBUG
|
714
|
+
else
|
715
|
+
{
|
716
|
+
printf("error getting XML description %s\n", dev->descURL);
|
717
|
+
}
|
718
|
+
#endif
|
719
|
+
}
|
720
|
+
}
|
721
|
+
return 0;
|
722
|
+
}
|
723
|
+
|
724
|
+
/* UPNP_GetIGDFromUrl()
|
725
|
+
* Used when skipping the discovery process.
|
726
|
+
* return value :
|
727
|
+
* 0 - Not ok
|
728
|
+
* 1 - OK */
|
729
|
+
int
|
730
|
+
UPNP_GetIGDFromUrl(const char * rootdescurl,
|
731
|
+
struct UPNPUrls * urls,
|
732
|
+
struct IGDdatas * data,
|
733
|
+
char * lanaddr, int lanaddrlen)
|
734
|
+
{
|
735
|
+
char * descXML;
|
736
|
+
int descXMLsize = 0;
|
737
|
+
descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
|
738
|
+
lanaddr, lanaddrlen);
|
739
|
+
if(descXML) {
|
740
|
+
memset(data, 0, sizeof(struct IGDdatas));
|
741
|
+
memset(urls, 0, sizeof(struct UPNPUrls));
|
742
|
+
parserootdesc(descXML, descXMLsize, data);
|
743
|
+
free(descXML);
|
744
|
+
descXML = NULL;
|
745
|
+
GetUPNPUrls(urls, data, rootdescurl);
|
746
|
+
return 1;
|
747
|
+
} else {
|
748
|
+
return 0;
|
749
|
+
}
|
750
|
+
}
|
751
|
+
|