diff options
| author | Tobias Markmann <tm@ayena.de> | 2011-05-26 18:46:49 (GMT) | 
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2011-09-25 17:42:32 (GMT) | 
| commit | 4f62e5ec4b42929fe3c1a68667e63cb1b7a35509 (patch) | |
| tree | 0d19fac3f578dec00ccf3e58930312951e38de89 /3rdParty/LibMiniUPnPc/src | |
| parent | de660b763459cdd707876ec244b6866abca07fa2 (diff) | |
| download | swift-4f62e5ec4b42929fe3c1a68667e63cb1b7a35509.zip swift-4f62e5ec4b42929fe3c1a68667e63cb1b7a35509.tar.bz2  | |
Google Summer of Code 2011 Project: Adding support for Jingle File Transfers (XEP-0234), Jingle SOCKS5 Bytestreams Transport Method (XEP-0260), Jingle In-Band Bytestreams Transport Method (XEP-0261) and SOCKS5 Bytestreams (XEP-0065).
License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php
Diffstat (limited to '3rdParty/LibMiniUPnPc/src')
31 files changed, 6046 insertions, 0 deletions
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE b/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE new file mode 100644 index 0000000..2434c86 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE @@ -0,0 +1,27 @@ +MiniUPnPc +Copyright (c) 2005-2011, 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. + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h new file mode 100644 index 0000000..1fe0599 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h @@ -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_ */ diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h new file mode 100644 index 0000000..f11e5e9 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h @@ -0,0 +1,24 @@ +/* $Id: codelength.h,v 1.1 2008/10/06 22:04:06 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2008 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef __CODELENGTH_H__ +#define __CODELENGTH_H__ + +/* Encode length by using 7bit per Byte : + * Most significant bit of each byte specifies that the + * following byte is part of the code */ +#define DECODELENGTH(n, p) n = 0; \ +                           do { n = (n << 7) | (*p & 0x7f); } \ +                           while(*(p++)&0x80); + +#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ +                         if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ +                         if(n>=16384) *(p++) = (n >> 14) | 0x80; \ +                         if(n>=128) *(p++) = (n >> 7) | 0x80; \ +                         *(p++) = n & 0x7f; + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c new file mode 100644 index 0000000..76e8e37 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c @@ -0,0 +1,241 @@ +/* $Id: connecthostport.c,v 1.5 2011/04/09 08:49:50 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2010-2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +/* use getaddrinfo() or gethostbyname() + * uncomment the following line in order to use gethostbyname() */ +#ifdef NO_GETADDRINFO +#define USE_GETHOSTBYNAME +#endif + +#include <string.h> +#include <stdio.h> +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#define MAXHOSTNAMELEN 64 +#define snprintf _snprintf +#define herror +#define socklen_t int +#else /* #ifdef WIN32 */ +#include <unistd.h> +#include <sys/param.h> +#include <errno.h> +#define closesocket close +#include <netdb.h> +/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions + * during the connect() call */ +#define MINIUPNPC_IGNORE_EINTR +#ifndef USE_GETHOSTBYNAME +#include <sys/types.h> +#include <sys/socket.h> +#endif /* #ifndef USE_GETHOSTBYNAME */ +#endif /* #else WIN32 */ + +/* definition of PRINT_SOCKET_ERROR */ +#ifdef WIN32 +#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#if defined(__amigaos__) || defined(__amigaos4__) +#define herror(A) printf("%s\n", A) +#endif + +#include "connecthostport.h" + +/* connecthostport() + * return a socket connected (TCP) to the host and port + * or -1 in case of error */ +int connecthostport(const char * host, unsigned short port) +{ +	int s, n; +#ifdef USE_GETHOSTBYNAME +	struct sockaddr_in dest; +	struct hostent *hp; +#else /* #ifdef USE_GETHOSTBYNAME */ +	char tmp_host[MAXHOSTNAMELEN+1]; +	char port_str[8]; +	struct addrinfo *ai, *p; +	struct addrinfo hints; +#endif /* #ifdef USE_GETHOSTBYNAME */ +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT +	struct timeval timeout; +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ +	 +#ifdef USE_GETHOSTBYNAME +	hp = gethostbyname(host); +	if(hp == NULL) +	{ +		herror(host); +		return -1; +	} +	memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); +	memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); +	s = socket(PF_INET, SOCK_STREAM, 0); +	if(s < 0) +	{ +		PRINT_SOCKET_ERROR("socket"); +		return -1; +	} +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT +	/* setting a 3 seconds timeout for the connect() call */ +	timeout.tv_sec = 3; +	timeout.tv_usec = 0; +	if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) +	{ +		PRINT_SOCKET_ERROR("setsockopt"); +	} +	timeout.tv_sec = 3; +	timeout.tv_usec = 0; +	if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) +	{ +		PRINT_SOCKET_ERROR("setsockopt"); +	} +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ +	dest.sin_family = AF_INET; +	dest.sin_port = htons(port); +	n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); +#ifdef MINIUPNPC_IGNORE_EINTR +	while(n < 0 && errno == EINTR) +	{ +		socklen_t len; +		fd_set wset; +		int err; +		FD_ZERO(&wset); +		FD_SET(s, &wset); +		if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) +			continue; +		/*len = 0;*/ +		/*n = getpeername(s, NULL, &len);*/ +		len = sizeof(err); +		if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { +			PRINT_SOCKET_ERROR("getsockopt"); +			closesocket(s); +			return -1; +		} +		if(err != 0) { +			errno = err; +			n = -1; +		} +	} +#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ +	if(n<0) +	{ +		PRINT_SOCKET_ERROR("connect"); +		closesocket(s); +		return -1; +	} +#else /* #ifdef USE_GETHOSTBYNAME */ +	/* use getaddrinfo() instead of gethostbyname() */ +	memset(&hints, 0, sizeof(hints)); +	/* hints.ai_flags = AI_ADDRCONFIG; */ +#ifdef AI_NUMERICSERV +	hints.ai_flags = AI_NUMERICSERV; +#endif +	hints.ai_socktype = SOCK_STREAM; +	hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ +	/* hints.ai_protocol = IPPROTO_TCP; */ +	snprintf(port_str, sizeof(port_str), "%hu", port); +	if(host[0] == '[') +	{ +		/* literal ip v6 address */ +		int i; +		for(i = 0; host[i+1] && (host[i+1] != ']') && i < MAXHOSTNAMELEN; i++) +		{ +			tmp_host[i] = host[i+1]; +		} +		tmp_host[i] = '\0'; +	} +	else +	{ +		strncpy(tmp_host, host, MAXHOSTNAMELEN); +	} +	tmp_host[MAXHOSTNAMELEN] = '\0'; +	n = getaddrinfo(tmp_host, port_str, &hints, &ai); +	if(n != 0) +	{ +#ifdef WIN32 +		fprintf(stderr, "getaddrinfo() error : %d\n", n); +#else +		fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); +#endif +		return -1; +	} +	s = -1; +	for(p = ai; p; p = p->ai_next) +	{ +		s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); +		if(s < 0) +			continue; +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT +		/* setting a 3 seconds timeout for the connect() call */ +		timeout.tv_sec = 3; +		timeout.tv_usec = 0; +		if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) +		{ +			PRINT_SOCKET_ERROR("setsockopt"); +		} +		timeout.tv_sec = 3; +		timeout.tv_usec = 0; +		if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) +		{ +			PRINT_SOCKET_ERROR("setsockopt"); +		} +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ +		n = connect(s, p->ai_addr, p->ai_addrlen); +#ifdef MINIUPNPC_IGNORE_EINTR +		while(n < 0 && errno == EINTR) +		{ +			socklen_t len; +			fd_set wset; +			int err; +			FD_ZERO(&wset); +			FD_SET(s, &wset); +			if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) +				continue; +			/*len = 0;*/ +			/*n = getpeername(s, NULL, &len);*/ +			len = sizeof(err); +			if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { +				PRINT_SOCKET_ERROR("getsockopt"); +				closesocket(s); +				freeaddrinfo(ai); +				return -1; +			} +			if(err != 0) { +				errno = err; +				n = -1; +			} +		} +#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ +		if(n < 0) +		{ +			closesocket(s); +			continue; +		} +		else +		{ +			break; +		} +	} +	freeaddrinfo(ai); +	if(s < 0) +	{ +		PRINT_SOCKET_ERROR("socket"); +		return -1; +	} +	if(n < 0) +	{ +		PRINT_SOCKET_ERROR("connect"); +		return -1; +	} +#endif /* #ifdef USE_GETHOSTBYNAME */ +	return s; +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h new file mode 100644 index 0000000..57e24eb --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h @@ -0,0 +1,17 @@ +/* $Id: connecthostport.h,v 1.1 2010/04/04 23:21:03 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2010 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef __CONNECTHOSTPORT_H__ +#define __CONNECTHOSTPORT_H__ + +/* connecthostport() + * return a socket connected (TCP) to the host and port + * or -1 in case of error */ +int connecthostport(const char * host, unsigned short port); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h new file mode 100644 index 0000000..b804247 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h @@ -0,0 +1,15 @@ +#ifndef __DECLSPEC_H__ +#define __DECLSPEC_H__ + +#if defined(WIN32) && !defined(STATICLIB) +	#ifdef MINIUPNP_EXPORTS +		#define LIBSPEC __declspec(dllexport) +	#else +		#define LIBSPEC __declspec(dllimport) +	#endif +#else +	#define LIBSPEC +#endif + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c new file mode 100644 index 0000000..6c3e656 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c @@ -0,0 +1,125 @@ +/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2010 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++; +	if( (l==7) && !memcmp(name, "service", l) ) { +		datas->tmp.controlurl[0] = '\0'; +		datas->tmp.eventsuburl[0] = '\0'; +		datas->tmp.scpdurl[0] = '\0'; +		datas->tmp.servicetype[0] = '\0'; +	} +} + +/* 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) ) +	{ +		/* +		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->tmp.servicetype, +				"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) { +			memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); +		} else if(0==strcmp(datas->tmp.servicetype, +				"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) { +			memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); +		} else if(0==strcmp(datas->tmp.servicetype, +				"urn:schemas-upnp-org:service:WANIPConnection:1") +				 || 0==strcmp(datas->tmp.servicetype, +				"urn:schemas-upnp-org:service:WANPPPConnection:1") ) { +			if(datas->first.servicetype[0] == '\0') { +				memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); +			} else { +				memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); +			} +		} +	} +} + +/* 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( !strcmp(datas->cureltname, "presentationURL") ) +		dstmember = datas->presentationurl; +	else if( !strcmp(datas->cureltname, "serviceType") ) +		dstmember = datas->tmp.servicetype; +	else if( !strcmp(datas->cureltname, "controlURL") ) +		dstmember = datas->tmp.controlurl; +	else if( !strcmp(datas->cureltname, "eventSubURL") ) +		dstmember = datas->tmp.eventsuburl; +	else if( !strcmp(datas->cureltname, "SCPDURL") ) +		dstmember = datas->tmp.scpdurl; +/*	else if( !strcmp(datas->cureltname, "deviceType") ) +		dstmember = datas->devicetype_tmp;*/ +	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->CIF.devicetype);*/ +	printf(" serviceType = '%s'\n", d->CIF.servicetype); +	printf(" controlURL = '%s'\n", d->CIF.controlurl); +	printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); +	printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); +	printf("primary WAN Connection Device (IP or PPP Connection):\n"); +	/*printf(" deviceType = '%s'\n", d->first.devicetype);*/ +	printf(" servicetype = '%s'\n", d->first.servicetype); +	printf(" controlURL = '%s'\n", d->first.controlurl); +	printf(" eventSubURL = '%s'\n", d->first.eventsuburl); +	printf(" SCPDURL = '%s'\n", d->first.scpdurl); +	printf("secondary WAN Connection Device (IP or PPP Connection):\n"); +	/*printf(" deviceType = '%s'\n", d->second.devicetype);*/ +	printf(" servicetype = '%s'\n", d->second.servicetype); +	printf(" controlURL = '%s'\n", d->second.controlurl); +	printf(" eventSubURL = '%s'\n", d->second.eventsuburl); +	printf(" SCPDURL = '%s'\n", d->second.scpdurl); +	printf("WAN IPv6 Firewall Control :\n"); +	/*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ +	printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); +	printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); +	printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); +	printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h new file mode 100644 index 0000000..bab1fd5 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h @@ -0,0 +1,48 @@ +/* $Id: igd_desc_parse.h,v 1.10 2011/04/11 09:19:24 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2010 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 (128) +struct IGDdatas_service { +	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];*/ +}; + +struct IGDdatas { +	char cureltname[MINIUPNPC_URL_MAXSIZE]; +	char urlbase[MINIUPNPC_URL_MAXSIZE]; +	char presentationurl[MINIUPNPC_URL_MAXSIZE]; +	int level; +	/*int state;*/ +	/* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ +	struct IGDdatas_service CIF; +	/* "urn:schemas-upnp-org:service:WANIPConnection:1" +	 * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ +	struct IGDdatas_service first; +	/* if both WANIPConnection and WANPPPConnection are present */ +	struct IGDdatas_service second; +	/* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ +	struct IGDdatas_service IPv6FC; +	/* tmp */ +	struct IGDdatas_service tmp; +}; + +void IGDstartelt(void *, const char *, int); +void IGDendelt(void *, const char *, int); +void IGDdata(void *, const char *, int); +void printIGD(struct IGDdatas *); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c new file mode 100644 index 0000000..8889bf0 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c @@ -0,0 +1,121 @@ +/* $Id: minisoap.c,v 1.21 2011/03/22 19:15:35 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2009 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" +#include "miniupnpcstrings.h" + +/* only for malloc */ +#include <stdlib.h> + +#ifdef WIN32 +#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +/* 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; +	/* TODO: AVOID MALLOC */ +	p = malloc(headerssize+bodysize); +	if(!p) +	  return 0; +	memcpy(p, headers, headerssize); +	memcpy(p+headerssize, body, bodysize); +	/*n = write(fd, p, headerssize+bodysize);*/ +	n = send(fd, p, headerssize+bodysize, 0); +	if(n<0) { +	  PRINT_SOCKET_ERROR("send"); +	} +	/* disable send on the socket */ +	/* draytek routers dont seems to like that... */ +#if 0 +#ifdef WIN32 +	if(shutdown(fd, SD_SEND)<0) { +#else +	if(shutdown(fd, SHUT_WR)<0)	{ /*SD_SEND*/ +#endif +		PRINT_SOCKET_ERROR("shutdown"); +	} +#endif +	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, +				   const char * httpversion) +{ +	int bodysize; +	char headerbuf[512]; +	int headerssize; +	char portstr[8]; +	bodysize = (int)strlen(body); +	/* We are not using keep-alive HTTP connections. +	 * HTTP/1.1 needs the header Connection: close to do that. +	 * This is the default with HTTP/1.0 +	 * Using HTTP/1.1 means we need to support chunked transfer-encoding : +	 * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked +	 * transfer encoding. */ +    /* Connection: Close is normally there only in HTTP/1.1 but who knows */ +	portstr[0] = '\0'; +	if(port != 80) +		snprintf(portstr, sizeof(portstr), ":%hu", port); +	headerssize = snprintf(headerbuf, sizeof(headerbuf), +                       "POST %s HTTP/%s\r\n" +	                   "Host: %s%s\r\n" +					   "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" +	                   "Content-Length: %d\r\n" +					   "Content-Type: text/xml\r\n" +					   "SOAPAction: \"%s\"\r\n" +					   "Connection: Close\r\n" +					   "Cache-Control: no-cache\r\n"	/* ??? */ +					   "Pragma: no-cache\r\n" +					   "\r\n", +					   url, httpversion, host, portstr, bodysize, action); +#ifdef DEBUG +	/*printf("SOAP request : headersize=%d bodysize=%d\n", +	       headerssize, bodysize); +	*/ +	printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", +	        url, httpversion, host, portstr); +	printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); +	printf("Headers :\n%s", headerbuf); +	printf("Body :\n%s\n", body); +#endif +	return httpWrite(fd, body, bodysize, headerbuf, headerssize); +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h new file mode 100644 index 0000000..696725f --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h @@ -0,0 +1,15 @@ +/* $Id: minisoap.h,v 1.4 2010/04/12 20:39:41 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 *, const char *); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c new file mode 100644 index 0000000..e61c1cd --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c @@ -0,0 +1,138 @@ +/* $Id: minissdpc.c,v 1.14 2010/11/25 09:57:25 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2009 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +/*#include <syslog.h>*/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#ifndef WIN32 +#include <unistd.h> +#include <sys/types.h> +#else +#define ssize_t int +#endif + +#if defined(WIN32) || defined(__amigaos__) || defined(__amigaos4__) +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#include <winsock.h> +#include <stdint.h> +#endif +#if defined(__amigaos__) || defined(__amigaos4__) +#include <sys/socket.h> +#endif +#if defined(__amigaos__) +#define uint16_t unsigned short +#endif +/* Hack */ +#define UNIX_PATH_LEN   108 +struct sockaddr_un { +  uint16_t sun_family; +  char     sun_path[UNIX_PATH_LEN]; +}; +#else +#include <sys/socket.h> +#include <sys/un.h> +#endif + +#include "minissdpc.h" +#include "miniupnpc.h" + +#include "codelength.h" + +struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) +{ +	struct UPNPDev * tmp; +	struct UPNPDev * devlist = NULL; +	unsigned char buffer[2048]; +	ssize_t n; +	unsigned char * p; +	unsigned char * url; +	unsigned int i; +	unsigned int urlsize, stsize, usnsize, l; +	int s; +	struct sockaddr_un addr; + +	s = socket(AF_UNIX, SOCK_STREAM, 0); +	if(s < 0) +	{ +		/*syslog(LOG_ERR, "socket(unix): %m");*/ +		perror("socket(unix)"); +		return NULL; +	} +	addr.sun_family = AF_UNIX; +	strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); +	/* TODO : check if we need to handle the EINTR */ +	if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) +	{ +		/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ +		close(s); +		return NULL; +	} +	stsize = strlen(devtype); +	buffer[0] = 1; /* request type 1 : request devices/services by type */ +	p = buffer + 1; +	l = stsize;	CODELENGTH(l, p); +	if(p + stsize > buffer + sizeof(buffer)) +	{ +		/* devtype is too long ! */ +		close(s); +		return NULL; +	} +	memcpy(p, devtype, stsize); +	p += stsize; +	if(write(s, buffer, p - buffer) < 0) +	{ +		/*syslog(LOG_ERR, "write(): %m");*/ +		perror("minissdpc.c: write()"); +		close(s); +		return NULL; +	} +	n = read(s, buffer, sizeof(buffer)); +	if(n<=0) +	{ +		perror("minissdpc.c: read()"); +		close(s); +		return NULL; +	} +	p = buffer + 1; +	for(i = 0; i < buffer[0]; i++) +	{ +		if(p+2>=buffer+sizeof(buffer)) +			break; +		DECODELENGTH(urlsize, p); +		if(p+urlsize+2>=buffer+sizeof(buffer)) +			break; +		url = p; +		p += urlsize; +		DECODELENGTH(stsize, p); +		if(p+stsize+2>=buffer+sizeof(buffer)) +			break; +		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, url, urlsize); +		tmp->buffer[urlsize] = '\0'; +		memcpy(tmp->buffer + urlsize + 1, p, stsize); +		p += stsize; +		tmp->buffer[urlsize+1+stsize] = '\0'; +		devlist = tmp; +		/* added for compatibility with recent versions of MiniSSDPd  +		 * >= 2007/12/19 */ +		DECODELENGTH(usnsize, p); +		p += usnsize; +		if(p>buffer + sizeof(buffer)) +			break; +	} +	close(s); +	return devlist; +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h new file mode 100644 index 0000000..25e91ce --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h @@ -0,0 +1,15 @@ +/* $Id: minissdpc.h,v 1.1 2007/08/31 15:15:33 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2007 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef __MINISSDPC_H__ +#define __MINISSDPC_H__ + +struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c new file mode 100644 index 0000000..bd46a24 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c @@ -0,0 +1,906 @@ +/* $Id: miniupnpc.c,v 1.95 2011/05/15 21:42:26 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2011 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENSE file. */ +#define __EXTENSIONS__ 1 +#if !defined(MACOSX) && !defined(__sun) +#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__) +#ifndef __cplusplus +#define _XOPEN_SOURCE 600 +#endif +#endif +#ifndef __BSD_VISIBLE +#define __BSD_VISIBLE 1 +#endif +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#ifdef WIN32 +/* Win32 Specific includes and defines */ +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#include <iphlpapi.h> +#define snprintf _snprintf +#ifndef strncasecmp +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define strncasecmp _memicmp +#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#define strncasecmp memicmp +#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#endif /* #ifndef strncasecmp */ +#define MAXHOSTNAMELEN 64 +#else /* #ifdef WIN32 */ +/* Standard POSIX includes */ +#include <unistd.h> +#if defined(__amigaos__) && !defined(__amigaos4__) +/* Amiga OS 3 specific stuff */ +#define socklen_t int +#else +#include <sys/select.h> +#endif +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <net/if.h> +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include <poll.h> +#endif +#include <strings.h> +#include <errno.h> +#define closesocket close +#endif /* #else WIN32 */ +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT +#include <sys/time.h> +#endif +#if defined(__amigaos__) || defined(__amigaos4__) +/* Amiga OS specific stuff */ +#define TIMEVAL struct timeval +#endif + +#include "miniupnpc.h" +#include "minissdpc.h" +#include "miniwget.h" +#include "minisoap.h" +#include "minixml.h" +#include "upnpcommands.h" +#include "connecthostport.h" +#include "receivedata.h" + +#ifdef WIN32 +#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#define SOAPPREFIX "s" +#define SERVICEPREFIX "u" +#define SERVICEPREFIX2 'u' + +/* root description parsing */ +LIBSPEC 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); +#ifdef DEBUG +	printIGD(data); +#endif +} + +/* simpleUPnPcommand2 : + * not so simple ! + * return values : + *   pointer - OK + *   NULL - error */ +char * simpleUPnPcommand2(int s, const char * url, const char * service, +		       const char * action, struct UPNParg * args, +		       int * bufsize, const char * httpversion) +{ +	char hostname[MAXHOSTNAMELEN+1]; +	unsigned short port = 0; +	char * path; +	char soapact[128]; +	char soapbody[2048]; +	char * buf; +    int n; + +	*bufsize = 0; +	snprintf(soapact, sizeof(soapact), "%s#%s", service, action); +	if(args==NULL) +	{ +		/*soapbodylen = */snprintf(soapbody, sizeof(soapbody), +						"<?xml version=\"1.0\"?>\r\n" +	    	              "<" SOAPPREFIX ":Envelope " +						  "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " +						  SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +						  "<" SOAPPREFIX ":Body>" +						  "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" +						  "</" SERVICEPREFIX ":%s>" +						  "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>" +					 	  "\r\n", action, service, action); +	} +	else +	{ +		char * p; +		const char * pe, * pv; +		int soapbodylen; +		soapbodylen = snprintf(soapbody, sizeof(soapbody), +						"<?xml version=\"1.0\"?>\r\n" +	    	            "<" SOAPPREFIX ":Envelope " +						"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " +						SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +						"<" SOAPPREFIX ":Body>" +						"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%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 */ +				return NULL; +			} +			*(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++) = SERVICEPREFIX2; +		*(p++) = ':'; +		pe = action; +		while(*pe) +			*(p++) = *(pe++); +		strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", +		        soapbody + sizeof(soapbody) - p); +	} +	if(!parseURL(url, hostname, &port, &path)) return NULL; +	if(s<0) +	{ +		s = connecthostport(hostname, port); +		if(s < 0) +		{ +			return NULL; +		} +	} + +	n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); +	if(n<=0) { +#ifdef DEBUG +		printf("Error sending SOAP request\n"); +#endif +		closesocket(s); +		return NULL; +	} + +	buf = getHTTPResponse(s, bufsize); +#ifdef DEBUG +	if(*bufsize > 0 && buf) +	{ +		printf("SOAP Response :\n%.*s\n", *bufsize, buf); +	} +#endif +	closesocket(s); +	return buf; +} + +/* simpleUPnPcommand : + * not so simple ! + * return values : + *   pointer - OK + *   NULL    - error */ +char * simpleUPnPcommand(int s, const char * url, const char * service, +		       const char * action, struct UPNParg * args, +		       int * bufsize) +{ +	char * buf; + +	buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); +/* +	buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); +	if (!buf || *bufsize == 0) +	{ +#if DEBUG +	    printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); +#endif +		buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); +	} +*/ +	return buf; +} + +/* 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;	/* end of the "header" (position of the colon) */ +	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');*/ +					/* skip the colon and white spaces */ +					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 XSTR(s) STR(s) +#define STR(s) #s +#define UPNP_MCAST_ADDR "239.255.255.250" +/* for IPv6 */ +#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */ +#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */ + +/* 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) */ +LIBSPEC struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, +             const char * minissdpdsock, int sameport, +             int ipv6, +             int * error) +{ +	struct UPNPDev * tmp; +	struct UPNPDev * devlist = 0; +	int opt = 1; +	static const char MSearchMsgFmt[] =  +	"M-SEARCH * HTTP/1.1\r\n" +	"HOST: %s:" XSTR(PORT) "\r\n" +	"ST: %s\r\n" +	"MAN: \"ssdp:discover\"\r\n" +	"MX: %u\r\n" +	"\r\n"; +	static const char * const deviceList[] = { +#if 0 +		"urn:schemas-upnp-org:device:InternetGatewayDevice:2", +		"urn:schemas-upnp-org:service:WANIPConnection:2", +#endif +		"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_storage sockudp_r; +	unsigned int mx; +#ifdef NO_GETADDRINFO +	struct sockaddr_storage sockudp_w; +#else +	int rv; +	struct addrinfo hints, *servinfo, *p; +#endif +#ifdef WIN32 +	MIB_IPFORWARDROW ip_forward; +#endif +	int linklocal = 1; + +	if(error) +		*error = UPNPDISCOVER_UNKNOWN_ERROR; +#if !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) +	/* first try to get infos from minissdpd ! */ +	if(!minissdpdsock) +		minissdpdsock = "/var/run/minissdpd.sock"; +	while(!devlist && deviceList[deviceIndex]) { +		devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex], +		                                  minissdpdsock); +		/* We return what we have found if it was not only a rootdevice */ +		if(devlist && !strstr(deviceList[deviceIndex], "rootdevice")) { +			if(error) +				*error = UPNPDISCOVER_SUCCESS; +			return devlist; +		} +		deviceIndex++; +	} +	deviceIndex = 0; +#endif +	/* fallback to direct discovery */ +#ifdef WIN32 +	sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP); +#else +	sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0); +#endif +	if(sudp < 0) +	{ +		if(error) +			*error = UPNPDISCOVER_SOCKET_ERROR; +		PRINT_SOCKET_ERROR("socket"); +		return NULL; +	} +	/* reception */ +	memset(&sockudp_r, 0, sizeof(struct sockaddr_storage)); +	if(ipv6) { +		struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r; +		p->sin6_family = AF_INET6; +		if(sameport) +			p->sin6_port = htons(PORT); +		p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ +	} else { +		struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; +		p->sin_family = AF_INET; +		if(sameport) +			p->sin_port = htons(PORT); +		p->sin_addr.s_addr = INADDR_ANY; +	} +#ifdef WIN32 +/* This code could help us to use the right Network interface for  + * SSDP multicast traffic */ +/* Get IP associated with the index given in the ip_forward struct + * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ +	if(!ipv6 +	   && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { +		DWORD dwRetVal = 0; +		PMIB_IPADDRTABLE pIPAddrTable; +		DWORD dwSize = 0; +#ifdef DEBUG +		IN_ADDR IPAddr; +#endif +		int i; +#ifdef DEBUG +		printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); +#endif +		pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); +		if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { +			free(pIPAddrTable); +			pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); +		} +		if(pIPAddrTable) { +			dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); +#ifdef DEBUG +			printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); +#endif +			for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { +#ifdef DEBUG +				printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); +				IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; +				printf("\tIP Address[%d]:     \t%s\n", i, inet_ntoa(IPAddr) ); +				IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; +				printf("\tSubnet Mask[%d]:    \t%s\n", i, inet_ntoa(IPAddr) ); +				IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; +				printf("\tBroadCast[%d]:      \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); +				printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); +				printf("\tType and State[%d]:", i); +				printf("\n"); +#endif +				if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { +					/* Set the address of this interface to be used */ +					struct in_addr mc_if; +					memset(&mc_if, 0, sizeof(mc_if)); +					mc_if.s_addr = pIPAddrTable->table[i].dwAddr; +					if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { +						PRINT_SOCKET_ERROR("setsockopt"); +					} +					((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; +#ifndef DEBUG +					break; +#endif +				} +			} +			free(pIPAddrTable); +			pIPAddrTable = NULL; +		} +	} +#endif + +#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 +	{ +		if(error) +			*error = UPNPDISCOVER_SOCKET_ERROR; +		PRINT_SOCKET_ERROR("setsockopt"); +		return NULL; +	} + +	if(multicastif) +	{ +		if(ipv6) { +#if !defined(WIN32) +			/* according to MSDN, if_nametoindex() is supported since +			 * MS Windows Vista and MS Windows Server 2008. +			 * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ +			unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ +			if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0) +			{ +				PRINT_SOCKET_ERROR("setsockopt"); +			} +#else +#ifdef DEBUG +			printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); +#endif +#endif +		} else { +			struct in_addr mc_if; +			mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ +			((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; +			if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) +			{ +				PRINT_SOCKET_ERROR("setsockopt"); +			} +		} +	} + +	/* Avant d'envoyer le paquet on bind pour recevoir la reponse */ +    if (bind(sudp, (const struct sockaddr *)&sockudp_r, +	         ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) +	{ +		if(error) +			*error = UPNPDISCOVER_SOCKET_ERROR; +        PRINT_SOCKET_ERROR("bind"); +		closesocket(sudp); +		return NULL; +    } + +	if(error) +		*error = UPNPDISCOVER_SUCCESS; +	/* Calculating maximum response time in seconds */ +	mx = ((unsigned int)delay) / 1000u; +	/* receiving SSDP response packet */ +	for(n = 0; deviceList[deviceIndex]; deviceIndex++) +	{ +	if(n == 0) +	{ +		/* sending the SSDP M-SEARCH packet */ +		n = snprintf(bufr, sizeof(bufr), +		             MSearchMsgFmt, +		             ipv6 ? +		             (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" :  "[" UPNP_MCAST_SL_ADDR "]") +		             : UPNP_MCAST_ADDR, +		             deviceList[deviceIndex], mx); +#ifdef DEBUG +		printf("Sending %s", bufr); +#endif +#ifdef NO_GETADDRINFO +		/* the following code is not using getaddrinfo */ +		/* emission */ +		memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); +		if(ipv6) { +			struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; +			p->sin6_family = AF_INET6; +			p->sin6_port = htons(PORT); +			inet_pton(AF_INET6, +			          linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, +			          &(p->sin6_addr)); +		} else { +			struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; +			p->sin_family = AF_INET; +			p->sin_port = htons(PORT); +			p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); +		} +		n = sendto(sudp, bufr, n, 0, +		           &sockudp_w, +		           ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); +		if (n < 0) { +			if(error) +				*error = UPNPDISCOVER_SOCKET_ERROR; +			PRINT_SOCKET_ERROR("sendto"); +			break; +		} +#else /* #ifdef NO_GETADDRINFO */ +		memset(&hints, 0, sizeof(hints)); +		hints.ai_family = AF_UNSPEC; // AF_INET6 or AF_INET +		hints.ai_socktype = SOCK_DGRAM; +		/*hints.ai_flags = */ +		if ((rv = getaddrinfo(ipv6 +		                      ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) +		                      : UPNP_MCAST_ADDR, +		                      XSTR(PORT), &hints, &servinfo)) != 0) { +			if(error) +				*error = UPNPDISCOVER_SOCKET_ERROR; +#ifdef WIN32 +		    fprintf(stderr, "getaddrinfo() failed: %d\n", rv); +#else +		    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); +#endif +			break; +		} +		for(p = servinfo; p; p = p->ai_next) { +			n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); +			if (n < 0) { +				PRINT_SOCKET_ERROR("sendto"); +				continue; +			} +		} +		freeaddrinfo(servinfo); +		if(n < 0) { +			if(error) +				*error = UPNPDISCOVER_SOCKET_ERROR; +			break; +		} +#endif /* #ifdef NO_GETADDRINFO */ +	} +	/* Waiting for SSDP REPLY packet to M-SEARCH */ +	n = receivedata(sudp, bufr, sizeof(bufr), delay); +	if (n < 0) { +		/* error */ +		if(error) +			*error = UPNPDISCOVER_SOCKET_ERROR; +		break; +	} else if (n == 0) { +		/* no data or Time Out */ +		if (devlist) { +			/* no more device type to look for... */ +			if(error) +				*error = UPNPDISCOVER_SUCCESS; +			break; +		} +		if(ipv6) { +			if(linklocal) { +				linklocal = 0; +				--deviceIndex; +			} else { +				linklocal = 1; +			} +		} +	} 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) +		{ +#ifdef DEBUG +			printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n", +			       stsize, st, urlsize, descURL); +#endif +			for(tmp=devlist; tmp; tmp = tmp->pNext) { +				if(memcmp(tmp->descURL, descURL, urlsize) == 0 && +				   tmp->descURL[urlsize] == '\0' && +				   memcmp(tmp->st, st, stsize) == 0 && +				   tmp->st[stsize] == '\0') +					break; +			} +			/* at the exit of the loop above, tmp is null if +			 * no duplicate device was found */ +			if(tmp) +				continue; +			tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); +			if(!tmp) { +				/* memory allocation error */ +				if(error) +					*error = UPNPDISCOVER_MEMORY_ERROR; +				break; +			} +			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; +		} +	} +	} +	closesocket(sudp); +	return devlist; +} + +/* freeUPNPDevlist() should be used to + * free the chained list returned by upnpDiscover() */ +LIBSPEC 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 +	{ +		int l = strlen(dst); +		if(src[0] != '/') +			dst[l++] = '/'; +		if(l<=n) +			strncpy(dst + l, src, n - l); +	} +} + +/* Prepare the Urls for usage... + */ +LIBSPEC void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, +                 const char * descURL) +{ +	char * p; +	int n1, n2, n3, n4; +	n1 = strlen(data->urlbase); +	if(n1==0) +		n1 = strlen(descURL); +	n1 += 2;	/* 1 byte more for Null terminator, 1 byte for '/' if needed */ +	n2 = n1; n3 = n1; n4 = n1; +	n1 += strlen(data->first.scpdurl); +	n2 += strlen(data->first.controlurl); +	n3 += strlen(data->CIF.controlurl); +	n4 += strlen(data->IPv6FC.controlurl); + +	urls->ipcondescURL = (char *)malloc(n1); +	urls->controlURL = (char *)malloc(n2); +	urls->controlURL_CIF = (char *)malloc(n3); +	urls->controlURL_6FC = (char *)malloc(n4); +	/* 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); +	strncpy(urls->controlURL_6FC, urls->ipcondescURL, n4); +	 +	url_cpy_or_cat(urls->ipcondescURL, data->first.scpdurl, n1); + +	url_cpy_or_cat(urls->controlURL, data->first.controlurl, n2); + +	url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3); + +	url_cpy_or_cat(urls->controlURL_6FC, data->IPv6FC.controlurl, n4); + +#ifdef DEBUG +	printf("urls->ipcondescURL='%s' %u n1=%d\n", urls->ipcondescURL, +	       (unsigned)strlen(urls->ipcondescURL), n1); +	printf("urls->controlURL='%s' %u n2=%d\n", urls->controlURL, +	       (unsigned)strlen(urls->controlURL), n2); +	printf("urls->controlURL_CIF='%s' %u n3=%d\n", urls->controlURL_CIF, +	       (unsigned)strlen(urls->controlURL_CIF), n3); +	printf("urls->controlURL_6FC='%s' %u n4=%d\n", urls->controlURL_6FC, +	       (unsigned)strlen(urls->controlURL_6FC), n4); +#endif +} + +LIBSPEC 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; +	free(urls->controlURL_6FC); +	urls->controlURL_6FC = 0; +} + +int +UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) +{ +	char status[64]; +	unsigned int uptime; +	status[0] = '\0'; +	UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, +	                   status, &uptime, NULL); +	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. + */ +LIBSPEC 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 */ +			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; +				if(0==strcmp(data->CIF.servicetype, +				   "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1") +				   || state >= 3 ) +				{ +				  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); +				  if(data->second.servicetype[0] != '\0') { +#ifdef DEBUG +				    printf("We tried %s, now we try %s !\n", +				           data->first.servicetype, data->second.servicetype); +#endif +				    /* swaping WANPPPConnection and WANIPConnection ! */ +				    memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); +				    memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); +				    memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); +				    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; +} + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * return value : + *   0 - Not ok + *   1 - OK */ +int +UPNP_GetIGDFromUrl(const char * rootdescurl, +                   struct UPNPUrls * urls, +                   struct IGDdatas * data, +                   char * lanaddr, int lanaddrlen) +{ +	char * descXML; +	int descXMLsize = 0; +	descXML = miniwget_getaddr(rootdescurl, &descXMLsize, +	   	                       lanaddr, lanaddrlen); +	if(descXML) { +		memset(data, 0, sizeof(struct IGDdatas)); +		memset(urls, 0, sizeof(struct UPNPUrls)); +		parserootdesc(descXML, descXMLsize, data); +		free(descXML); +		descXML = NULL; +		GetUPNPUrls(urls, data, rootdescurl); +		return 1; +	} else { +		return 0; +	} +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h new file mode 100644 index 0000000..50df017 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h @@ -0,0 +1,121 @@ +/* $Id: miniupnpc.h,v 1.23 2011/04/11 08:21:46 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2005-2011 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" + +/* error codes : */ +#define UPNPDISCOVER_SUCCESS (0) +#define UPNPDISCOVER_UNKNOWN_ERROR (-1) +#define UPNPDISCOVER_SOCKET_ERROR (-101) +#define UPNPDISCOVER_MEMORY_ERROR (-102) + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structures definitions : */ +struct UPNParg { const char * elt; const char * val; }; + +char * +simpleUPnPcommand(int, const char *, const char *, +                  const char *, struct UPNParg *, +                  int *); + +struct UPNPDev { +	struct UPNPDev * pNext; +	char * descURL; +	char * st; +	char buffer[2]; +}; + +/* upnpDiscover() + * discover UPnP devices on the network. + * The discovered devices are returned as a chained list. + * It is up to the caller to free the list with freeUPNPDevlist(). + * delay (in millisecond) is the maximum time for waiting any device + * response. + * If available, device list will be obtained from MiniSSDPd. + * Default path for minissdpd socket will be used if minissdpdsock argument + * is NULL. + * If multicastif is not NULL, it will be used instead of the default + * multicast interface for sending SSDP discover packets. + * If sameport is not null, SSDP packets will be sent from the source port + * 1900 (same as destination port) otherwise system assign a source port. */ +LIBSPEC struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, +             const char * minissdpdsock, int sameport, +             int ipv6, +             int * error); +/* freeUPNPDevlist() + * free list returned by upnpDiscover() */ +LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); + +/* parserootdesc() : + * parse root XML description of a UPnP device and fill the IGDdatas + * structure. */ +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 + * controlURL_6FC: controlURL of the WANIPv6FirewallControl + */ +struct UPNPUrls { +	char * controlURL; +	char * ipcondescURL; +	char * controlURL_CIF; +	char * controlURL_6FC; +}; + +/* 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); + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * return value : + *   0 - Not ok + *   1 - OK */ +LIBSPEC int +UPNP_GetIGDFromUrl(const char * rootdescurl, +                   struct UPNPUrls * urls, +                   struct IGDdatas * data, +                   char * lanaddr, int lanaddrlen); + +LIBSPEC void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *); + +LIBSPEC void FreeUPNPUrls(struct UPNPUrls *); + +/* return 0 or 1 */ +LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h new file mode 100644 index 0000000..86081c3 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h @@ -0,0 +1,19 @@ +/* $Id: miniupnpctypes.h,v 1.1 2011/02/15 11:10:40 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org + * Author : Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef __MINIUPNPCTYPES_H__ +#define __MINIUPNPCTYPES_H__ + +#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) +#define UNSIGNED_INTEGER unsigned long long +#define STRTOUI	strtoull +#else +#define UNSIGNED_INTEGER unsigned int +#define STRTOUI	strtoul +#endif + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c new file mode 100644 index 0000000..87f6155 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c @@ -0,0 +1,522 @@ +/* $Id: miniwget.c,v 1.52 2011/06/17 22:59:42 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2011 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 <ctype.h> +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#define MAXHOSTNAMELEN 64 +#define MIN(x,y) (((x)<(y))?(x):(y)) +#define snprintf _snprintf +#define socklen_t int +#ifndef strncasecmp +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define strncasecmp _memicmp +#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#define strncasecmp memicmp +#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#endif /* #ifndef strncasecmp */ +#else /* #ifdef WIN32 */ +#include <unistd.h> +#include <sys/param.h> +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include <sys/select.h> +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netdb.h> +#define closesocket close +/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions + * during the connect() call */ +#define MINIUPNPC_IGNORE_EINTR +#endif /* #else WIN32 */ +#if defined(__sun) || defined(sun) +#define MIN(x,y) (((x)<(y))?(x):(y)) +#endif + +#include "miniupnpcstrings.h" +#include "miniwget.h" +#include "connecthostport.h" +#include "receivedata.h" + +/* + * Read a HTTP response from a socket. + * Process Content-Length and Transfer-encoding headers. + * return a pointer to the content buffer, which length is saved + * to the length parameter. + */ +void * +getHTTPResponse(int s, int * size) +{ +	char buf[2048]; +	int n; +	int endofheaders = 0; +	int chunked = 0; +	int content_length = -1; +	unsigned int chunksize = 0; +	unsigned int bytestocopy = 0; +	/* buffers : */ +	char * header_buf; +	int header_buf_len = 2048; +	int header_buf_used = 0; +	char * content_buf; +	int content_buf_len = 2048; +	int content_buf_used = 0; +	char chunksize_buf[32]; +	int chunksize_buf_index; + +	header_buf = malloc(header_buf_len); +	content_buf = malloc(content_buf_len); +	chunksize_buf[0] = '\0'; +	chunksize_buf_index = 0; + +	while((n = receivedata(s, buf, 2048, 5000)) > 0) +	{ +		if(endofheaders == 0) +		{ +			int i; +			int linestart=0; +			int colon=0; +			int valuestart=0; +			if(header_buf_used + n > header_buf_len) { +				header_buf = realloc(header_buf, header_buf_used + n); +				header_buf_len = header_buf_used + n; +			} +			memcpy(header_buf + header_buf_used, buf, n); +			header_buf_used += n; +			/* search for CR LF CR LF (end of headers) +			 * recognize also LF LF */ +			i = 0; +			while(i < (header_buf_used-1) && (endofheaders == 0)) { +				if(header_buf[i] == '\r') { +					i++; +					if(header_buf[i] == '\n') { +						i++; +						if(i < header_buf_used && header_buf[i] == '\r') { +							i++; +							if(i < header_buf_used && header_buf[i] == '\n') { +								endofheaders = i+1; +							} +						} +					} +				} else if(header_buf[i] == '\n') { +					i++; +					if(header_buf[i] == '\n') { +						endofheaders = i+1; +					} +				} +				i++; +			} +			if(endofheaders == 0) +				continue; +			/* parse header lines */ +			for(i = 0; i < endofheaders - 1; i++) { +				if(colon <= linestart && header_buf[i]==':') +				{ +					colon = i; +					while(i < (endofheaders-1) +					      && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t')) +						i++; +					valuestart = i + 1; +				} +				/* detecting end of line */ +				else if(header_buf[i]=='\r' || header_buf[i]=='\n') +				{ +					if(colon > linestart && valuestart > colon) +					{ +#ifdef DEBUG +						printf("header='%.*s', value='%.*s'\n", +						       colon-linestart, header_buf+linestart, +						       i-valuestart, header_buf+valuestart); +#endif +						if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart)) +						{ +							content_length = atoi(header_buf+valuestart); +#ifdef DEBUG +							printf("Content-Length: %d\n", content_length); +#endif +						} +						else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart) +						   && 0==strncasecmp(header_buf+valuestart, "chunked", 7)) +						{ +#ifdef DEBUG +							printf("chunked transfer-encoding!\n"); +#endif +							chunked = 1; +						} +					} +					while(header_buf[i]=='\r' || header_buf[i] == '\n') +						i++; +					linestart = i; +					colon = linestart; +					valuestart = 0; +				}  +			} +			/* copy the remaining of the received data back to buf */ +			n = header_buf_used - endofheaders; +			memcpy(buf, header_buf + endofheaders, n); +			/* if(headers) */ +		} +		if(endofheaders) +		{ +			/* content */ +			if(chunked) +			{ +				int i = 0; +				while(i < n) +				{ +					if(chunksize == 0) +					{ +						/* reading chunk size */ +						if(chunksize_buf_index == 0) { +							/* skipping any leading CR LF */ +							if(i<n && buf[i] == '\r') i++; +							if(i<n && buf[i] == '\n') i++; +						} +						while(i<n && isxdigit(buf[i]) +						     && chunksize_buf_index < (sizeof(chunksize_buf)-1)) +						{ +							chunksize_buf[chunksize_buf_index++] = buf[i]; +							chunksize_buf[chunksize_buf_index] = '\0'; +							i++; +						} +						while(i<n && buf[i] != '\r' && buf[i] != '\n') +							i++; /* discarding chunk-extension */ +						if(i<n && buf[i] == '\r') i++; +						if(i<n && buf[i] == '\n') { +							int j; +							for(j = 0; j < chunksize_buf_index; j++) { +							if(chunksize_buf[j] >= '0' +							   && chunksize_buf[j] <= '9') +								chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); +							else +								chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); +							} +							chunksize_buf[0] = '\0'; +							chunksize_buf_index = 0; +							i++; +						} else { +							/* not finished to get chunksize */ +							continue; +						} +#ifdef DEBUG +						printf("chunksize = %u (%x)\n", chunksize, chunksize); +#endif +						if(chunksize == 0) +						{ +#ifdef DEBUG +							printf("end of HTTP content - %d %d\n", i, n); +							/*printf("'%.*s'\n", n-i, buf+i);*/ +#endif +							goto end_of_stream; +						} +					} +					bytestocopy = ((int)chunksize < n - i)?chunksize:(n - i); +					if((int)(content_buf_used + bytestocopy) > content_buf_len) +					{ +						if(content_length >= content_buf_used + (int)bytestocopy) { +							content_buf_len = content_length; +						} else { +							content_buf_len = content_buf_used + (int)bytestocopy; +						} +						content_buf = (char *)realloc((void *)content_buf,  +						                              content_buf_len); +					} +					memcpy(content_buf + content_buf_used, buf + i, bytestocopy); +					content_buf_used += bytestocopy; +					i += bytestocopy; +					chunksize -= bytestocopy; +				} +			} +			else +			{ +				/* not chunked */ +				if(content_length > 0 +				   && (content_buf_used + n) > content_length) { +					/* skipping additional bytes */ +					n = content_length - content_buf_used; +				} +				if(content_buf_used + n > content_buf_len) +				{ +					if(content_length >= content_buf_used + n) { +						content_buf_len = content_length; +					} else { +						content_buf_len = content_buf_used + n; +					} +					content_buf = (char *)realloc((void *)content_buf,  +					                              content_buf_len); +				} +				memcpy(content_buf + content_buf_used, buf, n); +				content_buf_used += n; +			} +		} +		/* use the Content-Length header value if available */ +		if(content_length > 0 && content_buf_used >= content_length) +		{ +#ifdef DEBUG +			printf("End of HTTP content\n"); +#endif +			break; +		} +	} +end_of_stream: +	free(header_buf); header_buf = NULL; +	*size = content_buf_used; +	if(content_buf_used == 0) +	{ +		free(content_buf); +		content_buf = NULL; +	} +	return content_buf; +} + +/* miniwget3() : + * do all the work. + * Return NULL if something failed. */ +static void * +miniwget3(const char * url, const char * host, +          unsigned short port, const char * path, +          int * size, char * addr_str, int addr_str_len, +          const char * httpversion) +{ +	char buf[2048]; +    int s; +	int n; +	int len; +	int sent; +	void * content; + +	*size = 0; +	s = connecthostport(host, port); +	if(s < 0) +		return NULL; + +	/* get address for caller ! */ +	if(addr_str) +	{ +		struct sockaddr_storage saddr; +		socklen_t saddrlen; + +		saddrlen = sizeof(saddr); +		if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) +		{ +			perror("getsockname"); +		} +		else +		{ +#if defined(__amigaos__) && !defined(__amigaos4__) +	/* 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()); +		}*/ +			/* the following code is only compatible with ip v4 addresses */ +			strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len); +#else +#if 0 +			if(saddr.sa_family == AF_INET6) { +				inet_ntop(AF_INET6, +				          &(((struct sockaddr_in6 *)&saddr)->sin6_addr), +				          addr_str, addr_str_len); +			} else { +				inet_ntop(AF_INET, +				          &(((struct sockaddr_in *)&saddr)->sin_addr), +				          addr_str, addr_str_len); +			} +#endif +			/* getnameinfo return ip v6 address with the scope identifier +			 * such as : 2a01:e35:8b2b:7330::%4281128194 */ +			n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, +			                addr_str, addr_str_len, +			                NULL, 0, +			                NI_NUMERICHOST | NI_NUMERICSERV); +			if(n != 0) { +#ifdef WIN32 +				fprintf(stderr, "getnameinfo() failed : %d\n", n); +#else +				fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); +#endif +			} +#endif +		} +#ifdef DEBUG +		printf("address miniwget : %s\n", addr_str); +#endif +	} + +	len = snprintf(buf, sizeof(buf), +                 "GET %s HTTP/%s\r\n" +			     "Host: %s:%d\r\n" +				 "Connection: Close\r\n" +				 "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" + +				 "\r\n", +			   path, httpversion, host, port); +	sent = 0; +	/* sending the HTTP request */ +	while(sent < len) +	{ +		n = send(s, buf+sent, len-sent, 0); +		if(n < 0) +		{ +			perror("send"); +			closesocket(s); +			return NULL; +		} +		else +		{ +			sent += n; +		} +	} +	content = getHTTPResponse(s, size); +	closesocket(s); +	return content; +} + +/* miniwget2() : + * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ +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 * respbuffer; + +	respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); +/* +	respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.0"); +	if (*size == 0) +	{ +#ifdef DEBUG +		printf("Retrying with HTTP/1.1\n"); +#endif +		free(respbuffer); +		respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); +	} +*/ +	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; +	if(!url) +		return 0; +	p1 = strstr(url, "://"); +	if(!p1) +		return 0; +	p1 += 3; +	if(  (url[0]!='h') || (url[1]!='t') +	   ||(url[2]!='t') || (url[3]!='p')) +		return 0; +	memset(hostname, 0, MAXHOSTNAMELEN + 1); +	if(*p1 == '[') +	{ +		/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ +		p2 = strchr(p1, ']'); +		p3 = strchr(p1, '/'); +		if(p2 && p3) +		{ +			p2++; +			strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); +			if(*p2 == ':') +			{ +				*port = 0; +				p2++; +				while( (*p2 >= '0') && (*p2 <= '9')) +				{ +					*port *= 10; +					*port += (unsigned short)(*p2 - '0'); +					p2++; +				} +			} +			else +			{ +				*port = 80; +			} +			*path = p3; +			return 1; +		} +	} +	p2 = strchr(p1, ':'); +	p3 = strchr(p1, '/'); +	if(!p3) +		return 0; +	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; +#ifdef DEBUG +	printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); +#endif +	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; +#ifdef DEBUG +	printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); +#endif +	return miniwget2(url, hostname, port, path, size, addr, addrlen); +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h new file mode 100644 index 0000000..8314b40 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h @@ -0,0 +1,30 @@ +/* $Id: miniwget.h,v 1.6 2010/12/09 16:11:33 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 * getHTTPResponse(int s, int * size); + +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 + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c new file mode 100644 index 0000000..8b5594c --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c @@ -0,0 +1,216 @@ +/* $Id: minixml.c,v 1.9 2011/02/07 13:44:57 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-2011, 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 <string.h> +#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. */ +static 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... */ +static 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; +				/* to ignore namespace : */ +				if(*p->xml==':') +				{ +					i = 0; +					elementname = ++p->xml; +				} +			} +			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) ) +					{ +						i++; p->xml++; +						if (p->xml >= p->xmlend) +							return; +					} +					if(memcmp(p->xml, "<![CDATA[", 9) == 0) +					{  +						/* CDATA handling */ +						p->xml += 9; +						data = p->xml; +						i = 0; +						while(memcmp(p->xml, "]]>", 3) != 0) +						{ +							i++; p->xml++; +							if ((p->xml + 3) >= p->xmlend) +								return; +						} +						if(i>0 && p->datafunc) +							p->datafunc(p->data, data, i); +						while(*p->xml!='<') +						{ +							p->xml++; +							if (p->xml >= p->xmlend) +								return; +						} +					} +					else +					{ +						while(*p->xml!='<') +						{ +							i++; p->xml++; +							if ((p->xml + 1) >= p->xmlend) +								return; +						} +						if(i>0 && p->datafunc && *(p->xml + 1) == '/') +							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); +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h new file mode 100644 index 0000000..857c70e --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h @@ -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 + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c new file mode 100644 index 0000000..766211b --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c @@ -0,0 +1,156 @@ +/* $Id: minixmlvalid.c,v 1.4 2011/02/07 13:44:57 nanard Exp $ */ +/* MiniUPnP Project + * http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ + * minixmlvalid.c : + * validation program for the minixml parser + * + * (c) 2006-2011 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) +	{ +		printf("event number not matching : %d != %d\n", 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/>" +"<elt1>\n<![CDATA[ <html>stuff !\n ]]> \n</elt1>\n" +"<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, "elt1", 4}, +	{CHARDATA, " <html>stuff !\n ", 16}, +	{ELTEND, "elt1", 4}, +	{ELTSTART, "elt2a", 5}, +	{ELTSTART, "elt2b", 5}, +	{CHARDATA, "chardata1", 9}, +	{ELTEND, "elt2b", 5}, +	{ELTSTART, "elt2b", 5}, +	{CHARDATA, " chardata2 ", 11}, +	{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; +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c new file mode 100644 index 0000000..e09e80f --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c @@ -0,0 +1,157 @@ +/* $Id: portlistingparse.c,v 1.4 2011/03/18 11:02:17 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2011 Thomas Bernard  + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#include <string.h> +#include <stdlib.h> +#include "portlistingparse.h" +#include "minixml.h" + +/* list of the elements */ +static const struct { +	const portMappingElt code; +	const char * const str; +} elements[] = { +	{ PortMappingEntry, "PortMappingEntry"}, +	{ NewRemoteHost, "NewRemoteHost"}, +	{ NewExternalPort, "NewExternalPort"}, +	{ NewProtocol, "NewProtocol"}, +	{ NewInternalPort, "NewInternalPort"}, +	{ NewInternalClient, "NewInternalClient"}, +	{ NewEnabled, "NewEnabled"}, +	{ NewDescription, "NewDescription"}, +	{ NewLeaseTime, "NewLeaseTime"}, +	{ PortMappingEltNone, NULL} +}; + +/* Helper function */ +static UNSIGNED_INTEGER +atoui(const char * p, int l) +{ +	UNSIGNED_INTEGER r = 0; +	while(l > 0 && *p) +	{ +		if(*p >= '0' && *p <= '9') +			r = r*10 + (*p - '0'); +		else +			break; +		p++; +		l--; +	} +	return r; +} + +/* Start element handler */ +static void +startelt(void * d, const char * name, int l) +{ +	int i; +	struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; +	pdata->curelt = PortMappingEltNone; +	for(i = 0; elements[i].str; i++) +	{ +		if(memcmp(name, elements[i].str, l) == 0) +		{ +			pdata->curelt = elements[i].code; +			break; +		} +	} +	if(pdata->curelt == PortMappingEntry) +	{ +		struct PortMapping * pm; +		pm = calloc(1, sizeof(struct PortMapping)); +		LIST_INSERT_HEAD( &(pdata->head), pm, entries); +	} +} + +/* End element handler */ +static void +endelt(void * d, const char * name, int l) +{ +	struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; +	pdata->curelt = PortMappingEltNone; +} + +/* Data handler */ +static void +data(void * d, const char * data, int l) +{ +	struct PortMapping * pm; +	struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; +	pm = pdata->head.lh_first; +	if(!pm) +		return; +	if(l > 63) +		l = 63; +	switch(pdata->curelt) +	{ +	case NewRemoteHost: +		memcpy(pm->remoteHost, data, l); +		pm->remoteHost[l] = '\0'; +		break; +	case NewExternalPort: +		pm->externalPort = (unsigned short)atoui(data, l); +		break; +	case NewProtocol: +		if(l > 3) +			l = 3; +		memcpy(pm->protocol, data, l); +		pm->protocol[l] = '\0'; +		break; +	case NewInternalPort: +		pm->internalPort = (unsigned short)atoui(data, l); +		break; +	case NewInternalClient: +		memcpy(pm->internalClient, data, l); +		pm->internalClient[l] = '\0'; +		break; +	case NewEnabled: +		pm->enabled = (unsigned char)atoui(data, l); +		break; +	case NewDescription: +		memcpy(pm->description, data, l); +		pm->description[l] = '\0'; +		break; +	case NewLeaseTime: +		pm->leaseTime = atoui(data, l); +		break; +	default: +		break; +	} +} + + +/* Parse the PortMappingList XML document for IGD version 2 + */ +void +ParsePortListing(const char * buffer, int bufsize, +                 struct PortMappingParserData * pdata) +{ +	struct xmlparser parser; + +	memset(pdata, 0, sizeof(struct PortMappingParserData)); +	LIST_INIT(&(pdata->head)); +	/* init xmlparser */ +	parser.xmlstart = buffer; +	parser.xmlsize = bufsize; +	parser.data = pdata; +	parser.starteltfunc = startelt; +	parser.endeltfunc = endelt; +	parser.datafunc = data; +	parser.attfunc = 0; +	parsexml(&parser); +} + +void +FreePortListing(struct PortMappingParserData * pdata) +{ +	struct PortMapping * pm; +	while((pm = pdata->head.lh_first) != NULL) +	{ +		LIST_REMOVE(pm, entries); +		free(pm); +	} +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h new file mode 100644 index 0000000..1852478 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h @@ -0,0 +1,71 @@ +/* $Id: portlistingparse.h,v 1.4 2011/02/15 23:03:56 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2011 Thomas Bernard  + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#ifndef __PORTLISTINGPARSE_H__ +#define __PORTLISTINGPARSE_H__ + +#include "declspec.h" +/* for the definition of UNSIGNED_INTEGER */ +#include "miniupnpctypes.h" + +#if defined(NO_SYS_QUEUE_H) || defined(WIN32) || defined(__HAIKU__)  +#include "bsdqueue.h" +#else +#include <sys/queue.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* sample of PortMappingEntry : +  <p:PortMappingEntry> +    <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost> +    <p:NewExternalPort>2345</p:NewExternalPort> +    <p:NewProtocol>TCP</p:NewProtocol> +    <p:NewInternalPort>2345</p:NewInternalPort> +    <p:NewInternalClient>192.168.1.137</p:NewInternalClient> +    <p:NewEnabled>1</p:NewEnabled> +    <p:NewDescription>dooom</p:NewDescription> +    <p:NewLeaseTime>345</p:NewLeaseTime> +  </p:PortMappingEntry> + */ +typedef enum { PortMappingEltNone, +       PortMappingEntry, NewRemoteHost, +       NewExternalPort, NewProtocol, +       NewInternalPort, NewInternalClient, +       NewEnabled, NewDescription,  +       NewLeaseTime } portMappingElt; + +struct PortMapping { +	LIST_ENTRY(PortMapping) entries; +	UNSIGNED_INTEGER leaseTime; +	unsigned short externalPort; +	unsigned short internalPort; +	char remoteHost[64]; +	char internalClient[64]; +	char description[64]; +	char protocol[4]; +	unsigned char enabled; +}; + +struct PortMappingParserData { +	LIST_HEAD(portmappinglisthead, PortMapping) head; +	portMappingElt curelt; +}; + +LIBSPEC void +ParsePortListing(const char * buffer, int bufsize, +                 struct PortMappingParserData * pdata); + +LIBSPEC void +FreePortListing(struct PortMappingParserData * pdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c new file mode 100644 index 0000000..a1eadfc --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c @@ -0,0 +1,81 @@ +/* $Id: receivedata.c,v 1.1 2011/04/11 08:21:47 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include <stdio.h> +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#else +#include <unistd.h> +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include <sys/select.h> +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include <sys/socket.h> +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include <poll.h> +#endif +#include <errno.h> +#define MINIUPNPC_IGNORE_EINTR +#endif + +#ifdef WIN32 +#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#include "receivedata.h" + +int +receivedata(int socket, char * data, int length, int timeout) +{ +    int n; +#if !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) +	/* using poll */ +    struct pollfd fds[1]; /* for the poll */ +#ifdef MINIUPNPC_IGNORE_EINTR +    do { +#endif +        fds[0].fd = socket; +        fds[0].events = POLLIN; +        n = poll(fds, 1, timeout); +#ifdef MINIUPNPC_IGNORE_EINTR +    } while(n < 0 && errno == EINTR); +#endif +    if(n < 0) { +        PRINT_SOCKET_ERROR("poll"); +        return -1; +    } else if(n == 0) { +		/* timeout */ +        return 0; +    } +#else /* !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ +	/* using select under WIN32 and amigaos */ +    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(FD_SETSIZE, &socketSet, NULL, NULL, &timeval); +    if(n < 0) { +        PRINT_SOCKET_ERROR("select"); +        return -1; +    } else if(n == 0) { +        return 0; +    }     +#endif +	n = recv(socket, data, length, 0); +	if(n<0) { +		PRINT_SOCKET_ERROR("recv"); +	} +	return n; +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h new file mode 100644 index 0000000..7a551b9 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h @@ -0,0 +1,17 @@ +/* $Id: receivedata.h,v 1.1 2011/04/11 08:21:47 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef __RECEIVEDATA_H__ +#define __RECEIVEDATA_H__ + +/* 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); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c new file mode 100644 index 0000000..b136d9d --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c @@ -0,0 +1,683 @@ +/* $Id: upnpc.c,v 1.88 2011/06/17 23:31:01 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2011 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 <time.h> +#ifdef WIN32 +#include <winsock2.h> +#define snprintf _snprintf +#endif +#include "miniwget.h" +#include "miniupnpc.h" +#include "upnpcommands.h" +#include "upnperrors.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 externalIPAddress[40]; +	char connectionType[64]; +	char status[64]; +	char lastconnerr[64]; +	unsigned int uptime; +	unsigned int brUp, brDown; +	time_t timenow, timestarted; +	int r; +	UPNP_GetConnectionTypeInfo(urls->controlURL, +	                           data->first.servicetype, +							   connectionType); +	if(connectionType[0]) +		printf("Connection Type : %s\n", connectionType); +	else +		printf("GetConnectionTypeInfo failed.\n"); +	UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, +	                   status, &uptime, lastconnerr); +	printf("Status : %s, uptime=%us, LastConnectionError : %s\n", +	       status, uptime, lastconnerr); +	timenow = time(NULL); +	timestarted = timenow - uptime; +	printf("  Time started : %s", ctime(×tarted)); +	UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, +			&brDown, &brUp); +	printf("MaxBitRateDown : %u bps", brDown); +	if(brDown >= 1000000) { +		printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10); +	} else if(brDown >= 1000) { +		printf(" (%u Kbps)", brDown / 1000); +	} +	printf("   MaxBitRateUp %u bps", brUp); +	if(brUp >= 1000000) { +		printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10); +	} else if(brUp >= 1000) { +		printf(" (%u Kbps)", brUp / 1000); +	} +	printf("\n"); +	r = UPNP_GetExternalIPAddress(urls->controlURL, +	                          data->first.servicetype, +							  externalIPAddress); +	if(r != UPNPCOMMAND_SUCCESS) +		printf("GetExternalIPAddress() returned %d\n", r); +	if(externalIPAddress[0]) +		printf("ExternalIPAddress = %s\n", externalIPAddress); +	else +		printf("GetExternalIPAddress failed.\n"); +} + +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->CIF.servicetype); +	bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); +	packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); +	packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); +	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[40]; +	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->first.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); +				   */ +			printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n", +			       i, protocol, extPort, intClient, intPort, +			       desc, rHost, duration); +		else +			printf("GetGenericPortMappingEntry() returned %d (%s)\n", +			       r, strupnperror(r)); +		i++; +	} while(r==0); +} + +static void NewListRedirections(struct UPNPUrls * urls, +                                struct IGDdatas * data) +{ +	int r; +	int i = 0; +	struct PortMappingParserData pdata; +	struct PortMapping * pm; + +	memset(&pdata, 0, sizeof(struct PortMappingParserData)); +	r = UPNP_GetListOfPortMappings(urls->controlURL, +                                   data->first.servicetype, +	                               "0", +	                               "65535", +	                               "TCP", +	                               "1000", +	                               &pdata); +	if(r == UPNPCOMMAND_SUCCESS) +	{ +		for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) +		{ +			printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", +			       i, pm->protocol, pm->externalPort, pm->internalClient, +			       pm->internalPort, +			       pm->description, pm->remoteHost, +			       (unsigned)pm->leaseTime); +			i++; +		} +		FreePortListing(&pdata); +	} +	else +	{ +		printf("GetListOfPortMappings() returned %d (%s)\n", +		       r, strupnperror(r)); +	} +	r = UPNP_GetListOfPortMappings(urls->controlURL, +                                   data->first.servicetype, +	                               "0", +	                               "65535", +	                               "UDP", +	                               "1000", +	                               &pdata); +	if(r == UPNPCOMMAND_SUCCESS) +	{ +		for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) +		{ +			printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", +			       i, pm->protocol, pm->externalPort, pm->internalClient, +			       pm->internalPort, +			       pm->description, pm->remoteHost, +			       (unsigned)pm->leaseTime); +			i++; +		} +		FreePortListing(&pdata); +	} +	else +	{ +		printf("GetListOfPortMappings() returned %d (%s)\n", +		       r, strupnperror(r)); +	} +} + +/* 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, +                               const char * leaseDuration) +{ +	char externalIPAddress[40]; +	char intClient[40]; +	char intPort[6]; +	char duration[16]; +	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->first.servicetype, +							  externalIPAddress); +	if(externalIPAddress[0]) +		printf("ExternalIPAddress = %s\n", externalIPAddress); +	else +		printf("GetExternalIPAddress failed.\n"); +	 +	r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, +	                        eport, iport, iaddr, 0, proto, 0, leaseDuration); +	if(r!=UPNPCOMMAND_SUCCESS) +		printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", +		       eport, iport, iaddr, r, strupnperror(r)); + +	r = UPNP_GetSpecificPortMappingEntry(urls->controlURL, +	                                 data->first.servicetype, +    	                             eport, proto, +									 intClient, intPort, NULL/*desc*/, +	                                 NULL/*enabled*/, duration); +	if(r!=UPNPCOMMAND_SUCCESS) +		printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n", +		       r, strupnperror(r)); +	 +	if(intClient[0]) { +		printf("InternalIP:Port = %s:%s\n", intClient, intPort); +		printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n", +		       externalIPAddress, eport, proto, intClient, intPort, duration); +	} +} + +static void +RemoveRedirect(struct UPNPUrls * urls, +               struct IGDdatas * data, +			   const char * eport, +			   const char * proto) +{ +	int r; +	if(!proto || !eport) +	{ +		fprintf(stderr, "invalid arguments\n"); +		return; +	} +	proto = protofix(proto); +	if(!proto) +	{ +		fprintf(stderr, "protocol invalid\n"); +		return; +	} +	r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, 0); +	printf("UPNP_DeletePortMapping() returned : %d\n", r); +} + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data) +{ +	unsigned int bytessent, bytesreceived, packetsreceived, packetssent; +	int firewallEnabled = 0, inboundPinholeAllowed = 0; + +	UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed); +	printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed); +	printf("GetFirewallStatus:\n   Firewall Enabled: %s\n   Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No"); +	 +	bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); +	bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); +	packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); +	packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); +	printf("Bytes:   Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); +	printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); +} + +/* Test function  + * 1 - Add pinhole + * 2 - Check if pinhole is working from the IGD side */ +static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, +					const char * remoteaddr, const char * eport, +					const char * intaddr, const char * iport, +					const char * proto, const char * lease_time) +{ +	char uniqueID[8]; +	//int isWorking = 0; +	int r; + +	if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time) +	{ +		fprintf(stderr, "Wrong arguments\n"); +		return; +	} +	/*proto = protofix(proto); +	if(!proto) +	{ +		fprintf(stderr, "invalid protocol\n"); +		return; +	}*/ +	r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID); +	if(r!=UPNPCOMMAND_SUCCESS) +		printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", +		       intaddr, iport, remoteaddr, eport, r, strupnperror(r)); +	else +	{ +		printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", intaddr, iport, remoteaddr, eport, uniqueID); +		/*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking); +		if(r!=UPNPCOMMAND_SUCCESS) +			printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); +		printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/ +	} +} + +/* Test function + * 1 - Check if pinhole is working from the IGD side + * 2 - Update pinhole */ +static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data, +					const char * uniqueID, const char * lease_time) +{ +	int isWorking = 0; +	int r; + +	if(!uniqueID || !lease_time) +	{ +		fprintf(stderr, "Wrong arguments\n"); +		return; +	} +	r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); +	printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); +	if(r!=UPNPCOMMAND_SUCCESS) +		printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); +	if(isWorking || r==709) +	{ +		r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time); +		printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time); +		if(r!=UPNPCOMMAND_SUCCESS) +			printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r)); +	} +} + +/* Test function  + * Get pinhole timeout + */ +static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data, +					const char * remoteaddr, const char * eport, +					const char * intaddr, const char * iport, +					const char * proto) +{ +	int timeout = 0; +	int r; + +	if(!intaddr || !remoteaddr || !iport || !eport || !proto) +	{ +		fprintf(stderr, "Wrong arguments\n"); +		return; +	} + +	r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout); +	if(r!=UPNPCOMMAND_SUCCESS) +		printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", +		       intaddr, iport, remoteaddr, eport, r, strupnperror(r)); +	else +		printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout); +} + +static void +GetPinholePackets(struct UPNPUrls * urls, +               struct IGDdatas * data, const char * uniqueID) +{ +	int r, pinholePackets = 0; +	if(!uniqueID) +	{ +		fprintf(stderr, "invalid arguments\n"); +		return; +	} +	r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets); +	if(r!=UPNPCOMMAND_SUCCESS) +		printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r)); +	else +		printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets); +} + +static void +CheckPinhole(struct UPNPUrls * urls, +               struct IGDdatas * data, const char * uniqueID) +{ +	int r, isWorking = 0; +	if(!uniqueID) +	{ +		fprintf(stderr, "invalid arguments\n"); +		return; +	} +	r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); +	if(r!=UPNPCOMMAND_SUCCESS) +		printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); +	else +		printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); +} + +static void +RemovePinhole(struct UPNPUrls * urls, +               struct IGDdatas * data, const char * uniqueID) +{ +	int r; +	if(!uniqueID) +	{ +		fprintf(stderr, "invalid arguments\n"); +		return; +	} +	r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID); +	printf("UPNP_DeletePinhole() returned : %d\n", r); +} + + +/* sample upnp client program */ +int main(int argc, char ** argv) +{ +	char command = 0; +	char ** commandargv = 0; +	int commandargc = 0; +	struct UPNPDev * devlist = 0; +	char lanaddr[64];	/* my ip address on the LAN */ +	int i; +	const char * rootdescurl = 0; +	const char * multicastif = 0; +	const char * minissdpdpath = 0; +	int retcode = 0; +	int error = 0; +	int ipv6 = 0; + +#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 : miniupnpc library test client. (c) 2006-2011 Thomas Bernard\n"); +    printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" +	       "for more information.\n"); +	/* command line processing */ +	for(i=1; i<argc; i++) +	{ +		if(argv[i][0] == '-') +		{ +			if(argv[i][1] == 'u') +				rootdescurl = argv[++i]; +			else if(argv[i][1] == 'm') +				multicastif = argv[++i]; +			else if(argv[i][1] == 'p') +				minissdpdpath = argv[++i]; +			else if(argv[i][1] == '6') +				ipv6 = 1; +			else +			{ +				command = argv[i][1]; +				i++; +				commandargv = argv + i; +				commandargc = argc - i; +				break; +			} +		} +		else +		{ +			fprintf(stderr, "option '%s' invalid\n", argv[i]); +		} +	} + +	if(!command || (command == 'a' && commandargc<4) +	   || (command == 'd' && argc<2) +	   || (command == 'r' && argc<2) +	   || (command == 'A' && commandargc<6) +	   || (command == 'U' && commandargc<2) +	   || (command == 'D' && commandargc<1)) +	{ +		fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -d external_port protocol [port2 protocol2] [...]\n\t\tDelete port redirection\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -s\n\t\tGet Connection status\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -l\n\t\tList redirections\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings, IGD v2)\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -r port1 protocol1 [port2 protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]); +		fprintf(stderr, "       \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]); +		fprintf(stderr, "\nprotocol is UDP or TCP\n"); +		fprintf(stderr, "Options:\n"); +		fprintf(stderr, "  -6 : use ip v6 instead of ip v4.\n"); +		fprintf(stderr, "  -u url : bypass discovery process by providing the XML root description url.\n"); +		fprintf(stderr, "  -m address/interface : provide ip address (ip v4) or interface name (ip v6) to use for sending SSDP multicast packets.\n"); +		fprintf(stderr, "  -p path : use this path for MiniSSDPd socket.\n"); +		return 1; +	} + +	if( rootdescurl +	  || (devlist = upnpDiscover(2000, multicastif, minissdpdpath, +	                             0/*sameport*/, ipv6, &error))) +	{ +		struct UPNPDev * device; +		struct UPNPUrls urls; +		struct IGDdatas data; +		if(devlist) +		{ +			printf("List of UPNP devices found on the network :\n"); +			for(device = devlist; device; device = device->pNext) +			{ +				printf(" desc: %s\n st: %s\n\n", +					   device->descURL, device->st); +			} +		} +		else +		{ +			printf("upnpDiscover() error code=%d\n", error); +		} +		i = 1; +		if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr))) +		  || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) +		{ +			switch(i) { +			case 1: +				printf("Found valid IGD : %s\n", urls.controlURL); +				break; +			case 2: +				printf("Found a (not connected?) IGD : %s\n", urls.controlURL); +				printf("Trying to continue anyway\n"); +				break; +			case 3: +				printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); +				printf("Trying to continue anyway\n"); +				break; +			default: +				printf("Found device (igd ?) : %s\n", urls.controlURL); +				printf("Trying to continue anyway\n"); +			} +			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 'L': +				NewListRedirections(&urls, &data); +				break; +			case 'a': +				SetRedirectAndTest(&urls, &data, +				                   commandargv[0], commandargv[1], +				                   commandargv[2], commandargv[3], +				                   (commandargc > 4)?commandargv[4]:"0"); +				break; +			case 'd': +				for(i=0; i<commandargc; i+=2) +				{ +					RemoveRedirect(&urls, &data, commandargv[i], commandargv[i+1]); +				} +				break; +			case 's': +				GetConnectionStatus(&urls, &data); +				break; +			case 'r': +				for(i=0; i<commandargc; i+=2) +				{ +					/*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/ +					SetRedirectAndTest(&urls, &data, +					                   lanaddr, commandargv[i], +									   commandargv[i], commandargv[i+1], "0"); +				} +				break; +			case 'A': +				SetPinholeAndTest(&urls, &data, +				                  commandargv[0], commandargv[1], +				                  commandargv[2], commandargv[3], +				                  commandargv[4], commandargv[5]); +				break; +			case 'U': +				GetPinholeAndUpdate(&urls, &data, +				                   commandargv[0], commandargv[1]); +				break; +			case 'C': +				for(i=0; i<commandargc; i++) +				{ +					CheckPinhole(&urls, &data, commandargv[i]); +				} +				break; +			case 'K': +				for(i=0; i<commandargc; i++) +				{ +					GetPinholePackets(&urls, &data, commandargv[i]); +				} +				break; +			case 'D': +				for(i=0; i<commandargc; i++) +				{ +					RemovePinhole(&urls, &data, commandargv[i]); +				} +				break; +			case 'S': +				GetFirewallStatus(&urls, &data); +				break; +			case 'G': +				GetPinholeOutboundTimeout(&urls, &data, +							commandargv[0], commandargv[1], +							commandargv[2], commandargv[3], +							commandargv[4]); +				break; +			case 'P': +				printf("Presentation URL found:\n"); +				printf("            %s\n", data.presentationurl); +				break; +			default: +				fprintf(stderr, "Unknown switch -%c\n", command); +				retcode = 1; +			} + +			FreeUPNPUrls(&urls); +		} +		else +		{ +			fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n"); +			retcode = 1; +		} +		freeUPNPDevlist(devlist); devlist = 0; +	} +	else +	{ +		fprintf(stderr, "No IGD UPnP Device found on the network !\n"); +		retcode = 1; +	} +	return retcode; +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c new file mode 100644 index 0000000..1114759 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c @@ -0,0 +1,1097 @@ +/* $Id: upnpcommands.c,v 1.37 2011/06/04 15:56:23 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2011 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" +#include "portlistingparse.h" + +static UNSIGNED_INTEGER +my_atoui(const char * s) +{ +	return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, +					const char * servicetype) +{ +	struct NameValueParserData pdata; +	char * buffer; +	int bufsize; +	unsigned int r = 0; +	char * p; +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetTotalBytesSent", 0, &bufsize))) { +		return UPNPCOMMAND_HTTP_ERROR; +	} +	ParseNameValue(buffer, bufsize, &pdata); +	/*DisplayNameValueList(buffer, bufsize);*/ +	free(buffer); buffer = NULL; +	p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); +	r = my_atoui(p); +	ClearNameValueList(&pdata); +	return r; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, +						const char * servicetype) +{ +	struct NameValueParserData pdata; +	char * buffer; +	int bufsize; +	unsigned int r = 0; +	char * p; +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetTotalBytesReceived", 0, &bufsize))) { +		return UPNPCOMMAND_HTTP_ERROR; +	} +	ParseNameValue(buffer, bufsize, &pdata); +	/*DisplayNameValueList(buffer, bufsize);*/ +	free(buffer); buffer = NULL; +	p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); +	r = my_atoui(p); +	ClearNameValueList(&pdata); +	return r; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, +						const char * servicetype) +{ +	struct NameValueParserData pdata; +	char * buffer; +	int bufsize; +	unsigned int r = 0; +	char * p; +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetTotalPacketsSent", 0, &bufsize))) { +		return UPNPCOMMAND_HTTP_ERROR; +	} +	ParseNameValue(buffer, bufsize, &pdata); +	/*DisplayNameValueList(buffer, bufsize);*/ +	free(buffer); buffer = NULL; +	p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); +	r = my_atoui(p); +	ClearNameValueList(&pdata); +	return r; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, +						const char * servicetype) +{ +	struct NameValueParserData pdata; +	char * buffer; +	int bufsize; +	unsigned int r = 0; +	char * p; +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetTotalPacketsReceived", 0, &bufsize))) { +		return UPNPCOMMAND_HTTP_ERROR; +	} +	ParseNameValue(buffer, bufsize, &pdata); +	/*DisplayNameValueList(buffer, bufsize);*/ +	free(buffer); buffer = NULL; +	p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); +	r = my_atoui(p); +	ClearNameValueList(&pdata); +	return r; +} + +/* UPNP_GetStatusInfo() call the corresponding UPNP method + * returns the current status and uptime */ +LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, +				const char * servicetype, +				char * status,  +				unsigned int * uptime, +				char * lastconnerror) +{ +	struct NameValueParserData pdata; +	char * buffer; +	int bufsize; +	char * p; +	char * up; +	char * err; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; + +	if(!status && !uptime) +		return UPNPCOMMAND_INVALID_ARGS; + +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetStatusInfo", 0, &bufsize))) { +		return UPNPCOMMAND_HTTP_ERROR; +	} +	ParseNameValue(buffer, bufsize, &pdata); +	/*DisplayNameValueList(buffer, bufsize);*/ +	free(buffer); buffer = NULL; +	up = GetValueFromNameValueList(&pdata, "NewUptime"); +	p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); +	err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); +	if(p && up) +	  ret = UPNPCOMMAND_SUCCESS; + +	if(status) { +		if(p){ +			strncpy(status, p, 64 ); +			status[63] = '\0'; +		}else +			status[0]= '\0'; +	} + +	if(uptime) { +		if(up) +			sscanf(up,"%u",uptime); +		else +			uptime = 0; +	} + +	if(lastconnerror) { +		if(err) { +			strncpy(lastconnerror, err, 64 ); +			lastconnerror[63] = '\0'; +		} else +			lastconnerror[0] = '\0'; +	} + +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) { +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} +	ClearNameValueList(&pdata); +	return ret; +} + +/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method + * returns the connection type */ +LIBSPEC int +UPNP_GetConnectionTypeInfo(const char * controlURL, +                           const char * servicetype, +                           char * connectionType) +{ +	struct NameValueParserData pdata; +	char * buffer; +	int bufsize; +	char * p; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; + +	if(!connectionType) +		return UPNPCOMMAND_INVALID_ARGS; + +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetConnectionTypeInfo", 0, &bufsize))) { +		return UPNPCOMMAND_HTTP_ERROR; +	} +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	p = GetValueFromNameValueList(&pdata, "NewConnectionType"); +	/*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ +	/* PossibleConnectionTypes will have several values.... */ +	if(p) { +		strncpy(connectionType, p, 64 ); +		connectionType[63] = '\0'; +		ret = UPNPCOMMAND_SUCCESS; +	} else +		connectionType[0] = '\0'; +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) { +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} +	ClearNameValueList(&pdata); +	return ret; +} + +/* 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 */ +LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char * controlURL, +                             const char * servicetype, +                             unsigned int * bitrateDown, +                             unsigned int * bitrateUp) +{ +	struct NameValueParserData pdata; +	char * buffer; +	int bufsize; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; +	char * down; +	char * up; +	char * p; + +	if(!bitrateDown && !bitrateUp) +		return UPNPCOMMAND_INVALID_ARGS; + +	/* shouldn't we use GetCommonLinkProperties ? */ +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetCommonLinkProperties", 0, &bufsize))) { +	                              /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ +		return UPNPCOMMAND_HTTP_ERROR; +	} +	/*DisplayNameValueList(buffer, bufsize);*/ +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	/*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ +	/*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ +	down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); +	up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate"); +	/*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/ +	/*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/ +	if(down && up) +		ret = UPNPCOMMAND_SUCCESS; + +	if(bitrateDown) { +		if(down) +			sscanf(down,"%u",bitrateDown); +		else +			*bitrateDown = 0; +	} + +	if(bitrateUp) { +		if(up) +			sscanf(up,"%u",bitrateUp); +		else +			*bitrateUp = 0; +	} +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) { +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} +	ClearNameValueList(&pdata); +	return ret; +} + + +/* 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 + *  + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR Either an UPnP error code or an unknown error. + * + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + */ +LIBSPEC int +UPNP_GetExternalIPAddress(const char * controlURL, +                          const char * servicetype, +                          char * extIpAdd) +{ +	struct NameValueParserData pdata; +	char * buffer; +	int bufsize; +	char * p; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; + +	if(!extIpAdd || !controlURL || !servicetype) +		return UPNPCOMMAND_INVALID_ARGS; + +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetExternalIPAddress", 0, &bufsize))) { +		return UPNPCOMMAND_HTTP_ERROR; +	} +	/*DisplayNameValueList(buffer, bufsize);*/ +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	/*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ +	p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); +	if(p) { +		strncpy(extIpAdd, p, 16 ); +		extIpAdd[15] = '\0'; +		ret = UPNPCOMMAND_SUCCESS; +	} else +		extIpAdd[0] = '\0'; + +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) { +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} + +	ClearNameValueList(&pdata); +	return ret; +} + +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, +                    const char * remoteHost, +                    const char * leaseDuration) +{ +	struct UPNParg * AddPortMappingArgs; +	char * buffer; +	int bufsize; +	struct NameValueParserData pdata; +	const char * resVal; +	int ret; + +	if(!inPort || !inClient || !proto || !extPort) +		return UPNPCOMMAND_INVALID_ARGS; + +	AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); +	AddPortMappingArgs[0].elt = "NewRemoteHost"; +	AddPortMappingArgs[0].val = remoteHost; +	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 = leaseDuration?leaseDuration:"0"; +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "AddPortMapping", AddPortMappingArgs, +	                                &bufsize))) { +		free(AddPortMappingArgs); +		return UPNPCOMMAND_HTTP_ERROR; +	} +	/*DisplayNameValueList(buffer, bufsize);*/ +	/*buffer[bufsize] = '\0';*/ +	/*puts(buffer);*/ +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	resVal = GetValueFromNameValueList(&pdata, "errorCode"); +	if(resVal) { +		/*printf("AddPortMapping errorCode = '%s'\n", resVal); */ +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(resVal, "%d", &ret); +	} else { +		ret = UPNPCOMMAND_SUCCESS; +	} +	ClearNameValueList(&pdata); +	free(AddPortMappingArgs); +	return ret; +} + +LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, +                       const char * extPort, const char * proto, +                       const char * remoteHost) +{ +	/*struct NameValueParserData pdata;*/ +	struct UPNParg * DeletePortMappingArgs; +	char * buffer; +	int bufsize; +	struct NameValueParserData pdata; +	const char * resVal; +	int ret; + +	if(!extPort || !proto) +		return UPNPCOMMAND_INVALID_ARGS; + +	DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); +	DeletePortMappingArgs[0].elt = "NewRemoteHost"; +	DeletePortMappingArgs[0].val = remoteHost; +	DeletePortMappingArgs[1].elt = "NewExternalPort"; +	DeletePortMappingArgs[1].val = extPort; +	DeletePortMappingArgs[2].elt = "NewProtocol"; +	DeletePortMappingArgs[2].val = proto; +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                               "DeletePortMapping", +	                               DeletePortMappingArgs, &bufsize))) { +		free(DeletePortMappingArgs); +		return UPNPCOMMAND_HTTP_ERROR; +	} +	/*DisplayNameValueList(buffer, bufsize);*/ +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	resVal = GetValueFromNameValueList(&pdata, "errorCode"); +	if(resVal) { +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(resVal, "%d", &ret); +	} else { +		ret = UPNPCOMMAND_SUCCESS; +	} +	ClearNameValueList(&pdata); +	free(DeletePortMappingArgs); +	return ret; +} + +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) +{ +	struct NameValueParserData pdata; +	struct UPNParg * GetPortMappingArgs; +	char * buffer; +	int bufsize; +	char * p; +	int r = UPNPCOMMAND_UNKNOWN_ERROR; +	if(!index) +		return UPNPCOMMAND_INVALID_ARGS; +	intClient[0] = '\0'; +	intPort[0] = '\0'; +	GetPortMappingArgs = calloc(2, sizeof(struct UPNParg)); +	GetPortMappingArgs[0].elt = "NewPortMappingIndex"; +	GetPortMappingArgs[0].val = index; +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                               "GetGenericPortMappingEntry", +	                               GetPortMappingArgs, &bufsize))) { +		free(GetPortMappingArgs); +		return UPNPCOMMAND_HTTP_ERROR; +	} +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; + +	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 = UPNPCOMMAND_SUCCESS; +	} +	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'; +	} +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) { +		r = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &r); +	} +	ClearNameValueList(&pdata); +	free(GetPortMappingArgs); +	return r; +} + +LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char * controlURL, +                                   const char * servicetype, +                                   unsigned int * numEntries) +{ + 	struct NameValueParserData pdata; + 	char * buffer; + 	int bufsize; + 	char* p; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; + 	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetPortMappingNumberOfEntries", 0, +	                                &bufsize))) { +		return UPNPCOMMAND_HTTP_ERROR; +	} +#ifdef DEBUG +	DisplayNameValueList(buffer, bufsize); +#endif + 	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; + + 	p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); + 	if(numEntries && p) { +		*numEntries = 0; + 		sscanf(p, "%u", numEntries); +		ret = UPNPCOMMAND_SUCCESS; + 	} + +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) { +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} + + 	ClearNameValueList(&pdata); +	return ret; +} + +/* 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 int +UPNP_GetSpecificPortMappingEntry(const char * controlURL, +                                 const char * servicetype, +                                 const char * extPort, +							     const char * proto, +                                 char * intClient, +                                 char * intPort, +                                 char * desc, +                                 char * enabled, +                                 char * leaseDuration) +{ +	struct NameValueParserData pdata; +	struct UPNParg * GetPortMappingArgs; +	char * buffer; +	int bufsize; +	char * p; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; + +	if(!intPort || !intClient || !extPort || !proto) +		return UPNPCOMMAND_INVALID_ARGS; + +	GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); +	GetPortMappingArgs[0].elt = "NewRemoteHost"; +	/* TODO : add remote host ? */ +	GetPortMappingArgs[1].elt = "NewExternalPort"; +	GetPortMappingArgs[1].val = extPort; +	GetPortMappingArgs[2].elt = "NewProtocol"; +	GetPortMappingArgs[2].val = proto; +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetSpecificPortMappingEntry", +	                                GetPortMappingArgs, &bufsize))) { +		free(GetPortMappingArgs); +		return UPNPCOMMAND_HTTP_ERROR; +	} +	/*DisplayNameValueList(buffer, bufsize);*/ +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; + +	p = GetValueFromNameValueList(&pdata, "NewInternalClient"); +	if(p) { +		strncpy(intClient, p, 16); +		intClient[15] = '\0'; +		ret = UPNPCOMMAND_SUCCESS; +	} else +		intClient[0] = '\0'; + +	p = GetValueFromNameValueList(&pdata, "NewInternalPort"); +	if(p) { +		strncpy(intPort, p, 6); +		intPort[5] = '\0'; +	} else +		intPort[0] = '\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 && leaseDuration) +	{ +		strncpy(leaseDuration, p, 16); +		leaseDuration[15] = '\0'; +	} + +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) { +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} + +	ClearNameValueList(&pdata); +	free(GetPortMappingArgs); +	return ret; +} + +/* UPNP_GetListOfPortMappings() + * + * Possible UPNP Error codes : + * 606 Action not Authorized + * 730 PortMappingNotFound - no port mapping is found in the specified range. + * 733 InconsistantParameters - NewStartPort and NewEndPort values are not + *                              consistent. + */ +LIBSPEC int +UPNP_GetListOfPortMappings(const char * controlURL, +                           const char * servicetype, +                           const char * startPort, +                           const char * endPort, +                           const char * protocol, +                           const char * numberOfPorts, +                           struct PortMappingParserData * data) +{ +	struct NameValueParserData pdata; +	struct UPNParg * GetListOfPortMappingsArgs; +	const char * p; +	char * buffer; +	int bufsize; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; + +	if(!startPort || !endPort || !protocol) +		return UPNPCOMMAND_INVALID_ARGS; + +	GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); +	GetListOfPortMappingsArgs[0].elt = "NewStartPort"; +	GetListOfPortMappingsArgs[0].val = startPort; +	GetListOfPortMappingsArgs[1].elt = "NewEndPort"; +	GetListOfPortMappingsArgs[1].val = endPort; +	GetListOfPortMappingsArgs[2].elt = "NewProtocol"; +	GetListOfPortMappingsArgs[2].val = protocol; +	GetListOfPortMappingsArgs[3].elt = "NewManage"; +	GetListOfPortMappingsArgs[3].val = "1"; +	GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts"; +	GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000"; + +	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                                "GetListOfPortMappings", +	                                GetListOfPortMappingsArgs, &bufsize))) { +		free(GetListOfPortMappingsArgs); +		return UPNPCOMMAND_HTTP_ERROR; +	} +	free(GetListOfPortMappingsArgs); + +	/*DisplayNameValueList(buffer, bufsize);*/ +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; + +	/*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ +	/*if(p) { +		printf("NewPortListing : %s\n", p); +	}*/ +	/*printf("NewPortListing(%d chars) : %s\n", +	       pdata.portListingLength, pdata.portListing);*/ +	if(pdata.portListing) +	{ +		/*struct PortMapping * pm; +		int i = 0;*/ +		ParsePortListing(pdata.portListing, pdata.portListingLength, +		                 data); +		ret = UPNPCOMMAND_SUCCESS; +		/* +		for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next) +		{ +			printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n", +			       i, pm->protocol, pm->externalPort, pm->internalClient, +			       pm->internalPort, +			       pm->description, pm->remoteHost); +			i++; +		} +		*/ +		/*FreePortListing(&data);*/ +	} + +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) { +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} +	ClearNameValueList(&pdata); + +	//printf("%.*s", bufsize, buffer); + +	return ret; +} + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */  +LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, +				const char * servicetype, +				int * firewallEnabled,  +				int * inboundPinholeAllowed) +{ +	struct NameValueParserData pdata; +	char * buffer; +	int bufsize; +	char * fe, *ipa, *p; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; + +	if(!firewallEnabled && !inboundPinholeAllowed) +		return UPNPCOMMAND_INVALID_ARGS; + +	buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                           "GetFirewallStatus", 0, &bufsize); +	if(!buffer) { +		return UPNPCOMMAND_HTTP_ERROR; +	} +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); +	ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); +	if(ipa && fe) +		ret = UPNPCOMMAND_SUCCESS; +	if(fe) +		*firewallEnabled = my_atoui(fe); +	/*else +		*firewallEnabled = 0;*/ +	if(ipa) +		*inboundPinholeAllowed = my_atoui(ipa); +	/*else +		*inboundPinholeAllowed = 0;*/ +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) +	{ +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} +	ClearNameValueList(&pdata); +	return ret; +} + +LIBSPEC int +UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, +                    const char * remoteHost, +                    const char * remotePort, +                    const char * intClient, +                    const char * intPort, +                    const char * proto, +                    int * opTimeout) +{ +	struct UPNParg * GetOutboundPinholeTimeoutArgs; +	char * buffer; +	int bufsize; +	struct NameValueParserData pdata; +	const char * resVal; +	char * p; +	int ret; + +	if(!intPort || !intClient || !proto || !remotePort || !remoteHost) +		return UPNPCOMMAND_INVALID_ARGS; + +	GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); +	GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost"; +	GetOutboundPinholeTimeoutArgs[0].val = remoteHost; +	GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort"; +	GetOutboundPinholeTimeoutArgs[1].val = remotePort; +	GetOutboundPinholeTimeoutArgs[2].elt = "Protocol"; +	GetOutboundPinholeTimeoutArgs[2].val = proto; +	GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort"; +	GetOutboundPinholeTimeoutArgs[3].val = intPort; +	GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient"; +	GetOutboundPinholeTimeoutArgs[4].val = intClient; +	buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                           "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); +	if(!buffer) +		return UPNPCOMMAND_HTTP_ERROR; +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	resVal = GetValueFromNameValueList(&pdata, "errorCode"); +	if(resVal) +	{ +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(resVal, "%d", &ret); +	} +	else +	{ +		ret = UPNPCOMMAND_SUCCESS; +		p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); +		if(p) +			*opTimeout = my_atoui(p); +	} +	ClearNameValueList(&pdata); +	free(GetOutboundPinholeTimeoutArgs); +	return ret; +} + +LIBSPEC int +UPNP_AddPinhole(const char * controlURL, const char * servicetype, +                    const char * remoteHost, +                    const char * remotePort, +                    const char * intClient, +                    const char * intPort, +                    const char * proto, +                    const char * leaseTime, +                    char * uniqueID) +{ +	struct UPNParg * AddPinholeArgs; +	char * buffer; +	int bufsize; +	struct NameValueParserData pdata; +	const char * resVal; +	char * p; +	int ret; + +	if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) +		return UPNPCOMMAND_INVALID_ARGS; + +	AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); +	// RemoteHost can be wilcarded +	if(strncmp(remoteHost, "empty", 5)==0) +	{ +		AddPinholeArgs[0].elt = "RemoteHost"; +		AddPinholeArgs[0].val = ""; +	} +	else +	{ +		AddPinholeArgs[0].elt = "RemoteHost"; +		AddPinholeArgs[0].val = remoteHost; +	} +	AddPinholeArgs[1].elt = "RemotePort"; +	AddPinholeArgs[1].val = remotePort; +	AddPinholeArgs[2].elt = "Protocol"; +	AddPinholeArgs[2].val = proto; +	AddPinholeArgs[3].elt = "InternalPort"; +	AddPinholeArgs[3].val = intPort; +	if(strncmp(intClient, "empty", 5)==0) +	{ +		AddPinholeArgs[4].elt = "InternalClient"; +		AddPinholeArgs[4].val = ""; +	} +	else +	{ +		AddPinholeArgs[4].elt = "InternalClient"; +		AddPinholeArgs[4].val = intClient; +	} +	AddPinholeArgs[5].elt = "LeaseTime"; +	AddPinholeArgs[5].val = leaseTime; +	buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                           "AddPinhole", AddPinholeArgs, &bufsize); +	if(!buffer) +		return UPNPCOMMAND_HTTP_ERROR; +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	p = GetValueFromNameValueList(&pdata, "UniqueID"); +	if(p) +	{ +		strncpy(uniqueID, p, 8); +		uniqueID[7] = '\0'; +	} +	resVal = GetValueFromNameValueList(&pdata, "errorCode"); +	if(resVal) +	{ +		//printf("AddPortMapping errorCode = '%s'\n", resVal);  +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(resVal, "%d", &ret); +	} +	else +	{ +		ret = UPNPCOMMAND_SUCCESS; +	} +	ClearNameValueList(&pdata); +	free(AddPinholeArgs); +	return ret; +} + +LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, +                    const char * uniqueID, +                    const char * leaseTime) +{ +	struct UPNParg * UpdatePinholeArgs; +	char * buffer; +	int bufsize; +	struct NameValueParserData pdata; +	const char * resVal; +	int ret; + +	if(!uniqueID || !leaseTime) +		return UPNPCOMMAND_INVALID_ARGS; + +	UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); +	UpdatePinholeArgs[0].elt = "UniqueID"; +	UpdatePinholeArgs[0].val = uniqueID; +	UpdatePinholeArgs[1].elt = "NewLeaseTime"; +	UpdatePinholeArgs[1].val = leaseTime; +	buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                           "UpdatePinhole", UpdatePinholeArgs, &bufsize); +	if(!buffer) +		return UPNPCOMMAND_HTTP_ERROR; +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	resVal = GetValueFromNameValueList(&pdata, "errorCode"); +	if(resVal) +	{ +		/*printf("AddPortMapping errorCode = '%s'\n", resVal); */ +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(resVal, "%d", &ret); +	} +	else +	{ +		ret = UPNPCOMMAND_SUCCESS; +	} +	ClearNameValueList(&pdata); +	free(UpdatePinholeArgs); +	return ret; +} + +LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) +{ +	/*struct NameValueParserData pdata;*/ +	struct UPNParg * DeletePinholeArgs; +	char * buffer; +	int bufsize; +	struct NameValueParserData pdata; +	const char * resVal; +	int ret; + +	if(!uniqueID) +		return UPNPCOMMAND_INVALID_ARGS; + +	DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); +	DeletePinholeArgs[0].elt = "UniqueID"; +	DeletePinholeArgs[0].val = uniqueID; +	buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                           "DeletePinhole", DeletePinholeArgs, &bufsize); +	if(!buffer) +		return UPNPCOMMAND_HTTP_ERROR; +	/*DisplayNameValueList(buffer, bufsize);*/ +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; +	resVal = GetValueFromNameValueList(&pdata, "errorCode"); +	if(resVal) +	{ +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(resVal, "%d", &ret); +	} +	else +	{ +		ret = UPNPCOMMAND_SUCCESS; +	} +	ClearNameValueList(&pdata); +	free(DeletePinholeArgs); +	return ret; +} + +LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, +                                 const char * uniqueID, int * isWorking) +{ +	struct NameValueParserData pdata; +	struct UPNParg * CheckPinholeWorkingArgs; +	char * buffer; +	int bufsize; +	char * p; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; + +	if(!uniqueID) +		return UPNPCOMMAND_INVALID_ARGS; + +	CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); +	CheckPinholeWorkingArgs[0].elt = "UniqueID"; +	CheckPinholeWorkingArgs[0].val = uniqueID; +	buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                           "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); +	if(!buffer) +		return UPNPCOMMAND_HTTP_ERROR; +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; + +	p = GetValueFromNameValueList(&pdata, "IsWorking"); +	if(p) +	{ +		*isWorking=my_atoui(p); +		ret = UPNPCOMMAND_SUCCESS; +	} +	else +		*isWorking = 0; + +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) +	{ +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} + +	ClearNameValueList(&pdata); +	free(CheckPinholeWorkingArgs); +	return ret; +} + +LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, +                                 const char * uniqueID, int * packets) +{ +	struct NameValueParserData pdata; +	struct UPNParg * GetPinholePacketsArgs; +	char * buffer; +	int bufsize; +	char * p; +	int ret = UPNPCOMMAND_UNKNOWN_ERROR; + +	if(!uniqueID) +		return UPNPCOMMAND_INVALID_ARGS; + +	GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); +	GetPinholePacketsArgs[0].elt = "UniqueID"; +	GetPinholePacketsArgs[0].val = uniqueID; +	buffer = simpleUPnPcommand(-1, controlURL, servicetype, +	                           "GetPinholePackets", GetPinholePacketsArgs, &bufsize); +	if(!buffer) +		return UPNPCOMMAND_HTTP_ERROR; +	ParseNameValue(buffer, bufsize, &pdata); +	free(buffer); buffer = NULL; + +	p = GetValueFromNameValueList(&pdata, "PinholePackets"); +	if(p) +	{ +		*packets=my_atoui(p); +		ret = UPNPCOMMAND_SUCCESS; +	} + +	p = GetValueFromNameValueList(&pdata, "errorCode"); +	if(p) +	{ +		ret = UPNPCOMMAND_UNKNOWN_ERROR; +		sscanf(p, "%d", &ret); +	} + +	ClearNameValueList(&pdata); +	free(GetPinholePacketsArgs); +	return ret; +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h new file mode 100644 index 0000000..66d95e0 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h @@ -0,0 +1,271 @@ +/* $Id: upnpcommands.h,v 1.23 2011/04/11 09:14:00 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2011 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 "portlistingparse.h" +#include "declspec.h" +#include "miniupnpctypes.h" + +/* MiniUPnPc return codes : */ +#define UPNPCOMMAND_SUCCESS (0) +#define UPNPCOMMAND_UNKNOWN_ERROR (-1) +#define UPNPCOMMAND_INVALID_ARGS (-2) +#define UPNPCOMMAND_HTTP_ERROR (-3) + +#ifdef __cplusplus +extern "C" { +#endif + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, +					const char * servicetype); + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, +						const char * servicetype); + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, +					const char * servicetype); + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, +					const char * servicetype); + +/* UPNP_GetStatusInfo() + * status and lastconnerror are 64 byte buffers + * Return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, +			       const char * servicetype, +				   char * status, +				   unsigned int * uptime, +                   char * lastconnerror); + +/* UPNP_GetConnectionTypeInfo() + * argument connectionType is a 64 character buffer + * Return Values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +LIBSPEC int +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  + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR Either an UPnP error code or an unknown error. + *  + * possible UPnP Errors : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. */ +LIBSPEC int +UPNP_GetExternalIPAddress(const char * controlURL, +                          const char * servicetype, +                          char * extIpAdd); + +/* UPNP_GetLinkLayerMaxBitRates() + * call WANCommonInterfaceConfig:1#GetCommonLinkProperties + * + * return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. */ +LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char* controlURL, +							const char* servicetype, +							unsigned int * bitrateDown, +							unsigned int * bitrateUp); + +/* UPNP_AddPortMapping() + * if desc is NULL, it will be defaulted to "libminiupnpc" + * remoteHost is usually NULL because IGD don't support it. + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR. Either an UPnP error code or an unknown error. + *  + * List of possible UPnP errors for AddPortMapping : + * errorCode errorDescription (short) - Description (long) + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be + *                                   wild-carded + * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded + * 718 ConflictInMappingEntry - The port mapping entry specified conflicts + *                     with a mapping assigned previously to another client + * 724 SamePortValuesRequired - Internal and External port values + *                              must be the same  + * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports + *                  permanent lease times on port mappings + * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard + *                             and cannot be a specific IP address or DNS name + * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and + *                                        cannot be a specific port value */ +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, +                    const char * remoteHost, +                    const char * leaseDuration); + +/* UPNP_DeletePortMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 714 NoSuchEntryInArray - The specified value does not exist in the array */ +LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, +                       const char * extPort, const char * proto, +                       const char * remoteHost); + +/* UPNP_GetPortMappingNumberOfEntries() + * not supported by all routers */ +LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char* controlURL, +                                   const char* servicetype, +                                   unsigned int * num); + +/* UPNP_GetSpecificPortMappingEntry() + *    retrieves an existing port mapping + * params : + *  in   extPort + *  in   proto + *  out  intClient (16 bytes) + *  out  intPort (6 bytes) + *  out  desc (80 bytes) + *  out  enabled (4 bytes) + *  out  leaseDuration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. */ +LIBSPEC int +UPNP_GetSpecificPortMappingEntry(const char * controlURL, +                                 const char * servicetype, +                                 const char * extPort, +                                 const char * proto, +                                 char * intClient, +                                 char * intPort, +                                 char * desc, +                                 char * enabled, +                                 char * leaseDuration); + +/* UPNP_GetGenericPortMappingEntry() + * params : + *  in   index + *  out  extPort (6 bytes) + *  out  intClient (16 bytes) + *  out  intPort (6 bytes) + *  out  protocol (4 bytes) + *  out  desc (80 bytes) + *  out  enabled (4 bytes) + *  out  rHost (64 bytes) + *  out  duration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * Possible UPNP Error codes : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds + */ +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); + +/* UPNP_GetListOfPortMappings()      Available in IGD v2 + * + * + * Possible UPNP Error codes : + * 606 Action not Authorized + * 730 PortMappingNotFound - no port mapping is found in the specified range. + * 733 InconsistantParameters - NewStartPort and NewEndPort values are not + *                              consistent. + */ +LIBSPEC int +UPNP_GetListOfPortMappings(const char * controlURL, +                           const char * servicetype, +                           const char * startPort, +                           const char * endPort, +                           const char * protocol, +                           const char * numberOfPorts, +                           struct PortMappingParserData * data); + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */  +LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, +				const char * servicetype, +				int * firewallEnabled,  +				int * inboundPinholeAllowed); + +LIBSPEC int +UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, +                    const char * remoteHost, +                    const char * remotePort, +                    const char * intClient, +                    const char * intPort, +                    const char * proto, +                    int * opTimeout); + +LIBSPEC int +UPNP_AddPinhole(const char * controlURL, const char * servicetype, +                    const char * remoteHost, +                    const char * remotePort, +                    const char * intClient, +                    const char * intPort, +                    const char * proto, +                    const char * leaseTime, +                    char * uniqueID); + +LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, +                    const char * uniqueID, +                    const char * leaseTime); + +LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); + +LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, +                                 const char * uniqueID, int * isWorking); + +LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, +                                 const char * uniqueID, int * packets); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c new file mode 100644 index 0000000..a48ae10 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c @@ -0,0 +1,103 @@ +/* $Id: upnperrors.c,v 1.5 2011/04/10 11:19:36 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2007 Thomas Bernard + * All Right reserved. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#include <string.h> +#include "upnperrors.h" +#include "upnpcommands.h" +#include "miniupnpc.h" + +const char * strupnperror(int err) +{ +	const char * s = NULL; +	switch(err) { +	case UPNPCOMMAND_SUCCESS: +		s = "Success"; +		break; +	case UPNPCOMMAND_UNKNOWN_ERROR: +		s = "Miniupnpc Unknown Error"; +		break; +	case UPNPCOMMAND_INVALID_ARGS: +		s = "Miniupnpc Invalid Arguments"; +		break; +	case UPNPDISCOVER_SOCKET_ERROR: +		s = "Miniupnpc Socket error"; +		break; +	case UPNPDISCOVER_MEMORY_ERROR: +		s = "Miniupnpc Memory allocation error"; +		break; +	case 401: +		s = "Invalid Action"; +		break; +	case 402: +		s = "Invalid Args"; +		break; +	case 501: +		s = "Action Failed"; +		break; +	case 606: +		s = "Action not authorized"; +		break; +	case 701: +		s = "PinholeSpaceExhausted"; +		break; +	case 702: +		s = "FirewallDisabled"; +		break; +	case 703: +		s = "InboundPinholeNotAllowed"; +		break; +	case 704: +		s = "NoSuchEntry"; +		break; +	case 705: +		s = "ProtocolNotSupported"; +		break; +	case 706: +		s = "InternalPortWildcardingNotAllowed"; +		break; +	case 707: +		s = "ProtocolWildcardingNotAllowed"; +		break; +	case 708: +		s = "WildcardNotPermittedInSrcIP"; +		break; +	case 709: +		s = "NoPacketSent"; +		break; +	case 713: +		s = "SpecifiedArrayIndexInvalid"; +		break; +	case 714: +		s = "NoSuchEntryInArray"; +		break; +	case 715: +		s = "WildCardNotPermittedInSrcIP"; +		break; +	case 716: +		s = "WildCardNotPermittedInExtPort"; +		break; +	case 718: +		s = "ConflictInMappingEntry"; +		break; +	case 724: +		s = "SamePortValuesRequired"; +		break; +	case 725: +		s = "OnlyPermanentLeasesSupported"; +		break; +	case 726: +		s = "RemoteHostOnlySupportsWildcard"; +		break; +	case 727: +		s = "ExternalPortOnlySupportsWildcard"; +		break; +	default: +		s = NULL; +	} +	return s; +} diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h new file mode 100644 index 0000000..2c544c9 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h @@ -0,0 +1,26 @@ +/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */ +/* (c) 2007 Thomas Bernard + * All rights reserved. + * MiniUPnP Project. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef __UPNPERRORS_H__ +#define __UPNPERRORS_H__ + +#include "declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* strupnperror() + * Return a string description of the UPnP error code  + * or NULL for undefinded errors */ +LIBSPEC const char * strupnperror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c new file mode 100644 index 0000000..482030b --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c @@ -0,0 +1,152 @@ +/* $Id: upnpreplyparse.c,v 1.11 2011/02/07 16:17:06 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2011 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; +	if(strcmp(data->curelt, "NewPortListing") == 0) +	{ +		/* specific case for NewPortListing which is a XML Document */ +		data->portListing = malloc(l + 1); +		if(!data->portListing) +		{ +			/* malloc error */ +			return; +		} +		memcpy(data->portListing, datas, l); +		data->portListing[l] = '\0'; +		data->portListingLength = l; +	} +	else +	{ +		/* standard case. Limited to 63 chars strings */ +	    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)); +	data->portListing = NULL; +	data->portListingLength = 0; +    /* 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; +	if(pdata->portListing) +	{ +		free(pdata->portListing); +		pdata->portListing = NULL; +		pdata->portListingLength = 0; +	} +    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; +} + +#if 0 +/* useless now that minixml ignores namespaces by itself */ +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; +} +#endif + +/* debug all-in-one function  + * do parsing then display to stdout */ +#ifdef DEBUG +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); +} +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h new file mode 100644 index 0000000..267ea87 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h @@ -0,0 +1,64 @@ +/* $Id: upnpreplyparse.h,v 1.11 2011/02/07 16:17:06 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2011 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(NO_SYS_QUEUE_H) || defined(WIN32) || defined(__HAIKU__)  +#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]; +	char * portListing; +	int portListingLength; +}; + +/* 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() */ +#ifdef DEBUG +void +DisplayNameValueList(char * buffer, int bufsize); +#endif + +#ifdef __cplusplus +} +#endif + +#endif +  | 
 Swift