upnp libraries
This commit is contained in:
parent
74d666951c
commit
76fde311c9
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,85 @@
|
||||||
|
$Id: Changelog.txt,v 1.27 2007/03/01 22:29:48 nanard Exp $
|
||||||
|
miniUPnP client Changelog.
|
||||||
|
|
||||||
|
2007/03/01:
|
||||||
|
Small typo fix...
|
||||||
|
|
||||||
|
2007/01/30:
|
||||||
|
Now parsing the HTTP header from SOAP responses in order to
|
||||||
|
get content-length value.
|
||||||
|
|
||||||
|
2007/01/29:
|
||||||
|
Fixed the Soap Query to speedup the HTTP request.
|
||||||
|
added some Win32 DLL stuff...
|
||||||
|
|
||||||
|
2007/01/27:
|
||||||
|
Fixed some WIN32 compatibility issues
|
||||||
|
|
||||||
|
2006/12/14:
|
||||||
|
Added UPNPIGD_IsConnected() function in miniupnp.c/.h
|
||||||
|
Added UPNP_GetValidIGD() in miniupnp.c/.h
|
||||||
|
cleaned upnpc.c main(). now using UPNP_GetValidIGD()
|
||||||
|
|
||||||
|
2006/12/07:
|
||||||
|
Version 1.0-RC1 released
|
||||||
|
|
||||||
|
2006/12/03:
|
||||||
|
Minor changes to compile under SunOS/Solaris
|
||||||
|
|
||||||
|
2006/11/30:
|
||||||
|
made a minixml parser validator program
|
||||||
|
updated minixml to handle attributes correctly
|
||||||
|
|
||||||
|
2006/11/22:
|
||||||
|
Added a -r option to the upnpc sample thanks to Alexander Hubmann.
|
||||||
|
|
||||||
|
2006/11/19:
|
||||||
|
Cleanup code to make it more ANSI C compliant
|
||||||
|
|
||||||
|
2006/11/10:
|
||||||
|
detect and display local lan address.
|
||||||
|
|
||||||
|
2006/11/04:
|
||||||
|
Packets and Bytes Sent/Received are now unsigned int.
|
||||||
|
|
||||||
|
2006/11/01:
|
||||||
|
Bug fix thanks to Giuseppe D'Angelo
|
||||||
|
|
||||||
|
2006/10/31:
|
||||||
|
C++ compatibility for .h files.
|
||||||
|
Added a way to get ip Address on the LAN used to reach the IGD.
|
||||||
|
|
||||||
|
2006/10/25:
|
||||||
|
Added M-SEARCH to the services in the discovery process.
|
||||||
|
|
||||||
|
2006/10/22:
|
||||||
|
updated the Makefile to use makedepend, added a "make install"
|
||||||
|
update Makefile
|
||||||
|
|
||||||
|
2006/10/20:
|
||||||
|
fixing the description url parsing thanks to patch sent by
|
||||||
|
Wayne Dawe.
|
||||||
|
Fixed/translated some comments.
|
||||||
|
Implemented a better discover process, first looking
|
||||||
|
for IGD then for root devices (as some devices only reply to
|
||||||
|
M-SEARCH for root devices).
|
||||||
|
|
||||||
|
2006/09/02:
|
||||||
|
added freeUPNPDevlist() function.
|
||||||
|
|
||||||
|
2006/08/04:
|
||||||
|
More command line arguments checking
|
||||||
|
|
||||||
|
2006/08/01:
|
||||||
|
Added the .bat file to compile under Win32 with minGW32
|
||||||
|
|
||||||
|
2006/07/31:
|
||||||
|
Fixed the rootdesc parser (igd_desc_parse.c)
|
||||||
|
|
||||||
|
2006/07/20:
|
||||||
|
parseMSEARCHReply() is now returning the ST: line as well
|
||||||
|
starting changes to detect several UPnP devices on the network
|
||||||
|
|
||||||
|
2006/07/19:
|
||||||
|
using GetCommonLinkProperties to get down/upload bitrate
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
Copyright (c) 2005-2006, Thomas BERNARD
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
# $Id: Makefile,v 1.21 2007/03/02 10:45:52 nanard Exp $
|
||||||
|
# MiniUPnP Project
|
||||||
|
# http://miniupnp.free.fr/
|
||||||
|
# (c) 2005-2006 Thomas Bernard
|
||||||
|
CC = gcc
|
||||||
|
#AR = gar
|
||||||
|
CFLAGS = -O -Wall -g -DDEBUG
|
||||||
|
#CFLAGS = -O -Wall -DNDEBUG
|
||||||
|
INSTALL = install
|
||||||
|
#following libs are needed on Solaris
|
||||||
|
#LDLIBS=-lsocket -lnsl -lresolv
|
||||||
|
|
||||||
|
SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \
|
||||||
|
upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \
|
||||||
|
minixmlvalid.c
|
||||||
|
|
||||||
|
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||||
|
|
||||||
|
# HEADERS to install
|
||||||
|
HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
|
||||||
|
upnpreplyparse.h
|
||||||
|
LIBRARY = libminiupnpc.a
|
||||||
|
EXECUTABLES = upnpc testminixml minixmlvalid
|
||||||
|
|
||||||
|
INSTALLPREFIX = /usr
|
||||||
|
INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc
|
||||||
|
INSTALLDIRLIB = $(INSTALLPREFIX)/lib
|
||||||
|
|
||||||
|
.PHONY: install clean depend all
|
||||||
|
|
||||||
|
all: validateminixml $(LIBRARY) $(EXECUTABLES)
|
||||||
|
|
||||||
|
validateminixml: minixmlvalid
|
||||||
|
@echo "minixml validation test"
|
||||||
|
./minixmlvalid
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(LIBRARY) $(EXECUTABLES) $(OBJS)
|
||||||
|
|
||||||
|
install: $(LIBRARY)
|
||||||
|
$(INSTALL) -d $(INSTALLDIRINC)
|
||||||
|
$(INSTALL) --mode=644 $(HEADERS) $(INSTALLDIRINC)
|
||||||
|
$(INSTALL) --mode=644 $(LIBRARY) $(INSTALLDIRLIB)
|
||||||
|
|
||||||
|
cleaninstall:
|
||||||
|
$(RM) -r $(INSTALLDIRINC)
|
||||||
|
$(RM) $(INSTALLDIRLIB)/$(LIBRARY)
|
||||||
|
|
||||||
|
depend:
|
||||||
|
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
|
||||||
|
|
||||||
|
libminiupnpc.a: miniwget.o minixml.o igd_desc_parse.o minisoap.o miniupnpc.o upnpreplyparse.o upnpcommands.o
|
||||||
|
$(AR) crs $@ $?
|
||||||
|
|
||||||
|
upnpc: upnpc.o libminiupnpc.a
|
||||||
|
|
||||||
|
testminixml: minixml.o igd_desc_parse.o testminixml.o
|
||||||
|
|
||||||
|
minixmlvalid: minixml.o minixmlvalid.o
|
||||||
|
|
||||||
|
# DO NOT DELETE THIS LINE -- make depend depends on it.
|
||||||
|
|
||||||
|
igd_desc_parse.o: igd_desc_parse.h
|
||||||
|
miniupnpc.o: miniupnpc.h declspec.h igd_desc_parse.h miniwget.h minisoap.h
|
||||||
|
miniupnpc.o: minixml.h upnpcommands.h upnpreplyparse.h
|
||||||
|
minixml.o: minixml.h
|
||||||
|
minisoap.o: minisoap.h
|
||||||
|
miniwget.o: miniupnpc.h declspec.h igd_desc_parse.h
|
||||||
|
upnpc.o: miniwget.h declspec.h miniupnpc.h igd_desc_parse.h upnpcommands.h
|
||||||
|
upnpc.o: upnpreplyparse.h
|
||||||
|
upnpcommands.o: upnpcommands.h upnpreplyparse.h miniupnpc.h declspec.h
|
||||||
|
upnpcommands.o: igd_desc_parse.h
|
||||||
|
upnpreplyparse.o: upnpreplyparse.h minixml.h
|
||||||
|
testminixml.o: minixml.h igd_desc_parse.h
|
||||||
|
minixmlvalid.o: minixml.h
|
|
@ -0,0 +1,35 @@
|
||||||
|
# $Id: Makefile.mingw,v 1.4 2006/11/08 22:07:47 nanard Exp $
|
||||||
|
CC = gcc
|
||||||
|
#CFLAGS = -Wall -g -DDEBUG
|
||||||
|
CFLAGS = -Wall -Os -DNDEBUG
|
||||||
|
LDLIBS = -lws2_32
|
||||||
|
# -lwsock32
|
||||||
|
|
||||||
|
all: upnpc testminixml libminiupnpc.a
|
||||||
|
|
||||||
|
clean:
|
||||||
|
del upnpc testminixml *.o
|
||||||
|
|
||||||
|
libminiupnpc.a: miniwget.o minixml.o igd_desc_parse.o minisoap.o miniupnpc.o upnpreplyparse.o upnpcommands.o
|
||||||
|
$(AR) cr $@ $?
|
||||||
|
|
||||||
|
upnpc: upnpc.o libminiupnpc.a
|
||||||
|
|
||||||
|
minixml.o: minixml.c minixml.h
|
||||||
|
|
||||||
|
upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h upnpreplyparse.h upnpcommands.h
|
||||||
|
|
||||||
|
miniwget.o: miniwget.c miniwget.h
|
||||||
|
|
||||||
|
minisoap.o: minisoap.c minisoap.h
|
||||||
|
|
||||||
|
miniupnpc.o: miniupnpc.c miniupnpc.h minisoap.h miniwget.h minixml.h
|
||||||
|
|
||||||
|
igd_desc_parse.o: igd_desc_parse.c igd_desc_parse.h
|
||||||
|
|
||||||
|
testminixml: minixml.o igd_desc_parse.o testminixml.c
|
||||||
|
|
||||||
|
upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h
|
||||||
|
|
||||||
|
upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
Project: miniupnp
|
||||||
|
Project web page: http://miniupnp.free.fr/
|
||||||
|
Author: Thomas Bernard
|
||||||
|
Copyright (c) 2005 Thomas Bernard
|
||||||
|
This software is subject to the conditions detailed in the
|
||||||
|
LICENCE file provided within this distribution.
|
||||||
|
|
||||||
|
For the comfort of Win32 users, bsdqueue.h is included in the distribution.
|
||||||
|
Its licence is included in the header of the file.
|
||||||
|
bsdqueue.h is a copy of the sys/queue.h of an OpenBSD system.
|
||||||
|
|
||||||
|
* miniupnp Client *
|
||||||
|
|
||||||
|
To compile, simply run 'gmake' (could be 'make').
|
||||||
|
Under win32, to compile with MinGW, type "mingw32make.bat".
|
||||||
|
The compilation is known to work under linux, FreeBSD,
|
||||||
|
OpenBSD, MacOS X and cygwin.
|
||||||
|
To install the library and headers on the system use :
|
||||||
|
> su
|
||||||
|
> make install
|
||||||
|
> exit
|
||||||
|
|
||||||
|
upnpc.c is a sample client using the libminiupnpc.
|
||||||
|
To use the libminiupnpc in your application, link it with
|
||||||
|
libminiupnpc.a and use the following functions found in miniupnpc.h,
|
||||||
|
upnpcommands.h and miniwget.h :
|
||||||
|
- upnpDiscover()
|
||||||
|
- miniwget()
|
||||||
|
- parserootdesc()
|
||||||
|
- GetUPNPUrls()
|
||||||
|
- UPNP_* (calling UPNP methods)
|
||||||
|
|
||||||
|
Note : use #include <miniupnpc/miniupnpc.h> etc... for the includes
|
||||||
|
and -lminiupnpc for the link
|
||||||
|
|
||||||
|
Feel free to contact me if you have any problem :
|
||||||
|
e-mail : miniupnp@free.fr
|
||||||
|
|
||||||
|
If you are using libminiupnpc in your application, please
|
||||||
|
send me an email !
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,531 @@
|
||||||
|
/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */
|
||||||
|
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1991, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_QUEUE_H_
|
||||||
|
#define _SYS_QUEUE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file defines five types of data structures: singly-linked lists,
|
||||||
|
* lists, simple queues, tail queues, and circular queues.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* A singly-linked list is headed by a single forward pointer. The elements
|
||||||
|
* are singly linked for minimum space and pointer manipulation overhead at
|
||||||
|
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||||
|
* added to the list after an existing element or at the head of the list.
|
||||||
|
* Elements being removed from the head of the list should use the explicit
|
||||||
|
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||||
|
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||||
|
* for applications with large datasets and few or no removals or for
|
||||||
|
* implementing a LIFO queue.
|
||||||
|
*
|
||||||
|
* A list is headed by a single forward pointer (or an array of forward
|
||||||
|
* pointers for a hash table header). The elements are doubly linked
|
||||||
|
* so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before
|
||||||
|
* or after an existing element or at the head of the list. A list
|
||||||
|
* may only be traversed in the forward direction.
|
||||||
|
*
|
||||||
|
* A simple queue is headed by a pair of pointers, one the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are singly
|
||||||
|
* linked to save space, so elements can only be removed from the
|
||||||
|
* head of the list. New elements can be added to the list before or after
|
||||||
|
* an existing element, at the head of the list, or at the end of the
|
||||||
|
* list. A simple queue may only be traversed in the forward direction.
|
||||||
|
*
|
||||||
|
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are doubly
|
||||||
|
* linked so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before or
|
||||||
|
* after an existing element, at the head of the list, or at the end of
|
||||||
|
* the list. A tail queue may be traversed in either direction.
|
||||||
|
*
|
||||||
|
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are doubly
|
||||||
|
* linked so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before or after
|
||||||
|
* an existing element, at the head of the list, or at the end of the list.
|
||||||
|
* A circle queue may be traversed in either direction, but has a more
|
||||||
|
* complex end of list detection.
|
||||||
|
*
|
||||||
|
* For details on the use of these macros, see the queue(3) manual page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef QUEUE_MACRO_DEBUG
|
||||||
|
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
|
||||||
|
#else
|
||||||
|
#define _Q_INVALIDATE(a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked List definitions.
|
||||||
|
*/
|
||||||
|
#define SLIST_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *slh_first; /* first element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SLIST_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL }
|
||||||
|
|
||||||
|
#ifdef SLIST_ENTRY
|
||||||
|
#undef SLIST_ENTRY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SLIST_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *sle_next; /* next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked List access methods.
|
||||||
|
*/
|
||||||
|
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||||
|
#define SLIST_END(head) NULL
|
||||||
|
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
|
||||||
|
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||||
|
|
||||||
|
#define SLIST_FOREACH(var, head, field) \
|
||||||
|
for((var) = SLIST_FIRST(head); \
|
||||||
|
(var) != SLIST_END(head); \
|
||||||
|
(var) = SLIST_NEXT(var, field))
|
||||||
|
|
||||||
|
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
|
||||||
|
for ((varp) = &SLIST_FIRST((head)); \
|
||||||
|
((var) = *(varp)) != SLIST_END(head); \
|
||||||
|
(varp) = &SLIST_NEXT((var), field))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked List functions.
|
||||||
|
*/
|
||||||
|
#define SLIST_INIT(head) { \
|
||||||
|
SLIST_FIRST(head) = SLIST_END(head); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||||
|
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||||
|
(slistelm)->field.sle_next = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
(elm)->field.sle_next = (head)->slh_first; \
|
||||||
|
(head)->slh_first = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SLIST_REMOVE_NEXT(head, elm, field) do { \
|
||||||
|
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||||
|
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||||
|
if ((head)->slh_first == (elm)) { \
|
||||||
|
SLIST_REMOVE_HEAD((head), field); \
|
||||||
|
} else { \
|
||||||
|
struct type *curelm = (head)->slh_first; \
|
||||||
|
\
|
||||||
|
while (curelm->field.sle_next != (elm)) \
|
||||||
|
curelm = curelm->field.sle_next; \
|
||||||
|
curelm->field.sle_next = \
|
||||||
|
curelm->field.sle_next->field.sle_next; \
|
||||||
|
_Q_INVALIDATE((elm)->field.sle_next); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List definitions.
|
||||||
|
*/
|
||||||
|
#define LIST_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *lh_first; /* first element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIST_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL }
|
||||||
|
|
||||||
|
#define LIST_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *le_next; /* next element */ \
|
||||||
|
struct type **le_prev; /* address of previous next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List access methods
|
||||||
|
*/
|
||||||
|
#define LIST_FIRST(head) ((head)->lh_first)
|
||||||
|
#define LIST_END(head) NULL
|
||||||
|
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
|
||||||
|
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||||
|
|
||||||
|
#define LIST_FOREACH(var, head, field) \
|
||||||
|
for((var) = LIST_FIRST(head); \
|
||||||
|
(var)!= LIST_END(head); \
|
||||||
|
(var) = LIST_NEXT(var, field))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List functions.
|
||||||
|
*/
|
||||||
|
#define LIST_INIT(head) do { \
|
||||||
|
LIST_FIRST(head) = LIST_END(head); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||||
|
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||||
|
(listelm)->field.le_next->field.le_prev = \
|
||||||
|
&(elm)->field.le_next; \
|
||||||
|
(listelm)->field.le_next = (elm); \
|
||||||
|
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||||
|
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||||
|
(elm)->field.le_next = (listelm); \
|
||||||
|
*(listelm)->field.le_prev = (elm); \
|
||||||
|
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||||
|
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||||
|
(head)->lh_first = (elm); \
|
||||||
|
(elm)->field.le_prev = &(head)->lh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_REMOVE(elm, field) do { \
|
||||||
|
if ((elm)->field.le_next != NULL) \
|
||||||
|
(elm)->field.le_next->field.le_prev = \
|
||||||
|
(elm)->field.le_prev; \
|
||||||
|
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||||
|
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.le_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_REPLACE(elm, elm2, field) do { \
|
||||||
|
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||||
|
(elm2)->field.le_next->field.le_prev = \
|
||||||
|
&(elm2)->field.le_next; \
|
||||||
|
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||||
|
*(elm2)->field.le_prev = (elm2); \
|
||||||
|
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.le_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple queue definitions.
|
||||||
|
*/
|
||||||
|
#define SIMPLEQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *sqh_first; /* first element */ \
|
||||||
|
struct type **sqh_last; /* addr of last next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL, &(head).sqh_first }
|
||||||
|
|
||||||
|
#define SIMPLEQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *sqe_next; /* next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple queue access methods.
|
||||||
|
*/
|
||||||
|
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||||
|
#define SIMPLEQ_END(head) NULL
|
||||||
|
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
|
||||||
|
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||||
|
|
||||||
|
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||||
|
for((var) = SIMPLEQ_FIRST(head); \
|
||||||
|
(var) != SIMPLEQ_END(head); \
|
||||||
|
(var) = SIMPLEQ_NEXT(var, field))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple queue functions.
|
||||||
|
*/
|
||||||
|
#define SIMPLEQ_INIT(head) do { \
|
||||||
|
(head)->sqh_first = NULL; \
|
||||||
|
(head)->sqh_last = &(head)->sqh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
(head)->sqh_first = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
(elm)->field.sqe_next = NULL; \
|
||||||
|
*(head)->sqh_last = (elm); \
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
(listelm)->field.sqe_next = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||||
|
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||||
|
(head)->sqh_last = &(head)->sqh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tail queue definitions.
|
||||||
|
*/
|
||||||
|
#define TAILQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *tqh_first; /* first element */ \
|
||||||
|
struct type **tqh_last; /* addr of last next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL, &(head).tqh_first }
|
||||||
|
|
||||||
|
#define TAILQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *tqe_next; /* next element */ \
|
||||||
|
struct type **tqe_prev; /* address of previous next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tail queue access methods
|
||||||
|
*/
|
||||||
|
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||||
|
#define TAILQ_END(head) NULL
|
||||||
|
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||||
|
#define TAILQ_LAST(head, headname) \
|
||||||
|
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||||
|
/* XXX */
|
||||||
|
#define TAILQ_PREV(elm, headname, field) \
|
||||||
|
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||||
|
#define TAILQ_EMPTY(head) \
|
||||||
|
(TAILQ_FIRST(head) == TAILQ_END(head))
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH(var, head, field) \
|
||||||
|
for((var) = TAILQ_FIRST(head); \
|
||||||
|
(var) != TAILQ_END(head); \
|
||||||
|
(var) = TAILQ_NEXT(var, field))
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||||
|
for((var) = TAILQ_LAST(head, headname); \
|
||||||
|
(var) != TAILQ_END(head); \
|
||||||
|
(var) = TAILQ_PREV(var, headname, field))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tail queue functions.
|
||||||
|
*/
|
||||||
|
#define TAILQ_INIT(head) do { \
|
||||||
|
(head)->tqh_first = NULL; \
|
||||||
|
(head)->tqh_last = &(head)->tqh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||||
|
(head)->tqh_first->field.tqe_prev = \
|
||||||
|
&(elm)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
(head)->tqh_first = (elm); \
|
||||||
|
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
(elm)->field.tqe_next = NULL; \
|
||||||
|
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||||
|
*(head)->tqh_last = (elm); \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev = \
|
||||||
|
&(elm)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
(listelm)->field.tqe_next = (elm); \
|
||||||
|
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||||
|
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||||
|
(elm)->field.tqe_next = (listelm); \
|
||||||
|
*(listelm)->field.tqe_prev = (elm); \
|
||||||
|
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||||
|
if (((elm)->field.tqe_next) != NULL) \
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev = \
|
||||||
|
(elm)->field.tqe_prev; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||||
|
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||||
|
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||||
|
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||||
|
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||||
|
&(elm2)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||||
|
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||||
|
*(elm2)->field.tqe_prev = (elm2); \
|
||||||
|
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue definitions.
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *cqh_first; /* first element */ \
|
||||||
|
struct type *cqh_last; /* last element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
||||||
|
|
||||||
|
#define CIRCLEQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *cqe_next; /* next element */ \
|
||||||
|
struct type *cqe_prev; /* previous element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue access methods
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||||
|
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||||
|
#define CIRCLEQ_END(head) ((void *)(head))
|
||||||
|
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||||
|
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||||
|
#define CIRCLEQ_EMPTY(head) \
|
||||||
|
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
|
||||||
|
|
||||||
|
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||||
|
for((var) = CIRCLEQ_FIRST(head); \
|
||||||
|
(var) != CIRCLEQ_END(head); \
|
||||||
|
(var) = CIRCLEQ_NEXT(var, field))
|
||||||
|
|
||||||
|
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||||
|
for((var) = CIRCLEQ_LAST(head); \
|
||||||
|
(var) != CIRCLEQ_END(head); \
|
||||||
|
(var) = CIRCLEQ_PREV(var, field))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue functions.
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_INIT(head) do { \
|
||||||
|
(head)->cqh_first = CIRCLEQ_END(head); \
|
||||||
|
(head)->cqh_last = CIRCLEQ_END(head); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||||
|
(elm)->field.cqe_prev = (listelm); \
|
||||||
|
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
else \
|
||||||
|
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||||
|
(listelm)->field.cqe_next = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||||
|
(elm)->field.cqe_next = (listelm); \
|
||||||
|
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||||
|
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
else \
|
||||||
|
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||||
|
(listelm)->field.cqe_prev = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||||
|
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
||||||
|
if ((head)->cqh_last == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
else \
|
||||||
|
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
||||||
|
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||||
|
if ((head)->cqh_first == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
else \
|
||||||
|
(head)->cqh_last->field.cqe_next = (elm); \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||||
|
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||||
|
else \
|
||||||
|
(elm)->field.cqe_next->field.cqe_prev = \
|
||||||
|
(elm)->field.cqe_prev; \
|
||||||
|
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||||
|
else \
|
||||||
|
(elm)->field.cqe_prev->field.cqe_next = \
|
||||||
|
(elm)->field.cqe_next; \
|
||||||
|
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||||
|
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||||
|
CIRCLEQ_END(head)) \
|
||||||
|
(head).cqh_last = (elm2); \
|
||||||
|
else \
|
||||||
|
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||||
|
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||||
|
CIRCLEQ_END(head)) \
|
||||||
|
(head).cqh_first = (elm2); \
|
||||||
|
else \
|
||||||
|
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||||
|
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* !_SYS_QUEUE_H_ */
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef __DECLSPEC_H__
|
||||||
|
#define __DECLSPEC_H__
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#ifdef MINIUPNP_EXPORTS
|
||||||
|
#define LIBSPEC __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define LIBSPEC __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define LIBSPEC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
/* $Id: igd_desc_parse.c,v 1.7 2006/11/19 22:32:33 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#include "igd_desc_parse.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Start element handler :
|
||||||
|
* update nesting level counter and copy element name */
|
||||||
|
void IGDstartelt(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||||
|
memcpy( datas->cureltname, name, l);
|
||||||
|
datas->cureltname[l] = '\0';
|
||||||
|
datas->level++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End element handler :
|
||||||
|
* update nesting level counter and update parser state if
|
||||||
|
* service element is parsed */
|
||||||
|
void IGDendelt(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||||
|
datas->level--;
|
||||||
|
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/
|
||||||
|
if( (l==7) && !memcmp(name, "service", l) )
|
||||||
|
{
|
||||||
|
/*datas->state++; */
|
||||||
|
/*
|
||||||
|
if( datas->state < 1
|
||||||
|
&& !strcmp(datas->servicetype,
|
||||||
|
// "urn:schemas-upnp-org:service:WANIPConnection:1") )
|
||||||
|
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
|
||||||
|
datas->state ++;
|
||||||
|
*/
|
||||||
|
if(0==strcmp(datas->servicetype_CIF,
|
||||||
|
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
|
||||||
|
datas->state = 2;
|
||||||
|
if(0==strcmp(datas->servicetype,
|
||||||
|
"urn:schemas-upnp-org:service:WANIPConnection:1") )
|
||||||
|
datas->state = 3;
|
||||||
|
/* if(0==strcmp(datas->servicetype,
|
||||||
|
"urn:schemas-upnp-org:service:WANPPPConnection:1") )
|
||||||
|
datas->state = 4; */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data handler :
|
||||||
|
* copy data depending on the current element name and state */
|
||||||
|
void IGDdata(void * d, const char * data, int l)
|
||||||
|
{
|
||||||
|
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||||
|
char * dstmember = 0;
|
||||||
|
/*printf("%2d %s : %.*s\n",
|
||||||
|
datas->level, datas->cureltname, l, data); */
|
||||||
|
if( !strcmp(datas->cureltname, "URLBase") )
|
||||||
|
dstmember = datas->urlbase;
|
||||||
|
else if(datas->state<=1)
|
||||||
|
{
|
||||||
|
if( !strcmp(datas->cureltname, "serviceType") )
|
||||||
|
dstmember = datas->servicetype_CIF;
|
||||||
|
else if( !strcmp(datas->cureltname, "controlURL") )
|
||||||
|
dstmember = datas->controlurl_CIF;
|
||||||
|
else if( !strcmp(datas->cureltname, "eventSubURL") )
|
||||||
|
dstmember = datas->eventsuburl_CIF;
|
||||||
|
else if( !strcmp(datas->cureltname, "SCPDURL") )
|
||||||
|
dstmember = datas->scpdurl_CIF;
|
||||||
|
else if( !strcmp(datas->cureltname, "deviceType") )
|
||||||
|
dstmember = datas->devicetype_CIF;
|
||||||
|
}
|
||||||
|
else if(datas->state==2)
|
||||||
|
{
|
||||||
|
if( !strcmp(datas->cureltname, "serviceType") )
|
||||||
|
dstmember = datas->servicetype;
|
||||||
|
else if( !strcmp(datas->cureltname, "controlURL") )
|
||||||
|
dstmember = datas->controlurl;
|
||||||
|
else if( !strcmp(datas->cureltname, "eventSubURL") )
|
||||||
|
dstmember = datas->eventsuburl;
|
||||||
|
else if( !strcmp(datas->cureltname, "SCPDURL") )
|
||||||
|
dstmember = datas->scpdurl;
|
||||||
|
else if( !strcmp(datas->cureltname, "deviceType") )
|
||||||
|
dstmember = datas->devicetype;
|
||||||
|
}
|
||||||
|
if(dstmember)
|
||||||
|
{
|
||||||
|
if(l>=MINIUPNPC_URL_MAXSIZE)
|
||||||
|
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||||
|
memcpy(dstmember, data, l);
|
||||||
|
dstmember[l] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printIGD(struct IGDdatas * d)
|
||||||
|
{
|
||||||
|
printf("urlbase = %s\n", d->urlbase);
|
||||||
|
printf("WAN Device (Common interface config) :\n");
|
||||||
|
printf(" deviceType = %s\n", d->devicetype_CIF);
|
||||||
|
printf(" serviceType = %s\n", d->servicetype_CIF);
|
||||||
|
printf(" controlURL = %s\n", d->controlurl_CIF);
|
||||||
|
printf(" eventSubURL = %s\n", d->eventsuburl_CIF);
|
||||||
|
printf(" SCPDURL = %s\n", d->scpdurl_CIF);
|
||||||
|
printf("WAN Connection Device :\n");
|
||||||
|
printf(" deviceType = %s\n", d->devicetype);
|
||||||
|
printf(" servicetype = %s\n", d->servicetype);
|
||||||
|
printf(" controlURL = %s\n", d->controlurl);
|
||||||
|
printf(" eventSubURL = %s\n", d->eventsuburl);
|
||||||
|
printf(" SCPDURL = %s\n", d->scpdurl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* $Id: igd_desc_parse.h,v 1.4 2006/07/06 00:05:11 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#ifndef __IGD_DESC_PARSE_H__
|
||||||
|
#define __IGD_DESC_PARSE_H__
|
||||||
|
|
||||||
|
/* Structure to store the result of the parsing of UPnP
|
||||||
|
* descriptions of Internet Gateway Devices */
|
||||||
|
#define MINIUPNPC_URL_MAXSIZE (64)
|
||||||
|
struct IGDdatas {
|
||||||
|
char cureltname[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char urlbase[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
int level;
|
||||||
|
int state;
|
||||||
|
char controlurl_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char eventsuburl_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char scpdurl_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char servicetype_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char devicetype_CIF[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char controlurl[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char eventsuburl[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char scpdurl[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char servicetype[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char devicetype[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
void IGDstartelt(void *, const char *, int);
|
||||||
|
void IGDendelt(void *, const char *, int);
|
||||||
|
void IGDdata(void *, const char *, int);
|
||||||
|
void printIGD(struct IGDdatas *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
mingw32-make -f Makefile.mingw
|
||||||
|
if errorlevel 1 goto end
|
||||||
|
strip upnpc.exe
|
||||||
|
upx --best upnpc.exe
|
||||||
|
:end
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* $Id: minisoap.c,v 1.10 2007/01/29 20:05:07 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
*
|
||||||
|
* Minimal SOAP implementation for UPnP protocol.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <io.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
#include "minisoap.h"
|
||||||
|
|
||||||
|
/* only for malloc */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* httpWrite sends the headers and the body to the socket
|
||||||
|
* and returns the number of bytes sent */
|
||||||
|
static int
|
||||||
|
httpWrite(int fd, const char * body, int bodysize,
|
||||||
|
const char * headers, int headerssize)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
/*n = write(fd, headers, headerssize);*/
|
||||||
|
/*if(bodysize>0)
|
||||||
|
n += write(fd, body, bodysize);*/
|
||||||
|
/* Note : my old linksys router only took into account
|
||||||
|
* soap request that are sent into only one packet */
|
||||||
|
char * p;
|
||||||
|
p = malloc(headerssize+bodysize);
|
||||||
|
memcpy(p, headers, headerssize);
|
||||||
|
memcpy(p+headerssize, body, bodysize);
|
||||||
|
/*n = write(fd, p, headerssize+bodysize);*/
|
||||||
|
n = send(fd, p, headerssize+bodysize, 0);
|
||||||
|
shutdown(fd, SHUT_WR); /*SD_SEND*/
|
||||||
|
free(p);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* self explanatory */
|
||||||
|
int soapPostSubmit(int fd,
|
||||||
|
const char * url,
|
||||||
|
const char * host,
|
||||||
|
unsigned short port,
|
||||||
|
const char * action,
|
||||||
|
const char * body)
|
||||||
|
{
|
||||||
|
int bodysize;
|
||||||
|
char headerbuf[1024];
|
||||||
|
int headerssize;
|
||||||
|
bodysize = (int)strlen(body);
|
||||||
|
headerssize = snprintf(headerbuf, sizeof(headerbuf),
|
||||||
|
"POST %s HTTP/1.1\r\n"
|
||||||
|
"HOST: %s:%d\r\n"
|
||||||
|
"Content-length: %d\r\n"
|
||||||
|
"Content-Type: text/xml\r\n"
|
||||||
|
"SOAPAction: \"%s\"\r\n"
|
||||||
|
"Connection: Close\r\n"
|
||||||
|
"\r\n",
|
||||||
|
url, host, port, bodysize, action);
|
||||||
|
return httpWrite(fd, body, bodysize, headerbuf, headerssize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/* $Id: minisoap.h,v 1.3 2006/11/19 22:32:34 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution. */
|
||||||
|
#ifndef __MINISOAP_H__
|
||||||
|
#define __MINISOAP_H__
|
||||||
|
|
||||||
|
/*int httpWrite(int, const char *, int, const char *);*/
|
||||||
|
int soapPostSubmit(int, const char *, const char *, unsigned short,
|
||||||
|
const char *, const char *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,659 @@
|
||||||
|
/* $Id: miniupnpc.c,v 1.38 2007/03/01 22:29:49 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas BERNARD
|
||||||
|
* copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subjet to the conditions detailed in the
|
||||||
|
* provided LICENCE file. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <Ws2tcpip.h>
|
||||||
|
#include <io.h>
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define strncasecmp memicmp
|
||||||
|
#define MAXHOSTNAMELEN 64
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#define closesocket close
|
||||||
|
#endif
|
||||||
|
#include "miniupnpc.h"
|
||||||
|
#include "miniwget.h"
|
||||||
|
#include "minisoap.h"
|
||||||
|
#include "minixml.h"
|
||||||
|
#include "upnpcommands.h"
|
||||||
|
|
||||||
|
/* Uncomment the following to transmit the msearch from the same port
|
||||||
|
* as the UPnP multicast port. With WinXP this seems to result in the
|
||||||
|
* responses to the msearch being lost, thus if things dont work then
|
||||||
|
* comment this out. */
|
||||||
|
/* #define TX_FROM_UPNP_PORT */
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
|
||||||
|
#else
|
||||||
|
#define PRINT_SOCKET_ERROR(x) perror(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* root description parsing */
|
||||||
|
void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
struct xmlparser parser;
|
||||||
|
/* xmlparser object */
|
||||||
|
parser.xmlstart = buffer;
|
||||||
|
parser.xmlsize = bufsize;
|
||||||
|
parser.data = data;
|
||||||
|
parser.starteltfunc = IGDstartelt;
|
||||||
|
parser.endeltfunc = IGDendelt;
|
||||||
|
parser.datafunc = IGDdata;
|
||||||
|
parser.attfunc = 0;
|
||||||
|
parsexml(&parser);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printIGD(data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content-length: nnn */
|
||||||
|
static int getcontentlenfromline(const char * p, int n)
|
||||||
|
{
|
||||||
|
static const char contlenstr[] = "content-length";
|
||||||
|
const char * p2 = contlenstr;
|
||||||
|
int a = 0;
|
||||||
|
while(*p2)
|
||||||
|
{
|
||||||
|
if(n==0)
|
||||||
|
return -1;
|
||||||
|
if(*p2 != *p && *p2 != (*p + 32))
|
||||||
|
return -1;
|
||||||
|
p++; p2++; n--;
|
||||||
|
}
|
||||||
|
if(n==0)
|
||||||
|
return -1;
|
||||||
|
if(*p != ':')
|
||||||
|
return -1;
|
||||||
|
p++; n--;
|
||||||
|
while(*p == ' ')
|
||||||
|
{
|
||||||
|
if(n==0)
|
||||||
|
return -1;
|
||||||
|
p++; n--;
|
||||||
|
}
|
||||||
|
while(*p >= '0' && *p <= '9')
|
||||||
|
{
|
||||||
|
if(n==0)
|
||||||
|
return -1;
|
||||||
|
a = (a * 10) + (*p - '0');
|
||||||
|
p++; n--;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getContentLengthAndHeaderLength(char * p, int n,
|
||||||
|
int * contentlen, int * headerlen)
|
||||||
|
{
|
||||||
|
char * line;
|
||||||
|
int linelen;
|
||||||
|
int r;
|
||||||
|
line = p;
|
||||||
|
while(line < p + n)
|
||||||
|
{
|
||||||
|
linelen = 0;
|
||||||
|
while(line[linelen] != '\r' && line[linelen] != '\r')
|
||||||
|
{
|
||||||
|
if(line+linelen >= p+n)
|
||||||
|
return;
|
||||||
|
linelen++;
|
||||||
|
}
|
||||||
|
r = getcontentlenfromline(line, linelen);
|
||||||
|
if(r>0)
|
||||||
|
*contentlen = r;
|
||||||
|
line = line + linelen + 2;
|
||||||
|
if(line[0] == '\r' && line[1] == '\n')
|
||||||
|
{
|
||||||
|
*headerlen = (line - p) + 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simpleUPnPcommand :
|
||||||
|
* not so simple !
|
||||||
|
* */
|
||||||
|
int simpleUPnPcommand(int s, const char * url, const char * service,
|
||||||
|
const char * action, struct UPNParg * args,
|
||||||
|
char * buffer, int * bufsize)
|
||||||
|
{
|
||||||
|
struct sockaddr_in dest;
|
||||||
|
char hostname[MAXHOSTNAMELEN+1];
|
||||||
|
unsigned short port = 0;
|
||||||
|
char * path;
|
||||||
|
char soapact[128];
|
||||||
|
char soapbody[2048];
|
||||||
|
int soapbodylen;
|
||||||
|
char * buf;
|
||||||
|
int buffree;
|
||||||
|
int n;
|
||||||
|
int contentlen, headerlen; /* for the response */
|
||||||
|
snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
|
||||||
|
if(args==NULL)
|
||||||
|
{
|
||||||
|
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||||
|
"<?xml version=\"1.0\"?>\r\n"
|
||||||
|
"<SOAP-ENV:Envelope "
|
||||||
|
"xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||||
|
"SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||||
|
"<SOAP-ENV:Body>"
|
||||||
|
"<m:%s xmlns:m=\"%s\"/>"
|
||||||
|
"</SOAP-ENV:Body></SOAP-ENV:Envelope>"
|
||||||
|
"\r\n", action, service);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char * p;
|
||||||
|
const char * pe, * pv;
|
||||||
|
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||||
|
"<?xml version=\"1.0\"?>\r\n"
|
||||||
|
"<SOAP-ENV:Envelope "
|
||||||
|
"xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||||
|
"SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||||
|
"<SOAP-ENV:Body>"
|
||||||
|
"<m:%s xmlns:m=\"%s\">",
|
||||||
|
action, service);
|
||||||
|
p = soapbody + soapbodylen;
|
||||||
|
while(args->elt)
|
||||||
|
{
|
||||||
|
/* check that we are never overflowing the string... */
|
||||||
|
if(soapbody + sizeof(soapbody) <= p + 100)
|
||||||
|
{
|
||||||
|
/* we keep a margin of at least 100 bytes */
|
||||||
|
*bufsize = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*(p++) = '<';
|
||||||
|
pe = args->elt;
|
||||||
|
while(*pe)
|
||||||
|
*(p++) = *(pe++);
|
||||||
|
*(p++) = '>';
|
||||||
|
if((pv = args->val))
|
||||||
|
{
|
||||||
|
while(*pv)
|
||||||
|
*(p++) = *(pv++);
|
||||||
|
}
|
||||||
|
*(p++) = '<';
|
||||||
|
*(p++) = '/';
|
||||||
|
pe = args->elt;
|
||||||
|
while(*pe)
|
||||||
|
*(p++) = *(pe++);
|
||||||
|
*(p++) = '>';
|
||||||
|
args++;
|
||||||
|
}
|
||||||
|
*(p++) = '<';
|
||||||
|
*(p++) = '/';
|
||||||
|
*(p++) = 'm';
|
||||||
|
*(p++) = ':';
|
||||||
|
pe = action;
|
||||||
|
while(*pe)
|
||||||
|
*(p++) = *(pe++);
|
||||||
|
strncpy(p, "></SOAP-ENV:Body></SOAP-ENV:Envelope>\r\n",
|
||||||
|
soapbody + sizeof(soapbody) - p);
|
||||||
|
}
|
||||||
|
if(!parseURL(url, hostname, &port, &path)) return -1;
|
||||||
|
if(s<0)
|
||||||
|
{
|
||||||
|
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
dest.sin_family = AF_INET;
|
||||||
|
dest.sin_port = htons(port);
|
||||||
|
dest.sin_addr.s_addr = inet_addr(hostname);
|
||||||
|
if(connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("connect");
|
||||||
|
*bufsize = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n = soapPostSubmit(s, path, hostname, port, soapact, soapbody);
|
||||||
|
|
||||||
|
contentlen = -1;
|
||||||
|
headerlen = -1;
|
||||||
|
buf = buffer;
|
||||||
|
buffree = *bufsize;
|
||||||
|
*bufsize = 0;
|
||||||
|
while ((n = ReceiveData(s, buf, buffree, 5000)) > 0) {
|
||||||
|
buffree -= n;
|
||||||
|
buf += n;
|
||||||
|
*bufsize += n;
|
||||||
|
getContentLengthAndHeaderLength(buffer, *bufsize,
|
||||||
|
&contentlen, &headerlen);
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("n=%d bufsize=%d ContLen=%d HeadLen=%d\n",
|
||||||
|
n, *bufsize, contentlen, headerlen);
|
||||||
|
#endif
|
||||||
|
if(contentlen > 0 && headerlen > 0 && *bufsize >= contentlen+headerlen)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
closesocket(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parseMSEARCHReply()
|
||||||
|
* the last 4 arguments are filled during the parsing :
|
||||||
|
* - location/locationsize : "location:" field of the SSDP reply packet
|
||||||
|
* - st/stsize : "st:" field of the SSDP reply packet.
|
||||||
|
* The strings are NOT null terminated */
|
||||||
|
static void
|
||||||
|
parseMSEARCHReply(const char * reply, int size,
|
||||||
|
const char * * location, int * locationsize,
|
||||||
|
const char * * st, int * stsize)
|
||||||
|
{
|
||||||
|
int a, b, i;
|
||||||
|
i = 0;
|
||||||
|
a = i; /* start of the line */
|
||||||
|
b = 0;
|
||||||
|
while(i<size)
|
||||||
|
{
|
||||||
|
switch(reply[i])
|
||||||
|
{
|
||||||
|
case ':':
|
||||||
|
if(b==0)
|
||||||
|
{
|
||||||
|
b = i; /* end of the "header" */
|
||||||
|
/*for(j=a; j<b; j++)
|
||||||
|
{
|
||||||
|
putchar(reply[j]);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\x0a':
|
||||||
|
case '\x0d':
|
||||||
|
if(b!=0)
|
||||||
|
{
|
||||||
|
/*for(j=b+1; j<i; j++)
|
||||||
|
{
|
||||||
|
putchar(reply[j]);
|
||||||
|
}
|
||||||
|
putchar('\n');*/
|
||||||
|
do { b++; } while(reply[b]==' ');
|
||||||
|
if(0==strncasecmp(reply+a, "location", 8))
|
||||||
|
{
|
||||||
|
*location = reply+b;
|
||||||
|
*locationsize = i-b;
|
||||||
|
}
|
||||||
|
else if(0==strncasecmp(reply+a, "st", 2))
|
||||||
|
{
|
||||||
|
*st = reply+b;
|
||||||
|
*stsize = i-b;
|
||||||
|
}
|
||||||
|
b = 0;
|
||||||
|
}
|
||||||
|
a = i+1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* port upnp discover : SSDP protocol */
|
||||||
|
#define PORT (1900)
|
||||||
|
#define UPNP_MCAST_ADDR "239.255.255.250"
|
||||||
|
|
||||||
|
/* upnpDiscover() :
|
||||||
|
* return a chained list of all devices found or NULL if
|
||||||
|
* no devices was found.
|
||||||
|
* It is up to the caller to free the chained list
|
||||||
|
* delay is in millisecond (poll) */
|
||||||
|
struct UPNPDev * upnpDiscover(int delay)
|
||||||
|
{
|
||||||
|
struct UPNPDev * tmp;
|
||||||
|
struct UPNPDev * devlist = 0;
|
||||||
|
int opt = 1;
|
||||||
|
static const char MSearchMsgFmt[] =
|
||||||
|
"M-SEARCH * HTTP/1.1\r\n"
|
||||||
|
"HOST: " UPNP_MCAST_ADDR ":" "1900" "\r\n"
|
||||||
|
"ST: %s\r\n"
|
||||||
|
"MAN: \"ssdp:discover\"\r\n"
|
||||||
|
"MX: 3\r\n"
|
||||||
|
"\r\n";
|
||||||
|
static const char * const deviceList[] = {
|
||||||
|
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
|
||||||
|
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||||
|
"urn:schemas-upnp-org:service:WANPPPConnection:1",
|
||||||
|
"upnp:rootdevice",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
int deviceIndex = 0;
|
||||||
|
char bufr[1536]; /* reception and emission buffer */
|
||||||
|
int sudp;
|
||||||
|
int n;
|
||||||
|
struct sockaddr_in sockudp_r, sockudp_w;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
sudp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
#else
|
||||||
|
sudp = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
#endif
|
||||||
|
/* reception */
|
||||||
|
memset(&sockudp_r, 0, sizeof(struct sockaddr_in));
|
||||||
|
sockudp_r.sin_family = AF_INET;
|
||||||
|
#ifdef TX_FROM_UPNP_PORT
|
||||||
|
sockudp_r.sin_port = htons(PORT);
|
||||||
|
#endif
|
||||||
|
sockudp_r.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
/* emission */
|
||||||
|
memset(&sockudp_w, 0, sizeof(struct sockaddr_in));
|
||||||
|
sockudp_w.sin_family = AF_INET;
|
||||||
|
sockudp_w.sin_port = htons(PORT);
|
||||||
|
sockudp_w.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
|
||||||
|
#else
|
||||||
|
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("setsockopt");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avant d'envoyer le paquet on bind pour recevoir la reponse */
|
||||||
|
if (bind(sudp, (struct sockaddr *)&sockudp_r, sizeof(struct sockaddr_in)) != 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("bind");
|
||||||
|
closesocket(sudp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* receiving SSDP response packet */
|
||||||
|
for(n = 0;;)
|
||||||
|
{
|
||||||
|
if(n == 0)
|
||||||
|
{
|
||||||
|
/* sending the SSDP M-SEARCH packet */
|
||||||
|
n = snprintf(bufr, sizeof(bufr),
|
||||||
|
MSearchMsgFmt, deviceList[deviceIndex++]);
|
||||||
|
/*printf("Sending %s", bufr);*/
|
||||||
|
n = sendto(sudp, bufr, n, 0,
|
||||||
|
(struct sockaddr *)&sockudp_w, sizeof(struct sockaddr_in));
|
||||||
|
if (n < 0) {
|
||||||
|
PRINT_SOCKET_ERROR("sendto");
|
||||||
|
closesocket(sudp);
|
||||||
|
return devlist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Waiting for SSDP REPLY packet to M-SEARCH */
|
||||||
|
n = ReceiveData(sudp, bufr, sizeof(bufr), delay);
|
||||||
|
if (n < 0) {
|
||||||
|
/* error */
|
||||||
|
closesocket(sudp);
|
||||||
|
return devlist;
|
||||||
|
} else if (n == 0) {
|
||||||
|
/* no data or Time Out */
|
||||||
|
if (devlist || (deviceList[deviceIndex] == 0)) {
|
||||||
|
/* no more device type to look for... */
|
||||||
|
closesocket(sudp);
|
||||||
|
return devlist;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const char * descURL=NULL;
|
||||||
|
int urlsize=0;
|
||||||
|
const char * st=NULL;
|
||||||
|
int stsize=0;
|
||||||
|
/*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
|
||||||
|
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
|
||||||
|
if(st&&descURL)
|
||||||
|
{
|
||||||
|
/*printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
|
||||||
|
stsize, st, urlsize, descURL); */
|
||||||
|
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
|
||||||
|
tmp->pNext = devlist;
|
||||||
|
tmp->descURL = tmp->buffer;
|
||||||
|
tmp->st = tmp->buffer + 1 + urlsize;
|
||||||
|
memcpy(tmp->buffer, descURL, urlsize);
|
||||||
|
tmp->buffer[urlsize] = '\0';
|
||||||
|
memcpy(tmp->buffer + urlsize + 1, st, stsize);
|
||||||
|
tmp->buffer[urlsize+1+stsize] = '\0';
|
||||||
|
devlist = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* freeUPNPDevlist() should be used to
|
||||||
|
* free the chained list returned by upnpDiscover() */
|
||||||
|
void freeUPNPDevlist(struct UPNPDev * devlist)
|
||||||
|
{
|
||||||
|
struct UPNPDev * next;
|
||||||
|
while(devlist)
|
||||||
|
{
|
||||||
|
next = devlist->pNext;
|
||||||
|
free(devlist);
|
||||||
|
devlist = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
url_cpy_or_cat(char * dst, const char * src, int n)
|
||||||
|
{
|
||||||
|
if( (src[0] == 'h')
|
||||||
|
&&(src[1] == 't')
|
||||||
|
&&(src[2] == 't')
|
||||||
|
&&(src[3] == 'p')
|
||||||
|
&&(src[4] == ':')
|
||||||
|
&&(src[5] == '/')
|
||||||
|
&&(src[6] == '/'))
|
||||||
|
{
|
||||||
|
strncpy(dst, src, n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(src[0] != '/')
|
||||||
|
strncat(dst, "/", n-1);
|
||||||
|
strncat(dst, src, n-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare the Urls for usage...
|
||||||
|
*/
|
||||||
|
void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||||
|
const char * descURL)
|
||||||
|
{
|
||||||
|
char * p;
|
||||||
|
int n1, n2, n3;
|
||||||
|
n1 = strlen(data->urlbase);
|
||||||
|
if(n1==0)
|
||||||
|
n1 = strlen(descURL);
|
||||||
|
n1++;
|
||||||
|
n2 = n1; n3 = n1;
|
||||||
|
n1 += strlen(data->scpdurl);
|
||||||
|
n2 += strlen(data->controlurl);
|
||||||
|
n3 += strlen(data->controlurl_CIF);
|
||||||
|
|
||||||
|
urls->ipcondescURL = (char *)malloc(n1);
|
||||||
|
urls->controlURL = (char *)malloc(n2);
|
||||||
|
urls->controlURL_CIF = (char *)malloc(n3);
|
||||||
|
/* maintenant on chope la desc du WANIPConnection */
|
||||||
|
if(data->urlbase[0] != '\0')
|
||||||
|
strncpy(urls->ipcondescURL, data->urlbase, n1);
|
||||||
|
else
|
||||||
|
strncpy(urls->ipcondescURL, descURL, n1);
|
||||||
|
p = strchr(urls->ipcondescURL+7, '/');
|
||||||
|
if(p) p[0] = '\0';
|
||||||
|
strncpy(urls->controlURL, urls->ipcondescURL, n2);
|
||||||
|
strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
|
||||||
|
|
||||||
|
url_cpy_or_cat(urls->ipcondescURL, data->scpdurl, n1);
|
||||||
|
|
||||||
|
url_cpy_or_cat(urls->controlURL, data->controlurl, n2);
|
||||||
|
|
||||||
|
url_cpy_or_cat(urls->controlURL_CIF, data->controlurl_CIF, n3);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("urls->ipcondescURL='%s' %d n1=%d\n", urls->ipcondescURL,
|
||||||
|
strlen(urls->ipcondescURL), n1);
|
||||||
|
printf("urls->controlURL='%s' %d n2=%d\n", urls->controlURL,
|
||||||
|
strlen(urls->controlURL), n2);
|
||||||
|
printf("urls->controlURL_CIF='%s' %d n3=%d\n", urls->controlURL_CIF,
|
||||||
|
strlen(urls->controlURL_CIF), n3);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FreeUPNPUrls(struct UPNPUrls * urls)
|
||||||
|
{
|
||||||
|
if(!urls)
|
||||||
|
return;
|
||||||
|
free(urls->controlURL);
|
||||||
|
urls->controlURL = 0;
|
||||||
|
free(urls->ipcondescURL);
|
||||||
|
urls->ipcondescURL = 0;
|
||||||
|
free(urls->controlURL_CIF);
|
||||||
|
urls->controlURL_CIF = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ReceiveData(int socket, char * data, int length, int timeout)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
#ifndef WIN32
|
||||||
|
struct pollfd fds[1]; /* for the poll */
|
||||||
|
fds[0].fd = socket;
|
||||||
|
fds[0].events = POLLIN;
|
||||||
|
n = poll(fds, 1, timeout);
|
||||||
|
if(n < 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("poll");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if(n == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
fd_set socketSet;
|
||||||
|
TIMEVAL timeval;
|
||||||
|
FD_ZERO(&socketSet);
|
||||||
|
FD_SET(socket, &socketSet);
|
||||||
|
timeval.tv_sec = timeout / 1000;
|
||||||
|
timeval.tv_usec = (timeout % 1000) * 1000;
|
||||||
|
n = select(0, &socketSet, NULL, NULL, &timeval);
|
||||||
|
if(n < 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("poll");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if(n == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
n = recv(socket, data, length, 0);
|
||||||
|
if(n<0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("recv");
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
char status[64];
|
||||||
|
unsigned int uptime;
|
||||||
|
status[0] = '\0';
|
||||||
|
UPNP_GetStatusInfo(urls->controlURL, data->servicetype, status, &uptime);
|
||||||
|
if(0 == strcmp("Connected", status))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* UPNP_GetValidIGD() :
|
||||||
|
* return values :
|
||||||
|
* 0 = NO IGD found
|
||||||
|
* 1 = A valid connected IGD has been found
|
||||||
|
* 2 = A valid IGD has been found but it reported as
|
||||||
|
* not connected
|
||||||
|
* 3 = an UPnP device has been found but was not recognized as an IGD
|
||||||
|
*
|
||||||
|
* In any non zero return case, the urls and data structures
|
||||||
|
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
||||||
|
* free allocated memory.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||||
|
struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data,
|
||||||
|
char * lanaddr, int lanaddrlen)
|
||||||
|
{
|
||||||
|
char * descXML;
|
||||||
|
int descXMLsize = 0;
|
||||||
|
struct UPNPDev * dev;
|
||||||
|
int ndev = 0;
|
||||||
|
int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
|
||||||
|
if(!devlist)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Empty devlist\n");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for(state = 1; state <= 3; state++)
|
||||||
|
{
|
||||||
|
for(dev = devlist; dev; dev = dev->pNext)
|
||||||
|
{
|
||||||
|
/* we should choose an internet gateway device.
|
||||||
|
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
|
||||||
|
if((state >= 3) || strstr(dev->st, "InternetGatewayDevice"))
|
||||||
|
{
|
||||||
|
descXML = miniwget_getaddr(dev->descURL, &descXMLsize,
|
||||||
|
lanaddr, lanaddrlen);
|
||||||
|
if(descXML)
|
||||||
|
{
|
||||||
|
ndev++;
|
||||||
|
memset(data, 0, sizeof(struct IGDdatas));
|
||||||
|
memset(urls, 0, sizeof(struct UPNPUrls));
|
||||||
|
parserootdesc(descXML, descXMLsize, data);
|
||||||
|
free(descXML);
|
||||||
|
descXML = NULL;
|
||||||
|
GetUPNPUrls(urls, data, dev->descURL);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("UPNPIGD_IsConnected(%s) = %d\n",
|
||||||
|
urls->controlURL,
|
||||||
|
UPNPIGD_IsConnected(urls, data));
|
||||||
|
#endif
|
||||||
|
if((state >= 2) || UPNPIGD_IsConnected(urls, data))
|
||||||
|
return state;
|
||||||
|
FreeUPNPUrls(urls);
|
||||||
|
memset(data, 0, sizeof(struct IGDdatas));
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("error getting XML description %s\n", dev->descURL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* $Id: miniupnpc.h,v 1.13 2007/01/29 20:27:23 nanard Exp $ */
|
||||||
|
/* Project: miniupnp
|
||||||
|
* http://miniupnp.free.fr/
|
||||||
|
* Author: Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2006 Thomas Bernard
|
||||||
|
* This software is subjects to the conditions detailed
|
||||||
|
* in the LICENCE file provided within this distribution */
|
||||||
|
#ifndef __MINIUPNPC_H__
|
||||||
|
#define __MINIUPNPC_H__
|
||||||
|
|
||||||
|
#include "declspec.h"
|
||||||
|
#include "igd_desc_parse.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct UPNParg { const char * elt; const char * val; };
|
||||||
|
|
||||||
|
int simpleUPnPcommand(int, const char *, const char *,
|
||||||
|
const char *, struct UPNParg *,
|
||||||
|
char *, int *);
|
||||||
|
|
||||||
|
struct UPNPDev {
|
||||||
|
struct UPNPDev * pNext;
|
||||||
|
char * descURL;
|
||||||
|
char * st;
|
||||||
|
char buffer[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* discover UPnP devices on the network */
|
||||||
|
LIBSPEC struct UPNPDev * upnpDiscover(int);
|
||||||
|
/* free returned list from above function */
|
||||||
|
LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
|
||||||
|
|
||||||
|
LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
|
||||||
|
|
||||||
|
/* structure used to get fast access to urls
|
||||||
|
* controlURL: controlURL of the WANIPConnection
|
||||||
|
* ipcondescURL: url of the description of the WANIPConnection
|
||||||
|
* controlURL_CIF: controlURL of the WANCOmmonInterfaceConfig
|
||||||
|
*/
|
||||||
|
struct UPNPUrls {
|
||||||
|
char * controlURL;
|
||||||
|
char * ipcondescURL;
|
||||||
|
char * controlURL_CIF;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* UPNP_GetValidIGD() :
|
||||||
|
* return values :
|
||||||
|
* 0 = NO IGD found
|
||||||
|
* 1 = A valid connected IGD has been found
|
||||||
|
* 2 = A valid IGD has been found but it reported as
|
||||||
|
* not connected
|
||||||
|
* 3 = an UPnP device has been found but was not recognized as an IGD
|
||||||
|
*
|
||||||
|
* In any non zero return case, the urls and data structures
|
||||||
|
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
||||||
|
* free allocated memory.
|
||||||
|
*/
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||||
|
struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data,
|
||||||
|
char * lanaddr, int lanaddrlen);
|
||||||
|
|
||||||
|
LIBSPEC void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *);
|
||||||
|
|
||||||
|
LIBSPEC void FreeUPNPUrls(struct UPNPUrls *);
|
||||||
|
|
||||||
|
/* Reads data from the specified socket.
|
||||||
|
* Returns the number of bytes read if successful, zero if no bytes were
|
||||||
|
* read or if we timed out. Returns negative if there was an error. */
|
||||||
|
int ReceiveData(int socket, char * data, int length, int timeout);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
/* $Id: miniwget.c,v 1.17 2006/12/03 17:22:09 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "miniupnpc.h"
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <io.h>
|
||||||
|
#define MAXHOSTNAMELEN 64
|
||||||
|
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define herror
|
||||||
|
#define socklen_t int
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#define closesocket close
|
||||||
|
#endif
|
||||||
|
/* for MIN() macro : */
|
||||||
|
#if defined(__sun) || defined(sun)
|
||||||
|
#include <utility.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* miniwget2() :
|
||||||
|
* */
|
||||||
|
static void *
|
||||||
|
miniwget2(const char * url, const char * host,
|
||||||
|
unsigned short port, const char * path,
|
||||||
|
int * size, char * addr_str, int addr_str_len)
|
||||||
|
{
|
||||||
|
char buf[2048];
|
||||||
|
int s;
|
||||||
|
struct sockaddr_in dest;
|
||||||
|
struct hostent *hp;
|
||||||
|
*size = 0;
|
||||||
|
hp = gethostbyname(host);
|
||||||
|
if(hp==NULL)
|
||||||
|
{
|
||||||
|
herror(host);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy((char *)&dest.sin_addr, hp->h_addr, hp->h_length);
|
||||||
|
memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
|
||||||
|
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
dest.sin_family = AF_INET;
|
||||||
|
dest.sin_port = htons(port);
|
||||||
|
if(connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0)
|
||||||
|
{
|
||||||
|
perror("connect");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get address for caller ! */
|
||||||
|
if(addr_str)
|
||||||
|
{
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
socklen_t len;
|
||||||
|
|
||||||
|
len = sizeof(saddr);
|
||||||
|
getsockname(s, (struct sockaddr *)&saddr, &len);
|
||||||
|
#ifndef WIN32
|
||||||
|
inet_ntop(AF_INET, &saddr.sin_addr, addr_str, addr_str_len);
|
||||||
|
#else
|
||||||
|
/* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
|
||||||
|
* But his function make a string with the port : nn.nn.nn.nn:port */
|
||||||
|
/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
|
||||||
|
NULL, addr_str, (DWORD *)&addr_str_len))
|
||||||
|
{
|
||||||
|
printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError());
|
||||||
|
}*/
|
||||||
|
strncpy(addr_str, inet_ntoa(saddr.sin_addr), addr_str_len);
|
||||||
|
#endif
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("address miniwget : %s\n", addr_str);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, 2048,
|
||||||
|
"GET %s HTTP/1.1\r\n"
|
||||||
|
"Host: %s:%d\r\n"
|
||||||
|
"Connection: Close\r\n"
|
||||||
|
"\r\n",
|
||||||
|
path, host, port);
|
||||||
|
/*write(s, buf, strlen(buf));*/
|
||||||
|
send(s, buf, strlen(buf), 0);
|
||||||
|
{
|
||||||
|
int n, headers=1;
|
||||||
|
char * respbuffer = NULL;
|
||||||
|
int allreadyread = 0;
|
||||||
|
/*while((n = recv(s, buf, 2048, 0)) > 0)*/
|
||||||
|
while((n = ReceiveData(s, buf, 2048, 5000)) > 0)
|
||||||
|
{
|
||||||
|
if(headers)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
while(i<n-3)
|
||||||
|
{
|
||||||
|
if(buf[i]=='\r' && buf[i+1]=='\n'
|
||||||
|
&& buf[i+2]=='\r' && buf[i+3]=='\n')
|
||||||
|
{
|
||||||
|
headers = 0; /* end */
|
||||||
|
if(i<n-4)
|
||||||
|
{
|
||||||
|
respbuffer = (char *)realloc((void *)respbuffer,
|
||||||
|
allreadyread+(n-i-4));
|
||||||
|
memcpy(respbuffer+allreadyread, buf + i + 4, n-i-4);
|
||||||
|
allreadyread += (n-i-4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
respbuffer = (char *)realloc((void *)respbuffer,
|
||||||
|
allreadyread+n);
|
||||||
|
memcpy(respbuffer+allreadyread, buf, n);
|
||||||
|
allreadyread += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*size = allreadyread;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printf("%d bytes read\n", *size);
|
||||||
|
#endif
|
||||||
|
closesocket(s);
|
||||||
|
return respbuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parseURL()
|
||||||
|
* arguments :
|
||||||
|
* url : source string not modified
|
||||||
|
* hostname : hostname destination string (size of MAXHOSTNAMELEN+1)
|
||||||
|
* port : port (destination)
|
||||||
|
* path : pointer to the path part of the URL
|
||||||
|
*
|
||||||
|
* Return values :
|
||||||
|
* 0 - Failure
|
||||||
|
* 1 - Success */
|
||||||
|
int parseURL(const char * url, char * hostname, unsigned short * port, char * * path)
|
||||||
|
{
|
||||||
|
char * p1, *p2, *p3;
|
||||||
|
p1 = strstr(url, "://");
|
||||||
|
if(!p1)
|
||||||
|
return 0;
|
||||||
|
p1 += 3;
|
||||||
|
if( (url[0]!='h') || (url[1]!='t')
|
||||||
|
||(url[2]!='t') || (url[3]!='p'))
|
||||||
|
return 0;
|
||||||
|
p2 = strchr(p1, ':');
|
||||||
|
p3 = strchr(p1, '/');
|
||||||
|
if(!p3)
|
||||||
|
return 0;
|
||||||
|
memset(hostname, 0, MAXHOSTNAMELEN + 1);
|
||||||
|
if(!p2 || (p2>p3))
|
||||||
|
{
|
||||||
|
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
|
||||||
|
*port = 80;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||||
|
*port = 0;
|
||||||
|
p2++;
|
||||||
|
while( (*p2 >= '0') && (*p2 <= '9'))
|
||||||
|
{
|
||||||
|
*port *= 10;
|
||||||
|
*port += (unsigned short)(*p2 - '0');
|
||||||
|
p2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*path = p3;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * miniwget(const char * url, int * size)
|
||||||
|
{
|
||||||
|
unsigned short port;
|
||||||
|
char * path;
|
||||||
|
/* protocol://host:port/chemin */
|
||||||
|
char hostname[MAXHOSTNAMELEN+1];
|
||||||
|
*size = 0;
|
||||||
|
if(!parseURL(url, hostname, &port, &path))
|
||||||
|
return NULL;
|
||||||
|
return miniwget2(url, hostname, port, path, size, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen)
|
||||||
|
{
|
||||||
|
unsigned short port;
|
||||||
|
char * path;
|
||||||
|
/* protocol://host:port/chemin */
|
||||||
|
char hostname[MAXHOSTNAMELEN+1];
|
||||||
|
*size = 0;
|
||||||
|
if(addr)
|
||||||
|
addr[0] = '\0';
|
||||||
|
if(!parseURL(url, hostname, &port, &path))
|
||||||
|
return NULL;
|
||||||
|
return miniwget2(url, hostname, port, path, size, addr, addrlen);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* $Id: miniwget.h,v 1.5 2007/01/29 20:27:23 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#ifndef __MINIWGET_H__
|
||||||
|
#define __MINIWGET_H__
|
||||||
|
|
||||||
|
#include "declspec.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LIBSPEC void * miniwget(const char *, int *);
|
||||||
|
|
||||||
|
LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int);
|
||||||
|
|
||||||
|
int parseURL(const char *, char *, unsigned short *, char * *);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
/* $Id: minixml.c,v 1.5 2007/01/27 14:20:00 nanard Exp $ */
|
||||||
|
/* minixml.c : the minimum size a xml parser can be ! */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
|
||||||
|
Copyright (c) 2005-2006, Thomas BERNARD
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "minixml.h"
|
||||||
|
|
||||||
|
/* parseatt : used to parse the argument list
|
||||||
|
* return 0 (false) in case of success and -1 (true) if the end
|
||||||
|
* of the xmlbuffer is reached. */
|
||||||
|
int parseatt(struct xmlparser * p)
|
||||||
|
{
|
||||||
|
const char * attname;
|
||||||
|
int attnamelen;
|
||||||
|
const char * attvalue;
|
||||||
|
int attvaluelen;
|
||||||
|
while(p->xml < p->xmlend)
|
||||||
|
{
|
||||||
|
if(*p->xml=='/' || *p->xml=='>')
|
||||||
|
return 0;
|
||||||
|
if( !IS_WHITE_SPACE(*p->xml) )
|
||||||
|
{
|
||||||
|
char sep;
|
||||||
|
attname = p->xml;
|
||||||
|
attnamelen = 0;
|
||||||
|
while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
|
||||||
|
{
|
||||||
|
attnamelen++; p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while(*(p->xml++) != '=')
|
||||||
|
{
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while(IS_WHITE_SPACE(*p->xml))
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sep = *p->xml;
|
||||||
|
if(sep=='\'' || sep=='\"')
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
attvalue = p->xml;
|
||||||
|
attvaluelen = 0;
|
||||||
|
while(*p->xml != sep)
|
||||||
|
{
|
||||||
|
attvaluelen++; p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
attvalue = p->xml;
|
||||||
|
attvaluelen = 0;
|
||||||
|
while( !IS_WHITE_SPACE(*p->xml)
|
||||||
|
&& *p->xml != '>' && *p->xml != '/')
|
||||||
|
{
|
||||||
|
attvaluelen++; p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*printf("%.*s='%.*s'\n",
|
||||||
|
attnamelen, attname, attvaluelen, attvalue);*/
|
||||||
|
if(p->attfunc)
|
||||||
|
p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
|
||||||
|
}
|
||||||
|
p->xml++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parseelt parse the xml stream and
|
||||||
|
* call the callback functions when needed... */
|
||||||
|
void parseelt(struct xmlparser * p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char * elementname;
|
||||||
|
while(p->xml < (p->xmlend - 1))
|
||||||
|
{
|
||||||
|
if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||||
|
{
|
||||||
|
i = 0; elementname = ++p->xml;
|
||||||
|
while( !IS_WHITE_SPACE(*p->xml)
|
||||||
|
&& (*p->xml!='>') && (*p->xml!='/')
|
||||||
|
)
|
||||||
|
{
|
||||||
|
i++; p->xml++;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(i>0)
|
||||||
|
{
|
||||||
|
if(p->starteltfunc)
|
||||||
|
p->starteltfunc(p->data, elementname, i);
|
||||||
|
if(parseatt(p))
|
||||||
|
return;
|
||||||
|
if(*p->xml!='/')
|
||||||
|
{
|
||||||
|
const char * data;
|
||||||
|
i = 0; data = ++p->xml;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
while( IS_WHITE_SPACE(*p->xml) )
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while(*p->xml!='<')
|
||||||
|
{
|
||||||
|
i++; p->xml++;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(i>0 && p->datafunc)
|
||||||
|
p->datafunc(p->data, data, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(*p->xml == '/')
|
||||||
|
{
|
||||||
|
i = 0; elementname = ++p->xml;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
while((*p->xml != '>'))
|
||||||
|
{
|
||||||
|
i++; p->xml++;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(p->endeltfunc)
|
||||||
|
p->endeltfunc(p->data, elementname, i);
|
||||||
|
p->xml++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the parser must be initialized before calling this function */
|
||||||
|
void parsexml(struct xmlparser * parser)
|
||||||
|
{
|
||||||
|
parser->xml = parser->xmlstart;
|
||||||
|
parser->xmlend = parser->xmlstart + parser->xmlsize;
|
||||||
|
parseelt(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */
|
||||||
|
/* minimal xml parser
|
||||||
|
*
|
||||||
|
* Project : miniupnp
|
||||||
|
* Website : http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#ifndef __MINIXML_H__
|
||||||
|
#define __MINIXML_H__
|
||||||
|
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
|
||||||
|
|
||||||
|
/* if a callback function pointer is set to NULL,
|
||||||
|
* the function is not called */
|
||||||
|
struct xmlparser {
|
||||||
|
const char *xmlstart;
|
||||||
|
const char *xmlend;
|
||||||
|
const char *xml; /* pointer to current character */
|
||||||
|
int xmlsize;
|
||||||
|
void * data;
|
||||||
|
void (*starteltfunc) (void *, const char *, int);
|
||||||
|
void (*endeltfunc) (void *, const char *, int);
|
||||||
|
void (*datafunc) (void *, const char *, int);
|
||||||
|
void (*attfunc) (void *, const char *, int, const char *, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* parsexml()
|
||||||
|
* the xmlparser structure must be initialized before the call
|
||||||
|
* the following structure members have to be initialized :
|
||||||
|
* xmlstart, xmlsize, data, *func
|
||||||
|
* xml is for internal usage, xmlend is computed automatically */
|
||||||
|
void parsexml(struct xmlparser *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
/* $Id: minixmlvalid.c,v 1.2 2006/11/30 11:31:55 nanard Exp $ */
|
||||||
|
/* MiniUPnP Project
|
||||||
|
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
|
||||||
|
* minixmlvalid.c :
|
||||||
|
* validation program for the minixml parser
|
||||||
|
*
|
||||||
|
* (c) 2006 Thomas Bernard */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "minixml.h"
|
||||||
|
|
||||||
|
/* xml event structure */
|
||||||
|
struct event {
|
||||||
|
enum { ELTSTART, ELTEND, ATT, CHARDATA } type;
|
||||||
|
const char * data;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eventlist {
|
||||||
|
int n;
|
||||||
|
struct event * events;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* compare 2 xml event lists
|
||||||
|
* return 0 if the two lists are equals */
|
||||||
|
int evtlistcmp(struct eventlist * a, struct eventlist * b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct event * ae, * be;
|
||||||
|
if(a->n != b->n)
|
||||||
|
return 1;
|
||||||
|
for(i=0; i<a->n; i++)
|
||||||
|
{
|
||||||
|
ae = a->events + i;
|
||||||
|
be = b->events + i;
|
||||||
|
if( (ae->type != be->type)
|
||||||
|
||(ae->len != be->len)
|
||||||
|
||memcmp(ae->data, be->data, ae->len))
|
||||||
|
{
|
||||||
|
printf("Found a difference : %d '%.*s' != %d '%.*s'\n",
|
||||||
|
ae->type, ae->len, ae->data,
|
||||||
|
be->type, be->len, be->data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test data */
|
||||||
|
static const char xmldata[] =
|
||||||
|
"<xmlroot>\n"
|
||||||
|
" <elt1 att1=\"attvalue1\" att2=\"attvalue2\">"
|
||||||
|
"character data"
|
||||||
|
"</elt1> \n \t"
|
||||||
|
"<elt1b/>"
|
||||||
|
"<elt2a> \t<elt2b>chardata1</elt2b><elt2b>chardata2</elt2b></elt2a>"
|
||||||
|
"</xmlroot>";
|
||||||
|
|
||||||
|
static const struct event evtref[] =
|
||||||
|
{
|
||||||
|
{ELTSTART, "xmlroot", 7},
|
||||||
|
{ELTSTART, "elt1", 4},
|
||||||
|
/* attributes */
|
||||||
|
{CHARDATA, "character data", 14},
|
||||||
|
{ELTEND, "elt1", 4},
|
||||||
|
{ELTSTART, "elt1b", 5},
|
||||||
|
{ELTSTART, "elt2a", 5},
|
||||||
|
{ELTSTART, "elt2b", 5},
|
||||||
|
{CHARDATA, "chardata1", 9},
|
||||||
|
{ELTEND, "elt2b", 5},
|
||||||
|
{ELTSTART, "elt2b", 5},
|
||||||
|
{CHARDATA, "chardata2", 9},
|
||||||
|
{ELTEND, "elt2b", 5},
|
||||||
|
{ELTEND, "elt2a", 5},
|
||||||
|
{ELTEND, "xmlroot", 7}
|
||||||
|
};
|
||||||
|
|
||||||
|
void startelt(void * data, const char * p, int l)
|
||||||
|
{
|
||||||
|
struct eventlist * evtlist = data;
|
||||||
|
struct event * evt;
|
||||||
|
evt = evtlist->events + evtlist->n;
|
||||||
|
/*printf("startelt : %.*s\n", l, p);*/
|
||||||
|
evt->type = ELTSTART;
|
||||||
|
evt->data = p;
|
||||||
|
evt->len = l;
|
||||||
|
evtlist->n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void endelt(void * data, const char * p, int l)
|
||||||
|
{
|
||||||
|
struct eventlist * evtlist = data;
|
||||||
|
struct event * evt;
|
||||||
|
evt = evtlist->events + evtlist->n;
|
||||||
|
/*printf("endelt : %.*s\n", l, p);*/
|
||||||
|
evt->type = ELTEND;
|
||||||
|
evt->data = p;
|
||||||
|
evt->len = l;
|
||||||
|
evtlist->n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chardata(void * data, const char * p, int l)
|
||||||
|
{
|
||||||
|
struct eventlist * evtlist = data;
|
||||||
|
struct event * evt;
|
||||||
|
evt = evtlist->events + evtlist->n;
|
||||||
|
/*printf("chardata : '%.*s'\n", l, p);*/
|
||||||
|
evt->type = CHARDATA;
|
||||||
|
evt->data = p;
|
||||||
|
evt->len = l;
|
||||||
|
evtlist->n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int testxmlparser(const char * xml, int size)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct eventlist evtlist;
|
||||||
|
struct eventlist evtlistref;
|
||||||
|
struct xmlparser parser;
|
||||||
|
evtlist.n = 0;
|
||||||
|
evtlist.events = malloc(sizeof(struct event)*100);
|
||||||
|
memset(&parser, 0, sizeof(parser));
|
||||||
|
parser.xmlstart = xml;
|
||||||
|
parser.xmlsize = size;
|
||||||
|
parser.data = &evtlist;
|
||||||
|
parser.starteltfunc = startelt;
|
||||||
|
parser.endeltfunc = endelt;
|
||||||
|
parser.datafunc = chardata;
|
||||||
|
parsexml(&parser);
|
||||||
|
printf("%d events\n", evtlist.n);
|
||||||
|
/* compare */
|
||||||
|
evtlistref.n = sizeof(evtref)/sizeof(struct event);
|
||||||
|
evtlistref.events = (struct event *)evtref;
|
||||||
|
r = evtlistcmp(&evtlistref, &evtlist);
|
||||||
|
free(evtlist.events);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
r = testxmlparser(xmldata, sizeof(xmldata)-1);
|
||||||
|
if(r)
|
||||||
|
printf("minixml validation test failed\n");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/* $Id: testminixml.c,v 1.6 2006/11/19 22:32:35 nanard Exp $
|
||||||
|
* testminixml.c
|
||||||
|
* test program for the "minixml" functions.
|
||||||
|
* Author : Thomas Bernard.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "minixml.h"
|
||||||
|
#include "igd_desc_parse.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define NO_BZERO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_BZERO
|
||||||
|
#define bzero(p, n) memset(p, 0, n)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
void printeltname1(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printf("element ");
|
||||||
|
for(i=0;i<l;i++)
|
||||||
|
putchar(name[i]);
|
||||||
|
}
|
||||||
|
void printeltname2(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
putchar('/');
|
||||||
|
for(i=0;i<l;i++)
|
||||||
|
putchar(name[i]);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
void printdata(void *d, const char * data, int l)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printf("data : ");
|
||||||
|
for(i=0;i<l;i++)
|
||||||
|
putchar(data[i]);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void burptest(const char * buffer, int bufsize)
|
||||||
|
{
|
||||||
|
struct IGDdatas data;
|
||||||
|
struct xmlparser parser;
|
||||||
|
/*objet IGDdatas */
|
||||||
|
bzero(&data, sizeof(struct IGDdatas));
|
||||||
|
/* objet xmlparser */
|
||||||
|
parser.xmlstart = buffer;
|
||||||
|
parser.xmlsize = bufsize;
|
||||||
|
parser.data = &data;
|
||||||
|
/*parser.starteltfunc = printeltname1;
|
||||||
|
parser.endeltfunc = printeltname2;
|
||||||
|
parser.datafunc = printdata; */
|
||||||
|
parser.starteltfunc = IGDstartelt;
|
||||||
|
parser.endeltfunc = IGDendelt;
|
||||||
|
parser.datafunc = IGDdata;
|
||||||
|
parsexml(&parser);
|
||||||
|
printIGD(&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----- main ---- */
|
||||||
|
#define XML_MAX_SIZE (8192)
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
FILE * f;
|
||||||
|
char buffer[XML_MAX_SIZE];
|
||||||
|
int bufsize;
|
||||||
|
if(argc<2)
|
||||||
|
{
|
||||||
|
printf("usage:\t%s file.xml\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
f = fopen(argv[1], "r");
|
||||||
|
if(!f)
|
||||||
|
{
|
||||||
|
printf("cannot open file %s\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
bufsize = (int)fread(buffer, 1, XML_MAX_SIZE, f);
|
||||||
|
fclose(f);
|
||||||
|
burptest(buffer, bufsize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,293 @@
|
||||||
|
/* $Id: upnpc.c,v 1.49 2007/01/27 14:20:01 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
#include "miniwget.h"
|
||||||
|
#include "miniupnpc.h"
|
||||||
|
#include "upnpcommands.h"
|
||||||
|
|
||||||
|
/* protofix() checks if protocol is "UDP" or "TCP"
|
||||||
|
* returns NULL if not */
|
||||||
|
const char * protofix(const char * proto)
|
||||||
|
{
|
||||||
|
static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
|
||||||
|
static const char proto_udp[4] = { 'U', 'D', 'P', 0};
|
||||||
|
int i, b;
|
||||||
|
for(i=0, b=1; i<4; i++)
|
||||||
|
b = b && ( (proto[i] == proto_tcp[i])
|
||||||
|
|| (proto[i] == (proto_tcp[i] | 32)) );
|
||||||
|
if(b)
|
||||||
|
return proto_tcp;
|
||||||
|
for(i=0, b=1; i<4; i++)
|
||||||
|
b = b && ( (proto[i] == proto_udp[i])
|
||||||
|
|| (proto[i] == (proto_udp[i] | 32)) );
|
||||||
|
if(b)
|
||||||
|
return proto_udp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DisplayInfos(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
char connectionType[64];
|
||||||
|
char status[64];
|
||||||
|
unsigned int uptime;
|
||||||
|
unsigned int brUp, brDown;
|
||||||
|
UPNP_GetConnectionTypeInfo(urls->controlURL,
|
||||||
|
data->servicetype,
|
||||||
|
connectionType);
|
||||||
|
if(connectionType[0])
|
||||||
|
printf("Connection Type : %s\n", connectionType);
|
||||||
|
else
|
||||||
|
printf("GetConnectionTypeInfo failed.\n");
|
||||||
|
UPNP_GetStatusInfo(urls->controlURL, data->servicetype, status, &uptime);
|
||||||
|
printf("Status : %s, uptime=%u\n", status, uptime);
|
||||||
|
UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->servicetype_CIF,
|
||||||
|
&brDown, &brUp);
|
||||||
|
printf("MaxBitRateDown : %u bps MaxBitRateUp %u bps\n", brDown, brUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetConnectionStatus(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
|
||||||
|
DisplayInfos(urls, data);
|
||||||
|
bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->servicetype_CIF);
|
||||||
|
bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->servicetype_CIF);
|
||||||
|
packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->servicetype_CIF);
|
||||||
|
packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->servicetype_CIF);
|
||||||
|
printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
|
||||||
|
printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ListRedirections(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
int i = 0;
|
||||||
|
char index[6];
|
||||||
|
char intClient[16];
|
||||||
|
char intPort[6];
|
||||||
|
char extPort[6];
|
||||||
|
char protocol[4];
|
||||||
|
char desc[80];
|
||||||
|
char enabled[6];
|
||||||
|
char rHost[64];
|
||||||
|
char duration[16];
|
||||||
|
/*unsigned int num=0;
|
||||||
|
UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
|
||||||
|
printf("PortMappingNumberOfEntries : %u\n", num);*/
|
||||||
|
do {
|
||||||
|
snprintf(index, 6, "%d", i);
|
||||||
|
rHost[0] = '\0'; enabled[0] = '\0';
|
||||||
|
duration[0] = '\0'; desc[0] = '\0';
|
||||||
|
extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
|
||||||
|
r = UPNP_GetGenericPortMappingEntry(urls->controlURL, data->servicetype,
|
||||||
|
index,
|
||||||
|
extPort, intClient, intPort,
|
||||||
|
protocol, desc, enabled,
|
||||||
|
rHost, duration);
|
||||||
|
if(r==0)
|
||||||
|
printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
|
||||||
|
" desc='%s' rHost='%s'\n",
|
||||||
|
i, protocol, extPort, intClient, intPort,
|
||||||
|
enabled, duration,
|
||||||
|
desc, rHost);
|
||||||
|
i++;
|
||||||
|
} while(r==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test function
|
||||||
|
* 1 - get connection type
|
||||||
|
* 2 - get extenal ip address
|
||||||
|
* 3 - Add port mapping
|
||||||
|
* 4 - get this port mapping from the IGD */
|
||||||
|
static void SetRedirectAndTest(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data,
|
||||||
|
const char * iaddr,
|
||||||
|
const char * iport,
|
||||||
|
const char * eport,
|
||||||
|
const char * proto)
|
||||||
|
{
|
||||||
|
char externalIPAddress[16];
|
||||||
|
char intClient[16];
|
||||||
|
char intPort[6];
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if(!iaddr || !iport || !eport || !proto)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Wrong arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proto = protofix(proto);
|
||||||
|
if(!proto)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid protocol\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UPNP_GetExternalIPAddress(urls->controlURL,
|
||||||
|
data->servicetype,
|
||||||
|
externalIPAddress);
|
||||||
|
if(externalIPAddress[0])
|
||||||
|
printf("ExternalIPAddress = %s\n", externalIPAddress);
|
||||||
|
else
|
||||||
|
printf("GetExternalIPAddress failed.\n");
|
||||||
|
|
||||||
|
r = UPNP_AddPortMapping(urls->controlURL, data->servicetype,
|
||||||
|
eport, iport, iaddr, 0, proto);
|
||||||
|
if(r==0)
|
||||||
|
printf("AddPortMapping(%s, %s, %s) failed\n", eport, iport, iaddr);
|
||||||
|
|
||||||
|
UPNP_GetSpecificPortMappingEntry(urls->controlURL,
|
||||||
|
data->servicetype,
|
||||||
|
eport, proto,
|
||||||
|
intClient, intPort);
|
||||||
|
if(intClient[0])
|
||||||
|
printf("InternalIP:Port = %s:%s\n", intClient, intPort);
|
||||||
|
else
|
||||||
|
printf("GetSpecificPortMappingEntry failed.\n");
|
||||||
|
|
||||||
|
printf("external %s:%s is redirected to internal %s:%s\n",
|
||||||
|
externalIPAddress, eport, intClient, intPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RemoveRedirect(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data,
|
||||||
|
const char * eport,
|
||||||
|
const char * proto)
|
||||||
|
{
|
||||||
|
if(!proto || !eport)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proto = protofix(proto);
|
||||||
|
if(!proto)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "protocol invalid\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UPNP_DeletePortMapping(urls->controlURL, data->servicetype, eport, proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* sample upnp client program */
|
||||||
|
int main(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
char command = 0;
|
||||||
|
struct UPNPDev * devlist;
|
||||||
|
char lanaddr[16]; /* my ip address on the LAN */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
WSADATA wsaData;
|
||||||
|
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||||
|
if(nResult != NO_ERROR)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "WSAStartup() failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
printf("upnpc : miniupnp test client. (c) 2006 Thomas Bernard\n");
|
||||||
|
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
|
||||||
|
"for more information.\n");
|
||||||
|
if(argc>=2 && (argv[1][0] == '-'))
|
||||||
|
command = argv[1][1];
|
||||||
|
|
||||||
|
if(!command || argc<2 || (command == 'a' && argc<6)
|
||||||
|
|| (command == 'd' && argc<4)
|
||||||
|
|| (command == 'r' && argc<4))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage :\t%s -a ip port external_port protocol\tAdd port redirection\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s -d external_port protocol\tDelete port redirection\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s -s\t\t\t\tGet Connection status\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s -l\t\t\t\tList redirections\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s -r port1 protocol1 [port2 protocol2] [...]\n\t\t\t\tAdd all redirections to the current host\n", argv[0]);
|
||||||
|
fprintf(stderr, "\nprotocol is UDP or TCP\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
devlist = upnpDiscover(2000);
|
||||||
|
if(devlist)
|
||||||
|
{
|
||||||
|
struct UPNPDev * device;
|
||||||
|
struct UPNPUrls urls;
|
||||||
|
struct IGDdatas data;
|
||||||
|
printf("List of UPNP devices found on the network :\n");
|
||||||
|
for(device = devlist; device; device = device->pNext)
|
||||||
|
{
|
||||||
|
printf("\n desc: %s\n st: %s\n",
|
||||||
|
device->descURL, device->st);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
if(UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))
|
||||||
|
{
|
||||||
|
printf("Found valid IGD : %s\n", urls.controlURL);
|
||||||
|
printf("Local LAN ip address : %s\n", lanaddr);
|
||||||
|
#if 0
|
||||||
|
printf("getting \"%s\"\n", urls.ipcondescURL);
|
||||||
|
descXML = miniwget(urls.ipcondescURL, &descXMLsize);
|
||||||
|
if(descXML)
|
||||||
|
{
|
||||||
|
/*fwrite(descXML, 1, descXMLsize, stdout);*/
|
||||||
|
free(descXML); descXML = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch(command)
|
||||||
|
{
|
||||||
|
case 'l':
|
||||||
|
DisplayInfos(&urls, &data);
|
||||||
|
ListRedirections(&urls, &data);
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
SetRedirectAndTest(&urls, &data, argv[2], argv[3], argv[4], argv[5]);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
RemoveRedirect(&urls, &data, argv[2], argv[3]);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
GetConnectionStatus(&urls, &data);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
for(i=2; i<argc-1; i+=2)
|
||||||
|
{
|
||||||
|
/*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/
|
||||||
|
SetRedirectAndTest(&urls, &data,
|
||||||
|
lanaddr, argv[i], argv[i], argv[i+1]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown switch -%c\n", command);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeUPNPUrls(&urls);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
|
||||||
|
}
|
||||||
|
freeUPNPDevlist(devlist); devlist = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "No IGD UPnP Device found on the network !\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*puts("************* HOP ***************");*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,485 @@
|
||||||
|
/* $Id: upnpcommands.c,v 1.14 2006/11/19 22:32:36 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "upnpcommands.h"
|
||||||
|
#include "miniupnpc.h"
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
my_atoui(const char * s)
|
||||||
|
{
|
||||||
|
return (unsigned int)strtoul(s, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* */
|
||||||
|
unsigned int
|
||||||
|
UPNP_GetTotalBytesSent(const char * controlURL,
|
||||||
|
const char * servicetype)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
unsigned int r = 0;
|
||||||
|
char * p;
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesSent", 0, buffer, &bufsize);
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent");
|
||||||
|
if(p)
|
||||||
|
r = my_atoui(p);
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* */
|
||||||
|
unsigned int
|
||||||
|
UPNP_GetTotalBytesReceived(const char * controlURL,
|
||||||
|
const char * servicetype)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
unsigned int r = 0;
|
||||||
|
char * p;
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesReceived", 0, buffer, &bufsize);
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived");
|
||||||
|
if(p)
|
||||||
|
r = my_atoui(p);
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* */
|
||||||
|
unsigned int
|
||||||
|
UPNP_GetTotalPacketsSent(const char * controlURL,
|
||||||
|
const char * servicetype)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
unsigned int r = 0;
|
||||||
|
char * p;
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsSent", 0, buffer, &bufsize);
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent");
|
||||||
|
if(p)
|
||||||
|
r = my_atoui(p);
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* */
|
||||||
|
unsigned int
|
||||||
|
UPNP_GetTotalPacketsReceived(const char * controlURL,
|
||||||
|
const char * servicetype)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
unsigned int r = 0;
|
||||||
|
char * p;
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsReceived", 0, buffer, &bufsize);
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived");
|
||||||
|
if(p)
|
||||||
|
r = my_atoui(p);
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UPNP_GetStatusInfo() call the corresponding UPNP method
|
||||||
|
* returns the current status and uptime */
|
||||||
|
void UPNP_GetStatusInfo(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
char * status,
|
||||||
|
unsigned int * uptime)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
char * p;
|
||||||
|
char* up;
|
||||||
|
|
||||||
|
if(!status && !uptime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype, "GetStatusInfo", 0, buffer, &bufsize);
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
up = GetValueFromNameValueList(&pdata, "NewUptime");
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewConnectionStatus");
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
{
|
||||||
|
if(p){
|
||||||
|
strncpy(status, p, 64 );
|
||||||
|
status[63] = '\0';
|
||||||
|
}else
|
||||||
|
status[0]= '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uptime){
|
||||||
|
if(p)
|
||||||
|
sscanf(up,"%u",uptime);
|
||||||
|
else
|
||||||
|
uptime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method
|
||||||
|
* returns the connection type */
|
||||||
|
void UPNP_GetConnectionTypeInfo(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
char * connectionType)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
char * p;
|
||||||
|
|
||||||
|
if(!connectionType)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||||
|
"GetConnectionTypeInfo", 0, buffer, &bufsize);
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewConnectionType");
|
||||||
|
/*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/
|
||||||
|
/* PossibleConnectionTypes will have several values.... */
|
||||||
|
if(connectionType)
|
||||||
|
{
|
||||||
|
if(p){
|
||||||
|
strncpy(connectionType, p, 64 );
|
||||||
|
connectionType[63] = '\0';
|
||||||
|
} else
|
||||||
|
connectionType[0] = '\0';
|
||||||
|
}
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method.
|
||||||
|
* Returns 2 values: Downloadlink bandwidth and Uplink bandwidth.
|
||||||
|
* One of the values can be null
|
||||||
|
* Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only
|
||||||
|
* We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */
|
||||||
|
void UPNP_GetLinkLayerMaxBitRates(const char * controlURL, const char * servicetype, unsigned int * bitrateDown, unsigned int* bitrateUp)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
char * down;
|
||||||
|
char* up;
|
||||||
|
|
||||||
|
if(!bitrateDown && !bitrateUp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* shouldn't we use GetCommonLinkProperties ? */
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||||
|
"GetCommonLinkProperties", 0, buffer, &bufsize);
|
||||||
|
/*"GetLinkLayerMaxBitRates", 0, buffer, &bufsize);*/
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
/*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/
|
||||||
|
/*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/
|
||||||
|
down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate");
|
||||||
|
up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate");
|
||||||
|
/*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/
|
||||||
|
/*GetValueFromNameValueList(&pdata, "NewPhysicalLinkSatus");*/
|
||||||
|
|
||||||
|
if(bitrateDown)
|
||||||
|
{
|
||||||
|
if(down)
|
||||||
|
sscanf(down,"%u",bitrateDown);
|
||||||
|
else
|
||||||
|
*bitrateDown = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bitrateUp)
|
||||||
|
{
|
||||||
|
if(up)
|
||||||
|
sscanf(up,"%u",bitrateUp);
|
||||||
|
else
|
||||||
|
*bitrateUp = 0;
|
||||||
|
}
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
|
||||||
|
* if the third arg is not null the value is copied to it.
|
||||||
|
* at least 16 bytes must be available */
|
||||||
|
void UPNP_GetExternalIPAddress(const char * controlURL, const char * servicetype, char * extIpAdd)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
char * p;
|
||||||
|
|
||||||
|
if(!extIpAdd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype, "GetExternalIPAddress", 0, buffer, &bufsize);
|
||||||
|
/*fd = simpleUPnPcommand(fd, controlURL, data.servicetype, "GetExternalIPAddress", 0, buffer, &bufsize);*/
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
/*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress");
|
||||||
|
|
||||||
|
if(p){
|
||||||
|
strncpy(extIpAdd, p, 16 );
|
||||||
|
extIpAdd[15] = '\0';
|
||||||
|
}else
|
||||||
|
extIpAdd[0] = '\0';
|
||||||
|
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||||
|
const char * extPort,
|
||||||
|
const char * inPort,
|
||||||
|
const char * inClient,
|
||||||
|
const char * desc,
|
||||||
|
const char * proto)
|
||||||
|
{
|
||||||
|
struct UPNParg * AddPortMappingArgs;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
const char * resVal;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if(!inPort || !inClient)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
|
||||||
|
AddPortMappingArgs[0].elt = "NewRemoteHost";
|
||||||
|
AddPortMappingArgs[1].elt = "NewExternalPort";
|
||||||
|
AddPortMappingArgs[1].val = extPort;
|
||||||
|
AddPortMappingArgs[2].elt = "NewProtocol";
|
||||||
|
AddPortMappingArgs[2].val = proto;
|
||||||
|
AddPortMappingArgs[3].elt = "NewInternalPort";
|
||||||
|
AddPortMappingArgs[3].val = inPort;
|
||||||
|
AddPortMappingArgs[4].elt = "NewInternalClient";
|
||||||
|
AddPortMappingArgs[4].val = inClient;
|
||||||
|
AddPortMappingArgs[5].elt = "NewEnabled";
|
||||||
|
AddPortMappingArgs[5].val = "1";
|
||||||
|
AddPortMappingArgs[6].elt = "NewPortMappingDescription";
|
||||||
|
AddPortMappingArgs[6].val = desc?desc:"libminiupnpc";
|
||||||
|
AddPortMappingArgs[7].elt = "NewLeaseDuration";
|
||||||
|
AddPortMappingArgs[7].val = "0";
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype, "AddPortMapping", AddPortMappingArgs, buffer, &bufsize);
|
||||||
|
/*fd = simpleUPnPcommand(fd, controlURL, data.servicetype, "AddPortMapping", AddPortMappingArgs, buffer, &bufsize);*/
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
/*buffer[bufsize] = '\0';*/
|
||||||
|
/*puts(buffer);*/
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
resVal = GetValueFromNameValueList(&pdata, "errorCode");
|
||||||
|
ret = resVal?0:1;
|
||||||
|
/* Do something with resVal if not null ! */
|
||||||
|
/*printf("AddPortMapping errorCode = '%s'\n", resVal); */
|
||||||
|
free(AddPortMappingArgs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||||
|
const char * extPort, const char * proto)
|
||||||
|
{
|
||||||
|
/*struct NameValueParserData pdata;*/
|
||||||
|
struct UPNParg * DeletePortMappingArgs;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
|
||||||
|
if(!extPort)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg));
|
||||||
|
DeletePortMappingArgs[0].elt = "NewRemoteHost";
|
||||||
|
DeletePortMappingArgs[1].elt = "NewExternalPort";
|
||||||
|
DeletePortMappingArgs[1].val = extPort;
|
||||||
|
DeletePortMappingArgs[2].elt = "NewProtocol";
|
||||||
|
DeletePortMappingArgs[2].val = proto;
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||||
|
"DeletePortMapping",
|
||||||
|
DeletePortMappingArgs, buffer, &bufsize);
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
free(DeletePortMappingArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
const char * index,
|
||||||
|
char * extPort,
|
||||||
|
char * intClient,
|
||||||
|
char * intPort,
|
||||||
|
char * protocol,
|
||||||
|
char * desc,
|
||||||
|
char * enabled,
|
||||||
|
char * rHost,
|
||||||
|
char * duration)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
struct UPNParg * GetPortMappingArgs;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
char * p;
|
||||||
|
int r = -1;
|
||||||
|
intClient[0] = '\0';
|
||||||
|
intPort[0] = '\0';
|
||||||
|
GetPortMappingArgs = calloc(2, sizeof(struct UPNParg));
|
||||||
|
GetPortMappingArgs[0].elt = "NewPortMappingIndex";
|
||||||
|
GetPortMappingArgs[0].val = index;
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||||
|
"GetGenericPortMappingEntry",
|
||||||
|
GetPortMappingArgs, buffer, &bufsize);
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewRemoteHost");
|
||||||
|
if(p && rHost)
|
||||||
|
{
|
||||||
|
strncpy(rHost, p, 64);
|
||||||
|
rHost[63] = '\0';
|
||||||
|
}
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewExternalPort");
|
||||||
|
if(p && extPort)
|
||||||
|
{
|
||||||
|
strncpy(extPort, p, 6);
|
||||||
|
extPort[5] = '\0';
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewProtocol");
|
||||||
|
if(p && protocol)
|
||||||
|
{
|
||||||
|
strncpy(protocol, p, 4);
|
||||||
|
protocol[3] = '\0';
|
||||||
|
}
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewInternalClient");
|
||||||
|
if(p && intClient)
|
||||||
|
{
|
||||||
|
strncpy(intClient, p, 16);
|
||||||
|
intClient[15] = '\0';
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewInternalPort");
|
||||||
|
if(p && intPort)
|
||||||
|
{
|
||||||
|
strncpy(intPort, p, 6);
|
||||||
|
intPort[5] = '\0';
|
||||||
|
}
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewEnabled");
|
||||||
|
if(p && enabled)
|
||||||
|
{
|
||||||
|
strncpy(enabled, p, 4);
|
||||||
|
enabled[3] = '\0';
|
||||||
|
}
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription");
|
||||||
|
if(p && desc)
|
||||||
|
{
|
||||||
|
strncpy(desc, p, 80);
|
||||||
|
desc[79] = '\0';
|
||||||
|
}
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewLeaseDuration");
|
||||||
|
if(p && duration)
|
||||||
|
{
|
||||||
|
strncpy(duration, p, 16);
|
||||||
|
duration[15] = '\0';
|
||||||
|
}
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
free(GetPortMappingArgs);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPNP_GetPortMappingNumberOfEntries(const char * controlURL, const char * servicetype, unsigned int * numEntries)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
char* p;
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype, "GetPortMappingNumberOfEntries", 0, buffer, &bufsize);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
DisplayNameValueList(buffer, bufsize);
|
||||||
|
#endif
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries");
|
||||||
|
|
||||||
|
if(numEntries && p)
|
||||||
|
{
|
||||||
|
sscanf(p,"%u",numEntries);
|
||||||
|
}
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping
|
||||||
|
* the result is returned in the intClient and intPort strings
|
||||||
|
* please provide 16 and 6 bytes of data */
|
||||||
|
void
|
||||||
|
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
const char * extPort,
|
||||||
|
const char * proto,
|
||||||
|
char * intClient,
|
||||||
|
char * intPort)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
struct UPNParg * GetPortMappingArgs;
|
||||||
|
char buffer[4096];
|
||||||
|
int bufsize = 4096;
|
||||||
|
char * p;
|
||||||
|
|
||||||
|
if(!intPort && !intClient && !extPort)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GetPortMappingArgs = calloc(4, sizeof(struct UPNParg));
|
||||||
|
GetPortMappingArgs[0].elt = "NewRemoteHost";
|
||||||
|
GetPortMappingArgs[1].elt = "NewExternalPort";
|
||||||
|
GetPortMappingArgs[1].val = extPort;
|
||||||
|
GetPortMappingArgs[2].elt = "NewProtocol";
|
||||||
|
GetPortMappingArgs[2].val = proto;
|
||||||
|
simpleUPnPcommand(-1, controlURL, servicetype,
|
||||||
|
"GetSpecificPortMappingEntry",
|
||||||
|
GetPortMappingArgs, buffer, &bufsize);
|
||||||
|
/*fd = simpleUPnPcommand(fd, controlURL, data.servicetype, "GetSpecificPortMappingEntry", AddPortMappingArgs, buffer, &bufsize); */
|
||||||
|
/*DisplayNameValueList(buffer, bufsize);*/
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewInternalClient");
|
||||||
|
|
||||||
|
if(intClient)
|
||||||
|
{
|
||||||
|
if(p){
|
||||||
|
strncpy(intClient, p, 16);
|
||||||
|
intClient[15] = '\0';
|
||||||
|
}else
|
||||||
|
intClient[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
p = GetValueFromNameValueList(&pdata, "NewInternalPort");
|
||||||
|
if(intPort)
|
||||||
|
{
|
||||||
|
if(p){
|
||||||
|
strncpy(intPort, p, 6);
|
||||||
|
intPort[5] = '\0';
|
||||||
|
}else
|
||||||
|
intPort[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
free(GetPortMappingArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/* $Id: upnpcommands.h,v 1.10 2007/01/29 20:27:24 nanard Exp $ */
|
||||||
|
/* Miniupnp project : http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2006 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided within this distribution */
|
||||||
|
#ifndef __UPNPCOMMANDS_H__
|
||||||
|
#define __UPNPCOMMANDS_H__
|
||||||
|
|
||||||
|
#include "upnpreplyparse.h"
|
||||||
|
#include "declspec.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LIBSPEC unsigned int
|
||||||
|
UPNP_GetTotalBytesSent(const char * controlURL,
|
||||||
|
const char * servicetype);
|
||||||
|
|
||||||
|
LIBSPEC unsigned int
|
||||||
|
UPNP_GetTotalBytesReceived(const char * controlURL,
|
||||||
|
const char * servicetype);
|
||||||
|
|
||||||
|
LIBSPEC unsigned int
|
||||||
|
UPNP_GetTotalPacketsSent(const char * controlURL,
|
||||||
|
const char * servicetype);
|
||||||
|
|
||||||
|
LIBSPEC unsigned int
|
||||||
|
UPNP_GetTotalPacketsReceived(const char * controlURL,
|
||||||
|
const char * servicetype);
|
||||||
|
|
||||||
|
LIBSPEC void
|
||||||
|
UPNP_GetStatusInfo(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
char * status,
|
||||||
|
unsigned int * uptime);
|
||||||
|
|
||||||
|
LIBSPEC void
|
||||||
|
UPNP_GetConnectionTypeInfo(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
char * connectionType);
|
||||||
|
|
||||||
|
/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
|
||||||
|
* if the third arg is not null the value is copied to it.
|
||||||
|
* at least 16 bytes must be available */
|
||||||
|
LIBSPEC void
|
||||||
|
UPNP_GetExternalIPAddress(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
char * extIpAdd);
|
||||||
|
|
||||||
|
LIBSPEC void
|
||||||
|
UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
|
||||||
|
const char* servicetype,
|
||||||
|
unsigned int * bitrateDown,
|
||||||
|
unsigned int * bitrateUp);
|
||||||
|
|
||||||
|
/* Returns zero if unable to add the port mapping, otherwise non-zero
|
||||||
|
* to indicate success */
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||||
|
const char * extPort,
|
||||||
|
const char * inPort,
|
||||||
|
const char * inClient,
|
||||||
|
const char * desc,
|
||||||
|
const char * proto);
|
||||||
|
|
||||||
|
LIBSPEC void
|
||||||
|
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||||
|
const char * extPort, const char * proto);
|
||||||
|
|
||||||
|
LIBSPEC void
|
||||||
|
UPNP_GetPortMappingNumberOfEntries(const char* controlURL, const char* servicetype, unsigned int * num);
|
||||||
|
|
||||||
|
/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping
|
||||||
|
* the result is returned in the intClient and intPort strings
|
||||||
|
* please provide 16 and 6 bytes of data */
|
||||||
|
LIBSPEC void
|
||||||
|
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
const char * extPort,
|
||||||
|
const char * proto,
|
||||||
|
char * intClient,
|
||||||
|
char * intPort);
|
||||||
|
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
const char * index,
|
||||||
|
char * extPort,
|
||||||
|
char * intClient,
|
||||||
|
char * intPort,
|
||||||
|
char * protocol,
|
||||||
|
char * desc,
|
||||||
|
char * enabled,
|
||||||
|
char * rHost,
|
||||||
|
char * duration);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/* $Id: upnpreplyparse.c,v 1.8 2007/02/07 22:38:09 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "upnpreplyparse.h"
|
||||||
|
#include "minixml.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
NameValueParserStartElt(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||||
|
if(l>63)
|
||||||
|
l = 63;
|
||||||
|
memcpy(data->curelt, name, l);
|
||||||
|
data->curelt[l] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
NameValueParserGetData(void * d, const char * datas, int l)
|
||||||
|
{
|
||||||
|
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||||
|
struct NameValue * nv;
|
||||||
|
nv = malloc(sizeof(struct NameValue));
|
||||||
|
if(l>63)
|
||||||
|
l = 63;
|
||||||
|
strncpy(nv->name, data->curelt, 64);
|
||||||
|
nv->name[63] = '\0';
|
||||||
|
memcpy(nv->value, datas, l);
|
||||||
|
nv->value[l] = '\0';
|
||||||
|
LIST_INSERT_HEAD( &(data->head), nv, entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParseNameValue(const char * buffer, int bufsize,
|
||||||
|
struct NameValueParserData * data)
|
||||||
|
{
|
||||||
|
struct xmlparser parser;
|
||||||
|
LIST_INIT(&(data->head));
|
||||||
|
/* init xmlparser object */
|
||||||
|
parser.xmlstart = buffer;
|
||||||
|
parser.xmlsize = bufsize;
|
||||||
|
parser.data = data;
|
||||||
|
parser.starteltfunc = NameValueParserStartElt;
|
||||||
|
parser.endeltfunc = 0;
|
||||||
|
parser.datafunc = NameValueParserGetData;
|
||||||
|
parser.attfunc = 0;
|
||||||
|
parsexml(&parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ClearNameValueList(struct NameValueParserData * pdata)
|
||||||
|
{
|
||||||
|
struct NameValue * nv;
|
||||||
|
while((nv = pdata->head.lh_first) != NULL)
|
||||||
|
{
|
||||||
|
LIST_REMOVE(nv, entries);
|
||||||
|
free(nv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||||
|
const char * Name)
|
||||||
|
{
|
||||||
|
struct NameValue * nv;
|
||||||
|
char * p = NULL;
|
||||||
|
for(nv = pdata->head.lh_first;
|
||||||
|
(nv != NULL) && (p == NULL);
|
||||||
|
nv = nv->entries.le_next)
|
||||||
|
{
|
||||||
|
if(strcmp(nv->name, Name) == 0)
|
||||||
|
p = nv->value;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||||
|
const char * Name)
|
||||||
|
{
|
||||||
|
struct NameValue * nv;
|
||||||
|
char * p = NULL;
|
||||||
|
char * pname;
|
||||||
|
for(nv = pdata->head.lh_first;
|
||||||
|
(nv != NULL) && (p == NULL);
|
||||||
|
nv = nv->entries.le_next)
|
||||||
|
{
|
||||||
|
pname = strrchr(nv->name, ':');
|
||||||
|
if(pname)
|
||||||
|
pname++;
|
||||||
|
else
|
||||||
|
pname = nv->name;
|
||||||
|
if(strcmp(pname, Name)==0)
|
||||||
|
p = nv->value;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* debug all-in-one function
|
||||||
|
* do parsing then display to stdout */
|
||||||
|
void
|
||||||
|
DisplayNameValueList(char * buffer, int bufsize)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
struct NameValue * nv;
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
for(nv = pdata.head.lh_first;
|
||||||
|
nv != NULL;
|
||||||
|
nv = nv->entries.le_next)
|
||||||
|
{
|
||||||
|
printf("%s = %s\n", nv->name, nv->value);
|
||||||
|
}
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/* $Id: upnpreplyparse.h,v 1.6 2007/02/07 22:38:09 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
#ifndef __UPNPREPLYPARSE_H__
|
||||||
|
#define __UPNPREPLYPARSE_H__
|
||||||
|
|
||||||
|
#if defined(sun) || defined(__sun) || defined(WIN32)
|
||||||
|
#include "bsdqueue.h"
|
||||||
|
#else
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct NameValue {
|
||||||
|
LIST_ENTRY(NameValue) entries;
|
||||||
|
char name[64];
|
||||||
|
char value[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NameValueParserData {
|
||||||
|
LIST_HEAD(listhead, NameValue) head;
|
||||||
|
char curelt[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ParseNameValue() */
|
||||||
|
void
|
||||||
|
ParseNameValue(const char * buffer, int bufsize,
|
||||||
|
struct NameValueParserData * data);
|
||||||
|
|
||||||
|
/* ClearNameValueList() */
|
||||||
|
void
|
||||||
|
ClearNameValueList(struct NameValueParserData * pdata);
|
||||||
|
|
||||||
|
/* GetValueFromNameValueList() */
|
||||||
|
char *
|
||||||
|
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||||
|
const char * Name);
|
||||||
|
|
||||||
|
/* GetValueFromNameValueListIgnoreNS() */
|
||||||
|
char *
|
||||||
|
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||||
|
const char * Name);
|
||||||
|
|
||||||
|
/* DisplayNameValueList() */
|
||||||
|
void
|
||||||
|
DisplayNameValueList(char * buffer, int bufsize);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
14
setup.py
14
setup.py
|
@ -124,6 +124,18 @@ deluge_core = Extension('deluge_core',
|
||||||
'libtorrent/src/kademlia/rpc_manager.cpp',
|
'libtorrent/src/kademlia/rpc_manager.cpp',
|
||||||
'libtorrent/src/kademlia/traversal_algorithm.cpp'])
|
'libtorrent/src/kademlia/traversal_algorithm.cpp'])
|
||||||
|
|
||||||
|
upnp = Extension('upnp',
|
||||||
|
include_dirs = ['./miniupnpc'],
|
||||||
|
sources=['src/python-upnp.c',
|
||||||
|
'miniupnpc/igd_desc_parse.c',
|
||||||
|
'miniupnpc/minisoap.c',
|
||||||
|
'miniupnpc/miniupnpc.c',
|
||||||
|
'miniupnpc/miniwget.c',
|
||||||
|
'miniupnpc/minixml.c',
|
||||||
|
'miniupnpc/minixmlvalid.c',
|
||||||
|
'miniupnpc/upnpcommands.c',
|
||||||
|
'miniupnpc/upnpreplyparse.c'])
|
||||||
|
|
||||||
# Thanks to Iain Nicol for code to save the location for installed prefix
|
# Thanks to Iain Nicol for code to save the location for installed prefix
|
||||||
# At runtime, we need to know where we installed the data to.
|
# At runtime, we need to know where we installed the data to.
|
||||||
|
|
||||||
|
@ -245,6 +257,6 @@ setup(name=NAME, fullname=FULLNAME, version=VERSION,
|
||||||
package_dir = {'deluge': 'src'},
|
package_dir = {'deluge': 'src'},
|
||||||
data_files=data,
|
data_files=data,
|
||||||
ext_package='deluge',
|
ext_package='deluge',
|
||||||
ext_modules=[deluge_core],
|
ext_modules=[deluge_core, upnp],
|
||||||
cmdclass=cmdclass
|
cmdclass=cmdclass
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
/* python-miniupnp
|
||||||
|
*
|
||||||
|
* Copyright (C) Zach Tibbitts 2007 <zach@collegegeek.org>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* You may redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License, as published by the Free Software
|
||||||
|
* Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* python-miniupnp is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with python-miniupnp. If not, write to:
|
||||||
|
* The Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <miniupnpc.h>
|
||||||
|
#include <miniwget.h>
|
||||||
|
#include <upnpcommands.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// upnpDiscover()
|
||||||
|
static PyObject*
|
||||||
|
_upnpDiscover(PyObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
int delay, i, k;
|
||||||
|
if (!PyArg_ParseTuple(args, "i", &delay))
|
||||||
|
return NULL;
|
||||||
|
struct UPNPDev* discover = upnpDiscover(delay);
|
||||||
|
struct UPNPDev* next = discover;
|
||||||
|
// First, we have to find out how many elements are in the list
|
||||||
|
i = 0;
|
||||||
|
while(next)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
next = next->pNext;
|
||||||
|
}
|
||||||
|
// Turn the linked list into a python object
|
||||||
|
PyObject* list = PyList_New(i);
|
||||||
|
for(k=0;k<i;k++)
|
||||||
|
{
|
||||||
|
PyObject* tmp = Py_BuildValue("{ssssss}", "descURL", discover->descURL,
|
||||||
|
"st", discover->st,
|
||||||
|
"buffer", discover->buffer);
|
||||||
|
PyList_SET_ITEM(list, k, tmp);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
_miniwget(PyObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
char* url;
|
||||||
|
int* size;
|
||||||
|
if (!PyArg_ParseTuple(args, "si", &url, &size))
|
||||||
|
return NULL;
|
||||||
|
miniwget(url, size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
_parserootdesc(PyObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
_GetUPNPUrls(PyObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
_simpleUPnPcommand(PyObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
const char * url;
|
||||||
|
const char * service;
|
||||||
|
const char * action;
|
||||||
|
struct UPNParg * arguments;
|
||||||
|
char * buffer;
|
||||||
|
int * bufsize;
|
||||||
|
if (!PyArg_ParseTuple(args, "isssOsi", &s, &url, &service, &action,
|
||||||
|
&arguments, &buffer, &bufsize))
|
||||||
|
return NULL;
|
||||||
|
int result;
|
||||||
|
result = simpleUPnPcommand(s, url, service, action, arguments, buffer, bufsize);
|
||||||
|
return Py_BuildValue("i", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef upnp_methods[] = {
|
||||||
|
{"simple_upnp_command", (PyCFunction)_simpleUPnPcommand, METH_VARARGS, "."},
|
||||||
|
{"discover", (PyCFunction)_upnpDiscover, METH_VARARGS, "."},
|
||||||
|
{"miniwget", (PyCFunction)_miniwget, METH_VARARGS, "."},
|
||||||
|
{"parse_root_desc", (PyCFunction)_parserootdesc, METH_VARARGS, "."},
|
||||||
|
{"get_upnp_urls", (PyCFunction)_GetUPNPUrls, METH_VARARGS, "."},
|
||||||
|
{NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
initupnp(void)
|
||||||
|
{
|
||||||
|
Py_InitModule("upnp", upnp_methods);
|
||||||
|
}
|
Loading…
Reference in New Issue