Externals: Update miniupnpc to API version 14

This commit is contained in:
Jeffrey Pfau 2015-10-13 20:21:28 -07:00
parent b0bbe52cc9
commit efb7272396
41 changed files with 2009 additions and 2189 deletions

View File

@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 2.6)
project(miniupnpc C)
set(MINIUPNPC_VERSION 1.7)
set(MINIUPNPC_API_VERSION 9)
set(MINIUPNPC_VERSION 1.9)
set(MINIUPNPC_API_VERSION 14)
if(UNIX)
add_definitions(-DMINIUPNPC_SET_SOCKET_TIMEOUT)
@ -24,9 +24,10 @@ set(SRCS src/igd_desc_parse.c
src/miniupnpc.c
src/minixml.c
src/minisoap.c
src/minissdpc.c
src/miniwget.c
src/upnpc.c
src/upnpcommands.c
src/upnpdev.c
src/upnpreplyparse.c
src/upnperrors.c
src/connecthostport.c

View File

@ -1,6 +1,104 @@
$Id: Changelog.txt,v 1.185 2013/05/03 09:05:38 nanard Exp $
$Id: Changelog.txt,v 1.215 2015/10/01 09:26:11 nanard Exp $
miniUPnP client Changelog.
2015/09/15:
Fix buffer overflow in igd_desc_parse.c/IGDstartelt()
Discovered by Aleksandar Nikolic of Cisco Talos
2015/08/28:
move ssdpDiscoverDevices() to minissdpc.c
2015/08/27:
avoid unix socket leak in getDevicesFromMiniSSDPD()
2015/08/16:
Also accept "Up" as ConnectionStatus value
2015/07/23:
split getDevicesFromMiniSSDPD
add ttl argument to upnpDiscover() functions
increments API_VERSION to 14
2015/07/22:
Read USN from SSDP messages.
2015/07/15:
Check malloc/calloc
2015/06/16:
update getDevicesFromMiniSSDPD() to process longer minissdpd
responses
2015/05/22:
add searchalltypes param to upnpDiscoverDevices()
increments API_VERSION to 13
2015/04/30:
upnpc: output version on the terminal
2015/04/27:
_BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE
fix CMakeLists.txt COMPILE_DEFINITIONS
fix getDevicesFromMiniSSDPD() not setting scope_id
improve -r command of upnpc command line tool
2014/11/17:
search all :
upnpDiscoverDevices() / upnpDiscoverAll() functions
listdevices executable
increment API_VERSION to 12
validate igd_desc_parse
2014/11/13:
increment API_VERSION to 11
2014/11/05:
simplified function GetUPNPUrls()
2014/09/11:
use remoteHost arg of DeletePortMapping
2014/09/06:
Fix python3 build
2014/07/01:
Fix parsing of IGD2 root descriptions
2014/06/10:
rename LIBSPEC to MINIUPNP_LIBSPEC
2014/05/15:
Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange
2014/02/05:
handle EINPROGRESS after connect()
2014/02/03:
minixml now handle XML comments
VERSION 1.9 : released 2014/01/31
2014/01/31:
added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
increment API_VERSION to 10
2013/12/09:
--help and -h arguments in upnpc.c
2013/10/07:
fixed potential buffer overrun in miniwget.c
Modified UPNP_GetValidIGD() to check for ExternalIpAddress
2013/08/01:
define MAXHOSTNAMELEN if not already done
2013/06/06:
update upnpreplyparse to allow larger values (128 chars instead of 64)
2013/05/14:
Update upnpreplyparse to take into account "empty" elements
validate upnpreplyparse.c code with "make check"
2013/05/03:
Fix Solaris build thanks to Maciej Małecki

View File

@ -1,5 +1,5 @@
MiniUPnPc
Copyright (c) 2005-2011, Thomas BERNARD
Copyright (c) 2005-2015, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1 +1 @@
1.8
1.9

View File

@ -1,7 +1,47 @@
$Id: apiversions.txt,v 1.2 2013/03/29 14:45:09 nanard Exp $
$Id: apiversions.txt,v 1.7 2015/07/23 20:40:08 nanard Exp $
Differences in API between miniUPnPc versions
API version 14
miniupnpc.h
add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice()
upnpDiscoverDevices()
getDevicesFromMiniSSDPD() :
connectToMiniSSDPD() / disconnectFromMiniSSDPD()
requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD()
API version 13
miniupnpc.h:
add searchalltype param to upnpDiscoverDevices() function
updated macro :
#define MINIUPNPC_API_VERSION 13
API version 12
miniupnpc.h :
add upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices()
functions
updated macros :
#define MINIUPNPC_API_VERSION 12
API version 11
upnpreplyparse.h / portlistingparse.h :
removed usage of sys/queue.h / bsdqueue.h
miniupnpc.h:
updated macros :
#define MINIUPNPC_API_VERSION 11
====================== miniUPnPc version 1.9 ======================
API version 10
upnpcommands.h:
added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
miniupnpc.h:
updated macros :
#define MINIUPNPC_VERSION "1.9"
#define MINIUPNPC_API_VERSION 10
====================== miniUPnPc version 1.8 ======================
API version 9

View File

@ -35,14 +35,13 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClInclude Include="src\bsdqueue.h" />
<ClInclude Include="src\codelength.h" />
<ClInclude Include="src\connecthostport.h" />
<ClInclude Include="src\declspec.h" />
<ClInclude Include="src\igd_desc_parse.h" />
<ClInclude Include="src\minisoap.h" />
<ClInclude Include="src\minissdpc.h" />
<ClInclude Include="src\miniupnpc.h" />
<ClInclude Include="src\miniupnpc_declspec.h" />
<ClInclude Include="src\miniupnpcstrings.h" />
<ClInclude Include="src\miniupnpctypes.h" />
<ClInclude Include="src\miniwget.h" />
@ -50,6 +49,7 @@
<ClInclude Include="src\portlistingparse.h" />
<ClInclude Include="src\receivedata.h" />
<ClInclude Include="src\upnpcommands.h" />
<ClInclude Include="src\upnpdev.h" />
<ClInclude Include="src\upnperrors.h" />
<ClInclude Include="src\upnpreplyparse.h" />
</ItemGroup>
@ -57,19 +57,20 @@
<ClCompile Include="src\connecthostport.c" />
<ClCompile Include="src\igd_desc_parse.c" />
<ClCompile Include="src\minisoap.c" />
<ClCompile Include="src\minissdpc.c" />
<ClCompile Include="src\miniupnpc.c" />
<ClCompile Include="src\miniwget.c" />
<ClCompile Include="src\minixml.c" />
<ClCompile Include="src\portlistingparse.c" />
<ClCompile Include="src\receivedata.c" />
<ClCompile Include="src\upnpcommands.c" />
<ClCompile Include="src\upnpdev.c" />
<ClCompile Include="src\upnperrors.c" />
<ClCompile Include="src\upnpreplyparse.c" />
</ItemGroup>
<ItemGroup>
<None Include="LICENSE" />
<None Include="README" />
<None Include="src\miniupnpc.def" />
<None Include="VERSION" />
</ItemGroup>
<ItemGroup>

View File

@ -1,531 +0,0 @@
/* $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_ */

View File

@ -1,7 +1,7 @@
/* $Id: codelength.h,v 1.4 2012/09/27 15:40:29 nanard Exp $ */
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2011 Thomas Bernard
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#ifndef CODELENGTH_H_INCLUDED
@ -10,10 +10,30 @@
/* Encode length by using 7bit per Byte :
* Most significant bit of each byte specifies that the
* following byte is part of the code */
/* n : unsigned
* p : unsigned char *
*/
#define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \
while((*(p++)&0x80) && (n<(1<<25)));
/* n : unsigned
* READ : function/macro to read one byte (unsigned char)
*/
#define DECODELENGTH_READ(n, READ) \
n = 0; \
do { \
unsigned char c; \
READ(c); \
n = (n << 7) | (c & 0x07f); \
if(!(c&0x80)) break; \
} while(n<(1<<25));
/* n : unsigned
* p : unsigned char *
* p_limit : unsigned char *
*/
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
n = 0; \
do { \
@ -21,11 +41,14 @@
n = (n << 7) | (*(p) & 0x7f); \
} while((*((p)++)&0x80) && (n<(1<<25)));
/* n : unsigned
* p : unsigned char *
*/
#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
#endif /* CODELENGTH_H_INCLUDED */

View File

@ -1,7 +1,7 @@
/* $Id: connecthostport.c,v 1.10 2013/05/03 09:05:38 nanard Exp $ */
/* $Id: connecthostport.c,v 1.13 2014/03/31 12:36:36 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2010-2012 Thomas Bernard
* Copyright (c) 2010-2014 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@ -35,6 +35,7 @@
#ifndef USE_GETHOSTBYNAME
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#endif /* #ifndef USE_GETHOSTBYNAME */
#endif /* #else _WIN32 */
@ -51,6 +52,10 @@
#include "connecthostport.h"
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
/* connecthostport()
* return a socket connected (TCP) to the host and port
* or -1 in case of error */
@ -105,7 +110,10 @@ int connecthostport(const char * host, unsigned short port,
dest.sin_port = htons(port);
n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
#ifdef MINIUPNPC_IGNORE_EINTR
while(n < 0 && errno == EINTR)
/* EINTR The system call was interrupted by a signal that was caught
* EINPROGRESS The socket is nonblocking and the connection cannot
* be completed immediately. */
while(n < 0 && (errno == EINTR || errno = EINPROGRESS))
{
socklen_t len;
fd_set wset;
@ -199,7 +207,10 @@ int connecthostport(const char * host, unsigned short port,
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
n = connect(s, p->ai_addr, p->ai_addrlen);
#ifdef MINIUPNPC_IGNORE_EINTR
while(n < 0 && errno == EINTR)
/* EINTR The system call was interrupted by a signal that was caught
* EINPROGRESS The socket is nonblocking and the connection cannot
* be completed immediately. */
while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
{
socklen_t len;
fd_set wset;

View File

@ -1,4 +1,4 @@
/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */
/* $Id: connecthostport.h,v 1.2 2012/06/23 22:32:33 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/
* Author: Thomas Bernard

View File

@ -1,5 +0,0 @@
#ifndef DECLSPEC_H_INCLUDED
#define DECLSPEC_H_INCLUDED
#define LIBSPEC
#endif

View File

@ -1,8 +1,8 @@
/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */
/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */
/* Project : miniupnp
* http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2010 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@ -15,7 +15,9 @@
void IGDstartelt(void * d, const char * name, int l)
{
struct IGDdatas * datas = (struct IGDdatas *)d;
memcpy( datas->cureltname, name, l);
if(l >= MINIUPNPC_URL_MAXSIZE)
l = MINIUPNPC_URL_MAXSIZE-1;
memcpy(datas->cureltname, name, l);
datas->cureltname[l] = '\0';
datas->level++;
if( (l==7) && !memcmp(name, "service", l) ) {
@ -26,6 +28,8 @@ void IGDstartelt(void * d, const char * name, int l)
}
}
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
/* End element handler :
* update nesting level counter and update parser state if
* service element is parsed */
@ -36,23 +40,16 @@ void IGDendelt(void * d, const char * name, int l)
/*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")) {
if(COMPARE(datas->tmp.servicetype,
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) {
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
} else if(0==strcmp(datas->tmp.servicetype,
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) {
} else if(COMPARE(datas->tmp.servicetype,
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) {
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") ) {
} else if(COMPARE(datas->tmp.servicetype,
"urn:schemas-upnp-org:service:WANIPConnection:")
|| COMPARE(datas->tmp.servicetype,
"urn:schemas-upnp-org:service:WANPPPConnection:") ) {
if(datas->first.servicetype[0] == '\0') {
memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service));
} else {
@ -93,6 +90,7 @@ void IGDdata(void * d, const char * data, int l)
}
}
#ifdef DEBUG
void printIGD(struct IGDdatas * d)
{
printf("urlbase = '%s'\n", d->urlbase);
@ -121,5 +119,5 @@ void printIGD(struct IGDdatas * d)
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
}
#endif /* DEBUG */

View File

@ -1,8 +1,8 @@
/* $Id: igd_desc_parse.h,v 1.11 2012/10/16 16:49:02 nanard Exp $ */
/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */
/* Project : miniupnp
* http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2010 Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
@ -42,7 +42,8 @@ struct IGDdatas {
void IGDstartelt(void *, const char *, int);
void IGDendelt(void *, const char *, int);
void IGDdata(void *, const char *, int);
#ifdef DEBUG
void printIGD(struct IGDdatas *);
#endif /* DEBUG */
#endif
#endif /* IGD_DESC_PARSE_H_INCLUDED */

View File

@ -1,7 +1,7 @@
/* $Id: minisoap.c,v 1.22 2012/01/21 13:30:31 nanard Exp $ */
/* $Id: minisoap.c,v 1.23 2014/11/04 22:31:55 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
*
@ -96,7 +96,7 @@ int soapPostSubmit(int fd,
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"
"User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"Content-Length: %d\r\n"
"Content-Type: text/xml\r\n"
"SOAPAction: \"%s\"\r\n"

View File

@ -1,4 +1,4 @@
/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */
/* $Id: minisoap.h,v 1.4 2010/04/12 20:39:41 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005 Thomas Bernard

View File

@ -1,67 +1,193 @@
/* $Id: minissdpc.c,v 1.16 2012/03/05 19:42:46 nanard Exp $ */
/* $Id: minissdpc.c,v 1.28 2015/09/18 13:05:39 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2012 Thomas Bernard
* copyright (c) 2005-2015 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>
#include <unistd.h>
#include <sys/types.h>
#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#include <iphlpapi.h>
#include <winsock.h>
#define snprintf _snprintf
#if !defined(_MSC_VER)
#include <stdint.h>
#endif
#else /* !defined(_MSC_VER) */
typedef unsigned short uint16_t;
#endif /* !defined(_MSC_VER) */
#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 */
#endif /* _WIN32 */
#if defined(__amigaos__) || defined(__amigaos4__)
#include <sys/socket.h>
#endif
#endif /* defined(__amigaos__) || defined(__amigaos4__) */
#if defined(__amigaos__)
#define uint16_t unsigned short
#endif
#endif /* defined(__amigaos__) */
/* Hack */
#define UNIX_PATH_LEN 108
struct sockaddr_un {
uint16_t sun_family;
char sun_path[UNIX_PATH_LEN];
};
#else
#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */
#include <strings.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#define closesocket close
#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
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
#define HAS_IP_MREQN
#endif
#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
/* Several versions of glibc don't define this structure,
* define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
struct ip_mreqn
{
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_address; /* local IP address of interface */
int imr_ifindex; /* Interface index */
};
#endif
#if defined(__amigaos__) || defined(__amigaos4__)
/* Amiga OS specific stuff */
#define TIMEVAL struct timeval
#endif
#include "minissdpc.h"
#include "miniupnpc.h"
#include "receivedata.h"
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
#include "codelength.h"
struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error)
{
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;
int res;
s = connectToMiniSSDPD(socketpath);
if (s < 0) {
if (error)
*error = s;
return NULL;
}
res = requestDevicesFromMiniSSDPD(s, devtype);
if (res < 0) {
if (error)
*error = res;
} else {
devlist = receiveDevicesFromMiniSSDPD(s, error);
}
disconnectFromMiniSSDPD(s);
return devlist;
}
/* macros used to read from unix socket */
#define READ_BYTE_BUFFER(c) \
if((int)bufferindex >= n) { \
n = read(s, buffer, sizeof(buffer)); \
if(n<=0) break; \
bufferindex = 0; \
} \
c = buffer[bufferindex++];
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif /* MIN */
#define READ_COPY_BUFFER(dst, len) \
for(l = len, p = (unsigned char *)dst; l > 0; ) { \
unsigned int lcopy; \
if((int)bufferindex >= n) { \
n = read(s, buffer, sizeof(buffer)); \
if(n<=0) break; \
bufferindex = 0; \
} \
lcopy = MIN(l, (n - bufferindex)); \
memcpy(p, buffer + bufferindex, lcopy); \
l -= lcopy; \
p += lcopy; \
bufferindex += lcopy; \
}
#define READ_DISCARD_BUFFER(len) \
for(l = len; l > 0; ) { \
unsigned int lcopy; \
if(bufferindex >= n) { \
n = read(s, buffer, sizeof(buffer)); \
if(n<=0) break; \
bufferindex = 0; \
} \
lcopy = MIN(l, (n - bufferindex)); \
l -= lcopy; \
bufferindex += lcopy; \
}
int
connectToMiniSSDPD(const char * socketpath)
{
int s;
struct sockaddr_un addr;
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
struct timeval timeout;
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
s = socket(AF_UNIX, SOCK_STREAM, 0);
if(s < 0)
{
/*syslog(LOG_ERR, "socket(unix): %m");*/
perror("socket(unix)");
return NULL;
return MINISSDPC_SOCKET_ERROR;
}
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
/* setting a 3 seconds timeout */
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
perror("setsockopt");
}
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
perror("setsockopt");
}
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
if(!socketpath)
socketpath = "/var/run/minissdpd.sock";
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
/* TODO : check if we need to handle the EINTR */
@ -69,17 +195,45 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
{
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
close(s);
return NULL;
return MINISSDPC_SOCKET_ERROR;
}
return s;
}
int
disconnectFromMiniSSDPD(int s)
{
if (close(s) < 0)
return MINISSDPC_SOCKET_ERROR;
return MINISSDPC_SUCCESS;
}
int
requestDevicesFromMiniSSDPD(int s, const char * devtype)
{
unsigned char buffer[256];
unsigned char * p;
unsigned int stsize, l;
stsize = strlen(devtype);
buffer[0] = 1; /* request type 1 : request devices/services by type */
if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
{
buffer[0] = 3; /* request type 3 : everything */
}
else
{
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;
#ifdef DEBUG
fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
stsize, (unsigned)sizeof(buffer));
#endif /* DEBUG */
return MINISSDPC_INVALID_INPUT;
}
memcpy(p, devtype, stsize);
p += stsize;
@ -87,47 +241,600 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
{
/*syslog(LOG_ERR, "write(): %m");*/
perror("minissdpc.c: write()");
close(s);
return NULL;
return MINISSDPC_SOCKET_ERROR;
}
return MINISSDPC_SUCCESS;
}
struct UPNPDev *
receiveDevicesFromMiniSSDPD(int s, int * error)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = NULL;
unsigned char buffer[256];
ssize_t n;
unsigned char * p;
unsigned char * url;
unsigned char * st;
unsigned int bufferindex;
unsigned int i, ndev;
unsigned int urlsize, stsize, usnsize, l;
n = read(s, buffer, sizeof(buffer));
if(n<=0)
{
perror("minissdpc.c: read()");
close(s);
if (error)
*error = MINISSDPC_SOCKET_ERROR;
return NULL;
}
p = buffer + 1;
for(i = 0; i < buffer[0]; i++)
ndev = buffer[0];
bufferindex = 1;
for(i = 0; i < ndev; 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);
DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
return devlist;
}
#ifdef DEBUG
printf(" urlsize=%u", urlsize);
#endif /* DEBUG */
url = malloc(urlsize);
if(url == NULL) {
if (error)
*error = MINISSDPC_MEMORY_ERROR;
return devlist;
}
READ_COPY_BUFFER(url, urlsize);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_return;
}
DECODELENGTH_READ(stsize, READ_BYTE_BUFFER);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_return;
}
#ifdef DEBUG
printf(" stsize=%u", stsize);
#endif /* DEBUG */
st = malloc(stsize);
if (st == NULL) {
if (error)
*error = MINISSDPC_MEMORY_ERROR;
goto free_url_and_return;
}
READ_COPY_BUFFER(st, stsize);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_st_and_return;
}
DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_st_and_return;
}
#ifdef DEBUG
printf(" usnsize=%u\n", usnsize);
#endif /* DEBUG */
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
if(tmp == NULL) {
if (error)
*error = MINISSDPC_MEMORY_ERROR;
goto free_url_and_st_and_return;
}
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;
memcpy(tmp->st, st, stsize);
tmp->buffer[urlsize+1+stsize] = '\0';
free(url);
free(st);
url = NULL;
st = NULL;
tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
READ_COPY_BUFFER(tmp->usn, usnsize);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_tmp_and_return;
}
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */
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);
if (error)
*error = MINISSDPC_SUCCESS;
return devlist;
free_url_and_st_and_return:
free(st);
free_url_and_return:
free(url);
return devlist;
free_tmp_and_return:
free(tmp);
return devlist;
}
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
/* 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,
const char * * usn, int * usnsize)
{
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;
}
else if(0==strncasecmp(reply+a, "usn", 3))
{
*usn = reply+b;
*usnsize = 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 */
/* direct discovery if minissdpd responses are not sufficient */
/* ssdpDiscoverDevices() :
* 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).
* UDA v1.1 says :
* The TTL for the IP packet SHOULD default to 2 and
* SHOULD be configurable. */
struct UPNPDev *
ssdpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
int sameport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = 0;
unsigned int scope_id = 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";
int deviceIndex;
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;
unsigned long _ttl = (unsigned long)ttl;
#endif
int linklocal = 1;
if(error)
*error = MINISSDPC_UNKNOWN_ERROR;
#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 = MINISSDPC_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(pIPAddrTable) {
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
free(pIPAddrTable);
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
}
}
if(pIPAddrTable) {
dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
if (dwRetVal == NO_ERROR) {
#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 /* _WIN32 */
#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 = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)");
return NULL;
}
#ifdef _WIN32
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0)
#else /* _WIN32 */
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
#endif /* _WIN32 */
{
/* not a fatal error */
PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)");
}
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 */
if(mc_if.s_addr != INADDR_NONE)
{
((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");
}
} else {
#ifdef HAS_IP_MREQN
/* was not an ip address, try with an interface name */
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
memset(&reqn, 0, sizeof(struct ip_mreqn));
reqn.imr_ifindex = if_nametoindex(multicastif);
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported with interface name.\n");
#endif
#endif
}
}
}
/* Before sending the packed, we first "bind" in order to be able
* to receive the response */
if (bind(sudp, (const struct sockaddr *)&sockudp_r,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
{
if(error)
*error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("bind");
closesocket(sudp);
return NULL;
}
if(error)
*error = MINISSDPC_SUCCESS;
/* Calculating maximum response time in seconds */
mx = ((unsigned int)delay) / 1000u;
if(mx == 0) {
mx = 1;
delay = 1000;
}
/* receiving SSDP response packet */
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
/* 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,
deviceTypes[deviceIndex], mx);
#ifdef DEBUG
/*printf("Sending %s", bufr);*/
printf("Sending M-SEARCH request to %s with ST: %s\n",
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR,
deviceTypes[deviceIndex]);
#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 = MINISSDPC_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 = MINISSDPC_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) {
#ifdef DEBUG
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
}
#endif
PRINT_SOCKET_ERROR("sendto");
continue;
}
}
freeaddrinfo(servinfo);
if(n < 0) {
if(error)
*error = MINISSDPC_SOCKET_ERROR;
break;
}
#endif /* #ifdef NO_GETADDRINFO */
/* Waiting for SSDP REPLY packet to M-SEARCH
* if searchalltypes is set, enter the loop only
* when the last deviceType is reached */
if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do {
n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
if (n < 0) {
/* error */
if(error)
*error = MINISSDPC_SOCKET_ERROR;
goto error;
} else if (n == 0) {
/* no data or Time Out */
#ifdef DEBUG
printf("NODATA or TIMEOUT\n");
#endif /* DEBUG */
if (devlist && !searchalltypes) {
/* found some devices, stop now*/
if(error)
*error = MINISSDPC_SUCCESS;
goto error;
}
} else {
const char * descURL=NULL;
int urlsize=0;
const char * st=NULL;
int stsize=0;
const char * usn=NULL;
int usnsize=0;
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
if(st&&descURL) {
#ifdef DEBUG
printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
#endif /* DEBUG */
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' &&
(usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) &&
tmp->usn[usnsize] == '\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+usnsize);
if(!tmp) {
/* memory allocation error */
if(error)
*error = MINISSDPC_MEMORY_ERROR;
goto error;
}
tmp->pNext = devlist;
tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize;
tmp->usn = tmp->st + 1 + stsize;
memcpy(tmp->buffer, descURL, urlsize);
tmp->buffer[urlsize] = '\0';
memcpy(tmp->st, st, stsize);
tmp->buffer[urlsize+1+stsize] = '\0';
if(usn != NULL)
memcpy(tmp->usn, usn, usnsize);
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
tmp->scope_id = scope_id;
devlist = tmp;
}
}
} while(n > 0);
if(ipv6) {
/* switch linklocal flag */
if(linklocal) {
linklocal = 0;
--deviceIndex;
} else {
linklocal = 1;
}
}
}
error:
closesocket(sudp);
return devlist;
}

View File

@ -1,15 +1,58 @@
/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */
/* $Id: minissdpc.h,v 1.6 2015/09/18 12:45:16 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard
* Copyright (c) 2005-2007 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINISSDPC_H_INCLUDED
#define MINISSDPC_H_INCLUDED
struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath);
#include "miniupnpc_declspec.h"
#include "upnpdev.h"
/* error codes : */
#define MINISSDPC_SUCCESS (0)
#define MINISSDPC_UNKNOWN_ERROR (-1)
#define MINISSDPC_SOCKET_ERROR (-101)
#define MINISSDPC_MEMORY_ERROR (-102)
#define MINISSDPC_INVALID_INPUT (-103)
#define MINISSDPC_INVALID_SERVER_REPLY (-104)
#ifdef __cplusplus
extern "C" {
#endif
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
MINIUPNP_LIBSPEC struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
MINIUPNP_LIBSPEC int
connectToMiniSSDPD(const char * socketpath);
MINIUPNP_LIBSPEC int
disconnectFromMiniSSDPD(int fd);
MINIUPNP_LIBSPEC int
requestDevicesFromMiniSSDPD(int fd, const char * devtype);
MINIUPNP_LIBSPEC struct UPNPDev *
receiveDevicesFromMiniSSDPD(int fd, int * error);
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
MINIUPNP_LIBSPEC struct UPNPDev *
ssdpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
int sameport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,26 +1,10 @@
/* $Id: miniupnpc.c,v 1.111 2012/10/09 17:53:14 nanard Exp $ */
/* $Id: miniupnpc.c,v 1.135 2015/07/23 20:40:08 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2012 Thomas Bernard
* copyright (c) 2005-2015 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
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(MACOSX) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun)
#define HAS_IP_MREQN
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -63,14 +47,11 @@
#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
#ifdef __GNU__
#define MAXHOSTNAMELEN 64
#endif
#include "miniupnpc.h"
#include "minissdpc.h"
#include "miniwget.h"
@ -78,12 +59,12 @@
#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)
/* compare the begining of a string with a constant string */
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
#define SOAPPREFIX "s"
@ -91,7 +72,7 @@
#define SERVICEPREFIX2 'u'
/* root description parsing */
LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
{
struct xmlparser parser;
/* xmlparser object */
@ -245,98 +226,92 @@ char * simpleUPnPcommand(int s, const char * url, const char * service,
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() :
/* upnpDiscoverDevices() :
* 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)
* delay is in millisecond (poll).
* UDA v1.1 says :
* The TTL for the IP packet SHOULD default to 2 and
* SHOULD be configurable. */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = 0;
unsigned int scope_id = 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";
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
int deviceIndex;
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
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";
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
struct UPNPDev * minissdpd_devlist;
int only_rootdevice = 1;
minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
minissdpdsock, 0);
if(minissdpd_devlist) {
#ifdef DEBUG
printf("returned by MiniSSDPD: %s\t%s\n",
minissdpd_devlist->st, minissdpd_devlist->descURL);
#endif /* DEBUG */
if(!strstr(minissdpd_devlist->st, "rootdevice"))
only_rootdevice = 0;
for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
#ifdef DEBUG
printf("returned by MiniSSDPD: %s\t%s\n",
tmp->pNext->st, tmp->pNext->descURL);
#endif /* DEBUG */
if(!strstr(tmp->st, "rootdevice"))
only_rootdevice = 0;
}
tmp->pNext = devlist;
devlist = minissdpd_devlist;
if(!searchalltypes && !only_rootdevice)
break;
}
}
for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
/* We return what we have found if it was not only a rootdevice */
if(!strstr(tmp->st, "rootdevice")) {
if(error)
*error = UPNPDISCOVER_SUCCESS;
return devlist;
}
}
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
/* direct discovery if minissdpd responses are not sufficient */
{
struct UPNPDev * discovered_devlist;
discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, sameport,
ipv6, ttl, error, searchalltypes);
if(devlist == NULL)
devlist = discovered_devlist;
else {
for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
tmp->pNext = discovered_devlist;
}
}
return devlist;
}
/* upnpDiscover() Discover IGD device */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6, unsigned char ttl,
int * error)
{
static const char * const deviceList[] = {
#if 0
"urn:schemas-upnp-org:device:InternetGatewayDevice:2",
@ -346,468 +321,147 @@ upnpDiscover(int delay, const char * multicastif,
"urn:schemas-upnp-org:service:WANIPConnection:1",
"urn:schemas-upnp-org:service:WANPPPConnection:1",
"upnp:rootdevice",
/*"ssdp:all",*/
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;
/* 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 */
if(mc_if.s_addr != INADDR_NONE)
{
((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");
}
} else {
#ifdef HAS_IP_MREQN
/* was not an ip address, try with an interface name */
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
memset(&reqn, 0, sizeof(struct ip_mreqn));
reqn.imr_ifindex = if_nametoindex(multicastif);
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported with interface name.\n");
#endif
#endif
}
}
}
/* 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) {
#ifdef DEBUG
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
}
#endif
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, &scope_id);
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';
tmp->scope_id = scope_id;
devlist = tmp;
}
}
}
closesocket(sudp);
return devlist;
return upnpDiscoverDevices(deviceList,
delay, multicastif, minissdpdsock, sameport,
ipv6, ttl, error, 0);
}
/* freeUPNPDevlist() should be used to
* free the chained list returned by upnpDiscover() */
LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist)
/* upnpDiscoverAll() Discover all UPnP devices */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverAll(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6, unsigned char ttl,
int * error)
{
struct UPNPDev * next;
while(devlist)
{
next = devlist->pNext;
free(devlist);
devlist = next;
}
static const char * const deviceList[] = {
/*"upnp:rootdevice",*/
"ssdp:all",
0
};
return upnpDiscoverDevices(deviceList,
delay, multicastif, minissdpdsock, sameport,
ipv6, ttl, error, 0);
}
static void
url_cpy_or_cat(char * dst, const char * src, int n)
/* upnpDiscoverDevice() Discover a specific device */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6, unsigned char ttl,
int * error)
{
if( (src[0] == 'h')
&&(src[1] == 't')
&&(src[2] == 't')
&&(src[3] == 'p')
&&(src[4] == ':')
&&(src[5] == '/')
&&(src[6] == '/'))
{
strncpy(dst, src, n);
const char * const deviceList[] = {
device,
0
};
return upnpDiscoverDevices(deviceList,
delay, multicastif, minissdpdsock, sameport,
ipv6, ttl, error, 0);
}
static char *
build_absolute_url(const char * baseurl, const char * descURL,
const char * url, unsigned int scope_id)
{
int l, n;
char * s;
const char * base;
char * p;
#if defined(IF_NAMESIZE) && !defined(_WIN32)
char ifname[IF_NAMESIZE];
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
char scope_str[8];
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
if( (url[0] == 'h')
&&(url[1] == 't')
&&(url[2] == 't')
&&(url[3] == 'p')
&&(url[4] == ':')
&&(url[5] == '/')
&&(url[6] == '/'))
return strdup(url);
base = (baseurl[0] == '\0') ? descURL : baseurl;
n = strlen(base);
if(n > 7) {
p = strchr(base + 7, '/');
if(p)
n = p - base;
}
else
{
int l = strlen(dst);
if(src[0] != '/')
dst[l++] = '/';
if(l<=n)
strncpy(dst + l, src, n - l);
l = n + strlen(url) + 1;
if(url[0] != '/')
l++;
if(scope_id != 0) {
#if defined(IF_NAMESIZE) && !defined(_WIN32)
if(if_indextoname(scope_id, ifname)) {
l += 3 + strlen(ifname); /* 3 == strlen(%25) */
}
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
/* under windows, scope is numerical */
l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
}
s = malloc(l);
if(s == NULL) return NULL;
memcpy(s, base, n);
if(scope_id != 0) {
s[n] = '\0';
if(0 == memcmp(s, "http://[fe80:", 13)) {
/* this is a linklocal IPv6 address */
p = strchr(s, ']');
if(p) {
/* insert %25<scope> into URL */
#if defined(IF_NAMESIZE) && !defined(_WIN32)
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, ifname, strlen(ifname));
n += 3 + strlen(ifname);
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, scope_str, strlen(scope_str));
n += 3 + strlen(scope_str);
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
}
}
}
if(url[0] != '/')
s[n++] = '/';
memcpy(s + n, url, l - n);
return s;
}
/* Prepare the Urls for usage...
*/
LIBSPEC void
MINIUPNP_LIBSPEC void
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
const char * descURL, unsigned int scope_id)
{
char * p;
int n1, n2, n3, n4;
#ifdef IF_NAMESIZE
char ifname[IF_NAMESIZE];
#else
char scope_str[8];
#endif
n1 = strlen(data->urlbase);
if(n1==0)
n1 = strlen(descURL);
if(scope_id != 0) {
#ifdef IF_NAMESIZE
if(if_indextoname(scope_id, ifname)) {
n1 += 3 + strlen(ifname); /* 3 == strlen(%25) */
}
#else
/* under windows, scope is numerical */
snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
#endif
}
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);
/* allocate memory to store URLs */
urls->ipcondescURL = (char *)malloc(n1);
urls->controlURL = (char *)malloc(n2);
urls->controlURL_CIF = (char *)malloc(n3);
urls->controlURL_6FC = (char *)malloc(n4);
/* strdup descURL */
urls->rootdescURL = strdup(descURL);
/* get description of 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';
if(scope_id != 0) {
if(0 == memcmp(urls->ipcondescURL, "http://[fe80:", 13)) {
/* this is a linklocal IPv6 address */
p = strchr(urls->ipcondescURL, ']');
if(p) {
/* insert %25<scope> into URL */
#ifdef IF_NAMESIZE
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, ifname, strlen(ifname));
#else
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, scope_str, strlen(scope_str));
#endif
}
}
}
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);
urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
data->first.scpdurl, scope_id);
urls->controlURL = build_absolute_url(data->urlbase, descURL,
data->first.controlurl, scope_id);
urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
data->CIF.controlurl, scope_id);
urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
data->IPv6FC.controlurl, scope_id);
#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);
printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
printf("urls->controlURL='%s'\n", urls->controlURL);
printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
#endif
}
LIBSPEC void
MINIUPNP_LIBSPEC void
FreeUPNPUrls(struct UPNPUrls * urls)
{
if(!urls)
@ -833,9 +487,9 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
status, &uptime, NULL);
if(0 == strcmp("Connected", status))
{
return 1;
}
else if(0 == strcmp("Up", status)) /* Also accept "Up" */
return 1;
else
return 0;
}
@ -850,11 +504,11 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
* 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
* In any positive 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
MINIUPNP_LIBSPEC int
UPNP_GetValidIGD(struct UPNPDev * devlist,
struct UPNPUrls * urls,
struct IGDdatas * data,
@ -863,11 +517,14 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
struct xml_desc {
char * xml;
int size;
int is_igd;
} * desc = NULL;
struct UPNPDev * dev;
int ndev = 0;
int i;
int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
int n_igd = 0;
char extIpAddr[16];
if(!devlist)
{
#ifdef DEBUG
@ -875,6 +532,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
#endif
return 0;
}
/* counting total number of devices in the list */
for(dev = devlist; dev; dev = dev->pNext)
ndev++;
if(ndev > 0)
@ -883,41 +541,58 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
if(!desc)
return -1; /* memory allocation error */
}
/* Step 1 : downloading descriptions and testing type */
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
{
/* we should choose an internet gateway device.
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
lanaddr, lanaddrlen,
dev->scope_id);
#ifdef DEBUG
if(!desc[i].xml)
{
printf("error getting XML description %s\n", dev->descURL);
}
#endif
if(desc[i].xml)
{
memset(data, 0, sizeof(struct IGDdatas));
memset(urls, 0, sizeof(struct UPNPUrls));
parserootdesc(desc[i].xml, desc[i].size, data);
if(COMPARE(data->CIF.servicetype,
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
{
desc[i].is_igd = 1;
n_igd++;
}
}
}
/* iterate the list to find a device depending on state */
for(state = 1; state <= 3; state++)
{
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
{
/* we should choose an internet gateway device.
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
if(state == 1)
{
desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
lanaddr, lanaddrlen,
dev->scope_id);
#ifdef DEBUG
if(!desc[i].xml)
{
printf("error getting XML description %s\n", dev->descURL);
}
#endif
}
if(desc[i].xml)
{
memset(data, 0, sizeof(struct IGDdatas));
memset(urls, 0, sizeof(struct UPNPUrls));
parserootdesc(desc[i].xml, desc[i].size, data);
if(0==strcmp(data->CIF.servicetype,
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")
|| state >= 3 )
if(desc[i].is_igd || state >= 3 )
{
GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
/* in state 2 and 3 we dont test if device is connected ! */
if(state >= 2)
goto free_and_return;
#ifdef DEBUG
printf("UPNPIGD_IsConnected(%s) = %d\n",
urls->controlURL,
UPNPIGD_IsConnected(urls, data));
#endif
if((state >= 2) || UPNPIGD_IsConnected(urls, data))
/* checks that status is connected AND there is a external IP address assigned */
if(UPNPIGD_IsConnected(urls, data)
&& (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0))
goto free_and_return;
FreeUPNPUrls(urls);
if(data->second.servicetype[0] != '\0') {
@ -935,7 +610,8 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
urls->controlURL,
UPNPIGD_IsConnected(urls, data));
#endif
if((state >= 2) || UPNPIGD_IsConnected(urls, data))
if(UPNPIGD_IsConnected(urls, data)
&& (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0))
goto free_and_return;
FreeUPNPUrls(urls);
}

View File

@ -1,42 +0,0 @@
LIBRARY
; miniupnpc library
EXPORTS
; miniupnpc
upnpDiscover
freeUPNPDevlist
parserootdesc
UPNP_GetValidIGD
UPNP_GetIGDFromUrl
GetUPNPUrls
FreeUPNPUrls
; miniwget
miniwget
miniwget_getaddr
; upnpcommands
UPNP_GetTotalBytesSent
UPNP_GetTotalBytesReceived
UPNP_GetTotalPacketsSent
UPNP_GetTotalPacketsReceived
UPNP_GetStatusInfo
UPNP_GetConnectionTypeInfo
UPNP_GetExternalIPAddress
UPNP_GetLinkLayerMaxBitRates
UPNP_AddPortMapping
UPNP_DeletePortMapping
UPNP_GetPortMappingNumberOfEntries
UPNP_GetSpecificPortMappingEntry
UPNP_GetGenericPortMappingEntry
UPNP_GetListOfPortMappings
UPNP_AddPinhole
UPNP_CheckPinholeWorking
UPNP_UpdatePinhole
UPNP_GetPinholePackets
UPNP_DeletePinhole
UPNP_GetFirewallStatus
UPNP_GetOutboundPinholeTimeout
; upnperrors
strupnperror
; portlistingparse
ParsePortListing
FreePortListing

View File

@ -1,15 +1,16 @@
/* $Id: miniupnpc.h,v 1.32 2013/02/06 14:44:42 nanard Exp $ */
/* $Id: miniupnpc.h,v 1.44 2015/07/23 20:40:10 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/
* Author: Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINIUPNPC_H_INCLUDED
#define MINIUPNPC_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
#include "igd_desc_parse.h"
#include "upnpdev.h"
/* error codes : */
#define UPNPDISCOVER_SUCCESS (0)
@ -18,8 +19,8 @@
#define UPNPDISCOVER_MEMORY_ERROR (-102)
/* versions : */
#define MINIUPNPC_VERSION "1.8.20130503"
#define MINIUPNPC_API_VERSION 9
#define MINIUPNPC_VERSION "1.9"
#define MINIUPNPC_API_VERSION 14
#ifdef __cplusplus
extern "C" {
@ -33,14 +34,6 @@ simpleUPnPcommand(int, const char *, const char *,
const char *, struct UPNParg *,
int *);
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
unsigned int scope_id;
char buffer[2];
};
/* upnpDiscover()
* discover UPnP devices on the network.
* The discovered devices are returned as a chained list.
@ -53,20 +46,40 @@ struct UPNPDev {
* 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 *
* 1900 (same as destination port) otherwise system assign a source port.
* "searchalltypes" parameter is useful when searching several types,
* if 0, the discovery will stop with the first type returning results.
* TTL should default to 2. */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6,
int ipv6, unsigned char ttl,
int * error);
/* freeUPNPDevlist()
* free list returned by upnpDiscover() */
LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverAll(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes);
/* parserootdesc() :
* parse root XML description of a UPnP device and fill the IGDdatas
* structure. */
LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
/* structure used to get fast access to urls
* controlURL: controlURL of the WANIPConnection
@ -94,7 +107,7 @@ struct UPNPUrls {
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
* free allocated memory.
*/
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetValidIGD(struct UPNPDev * devlist,
struct UPNPUrls * urls,
struct IGDdatas * data,
@ -102,24 +115,25 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
/* UPNP_GetIGDFromUrl()
* Used when skipping the discovery process.
* When succeding, urls, data, and lanaddr arguments are set.
* return value :
* 0 - Not ok
* 1 - OK */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetIGDFromUrl(const char * rootdescurl,
struct UPNPUrls * urls,
struct IGDdatas * data,
char * lanaddr, int lanaddrlen);
LIBSPEC void
MINIUPNP_LIBSPEC void
GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *,
const char *, unsigned int);
LIBSPEC void
MINIUPNP_LIBSPEC void
FreeUPNPUrls(struct UPNPUrls *);
/* return 0 or 1 */
LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
#ifdef __cplusplus

View File

@ -0,0 +1,12 @@
#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED
#define MINIUPNPC_DECLSPEC_H_INCLUDED
#if defined(__GNUC__) && __GNUC__ >= 4
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */
#define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default")))
#else
#define MINIUPNP_LIBSPEC
#endif
#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */

View File

@ -1,12 +1,12 @@
/* $Id: miniupnpcmodule.c,v 1.21 2012/08/29 07:51:30 nanard Exp $*/
/* $Id: miniupnpcmodule.c,v 1.24 2014/06/10 09:48:11 nanard Exp $*/
/* Project : miniupnp
* Author : Thomas BERNARD
* website : http://miniupnp.tuxfamily.org/
* copyright (c) 2007-2012 Thomas Bernard
* copyright (c) 2007-2014 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#include <Python.h>
#define STATICLIB
#define MINIUPNP_STATICLIB
#include "structmember.h"
#include "miniupnpc.h"
#include "upnpcommands.h"
@ -58,17 +58,42 @@ static PyMemberDef UPnP_members[] = {
{"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
0, "IP of the network interface to be used for multicast operations"
},
{"minissdpdsocket", T_STRING, offsetof(UPnPObject, multicastif),
{"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket),
0, "path of the MiniSSDPd unix socket"
},
{NULL}
};
static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds)
{
char* multicastif = NULL;
char* minissdpdsocket = NULL;
static char *kwlist[] = {
"multicastif", "minissdpdsocket", "discoverdelay", NULL
};
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzI", kwlist,
&multicastif,
&minissdpdsocket,
&self->discoverdelay))
return -1;
if(multicastif)
self->multicastif = strdup(multicastif);
if(minissdpdsocket)
self->minissdpdsocket = strdup(minissdpdsocket);
return 0;
}
static void
UPnPObject_dealloc(UPnPObject *self)
{
freeUPNPDevlist(self->devlist);
FreeUPNPUrls(&self->urls);
free(self->multicastif);
free(self->minissdpdsocket);
Py_TYPE(self)->tp_free((PyObject*)self);
}
@ -85,10 +110,11 @@ UPnP_discover(UPnPObject *self)
}
Py_BEGIN_ALLOW_THREADS
self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
0/* multicast if*/,
0/*minissdpd socket*/,
0/*sameport flag*/,
self->multicastif,
self->minissdpdsocket,
0/*sameport flag*/,
0/*ip v6*/,
2/* TTL */,
0/*error */);
Py_END_ALLOW_THREADS
/* Py_RETURN_NONE ??? */
@ -265,6 +291,42 @@ Py_END_ALLOW_THREADS
}
}
/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc,
* remoteHost)
* protocol is 'UDP' or 'TCP' */
static PyObject *
UPnP_addanyportmapping(UPnPObject *self, PyObject *args)
{
char extPort[6];
unsigned short ePort;
char inPort[6];
unsigned short iPort;
char reservedPort[6];
const char * proto;
const char * host;
const char * desc;
const char * remoteHost;
const char * leaseDuration = "0";
int r;
if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, &host, &iPort, &desc, &remoteHost))
return NULL;
Py_BEGIN_ALLOW_THREADS
sprintf(extPort, "%hu", ePort);
sprintf(inPort, "%hu", iPort);
r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype,
extPort, inPort, host, desc, proto,
remoteHost, leaseDuration, reservedPort);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) {
return Py_BuildValue("i", atoi(reservedPort));
} else {
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
return NULL;
}
}
/* DeletePortMapping(extPort, proto, removeHost='')
* proto = 'UDP', 'TCP' */
static PyObject *
@ -291,6 +353,37 @@ Py_END_ALLOW_THREADS
}
}
/* DeletePortMappingRange(extPort, proto, removeHost='')
* proto = 'UDP', 'TCP' */
static PyObject *
UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args)
{
char extPortStart[6];
unsigned short ePortStart;
char extPortEnd[6];
unsigned short ePortEnd;
const char * proto;
unsigned char manage;
char manageStr[1];
int r;
if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage))
return NULL;
Py_BEGIN_ALLOW_THREADS
sprintf(extPortStart, "%hu", ePortStart);
sprintf(extPortEnd, "%hu", ePortEnd);
sprintf(manageStr, "%hhu", manage);
r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype,
extPortStart, extPortEnd, proto, manageStr);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) {
Py_RETURN_TRUE;
} else {
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
return NULL;
}
}
static PyObject *
UPnP_getportmappingnumberofentries(UPnPObject *self)
{
@ -310,7 +403,7 @@ Py_END_ALLOW_THREADS
}
}
/* GetSpecificPortMapping(ePort, proto)
/* GetSpecificPortMapping(ePort, proto, remoteHost='')
* proto = 'UDP' or 'TCP' */
static PyObject *
UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
@ -318,13 +411,14 @@ UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
char extPort[6];
unsigned short ePort;
const char * proto;
const char * remoteHost = "";
char intClient[40];
char intPort[6];
unsigned short iPort;
char desc[80];
char enabled[4];
char leaseDuration[16];
if(!PyArg_ParseTuple(args, "Hs", &ePort, &proto))
if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
return NULL;
extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
@ -332,7 +426,7 @@ Py_BEGIN_ALLOW_THREADS
sprintf(extPort, "%hu", ePort);
UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
self->data.first.servicetype,
extPort, proto,
extPort, proto, remoteHost,
intClient, intPort,
desc, enabled, leaseDuration);
Py_END_ALLOW_THREADS
@ -428,9 +522,15 @@ static PyMethodDef UPnP_methods[] = {
{"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
"add a port mapping"
},
{"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS,
"add a port mapping, IGD to select alternative if necessary"
},
{"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
"delete a port mapping"
},
{"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS,
"delete a range of port mappings"
},
{"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
"-- non standard --"
},
@ -480,7 +580,7 @@ static PyTypeObject UPnPType = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0,/*(initproc)UPnP_init,*/ /* tp_init */
(initproc)UPnP_init, /* tp_init */
0, /* tp_alloc */
#ifndef _WIN32
PyType_GenericNew,/*UPnP_new,*/ /* tp_new */
@ -525,7 +625,11 @@ initminiupnpc(void)
UPnPType.tp_new = PyType_GenericNew;
#endif
if (PyType_Ready(&UPnPType) < 0)
#if PY_MAJOR_VERSION >= 3
return 0;
#else
return;
#endif
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&moduledef);

View File

@ -1,10 +1,3 @@
/* $Id: miniupnpcstrings.h.in,v 1.5 2012/10/16 16:48:26 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* 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 MINIUPNPCSTRINGS_H_INCLUDED
#define MINIUPNPCSTRINGS_H_INCLUDED
@ -21,7 +14,7 @@
#else
#define OS_STRING "Generic"
#endif
#define MINIUPNPC_VERSION_STRING "1.7"
#define MINIUPNPC_VERSION_STRING "1.9"
#define UPNP_VERSION_STRING "UPnP/1.1"
#endif

View File

@ -1,4 +1,4 @@
/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */
/* $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

View File

@ -1,8 +1,8 @@
/* $Id: miniwget.c,v 1.58 2012/08/11 05:52:49 nanard Exp $ */
/* $Id: miniwget.c,v 1.70 2015/07/15 12:41:13 nanard Exp $ */
/* Project : miniupnp
* Website : http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@ -15,7 +15,6 @@
#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
@ -39,19 +38,26 @@
#include <net/if.h>
#include <netdb.h>
#define closesocket close
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
* during the connect() call */
#define MINIUPNPC_IGNORE_EINTR
#include <strings.h>
#endif /* #else _WIN32 */
#if defined(__sun) || defined(sun)
#ifdef __GNU__
#define MAXHOSTNAMELEN 64
#endif /* __GNU__ */
#ifndef MIN
#define MIN(x,y) (((x)<(y))?(x):(y))
#endif
#endif /* MIN */
#include "miniupnpcstrings.h"
#include "miniwget.h"
#include "connecthostport.h"
#include "receivedata.h"
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
/*
* Read a HTTP response from a socket.
* Process Content-Length and Transfer-encoding headers.
@ -79,7 +85,24 @@ getHTTPResponse(int s, int * size)
unsigned int chunksize_buf_index;
header_buf = malloc(header_buf_len);
if(header_buf == NULL)
{
#ifdef DEBUG
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
#endif /* DEBUG */
*size = -1;
return NULL;
}
content_buf = malloc(content_buf_len);
if(content_buf == NULL)
{
free(header_buf);
#ifdef DEBUG
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
#endif /* DEBUG */
*size = -1;
return NULL;
}
chunksize_buf[0] = '\0';
chunksize_buf_index = 0;
@ -92,7 +115,15 @@ getHTTPResponse(int s, int * size)
int colon=0;
int valuestart=0;
if(header_buf_used + n > header_buf_len) {
header_buf = realloc(header_buf, header_buf_used + n);
char * tmp = realloc(header_buf, header_buf_used + n);
if(tmp == NULL) {
/* memory allocation error */
free(header_buf);
free(content_buf);
*size = -1;
return NULL;
}
header_buf = tmp;
header_buf_len = header_buf_used + n;
}
memcpy(header_buf + header_buf_used, buf, n);
@ -158,7 +189,7 @@ getHTTPResponse(int s, int * size)
chunked = 1;
}
}
while(header_buf[i]=='\r' || header_buf[i] == '\n')
while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n'))
i++;
linestart = i;
colon = linestart;
@ -227,13 +258,21 @@ getHTTPResponse(int s, int * size)
bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
if((content_buf_used + bytestocopy) > content_buf_len)
{
char * tmp;
if(content_length >= (int)(content_buf_used + bytestocopy)) {
content_buf_len = content_length;
} else {
content_buf_len = content_buf_used + bytestocopy;
}
content_buf = (char *)realloc((void *)content_buf,
content_buf_len);
tmp = realloc(content_buf, content_buf_len);
if(tmp == NULL) {
/* memory allocation error */
free(content_buf);
free(header_buf);
*size = -1;
return NULL;
}
content_buf = tmp;
}
memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
content_buf_used += bytestocopy;
@ -251,13 +290,21 @@ getHTTPResponse(int s, int * size)
}
if(content_buf_used + n > content_buf_len)
{
char * tmp;
if(content_length >= (int)(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);
tmp = realloc(content_buf, content_buf_len);
if(tmp == NULL) {
/* memory allocation error */
free(content_buf);
free(header_buf);
*size = -1;
return NULL;
}
content_buf = tmp;
}
memcpy(content_buf + content_buf_used, buf, n);
content_buf_used += n;
@ -363,7 +410,7 @@ miniwget3(const char * host,
"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"
"User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"\r\n",
path, httpversion, host, port);

View File

@ -1,24 +1,24 @@
/* $Id: miniwget.h,v 1.8 2012/09/27 15:42:10 nanard Exp $ */
/* $Id: miniwget.h,v 1.7 2012/06/23 22:35:59 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
#ifndef MINIWGET_H_INCLUDED
#define MINIWGET_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {
#endif
LIBSPEC void * getHTTPResponse(int s, int * size);
MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size);
LIBSPEC void * miniwget(const char *, int *, unsigned int);
MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int);
LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int);
MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int);
int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *);

View File

@ -4,7 +4,7 @@
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author : Thomas Bernard
Copyright (c) 2005-2011, Thomas BERNARD
Copyright (c) 2005-2014, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -113,7 +113,20 @@ static void parseelt(struct xmlparser * p)
const char * elementname;
while(p->xml < (p->xmlend - 1))
{
if((p->xml)[0]=='<' && (p->xml)[1]!='?')
if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4)))
{
p->xml += 3;
/* ignore comments */
do
{
p->xml++;
if ((p->xml + 3) >= p->xmlend)
return;
}
while(memcmp(p->xml, "-->", 3) != 0);
p->xml += 3;
}
else if((p->xml)[0]=='<' && (p->xml)[1]!='?')
{
i = 0; elementname = ++p->xml;
while( !IS_WHITE_SPACE(*p->xml)

View File

@ -1,4 +1,4 @@
/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */
/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */
/* minimal xml parser
*
* Project : miniupnp

View File

@ -1,11 +1,14 @@
/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */
/* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011 Thomas Bernard
* (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#include <string.h>
#include <stdlib.h>
#ifdef DEBUG
#include <stdio.h>
#endif /* DEBUG */
#include "portlistingparse.h"
#include "minixml.h"
@ -62,7 +65,17 @@ startelt(void * d, const char * name, int l)
{
struct PortMapping * pm;
pm = calloc(1, sizeof(struct PortMapping));
LIST_INSERT_HEAD( &(pdata->head), pm, entries);
if(pm == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"startelt");
#endif /* DEBUG */
return;
}
pm->l_next = pdata->l_head; /* insert in list */
pdata->l_head = pm;
}
}
@ -82,7 +95,7 @@ data(void * d, const char * data, int l)
{
struct PortMapping * pm;
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
pm = pdata->head.lh_first;
pm = pdata->l_head;
if(!pm)
return;
if(l > 63)
@ -134,7 +147,6 @@ ParsePortListing(const char * buffer, int bufsize,
struct xmlparser parser;
memset(pdata, 0, sizeof(struct PortMappingParserData));
LIST_INIT(&(pdata->head));
/* init xmlparser */
parser.xmlstart = buffer;
parser.xmlsize = bufsize;
@ -150,9 +162,10 @@ void
FreePortListing(struct PortMappingParserData * pdata)
{
struct PortMapping * pm;
while((pm = pdata->head.lh_first) != NULL)
while((pm = pdata->l_head) != NULL)
{
LIST_REMOVE(pm, entries);
/* remove from list */
pdata->l_head = pm->l_next;
free(pm);
}
}

View File

@ -1,22 +1,16 @@
/* $Id: portlistingparse.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */
/* $Id: portlistingparse.h,v 1.10 2014/11/01 10:37:32 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011-2012 Thomas Bernard
* (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef PORTLISTINGPARSE_H_INCLUDED
#define PORTLISTINGPARSE_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_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
@ -41,7 +35,7 @@ typedef enum { PortMappingEltNone,
NewLeaseTime } portMappingElt;
struct PortMapping {
LIST_ENTRY(PortMapping) entries;
struct PortMapping * l_next; /* list next element */
UNSIGNED_INTEGER leaseTime;
unsigned short externalPort;
unsigned short internalPort;
@ -53,15 +47,15 @@ struct PortMapping {
};
struct PortMappingParserData {
LIST_HEAD(portmappinglisthead, PortMapping) head;
struct PortMapping * l_head; /* list head */
portMappingElt curelt;
};
LIBSPEC void
MINIUPNP_LIBSPEC void
ParsePortListing(const char * buffer, int bufsize,
struct PortMappingParserData * pdata);
LIBSPEC void
MINIUPNP_LIBSPEC void
FreePortListing(struct PortMappingParserData * pdata);
#ifdef __cplusplus

View File

@ -1,16 +1,17 @@
/* $Id: receivedata.c,v 1.4 2012/06/23 22:34:47 nanard Exp $ */
/* $Id: receivedata.c,v 1.6 2014/11/13 13:51:52 nanard Exp $ */
/* Project : miniupnp
* Website : http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2011-2012 Thomas Bernard
* Copyright (c) 2011-2014 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#else /* _WIN32 */
#include <unistd.h>
#if defined(__amigaos__) && !defined(__amigaos4__)
#define socklen_t int
@ -21,10 +22,10 @@
#include <netinet/in.h>
#if !defined(__amigaos__) && !defined(__amigaos4__)
#include <poll.h>
#endif
#endif /* !defined(__amigaos__) && !defined(__amigaos4__) */
#include <errno.h>
#define MINIUPNPC_IGNORE_EINTR
#endif
#endif /* _WIN32 */
#ifdef _WIN32
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
@ -42,20 +43,20 @@ receivedata(int socket,
#if MINIUPNPC_GET_SRC_ADDR
struct sockaddr_storage src_addr;
socklen_t src_addr_len = sizeof(src_addr);
#endif
#endif /* MINIUPNPC_GET_SRC_ADDR */
int n;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
/* using poll */
struct pollfd fds[1]; /* for the poll */
#ifdef MINIUPNPC_IGNORE_EINTR
do {
#endif
#endif /* MINIUPNPC_IGNORE_EINTR */
fds[0].fd = socket;
fds[0].events = POLLIN;
n = poll(fds, 1, timeout);
#ifdef MINIUPNPC_IGNORE_EINTR
} while(n < 0 && errno == EINTR);
#endif
#endif /* MINIUPNPC_IGNORE_EINTR */
if(n < 0) {
PRINT_SOCKET_ERROR("poll");
return -1;
@ -63,7 +64,7 @@ receivedata(int socket,
/* timeout */
return 0;
}
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
/* using select under _WIN32 and amigaos */
fd_set socketSet;
TIMEVAL timeval;
@ -78,13 +79,14 @@ receivedata(int socket,
} else if(n == 0) {
return 0;
}
#endif
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
#if MINIUPNPC_GET_SRC_ADDR
memset(&src_addr, 0, sizeof(src_addr));
n = recvfrom(socket, data, length, 0,
(struct sockaddr *)&src_addr, &src_addr_len);
#else
#else /* MINIUPNPC_GET_SRC_ADDR */
n = recv(socket, data, length, 0);
#endif
#endif /* MINIUPNPC_GET_SRC_ADDR */
if(n<0) {
PRINT_SOCKET_ERROR("recv");
}
@ -93,12 +95,11 @@ receivedata(int socket,
const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr;
#ifdef DEBUG
printf("scope_id=%u\n", src_addr6->sin6_scope_id);
#endif
#endif /* DEBUG */
if(scope_id)
*scope_id = src_addr6->sin6_scope_id;
}
#endif
#endif /* MINIUPNPC_GET_SRC_ADDR */
return n;
}

View File

@ -1,4 +1,4 @@
/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */
/* $Id: receivedata.h,v 1.3 2012/06/23 22:34:47 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard

View File

@ -1,715 +0,0 @@
/* $Id: upnpc.c,v 1.99 2013/02/06 12:56:41 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2013 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
#else
/* for IPPROTO_TCP / IPPROTO_UDP */
#include <netinet/in.h>
#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;
if(UPNP_GetConnectionTypeInfo(urls->controlURL,
data->first.servicetype,
connectionType) != UPNPCOMMAND_SUCCESS)
printf("GetConnectionTypeInfo failed.\n");
else
printf("Connection Type : %s\n", connectionType);
if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS)
printf("GetStatusInfo failed.\n");
else
printf("Status : %s, uptime=%us, LastConnectionError : %s\n",
status, uptime, lastconnerr);
timenow = time(NULL);
timestarted = timenow - uptime;
printf(" Time started : %s", ctime(&timestarted));
if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype,
&brDown, &brUp) != UPNPCOMMAND_SUCCESS) {
printf("GetLinkLayerMaxBitRates failed.\n");
} else {
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 failed. (errorcode=%d)\n", r);
} else {
printf("ExternalIPAddress = %s\n", externalIPAddress);
}
}
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);*/
printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
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)
{
printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
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,
const char * description)
{
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, description,
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;
char proto_tmp[8];
if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time)
{
fprintf(stderr, "Wrong arguments\n");
return;
}
if(atoi(proto) == 0)
{
const char * protocol;
protocol = protofix(proto);
if(protocol && (strcmp("TCP", protocol) == 0))
{
snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP);
proto = proto_tmp;
}
else if(protocol && (strcmp("UDP", protocol) == 0))
{
snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP);
proto = proto_tmp;
}
else
{
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",
remoteaddr, eport, intaddr, iport, r, strupnperror(r));
else
{
printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n",
remoteaddr, eport, intaddr, iport, 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;
const char * description = 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) 2005-2013 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 if(argv[i][1] == 'e')
description = argv[++i];
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, " -e description : set description for port mapping.\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 v4 or 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",
description);
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",
description);
}
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;
}

View File

@ -1,7 +1,7 @@
/* $Id: upnpcommands.c,v 1.40 2012/06/23 22:36:35 nanard Exp $ */
/* $Id: upnpcommands.c,v 1.46 2015/07/15 12:19:00 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
@ -20,7 +20,7 @@ my_atoui(const char * s)
/*
* */
LIBSPEC UNSIGNED_INTEGER
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalBytesSent(const char * controlURL,
const char * servicetype)
{
@ -44,7 +44,7 @@ UPNP_GetTotalBytesSent(const char * controlURL,
/*
* */
LIBSPEC UNSIGNED_INTEGER
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalBytesReceived(const char * controlURL,
const char * servicetype)
{
@ -68,7 +68,7 @@ UPNP_GetTotalBytesReceived(const char * controlURL,
/*
* */
LIBSPEC UNSIGNED_INTEGER
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalPacketsSent(const char * controlURL,
const char * servicetype)
{
@ -92,7 +92,7 @@ UPNP_GetTotalPacketsSent(const char * controlURL,
/*
* */
LIBSPEC UNSIGNED_INTEGER
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalPacketsReceived(const char * controlURL,
const char * servicetype)
{
@ -116,7 +116,7 @@ UPNP_GetTotalPacketsReceived(const char * controlURL,
/* UPNP_GetStatusInfo() call the corresponding UPNP method
* returns the current status and uptime */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetStatusInfo(const char * controlURL,
const char * servicetype,
char * status,
@ -159,7 +159,7 @@ UPNP_GetStatusInfo(const char * controlURL,
if(up)
sscanf(up,"%u",uptime);
else
uptime = 0;
*uptime = 0;
}
if(lastconnerror) {
@ -181,7 +181,7 @@ UPNP_GetStatusInfo(const char * controlURL,
/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method
* returns the connection type */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetConnectionTypeInfo(const char * controlURL,
const char * servicetype,
char * connectionType)
@ -224,7 +224,7 @@ UPNP_GetConnectionTypeInfo(const char * controlURL,
* One of the values can be null
* Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only
* We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetLinkLayerMaxBitRates(const char * controlURL,
const char * servicetype,
unsigned int * bitrateDown,
@ -293,7 +293,7 @@ UPNP_GetLinkLayerMaxBitRates(const char * controlURL,
* 402 Invalid Args - See UPnP Device Architecture section on Control.
* 501 Action Failed - See UPnP Device Architecture section on Control.
*/
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetExternalIPAddress(const char * controlURL,
const char * servicetype,
char * extIpAdd)
@ -333,15 +333,15 @@ UPNP_GetExternalIPAddress(const char * controlURL,
return ret;
}
LIBSPEC int
MINIUPNP_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)
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;
@ -354,6 +354,8 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
if(AddPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
AddPortMappingArgs[0].elt = "NewRemoteHost";
AddPortMappingArgs[0].val = remoteHost;
AddPortMappingArgs[1].elt = "NewExternalPort";
@ -394,7 +396,76 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
return ret;
}
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_AddAnyPortMapping(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,
char * reservedPort)
{
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));
if(AddPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
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,
"AddAnyPortMapping", AddPortMappingArgs,
&bufsize))) {
free(AddPortMappingArgs);
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 {
char *p;
p = GetValueFromNameValueList(&pdata, "NewReservedPort");
if(p) {
strncpy(reservedPort, p, 6);
reservedPort[5] = '\0';
ret = UPNPCOMMAND_SUCCESS;
} else {
ret = UPNPCOMMAND_INVALID_RESPONSE;
}
}
ClearNameValueList(&pdata);
free(AddPortMappingArgs);
return ret;
}
MINIUPNP_LIBSPEC int
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
const char * extPort, const char * proto,
const char * remoteHost)
@ -411,6 +482,8 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg));
if(DeletePortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePortMappingArgs[0].elt = "NewRemoteHost";
DeletePortMappingArgs[0].val = remoteHost;
DeletePortMappingArgs[1].elt = "NewExternalPort";
@ -438,7 +511,55 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
return ret;
}
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
const char * extPortStart, const char * extPortEnd,
const char * proto,
const char * manage)
{
struct UPNParg * DeletePortMappingArgs;
char * buffer;
int bufsize;
struct NameValueParserData pdata;
const char * resVal;
int ret;
if(!extPortStart || !extPortEnd || !proto || !manage)
return UPNPCOMMAND_INVALID_ARGS;
DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg));
if(DeletePortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePortMappingArgs[0].elt = "NewStartPort";
DeletePortMappingArgs[0].val = extPortStart;
DeletePortMappingArgs[1].elt = "NewEndPort";
DeletePortMappingArgs[1].val = extPortEnd;
DeletePortMappingArgs[2].elt = "NewProtocol";
DeletePortMappingArgs[2].val = proto;
DeletePortMappingArgs[3].elt = "NewManage";
DeletePortMappingArgs[3].val = manage;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"DeletePortMappingRange",
DeletePortMappingArgs, &bufsize))) {
free(DeletePortMappingArgs);
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;
}
ClearNameValueList(&pdata);
free(DeletePortMappingArgs);
return ret;
}
MINIUPNP_LIBSPEC int
UPNP_GetGenericPortMappingEntry(const char * controlURL,
const char * servicetype,
const char * index,
@ -462,6 +583,8 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
intClient[0] = '\0';
intPort[0] = '\0';
GetPortMappingArgs = calloc(2, sizeof(struct UPNParg));
if(GetPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPortMappingArgs[0].elt = "NewPortMappingIndex";
GetPortMappingArgs[0].val = index;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -533,7 +656,7 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
return r;
}
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
const char * servicetype,
unsigned int * numEntries)
@ -574,11 +697,12 @@ UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
/* 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
MINIUPNP_LIBSPEC int
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
const char * servicetype,
const char * extPort,
const char * proto,
const char * proto,
const char * remoteHost,
char * intClient,
char * intPort,
char * desc,
@ -596,8 +720,10 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
return UPNPCOMMAND_INVALID_ARGS;
GetPortMappingArgs = calloc(4, sizeof(struct UPNParg));
if(GetPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPortMappingArgs[0].elt = "NewRemoteHost";
/* TODO : add remote host ? */
GetPortMappingArgs[0].val = remoteHost;
GetPortMappingArgs[1].elt = "NewExternalPort";
GetPortMappingArgs[1].val = extPort;
GetPortMappingArgs[2].elt = "NewProtocol";
@ -665,7 +791,7 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
* 733 InconsistantParameters - NewStartPort and NewEndPort values are not
* consistent.
*/
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetListOfPortMappings(const char * controlURL,
const char * servicetype,
const char * startPort,
@ -685,6 +811,8 @@ UPNP_GetListOfPortMappings(const char * controlURL,
return UPNPCOMMAND_INVALID_ARGS;
GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg));
if(GetListOfPortMappingsArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetListOfPortMappingsArgs[0].elt = "NewStartPort";
GetListOfPortMappingsArgs[0].val = startPort;
GetListOfPortMappingsArgs[1].elt = "NewEndPort";
@ -747,7 +875,7 @@ UPNP_GetListOfPortMappings(const char * controlURL,
}
/* IGD:2, functions for service WANIPv6FirewallControl:1 */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetFirewallStatus(const char * controlURL,
const char * servicetype,
int * firewallEnabled,
@ -759,7 +887,7 @@ UPNP_GetFirewallStatus(const char * controlURL,
char * fe, *ipa, *p;
int ret = UPNPCOMMAND_UNKNOWN_ERROR;
if(!firewallEnabled && !inboundPinholeAllowed)
if(!firewallEnabled || !inboundPinholeAllowed)
return UPNPCOMMAND_INVALID_ARGS;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -791,7 +919,7 @@ UPNP_GetFirewallStatus(const char * controlURL,
return ret;
}
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
const char * remoteHost,
const char * remotePort,
@ -812,6 +940,8 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
return UPNPCOMMAND_INVALID_ARGS;
GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg));
if(GetOutboundPinholeTimeoutArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost";
GetOutboundPinholeTimeoutArgs[0].val = remoteHost;
GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort";
@ -846,7 +976,7 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
return ret;
}
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_AddPinhole(const char * controlURL, const char * servicetype,
const char * remoteHost,
const char * remotePort,
@ -868,6 +998,8 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
AddPinholeArgs = calloc(7, sizeof(struct UPNParg));
if(AddPinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
/* RemoteHost can be wilcarded */
if(strncmp(remoteHost, "empty", 5)==0)
{
@ -925,7 +1057,7 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
return ret;
}
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
const char * uniqueID,
const char * leaseTime)
@ -941,6 +1073,8 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg));
if(UpdatePinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
UpdatePinholeArgs[0].elt = "UniqueID";
UpdatePinholeArgs[0].val = uniqueID;
UpdatePinholeArgs[1].elt = "NewLeaseTime";
@ -967,7 +1101,7 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
return ret;
}
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID)
{
/*struct NameValueParserData pdata;*/
@ -982,6 +1116,8 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char
return UPNPCOMMAND_INVALID_ARGS;
DeletePinholeArgs = calloc(2, sizeof(struct UPNParg));
if(DeletePinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePinholeArgs[0].elt = "UniqueID";
DeletePinholeArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -1006,7 +1142,7 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char
return ret;
}
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
const char * uniqueID, int * isWorking)
{
@ -1021,6 +1157,8 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg));
if(CheckPinholeWorkingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
CheckPinholeWorkingArgs[0].elt = "UniqueID";
CheckPinholeWorkingArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -1051,7 +1189,7 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
return ret;
}
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
const char * uniqueID, int * packets)
{
@ -1066,6 +1204,8 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg));
if(GetPinholePacketsArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPinholePacketsArgs[0].elt = "UniqueID";
GetPinholePacketsArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,

View File

@ -1,7 +1,7 @@
/* $Id: upnpcommands.h,v 1.25 2012/09/27 15:42:10 nanard Exp $ */
/* $Id: upnpcommands.h,v 1.30 2015/07/15 12:21:28 nanard Exp $ */
/* Miniupnp project : http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2011 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided within this distribution */
#ifndef UPNPCOMMANDS_H_INCLUDED
@ -9,7 +9,7 @@
#include "upnpreplyparse.h"
#include "portlistingparse.h"
#include "declspec.h"
#include "miniupnpc_declspec.h"
#include "miniupnpctypes.h"
/* MiniUPnPc return codes : */
@ -17,24 +17,26 @@
#define UPNPCOMMAND_UNKNOWN_ERROR (-1)
#define UPNPCOMMAND_INVALID_ARGS (-2)
#define UPNPCOMMAND_HTTP_ERROR (-3)
#define UPNPCOMMAND_INVALID_RESPONSE (-4)
#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5)
#ifdef __cplusplus
extern "C" {
#endif
LIBSPEC UNSIGNED_INTEGER
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalBytesSent(const char * controlURL,
const char * servicetype);
LIBSPEC UNSIGNED_INTEGER
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalBytesReceived(const char * controlURL,
const char * servicetype);
LIBSPEC UNSIGNED_INTEGER
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalPacketsSent(const char * controlURL,
const char * servicetype);
LIBSPEC UNSIGNED_INTEGER
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalPacketsReceived(const char * controlURL,
const char * servicetype);
@ -43,7 +45,7 @@ UPNP_GetTotalPacketsReceived(const char * controlURL,
* Return values :
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
* or a UPnP Error code */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetStatusInfo(const char * controlURL,
const char * servicetype,
char * status,
@ -55,7 +57,7 @@ UPNP_GetStatusInfo(const char * controlURL,
* Return Values :
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
* or a UPnP Error code */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetConnectionTypeInfo(const char * controlURL,
const char * servicetype,
char * connectionType);
@ -71,7 +73,7 @@ UPNP_GetConnectionTypeInfo(const char * controlURL,
* 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
MINIUPNP_LIBSPEC int
UPNP_GetExternalIPAddress(const char * controlURL,
const char * servicetype,
char * extIpAdd);
@ -82,7 +84,7 @@ UPNP_GetExternalIPAddress(const char * controlURL,
* return values :
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
* or a UPnP Error Code. */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
const char* servicetype,
unsigned int * bitrateDown,
@ -100,6 +102,8 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
* 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.
* 606 Action not authorized - The action requested REQUIRES authorization and
* the sender was not authorized.
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
* wild-carded
* 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
@ -112,16 +116,56 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
* 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
* cannot be a specific port value
* 728 NoPortMapsAvailable - There are not enough free ports available to
* complete port mapping.
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed
* due to conflict with other mechanisms.
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded
*/
MINIUPNP_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);
const char * extPort,
const char * inPort,
const char * inClient,
const char * desc,
const char * proto,
const char * remoteHost,
const char * leaseDuration);
/* UPNP_AddAnyPortMapping()
* 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.
* 606 Action not authorized - The action requested REQUIRES authorization and
* the sender was not authorized.
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
* wild-carded
* 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
* 728 NoPortMapsAvailable - There are not enough free ports available to
* complete port mapping.
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed
* due to conflict with other mechanisms.
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded
*/
MINIUPNP_LIBSPEC int
UPNP_AddAnyPortMapping(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,
char * reservedPort);
/* UPNP_DeletePortMapping()
* Use same argument values as what was used for AddPortMapping().
@ -132,15 +176,36 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
*
* List of possible UPnP errors for DeletePortMapping :
* 402 Invalid Args - See UPnP Device Architecture section on Control.
* 606 Action not authorized - The action requested REQUIRES authorization
* and the sender was not authorized.
* 714 NoSuchEntryInArray - The specified value does not exist in the array */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
const char * extPort, const char * proto,
const char * remoteHost);
const char * extPort, const char * proto,
const char * remoteHost);
/* UPNP_DeletePortRangeMapping()
* 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 :
* 606 Action not authorized - The action requested REQUIRES authorization
* and the sender was not authorized.
* 730 PortMappingNotFound - This error message is returned if no port
* mapping is found in the specified range.
* 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */
MINIUPNP_LIBSPEC int
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
const char * extPortStart, const char * extPortEnd,
const char * proto,
const char * manage);
/* UPNP_GetPortMappingNumberOfEntries()
* not supported by all routers */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
const char* servicetype,
unsigned int * num);
@ -150,6 +215,7 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
* params :
* in extPort
* in proto
* in remoteHost
* out intClient (16 bytes)
* out intPort (6 bytes)
* out desc (80 bytes)
@ -158,12 +224,21 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
*
* return value :
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
* or a UPnP Error Code. */
LIBSPEC int
* or a UPnP Error Code.
*
* List of possible UPnP errors for _GetSpecificPortMappingEntry :
* 402 Invalid Args - See UPnP Device Architecture section on Control.
* 501 Action Failed - See UPnP Device Architecture section on Control.
* 606 Action not authorized - The action requested REQUIRES authorization
* and the sender was not authorized.
* 714 NoSuchEntryInArray - The specified value does not exist in the array.
*/
MINIUPNP_LIBSPEC int
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
const char * servicetype,
const char * extPort,
const char * proto,
const char * remoteHost,
char * intClient,
char * intPort,
char * desc,
@ -188,9 +263,11 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
*
* Possible UPNP Error codes :
* 402 Invalid Args - See UPnP Device Architecture section on Control.
* 606 Action not authorized - The action requested REQUIRES authorization
* and the sender was not authorized.
* 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds
*/
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetGenericPortMappingEntry(const char * controlURL,
const char * servicetype,
const char * index,
@ -212,7 +289,7 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
* 733 InconsistantParameters - NewStartPort and NewEndPort values are not
* consistent.
*/
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetListOfPortMappings(const char * controlURL,
const char * servicetype,
const char * startPort,
@ -222,13 +299,13 @@ UPNP_GetListOfPortMappings(const char * controlURL,
struct PortMappingParserData * data);
/* IGD:2, functions for service WANIPv6FirewallControl:1 */
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetFirewallStatus(const char * controlURL,
const char * servicetype,
int * firewallEnabled,
int * inboundPinholeAllowed);
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
const char * remoteHost,
const char * remotePort,
@ -237,7 +314,7 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
const char * proto,
int * opTimeout);
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_AddPinhole(const char * controlURL, const char * servicetype,
const char * remoteHost,
const char * remotePort,
@ -247,19 +324,19 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
const char * leaseTime,
char * uniqueID);
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
const char * uniqueID,
const char * leaseTime);
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID);
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
const char * uniqueID, int * isWorking);
LIBSPEC int
MINIUPNP_LIBSPEC int
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
const char * uniqueID, int * packets);

23
Externals/miniupnpc/src/upnpdev.c vendored Normal file
View File

@ -0,0 +1,23 @@
/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#include <stdlib.h>
#include "upnpdev.h"
/* freeUPNPDevlist() should be used to
* free the chained list returned by upnpDiscover() */
void freeUPNPDevlist(struct UPNPDev * devlist)
{
struct UPNPDev * next;
while(devlist)
{
next = devlist->pNext;
free(devlist);
devlist = next;
}
}

36
Externals/miniupnpc/src/upnpdev.h vendored Normal file
View File

@ -0,0 +1,36 @@
/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#ifndef UPNPDEV_H_INCLUDED
#define UPNPDEV_H_INCLUDED
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {
#endif
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
unsigned int scope_id;
char * usn;
char buffer[3];
};
/* freeUPNPDevlist()
* free list returned by upnpDiscover() */
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
#ifdef __cplusplus
}
#endif
#endif /* UPNPDEV_H_INCLUDED */

View File

@ -1,4 +1,4 @@
/* $Id: upnperrors.c,v 1.6 2012/03/15 01:02:03 nanard Exp $ */
/* $Id: upnperrors.c,v 1.5 2011/04/10 11:19:36 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2007 Thomas Bernard
@ -24,6 +24,9 @@ const char * strupnperror(int err)
case UPNPCOMMAND_INVALID_ARGS:
s = "Miniupnpc Invalid Arguments";
break;
case UPNPCOMMAND_INVALID_RESPONSE:
s = "Miniupnpc Invalid response";
break;
case UPNPDISCOVER_SOCKET_ERROR:
s = "Miniupnpc Socket error";
break;

View File

@ -1,5 +1,5 @@
/* $Id: upnperrors.h,v 1.4 2012/09/27 15:42:11 nanard Exp $ */
/* (c) 2007 Thomas Bernard
/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */
/* (c) 2007-2015 Thomas Bernard
* All rights reserved.
* MiniUPnP Project.
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -8,7 +8,7 @@
#ifndef UPNPERRORS_H_INCLUDED
#define UPNPERRORS_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {
@ -17,7 +17,7 @@ extern "C" {
/* strupnperror()
* Return a string description of the UPnP error code
* or NULL for undefinded errors */
LIBSPEC const char * strupnperror(int err);
MINIUPNP_LIBSPEC const char * strupnperror(int err);
#ifdef __cplusplus
}

View File

@ -1,7 +1,7 @@
/* $Id: upnpreplyparse.c,v 1.12 2012/03/05 19:42:48 nanard Exp $ */
/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2011 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -15,18 +15,65 @@
static void
NameValueParserStartElt(void * d, const char * name, int l)
{
struct NameValueParserData * data = (struct NameValueParserData *)d;
struct NameValueParserData * data = (struct NameValueParserData *)d;
data->topelt = 1;
if(l>63)
l = 63;
memcpy(data->curelt, name, l);
data->curelt[l] = '\0';
data->cdata = NULL;
data->cdatalen = 0;
}
static void
NameValueParserEndElt(void * d, const char * name, int l)
{
struct NameValueParserData * data = (struct NameValueParserData *)d;
struct NameValue * nv;
(void)name;
(void)l;
if(!data->topelt)
return;
if(strcmp(data->curelt, "NewPortListing") != 0)
{
int l;
/* standard case. Limited to n chars strings */
l = data->cdatalen;
nv = malloc(sizeof(struct NameValue));
if(nv == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserEndElt");
#endif /* DEBUG */
return;
}
if(l>=(int)sizeof(nv->value))
l = sizeof(nv->value) - 1;
strncpy(nv->name, data->curelt, 64);
nv->name[63] = '\0';
if(data->cdata != NULL)
{
memcpy(nv->value, data->cdata, l);
nv->value[l] = '\0';
}
else
{
nv->value[0] = '\0';
}
nv->l_next = data->l_head; /* insert in list */
data->l_head = nv;
}
data->cdata = NULL;
data->cdatalen = 0;
data->topelt = 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 */
@ -34,6 +81,10 @@ NameValueParserGetData(void * d, const char * datas, int l)
if(!data->portListing)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserGetData");
#endif /* DEBUG */
return;
}
memcpy(data->portListing, datas, l);
@ -42,15 +93,9 @@ NameValueParserGetData(void * d, const char * datas, int 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);
/* standard case. */
data->cdata = datas;
data->cdatalen = l;
}
}
@ -58,19 +103,19 @@ void
ParseNameValue(const char * buffer, int bufsize,
struct NameValueParserData * data)
{
struct xmlparser parser;
LIST_INIT(&(data->head));
struct xmlparser parser;
data->l_head = NULL;
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;
/* init xmlparser object */
parser.xmlstart = buffer;
parser.xmlsize = bufsize;
parser.data = data;
parser.starteltfunc = NameValueParserStartElt;
parser.endeltfunc = NameValueParserEndElt;
parser.datafunc = NameValueParserGetData;
parser.attfunc = 0;
parsexml(&parser);
parsexml(&parser);
}
void
@ -83,9 +128,9 @@ ClearNameValueList(struct NameValueParserData * pdata)
pdata->portListing = NULL;
pdata->portListingLength = 0;
}
while((nv = pdata->head.lh_first) != NULL)
while((nv = pdata->l_head) != NULL)
{
LIST_REMOVE(nv, entries);
pdata->l_head = nv->l_next;
free(nv);
}
}
@ -96,9 +141,9 @@ GetValueFromNameValueList(struct NameValueParserData * pdata,
{
struct NameValue * nv;
char * p = NULL;
for(nv = pdata->head.lh_first;
for(nv = pdata->l_head;
(nv != NULL) && (p == NULL);
nv = nv->entries.le_next)
nv = nv->l_next)
{
if(strcmp(nv->name, Name) == 0)
p = nv->value;
@ -140,13 +185,13 @@ DisplayNameValueList(char * buffer, int bufsize)
struct NameValueParserData pdata;
struct NameValue * nv;
ParseNameValue(buffer, bufsize, &pdata);
for(nv = pdata.head.lh_first;
for(nv = pdata.l_head;
nv != NULL;
nv = nv->entries.le_next)
nv = nv->l_next)
{
printf("%s = %s\n", nv->name, nv->value);
}
ClearNameValueList(&pdata);
}
#endif
#endif /* DEBUG */

View File

@ -1,34 +1,31 @@
/* $Id: upnpreplyparse.h,v 1.14 2012/09/27 15:42:11 nanard Exp $ */
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2012 Thomas Bernard
* (c) 2006-2013 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef UPNPREPLYPARSE_H_INCLUDED
#define UPNPREPLYPARSE_H_INCLUDED
#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 NameValue * l_next;
char name[64];
char value[128];
};
struct NameValueParserData {
LIST_HEAD(listhead, NameValue) head;
char curelt[64];
struct NameValue * l_head;
char curelt[64];
char * portListing;
int portListingLength;
int topelt;
const char * cdata;
int cdatalen;
};
/* ParseNameValue() */
@ -45,10 +42,12 @@ char *
GetValueFromNameValueList(struct NameValueParserData * pdata,
const char * Name);
#if 0
/* GetValueFromNameValueListIgnoreNS() */
char *
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
const char * Name);
#endif
/* DisplayNameValueList() */
#ifdef DEBUG