1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Merge pull request #107161 from akien-mga/miniupnpc-2.3.3

miniupnpc: Update to 2.3.3
This commit is contained in:
Rémi Verschelde
2025-06-14 00:00:07 +02:00
24 changed files with 1240 additions and 654 deletions

View File

@@ -416,7 +416,7 @@ License: CC0-1.0
Files: thirdparty/miniupnpc/* Files: thirdparty/miniupnpc/*
Comment: MiniUPnP Project Comment: MiniUPnP Project
Copyright: 2005-2024, Thomas Bernard Copyright: 2005-2025, Thomas Bernard
License: BSD-3-clause License: BSD-3-clause
Files: thirdparty/minizip/* Files: thirdparty/minizip/*

View File

@@ -717,7 +717,7 @@ Patches:
## miniupnpc ## miniupnpc
- Upstream: https://github.com/miniupnp/miniupnp - Upstream: https://github.com/miniupnp/miniupnp
- Version: 2.2.8 (b55145ec095652289a59c33603f3abafee898273, 2024) - Version: 2.3.3 (bf4215a7574f88aa55859db9db00e3ae58cf42d6, 2025)
- License: BSD-3-Clause - License: BSD-3-Clause
Files extracted from upstream source: Files extracted from upstream source:

View File

@@ -1,6 +1,6 @@
BSD 3-Clause License BSD 3-Clause License
Copyright (c) 2005-2024, Thomas BERNARD Copyright (c) 2005-2025, Thomas BERNARD
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@@ -1,46 +1,72 @@
/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */ /* $Id: igd_desc_parse.h,v 1.14 2025/02/08 23:15:16 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* http://miniupnp.free.fr/ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard * Copyright (c) 2005-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
#ifndef IGD_DESC_PARSE_H_INCLUDED #ifndef IGD_DESC_PARSE_H_INCLUDED
#define IGD_DESC_PARSE_H_INCLUDED #define IGD_DESC_PARSE_H_INCLUDED
/* Structure to store the result of the parsing of UPnP /*! \file igd_desc_parse.h
* descriptions of Internet Gateway Devices */ * \brief API to parse UPNP device description XML
* \todo should not be exposed in the public API
*/
/*! \brief maximum lenght of URLs */
#define MINIUPNPC_URL_MAXSIZE (128) #define MINIUPNPC_URL_MAXSIZE (128)
/*! \brief Structure to store the result of the parsing of UPnP
* descriptions of Internet Gateway Devices services */
struct IGDdatas_service { struct IGDdatas_service {
/*! \brief controlURL for the service */
char controlurl[MINIUPNPC_URL_MAXSIZE]; char controlurl[MINIUPNPC_URL_MAXSIZE];
/*! \brief eventSubURL for the service */
char eventsuburl[MINIUPNPC_URL_MAXSIZE]; char eventsuburl[MINIUPNPC_URL_MAXSIZE];
/*! \brief SCPDURL for the service */
char scpdurl[MINIUPNPC_URL_MAXSIZE]; char scpdurl[MINIUPNPC_URL_MAXSIZE];
/*! \brief serviceType */
char servicetype[MINIUPNPC_URL_MAXSIZE]; char servicetype[MINIUPNPC_URL_MAXSIZE];
/*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/
}; };
/*! \brief Structure to store the result of the parsing of UPnP
* descriptions of Internet Gateway Devices */
struct IGDdatas { struct IGDdatas {
/*! \brief current element name */
char cureltname[MINIUPNPC_URL_MAXSIZE]; char cureltname[MINIUPNPC_URL_MAXSIZE];
/*! \brief URLBase */
char urlbase[MINIUPNPC_URL_MAXSIZE]; char urlbase[MINIUPNPC_URL_MAXSIZE];
/*! \brief presentationURL */
char presentationurl[MINIUPNPC_URL_MAXSIZE]; char presentationurl[MINIUPNPC_URL_MAXSIZE];
/*! \brief depth into the XML tree */
int level; int level;
/*int state;*/ /*! \brief "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
/* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
struct IGDdatas_service CIF; struct IGDdatas_service CIF;
/* "urn:schemas-upnp-org:service:WANIPConnection:1" /*! \brief first of "urn:schemas-upnp-org:service:WANIPConnection:1"
* "urn:schemas-upnp-org:service:WANPPPConnection:1" */ * or "urn:schemas-upnp-org:service:WANPPPConnection:1" */
struct IGDdatas_service first; struct IGDdatas_service first;
/* if both WANIPConnection and WANPPPConnection are present */ /*! \brief second of "urn:schemas-upnp-org:service:WANIPConnection:1"
* or "urn:schemas-upnp-org:service:WANPPPConnection:1" */
struct IGDdatas_service second; struct IGDdatas_service second;
/* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ /*! \brief "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */
struct IGDdatas_service IPv6FC; struct IGDdatas_service IPv6FC;
/* tmp */ /*! \brief currently parsed service */
struct IGDdatas_service tmp; struct IGDdatas_service tmp;
}; };
/*!
* \brief XML start element handler
*/
void IGDstartelt(void *, const char *, int); void IGDstartelt(void *, const char *, int);
/*!
* \brief XML end element handler
*/
void IGDendelt(void *, const char *, int); void IGDendelt(void *, const char *, int);
/*!
* \brief XML characted data handler
*/
void IGDdata(void *, const char *, int); void IGDdata(void *, const char *, int);
#ifdef DEBUG #ifdef DEBUG
void printIGD(struct IGDdatas *); void printIGD(struct IGDdatas *);

View File

@@ -1,32 +1,54 @@
/* $Id: miniupnpc.h,v 1.66 2024/06/08 22:13:14 nanard Exp $ */ /* $Id: miniupnpc.h,v 1.80 2025/05/26 22:56:40 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project: miniupnp * Project: miniupnp
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author: Thomas Bernard * Author: Thomas Bernard
* Copyright (c) 2005-2024 Thomas Bernard * Copyright (c) 2005-2025 Thomas Bernard
* This software is subjects to the conditions detailed * This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */ * in the LICENCE file provided within this distribution */
#ifndef MINIUPNPC_H_INCLUDED #ifndef MINIUPNPC_H_INCLUDED
#define MINIUPNPC_H_INCLUDED #define MINIUPNPC_H_INCLUDED
/*! \file miniupnpc.h
* \brief Main C API for MiniUPnPc
*
* Contains functions to discover devices and check for device validity
* or connectivity.
*
* \mainpage MiniUPnPc API documentation
* MiniUPnPc (MiniUPnP client) is a library implementing a UPnP
* Internet Gateway Device (IGD) control point.
*
* It should be used by applications that need to listen to incoming
* traffic from the internet which are running on a LAN where a
* UPnP IGD is running on the router (or gateway).
*
* See more documentation on the website http://miniupnp.free.fr
* or https://miniupnp.tuxfamily.org/ or GitHub :
* https://github.com/miniupnp/miniupnp/tree/master/miniupnpc
*/
#include "miniupnpc_declspec.h" #include "miniupnpc_declspec.h"
#include "igd_desc_parse.h" #include "igd_desc_parse.h"
#include "upnpdev.h" #include "upnpdev.h"
/* error codes : */ /* error codes : */
/*! \brief value for success */
#define UPNPDISCOVER_SUCCESS (0) #define UPNPDISCOVER_SUCCESS (0)
/*! \brief value for unknown error */
#define UPNPDISCOVER_UNKNOWN_ERROR (-1) #define UPNPDISCOVER_UNKNOWN_ERROR (-1)
/*! \brief value for a socket error */
#define UPNPDISCOVER_SOCKET_ERROR (-101) #define UPNPDISCOVER_SOCKET_ERROR (-101)
/*! \brief value for a memory allocation error */
#define UPNPDISCOVER_MEMORY_ERROR (-102) #define UPNPDISCOVER_MEMORY_ERROR (-102)
/* versions : */ /*! \brief software version */
#define MINIUPNPC_VERSION "2.2.8" #define MINIUPNPC_VERSION "2.3.3"
#define MINIUPNPC_API_VERSION 18 /*! \brief C API version */
#define MINIUPNPC_API_VERSION 21
/* Source port: /*! \brief any (ie system chosen) port */
Using "1" as an alias for 1900 for backwards compatibility
(presuming one would have used that for the "sameport" parameter) */
#define UPNP_LOCAL_PORT_ANY 0 #define UPNP_LOCAL_PORT_ANY 0
/*! \brief Use as an alias for 1900 for backwards compatibility */
#define UPNP_LOCAL_PORT_SAME 1 #define UPNP_LOCAL_PORT_SAME 1
#ifdef __cplusplus #ifdef __cplusplus
@@ -34,49 +56,126 @@ extern "C" {
#endif #endif
/* Structures definitions : */ /* Structures definitions : */
struct UPNParg { const char * elt; const char * val; };
/*!
* \brief UPnP method argument
*/
struct UPNParg {
const char * elt; /*!< \brief UPnP argument name */
const char * val; /*!< \brief UPnP argument value */
};
/*!
* \brief execute a UPnP method (SOAP action)
*
* \todo error reporting should be improved
*
* \param[in] url Control URL for the service
* \param[in] service service to use
* \param[in] action action to call
* \param[in] args action arguments
* \param[out] bufsize the size of the returned buffer
* \return NULL in case of error or the raw XML response
*/
char * char *
simpleUPnPcommand(int, const char *, const char *, simpleUPnPcommand(const char * url, const char * service,
const char *, struct UPNParg *, const char * action, const struct UPNParg * args,
int *); int * bufsize);
/* upnpDiscover() /*!
* discover UPnP devices on the network. * \brief Discover UPnP IGD on the network.
*
* The discovered devices are returned as a chained list. * The discovered devices are returned as a chained list.
* It is up to the caller to free the list with freeUPNPDevlist(). * It is up to the caller to free the list with freeUPNPDevlist().
* delay (in millisecond) is the maximum time for waiting any device
* response.
* If available, device list will be obtained from MiniSSDPd. * If available, device list will be obtained from MiniSSDPd.
* Default path for minissdpd socket will be used if minissdpdsock argument *
* is NULL. * \param[in] delay (in millisecond) maximum time for waiting any device
* If multicastif is not NULL, it will be used instead of the default * response
* multicast interface for sending SSDP discover packets. * \param[in] multicastif If not NULL, used instead of the default
* If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent * multicast interface for sending SSDP discover packets
* from the source port 1900 (same as destination port), if set to * \param[in] minissdpdsock Path to minissdpd socket, default is used if
* UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will * NULL
* be attempted as the source port. * \param[in] localport Source port to send SSDP packets.
* "searchalltypes" parameter is useful when searching several types, * #UPNP_LOCAL_PORT_SAME for 1900 (same as destination port)
* if 0, the discovery will stop with the first type returning results. * #UPNP_LOCAL_PORT_ANY to let system assign a source port
* TTL should default to 2. */ * \param[in] ipv6 0 for IPv4, 1 of IPv6
* \param[in] ttl should default to 2 as advised by UDA 1.1
* \param[out] error error code when NULL is returned
* \return NULL or a linked list
*/
MINIUPNP_LIBSPEC struct UPNPDev * MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif, upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int localport, const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl, int ipv6, unsigned char ttl,
int * error); int * error);
/*!
* \brief Discover all UPnP devices on the network
*
* search for "ssdp:all"
* \param[in] delay (in millisecond) maximum time for waiting any device
* response
* \param[in] multicastif If not NULL, used instead of the default
* multicast interface for sending SSDP discover packets
* \param[in] minissdpdsock Path to minissdpd socket, default is used if
* NULL
* \param[in] localport Source port to send SSDP packets.
* #UPNP_LOCAL_PORT_SAME for 1900 (same as destination port)
* #UPNP_LOCAL_PORT_ANY to let system assign a source port
* \param[in] ipv6 0 for IPv4, 1 of IPv6
* \param[in] ttl should default to 2 as advised by UDA 1.1
* \param[out] error error code when NULL is returned
* \return NULL or a linked list
*/
MINIUPNP_LIBSPEC struct UPNPDev * MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverAll(int delay, const char * multicastif, upnpDiscoverAll(int delay, const char * multicastif,
const char * minissdpdsock, int localport, const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl, int ipv6, unsigned char ttl,
int * error); int * error);
/*!
* \brief Discover one type of UPnP devices
*
* \param[in] device device type to search
* \param[in] delay (in millisecond) maximum time for waiting any device
* response
* \param[in] multicastif If not NULL, used instead of the default
* multicast interface for sending SSDP discover packets
* \param[in] minissdpdsock Path to minissdpd socket, default is used if
* NULL
* \param[in] localport Source port to send SSDP packets.
* #UPNP_LOCAL_PORT_SAME for 1900 (same as destination port)
* #UPNP_LOCAL_PORT_ANY to let system assign a source port
* \param[in] ipv6 0 for IPv4, 1 of IPv6
* \param[in] ttl should default to 2 as advised by UDA 1.1
* \param[out] error error code when NULL is returned
* \return NULL or a linked list
*/
MINIUPNP_LIBSPEC struct UPNPDev * MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif, upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
const char * minissdpdsock, int localport, const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl, int ipv6, unsigned char ttl,
int * error); int * error);
/*!
* \brief Discover one or several type of UPnP devices
*
* \param[in] deviceTypes array of device types to search (ending with NULL)
* \param[in] delay (in millisecond) maximum time for waiting any device
* response
* \param[in] multicastif If not NULL, used instead of the default
* multicast interface for sending SSDP discover packets
* \param[in] minissdpdsock Path to minissdpd socket, default is used if
* NULL
* \param[in] localport Source port to send SSDP packets.
* #UPNP_LOCAL_PORT_SAME for 1900 (same as destination port)
* #UPNP_LOCAL_PORT_ANY to let system assign a source port
* \param[in] ipv6 0 for IPv4, 1 of IPv6
* \param[in] ttl should default to 2 as advised by UDA 1.1
* \param[out] error error code when NULL is returned
* \param[in] searchalltypes 0 to stop with the first type returning results
* \return NULL or a linked list
*/
MINIUPNP_LIBSPEC struct UPNPDev * MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[], upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif, int delay, const char * multicastif,
@@ -85,38 +184,60 @@ upnpDiscoverDevices(const char * const deviceTypes[],
int * error, int * error,
int searchalltypes); int searchalltypes);
/* parserootdesc() : /*!
* parse root XML description of a UPnP device and fill the IGDdatas * \brief parse root XML description of a UPnP device
* structure. */ *
MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); * fill the IGDdatas structure.
* \param[in] buffer character buffer containing the XML description
* \param[in] bufsize size in bytes of the buffer
* \param[out] data IGDdatas structure to fill
*/
MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data);
/* structure used to get fast access to urls /*!
* controlURL: controlURL of the WANIPConnection * \brief structure used to get fast access to urls
* ipcondescURL: url of the description of the WANIPConnection
* controlURL_CIF: controlURL of the WANCommonInterfaceConfig
* controlURL_6FC: controlURL of the WANIPv6FirewallControl
*/ */
struct UPNPUrls { struct UPNPUrls {
/*! \brief controlURL of the WANIPConnection */
char * controlURL; char * controlURL;
/*! \brief url of the description of the WANIPConnection */
char * ipcondescURL; char * ipcondescURL;
/*! \brief controlURL of the WANCommonInterfaceConfig */
char * controlURL_CIF; char * controlURL_CIF;
/*! \brief controlURL of the WANIPv6FirewallControl */
char * controlURL_6FC; char * controlURL_6FC;
/*! \brief url of the root description */
char * rootdescURL; char * rootdescURL;
}; };
/* UPNP_GetValidIGD() : /*! \brief NO IGD found */
* return values : #define UPNP_NO_IGD (0)
* 0 = NO IGD found /*! \brief valid and connected IGD */
* 1 = A valid connected IGD has been found #define UPNP_CONNECTED_IGD (1)
* 2 = A valid connected IGD has been found but its /*! \brief valid and connected IGD but with a reserved address
* IP address is reserved (non routable) * (non routable) */
* 3 = A valid IGD has been found but it reported as #define UPNP_PRIVATEIP_IGD (2)
* not connected /*! \brief valid but not connected IGD */
* 4 = an UPnP device has been found but was not recognized as an IGD #define UPNP_DISCONNECTED_IGD (3)
/*! \brief UPnP device not recognized as an IGD */
#define UPNP_UNKNOWN_DEVICE (4)
/*!
* \brief look for a valid and possibly connected IGD in the list
* *
* In any non zero return case, the urls and data structures * In any non zero return case, the urls and data structures
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
* free allocated memory. * free allocated memory.
* \param[in] devlist A device list obtained with upnpDiscover() /
* upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices()
* \param[out] urls Urls for the IGD found
* \param[out] data datas for the IGD found
* \param[out] lanaddr buffer to copy the local address of the host to reach the IGD
* \param[in] lanaddrlen size of the lanaddr buffer
* \param[out] wanaddr buffer to copy the public address of the IGD
* \param[in] wanaddrlen size of the wanaddr buffer
* \return #UPNP_NO_IGD / #UPNP_CONNECTED_IGD / #UPNP_PRIVATEIP_IGD /
* #UPNP_DISCONNECTED_IGD / #UPNP_UNKNOWN_DEVICE
*/ */
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetValidIGD(struct UPNPDev * devlist, UPNP_GetValidIGD(struct UPNPDev * devlist,
@@ -125,27 +246,55 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
char * lanaddr, int lanaddrlen, char * lanaddr, int lanaddrlen,
char * wanaddr, int wanaddrlen); char * wanaddr, int wanaddrlen);
/* UPNP_GetIGDFromUrl() /*!
* \brief Get IGD URLs and data for URL
*
* Used when skipping the discovery process. * Used when skipping the discovery process.
* When succeding, urls, data, and lanaddr arguments are set. * \param[in] rootdescurl Root description URL of the device
* return value : * \param[out] urls Urls for the IGD found
* 0 - Not ok * \param[out] data datas for the IGD found
* 1 - OK */ * \param[out] lanaddr buffer to copy the local address of the host to reach the IGD
* \param[in] lanaddrlen size of the lanaddr buffer
* \return 0 Not ok / 1 OK
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetIGDFromUrl(const char * rootdescurl, UPNP_GetIGDFromUrl(const char * rootdescurl,
struct UPNPUrls * urls, struct UPNPUrls * urls,
struct IGDdatas * data, struct IGDdatas * data,
char * lanaddr, int lanaddrlen); char * lanaddr, int lanaddrlen);
/*!
* \brief Prepare the URLs for usage
*
* build absolute URLs from the root description
* \param[out] urls URL structure to initialize
* \param[in] data datas for the IGD
* \param[in] descURL root description URL for the IGD
* \param[in] scope_id if not 0, add the scope to the linklocal IPv6
* addresses in URLs
*/
MINIUPNP_LIBSPEC void MINIUPNP_LIBSPEC void
GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
const char *, unsigned int); const char * descURL, unsigned int scope_id);
/*!
* \brief free the members of a UPNPUrls struct
*
* All URLs buffers are freed and zeroed
* \param[out] urls URL structure to free
*/
MINIUPNP_LIBSPEC void MINIUPNP_LIBSPEC void
FreeUPNPUrls(struct UPNPUrls *); FreeUPNPUrls(struct UPNPUrls * urls);
/* return 0 or 1 */ /*!
MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); * \brief check the current connection status of an IGD
*
* it uses UPNP_GetStatusInfo()
* \param[in] urls IGD URLs
* \param[in] data IGD data
* \return 1 Connected / 0 Disconnected
*/
MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -1,6 +1,8 @@
#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED #ifndef MINIUPNPC_DECLSPEC_H_INCLUDED
#define MINIUPNPC_DECLSPEC_H_INCLUDED #define MINIUPNPC_DECLSPEC_H_INCLUDED
/*! \file miniupnpc_declspec.h
* \brief define #MINIUPNP_LIBSPEC for dll exports and imports */
#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) #if defined(_WIN32) && !defined(MINIUPNP_STATICLIB)
/* for windows dll */ /* for windows dll */
#ifdef MINIUPNP_EXPORTS #ifdef MINIUPNP_EXPORTS
@@ -18,4 +20,3 @@
#endif #endif
#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */ #endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */

View File

@@ -1,21 +1,27 @@
/* $Id: miniupnpctypes.h,v 1.1 2011/02/15 11:10:40 nanard Exp $ */ /* $Id: miniupnpctypes.h,v 1.4 2025/02/08 23:15:16 nanard Exp $ */
/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org /* Project: miniupnp
* Author : Thomas Bernard * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org
* Copyright (c) 2021 Thomas Bernard * Author: Thomas Bernard
* Copyright (c) 2021-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided within this distribution */ * LICENCE file provided within this distribution */
#ifndef MINIUPNPCTYPES_H_INCLUDED #ifndef MINIUPNPCTYPES_H_INCLUDED
#define MINIUPNPCTYPES_H_INCLUDED #define MINIUPNPCTYPES_H_INCLUDED
/* Use unsigned long long when available : /*! \file miniupnpctypes.h
* strtoull is C99 */ * \brief type definitions
*
* Use unsigned long long when available :
* strtoull is C99
*
* \def UNSIGNED_INTEGER
* \brief `unsigned long long` or `unsigned int`
* \todo int can be 16 bits, so it should be `unsigned long`
*/
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define UNSIGNED_INTEGER unsigned long long #define UNSIGNED_INTEGER unsigned long long
#define STRTOUI strtoull
#else #else
#define UNSIGNED_INTEGER unsigned int #define UNSIGNED_INTEGER unsigned int
#define STRTOUI strtoul
#endif #endif
#endif #endif

View File

@@ -1,24 +1,51 @@
/* $Id: miniwget.h,v 1.12 2016/01/24 17:24:36 nanard Exp $ */ /* $Id: miniwget.h,v 1.14 2025/02/08 23:15:17 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2016 Thomas Bernard * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Copyright (c) 2005-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
#ifndef MINIWGET_H_INCLUDED #ifndef MINIWGET_H_INCLUDED
#define MINIWGET_H_INCLUDED #define MINIWGET_H_INCLUDED
/*! \file miniwget.h
* \brief Lightweight HTTP client API
*/
#include "miniupnpc_declspec.h" #include "miniupnpc_declspec.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int, int *); /*! \brief perform HTTP GET on an URL
*
* \param[in] url HTTP URL to GET
* \param[out] size length of the returned buffer. -1 in case of memory
* allocation error
* \param[in] scope_id interface id for IPv6 to use if not specified in the URL
* \param[out] status_code HTTP response status code (200, 404, etc.)
* \return the body of the HTTP response
*/
MINIUPNP_LIBSPEC void * miniwget(const char * url, int * size,
unsigned int scope_id, int * status_code);
MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int, int *); /*! \brief perform HTTP GET on an URL
*
int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); * Also get the local address used to reach the HTTP server
*
* \param[in] url HTTP URL to GET
* \param[out] size length of the returned buffer. -1 in case of memory
* allocation error
* \param[out] addr local address used to connect to the server
* \param[in] addrlen size of the addr buffer
* \param[in] scope_id interface id for IPv6 to use if not specified in the URL
* \param[out] status_code HTTP response status code (200, 404, etc.)
* \return the body of the HTTP response
*/
MINIUPNP_LIBSPEC void * miniwget_getaddr(const char * url, int * size,
char * addr, int addrlen,
unsigned int scope_id, int * status_code);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -1,12 +1,29 @@
/* $Id: portlistingparse.h,v 1.10 2014/11/01 10:37:32 nanard Exp $ */ /* $Id: portlistingparse.h,v 1.12 2025/02/08 23:15:17 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011-2015 Thomas Bernard * (c) 2011-2025 Thomas Bernard
* This software is subject to the conditions detailed * This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */ * in the LICENCE file provided within the distribution */
#ifndef PORTLISTINGPARSE_H_INCLUDED #ifndef PORTLISTINGPARSE_H_INCLUDED
#define PORTLISTINGPARSE_H_INCLUDED #define PORTLISTINGPARSE_H_INCLUDED
/*! \file portlistingparse.h
* \brief Parsing of the list of port mappings
*
* As returned by GetListOfPortMappings.
* Sample of PortMappingEntry :
*
* <p:PortMappingEntry>
* <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
* <p:NewExternalPort>2345</p:NewExternalPort>
* <p:NewProtocol>TCP</p:NewProtocol>
* <p:NewInternalPort>2345</p:NewInternalPort>
* <p:NewInternalClient>192.168.1.137</p:NewInternalClient>
* <p:NewEnabled>1</p:NewEnabled>
* <p:NewDescription>dooom</p:NewDescription>
* <p:NewLeaseTime>345</p:NewLeaseTime>
* </p:PortMappingEntry>
*/
#include "miniupnpc_declspec.h" #include "miniupnpc_declspec.h"
/* for the definition of UNSIGNED_INTEGER */ /* for the definition of UNSIGNED_INTEGER */
#include "miniupnpctypes.h" #include "miniupnpctypes.h"
@@ -15,17 +32,8 @@
extern "C" { extern "C" {
#endif #endif
/* sample of PortMappingEntry : /*!
<p:PortMappingEntry> * \brief enum of all XML elements
<p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
<p:NewExternalPort>2345</p:NewExternalPort>
<p:NewProtocol>TCP</p:NewProtocol>
<p:NewInternalPort>2345</p:NewInternalPort>
<p:NewInternalClient>192.168.1.137</p:NewInternalClient>
<p:NewEnabled>1</p:NewEnabled>
<p:NewDescription>dooom</p:NewDescription>
<p:NewLeaseTime>345</p:NewLeaseTime>
</p:PortMappingEntry>
*/ */
typedef enum { PortMappingEltNone, typedef enum { PortMappingEltNone,
PortMappingEntry, NewRemoteHost, PortMappingEntry, NewRemoteHost,
@@ -34,27 +42,45 @@ typedef enum { PortMappingEltNone,
NewEnabled, NewDescription, NewEnabled, NewDescription,
NewLeaseTime } portMappingElt; NewLeaseTime } portMappingElt;
/*!
* \brief linked list of port mappings
*/
struct PortMapping { struct PortMapping {
struct PortMapping * l_next; /* list next element */ struct PortMapping * l_next; /*!< \brief next list element */
UNSIGNED_INTEGER leaseTime; UNSIGNED_INTEGER leaseTime; /*!< \brief in seconds */
unsigned short externalPort; unsigned short externalPort; /*!< \brief external port */
unsigned short internalPort; unsigned short internalPort; /*!< \brief internal port */
char remoteHost[64]; char remoteHost[64]; /*!< \brief empty for wildcard */
char internalClient[64]; char internalClient[64]; /*!< \brief internal IP address */
char description[64]; char description[64]; /*!< \brief description */
char protocol[4]; char protocol[4]; /*!< \brief `TCP` or `UDP` */
unsigned char enabled; unsigned char enabled; /*!< \brief 0 (false) or 1 (true) */
}; };
/*!
* \brief structure for ParsePortListing()
*/
struct PortMappingParserData { struct PortMappingParserData {
struct PortMapping * l_head; /* list head */ struct PortMapping * l_head; /*!< \brief list head */
portMappingElt curelt; portMappingElt curelt; /*!< \brief currently parsed element */
}; };
/*!
* \brief parse the NewPortListing part of GetListOfPortMappings response
*
* \param[in] buffer XML data
* \param[in] bufsize length of XML data
* \param[out] pdata Parsed data
*/
MINIUPNP_LIBSPEC void MINIUPNP_LIBSPEC void
ParsePortListing(const char * buffer, int bufsize, ParsePortListing(const char * buffer, int bufsize,
struct PortMappingParserData * pdata); struct PortMappingParserData * pdata);
/*!
* \brief free parsed data structure
*
* \param[in] pdata Parsed data to free
*/
MINIUPNP_LIBSPEC void MINIUPNP_LIBSPEC void
FreePortListing(struct PortMappingParserData * pdata); FreePortListing(struct PortMappingParserData * pdata);

View File

@@ -1,21 +1,41 @@
/* $Id: upnpcommands.h,v 1.32 2018/03/13 23:34:47 nanard Exp $ */ /* $Id: upnpcommands.h,v 1.36 2025/03/18 23:40:15 nanard Exp $ */
/* Miniupnp project : http://miniupnp.free.fr/ /* vim: tabstop=4 shiftwidth=4 noexpandtab
* Author : Thomas Bernard * Project: miniupnp
* Copyright (c) 2005-2018 Thomas Bernard * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author: Thomas Bernard
* Copyright (c) 2005-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided within this distribution */ * LICENCE file provided within this distribution */
#ifndef UPNPCOMMANDS_H_INCLUDED #ifndef UPNPCOMMANDS_H_INCLUDED
#define UPNPCOMMANDS_H_INCLUDED #define UPNPCOMMANDS_H_INCLUDED
/*! \file upnpcommands.h
* \brief Internet Gateway Device methods
*
* See the documentation for both IGD v1 and IGD v2 :
* - https://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v1-Device.pdf
* - https://upnp.org/specs/gw/UPnP-gw-InternetGatewayDevice-v2-Device.pdf
*
* The methods are from WANIPConnection:1 or 2, WANCommonInterfaceConfig:1,
* and WANIPv6FirewallControl:1
*
*/
#include "miniupnpc_declspec.h" #include "miniupnpc_declspec.h"
#include "miniupnpctypes.h" #include "miniupnpctypes.h"
/* MiniUPnPc return codes : */ /* MiniUPnPc return codes : */
/*! \brief value for success */
#define UPNPCOMMAND_SUCCESS (0) #define UPNPCOMMAND_SUCCESS (0)
/*! \brief value for unknown error */
#define UPNPCOMMAND_UNKNOWN_ERROR (-1) #define UPNPCOMMAND_UNKNOWN_ERROR (-1)
/*! \brief error while checking the arguments */
#define UPNPCOMMAND_INVALID_ARGS (-2) #define UPNPCOMMAND_INVALID_ARGS (-2)
/*! \brief HTTP communication error */
#define UPNPCOMMAND_HTTP_ERROR (-3) #define UPNPCOMMAND_HTTP_ERROR (-3)
/*! \brief The response contains invalid values */
#define UPNPCOMMAND_INVALID_RESPONSE (-4) #define UPNPCOMMAND_INVALID_RESPONSE (-4)
/*! \brief Memory allocation error */
#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5) #define UPNPCOMMAND_MEM_ALLOC_ERROR (-5)
#ifdef __cplusplus #ifdef __cplusplus
@@ -24,27 +44,70 @@ extern "C" {
struct PortMappingParserData; struct PortMappingParserData;
/*! \brief WANCommonInterfaceConfig:GetTotalBytesSent
*
* Note: this is a 32bits unsigned value and rolls over to 0 after reaching
* the maximum value
*
* \param[in] controlURL controlURL of the WANCommonInterfaceConfig of
* a WANDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
*/
MINIUPNP_LIBSPEC UNSIGNED_INTEGER MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalBytesSent(const char * controlURL, UPNP_GetTotalBytesSent(const char * controlURL,
const char * servicetype); const char * servicetype);
/*! \brief WANCommonInterfaceConfig:GetTotalBytesReceived
*
* Note: this is a 32bits unsigned value and rolls over to 0 after reaching
* the maximum value
*
* \param[in] controlURL controlURL of the WANCommonInterfaceConfig of a WANDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
*/
MINIUPNP_LIBSPEC UNSIGNED_INTEGER MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalBytesReceived(const char * controlURL, UPNP_GetTotalBytesReceived(const char * controlURL,
const char * servicetype); const char * servicetype);
/*! \brief WANCommonInterfaceConfig:GetTotalPacketsSent
*
* Note: this is a 32bits unsigned value and rolls over to 0 after reaching
* the maximum value
*
* \param[in] controlURL controlURL of the WANCommonInterfaceConfig of a WANDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
*/
MINIUPNP_LIBSPEC UNSIGNED_INTEGER MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalPacketsSent(const char * controlURL, UPNP_GetTotalPacketsSent(const char * controlURL,
const char * servicetype); const char * servicetype);
/*! \brief WANCommonInterfaceConfig:GetTotalBytesReceived
*
* Note: this is a 32bits unsigned value and rolls over to 0 after reaching
* the maximum value
*
* \param[in] controlURL controlURL of the WANCommonInterfaceConfig of a WANDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
*/
MINIUPNP_LIBSPEC UNSIGNED_INTEGER MINIUPNP_LIBSPEC UNSIGNED_INTEGER
UPNP_GetTotalPacketsReceived(const char * controlURL, UPNP_GetTotalPacketsReceived(const char * controlURL,
const char * servicetype); const char * servicetype);
/* UPNP_GetStatusInfo() /*! \brief WANIPConnection:GetStatusInfo()
* status and lastconnerror are 64 byte buffers *
* Return values : * \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* or a UPnP Error code */ * \param[out] status 64 bytes buffer : `Unconfigured`, `Connecting`,
* `Connected`, `PendingDisconnect`, `Disconnecting`, `Disconnected`
* \param[out] uptime time in seconds
* \param[out] lastconnerror 64 bytes buffer : `ERROR_NONE`,
* `ERROR_COMMAND_ABORTED`, `ERROR_NOT_ENABLED_FOR_INTERNET`,
* `ERROR_USER_DISCONNECT`, `ERROR_ISP_DISCONNECT`,
* `ERROR_IDLE_DISCONNECT`, `ERROR_FORCED_DISCONNECT`,
* `ERROR_NO_CARRIER`, `ERROR_IP_CONFIGURATION`, `ERROR_UNKNOWN`
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP Error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetStatusInfo(const char * controlURL, UPNP_GetStatusInfo(const char * controlURL,
const char * servicetype, const char * servicetype,
@@ -52,76 +115,87 @@ UPNP_GetStatusInfo(const char * controlURL,
unsigned int * uptime, unsigned int * uptime,
char * lastconnerror); char * lastconnerror);
/* UPNP_GetConnectionTypeInfo() /*! \brief WANIPConnection:GetConnectionTypeInfo()
* argument connectionType is a 64 character buffer *
* Return Values : * \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* or a UPnP Error code */ * \param[out] connectionType 64 characters buffer : `Unconfigured`,
* `IP_Routed`, `IP_Bridged`
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP Error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetConnectionTypeInfo(const char * controlURL, UPNP_GetConnectionTypeInfo(const char * controlURL,
const char * servicetype, const char * servicetype,
char * connectionType); char * connectionType);
/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. /*! \brief WANIPConnection:GetExternalIPAddress()
* if the third arg is not null the value is copied to it.
* at least 16 bytes must be available
*
* Return values :
* 0 : SUCCESS
* NON ZERO : ERROR Either an UPnP error code or an unknown error.
* *
* possible UPnP Errors : * possible UPnP Errors :
* 402 Invalid Args - See UPnP Device Architecture section on Control. * - 402 Invalid Args - See UPnP Device Architecture section on Control.
* 501 Action Failed - See UPnP Device Architecture section on Control. */ * - 501 Action Failed - See UPnP Device Architecture section on Control.
*
* \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* \param[out] extIpAdd 16 bytes buffer
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_UNKNOWN_ERROR,
* #UPNPCOMMAND_INVALID_ARGS, #UPNPCOMMAND_HTTP_ERROR or an
* UPnP error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetExternalIPAddress(const char * controlURL, UPNP_GetExternalIPAddress(const char * controlURL,
const char * servicetype, const char * servicetype,
char * extIpAdd); char * extIpAdd);
/* UPNP_GetLinkLayerMaxBitRates() /*! \brief UPNP_GetLinkLayerMaxBitRates()
* call WANCommonInterfaceConfig:1#GetCommonLinkProperties * call `WANCommonInterfaceConfig:GetCommonLinkProperties`
* *
* return values : * \param[in] controlURL controlURL of the WANCommonInterfaceConfig of a WANDevice
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * \param[in] servicetype urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
* or a UPnP Error Code. */ * \param[out] bitrateDown bits per second
* \param[out] bitrateUp bits per second
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP Error Code.
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetLinkLayerMaxBitRates(const char* controlURL, UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
const char* servicetype, const char* servicetype,
unsigned int * bitrateDown, unsigned int * bitrateDown,
unsigned int * bitrateUp); unsigned int * bitrateUp);
/* UPNP_AddPortMapping() /*! \brief WANIPConnection:AddPortMapping()
* if desc is NULL, it will be defaulted to "libminiupnpc"
* remoteHost is usually NULL because IGD don't support it.
*
* Return values :
* 0 : SUCCESS
* NON ZERO : ERROR. Either an UPnP error code or an unknown error.
* *
* List of possible UPnP errors for AddPortMapping : * List of possible UPnP errors for AddPortMapping :
* errorCode errorDescription (short) - Description (long) * 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. * 402 Invalid Args | See UPnP Device Architecture section on Control.
* 606 Action not authorized - The action requested REQUIRES authorization and * 501 Action Failed | See UPnP Device Architecture section on Control.
* the sender was not authorized. * 606 Action not authorized | The action requested REQUIRES authorization and the sender was not authorized.
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be * 715 WildCardNotPermittedInSrcIP | The source IP address cannot be wild-carded
* wild-carded * 716 WildCardNotPermittedInExtPort | The external port cannot be wild-carded
* 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded * 718 ConflictInMappingEntry | The port mapping entry specified conflicts with a mapping assigned previously to another client
* 718 ConflictInMappingEntry - The port mapping entry specified conflicts * 724 SamePortValuesRequired | Internal and External port values must be the same
* with a mapping assigned previously to another client * 725 OnlyPermanentLeasesSupported | The NAT implementation only supports permanent lease times on port mappings
* 724 SamePortValuesRequired - Internal and External port values * 726 RemoteHostOnlySupportsWildcard | RemoteHost must be a wildcard and cannot be a specific IP address or DNS name
* must be the same * 727 ExternalPortOnlySupportsWildcard | ExternalPort must be a wildcard and cannot be a specific port value
* 725 OnlyPermanentLeasesSupported - The NAT implementation only supports * 728 NoPortMapsAvailable | There are not enough free ports available to complete port mapping.
* permanent lease times on port mappings * 729 ConflictWithOtherMechanisms | Attempted port mapping is not allowed due to conflict with other mechanisms.
* 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard * 732 WildCardNotPermittedInIntPort | The internal port cannot be wild-carded
* and cannot be a specific IP address or DNS name *
* 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and * \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* cannot be a specific port value * \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* 728 NoPortMapsAvailable - There are not enough free ports available to * \param[in] extPort External port
* complete port mapping. * \param[in] inPort Internal port
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed * \param[in] inClient IP of Internal client.
* due to conflict with other mechanisms. * \param[in] desc Port Mapping description. if NULL, defaults to
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded * "libminiupnpc"
* \param[in] proto `TCP` or `UDP`
* \param[in] remoteHost IP or empty string for wildcard. Most IGD don't
* support it
* \param[in] leaseDuration between 0 and 604800
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_MEM_ALLOC_ERROR, #UPNPCOMMAND_HTTP_ERROR,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP error code.
*/ */
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_AddPortMapping(const char * controlURL, const char * servicetype, UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
@@ -133,28 +207,38 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
const char * remoteHost, const char * remoteHost,
const char * leaseDuration); const char * leaseDuration);
/* UPNP_AddAnyPortMapping() /*! \brief WANIPConnection:AddAnyPortMapping()
* if desc is NULL, it will be defaulted to "libminiupnpc"
* remoteHost is usually NULL because IGD don't support it.
* *
* Return values : * Only in WANIPConnection:2
* 0 : SUCCESS
* NON ZERO : ERROR. Either an UPnP error code or an unknown error.
* *
* List of possible UPnP errors for AddPortMapping : * List of possible UPnP errors for AddPortMapping :
* errorCode errorDescription (short) - Description (long) * 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. * 402 Invalid Args | See UPnP Device Architecture section on Control.
* 606 Action not authorized - The action requested REQUIRES authorization and * 501 Action Failed | See UPnP Device Architecture section on Control.
* the sender was not authorized. * 606 Action not authorized | The action requested REQUIRES authorization and the sender was not authorized.
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be * 715 WildCardNotPermittedInSrcIP | The source IP address cannot be wild-carded
* wild-carded * 716 WildCardNotPermittedInExtPort | The external port 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.
* 728 NoPortMapsAvailable - There are not enough free ports available to * 729 ConflictWithOtherMechanisms | Attempted port mapping is not allowed due to conflict with other mechanisms.
* complete port mapping. * 732 WildCardNotPermittedInIntPort | The internal port cannot be wild-carded
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed *
* due to conflict with other mechanisms. * \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded * \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:2
* \param[in] extPort External port
* \param[in] inPort Internal port
* \param[in] inClient IP of Internal client.
* \param[in] desc Port Mapping description. if NULL, defaults to
* "libminiupnpc"
* \param[in] proto `TCP` or `UDP`
* \param[in] remoteHost IP or empty string for wildcard. Most IGD don't
* support it
* \param[in] leaseDuration between 0 and 604800
* \param[out] reservedPort 6 bytes buffer
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_MEM_ALLOC_ERROR, #UPNPCOMMAND_HTTP_ERROR,
* #UPNPCOMMAND_INVALID_RESPONSE, #UPNPCOMMAND_UNKNOWN_ERROR
* or a UPnP error code.
*/ */
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
@@ -167,24 +251,35 @@ UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
const char * leaseDuration, const char * leaseDuration,
char * reservedPort); char * reservedPort);
/* UPNP_DeletePortMapping() /*! \brief WANIPConnection:DeletePortMapping()
* Use same argument values as what was used for AddPortMapping().
* remoteHost is usually NULL because IGD don't support it.
* Return Values :
* 0 : SUCCESS
* NON ZERO : error. Either an UPnP error code or an undefined error.
* *
* List of possible UPnP errors for DeletePortMapping : * Use same argument values as what was used for UPNP_AddPortMapping()
* 402 Invalid Args - See UPnP Device Architecture section on Control. *
* 606 Action not authorized - The action requested REQUIRES authorization * List of possible UPnP errors for UPNP_DeletePortMapping() :
* and the sender was not authorized. * errorCode errorDescription (short) | Description (long)
* 714 NoSuchEntryInArray - The specified value does not exist in the array */ * ---------------------------------- | ------------------
* 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
*
* \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* \param[in] extPort External port
* \param[in] proto `TCP` or `UDP`
* \param[in] remoteHost IP or empty string for wildcard. Most IGD don't
* support it
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_MEM_ALLOC_ERROR, #UPNPCOMMAND_HTTP_ERROR,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP error code.
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
const char * extPort, const char * proto, const char * extPort, const char * proto,
const char * remoteHost); const char * remoteHost);
/* UPNP_DeletePortRangeMapping() /*! \brief WANIPConnection:DeletePortRangeMapping()
*
* Only in WANIPConnection:2
* Use same argument values as what was used for AddPortMapping(). * Use same argument values as what was used for AddPortMapping().
* remoteHost is usually NULL because IGD don't support it. * remoteHost is usually NULL because IGD don't support it.
* Return Values : * Return Values :
@@ -192,46 +287,66 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
* NON ZERO : error. Either an UPnP error code or an undefined error. * NON ZERO : error. Either an UPnP error code or an undefined error.
* *
* List of possible UPnP errors for DeletePortMapping : * List of possible UPnP errors for DeletePortMapping :
* 606 Action not authorized - The action requested REQUIRES authorization * errorCode errorDescription (short) | Description (long)
* and the sender was not authorized. * ---------------------------------- | ------------------
* 730 PortMappingNotFound - This error message is returned if no port * 606 Action not authorized | The action requested REQUIRES authorization and the sender was not authorized.
* mapping is found in the specified range. * 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. */ * 733 InconsistentParameters | NewStartPort and NewEndPort values are not consistent.
* \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:2
* \param[in] extPortStart External port range start
* \param[in] extPortEnd External port range end
* \param[in] proto `TCP` or `UDP`
* \param[in] manage `0` to remove only the port mappings of this IGD,
* `1` to remove port mappings also for other clients
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_MEM_ALLOC_ERROR, #UPNPCOMMAND_HTTP_ERROR,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP error code.
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
const char * extPortStart, const char * extPortEnd, const char * extPortStart, const char * extPortEnd,
const char * proto, const char * proto,
const char * manage); const char * manage);
/* UPNP_GetPortMappingNumberOfEntries() /*! \brief WANIPConnection:GetPortMappingNumberOfEntries()
* not supported by all routers */ *
* not supported by all routers
*
* \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* \param[out] numEntries Port mappings count
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_HTTP_ERROR,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP error code.
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetPortMappingNumberOfEntries(const char * controlURL, UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
const char * servicetype, const char * servicetype,
unsigned int * numEntries); unsigned int * numEntries);
/* UPNP_GetSpecificPortMappingEntry() /*! \brief retrieves an existing port mapping for a port:protocol
* retrieves an existing port mapping
* params :
* in extPort
* in proto
* in remoteHost
* out intClient (16 bytes)
* out intPort (6 bytes)
* out desc (80 bytes)
* out enabled (4 bytes)
* out leaseDuration (16 bytes)
* *
* return value : * List of possible UPnP errors for UPNP_GetSpecificPortMappingEntry() :
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * errorCode errorDescription (short) | Description (long)
* or a UPnP Error Code. * ---------------------------------- | ------------------
* 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.
* *
* List of possible UPnP errors for _GetSpecificPortMappingEntry : * \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* 402 Invalid Args - See UPnP Device Architecture section on Control. * \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* 501 Action Failed - See UPnP Device Architecture section on Control. * \param[in] extPort External port
* 606 Action not authorized - The action requested REQUIRES authorization * \param[in] proto `TCP` or `UDP`
* and the sender was not authorized. * \param[in] remoteHost IP or empty string for wildcard. Most IGD don't
* 714 NoSuchEntryInArray - The specified value does not exist in the array. * support it
* \param[out] intClient 16 bytes buffer
* \param[out] intPort 6 bytes buffer
* \param[out] desc 80 bytes buffer
* \param[out] enabled 4 bytes buffer
* \param[out] leaseDuration 16 bytes
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP Error Code.
*/ */
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetSpecificPortMappingEntry(const char * controlURL, UPNP_GetSpecificPortMappingEntry(const char * controlURL,
@@ -245,27 +360,65 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
char * enabled, char * enabled,
char * leaseDuration); char * leaseDuration);
/* UPNP_GetGenericPortMappingEntry() /*! \brief retrieves an existing port mapping for a port:protocol
* params :
* in index
* out extPort (6 bytes)
* out intClient (16 bytes)
* out intPort (6 bytes)
* out protocol (4 bytes)
* out desc (80 bytes)
* out enabled (4 bytes)
* out rHost (64 bytes)
* out duration (16 bytes)
* *
* return value : * List of possible UPnP errors for UPNP_GetSpecificPortMappingEntry() :
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * errorCode errorDescription (short) | Description (long)
* or a UPnP Error Code. * ---------------------------------- | ------------------
* 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.
* *
* Possible UPNP Error codes : * \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* 402 Invalid Args - See UPnP Device Architecture section on Control. * \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* 606 Action not authorized - The action requested REQUIRES authorization * \param[in] extPort External port
* and the sender was not authorized. * \param[in] proto `TCP` or `UDP`
* 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds * \param[in] remoteHost IP or empty string for wildcard. Most IGD don't
* support it
* \param[out] intClient 16 bytes buffer
* \param[out] intPort 6 bytes buffer
* \param[out] desc desclen bytes buffer
* \param[in] desclen desc buffer length
* \param[out] enabled 4 bytes buffer
* \param[out] leaseDuration 16 bytes
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP Error Code.
*/
MINIUPNP_LIBSPEC int
UPNP_GetSpecificPortMappingEntryExt(const char * controlURL,
const char * servicetype,
const char * extPort,
const char * proto,
const char * remoteHost,
char * intClient,
char * intPort,
char * desc,
size_t desclen,
char * enabled,
char * leaseDuration);
/*! \brief WANIPConnection:GetGenericPortMappingEntry()
*
* errorCode errorDescription (short) | Description (long)
* ---------------------------------- | ------------------
* 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
*
* \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* \param[in] index
* \param[out] extPort 6 bytes buffer
* \param[out] intClient 16 bytes buffer
* \param[out] intPort 6 bytes buffer
* \param[out] protocol 4 bytes buffer
* \param[out] desc 80 bytes buffer
* \param[out] enabled 4 bytes buffer
* \param[out] rHost 64 bytes buffer
* \param[out] duration 16 bytes buffer
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP Error Code.
*/ */
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetGenericPortMappingEntry(const char * controlURL, UPNP_GetGenericPortMappingEntry(const char * controlURL,
@@ -280,14 +433,64 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
char * rHost, char * rHost,
char * duration); char * duration);
/* UPNP_GetListOfPortMappings() Available in IGD v2 /*! \brief WANIPConnection:GetGenericPortMappingEntry()
* *
* errorCode errorDescription (short) | Description (long)
* ---------------------------------- | ------------------
* 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
* *
* Possible UPNP Error codes : * \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
* 606 Action not Authorized * \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
* 730 PortMappingNotFound - no port mapping is found in the specified range. * \param[in] index
* 733 InconsistantParameters - NewStartPort and NewEndPort values are not * \param[out] extPort 6 bytes buffer
* consistent. * \param[out] intClient 16 bytes buffer
* \param[out] intPort 6 bytes buffer
* \param[out] protocol 4 bytes buffer
* \param[out] desc desclen bytes buffer
* \param[in] desclen desc buffer length
* \param[out] enabled 4 bytes buffer
* \param[out] rHost desclen bytes buffer
* \param[in] rHostlen rHost buffer length
* \param[out] duration 16 bytes buffer
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP Error Code.
*/
MINIUPNP_LIBSPEC int
UPNP_GetGenericPortMappingEntryExt(const char * controlURL,
const char * servicetype,
const char * index,
char * extPort,
char * intClient,
char * intPort,
char * protocol,
char * desc,
size_t desclen,
char * enabled,
char * rHost,
size_t rHostlen,
char * duration);
/*! \brief retrieval of a list of existing port mappings
*
* Available in IGD v2 : WANIPConnection:GetListOfPortMappings()
*
* errorCode errorDescription (short) | Description (long)
* ---------------------------------- | ------------------
* 606 Action not authorized | The action requested REQUIRES authorization and the sender was not authorized.
* 730 PortMappingNotFound | no port mapping is found in the specified range.
* 733 InconsistantParameters | NewStartPort and NewEndPort values are not consistent.
*
* \param[in] controlURL controlURL of the WANIPConnection of a
* WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:2
* \param[in] startPort port interval start
* \param[in] endPort port interval end
* \param[in] protocol `TCP` or `UDP`
* \param[in] numberOfPorts size limit of the list returned. `0` to request
* all port mappings
* \param[out] data port mappings list
*/ */
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetListOfPortMappings(const char * controlURL, UPNP_GetListOfPortMappings(const char * controlURL,
@@ -298,15 +501,48 @@ UPNP_GetListOfPortMappings(const char * controlURL,
const char * numberOfPorts, const char * numberOfPorts,
struct PortMappingParserData * data); struct PortMappingParserData * data);
/* IGD:2, functions for service WANIPv6FirewallControl:1 */ /*! \brief GetFirewallStatus() retrieves whether the firewall is enabled
* and pinhole can be created through UPnP
*
* IGD:2, functions for service WANIPv6FirewallControl:1
*
* \param[in] controlURL controlURL of the WANIPv6FirewallControl of a
* WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
* \param[out] firewallEnabled false (0) or true (1)
* \param[out] inboundPinholeAllowed false (0) or true (1)
* \return #UPNPCOMMAND_UNKNOWN_ERROR, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_HTTP_ERROR, #UPNPCOMMAND_SUCCESS or an UPnP error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetFirewallStatus(const char * controlURL, UPNP_GetFirewallStatus(const char * controlURL,
const char * servicetype, const char * servicetype,
int * firewallEnabled, int * firewallEnabled,
int * inboundPinholeAllowed); int * inboundPinholeAllowed);
/*! \brief retrieve default value after which automatically created pinholes
* expire
*
* The returned value may be specific to the \p proto, \p remoteHost,
* \p remotePort, \p intClient and \p intPort, but this behavior depends
* on the implementation of the firewall.
*
* \param[in] controlURL controlURL of the WANIPv6FirewallControl of a
* WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
* \param[in] remoteHost
* \param[in] remotePort
* \param[in] intClient
* \param[in] intPort
* \param[in] proto `TCP` or `UDP`
* \param[out] opTimeout lifetime in seconds of an inbound "automatic"
* firewall pinhole created by an outbound traffic initiation.
* \return #UPNPCOMMAND_UNKNOWN_ERROR, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_HTTP_ERROR, #UPNPCOMMAND_SUCCESS or an UPnP error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, UPNP_GetOutboundPinholeTimeout(const char * controlURL,
const char * servicetype,
const char * remoteHost, const char * remoteHost,
const char * remotePort, const char * remotePort,
const char * intClient, const char * intClient,
@@ -314,6 +550,24 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
const char * proto, const char * proto,
int * opTimeout); int * opTimeout);
/*! \brief create a new pinhole that allows incoming traffic to pass
* through the firewall
*
* \param[in] controlURL controlURL of the WANIPv6FirewallControl of a
* WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
* \param[in] remoteHost literal presentation of IPv6 address or domain name.
* empty string for wildcard
* \param[in] remotePort remote host port. Likely 0 (for wildcard)
* \param[in] intClient IP address of internal client. cannot be wildcarded
* \param[in] intPort client port. 0 for wildcard
* \param[in] proto IP protocol integer (6 for TCP, 17 for UDP, etc.)
* 65535 for wildcard.
* \param[in] leaseTime in seconds
* \param[out] uniqueID 8 bytes buffer
* \return #UPNPCOMMAND_UNKNOWN_ERROR, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_HTTP_ERROR, #UPNPCOMMAND_SUCCESS or an UPnP error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_AddPinhole(const char * controlURL, const char * servicetype, UPNP_AddPinhole(const char * controlURL, const char * servicetype,
const char * remoteHost, const char * remoteHost,
@@ -324,18 +578,61 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
const char * leaseTime, const char * leaseTime,
char * uniqueID); char * uniqueID);
/*! \brief update a pinholes lease time
*
* \param[in] controlURL controlURL of the WANIPv6FirewallControl of a
* WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
* \param[in] uniqueID value obtained through UPNP_AddPinhole()
* \param[in] leaseTime in seconds
* \return #UPNPCOMMAND_UNKNOWN_ERROR, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_HTTP_ERROR, #UPNPCOMMAND_SUCCESS or an UPnP error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
const char * uniqueID, const char * uniqueID,
const char * leaseTime); const char * leaseTime);
/*! \brief remove a pinhole
*
* \param[in] controlURL controlURL of the WANIPv6FirewallControl of a
* WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
* \param[in] uniqueID value obtained through UPNP_AddPinhole()
* \return #UPNPCOMMAND_UNKNOWN_ERROR, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_HTTP_ERROR, #UPNPCOMMAND_SUCCESS or an UPnP error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); UPNP_DeletePinhole(const char * controlURL,
const char * servicetype,
const char * uniqueID);
/*! \brief checking if a certain pinhole allows traffic to pass through the firewall
*
* \param[in] controlURL controlURL of the WANIPv6FirewallControl of a
* WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
* \param[in] uniqueID value obtained through UPNP_AddPinhole()
* \param[out] isWorking `0` for false, `1` for true
* \return #UPNPCOMMAND_UNKNOWN_ERROR, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_HTTP_ERROR, #UPNPCOMMAND_SUCCESS or an UPnP error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
const char * uniqueID, int * isWorking); const char * uniqueID, int * isWorking);
/*! \brief get the total number of IP packets which have been going through
* the specified pinhole
* \todo \p packets should be #UNSIGNED_INTEGER
* \param[in] controlURL controlURL of the WANIPv6FirewallControl of a
* WANConnectionDevice
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
* \param[in] uniqueID value obtained through UPNP_AddPinhole()
* \param[out] packets how many IP packets have been going through the
* specified pinhole
* \return #UPNPCOMMAND_UNKNOWN_ERROR, #UPNPCOMMAND_INVALID_ARGS,
* #UPNPCOMMAND_HTTP_ERROR, #UPNPCOMMAND_SUCCESS or an UPnP error code
*/
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
const char * uniqueID, int * packets); const char * uniqueID, int * packets);

View File

@@ -1,27 +1,40 @@
/* $Id: upnpdev.h,v 1.4 2021/08/21 09:45:01 nanard Exp $ */ /* $Id: upnpdev.h,v 1.6 2025/02/08 23:15:17 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD * Author : Thomas BERNARD
* copyright (c) 2005-2021 Thomas Bernard * copyright (c) 2005-2025 Thomas Bernard
* This software is subjet to the conditions detailed in the * This software is subjet to the conditions detailed in the
* provided LICENSE file. */ * provided LICENSE file. */
#ifndef UPNPDEV_H_INCLUDED #ifndef UPNPDEV_H_INCLUDED
#define UPNPDEV_H_INCLUDED #define UPNPDEV_H_INCLUDED
/*! \file upnpdev.h
* \brief UPNPDev device linked-list structure
* \todo could be merged into miniupnpc.h
*/
#include "miniupnpc_declspec.h" #include "miniupnpc_declspec.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/*!
* \brief UPnP device linked-list
*/
struct UPNPDev { struct UPNPDev {
/*! \brief pointer to the next element */
struct UPNPDev * pNext; struct UPNPDev * pNext;
/*! \brief root description URL */
char * descURL; char * descURL;
/*! \brief ST: as advertised */
char * st; char * st;
/*! \brief USN: as advertised */
char * usn; char * usn;
/*! \brief IPv6 scope id of the network interface */
unsigned int scope_id; unsigned int scope_id;
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 flexible array member */ /* C99 flexible array member */
/*! \brief buffer for descURL, st and usn */
char buffer[]; char buffer[];
#elif defined(__GNUC__) #elif defined(__GNUC__)
char buffer[0]; char buffer[0];
@@ -31,8 +44,9 @@ struct UPNPDev {
#endif #endif
}; };
/* freeUPNPDevlist() /*! \brief free list returned by upnpDiscover()
* free list returned by upnpDiscover() */ * \param[in] devlist linked list to free
*/
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);

View File

@@ -1,53 +1,73 @@
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */ /* $Id: upnpreplyparse.h,v 1.22 2025/03/29 17:58:12 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* (c) 2006-2013 Thomas Bernard * (c) 2006-2025 Thomas Bernard
* This software is subject to the conditions detailed * This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */ * in the LICENCE file provided within the distribution */
#ifndef UPNPREPLYPARSE_H_INCLUDED #ifndef UPNPREPLYPARSE_H_INCLUDED
#define UPNPREPLYPARSE_H_INCLUDED #define UPNPREPLYPARSE_H_INCLUDED
/*! \file upnpreplyparse.h
* \brief Parsing of UPnP SOAP responses
*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
struct NameValue { /*! \brief Name/Value linked list
struct NameValue * l_next; * not exposed in the public API
char name[64]; */
char value[128]; struct NameValue;
};
/*! \brief data structure for parsing */
struct NameValueParserData { struct NameValueParserData {
/*! \brief name/value linked list */
struct NameValue * l_head; struct NameValue * l_head;
/*! \brief current element name */
char curelt[64]; char curelt[64];
/*! \brief port listing array */
char * portListing; char * portListing;
/*! \brief port listing array length */
int portListingLength; int portListingLength;
/*! \brief flag indicating the current element is */
int topelt; int topelt;
/*! \brief top element character data */
const char * cdata; const char * cdata;
/*! \brief top element character data length */
int cdatalen; int cdatalen;
}; };
/* ParseNameValue() */ /*!
* \brief Parse XML and fill the structure
*
* \param[in] buffer XML data
* \param[in] bufsize buffer length
* \param[out] data structure to fill
*/
void void
ParseNameValue(const char * buffer, int bufsize, ParseNameValue(const char * buffer, int bufsize,
struct NameValueParserData * data); struct NameValueParserData * data);
/* ClearNameValueList() */ /*!
* \brief free memory
*
* \param[in,out] pdata data structure
*/
void void
ClearNameValueList(struct NameValueParserData * pdata); ClearNameValueList(struct NameValueParserData * pdata);
/* GetValueFromNameValueList() */ /*!
* \brief get a value from the parsed data
*
* \param[in] pdata data structure
* \param[in] name name
* \return the value or NULL if not found
*/
char * char *
GetValueFromNameValueList(struct NameValueParserData * pdata, GetValueFromNameValueList(struct NameValueParserData * pdata,
const char * Name); const char * name);
#if 0
/* GetValueFromNameValueListIgnoreNS() */
char *
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
const char * Name);
#endif
/* DisplayNameValueList() */ /* DisplayNameValueList() */
#ifdef DEBUG #ifdef DEBUG
@@ -60,4 +80,3 @@ DisplayNameValueList(char * buffer, int bufsize);
#endif #endif
#endif #endif

View File

@@ -1,13 +1,14 @@
/* $Id: addr_is_reserved.c,v 1.4 2021/03/02 23:40:32 nanard Exp $ */ /* $Id: addr_is_reserved.c,v 1.7 2025/01/12 15:47:17 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp * Project : miniupnp
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD * Author : Thomas BERNARD
* copyright (c) 2005-2024 Thomas Bernard * copyright (c) 2005-2025 Thomas Bernard
* This software is subjet to the conditions detailed in the * This software is subjet to the conditions detailed in the
* provided LICENSE file. */ * provided LICENSE file. */
#ifdef _WIN32 #ifdef _WIN32
/* Win32 Specific includes and defines */ /* Win32 Specific includes and defines */
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
@@ -15,6 +16,9 @@
#else /* !defined(_MSC_VER) */ #else /* !defined(_MSC_VER) */
typedef unsigned long uint32_t; typedef unsigned long uint32_t;
#endif /* !defined(_MSC_VER) */ #endif /* !defined(_MSC_VER) */
#if !defined(_WIN32_WINNT_VISTA)
#define _WIN32_WINNT_VISTA 0x0600
#endif
#else /* _WIN32 */ #else /* _WIN32 */
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
@@ -59,7 +63,7 @@ int addr_is_reserved(const char * addr_str)
uint32_t addr_n, address; uint32_t addr_n, address;
size_t i; size_t i;
#if defined(_WIN32) && _WIN32_WINNT < 0x0600 // _WIN32_WINNT_VISTA #if defined(_WIN32) && (_WIN32_WINNT < _WIN32_WINNT_VISTA)
addr_n = inet_addr(addr_str); addr_n = inet_addr(addr_str);
if (addr_n == INADDR_NONE) if (addr_n == INADDR_NONE)
return 1; return 1;

View File

@@ -1,8 +1,9 @@
/* $Id: connecthostport.c,v 1.24 2020/11/09 19:26:53 nanard Exp $ */ /* $Id: connecthostport.c,v 1.25 2025/05/24 15:59:08 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp * Project : miniupnp
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2010-2020 Thomas Bernard * Copyright (c) 2010-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
@@ -15,6 +16,7 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <io.h> #include <io.h>
@@ -123,8 +125,12 @@ SOCKET connecthostport(const char * host, unsigned short port,
#else #else
n = select(s + 1, NULL, &wset, NULL, NULL); n = select(s + 1, NULL, &wset, NULL, NULL);
#endif #endif
if(n == -1 && errno == EINTR) if(n < 0) {
continue; if (errno == EINTR)
continue; /* try again */
else
break; /* EBADF, EFAULT, EINVAL */
}
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
if(n == 0) { if(n == 0) {
errno = ETIMEDOUT; errno = ETIMEDOUT;
@@ -132,8 +138,6 @@ SOCKET connecthostport(const char * host, unsigned short port,
break; break;
} }
#endif #endif
/*len = 0;*/
/*n = getpeername(s, NULL, &len);*/
len = sizeof(err); len = sizeof(err);
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
PRINT_SOCKET_ERROR("getsockopt"); PRINT_SOCKET_ERROR("getsockopt");
@@ -240,8 +244,12 @@ SOCKET connecthostport(const char * host, unsigned short port,
#else #else
n = select(s + 1, NULL, &wset, NULL, NULL); n = select(s + 1, NULL, &wset, NULL, NULL);
#endif #endif
if(n == -1 && errno == EINTR) if(n < 0) {
continue; if (errno == EINTR)
continue; /* try again */
else
break; /* EBADF, EFAULT, EINVAL */
}
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
if(n == 0) { if(n == 0) {
errno = ETIMEDOUT; errno = ETIMEDOUT;
@@ -249,8 +257,6 @@ SOCKET connecthostport(const char * host, unsigned short port,
break; break;
} }
#endif #endif
/*len = 0;*/
/*n = getpeername(s, NULL, &len);*/
len = sizeof(err); len = sizeof(err);
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
PRINT_SOCKET_ERROR("getsockopt"); PRINT_SOCKET_ERROR("getsockopt");

View File

@@ -1,8 +1,8 @@
/* $Id: minisoap.c,v 1.32 2023/07/05 22:43:50 nanard Exp $ */ /* $Id: minisoap.c,v 1.35 2025/04/27 21:13:45 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp * Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2024 Thomas Bernard * Copyright (c) 2005-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* *
@@ -11,6 +11,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <io.h> #include <io.h>
#include <winsock2.h> #include <winsock2.h>
#include "win32_snprintf.h" #include "win32_snprintf.h"
@@ -99,7 +100,6 @@ int soapPostSubmit(SOCKET fd,
#endif #endif
"SOAPAction: \"%s\"\r\n" "SOAPAction: \"%s\"\r\n"
"Connection: close\r\n" "Connection: close\r\n"
"Cache-Control: no-cache\r\n" /* ??? */
"\r\n", "\r\n",
url, httpversion, host, portstr, bodysize, action); url, httpversion, host, portstr, bodysize, action);
if ((unsigned int)headerssize >= sizeof(headerbuf)) if ((unsigned int)headerssize >= sizeof(headerbuf))

View File

@@ -1,9 +1,9 @@
/* $Id: minissdpc.c,v 1.51 2024/05/16 00:12:05 nanard Exp $ */ /* $Id: minissdpc.c,v 1.54 2025/03/29 17:59:01 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp * Project : miniupnp
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD * Author : Thomas BERNARD
* copyright (c) 2005-2024 Thomas Bernard * copyright (c) 2005-2025 Thomas Bernard
* This software is subjet to the conditions detailed in the * This software is subjet to the conditions detailed in the
* provided LICENCE file. */ * provided LICENCE file. */
#include <stdio.h> #include <stdio.h>
@@ -16,6 +16,7 @@
#endif #endif
#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) #if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <io.h> #include <io.h>
@@ -39,6 +40,9 @@ typedef unsigned short uint16_t;
static const IN6_ADDR in6addr_any_init = {0}; static const IN6_ADDR in6addr_any_init = {0};
#endif #endif
#endif #endif
#if !defined(_WIN32_WINNT_VISTA)
#define _WIN32_WINNT_VISTA 0x0600
#endif
#endif /* _WIN32 */ #endif /* _WIN32 */
#if defined(__amigaos__) || defined(__amigaos4__) #if defined(__amigaos__) || defined(__amigaos4__)
#include <sys/socket.h> #include <sys/socket.h>
@@ -387,7 +391,7 @@ free_tmp_and_return:
* the last 4 arguments are filled during the parsing : * the last 4 arguments are filled during the parsing :
* - location/locationsize : "location:" field of the SSDP reply packet * - location/locationsize : "location:" field of the SSDP reply packet
* - st/stsize : "st:" field of the SSDP reply packet. * - st/stsize : "st:" field of the SSDP reply packet.
* - usn/usnsize : "usn:" filed of the SSDP reply packet * - usn/usnsize : "usn:" field of the SSDP reply packet
* The strings are NOT null terminated */ * The strings are NOT null terminated */
static void static void
parseMSEARCHReply(const char * reply, int size, parseMSEARCHReply(const char * reply, int size,
@@ -460,7 +464,7 @@ parseMSEARCHReply(const char * reply, int size,
static int upnp_gettimeofday(struct timeval * tv) static int upnp_gettimeofday(struct timeval * tv)
{ {
#if defined(_WIN32) #if defined(_WIN32)
#if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
ULONGLONG ts = GetTickCount64(); ULONGLONG ts = GetTickCount64();
#else #else
DWORD ts = GetTickCount(); DWORD ts = GetTickCount();
@@ -539,10 +543,10 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
int n; int n;
struct sockaddr_storage sockudp_r; struct sockaddr_storage sockudp_r;
unsigned int mx; unsigned int mx;
int rv;
#ifdef NO_GETADDRINFO #ifdef NO_GETADDRINFO
struct sockaddr_storage sockudp_w; struct sockaddr_storage sockudp_w;
#else #else
int rv;
struct addrinfo hints, *servinfo; struct addrinfo hints, *servinfo;
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
@@ -591,8 +595,8 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
if(!ipv6) { if(!ipv6) {
DWORD ifbestidx; DWORD ifbestidx;
#if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
// While we don't need IPv6 support, the IPv4 only funciton is not available in UWP apps. // While we don't need IPv6 support, the IPv4 only function is not available in UWP apps.
SOCKADDR_IN destAddr; SOCKADDR_IN destAddr;
memset(&destAddr, 0, sizeof(destAddr)); memset(&destAddr, 0, sizeof(destAddr));
destAddr.sin_family = AF_INET; destAddr.sin_family = AF_INET;
@@ -747,7 +751,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
} else { } else {
struct in_addr mc_if; struct in_addr mc_if;
#if defined(_WIN32) #if defined(_WIN32)
#if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
InetPtonA(AF_INET, multicastif, &mc_if); InetPtonA(AF_INET, multicastif, &mc_if);
#else #else
mc_if.s_addr = inet_addr(multicastif); /* old Windows SDK do not support InetPtoA() */ mc_if.s_addr = inet_addr(multicastif); /* old Windows SDK do not support InetPtoA() */
@@ -871,9 +875,9 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
p->sin_port = htons(SSDP_PORT); p->sin_port = htons(SSDP_PORT);
p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
} }
n = sendto(sudp, bufr, n, 0, &sockudp_w, rv = sendto(sudp, bufr, n, 0, (struct sockaddr *)&sockudp_w,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
if (n < 0) { if (rv < 0) {
if(error) if(error)
*error = MINISSDPC_SOCKET_ERROR; *error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("sendto"); PRINT_SOCKET_ERROR("sendto");
@@ -899,9 +903,11 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
break; break;
} else { } else {
struct addrinfo *p; struct addrinfo *p;
/* as getaddrinfo() returns a linked list, we are iterating it
* even thought it should only return one result here */
for(p = servinfo; p; p = p->ai_next) { for(p = servinfo; p; p = p->ai_next) {
n = sendto(sudp, bufr, n, 0, p->ai_addr, MSC_CAST_INT p->ai_addrlen); rv = sendto(sudp, bufr, n, 0, p->ai_addr, MSC_CAST_INT p->ai_addrlen);
if (n < 0) { if (rv < 0) {
#ifdef DEBUG #ifdef DEBUG
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo(p->ai_addr, (socklen_t)p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, if (getnameinfo(p->ai_addr, (socklen_t)p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,

View File

@@ -1,9 +1,9 @@
/* $Id: miniupnpc.c,v 1.159 2021/03/02 23:36:32 nanard Exp $ */ /* $Id: miniupnpc.c,v 1.165 2025/01/10 22:57:21 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp * Project : miniupnp
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD * Author : Thomas BERNARD
* copyright (c) 2005-2024 Thomas Bernard * copyright (c) 2005-2025 Thomas Bernard
* This software is subjet to the conditions detailed in the * This software is subjet to the conditions detailed in the
* provided LICENSE file. */ * provided LICENSE file. */
#include <stdlib.h> #include <stdlib.h>
@@ -11,6 +11,7 @@
#include <string.h> #include <string.h>
#ifdef _WIN32 #ifdef _WIN32
/* Win32 Specific includes and defines */ /* Win32 Specific includes and defines */
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <io.h> #include <io.h>
@@ -98,8 +99,8 @@ MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGD
* pointer - OK * pointer - OK
* NULL - error */ * NULL - error */
char * char *
simpleUPnPcommand(int s, const char * url, const char * service, simpleUPnPcommand(const char * url, const char * service,
const char * action, struct UPNParg * args, const char * action, const struct UPNParg * args,
int * bufsize) int * bufsize)
{ {
char hostname[MAXHOSTNAMELEN+1]; char hostname[MAXHOSTNAMELEN+1];
@@ -111,6 +112,7 @@ simpleUPnPcommand(int s, const char * url, const char * service,
char * buf; char * buf;
int n; int n;
int status_code; int status_code;
SOCKET s;
*bufsize = 0; *bufsize = 0;
snprintf(soapact, sizeof(soapact), "%s#%s", service, action); snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
@@ -197,12 +199,10 @@ simpleUPnPcommand(int s, const char * url, const char * service,
return NULL; return NULL;
} }
if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
if(ISINVALID((SOCKET)s)) { s = connecthostport(hostname, port, 0);
s = connecthostport(hostname, port, 0); if(ISINVALID(s)) {
if(ISINVALID((SOCKET)s)) { /* failed to connect */
/* failed to connect */ return NULL;
return NULL;
}
} }
n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, "1.1"); n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, "1.1");
@@ -505,13 +505,14 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
/* UPNP_GetValidIGD() : /* UPNP_GetValidIGD() :
* return values : * return values :
* -1 = Internal error * -1 = Internal error
* 0 = NO IGD found * 0 = NO IGD found (UPNP_NO_IGD)
* 1 = A valid connected IGD has been found * 1 = A valid connected IGD has been found (UPNP_CONNECTED_IGD)
* 2 = A valid connected IGD has been found but its * 2 = A valid connected IGD has been found but its
* IP address is reserved (non routable) * IP address is reserved (non routable) (UPNP_PRIVATEIP_IGD)
* 3 = A valid IGD has been found but it reported as * 3 = A valid IGD has been found but it reported as
* not connected * not connected (UPNP_DISCONNECTED_IGD)
* 4 = an UPnP device has been found but was not recognized as an IGD * 4 = an UPnP device has been found but was not recognized as an IGD
* (UPNP_UNKNOWN_DEVICE)
* *
* In any positive 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. Don't forget to call FreeUPNPUrls(urls) to * passed as parameters are set. Don't forget to call FreeUPNPUrls(urls) to

View File

@@ -2,7 +2,7 @@
#define MINIUPNPCSTRINGS_H_INCLUDED #define MINIUPNPCSTRINGS_H_INCLUDED
#define OS_STRING "Godot Engine/1.0" #define OS_STRING "Godot Engine/1.0"
#define MINIUPNPC_VERSION_STRING "2.2.8" #define MINIUPNPC_VERSION_STRING "2.3.3"
#if 0 #if 0
/* according to "UPnP Device Architecture 1.0" */ /* according to "UPnP Device Architecture 1.0" */

View File

@@ -1,8 +1,8 @@
/* $Id: miniwget.c,v 1.85 2023/06/15 21:47:50 nanard Exp $ */ /* $Id: miniwget.c,v 1.88 2025/05/25 21:56:49 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2024 Thomas Bernard * Copyright (c) 2005-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
@@ -11,6 +11,7 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <io.h> #include <io.h>

View File

@@ -1,15 +1,54 @@
/* $Id: miniwget_private.h,v 1.1 2018/04/06 10:17:58 nanard Exp $ */ /* $Id: miniwget_private.h,v 1.1 2018/04/06 10:17:58 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2018 Thomas Bernard * Copyright (c) 2018-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
#ifndef MINIWGET_INTERNAL_H_INCLUDED #ifndef MINIWGET_INTERNAL_H_INCLUDED
#define MINIWGET_INTERNAL_H_INCLUDED #define MINIWGET_INTERNAL_H_INCLUDED
/*! \file miniwget_private.h
* \brief Lightweight HTTP client private API
*/
#include "miniupnpc_socketdef.h" #include "miniupnpc_socketdef.h"
/*! \brief Read a HTTP response from a socket
*
* Processed HTTP headers :
* - `Content-Length`
* - `Transfer-encoding`
* return a pointer to the content buffer, which length is saved
* to the length parameter.
* \param[in] s socket
* \param[out] size returned content buffer size
* \param[out] status_code HTTP Status code
* \return malloc'ed content buffer
*/
void * getHTTPResponse(SOCKET s, int * size, int * status_code); void * getHTTPResponse(SOCKET s, int * size, int * status_code);
/*! \brief parse a HTTP URL
*
* URL formats supported :
* - `http://192.168.1.1/path/xxx`
* - `http://192.168.1.1:8080/path/xxx`
* - `http://[2a00:1234:5678:90ab::123]/path/xxx`
* - `http://[2a00:1234:5678:90ab::123]:8080/path/xxx`
* - `http://[fe80::1234:5678:90ab%%eth0]/path/xxx`
* - `http://[fe80::1234:5678:90ab%%eth0]:8080/path/xxx`
*
* `%` may be encoded as `%25`
*
* \param[in] url URL to parse
* \param[out] hostname hostname part of the URL (size of MAXHOSTNAMELEN+1)
* \param[out] port set to the port specified in the URL or 80
* \param[out] path set to the begining of the path part of the URL
* \param[out] scope_id set to the interface id if specified in the
* link-local IPv6 address
* \return 0 for failure, 1 for success
*/
int parseURL(const char * url,
char * hostname, unsigned short * port, char * * path,
unsigned int * scope_id);
#endif #endif

View File

@@ -1,7 +1,7 @@
/* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */ /* $Id: portlistingparse.c,v 1.12 2025/03/29 17:58:33 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* (c) 2011-2020 Thomas Bernard * (c) 2011-2025 Thomas Bernard
* This software is subject to the conditions detailed * This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */ * in the LICENCE file provided within the distribution */
#include <string.h> #include <string.h>
@@ -15,7 +15,7 @@
#if defined(__HAIKU__) #if defined(__HAIKU__)
/* rename our private function because Haiku already defines a atoui() function */ /* rename our private function because Haiku already defines a atoui() function */
#define atoui atoui2 #define atoui atoui2
#endif #endif
/* list of the elements */ /* list of the elements */
static const struct { static const struct {

View File

@@ -1,14 +1,15 @@
/* $Id: receivedata.c,v 1.10 2021/03/02 23:33:07 nanard Exp $ */ /* $Id: receivedata.c,v 1.11 2025/05/25 21:56:49 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Website : http://miniupnp.free.fr/ * Website : http://miniupnp.free.fr/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2011-2021 Thomas Bernard * Copyright (c) 2011-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#else /* _WIN32 */ #else /* _WIN32 */

View File

@@ -1,8 +1,8 @@
/* $Id: upnpcommands.c,v 1.51 2019/04/23 11:45:15 nanard Exp $ */ /* $Id: upnpcommands.c,v 1.56 2025/03/29 18:08:59 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp * Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2018 Thomas Bernard * Copyright (c) 2005-2025 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
@@ -14,6 +14,17 @@
#include "portlistingparse.h" #include "portlistingparse.h"
#include "upnpreplyparse.h" #include "upnpreplyparse.h"
/*! \file upnpcommands.c
* \brief Internet Gateway Device methods implementations
* \def STRTOUI
* \brief strtoull() if available, strtol() if not
*/
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define STRTOUI strtoull
#else
#define STRTOUI strtoul
#endif
static UNSIGNED_INTEGER static UNSIGNED_INTEGER
my_atoui(const char * s) my_atoui(const char * s)
{ {
@@ -31,7 +42,7 @@ UPNP_GetTotalBytesSent(const char * controlURL,
int bufsize; int bufsize;
unsigned int r = 0; unsigned int r = 0;
char * p; char * p;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(controlURL, servicetype,
"GetTotalBytesSent", 0, &bufsize))) { "GetTotalBytesSent", 0, &bufsize))) {
return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR;
} }
@@ -55,7 +66,7 @@ UPNP_GetTotalBytesReceived(const char * controlURL,
int bufsize; int bufsize;
unsigned int r = 0; unsigned int r = 0;
char * p; char * p;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(controlURL, servicetype,
"GetTotalBytesReceived", 0, &bufsize))) { "GetTotalBytesReceived", 0, &bufsize))) {
return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR;
} }
@@ -79,7 +90,7 @@ UPNP_GetTotalPacketsSent(const char * controlURL,
int bufsize; int bufsize;
unsigned int r = 0; unsigned int r = 0;
char * p; char * p;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(controlURL, servicetype,
"GetTotalPacketsSent", 0, &bufsize))) { "GetTotalPacketsSent", 0, &bufsize))) {
return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR;
} }
@@ -103,7 +114,7 @@ UPNP_GetTotalPacketsReceived(const char * controlURL,
int bufsize; int bufsize;
unsigned int r = 0; unsigned int r = 0;
char * p; char * p;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(controlURL, servicetype,
"GetTotalPacketsReceived", 0, &bufsize))) { "GetTotalPacketsReceived", 0, &bufsize))) {
return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR;
} }
@@ -136,7 +147,7 @@ UPNP_GetStatusInfo(const char * controlURL,
if(!status && !uptime) if(!status && !uptime)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(controlURL, servicetype,
"GetStatusInfo", 0, &bufsize))) { "GetStatusInfo", 0, &bufsize))) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -158,9 +169,7 @@ UPNP_GetStatusInfo(const char * controlURL,
} }
if(uptime) { if(uptime) {
if(up) if(!up || sscanf(up,"%u",uptime) != 1)
sscanf(up,"%u",uptime);
else
*uptime = 0; *uptime = 0;
} }
@@ -174,8 +183,8 @@ UPNP_GetStatusInfo(const char * controlURL,
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) { if(p) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
return ret; return ret;
@@ -197,7 +206,7 @@ UPNP_GetConnectionTypeInfo(const char * controlURL,
if(!connectionType) if(!connectionType)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(controlURL, servicetype,
"GetConnectionTypeInfo", 0, &bufsize))) { "GetConnectionTypeInfo", 0, &bufsize))) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -214,8 +223,8 @@ UPNP_GetConnectionTypeInfo(const char * controlURL,
connectionType[0] = '\0'; connectionType[0] = '\0';
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) { if(p) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
return ret; return ret;
@@ -244,7 +253,7 @@ UPNP_GetLinkLayerMaxBitRates(const char * controlURL,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
/* shouldn't we use GetCommonLinkProperties ? */ /* shouldn't we use GetCommonLinkProperties ? */
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(controlURL, servicetype,
"GetCommonLinkProperties", 0, &bufsize))) { "GetCommonLinkProperties", 0, &bufsize))) {
/*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
@@ -262,22 +271,18 @@ UPNP_GetLinkLayerMaxBitRates(const char * controlURL,
ret = UPNPCOMMAND_SUCCESS; ret = UPNPCOMMAND_SUCCESS;
if(bitrateDown) { if(bitrateDown) {
if(down) if(!down || sscanf(down,"%u",bitrateDown) != 1)
sscanf(down,"%u",bitrateDown);
else
*bitrateDown = 0; *bitrateDown = 0;
} }
if(bitrateUp) { if(bitrateUp) {
if(up) if(!up || sscanf(up,"%u",bitrateUp) != 1)
sscanf(up,"%u",bitrateUp);
else
*bitrateUp = 0; *bitrateUp = 0;
} }
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) { if(p) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
return ret; return ret;
@@ -309,7 +314,7 @@ UPNP_GetExternalIPAddress(const char * controlURL,
if(!extIpAdd || !controlURL || !servicetype) if(!extIpAdd || !controlURL || !servicetype)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(controlURL, servicetype,
"GetExternalIPAddress", 0, &bufsize))) { "GetExternalIPAddress", 0, &bufsize))) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -327,8 +332,8 @@ UPNP_GetExternalIPAddress(const char * controlURL,
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) { if(p) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
@@ -345,7 +350,17 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
const char * remoteHost, const char * remoteHost,
const char * leaseDuration) const char * leaseDuration)
{ {
struct UPNParg * AddPortMappingArgs; struct UPNParg AddPortMappingArgs[] = {
{"NewRemoteHost", remoteHost},
{"NewExternalPort", extPort},
{"NewProtocol", proto},
{"NewInternalPort", inPort},
{"NewInternalClient", inClient},
{"NewEnabled", "1"},
{"NewPortMappingDescription", desc?desc:"libminiupnpc"},
{"NewLeaseDuration", leaseDuration?leaseDuration:"0"},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
struct NameValueParserData pdata; struct NameValueParserData pdata;
@@ -355,29 +370,9 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
if(!inPort || !inClient || !proto || !extPort) if(!inPort || !inClient || !proto || !extPort)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); buffer = simpleUPnPcommand(controlURL, servicetype,
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";
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"AddPortMapping", AddPortMappingArgs, "AddPortMapping", AddPortMappingArgs,
&bufsize); &bufsize);
free(AddPortMappingArgs);
if(!buffer) { if(!buffer) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -389,8 +384,8 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
resVal = GetValueFromNameValueList(&pdata, "errorCode"); resVal = GetValueFromNameValueList(&pdata, "errorCode");
if(resVal) { if(resVal) {
/*printf("AddPortMapping errorCode = '%s'\n", resVal); */ /*printf("AddPortMapping errorCode = '%s'\n", resVal); */
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(resVal, "%d", &ret) != 1)
sscanf(resVal, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} else { } else {
ret = UPNPCOMMAND_SUCCESS; ret = UPNPCOMMAND_SUCCESS;
} }
@@ -409,39 +404,28 @@ UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
const char * leaseDuration, const char * leaseDuration,
char * reservedPort) char * reservedPort)
{ {
struct UPNParg * AddPortMappingArgs; struct UPNParg AddAnyPortMappingArgs[] = {
{"NewRemoteHost", remoteHost},
{"NewExternalPort", extPort},
{"NewProtocol", proto},
{"NewInternalPort", inPort},
{"NewInternalClient", inClient},
{"NewEnabled", "1"},
{"NewPortMappingDescription", desc?desc:"libminiupnpc"},
{"NewLeaseDuration", leaseDuration?leaseDuration:"0"},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
struct NameValueParserData pdata; struct NameValueParserData pdata;
const char * resVal; const char * resVal;
int ret; int ret;
if(!inPort || !inClient || !proto || !extPort) if(!inPort || !inClient || !proto || !extPort || !reservedPort)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
buffer = simpleUPnPcommand(controlURL, servicetype,
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); "AddAnyPortMapping", AddAnyPortMappingArgs,
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";
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"AddAnyPortMapping", AddPortMappingArgs,
&bufsize); &bufsize);
free(AddPortMappingArgs);
if(!buffer) { if(!buffer) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -449,8 +433,8 @@ UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
free(buffer); free(buffer);
resVal = GetValueFromNameValueList(&pdata, "errorCode"); resVal = GetValueFromNameValueList(&pdata, "errorCode");
if(resVal) { if(resVal) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(resVal, "%d", &ret) != 1)
sscanf(resVal, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} else { } else {
char *p; char *p;
@@ -473,7 +457,12 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
const char * remoteHost) const char * remoteHost)
{ {
/*struct NameValueParserData pdata;*/ /*struct NameValueParserData pdata;*/
struct UPNParg * DeletePortMappingArgs; struct UPNParg DeletePortMappingArgs[] = {
{"NewRemoteHost", remoteHost},
{"NewExternalPort", extPort},
{"NewProtocol", proto},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
struct NameValueParserData pdata; struct NameValueParserData pdata;
@@ -483,19 +472,9 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
if(!extPort || !proto) if(!extPort || !proto)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); buffer = simpleUPnPcommand(controlURL, servicetype,
if(DeletePortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePortMappingArgs[0].elt = "NewRemoteHost";
DeletePortMappingArgs[0].val = remoteHost;
DeletePortMappingArgs[1].elt = "NewExternalPort";
DeletePortMappingArgs[1].val = extPort;
DeletePortMappingArgs[2].elt = "NewProtocol";
DeletePortMappingArgs[2].val = proto;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"DeletePortMapping", "DeletePortMapping",
DeletePortMappingArgs, &bufsize); DeletePortMappingArgs, &bufsize);
free(DeletePortMappingArgs);
if(!buffer) { if(!buffer) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -504,8 +483,8 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
free(buffer); free(buffer);
resVal = GetValueFromNameValueList(&pdata, "errorCode"); resVal = GetValueFromNameValueList(&pdata, "errorCode");
if(resVal) { if(resVal) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(resVal, "%d", &ret) != 1)
sscanf(resVal, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} else { } else {
ret = UPNPCOMMAND_SUCCESS; ret = UPNPCOMMAND_SUCCESS;
} }
@@ -515,11 +494,17 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
const char * extPortStart, const char * extPortEnd, const char * extPortStart, const char * extPortEnd,
const char * proto, const char * proto,
const char * manage) const char * manage)
{ {
struct UPNParg * DeletePortMappingArgs; struct UPNParg DeletePortMappingRangeArgs[] = {
{"NewStartPort", extPortStart},
{"NewEndPort", extPortEnd},
{"NewProtocol", proto},
{"NewManage", manage},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
struct NameValueParserData pdata; struct NameValueParserData pdata;
@@ -529,22 +514,10 @@ UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
if(!extPortStart || !extPortEnd || !proto || !manage) if(!extPortStart || !extPortEnd || !proto || !manage)
return UPNPCOMMAND_INVALID_ARGS; 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;
buffer = simpleUPnPcommand(-1, controlURL, servicetype, buffer = simpleUPnPcommand(controlURL, servicetype,
"DeletePortMappingRange", "DeletePortMappingRange",
DeletePortMappingArgs, &bufsize); DeletePortMappingRangeArgs, &bufsize);
free(DeletePortMappingArgs);
if(!buffer) { if(!buffer) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -552,8 +525,8 @@ UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
free(buffer); free(buffer);
resVal = GetValueFromNameValueList(&pdata, "errorCode"); resVal = GetValueFromNameValueList(&pdata, "errorCode");
if(resVal) { if(resVal) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(resVal, "%d", &ret) != 1)
sscanf(resVal, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} else { } else {
ret = UPNPCOMMAND_SUCCESS; ret = UPNPCOMMAND_SUCCESS;
} }
@@ -564,35 +537,51 @@ UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
UPNP_GetGenericPortMappingEntry(const char * controlURL, UPNP_GetGenericPortMappingEntry(const char * controlURL,
const char * servicetype, const char * servicetype,
const char * index, const char * index,
char * extPort, char * extPort,
char * intClient, char * intClient,
char * intPort, char * intPort,
char * protocol, char * protocol,
char * desc, char * desc,
char * enabled, char * enabled,
char * rHost, char * rHost,
char * duration) char * duration)
{
return UPNP_GetGenericPortMappingEntryExt(controlURL, servicetype, index,
extPort, intClient, intPort,
protocol, desc, 80, enabled,
rHost, 64, duration);
}
MINIUPNP_LIBSPEC int
UPNP_GetGenericPortMappingEntryExt(const char * controlURL,
const char * servicetype,
const char * index,
char * extPort,
char * intClient,
char * intPort,
char * protocol,
char * desc,
size_t desclen,
char * enabled,
char * rHost,
size_t rHostlen,
char * duration)
{ {
struct NameValueParserData pdata; struct NameValueParserData pdata;
struct UPNParg * GetPortMappingArgs; struct UPNParg GetPortMappingArgs[] = {
{"NewPortMappingIndex", index},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
char * p; char * p;
int r = UPNPCOMMAND_UNKNOWN_ERROR; int ret = UPNPCOMMAND_UNKNOWN_ERROR;
if(!index) if(!index || !extPort || !intClient || !intPort || !protocol)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
intClient[0] = '\0'; buffer = simpleUPnPcommand(controlURL, servicetype,
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;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"GetGenericPortMappingEntry", "GetGenericPortMappingEntry",
GetPortMappingArgs, &bufsize); GetPortMappingArgs, &bufsize);
free(GetPortMappingArgs);
if(!buffer) { if(!buffer) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -602,28 +591,40 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); p = GetValueFromNameValueList(&pdata, "NewRemoteHost");
if(p && rHost) if(p && rHost)
{ {
strncpy(rHost, p, 64); strncpy(rHost, p, rHostlen);
rHost[63] = '\0'; rHost[rHostlen-1] = '\0';
} }
p = GetValueFromNameValueList(&pdata, "NewExternalPort"); p = GetValueFromNameValueList(&pdata, "NewExternalPort");
if(p && extPort) if(p)
{ {
strncpy(extPort, p, 6); strncpy(extPort, p, 6);
extPort[5] = '\0'; extPort[5] = '\0';
r = UPNPCOMMAND_SUCCESS; ret = UPNPCOMMAND_SUCCESS;
}
else
{
extPort[0] = '\0';
} }
p = GetValueFromNameValueList(&pdata, "NewProtocol"); p = GetValueFromNameValueList(&pdata, "NewProtocol");
if(p && protocol) if(p)
{ {
strncpy(protocol, p, 4); strncpy(protocol, p, 4);
protocol[3] = '\0'; protocol[3] = '\0';
} }
else
{
protocol[0] = '\0';
}
p = GetValueFromNameValueList(&pdata, "NewInternalClient"); p = GetValueFromNameValueList(&pdata, "NewInternalClient");
if(p) if(p)
{ {
strncpy(intClient, p, 16); strncpy(intClient, p, 16);
intClient[15] = '\0'; intClient[15] = '\0';
r = 0; ret = 0;
}
else
{
intClient[0] = '\0';
} }
p = GetValueFromNameValueList(&pdata, "NewInternalPort"); p = GetValueFromNameValueList(&pdata, "NewInternalPort");
if(p) if(p)
@@ -631,6 +632,10 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
strncpy(intPort, p, 6); strncpy(intPort, p, 6);
intPort[5] = '\0'; intPort[5] = '\0';
} }
else
{
intPort[0] = '\0';
}
p = GetValueFromNameValueList(&pdata, "NewEnabled"); p = GetValueFromNameValueList(&pdata, "NewEnabled");
if(p && enabled) if(p && enabled)
{ {
@@ -640,8 +645,8 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription");
if(p && desc) if(p && desc)
{ {
strncpy(desc, p, 80); strncpy(desc, p, desclen);
desc[79] = '\0'; desc[desclen-1] = '\0';
} }
p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); p = GetValueFromNameValueList(&pdata, "NewLeaseDuration");
if(p && duration) if(p && duration)
@@ -651,11 +656,11 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
} }
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) { if(p) {
r = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &r); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
return r; return ret;
} }
MINIUPNP_LIBSPEC int MINIUPNP_LIBSPEC int
@@ -663,12 +668,12 @@ UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
const char * servicetype, const char * servicetype,
unsigned int * numEntries) unsigned int * numEntries)
{ {
struct NameValueParserData pdata; struct NameValueParserData pdata;
char * buffer; char * buffer;
int bufsize; int bufsize;
char* p; char* p;
int ret = UPNPCOMMAND_UNKNOWN_ERROR; int ret = UPNPCOMMAND_UNKNOWN_ERROR;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(controlURL, servicetype,
"GetPortMappingNumberOfEntries", 0, "GetPortMappingNumberOfEntries", 0,
&bufsize))) { &bufsize))) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
@@ -676,23 +681,23 @@ UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
#ifdef DEBUG #ifdef DEBUG
DisplayNameValueList(buffer, bufsize); DisplayNameValueList(buffer, bufsize);
#endif #endif
ParseNameValue(buffer, bufsize, &pdata); ParseNameValue(buffer, bufsize, &pdata);
free(buffer); free(buffer);
p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries");
if(numEntries && p) { if(numEntries && p) {
*numEntries = 0; *numEntries = 0;
sscanf(p, "%u", numEntries); sscanf(p, "%u", numEntries);
ret = UPNPCOMMAND_SUCCESS; ret = UPNPCOMMAND_SUCCESS;
} }
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) { if(p) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
return ret; return ret;
} }
@@ -710,9 +715,34 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
char * desc, char * desc,
char * enabled, char * enabled,
char * leaseDuration) char * leaseDuration)
{
return UPNP_GetSpecificPortMappingEntryExt(controlURL, servicetype,
extPort, proto, remoteHost,
intClient, intPort,
desc, 80, enabled,
leaseDuration);
}
MINIUPNP_LIBSPEC int
UPNP_GetSpecificPortMappingEntryExt(const char * controlURL,
const char * servicetype,
const char * extPort,
const char * proto,
const char * remoteHost,
char * intClient,
char * intPort,
char * desc,
size_t desclen,
char * enabled,
char * leaseDuration)
{ {
struct NameValueParserData pdata; struct NameValueParserData pdata;
struct UPNParg * GetPortMappingArgs; struct UPNParg GetPortMappingArgs[] = {
{"NewRemoteHost", remoteHost},
{"NewExternalPort", extPort},
{"NewProtocol", proto},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
char * p; char * p;
@@ -721,19 +751,9 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
if(!intPort || !intClient || !extPort || !proto) if(!intPort || !intClient || !extPort || !proto)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); buffer = simpleUPnPcommand(controlURL, servicetype,
if(GetPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPortMappingArgs[0].elt = "NewRemoteHost";
GetPortMappingArgs[0].val = remoteHost;
GetPortMappingArgs[1].elt = "NewExternalPort";
GetPortMappingArgs[1].val = extPort;
GetPortMappingArgs[2].elt = "NewProtocol";
GetPortMappingArgs[2].val = proto;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"GetSpecificPortMappingEntry", "GetSpecificPortMappingEntry",
GetPortMappingArgs, &bufsize); GetPortMappingArgs, &bufsize);
free(GetPortMappingArgs);
if(!buffer) { if(!buffer) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -764,8 +784,8 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription");
if(p && desc) { if(p && desc) {
strncpy(desc, p, 80); strncpy(desc, p, desclen);
desc[79] = '\0'; desc[desclen-1] = '\0';
} }
p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); p = GetValueFromNameValueList(&pdata, "NewLeaseDuration");
@@ -777,8 +797,8 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) { if(p) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
@@ -803,7 +823,14 @@ UPNP_GetListOfPortMappings(const char * controlURL,
struct PortMappingParserData * data) struct PortMappingParserData * data)
{ {
struct NameValueParserData pdata; struct NameValueParserData pdata;
struct UPNParg * GetListOfPortMappingsArgs; struct UPNParg GetListOfPortMappingsArgs[] = {
{"NewStartPort", startPort},
{"NewEndPort", endPort},
{"NewProtocol", protocol},
{"NewManage", "1"},
{"NewNumberOfPorts", numberOfPorts?numberOfPorts:"1000"},
{NULL, NULL}
};
const char * p; const char * p;
char * buffer; char * buffer;
int bufsize; int bufsize;
@@ -812,24 +839,9 @@ UPNP_GetListOfPortMappings(const char * controlURL,
if(!startPort || !endPort || !protocol) if(!startPort || !endPort || !protocol)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); buffer = simpleUPnPcommand(controlURL, servicetype,
if(GetListOfPortMappingsArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetListOfPortMappingsArgs[0].elt = "NewStartPort";
GetListOfPortMappingsArgs[0].val = startPort;
GetListOfPortMappingsArgs[1].elt = "NewEndPort";
GetListOfPortMappingsArgs[1].val = endPort;
GetListOfPortMappingsArgs[2].elt = "NewProtocol";
GetListOfPortMappingsArgs[2].val = protocol;
GetListOfPortMappingsArgs[3].elt = "NewManage";
GetListOfPortMappingsArgs[3].val = "1";
GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts";
GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000";
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"GetListOfPortMappings", "GetListOfPortMappings",
GetListOfPortMappingsArgs, &bufsize); GetListOfPortMappingsArgs, &bufsize);
free(GetListOfPortMappingsArgs);
if(!buffer) { if(!buffer) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
} }
@@ -866,8 +878,8 @@ UPNP_GetListOfPortMappings(const char * controlURL,
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) { if(p) {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
@@ -892,7 +904,7 @@ UPNP_GetFirewallStatus(const char * controlURL,
if(!firewallEnabled || !inboundPinholeAllowed) if(!firewallEnabled || !inboundPinholeAllowed)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
buffer = simpleUPnPcommand(-1, controlURL, servicetype, buffer = simpleUPnPcommand(controlURL, servicetype,
"GetFirewallStatus", 0, &bufsize); "GetFirewallStatus", 0, &bufsize);
if(!buffer) { if(!buffer) {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
@@ -914,8 +926,8 @@ UPNP_GetFirewallStatus(const char * controlURL,
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) if(p)
{ {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
return ret; return ret;
@@ -930,7 +942,14 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
const char * proto, const char * proto,
int * opTimeout) int * opTimeout)
{ {
struct UPNParg * GetOutboundPinholeTimeoutArgs; struct UPNParg GetOutboundPinholeTimeoutArgs[] = {
{"RemoteHost", remoteHost},
{"RemotePort", remotePort},
{"Protocol", proto},
{"InternalPort", intPort},
{"InternalClient", intClient},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
struct NameValueParserData pdata; struct NameValueParserData pdata;
@@ -940,22 +959,8 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
if(!intPort || !intClient || !proto || !remotePort || !remoteHost) if(!intPort || !intClient || !proto || !remotePort || !remoteHost)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); buffer = simpleUPnPcommand(controlURL, servicetype,
if(GetOutboundPinholeTimeoutArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost";
GetOutboundPinholeTimeoutArgs[0].val = remoteHost;
GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort";
GetOutboundPinholeTimeoutArgs[1].val = remotePort;
GetOutboundPinholeTimeoutArgs[2].elt = "Protocol";
GetOutboundPinholeTimeoutArgs[2].val = proto;
GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort";
GetOutboundPinholeTimeoutArgs[3].val = intPort;
GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient";
GetOutboundPinholeTimeoutArgs[4].val = intClient;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize);
free(GetOutboundPinholeTimeoutArgs);
if(!buffer) if(!buffer)
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
ParseNameValue(buffer, bufsize, &pdata); ParseNameValue(buffer, bufsize, &pdata);
@@ -963,8 +968,8 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
resVal = GetValueFromNameValueList(&pdata, "errorCode"); resVal = GetValueFromNameValueList(&pdata, "errorCode");
if(resVal) if(resVal)
{ {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(resVal, "%d", &ret) != 1)
sscanf(resVal, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
else else
{ {
@@ -987,7 +992,15 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
const char * leaseTime, const char * leaseTime,
char * uniqueID) char * uniqueID)
{ {
struct UPNParg * AddPinholeArgs; struct UPNParg AddPinholeArgs[] = {
{"RemoteHost", ""},
{"RemotePort", remotePort},
{"Protocol", proto},
{"InternalPort", intPort},
{"InternalClient", ""},
{"LeaseTime", leaseTime},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
struct NameValueParserData pdata; struct NameValueParserData pdata;
@@ -998,41 +1011,14 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); /* RemoteHost and InternalClient can be wilcarded
if(AddPinholeArgs == NULL) * accept both the empty string and "empty" as wildcard */
return UPNPCOMMAND_MEM_ALLOC_ERROR; if(strncmp(remoteHost, "empty", 5) != 0)
/* RemoteHost can be wilcarded */
if(strncmp(remoteHost, "empty", 5)==0)
{
AddPinholeArgs[0].elt = "RemoteHost";
AddPinholeArgs[0].val = "";
}
else
{
AddPinholeArgs[0].elt = "RemoteHost";
AddPinholeArgs[0].val = remoteHost; AddPinholeArgs[0].val = remoteHost;
} if(strncmp(intClient, "empty", 5) != 0)
AddPinholeArgs[1].elt = "RemotePort";
AddPinholeArgs[1].val = remotePort;
AddPinholeArgs[2].elt = "Protocol";
AddPinholeArgs[2].val = proto;
AddPinholeArgs[3].elt = "InternalPort";
AddPinholeArgs[3].val = intPort;
if(strncmp(intClient, "empty", 5)==0)
{
AddPinholeArgs[4].elt = "InternalClient";
AddPinholeArgs[4].val = "";
}
else
{
AddPinholeArgs[4].elt = "InternalClient";
AddPinholeArgs[4].val = intClient; AddPinholeArgs[4].val = intClient;
} buffer = simpleUPnPcommand(controlURL, servicetype,
AddPinholeArgs[5].elt = "LeaseTime";
AddPinholeArgs[5].val = leaseTime;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"AddPinhole", AddPinholeArgs, &bufsize); "AddPinhole", AddPinholeArgs, &bufsize);
free(AddPinholeArgs);
if(!buffer) if(!buffer)
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
ParseNameValue(buffer, bufsize, &pdata); ParseNameValue(buffer, bufsize, &pdata);
@@ -1047,8 +1033,8 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
if(resVal) if(resVal)
{ {
/*printf("AddPortMapping errorCode = '%s'\n", resVal);*/ /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(resVal, "%d", &ret) != 1)
sscanf(resVal, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
else else
{ {
@@ -1063,7 +1049,11 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
const char * uniqueID, const char * uniqueID,
const char * leaseTime) const char * leaseTime)
{ {
struct UPNParg * UpdatePinholeArgs; struct UPNParg UpdatePinholeArgs[] = {
{"UniqueID", uniqueID},
{"NewLeaseTime", leaseTime},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
struct NameValueParserData pdata; struct NameValueParserData pdata;
@@ -1073,16 +1063,8 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
if(!uniqueID || !leaseTime) if(!uniqueID || !leaseTime)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); buffer = simpleUPnPcommand(controlURL, servicetype,
if(UpdatePinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
UpdatePinholeArgs[0].elt = "UniqueID";
UpdatePinholeArgs[0].val = uniqueID;
UpdatePinholeArgs[1].elt = "NewLeaseTime";
UpdatePinholeArgs[1].val = leaseTime;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"UpdatePinhole", UpdatePinholeArgs, &bufsize); "UpdatePinhole", UpdatePinholeArgs, &bufsize);
free(UpdatePinholeArgs);
if(!buffer) if(!buffer)
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
ParseNameValue(buffer, bufsize, &pdata); ParseNameValue(buffer, bufsize, &pdata);
@@ -1091,8 +1073,8 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
if(resVal) if(resVal)
{ {
/*printf("AddPortMapping errorCode = '%s'\n", resVal); */ /*printf("AddPortMapping errorCode = '%s'\n", resVal); */
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(resVal, "%d", &ret) != 1)
sscanf(resVal, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
else else
{ {
@@ -1106,7 +1088,10 @@ MINIUPNP_LIBSPEC int
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID)
{ {
/*struct NameValueParserData pdata;*/ /*struct NameValueParserData pdata;*/
struct UPNParg * DeletePinholeArgs; struct UPNParg DeletePinholeArgs[] = {
{"UniqueID", uniqueID},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
struct NameValueParserData pdata; struct NameValueParserData pdata;
@@ -1116,14 +1101,8 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char
if(!uniqueID) if(!uniqueID)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); buffer = simpleUPnPcommand(controlURL, servicetype,
if(DeletePinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePinholeArgs[0].elt = "UniqueID";
DeletePinholeArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"DeletePinhole", DeletePinholeArgs, &bufsize); "DeletePinhole", DeletePinholeArgs, &bufsize);
free(DeletePinholeArgs);
if(!buffer) if(!buffer)
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
/*DisplayNameValueList(buffer, bufsize);*/ /*DisplayNameValueList(buffer, bufsize);*/
@@ -1132,8 +1111,8 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char
resVal = GetValueFromNameValueList(&pdata, "errorCode"); resVal = GetValueFromNameValueList(&pdata, "errorCode");
if(resVal) if(resVal)
{ {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(resVal, "%d", &ret) != 1)
sscanf(resVal, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
else else
{ {
@@ -1148,7 +1127,10 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
const char * uniqueID, int * isWorking) const char * uniqueID, int * isWorking)
{ {
struct NameValueParserData pdata; struct NameValueParserData pdata;
struct UPNParg * CheckPinholeWorkingArgs; struct UPNParg CheckPinholeWorkingArgs[] = {
{"UniqueID", uniqueID},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
char * p; char * p;
@@ -1157,14 +1139,8 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
if(!uniqueID) if(!uniqueID)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); buffer = simpleUPnPcommand(controlURL, servicetype,
if(CheckPinholeWorkingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
CheckPinholeWorkingArgs[0].elt = "UniqueID";
CheckPinholeWorkingArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize);
free(CheckPinholeWorkingArgs);
if(!buffer) if(!buffer)
{ {
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
@@ -1184,8 +1160,8 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) if(p)
{ {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
@@ -1197,7 +1173,10 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
const char * uniqueID, int * packets) const char * uniqueID, int * packets)
{ {
struct NameValueParserData pdata; struct NameValueParserData pdata;
struct UPNParg * GetPinholePacketsArgs; struct UPNParg GetPinholePacketsArgs[] = {
{"UniqueID", uniqueID},
{NULL, NULL}
};
char * buffer; char * buffer;
int bufsize; int bufsize;
char * p; char * p;
@@ -1206,14 +1185,8 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
if(!uniqueID) if(!uniqueID)
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); buffer = simpleUPnPcommand(controlURL, servicetype,
if(GetPinholePacketsArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPinholePacketsArgs[0].elt = "UniqueID";
GetPinholePacketsArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
"GetPinholePackets", GetPinholePacketsArgs, &bufsize); "GetPinholePackets", GetPinholePacketsArgs, &bufsize);
free(GetPinholePacketsArgs);
if(!buffer) if(!buffer)
return UPNPCOMMAND_HTTP_ERROR; return UPNPCOMMAND_HTTP_ERROR;
ParseNameValue(buffer, bufsize, &pdata); ParseNameValue(buffer, bufsize, &pdata);
@@ -1229,8 +1202,8 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
p = GetValueFromNameValueList(&pdata, "errorCode"); p = GetValueFromNameValueList(&pdata, "errorCode");
if(p) if(p)
{ {
ret = UPNPCOMMAND_UNKNOWN_ERROR; if(sscanf(p, "%d", &ret) != 1)
sscanf(p, "%d", &ret); ret = UPNPCOMMAND_UNKNOWN_ERROR;
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);

View File

@@ -1,8 +1,8 @@
/* $Id: upnpreplyparse.c,v 1.20 2017/12/12 11:26:25 nanard Exp $ */ /* $Id: upnpreplyparse.c,v 1.22 2025/02/08 23:12:26 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* MiniUPnP project * MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* (c) 2006-2019 Thomas Bernard * (c) 2006-2025 Thomas Bernard
* This software is subject to the conditions detailed * This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */ * in the LICENCE file provided within the distribution */
@@ -13,6 +13,23 @@
#include "upnpreplyparse.h" #include "upnpreplyparse.h"
#include "minixml.h" #include "minixml.h"
struct NameValue {
/*! \brief pointer to the next element */
struct NameValue * l_next;
/*! \brief name */
char name[64];
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 flexible array member */
/*! \brief character value */
char value[];
#elif defined(__GNUC__)
char value[0];
#else
/* Fallback to a hack */
char value[1];
#endif
};
static void static void
NameValueParserStartElt(void * d, const char * name, int l) NameValueParserStartElt(void * d, const char * name, int l)
{ {
@@ -40,7 +57,7 @@ NameValueParserEndElt(void * d, const char * name, int namelen)
int l; int l;
/* standard case. Limited to n chars strings */ /* standard case. Limited to n chars strings */
l = data->cdatalen; l = data->cdatalen;
nv = malloc(sizeof(struct NameValue)); nv = malloc(sizeof(struct NameValue) + l + 1);
if(nv == NULL) if(nv == NULL)
{ {
/* malloc error */ /* malloc error */
@@ -50,8 +67,6 @@ NameValueParserEndElt(void * d, const char * name, int namelen)
#endif /* DEBUG */ #endif /* DEBUG */
return; return;
} }
if(l>=(int)sizeof(nv->value))
l = sizeof(nv->value) - 1;
strncpy(nv->name, data->curelt, 64); strncpy(nv->name, data->curelt, 64);
nv->name[63] = '\0'; nv->name[63] = '\0';
if(data->cdata != NULL) if(data->cdata != NULL)
@@ -137,7 +152,7 @@ ClearNameValueList(struct NameValueParserData * pdata)
char * char *
GetValueFromNameValueList(struct NameValueParserData * pdata, GetValueFromNameValueList(struct NameValueParserData * pdata,
const char * Name) const char * name)
{ {
struct NameValue * nv; struct NameValue * nv;
char * p = NULL; char * p = NULL;
@@ -145,37 +160,12 @@ GetValueFromNameValueList(struct NameValueParserData * pdata,
(nv != NULL) && (p == NULL); (nv != NULL) && (p == NULL);
nv = nv->l_next) nv = nv->l_next)
{ {
if(strcmp(nv->name, Name) == 0) if(strcmp(nv->name, name) == 0)
p = nv->value; p = nv->value;
} }
return p; return p;
} }
#if 0
/* useless now that minixml ignores namespaces by itself */
char *
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
const char * Name)
{
struct NameValue * nv;
char * p = NULL;
char * pname;
for(nv = pdata->head.lh_first;
(nv != NULL) && (p == NULL);
nv = nv->entries.le_next)
{
pname = strrchr(nv->name, ':');
if(pname)
pname++;
else
pname = nv->name;
if(strcmp(pname, Name)==0)
p = nv->value;
}
return p;
}
#endif
/* debug all-in-one function /* debug all-in-one function
* do parsing then display to stdout */ * do parsing then display to stdout */
#ifdef DEBUG #ifdef DEBUG