mupnp 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+