summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '3rdParty/LibMiniUPnPc/src/miniupnpc')
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE27
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h531
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h24
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c241
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h17
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h15
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c125
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h48
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c121
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h15
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c138
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h15
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c906
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h121
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h19
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c522
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h30
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c216
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h37
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c156
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c157
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h71
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c81
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h17
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c683
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c1097
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h271
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c103
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h26
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c152
-rw-r--r--3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h64
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(&timestarted));
+ 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
+