initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
This commit is contained in:
29
thirdparty/miniupnpc/LICENSE
vendored
Normal file
29
thirdparty/miniupnpc/LICENSE
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2005-2025, Thomas BERNARD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
75
thirdparty/miniupnpc/include/miniupnpc/igd_desc_parse.h
vendored
Normal file
75
thirdparty/miniupnpc/include/miniupnpc/igd_desc_parse.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/* $Id: igd_desc_parse.h,v 1.14 2025/02/08 23:15:16 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* 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
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef IGD_DESC_PARSE_H_INCLUDED
|
||||
#define IGD_DESC_PARSE_H_INCLUDED
|
||||
|
||||
/*! \file igd_desc_parse.h
|
||||
* \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)
|
||||
|
||||
/*! \brief Structure to store the result of the parsing of UPnP
|
||||
* descriptions of Internet Gateway Devices services */
|
||||
struct IGDdatas_service {
|
||||
/*! \brief controlURL for the service */
|
||||
char controlurl[MINIUPNPC_URL_MAXSIZE];
|
||||
/*! \brief eventSubURL for the service */
|
||||
char eventsuburl[MINIUPNPC_URL_MAXSIZE];
|
||||
/*! \brief SCPDURL for the service */
|
||||
char scpdurl[MINIUPNPC_URL_MAXSIZE];
|
||||
/*! \brief serviceType */
|
||||
char servicetype[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 {
|
||||
/*! \brief current element name */
|
||||
char cureltname[MINIUPNPC_URL_MAXSIZE];
|
||||
/*! \brief URLBase */
|
||||
char urlbase[MINIUPNPC_URL_MAXSIZE];
|
||||
/*! \brief presentationURL */
|
||||
char presentationurl[MINIUPNPC_URL_MAXSIZE];
|
||||
/*! \brief depth into the XML tree */
|
||||
int level;
|
||||
/*! \brief "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
|
||||
struct IGDdatas_service CIF;
|
||||
/*! \brief first of "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||
* or "urn:schemas-upnp-org:service:WANPPPConnection:1" */
|
||||
struct IGDdatas_service first;
|
||||
/*! \brief second of "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||
* or "urn:schemas-upnp-org:service:WANPPPConnection:1" */
|
||||
struct IGDdatas_service second;
|
||||
/*! \brief "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */
|
||||
struct IGDdatas_service IPv6FC;
|
||||
/*! \brief currently parsed service */
|
||||
struct IGDdatas_service tmp;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief XML start element handler
|
||||
*/
|
||||
void IGDstartelt(void *, const char *, int);
|
||||
/*!
|
||||
* \brief XML end element handler
|
||||
*/
|
||||
void IGDendelt(void *, const char *, int);
|
||||
/*!
|
||||
* \brief XML characted data handler
|
||||
*/
|
||||
void IGDdata(void *, const char *, int);
|
||||
#ifdef DEBUG
|
||||
void printIGD(struct IGDdatas *);
|
||||
#endif /* DEBUG */
|
||||
|
||||
#endif /* IGD_DESC_PARSE_H_INCLUDED */
|
305
thirdparty/miniupnpc/include/miniupnpc/miniupnpc.h
vendored
Normal file
305
thirdparty/miniupnpc/include/miniupnpc/miniupnpc.h
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
/* $Id: miniupnpc.h,v 1.80 2025/05/26 22:56:40 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2025 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef MINIUPNPC_H_INCLUDED
|
||||
#define MINIUPNPC_H_INCLUDED
|
||||
|
||||
/*! \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 "igd_desc_parse.h"
|
||||
#include "upnpdev.h"
|
||||
|
||||
/* error codes : */
|
||||
/*! \brief value for success */
|
||||
#define UPNPDISCOVER_SUCCESS (0)
|
||||
/*! \brief value for unknown error */
|
||||
#define UPNPDISCOVER_UNKNOWN_ERROR (-1)
|
||||
/*! \brief value for a socket error */
|
||||
#define UPNPDISCOVER_SOCKET_ERROR (-101)
|
||||
/*! \brief value for a memory allocation error */
|
||||
#define UPNPDISCOVER_MEMORY_ERROR (-102)
|
||||
|
||||
/*! \brief software version */
|
||||
#define MINIUPNPC_VERSION "2.3.3"
|
||||
/*! \brief C API version */
|
||||
#define MINIUPNPC_API_VERSION 21
|
||||
|
||||
/*! \brief any (ie system chosen) port */
|
||||
#define UPNP_LOCAL_PORT_ANY 0
|
||||
/*! \brief Use as an alias for 1900 for backwards compatibility */
|
||||
#define UPNP_LOCAL_PORT_SAME 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Structures definitions : */
|
||||
|
||||
/*!
|
||||
* \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 *
|
||||
simpleUPnPcommand(const char * url, const char * service,
|
||||
const char * action, const struct UPNParg * args,
|
||||
int * bufsize);
|
||||
|
||||
/*!
|
||||
* \brief Discover UPnP IGD on the network.
|
||||
*
|
||||
* The discovered devices are returned as a chained list.
|
||||
* It is up to the caller to free the list with freeUPNPDevlist().
|
||||
* If available, device list will be obtained from MiniSSDPd.
|
||||
*
|
||||
* \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 *
|
||||
upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
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 *
|
||||
upnpDiscoverAll(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
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 *
|
||||
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
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 *
|
||||
upnpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes);
|
||||
|
||||
/*!
|
||||
* \brief parse root XML description of a UPnP device
|
||||
*
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* \brief structure used to get fast access to urls
|
||||
*/
|
||||
struct UPNPUrls {
|
||||
/*! \brief controlURL of the WANIPConnection */
|
||||
char * controlURL;
|
||||
/*! \brief url of the description of the WANIPConnection */
|
||||
char * ipcondescURL;
|
||||
/*! \brief controlURL of the WANCommonInterfaceConfig */
|
||||
char * controlURL_CIF;
|
||||
/*! \brief controlURL of the WANIPv6FirewallControl */
|
||||
char * controlURL_6FC;
|
||||
/*! \brief url of the root description */
|
||||
char * rootdescURL;
|
||||
};
|
||||
|
||||
/*! \brief NO IGD found */
|
||||
#define UPNP_NO_IGD (0)
|
||||
/*! \brief valid and connected IGD */
|
||||
#define UPNP_CONNECTED_IGD (1)
|
||||
/*! \brief valid and connected IGD but with a reserved address
|
||||
* (non routable) */
|
||||
#define UPNP_PRIVATEIP_IGD (2)
|
||||
/*! \brief valid but not connected 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
|
||||
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
||||
* 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
|
||||
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen,
|
||||
char * wanaddr, int wanaddrlen);
|
||||
|
||||
/*!
|
||||
* \brief Get IGD URLs and data for URL
|
||||
*
|
||||
* Used when skipping the discovery process.
|
||||
* \param[in] rootdescurl Root description URL of the device
|
||||
* \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
|
||||
* \return 0 Not ok / 1 OK
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetIGDFromUrl(const char * rootdescurl,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
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
|
||||
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
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
|
||||
FreeUPNPUrls(struct UPNPUrls * urls);
|
||||
|
||||
/*!
|
||||
* \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
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
22
thirdparty/miniupnpc/include/miniupnpc/miniupnpc_declspec.h
vendored
Normal file
22
thirdparty/miniupnpc/include/miniupnpc/miniupnpc_declspec.h
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef 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)
|
||||
/* for windows dll */
|
||||
#ifdef MINIUPNP_EXPORTS
|
||||
#define MINIUPNP_LIBSPEC __declspec(dllexport)
|
||||
#else
|
||||
#define MINIUPNP_LIBSPEC __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */
|
||||
#define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define MINIUPNP_LIBSPEC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */
|
27
thirdparty/miniupnpc/include/miniupnpc/miniupnpctypes.h
vendored
Normal file
27
thirdparty/miniupnpc/include/miniupnpc/miniupnpctypes.h
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/* $Id: miniupnpctypes.h,v 1.4 2025/02/08 23:15:16 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2021-2025 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided within this distribution */
|
||||
#ifndef MINIUPNPCTYPES_H_INCLUDED
|
||||
#define MINIUPNPCTYPES_H_INCLUDED
|
||||
|
||||
/*! \file miniupnpctypes.h
|
||||
* \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
|
||||
#define UNSIGNED_INTEGER unsigned long long
|
||||
#else
|
||||
#define UNSIGNED_INTEGER unsigned int
|
||||
#endif
|
||||
|
||||
#endif
|
54
thirdparty/miniupnpc/include/miniupnpc/miniwget.h
vendored
Normal file
54
thirdparty/miniupnpc/include/miniupnpc/miniwget.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/* $Id: miniwget.h,v 1.14 2025/02/08 23:15:17 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : 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
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef MINIWGET_H_INCLUDED
|
||||
#define MINIWGET_H_INCLUDED
|
||||
|
||||
/*! \file miniwget.h
|
||||
* \brief Lightweight HTTP client API
|
||||
*/
|
||||
#include "miniupnpc_declspec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \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);
|
||||
|
||||
/*! \brief perform HTTP GET on an URL
|
||||
*
|
||||
* 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
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
91
thirdparty/miniupnpc/include/miniupnpc/portlistingparse.h
vendored
Normal file
91
thirdparty/miniupnpc/include/miniupnpc/portlistingparse.h
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/* $Id: portlistingparse.h,v 1.12 2025/02/08 23:15:17 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2025 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#ifndef PORTLISTINGPARSE_H_INCLUDED
|
||||
#define PORTLISTINGPARSE_H_INCLUDED
|
||||
|
||||
/*! \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"
|
||||
/* for the definition of UNSIGNED_INTEGER */
|
||||
#include "miniupnpctypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief enum of all XML elements
|
||||
*/
|
||||
typedef enum { PortMappingEltNone,
|
||||
PortMappingEntry, NewRemoteHost,
|
||||
NewExternalPort, NewProtocol,
|
||||
NewInternalPort, NewInternalClient,
|
||||
NewEnabled, NewDescription,
|
||||
NewLeaseTime } portMappingElt;
|
||||
|
||||
/*!
|
||||
* \brief linked list of port mappings
|
||||
*/
|
||||
struct PortMapping {
|
||||
struct PortMapping * l_next; /*!< \brief next list element */
|
||||
UNSIGNED_INTEGER leaseTime; /*!< \brief in seconds */
|
||||
unsigned short externalPort; /*!< \brief external port */
|
||||
unsigned short internalPort; /*!< \brief internal port */
|
||||
char remoteHost[64]; /*!< \brief empty for wildcard */
|
||||
char internalClient[64]; /*!< \brief internal IP address */
|
||||
char description[64]; /*!< \brief description */
|
||||
char protocol[4]; /*!< \brief `TCP` or `UDP` */
|
||||
unsigned char enabled; /*!< \brief 0 (false) or 1 (true) */
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief structure for ParsePortListing()
|
||||
*/
|
||||
struct PortMappingParserData {
|
||||
struct PortMapping * l_head; /*!< \brief list head */
|
||||
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
|
||||
ParsePortListing(const char * buffer, int bufsize,
|
||||
struct PortMappingParserData * pdata);
|
||||
|
||||
/*!
|
||||
* \brief free parsed data structure
|
||||
*
|
||||
* \param[in] pdata Parsed data to free
|
||||
*/
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreePortListing(struct PortMappingParserData * pdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
645
thirdparty/miniupnpc/include/miniupnpc/upnpcommands.h
vendored
Normal file
645
thirdparty/miniupnpc/include/miniupnpc/upnpcommands.h
vendored
Normal file
@@ -0,0 +1,645 @@
|
||||
/* $Id: upnpcommands.h,v 1.36 2025/03/18 23:40:15 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project: miniupnp
|
||||
* 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
|
||||
* LICENCE file provided within this distribution */
|
||||
#ifndef 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 "miniupnpctypes.h"
|
||||
|
||||
/* MiniUPnPc return codes : */
|
||||
/*! \brief value for success */
|
||||
#define UPNPCOMMAND_SUCCESS (0)
|
||||
/*! \brief value for unknown error */
|
||||
#define UPNPCOMMAND_UNKNOWN_ERROR (-1)
|
||||
/*! \brief error while checking the arguments */
|
||||
#define UPNPCOMMAND_INVALID_ARGS (-2)
|
||||
/*! \brief HTTP communication error */
|
||||
#define UPNPCOMMAND_HTTP_ERROR (-3)
|
||||
/*! \brief The response contains invalid values */
|
||||
#define UPNPCOMMAND_INVALID_RESPONSE (-4)
|
||||
/*! \brief Memory allocation error */
|
||||
#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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
|
||||
UPNP_GetTotalBytesSent(const char * controlURL,
|
||||
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
|
||||
UPNP_GetTotalBytesReceived(const char * controlURL,
|
||||
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
|
||||
UPNP_GetTotalPacketsSent(const char * controlURL,
|
||||
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
|
||||
UPNP_GetTotalPacketsReceived(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
/*! \brief WANIPConnection:GetStatusInfo()
|
||||
*
|
||||
* \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
|
||||
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
|
||||
* \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
|
||||
UPNP_GetStatusInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * status,
|
||||
unsigned int * uptime,
|
||||
char * lastconnerror);
|
||||
|
||||
/*! \brief WANIPConnection:GetConnectionTypeInfo()
|
||||
*
|
||||
* \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
|
||||
* \param[in] servicetype urn:schemas-upnp-org:service:WANIPConnection:1
|
||||
* \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
|
||||
UPNP_GetConnectionTypeInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * connectionType);
|
||||
|
||||
/*! \brief WANIPConnection:GetExternalIPAddress()
|
||||
*
|
||||
* possible UPnP Errors :
|
||||
* - 402 Invalid Args - 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
|
||||
UPNP_GetExternalIPAddress(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * extIpAdd);
|
||||
|
||||
/*! \brief UPNP_GetLinkLayerMaxBitRates()
|
||||
* call `WANCommonInterfaceConfig:GetCommonLinkProperties`
|
||||
*
|
||||
* \param[in] controlURL controlURL of the WANCommonInterfaceConfig of a WANDevice
|
||||
* \param[in] servicetype urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
|
||||
* \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
|
||||
UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
|
||||
const char* servicetype,
|
||||
unsigned int * bitrateDown,
|
||||
unsigned int * bitrateUp);
|
||||
|
||||
/*! \brief WANIPConnection:AddPortMapping()
|
||||
*
|
||||
* List of possible UPnP errors for AddPortMapping :
|
||||
* errorCode errorDescription (short) | Description (long)
|
||||
* ---------------------------------- | -----------------
|
||||
* 402 Invalid Args | See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed | See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized | The action requested REQUIRES authorization and the sender was not authorized.
|
||||
* 715 WildCardNotPermittedInSrcIP | The source IP address cannot be wild-carded
|
||||
* 716 WildCardNotPermittedInExtPort | The external port cannot be wild-carded
|
||||
* 718 ConflictInMappingEntry | The port mapping entry specified conflicts with a mapping assigned previously to another client
|
||||
* 724 SamePortValuesRequired | Internal and External port values must be the same
|
||||
* 725 OnlyPermanentLeasesSupported | The NAT implementation only supports permanent lease times on port mappings
|
||||
* 726 RemoteHostOnlySupportsWildcard | RemoteHost must be a wildcard and cannot be a specific IP address or DNS name
|
||||
* 727 ExternalPortOnlySupportsWildcard | ExternalPort must be a wildcard and cannot be a specific port value
|
||||
* 728 NoPortMapsAvailable | There are not enough free ports available to complete port mapping.
|
||||
* 729 ConflictWithOtherMechanisms | Attempted port mapping is not allowed due to conflict with other mechanisms.
|
||||
* 732 WildCardNotPermittedInIntPort | The internal port cannot be wild-carded
|
||||
*
|
||||
* \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] 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
|
||||
* \return #UPNPCOMMAND_SUCCESS, #UPNPCOMMAND_INVALID_ARGS,
|
||||
* #UPNPCOMMAND_MEM_ALLOC_ERROR, #UPNPCOMMAND_HTTP_ERROR,
|
||||
* #UPNPCOMMAND_UNKNOWN_ERROR or a UPnP error code.
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration);
|
||||
|
||||
/*! \brief WANIPConnection:AddAnyPortMapping()
|
||||
*
|
||||
* Only in WANIPConnection:2
|
||||
*
|
||||
* List of possible UPnP errors for AddPortMapping :
|
||||
* errorCode errorDescription (short) | Description (long)
|
||||
* ---------------------------------- | ------------------
|
||||
* 402 Invalid Args | See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed | See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized | The action requested REQUIRES authorization and the sender was not authorized.
|
||||
* 715 WildCardNotPermittedInSrcIP | The source IP address cannot be wild-carded
|
||||
* 716 WildCardNotPermittedInExtPort | The external port cannot be wild-carded
|
||||
* 728 NoPortMapsAvailable | There are not enough free ports available to complete port mapping.
|
||||
* 729 ConflictWithOtherMechanisms | Attempted port mapping is not allowed due to conflict with other mechanisms.
|
||||
* 732 WildCardNotPermittedInIntPort | The internal port cannot be wild-carded
|
||||
*
|
||||
* \param[in] controlURL controlURL of the WANIPConnection of a WANConnectionDevice
|
||||
* \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
|
||||
UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration,
|
||||
char * reservedPort);
|
||||
|
||||
/*! \brief WANIPConnection:DeletePortMapping()
|
||||
*
|
||||
* Use same argument values as what was used for UPNP_AddPortMapping()
|
||||
*
|
||||
* List of possible UPnP errors for UPNP_DeletePortMapping() :
|
||||
* 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.
|
||||
* 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
|
||||
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort, const char * proto,
|
||||
const char * remoteHost);
|
||||
|
||||
/*! \brief WANIPConnection:DeletePortRangeMapping()
|
||||
*
|
||||
* Only in WANIPConnection:2
|
||||
* 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 :
|
||||
* errorCode errorDescription (short) | Description (long)
|
||||
* ---------------------------------- | ------------------
|
||||
* 606 Action not authorized | The action requested REQUIRES authorization and the sender was not authorized.
|
||||
* 730 PortMappingNotFound | This error message is returned if no port mapping is found in the specified range.
|
||||
* 733 InconsistentParameters | NewStartPort and NewEndPort values are not consistent.
|
||||
* \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
|
||||
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
|
||||
const char * extPortStart, const char * extPortEnd,
|
||||
const char * proto,
|
||||
const char * manage);
|
||||
|
||||
/*! \brief WANIPConnection:GetPortMappingNumberOfEntries()
|
||||
*
|
||||
* 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
|
||||
UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
|
||||
const char * servicetype,
|
||||
unsigned int * numEntries);
|
||||
|
||||
/*! \brief retrieves an existing port mapping for a port:protocol
|
||||
*
|
||||
* List of possible UPnP errors for UPNP_GetSpecificPortMappingEntry() :
|
||||
* errorCode errorDescription (short) | Description (long)
|
||||
* ---------------------------------- | ------------------
|
||||
* 402 Invalid Args | See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed | See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized | The action requested REQUIRES authorization and the sender was not authorized.
|
||||
* 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
|
||||
* \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
|
||||
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
char * intClient,
|
||||
char * intPort,
|
||||
char * desc,
|
||||
char * enabled,
|
||||
char * leaseDuration);
|
||||
|
||||
/*! \brief retrieves an existing port mapping for a port:protocol
|
||||
*
|
||||
* List of possible UPnP errors for UPNP_GetSpecificPortMappingEntry() :
|
||||
* errorCode errorDescription (short) | Description (long)
|
||||
* ---------------------------------- | ------------------
|
||||
* 402 Invalid Args | See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed | See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized | The action requested REQUIRES authorization and the sender was not authorized.
|
||||
* 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
|
||||
* \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
|
||||
UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * index,
|
||||
char * extPort,
|
||||
char * intClient,
|
||||
char * intPort,
|
||||
char * protocol,
|
||||
char * desc,
|
||||
char * enabled,
|
||||
char * rHost,
|
||||
char * duration);
|
||||
|
||||
/*! \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 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
|
||||
UPNP_GetListOfPortMappings(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * startPort,
|
||||
const char * endPort,
|
||||
const char * protocol,
|
||||
const char * numberOfPorts,
|
||||
struct PortMappingParserData * data);
|
||||
|
||||
/*! \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
|
||||
UPNP_GetFirewallStatus(const char * controlURL,
|
||||
const char * servicetype,
|
||||
int * firewallEnabled,
|
||||
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
|
||||
UPNP_GetOutboundPinholeTimeout(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * remoteHost,
|
||||
const char * remotePort,
|
||||
const char * intClient,
|
||||
const char * intPort,
|
||||
const char * proto,
|
||||
int * opTimeout);
|
||||
|
||||
/*! \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
|
||||
UPNP_AddPinhole(const char * controlURL, const char * servicetype,
|
||||
const char * remoteHost,
|
||||
const char * remotePort,
|
||||
const char * intClient,
|
||||
const char * intPort,
|
||||
const char * proto,
|
||||
const char * leaseTime,
|
||||
char * uniqueID);
|
||||
|
||||
/*! \brief update a pinhole’s 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
|
||||
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID,
|
||||
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
|
||||
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
|
||||
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
|
||||
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
|
||||
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID, int * packets);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
58
thirdparty/miniupnpc/include/miniupnpc/upnpdev.h
vendored
Normal file
58
thirdparty/miniupnpc/include/miniupnpc/upnpdev.h
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/* $Id: upnpdev.h,v 1.6 2025/02/08 23:15:17 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2025 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#ifndef 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"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief UPnP device linked-list
|
||||
*/
|
||||
struct UPNPDev {
|
||||
/*! \brief pointer to the next element */
|
||||
struct UPNPDev * pNext;
|
||||
/*! \brief root description URL */
|
||||
char * descURL;
|
||||
/*! \brief ST: as advertised */
|
||||
char * st;
|
||||
/*! \brief USN: as advertised */
|
||||
char * usn;
|
||||
/*! \brief IPv6 scope id of the network interface */
|
||||
unsigned int scope_id;
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
/* C99 flexible array member */
|
||||
/*! \brief buffer for descURL, st and usn */
|
||||
char buffer[];
|
||||
#elif defined(__GNUC__)
|
||||
char buffer[0];
|
||||
#else
|
||||
/* Fallback to a hack */
|
||||
char buffer[1];
|
||||
#endif
|
||||
};
|
||||
|
||||
/*! \brief free list returned by upnpDiscover()
|
||||
* \param[in] devlist linked list to free
|
||||
*/
|
||||
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UPNPDEV_H_INCLUDED */
|
82
thirdparty/miniupnpc/include/miniupnpc/upnpreplyparse.h
vendored
Normal file
82
thirdparty/miniupnpc/include/miniupnpc/upnpreplyparse.h
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/* $Id: upnpreplyparse.h,v 1.22 2025/03/29 17:58:12 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2025 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef UPNPREPLYPARSE_H_INCLUDED
|
||||
#define UPNPREPLYPARSE_H_INCLUDED
|
||||
|
||||
/*! \file upnpreplyparse.h
|
||||
* \brief Parsing of UPnP SOAP responses
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \brief Name/Value linked list
|
||||
* not exposed in the public API
|
||||
*/
|
||||
struct NameValue;
|
||||
|
||||
/*! \brief data structure for parsing */
|
||||
struct NameValueParserData {
|
||||
/*! \brief name/value linked list */
|
||||
struct NameValue * l_head;
|
||||
/*! \brief current element name */
|
||||
char curelt[64];
|
||||
/*! \brief port listing array */
|
||||
char * portListing;
|
||||
/*! \brief port listing array length */
|
||||
int portListingLength;
|
||||
/*! \brief flag indicating the current element is */
|
||||
int topelt;
|
||||
/*! \brief top element character data */
|
||||
const char * cdata;
|
||||
/*! \brief top element character data length */
|
||||
int cdatalen;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Parse XML and fill the structure
|
||||
*
|
||||
* \param[in] buffer XML data
|
||||
* \param[in] bufsize buffer length
|
||||
* \param[out] data structure to fill
|
||||
*/
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data);
|
||||
|
||||
/*!
|
||||
* \brief free memory
|
||||
*
|
||||
* \param[in,out] pdata data structure
|
||||
*/
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata);
|
||||
|
||||
/*!
|
||||
* \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 *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * name);
|
||||
|
||||
/* DisplayNameValueList() */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
90
thirdparty/miniupnpc/src/addr_is_reserved.c
vendored
Normal file
90
thirdparty/miniupnpc/src/addr_is_reserved.c
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
/* $Id: addr_is_reserved.c,v 1.7 2025/01/12 15:47:17 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2025 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#ifdef _WIN32
|
||||
/* Win32 Specific includes and defines */
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#if !defined(_MSC_VER)
|
||||
#include <stdint.h>
|
||||
#else /* !defined(_MSC_VER) */
|
||||
typedef unsigned long uint32_t;
|
||||
#endif /* !defined(_MSC_VER) */
|
||||
#if !defined(_WIN32_WINNT_VISTA)
|
||||
#define _WIN32_WINNT_VISTA 0x0600
|
||||
#endif
|
||||
#else /* _WIN32 */
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif /* _WIN32 */
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/* List of IP address blocks which are private / reserved and therefore not suitable for public external IP addresses */
|
||||
#define IP(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
|
||||
#define MSK(m) (32-(m))
|
||||
static const struct { uint32_t address; uint32_t rmask; } reserved[] = {
|
||||
{ IP( 0, 0, 0, 0), MSK( 8) }, /* RFC1122 "This host on this network" */
|
||||
{ IP( 10, 0, 0, 0), MSK( 8) }, /* RFC1918 Private-Use */
|
||||
{ IP(100, 64, 0, 0), MSK(10) }, /* RFC6598 Shared Address Space */
|
||||
{ IP(127, 0, 0, 0), MSK( 8) }, /* RFC1122 Loopback */
|
||||
{ IP(169, 254, 0, 0), MSK(16) }, /* RFC3927 Link-Local */
|
||||
{ IP(172, 16, 0, 0), MSK(12) }, /* RFC1918 Private-Use */
|
||||
{ IP(192, 0, 0, 0), MSK(24) }, /* RFC6890 IETF Protocol Assignments */
|
||||
{ IP(192, 0, 2, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-1) */
|
||||
{ IP(192, 31, 196, 0), MSK(24) }, /* RFC7535 AS112-v4 */
|
||||
{ IP(192, 52, 193, 0), MSK(24) }, /* RFC7450 AMT */
|
||||
{ IP(192, 88, 99, 0), MSK(24) }, /* RFC7526 6to4 Relay Anycast */
|
||||
{ IP(192, 168, 0, 0), MSK(16) }, /* RFC1918 Private-Use */
|
||||
{ IP(192, 175, 48, 0), MSK(24) }, /* RFC7534 Direct Delegation AS112 Service */
|
||||
{ IP(198, 18, 0, 0), MSK(15) }, /* RFC2544 Benchmarking */
|
||||
{ IP(198, 51, 100, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-2) */
|
||||
{ IP(203, 0, 113, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-3) */
|
||||
{ IP(224, 0, 0, 0), MSK( 4) }, /* RFC1112 Multicast */
|
||||
{ IP(240, 0, 0, 0), MSK( 4) }, /* RFC1112 Reserved for Future Use + RFC919 Limited Broadcast */
|
||||
};
|
||||
#undef IP
|
||||
#undef MSK
|
||||
|
||||
/**
|
||||
* @return 1 or 0
|
||||
*/
|
||||
int addr_is_reserved(const char * addr_str)
|
||||
{
|
||||
uint32_t addr_n, address;
|
||||
size_t i;
|
||||
|
||||
#if defined(_WIN32) && (_WIN32_WINNT < _WIN32_WINNT_VISTA)
|
||||
addr_n = inet_addr(addr_str);
|
||||
if (addr_n == INADDR_NONE)
|
||||
return 1;
|
||||
#else
|
||||
/* was : addr_n = inet_addr(addr_str); */
|
||||
if (inet_pton(AF_INET, addr_str, &addr_n) <= 0) {
|
||||
/* error */
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
address = ntohl(addr_n);
|
||||
|
||||
for (i = 0; i < sizeof(reserved)/sizeof(reserved[0]); ++i) {
|
||||
if ((address >> reserved[i].rmask) == (reserved[i].address >> reserved[i].rmask)) {
|
||||
#ifdef DEBUG
|
||||
printf("IP address %s is reserved\n", addr_str);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
14
thirdparty/miniupnpc/src/addr_is_reserved.h
vendored
Normal file
14
thirdparty/miniupnpc/src/addr_is_reserved.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/* $Id: $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2020 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef ADDR_IS_RESERVED_H_INCLUDED
|
||||
#define ADDR_IS_RESERVED_H_INCLUDED
|
||||
|
||||
int addr_is_reserved(const char * addr_str);
|
||||
|
||||
#endif /* ADDR_IS_RESERVED_H_INCLUDED */
|
54
thirdparty/miniupnpc/src/codelength.h
vendored
Normal file
54
thirdparty/miniupnpc/src/codelength.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
#ifndef CODELENGTH_H_INCLUDED
|
||||
#define CODELENGTH_H_INCLUDED
|
||||
|
||||
/* Encode length by using 7bit per Byte :
|
||||
* Most significant bit of each byte specifies that the
|
||||
* following byte is part of the code */
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char *
|
||||
*/
|
||||
#define DECODELENGTH(n, p) n = 0; \
|
||||
do { n = (n << 7) | (*p & 0x7f); } \
|
||||
while((*(p++)&0x80) && (n<(1<<25)));
|
||||
|
||||
/* n : unsigned
|
||||
* READ : function/macro to read one byte (unsigned char)
|
||||
*/
|
||||
#define DECODELENGTH_READ(n, READ) \
|
||||
n = 0; \
|
||||
do { \
|
||||
unsigned char c; \
|
||||
READ(c); \
|
||||
n = (n << 7) | (c & 0x07f); \
|
||||
if(!(c&0x80)) break; \
|
||||
} while(n<(1<<25));
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char *
|
||||
* p_limit : unsigned char *
|
||||
*/
|
||||
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
|
||||
n = 0; \
|
||||
do { \
|
||||
if((p) >= (p_limit)) break; \
|
||||
n = (n << 7) | (*(p) & 0x7f); \
|
||||
} while((*((p)++)&0x80) && (n<(1<<25)));
|
||||
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char *
|
||||
*/
|
||||
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
|
||||
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
|
||||
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
|
||||
if(n>=128) *(p++) = (n >> 7) | 0x80; \
|
||||
*(p++) = n & 0x7f;
|
||||
|
||||
#endif /* CODELENGTH_H_INCLUDED */
|
290
thirdparty/miniupnpc/src/connecthostport.c
vendored
Normal file
290
thirdparty/miniupnpc/src/connecthostport.c
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
/* $Id: connecthostport.c,v 1.25 2025/05/24 15:59:08 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2010-2025 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
/* use getaddrinfo() or gethostbyname()
|
||||
* uncomment the following line in order to use gethostbyname() */
|
||||
#ifdef NO_GETADDRINFO
|
||||
#define USE_GETHOSTBYNAME
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#include "win32_snprintf.h"
|
||||
#define herror
|
||||
#define socklen_t int
|
||||
#else /* #ifdef _WIN32 */
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
#include <sys/time.h>
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
#include <sys/param.h>
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
#define closesocket close
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
|
||||
* during the connect() call */
|
||||
#define MINIUPNPC_IGNORE_EINTR
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#endif /* #else _WIN32 */
|
||||
|
||||
#if defined(__amigaos__) || defined(__amigaos4__)
|
||||
#define herror(A) printf("%s\n", A)
|
||||
#endif
|
||||
|
||||
#include "connecthostport.h"
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
/* connecthostport()
|
||||
* return a socket connected (TCP) to the host and port
|
||||
* or -1 in case of error */
|
||||
SOCKET connecthostport(const char * host, unsigned short port,
|
||||
unsigned int scope_id)
|
||||
{
|
||||
SOCKET s;
|
||||
int n;
|
||||
#ifdef USE_GETHOSTBYNAME
|
||||
struct sockaddr_in dest;
|
||||
struct hostent *hp;
|
||||
#else /* #ifdef USE_GETHOSTBYNAME */
|
||||
char tmp_host[MAXHOSTNAMELEN+1];
|
||||
char port_str[8];
|
||||
struct addrinfo *ai, *p;
|
||||
struct addrinfo hints;
|
||||
#endif /* #ifdef USE_GETHOSTBYNAME */
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
struct timeval timeout;
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
|
||||
#ifdef USE_GETHOSTBYNAME
|
||||
hp = gethostbyname(host);
|
||||
if(hp == NULL)
|
||||
{
|
||||
herror(host);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr));
|
||||
memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
|
||||
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if(ISINVALID(s))
|
||||
{
|
||||
PRINT_SOCKET_ERROR("socket");
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
/* setting a 3 seconds timeout for the connect() call */
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt SO_RCVTIMEO");
|
||||
}
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt SO_SNDTIMEO");
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = htons(port);
|
||||
n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
/* EINTR The system call was interrupted by a signal that was caught
|
||||
* EINPROGRESS The socket is nonblocking and the connection cannot
|
||||
* be completed immediately. */
|
||||
while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
|
||||
{
|
||||
socklen_t len;
|
||||
fd_set wset;
|
||||
int err;
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(s, &wset);
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
n = select(s + 1, NULL, &wset, NULL, &timeout);
|
||||
#else
|
||||
n = select(s + 1, NULL, &wset, NULL, NULL);
|
||||
#endif
|
||||
if(n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue; /* try again */
|
||||
else
|
||||
break; /* EBADF, EFAULT, EINVAL */
|
||||
}
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
if(n == 0) {
|
||||
errno = ETIMEDOUT;
|
||||
n = -1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
len = sizeof(err);
|
||||
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
|
||||
PRINT_SOCKET_ERROR("getsockopt");
|
||||
closesocket(s);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
if(err != 0) {
|
||||
errno = err;
|
||||
n = -1;
|
||||
}
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
|
||||
if(n<0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("connect");
|
||||
closesocket(s);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
#else /* #ifdef USE_GETHOSTBYNAME */
|
||||
/* use getaddrinfo() instead of gethostbyname() */
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
/* hints.ai_flags = AI_ADDRCONFIG; */
|
||||
#ifdef AI_NUMERICSERV
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
#endif
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
|
||||
/* hints.ai_protocol = IPPROTO_TCP; */
|
||||
snprintf(port_str, sizeof(port_str), "%hu", port);
|
||||
if(host[0] == '[')
|
||||
{
|
||||
/* literal ip v6 address */
|
||||
int i, j;
|
||||
for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++)
|
||||
{
|
||||
tmp_host[i] = host[j];
|
||||
if(0 == strncmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */
|
||||
j+=2; /* skip "25" */
|
||||
}
|
||||
tmp_host[i] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(tmp_host, host, MAXHOSTNAMELEN);
|
||||
}
|
||||
tmp_host[MAXHOSTNAMELEN] = '\0';
|
||||
n = getaddrinfo(tmp_host, port_str, &hints, &ai);
|
||||
if(n != 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
fprintf(stderr, "getaddrinfo() error : %d\n", n);
|
||||
#else
|
||||
fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
|
||||
#endif
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
s = INVALID_SOCKET;
|
||||
for(p = ai; p; p = p->ai_next)
|
||||
{
|
||||
if(!ISINVALID(s))
|
||||
closesocket(s);
|
||||
#ifdef DEBUG
|
||||
printf("ai_family=%d ai_socktype=%d ai_protocol=%d (PF_INET=%d, PF_INET6=%d)\n",
|
||||
p->ai_family, p->ai_socktype, p->ai_protocol, PF_INET, PF_INET6);
|
||||
#endif
|
||||
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||
if(ISINVALID(s))
|
||||
continue;
|
||||
if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) {
|
||||
struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
addr6->sin6_scope_id = scope_id;
|
||||
}
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
/* setting a 3 seconds timeout for the connect() call */
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt");
|
||||
}
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("setsockopt");
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||
n = connect(s, p->ai_addr, MSC_CAST_INT p->ai_addrlen);
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
/* EINTR The system call was interrupted by a signal that was caught
|
||||
* EINPROGRESS The socket is nonblocking and the connection cannot
|
||||
* be completed immediately. */
|
||||
while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
|
||||
{
|
||||
socklen_t len;
|
||||
fd_set wset;
|
||||
int err;
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(s, &wset);
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
n = select(s + 1, NULL, &wset, NULL, &timeout);
|
||||
#else
|
||||
n = select(s + 1, NULL, &wset, NULL, NULL);
|
||||
#endif
|
||||
if(n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue; /* try again */
|
||||
else
|
||||
break; /* EBADF, EFAULT, EINVAL */
|
||||
}
|
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||
if(n == 0) {
|
||||
errno = ETIMEDOUT;
|
||||
n = -1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
len = sizeof(err);
|
||||
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
|
||||
PRINT_SOCKET_ERROR("getsockopt");
|
||||
closesocket(s);
|
||||
freeaddrinfo(ai);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
if(err != 0) {
|
||||
errno = err;
|
||||
n = -1;
|
||||
}
|
||||
}
|
||||
#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
|
||||
if(n >= 0) /* connect() was successful */
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
if(ISINVALID(s))
|
||||
{
|
||||
PRINT_SOCKET_ERROR("socket");
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
if(n < 0)
|
||||
{
|
||||
PRINT_SOCKET_ERROR("connect");
|
||||
closesocket(s);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
#endif /* #ifdef USE_GETHOSTBYNAME */
|
||||
return s;
|
||||
}
|
20
thirdparty/miniupnpc/src/connecthostport.h
vendored
Normal file
20
thirdparty/miniupnpc/src/connecthostport.h
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/* $Id: connecthostport.h,v 1.2 2012/06/23 22:32:33 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2010-2018 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef CONNECTHOSTPORT_H_INCLUDED
|
||||
#define CONNECTHOSTPORT_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_socketdef.h"
|
||||
|
||||
/* connecthostport()
|
||||
* return a socket connected (TCP) to the host and port
|
||||
* or INVALID_SOCKET in case of error */
|
||||
SOCKET connecthostport(const char * host, unsigned short port,
|
||||
unsigned int scope_id);
|
||||
|
||||
#endif
|
||||
|
123
thirdparty/miniupnpc/src/igd_desc_parse.c
vendored
Normal file
123
thirdparty/miniupnpc/src/igd_desc_parse.c
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include "igd_desc_parse.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Start element handler :
|
||||
* update nesting level counter and copy element name */
|
||||
void IGDstartelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
if(l >= MINIUPNPC_URL_MAXSIZE)
|
||||
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||
memcpy(datas->cureltname, name, l);
|
||||
datas->cureltname[l] = '\0';
|
||||
datas->level++;
|
||||
if( (l==7) && !memcmp(name, "service", l) ) {
|
||||
datas->tmp.controlurl[0] = '\0';
|
||||
datas->tmp.eventsuburl[0] = '\0';
|
||||
datas->tmp.scpdurl[0] = '\0';
|
||||
datas->tmp.servicetype[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
|
||||
|
||||
/* End element handler :
|
||||
* update nesting level counter and update parser state if
|
||||
* service element is parsed */
|
||||
void IGDendelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
datas->level--;
|
||||
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/
|
||||
if( (l==7) && !memcmp(name, "service", l) )
|
||||
{
|
||||
if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) {
|
||||
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) {
|
||||
memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:")
|
||||
|| COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:") ) {
|
||||
if(datas->first.servicetype[0] == '\0') {
|
||||
memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else {
|
||||
memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Data handler :
|
||||
* copy data depending on the current element name and state */
|
||||
void IGDdata(void * d, const char * data, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
char * dstmember = 0;
|
||||
/*printf("%2d %s : %.*s\n",
|
||||
datas->level, datas->cureltname, l, data); */
|
||||
if( !strcmp(datas->cureltname, "URLBase") )
|
||||
dstmember = datas->urlbase;
|
||||
else if( !strcmp(datas->cureltname, "presentationURL") )
|
||||
dstmember = datas->presentationurl;
|
||||
else if( !strcmp(datas->cureltname, "serviceType") )
|
||||
dstmember = datas->tmp.servicetype;
|
||||
else if( !strcmp(datas->cureltname, "controlURL") )
|
||||
dstmember = datas->tmp.controlurl;
|
||||
else if( !strcmp(datas->cureltname, "eventSubURL") )
|
||||
dstmember = datas->tmp.eventsuburl;
|
||||
else if( !strcmp(datas->cureltname, "SCPDURL") )
|
||||
dstmember = datas->tmp.scpdurl;
|
||||
/* else if( !strcmp(datas->cureltname, "deviceType") )
|
||||
dstmember = datas->devicetype_tmp;*/
|
||||
if(dstmember)
|
||||
{
|
||||
if(l>=MINIUPNPC_URL_MAXSIZE)
|
||||
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||
memcpy(dstmember, data, l);
|
||||
dstmember[l] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void printIGD(struct IGDdatas * d)
|
||||
{
|
||||
printf("urlbase = '%s'\n", d->urlbase);
|
||||
printf("WAN Device (Common interface config) :\n");
|
||||
/*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/
|
||||
printf(" serviceType = '%s'\n", d->CIF.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->CIF.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->CIF.scpdurl);
|
||||
printf("primary WAN Connection Device (IP or PPP Connection):\n");
|
||||
/*printf(" deviceType = '%s'\n", d->first.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->first.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->first.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->first.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->first.scpdurl);
|
||||
printf("secondary WAN Connection Device (IP or PPP Connection):\n");
|
||||
/*printf(" deviceType = '%s'\n", d->second.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->second.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->second.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->second.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->second.scpdurl);
|
||||
printf("WAN IPv6 Firewall Control :\n");
|
||||
/*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->IPv6FC.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->IPv6FC.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
120
thirdparty/miniupnpc/src/minisoap.c
vendored
Normal file
120
thirdparty/miniupnpc/src/minisoap.c
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/* $Id: minisoap.c,v 1.35 2025/04/27 21:13:45 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2025 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
*
|
||||
* Minimal SOAP implementation for UPnP protocol.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <io.h>
|
||||
#include <winsock2.h>
|
||||
#include "win32_snprintf.h"
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include "minisoap.h"
|
||||
#include "miniupnpcstrings.h"
|
||||
|
||||
/* only for malloc */
|
||||
#include <stdlib.h>
|
||||
|
||||
/* httpWrite sends the headers and the body to the socket
|
||||
* and returns the number of bytes sent */
|
||||
static int
|
||||
httpWrite(SOCKET fd, const char * body, int bodysize,
|
||||
const char * headers, int headerssize)
|
||||
{
|
||||
int n = 0;
|
||||
/*n = write(fd, headers, headerssize);*/
|
||||
/*if(bodysize>0)
|
||||
n += write(fd, body, bodysize);*/
|
||||
/* Note : my old linksys router only took into account
|
||||
* soap request that are sent into only one packet */
|
||||
char * p;
|
||||
/* TODO: AVOID MALLOC, we could use writev() for that */
|
||||
p = malloc(headerssize+bodysize);
|
||||
if(!p)
|
||||
return -1;
|
||||
memcpy(p, headers, headerssize);
|
||||
memcpy(p+headerssize, body, bodysize);
|
||||
/*n = write(fd, p, headerssize+bodysize);*/
|
||||
n = send(fd, p, headerssize+bodysize, 0);
|
||||
if(n<0) {
|
||||
PRINT_SOCKET_ERROR("send");
|
||||
}
|
||||
/* disable send on the socket */
|
||||
/* draytek routers don't seem to like that... */
|
||||
#if 0
|
||||
#ifdef _WIN32
|
||||
if(shutdown(fd, SD_SEND)<0) {
|
||||
#else
|
||||
if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/
|
||||
#endif
|
||||
PRINT_SOCKET_ERROR("shutdown");
|
||||
}
|
||||
#endif
|
||||
free(p);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* self explanatory */
|
||||
int soapPostSubmit(SOCKET fd,
|
||||
const char * url,
|
||||
const char * host,
|
||||
unsigned short port,
|
||||
const char * action,
|
||||
const char * body,
|
||||
const char * httpversion)
|
||||
{
|
||||
char headerbuf[512];
|
||||
int headerssize;
|
||||
char portstr[8];
|
||||
int bodysize = (int)strlen(body);
|
||||
/* We are not using keep-alive HTTP connections.
|
||||
* HTTP/1.1 needs the header Connection: close to do that.
|
||||
* This is the default with HTTP/1.0
|
||||
* Using HTTP/1.1 means we need to support chunked transfer-encoding :
|
||||
* When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked
|
||||
* transfer encoding. */
|
||||
/* Connection: close is normally there only in HTTP/1.1 but who knows */
|
||||
portstr[0] = '\0';
|
||||
if(port != 80)
|
||||
snprintf(portstr, sizeof(portstr), ":%hu", port);
|
||||
headerssize = snprintf(headerbuf, sizeof(headerbuf),
|
||||
"POST %s HTTP/%s\r\n"
|
||||
"Host: %s%s\r\n"
|
||||
"User-Agent: " OS_STRING " " UPNP_VERSION_STRING " MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
#if (UPNP_VERSION_MAJOR == 1) && (UPNP_VERSION_MINOR == 0)
|
||||
"Content-Type: text/xml\r\n"
|
||||
#else
|
||||
"Content-Type: text/xml; charset=\"utf-8\"\r\n"
|
||||
#endif
|
||||
"SOAPAction: \"%s\"\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n",
|
||||
url, httpversion, host, portstr, bodysize, action);
|
||||
if ((unsigned int)headerssize >= sizeof(headerbuf))
|
||||
return -1;
|
||||
#ifdef DEBUG
|
||||
/*printf("SOAP request : headersize=%d bodysize=%d\n",
|
||||
headerssize, bodysize);
|
||||
*/
|
||||
printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n",
|
||||
url, httpversion, host, portstr);
|
||||
printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize);
|
||||
printf("Headers :\n%s", headerbuf);
|
||||
printf("Body :\n%s\n", body);
|
||||
#endif
|
||||
return httpWrite(fd, body, bodysize, headerbuf, headerssize);
|
||||
}
|
||||
|
||||
|
17
thirdparty/miniupnpc/src/minisoap.h
vendored
Normal file
17
thirdparty/miniupnpc/src/minisoap.h
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/* $Id: minisoap.h,v 1.4 2010/04/12 20:39:41 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2018 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
#ifndef MINISOAP_H_INCLUDED
|
||||
#define MINISOAP_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_socketdef.h"
|
||||
|
||||
/*int httpWrite(int, const char *, int, const char *);*/
|
||||
int soapPostSubmit(SOCKET, const char *, const char *, unsigned short,
|
||||
const char *, const char *, const char *);
|
||||
|
||||
#endif
|
||||
|
1026
thirdparty/miniupnpc/src/minissdpc.c
vendored
Normal file
1026
thirdparty/miniupnpc/src/minissdpc.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
58
thirdparty/miniupnpc/src/minissdpc.h
vendored
Normal file
58
thirdparty/miniupnpc/src/minissdpc.h
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/* $Id: minissdpc.h,v 1.6 2015/09/18 12:45:16 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef MINISSDPC_H_INCLUDED
|
||||
#define MINISSDPC_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_declspec.h"
|
||||
#include "upnpdev.h"
|
||||
|
||||
/* error codes : */
|
||||
#define MINISSDPC_SUCCESS (0)
|
||||
#define MINISSDPC_UNKNOWN_ERROR (-1)
|
||||
#define MINISSDPC_SOCKET_ERROR (-101)
|
||||
#define MINISSDPC_MEMORY_ERROR (-102)
|
||||
#define MINISSDPC_INVALID_INPUT (-103)
|
||||
#define MINISSDPC_INVALID_SERVER_REPLY (-104)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
connectToMiniSSDPD(const char * socketpath);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
disconnectFromMiniSSDPD(int s);
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
requestDevicesFromMiniSSDPD(int s, const char * devtype);
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
receiveDevicesFromMiniSSDPD(int s, int * error);
|
||||
|
||||
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
|
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
ssdpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
684
thirdparty/miniupnpc/src/miniupnpc.c
vendored
Normal file
684
thirdparty/miniupnpc/src/miniupnpc.c
vendored
Normal file
@@ -0,0 +1,684 @@
|
||||
/* $Id: miniupnpc.c,v 1.165 2025/01/10 22:57:21 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2025 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
/* Win32 Specific includes and defines */
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#include <iphlpapi.h>
|
||||
#include "win32_snprintf.h"
|
||||
#define strdup _strdup
|
||||
#ifndef strncasecmp
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
#define strncasecmp _memicmp
|
||||
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#define strncasecmp memicmp
|
||||
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#endif /* #ifndef strncasecmp */
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#else /* #ifdef _WIN32 */
|
||||
/* Standard POSIX includes */
|
||||
#include <unistd.h>
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* Amiga OS 3 specific stuff */
|
||||
#define socklen_t int
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#if !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#define closesocket close
|
||||
#endif /* #else _WIN32 */
|
||||
#ifdef __GNU__
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
|
||||
#include "miniupnpc.h"
|
||||
#include "minissdpc.h"
|
||||
#include "miniwget.h"
|
||||
#include "miniwget_private.h"
|
||||
#include "minisoap.h"
|
||||
#include "minixml.h"
|
||||
#include "upnpcommands.h"
|
||||
#include "connecthostport.h"
|
||||
#include "addr_is_reserved.h"
|
||||
|
||||
/* compare the beginning of a string with a constant string */
|
||||
#define COMPARE(str, cstr) (0==strncmp(str, cstr, sizeof(cstr) - 1))
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
#define SOAPPREFIX "s"
|
||||
#define SERVICEPREFIX "u"
|
||||
#define SERVICEPREFIX2 'u'
|
||||
|
||||
/* root description parsing */
|
||||
MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
/* xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = IGDstartelt;
|
||||
parser.endeltfunc = IGDendelt;
|
||||
parser.datafunc = IGDdata;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
#ifdef DEBUG
|
||||
printIGD(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* simpleUPnPcommand :
|
||||
* not so simple !
|
||||
* return values :
|
||||
* pointer - OK
|
||||
* NULL - error */
|
||||
char *
|
||||
simpleUPnPcommand(const char * url, const char * service,
|
||||
const char * action, const struct UPNParg * args,
|
||||
int * bufsize)
|
||||
{
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
unsigned short port = 0;
|
||||
char * path;
|
||||
char soapact[128];
|
||||
char soapbody[2048];
|
||||
int soapbodylen;
|
||||
char * buf;
|
||||
int n;
|
||||
int status_code;
|
||||
SOCKET s;
|
||||
|
||||
*bufsize = 0;
|
||||
snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
|
||||
if(args==NULL)
|
||||
{
|
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||
"<?xml version=\"1.0\"?>\r\n"
|
||||
"<" SOAPPREFIX ":Envelope "
|
||||
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<" SOAPPREFIX ":Body>"
|
||||
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
|
||||
"</" SERVICEPREFIX ":%s>"
|
||||
"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
|
||||
"\r\n", action, service, action);
|
||||
if ((unsigned int)soapbodylen >= sizeof(soapbody))
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
char * p;
|
||||
const char * pe, * pv;
|
||||
const char * const pend = soapbody + sizeof(soapbody);
|
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody),
|
||||
"<?xml version=\"1.0\"?>\r\n"
|
||||
"<" SOAPPREFIX ":Envelope "
|
||||
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<" SOAPPREFIX ":Body>"
|
||||
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
|
||||
action, service);
|
||||
if ((unsigned int)soapbodylen >= sizeof(soapbody))
|
||||
return NULL;
|
||||
p = soapbody + soapbodylen;
|
||||
while(args->elt)
|
||||
{
|
||||
if(p >= pend) /* check for space to write next byte */
|
||||
return NULL;
|
||||
*(p++) = '<';
|
||||
|
||||
pe = args->elt;
|
||||
while(p < pend && *pe)
|
||||
*(p++) = *(pe++);
|
||||
|
||||
if(p >= pend) /* check for space to write next byte */
|
||||
return NULL;
|
||||
*(p++) = '>';
|
||||
|
||||
if((pv = args->val))
|
||||
{
|
||||
while(p < pend && *pv)
|
||||
*(p++) = *(pv++);
|
||||
}
|
||||
|
||||
if((p+2) > pend) /* check for space to write next 2 bytes */
|
||||
return NULL;
|
||||
*(p++) = '<';
|
||||
*(p++) = '/';
|
||||
|
||||
pe = args->elt;
|
||||
while(p < pend && *pe)
|
||||
*(p++) = *(pe++);
|
||||
|
||||
if(p >= pend) /* check for space to write next byte */
|
||||
return NULL;
|
||||
*(p++) = '>';
|
||||
|
||||
args++;
|
||||
}
|
||||
if((p+4) > pend) /* check for space to write next 4 bytes */
|
||||
return NULL;
|
||||
*(p++) = '<';
|
||||
*(p++) = '/';
|
||||
*(p++) = SERVICEPREFIX2;
|
||||
*(p++) = ':';
|
||||
|
||||
pe = action;
|
||||
while(p < pend && *pe)
|
||||
*(p++) = *(pe++);
|
||||
|
||||
strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
|
||||
pend - p);
|
||||
if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
|
||||
return NULL;
|
||||
}
|
||||
if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
|
||||
s = connecthostport(hostname, port, 0);
|
||||
if(ISINVALID(s)) {
|
||||
/* failed to connect */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, "1.1");
|
||||
if(n<=0) {
|
||||
#ifdef DEBUG
|
||||
printf("Error sending SOAP request\n");
|
||||
#endif
|
||||
closesocket(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = getHTTPResponse(s, bufsize, &status_code);
|
||||
#ifdef DEBUG
|
||||
if(*bufsize > 0 && buf)
|
||||
{
|
||||
printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize);
|
||||
}
|
||||
#endif
|
||||
closesocket(s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* upnpDiscoverDevices() :
|
||||
* return a chained list of all devices found or NULL if
|
||||
* no devices was found.
|
||||
* It is up to the caller to free the chained list
|
||||
* delay is in millisecond (poll).
|
||||
* UDA v1.1 says :
|
||||
* The TTL for the IP packet SHOULD default to 2 and
|
||||
* SHOULD be configurable. */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error,
|
||||
int searchalltypes)
|
||||
{
|
||||
struct UPNPDev * tmp;
|
||||
struct UPNPDev * devlist = 0;
|
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
int deviceIndex;
|
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
|
||||
if(error)
|
||||
*error = UPNPDISCOVER_UNKNOWN_ERROR;
|
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* first try to get infos from minissdpd ! */
|
||||
if(!minissdpdsock)
|
||||
minissdpdsock = "/var/run/minissdpd.sock";
|
||||
if(minissdpdsock[0] != '\0') {
|
||||
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
|
||||
struct UPNPDev * minissdpd_devlist;
|
||||
int only_rootdevice = 1;
|
||||
minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
|
||||
minissdpdsock, 0);
|
||||
if(minissdpd_devlist) {
|
||||
#ifdef DEBUG
|
||||
printf("returned by MiniSSDPD: %s\t%s\n",
|
||||
minissdpd_devlist->st, minissdpd_devlist->descURL);
|
||||
#endif /* DEBUG */
|
||||
if(!strstr(minissdpd_devlist->st, "rootdevice"))
|
||||
only_rootdevice = 0;
|
||||
for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
|
||||
#ifdef DEBUG
|
||||
printf("returned by MiniSSDPD: %s\t%s\n",
|
||||
tmp->pNext->st, tmp->pNext->descURL);
|
||||
#endif /* DEBUG */
|
||||
if(!strstr(tmp->st, "rootdevice"))
|
||||
only_rootdevice = 0;
|
||||
}
|
||||
tmp->pNext = devlist;
|
||||
devlist = minissdpd_devlist;
|
||||
if(!searchalltypes && !only_rootdevice)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
|
||||
/* We return what we have found if it was not only a rootdevice */
|
||||
if(!strstr(tmp->st, "rootdevice")) {
|
||||
if(error)
|
||||
*error = UPNPDISCOVER_SUCCESS;
|
||||
return devlist;
|
||||
}
|
||||
}
|
||||
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
(void)minissdpdsock; /* unused */
|
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
|
||||
/* direct discovery if minissdpd responses are not sufficient */
|
||||
{
|
||||
struct UPNPDev * discovered_devlist;
|
||||
discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
|
||||
ipv6, ttl, error, searchalltypes);
|
||||
if(devlist == NULL)
|
||||
devlist = discovered_devlist;
|
||||
else {
|
||||
for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
|
||||
tmp->pNext = discovered_devlist;
|
||||
}
|
||||
}
|
||||
return devlist;
|
||||
}
|
||||
|
||||
/* upnpDiscover() Discover IGD device */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error)
|
||||
{
|
||||
static const char * const deviceList[] = {
|
||||
#if 0
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:2",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:2",
|
||||
#endif
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:1",
|
||||
"upnp:rootdevice",
|
||||
/*"ssdp:all",*/
|
||||
0
|
||||
};
|
||||
return upnpDiscoverDevices(deviceList,
|
||||
delay, multicastif, minissdpdsock, localport,
|
||||
ipv6, ttl, error, 0);
|
||||
}
|
||||
|
||||
/* upnpDiscoverAll() Discover all UPnP devices */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverAll(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error)
|
||||
{
|
||||
static const char * const deviceList[] = {
|
||||
/*"upnp:rootdevice",*/
|
||||
"ssdp:all",
|
||||
0
|
||||
};
|
||||
return upnpDiscoverDevices(deviceList,
|
||||
delay, multicastif, minissdpdsock, localport,
|
||||
ipv6, ttl, error, 0);
|
||||
}
|
||||
|
||||
/* upnpDiscoverDevice() Discover a specific device */
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int localport,
|
||||
int ipv6, unsigned char ttl,
|
||||
int * error)
|
||||
{
|
||||
const char * const deviceList[] = {
|
||||
device,
|
||||
0
|
||||
};
|
||||
return upnpDiscoverDevices(deviceList,
|
||||
delay, multicastif, minissdpdsock, localport,
|
||||
ipv6, ttl, error, 0);
|
||||
}
|
||||
|
||||
static char *
|
||||
build_absolute_url(const char * baseurl, const char * descURL,
|
||||
const char * url, unsigned int scope_id)
|
||||
{
|
||||
size_t l, n;
|
||||
char * s;
|
||||
const char * base;
|
||||
char * p;
|
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32)
|
||||
char ifname[IF_NAMESIZE];
|
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
char scope_str[8];
|
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
|
||||
if( (url[0] == 'h')
|
||||
&&(url[1] == 't')
|
||||
&&(url[2] == 't')
|
||||
&&(url[3] == 'p')
|
||||
&&(url[4] == ':')
|
||||
&&(url[5] == '/')
|
||||
&&(url[6] == '/'))
|
||||
return strdup(url);
|
||||
base = (baseurl[0] == '\0') ? descURL : baseurl;
|
||||
n = strlen(base);
|
||||
if(n > 7) {
|
||||
p = strchr(base + 7, '/');
|
||||
if(p)
|
||||
n = p - base;
|
||||
}
|
||||
l = n + strlen(url) + 1;
|
||||
if(url[0] != '/')
|
||||
l++;
|
||||
if(scope_id != 0) {
|
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32)
|
||||
if(if_indextoname(scope_id, ifname)) {
|
||||
l += 3 + strlen(ifname); /* 3 == strlen(%25) */
|
||||
}
|
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
/* under windows, scope is numerical */
|
||||
l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
|
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
}
|
||||
s = malloc(l);
|
||||
if(s == NULL) return NULL;
|
||||
memcpy(s, base, n);
|
||||
if(scope_id != 0) {
|
||||
s[n] = '\0';
|
||||
if(n > 13 && 0 == memcmp(s, "http://[fe80:", 13)) {
|
||||
/* this is a linklocal IPv6 address */
|
||||
p = strchr(s, ']');
|
||||
if(p) {
|
||||
/* insert %25<scope> into URL */
|
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32)
|
||||
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
|
||||
memcpy(p, "%25", 3);
|
||||
memcpy(p + 3, ifname, strlen(ifname));
|
||||
n += 3 + strlen(ifname);
|
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
|
||||
memcpy(p, "%25", 3);
|
||||
memcpy(p + 3, scope_str, strlen(scope_str));
|
||||
n += 3 + strlen(scope_str);
|
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
|
||||
}
|
||||
}
|
||||
}
|
||||
if(url[0] != '/')
|
||||
s[n++] = '/';
|
||||
memcpy(s + n, url, l - n);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Prepare the Urls for usage...
|
||||
*/
|
||||
MINIUPNP_LIBSPEC void
|
||||
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
const char * descURL, unsigned int scope_id)
|
||||
{
|
||||
/* strdup descURL */
|
||||
urls->rootdescURL = strdup(descURL);
|
||||
|
||||
/* get description of WANIPConnection */
|
||||
urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
|
||||
data->first.scpdurl, scope_id);
|
||||
urls->controlURL = build_absolute_url(data->urlbase, descURL,
|
||||
data->first.controlurl, scope_id);
|
||||
urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
|
||||
data->CIF.controlurl, scope_id);
|
||||
urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
|
||||
data->IPv6FC.controlurl, scope_id);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
|
||||
printf("urls->controlURL='%s'\n", urls->controlURL);
|
||||
printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
|
||||
printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
|
||||
#endif
|
||||
}
|
||||
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreeUPNPUrls(struct UPNPUrls * urls)
|
||||
{
|
||||
if(!urls)
|
||||
return;
|
||||
free(urls->controlURL);
|
||||
urls->controlURL = 0;
|
||||
free(urls->ipcondescURL);
|
||||
urls->ipcondescURL = 0;
|
||||
free(urls->controlURL_CIF);
|
||||
urls->controlURL_CIF = 0;
|
||||
free(urls->controlURL_6FC);
|
||||
urls->controlURL_6FC = 0;
|
||||
free(urls->rootdescURL);
|
||||
urls->rootdescURL = 0;
|
||||
}
|
||||
|
||||
int
|
||||
UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
|
||||
{
|
||||
char status[64];
|
||||
unsigned int uptime;
|
||||
status[0] = '\0';
|
||||
UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
|
||||
status, &uptime, NULL);
|
||||
if(0 == strcmp("Connected", status))
|
||||
return 1;
|
||||
else if(0 == strcmp("Up", status)) /* Also accept "Up" */
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* UPNP_GetValidIGD() :
|
||||
* return values :
|
||||
* -1 = Internal error
|
||||
* 0 = NO IGD found (UPNP_NO_IGD)
|
||||
* 1 = A valid connected IGD has been found (UPNP_CONNECTED_IGD)
|
||||
* 2 = A valid connected IGD has been found but its
|
||||
* IP address is reserved (non routable) (UPNP_PRIVATEIP_IGD)
|
||||
* 3 = A valid IGD has been found but it reported as
|
||||
* not connected (UPNP_DISCONNECTED_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
|
||||
* passed as parameters are set. Don't forget to call FreeUPNPUrls(urls) to
|
||||
* free allocated memory.
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen,
|
||||
char * wanaddr, int wanaddrlen)
|
||||
{
|
||||
struct xml_desc {
|
||||
char lanaddr[40];
|
||||
char wanaddr[40];
|
||||
char * xml;
|
||||
int size;
|
||||
int is_igd;
|
||||
} * desc = NULL;
|
||||
struct UPNPDev * dev;
|
||||
int ndev = 0;
|
||||
int i;
|
||||
int state = -1; /* state 1 : IGD connected. State 2 : connected with reserved IP.
|
||||
* State 3 : IGD. State 4 : anything */
|
||||
int status_code = -1;
|
||||
|
||||
if(!devlist)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Empty devlist\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/* counting total number of devices in the list */
|
||||
for(dev = devlist; dev; dev = dev->pNext)
|
||||
ndev++;
|
||||
/* ndev is always > 0 */
|
||||
desc = calloc(ndev, sizeof(struct xml_desc));
|
||||
if(!desc)
|
||||
return -1; /* memory allocation error */
|
||||
/* Step 1 : downloading descriptions and testing type */
|
||||
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
|
||||
{
|
||||
/* we should choose an internet gateway device.
|
||||
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
|
||||
desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
|
||||
desc[i].lanaddr, sizeof(desc[i].lanaddr),
|
||||
dev->scope_id, &status_code);
|
||||
#ifdef DEBUG
|
||||
if(!desc[i].xml)
|
||||
{
|
||||
printf("error getting XML description %s\n", dev->descURL);
|
||||
}
|
||||
#endif
|
||||
if(desc[i].xml)
|
||||
{
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
memset(urls, 0, sizeof(struct UPNPUrls));
|
||||
parserootdesc(desc[i].xml, desc[i].size, data);
|
||||
if(COMPARE(data->CIF.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
|
||||
{
|
||||
desc[i].is_igd = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* iterate the list to find a device depending on state */
|
||||
for(state = 1; state <= 4; state++)
|
||||
{
|
||||
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
|
||||
{
|
||||
if(desc[i].xml)
|
||||
{
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
memset(urls, 0, sizeof(struct UPNPUrls));
|
||||
parserootdesc(desc[i].xml, desc[i].size, data);
|
||||
if(desc[i].is_igd || state >= 4 )
|
||||
{
|
||||
int is_connected;
|
||||
|
||||
GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
|
||||
|
||||
/* in state 3 and 4 we don't test if device is connected ! */
|
||||
if(state >= 3)
|
||||
goto free_and_return;
|
||||
is_connected = UPNPIGD_IsConnected(urls, data);
|
||||
#ifdef DEBUG
|
||||
printf("UPNPIGD_IsConnected(%s) = %d\n",
|
||||
urls->controlURL, is_connected);
|
||||
#endif
|
||||
/* checks that status is connected AND there is a external IP address assigned */
|
||||
if(is_connected) {
|
||||
if(state >= 2)
|
||||
goto free_and_return;
|
||||
if(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, desc[i].wanaddr) == 0
|
||||
&& !addr_is_reserved(desc[i].wanaddr))
|
||||
goto free_and_return;
|
||||
}
|
||||
FreeUPNPUrls(urls);
|
||||
if(data->second.servicetype[0] != '\0') {
|
||||
#ifdef DEBUG
|
||||
printf("We tried %s, now we try %s !\n",
|
||||
data->first.servicetype, data->second.servicetype);
|
||||
#endif
|
||||
/* swaping WANPPPConnection and WANIPConnection ! */
|
||||
memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service));
|
||||
memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service));
|
||||
memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service));
|
||||
GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
|
||||
is_connected = UPNPIGD_IsConnected(urls, data);
|
||||
#ifdef DEBUG
|
||||
printf("UPNPIGD_IsConnected(%s) = %d\n",
|
||||
urls->controlURL, is_connected);
|
||||
#endif
|
||||
if(is_connected) {
|
||||
if(state >= 2)
|
||||
goto free_and_return;
|
||||
if(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, desc[i].wanaddr) == 0
|
||||
&& !addr_is_reserved(desc[i].wanaddr))
|
||||
goto free_and_return;
|
||||
}
|
||||
FreeUPNPUrls(urls);
|
||||
}
|
||||
}
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
}
|
||||
}
|
||||
}
|
||||
state = 0;
|
||||
free_and_return:
|
||||
if (state >= 1 && state <= 4 && i < ndev) {
|
||||
if (lanaddr != NULL)
|
||||
strncpy(lanaddr, desc[i].lanaddr, lanaddrlen);
|
||||
if (wanaddr != NULL)
|
||||
strncpy(wanaddr, desc[i].wanaddr, wanaddrlen);
|
||||
}
|
||||
for(i = 0; i < ndev; i++)
|
||||
free(desc[i].xml);
|
||||
free(desc);
|
||||
return state;
|
||||
}
|
||||
|
||||
/* UPNP_GetIGDFromUrl()
|
||||
* Used when skipping the discovery process.
|
||||
* return value :
|
||||
* 0 - Not ok
|
||||
* 1 - OK */
|
||||
int
|
||||
UPNP_GetIGDFromUrl(const char * rootdescurl,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen)
|
||||
{
|
||||
char * descXML;
|
||||
int descXMLsize = 0;
|
||||
|
||||
descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
|
||||
lanaddr, lanaddrlen, 0, NULL);
|
||||
if(descXML) {
|
||||
memset(data, 0, sizeof(struct IGDdatas));
|
||||
memset(urls, 0, sizeof(struct UPNPUrls));
|
||||
parserootdesc(descXML, descXMLsize, data);
|
||||
free(descXML);
|
||||
GetUPNPUrls(urls, data, rootdescurl, 0);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
44
thirdparty/miniupnpc/src/miniupnpc_socketdef.h
vendored
Normal file
44
thirdparty/miniupnpc/src/miniupnpc_socketdef.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/* $Id: miniupnpc_socketdef.h,v 1.1 2018/03/13 23:44:10 nanard Exp $ */
|
||||
/* Miniupnp project : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2018 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided within this distribution */
|
||||
#ifndef MINIUPNPC_SOCKETDEF_H_INCLUDED
|
||||
#define MINIUPNPC_SOCKETDEF_H_INCLUDED
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define ISINVALID(s) (INVALID_SOCKET==(s))
|
||||
|
||||
#else
|
||||
|
||||
#ifndef SOCKET
|
||||
#define SOCKET int
|
||||
#endif
|
||||
#ifndef SSIZE_T
|
||||
#define SSIZE_T ssize_t
|
||||
#endif
|
||||
#ifndef INVALID_SOCKET
|
||||
#define INVALID_SOCKET (-1)
|
||||
#endif
|
||||
#ifndef ISINVALID
|
||||
#define ISINVALID(s) ((s)<0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define MSC_CAST_INT (int)
|
||||
#else
|
||||
#define MSC_CAST_INT
|
||||
#endif
|
||||
|
||||
/* definition of PRINT_SOCKET_ERROR */
|
||||
#ifdef _WIN32
|
||||
#define PRINT_SOCKET_ERROR(x) fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError());
|
||||
#else
|
||||
#define PRINT_SOCKET_ERROR(x) perror(x)
|
||||
#endif
|
||||
|
||||
#endif /* MINIUPNPC_SOCKETDEF_H_INCLUDED */
|
15
thirdparty/miniupnpc/src/miniupnpcstrings.h
vendored
Normal file
15
thirdparty/miniupnpc/src/miniupnpcstrings.h
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
|
||||
#define MINIUPNPCSTRINGS_H_INCLUDED
|
||||
|
||||
#define OS_STRING "Godot Engine/1.0"
|
||||
#define MINIUPNPC_VERSION_STRING "2.3.3"
|
||||
|
||||
#if 0
|
||||
/* according to "UPnP Device Architecture 1.0" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.0"
|
||||
#else
|
||||
/* according to "UPnP Device Architecture 1.1" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.1"
|
||||
#endif
|
||||
|
||||
#endif
|
629
thirdparty/miniupnpc/src/miniwget.c
vendored
Normal file
629
thirdparty/miniupnpc/src/miniwget.c
vendored
Normal file
@@ -0,0 +1,629 @@
|
||||
/* $Id: miniwget.c,v 1.88 2025/05/25 21:56:49 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Website : 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
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#include "win32_snprintf.h"
|
||||
#define socklen_t int
|
||||
#ifndef strncasecmp
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
#define strncasecmp _memicmp
|
||||
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#define strncasecmp memicmp
|
||||
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||
#endif /* #ifndef strncasecmp */
|
||||
#else /* #ifdef _WIN32 */
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#define socklen_t int
|
||||
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/select.h>
|
||||
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#define closesocket close
|
||||
#include <strings.h>
|
||||
#endif /* #else _WIN32 */
|
||||
#ifdef __GNU__
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif /* __GNU__ */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#endif /* MIN */
|
||||
|
||||
|
||||
#include "miniupnpcstrings.h"
|
||||
#include "miniwget.h"
|
||||
#include "connecthostport.h"
|
||||
#include "receivedata.h"
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read a HTTP response from a socket.
|
||||
* Process Content-Length and Transfer-encoding headers.
|
||||
* return a pointer to the content buffer, which length is saved
|
||||
* to the length parameter.
|
||||
*/
|
||||
void *
|
||||
getHTTPResponse(SOCKET s, int * size, int * status_code)
|
||||
{
|
||||
char buf[2048];
|
||||
int n;
|
||||
int endofheaders = 0;
|
||||
int chunked = 0;
|
||||
int content_length = -1;
|
||||
unsigned int chunksize = 0;
|
||||
unsigned int bytestocopy = 0;
|
||||
/* buffers : */
|
||||
char * header_buf;
|
||||
unsigned int header_buf_len = 2048;
|
||||
unsigned int header_buf_used = 0;
|
||||
char * content_buf;
|
||||
unsigned int content_buf_len = 2048;
|
||||
unsigned int content_buf_used = 0;
|
||||
char chunksize_buf[32];
|
||||
unsigned int chunksize_buf_index;
|
||||
#ifdef DEBUG
|
||||
char * reason_phrase = NULL;
|
||||
int reason_phrase_len = 0;
|
||||
#endif
|
||||
|
||||
if(status_code) *status_code = -1;
|
||||
header_buf = malloc(header_buf_len);
|
||||
if(header_buf == NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
|
||||
#endif /* DEBUG */
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
content_buf = malloc(content_buf_len);
|
||||
if(content_buf == NULL)
|
||||
{
|
||||
free(header_buf);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
|
||||
#endif /* DEBUG */
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
chunksize_buf[0] = '\0';
|
||||
chunksize_buf_index = 0;
|
||||
|
||||
while((n = receivedata(s, buf, sizeof(buf), 5000, NULL)) > 0)
|
||||
{
|
||||
if(endofheaders == 0)
|
||||
{
|
||||
int i;
|
||||
int linestart=0;
|
||||
int colon=0;
|
||||
int valuestart=0;
|
||||
if(header_buf_used + n > header_buf_len) {
|
||||
char * tmp = realloc(header_buf, header_buf_used + n);
|
||||
if(tmp == NULL) {
|
||||
/* memory allocation error */
|
||||
free(header_buf);
|
||||
free(content_buf);
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
header_buf = tmp;
|
||||
header_buf_len = header_buf_used + n;
|
||||
}
|
||||
memcpy(header_buf + header_buf_used, buf, n);
|
||||
header_buf_used += n;
|
||||
/* search for CR LF CR LF (end of headers)
|
||||
* recognize also LF LF */
|
||||
i = 0;
|
||||
while(i < ((int)header_buf_used-1) && (endofheaders == 0)) {
|
||||
if(header_buf[i] == '\r') {
|
||||
i++;
|
||||
if(header_buf[i] == '\n') {
|
||||
i++;
|
||||
if(i < (int)header_buf_used && header_buf[i] == '\r') {
|
||||
i++;
|
||||
if(i < (int)header_buf_used && header_buf[i] == '\n') {
|
||||
endofheaders = i+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(header_buf[i] == '\n') {
|
||||
i++;
|
||||
if(header_buf[i] == '\n') {
|
||||
endofheaders = i+1;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(endofheaders == 0)
|
||||
continue;
|
||||
/* parse header lines */
|
||||
for(i = 0; i < endofheaders - 1; i++) {
|
||||
if(linestart > 0 && colon <= linestart && header_buf[i]==':')
|
||||
{
|
||||
colon = i;
|
||||
while(i < (endofheaders-1)
|
||||
&& (header_buf[i+1] == ' ' || header_buf[i+1] == '\t'))
|
||||
i++;
|
||||
valuestart = i + 1;
|
||||
}
|
||||
/* detecting end of line */
|
||||
else if(header_buf[i]=='\r' || header_buf[i]=='\n')
|
||||
{
|
||||
if(linestart == 0 && status_code)
|
||||
{
|
||||
/* Status line
|
||||
* HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
|
||||
int sp;
|
||||
for(sp = 0; sp < i - 1; sp++)
|
||||
if(header_buf[sp] == ' ')
|
||||
{
|
||||
if(*status_code < 0)
|
||||
{
|
||||
if (header_buf[sp+1] >= '1' && header_buf[sp+1] <= '9')
|
||||
*status_code = atoi(header_buf + sp + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
reason_phrase = header_buf + sp + 1;
|
||||
reason_phrase_len = i - sp - 1;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("HTTP status code = %d, Reason phrase = %.*s\n",
|
||||
*status_code, reason_phrase_len, reason_phrase);
|
||||
#endif
|
||||
}
|
||||
else if(colon > linestart && valuestart > colon)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("header='%.*s', value='%.*s'\n",
|
||||
colon-linestart, header_buf+linestart,
|
||||
i-valuestart, header_buf+valuestart);
|
||||
#endif
|
||||
if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart))
|
||||
{
|
||||
content_length = atoi(header_buf+valuestart);
|
||||
#ifdef DEBUG
|
||||
printf("Content-Length: %d\n", content_length);
|
||||
#endif
|
||||
}
|
||||
else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart)
|
||||
&& 0==strncasecmp(header_buf+valuestart, "chunked", 7))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("chunked transfer-encoding!\n");
|
||||
#endif
|
||||
chunked = 1;
|
||||
}
|
||||
}
|
||||
while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n'))
|
||||
i++;
|
||||
linestart = i;
|
||||
colon = linestart;
|
||||
valuestart = 0;
|
||||
}
|
||||
}
|
||||
/* copy the remaining of the received data back to buf */
|
||||
n = header_buf_used - endofheaders;
|
||||
memcpy(buf, header_buf + endofheaders, n);
|
||||
/* if(headers) */
|
||||
}
|
||||
/* if we get there, endofheaders != 0.
|
||||
* In the other case, there was a continue above */
|
||||
/* content */
|
||||
if(chunked)
|
||||
{
|
||||
int i = 0;
|
||||
while(i < n)
|
||||
{
|
||||
if(chunksize == 0)
|
||||
{
|
||||
/* reading chunk size */
|
||||
if(chunksize_buf_index == 0) {
|
||||
/* skipping any leading CR LF */
|
||||
if(buf[i] == '\r') i++;
|
||||
if(i<n && buf[i] == '\n') i++;
|
||||
}
|
||||
while(i<n && isxdigit(buf[i])
|
||||
&& chunksize_buf_index < (sizeof(chunksize_buf)-1))
|
||||
{
|
||||
chunksize_buf[chunksize_buf_index++] = buf[i];
|
||||
chunksize_buf[chunksize_buf_index] = '\0';
|
||||
i++;
|
||||
}
|
||||
while(i<n && buf[i] != '\r' && buf[i] != '\n')
|
||||
i++; /* discarding chunk-extension */
|
||||
if(i<n && buf[i] == '\r') i++;
|
||||
if(i<n && buf[i] == '\n') {
|
||||
unsigned int j;
|
||||
for(j = 0; j < chunksize_buf_index; j++) {
|
||||
if(chunksize_buf[j] >= '0'
|
||||
&& chunksize_buf[j] <= '9')
|
||||
chunksize = (chunksize << 4) + (chunksize_buf[j] - '0');
|
||||
else
|
||||
chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10);
|
||||
}
|
||||
chunksize_buf[0] = '\0';
|
||||
chunksize_buf_index = 0;
|
||||
i++;
|
||||
} else {
|
||||
/* not finished to get chunksize */
|
||||
continue;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("chunksize = %u (%x)\n", chunksize, chunksize);
|
||||
#endif
|
||||
if(chunksize == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("end of HTTP content - %d %d\n", i, n);
|
||||
/*printf("'%.*s'\n", n-i, buf+i);*/
|
||||
#endif
|
||||
goto end_of_stream;
|
||||
}
|
||||
}
|
||||
/* it is guaranteed that (n >= i) */
|
||||
bytestocopy = (chunksize < (unsigned int)(n - i))?chunksize:(unsigned int)(n - i);
|
||||
if((content_buf_used + bytestocopy) > content_buf_len)
|
||||
{
|
||||
char * tmp;
|
||||
if((content_length >= 0) && ((unsigned int)content_length >= (content_buf_used + bytestocopy))) {
|
||||
content_buf_len = content_length;
|
||||
} else {
|
||||
content_buf_len = content_buf_used + bytestocopy;
|
||||
}
|
||||
tmp = realloc(content_buf, content_buf_len);
|
||||
if(tmp == NULL) {
|
||||
/* memory allocation error */
|
||||
free(content_buf);
|
||||
free(header_buf);
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
content_buf = tmp;
|
||||
}
|
||||
memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
|
||||
content_buf_used += bytestocopy;
|
||||
i += bytestocopy;
|
||||
chunksize -= bytestocopy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not chunked */
|
||||
if(content_length > 0
|
||||
&& (content_buf_used + n) > (unsigned int)content_length) {
|
||||
/* skipping additional bytes */
|
||||
n = content_length - content_buf_used;
|
||||
}
|
||||
if(content_buf_used + n > content_buf_len)
|
||||
{
|
||||
char * tmp;
|
||||
if(content_length >= 0
|
||||
&& (unsigned int)content_length >= (content_buf_used + n)) {
|
||||
content_buf_len = content_length;
|
||||
} else {
|
||||
content_buf_len = content_buf_used + n;
|
||||
}
|
||||
tmp = realloc(content_buf, content_buf_len);
|
||||
if(tmp == NULL) {
|
||||
/* memory allocation error */
|
||||
free(content_buf);
|
||||
free(header_buf);
|
||||
*size = -1;
|
||||
return NULL;
|
||||
}
|
||||
content_buf = tmp;
|
||||
}
|
||||
memcpy(content_buf + content_buf_used, buf, n);
|
||||
content_buf_used += n;
|
||||
}
|
||||
/* use the Content-Length header value if available */
|
||||
if(content_length > 0 && content_buf_used >= (unsigned int)content_length)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("End of HTTP content\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
end_of_stream:
|
||||
free(header_buf);
|
||||
*size = content_buf_used;
|
||||
if(content_buf_used == 0)
|
||||
{
|
||||
free(content_buf);
|
||||
content_buf = NULL;
|
||||
}
|
||||
return content_buf;
|
||||
}
|
||||
|
||||
/* miniwget3() :
|
||||
* do all the work.
|
||||
* Return NULL if something failed. */
|
||||
static void *
|
||||
miniwget3(const char * host,
|
||||
unsigned short port, const char * path,
|
||||
int * size, char * addr_str, int addr_str_len,
|
||||
const char * httpversion, unsigned int scope_id,
|
||||
int * status_code)
|
||||
{
|
||||
char buf[2048];
|
||||
SOCKET s;
|
||||
int n;
|
||||
int len;
|
||||
int sent;
|
||||
void * content;
|
||||
|
||||
*size = 0;
|
||||
s = connecthostport(host, port, scope_id);
|
||||
if(ISINVALID(s))
|
||||
return NULL;
|
||||
|
||||
/* get address for caller ! */
|
||||
if(addr_str)
|
||||
{
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t saddrlen;
|
||||
|
||||
saddrlen = sizeof(saddr);
|
||||
if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0)
|
||||
{
|
||||
perror("getsockname");
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
|
||||
* But his function make a string with the port : nn.nn.nn.nn:port */
|
||||
/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
|
||||
NULL, addr_str, (DWORD *)&addr_str_len))
|
||||
{
|
||||
printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError());
|
||||
}*/
|
||||
/* the following code is only compatible with ip v4 addresses */
|
||||
strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len);
|
||||
#else
|
||||
#if 0
|
||||
if(saddr.sa_family == AF_INET6) {
|
||||
inet_ntop(AF_INET6,
|
||||
&(((struct sockaddr_in6 *)&saddr)->sin6_addr),
|
||||
addr_str, addr_str_len);
|
||||
} else {
|
||||
inet_ntop(AF_INET,
|
||||
&(((struct sockaddr_in *)&saddr)->sin_addr),
|
||||
addr_str, addr_str_len);
|
||||
}
|
||||
#endif
|
||||
/* getnameinfo return ip v6 address with the scope identifier
|
||||
* such as : 2a01:e35:8b2b:7330::%4281128194 */
|
||||
n = getnameinfo((const struct sockaddr *)&saddr, saddrlen,
|
||||
addr_str, addr_str_len,
|
||||
NULL, 0,
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
if(n != 0) {
|
||||
#ifdef _WIN32
|
||||
fprintf(stderr, "getnameinfo() failed : %d\n", n);
|
||||
#else
|
||||
fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("address miniwget : %s\n", addr_str);
|
||||
#endif
|
||||
}
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"GET %s HTTP/%s\r\n"
|
||||
"Host: %s:%d\r\n"
|
||||
"Connection: close\r\n"
|
||||
"User-Agent: " OS_STRING " " UPNP_VERSION_STRING " MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||
"\r\n",
|
||||
path, httpversion, host, port);
|
||||
if ((unsigned int)len >= sizeof(buf))
|
||||
{
|
||||
closesocket(s);
|
||||
return NULL;
|
||||
}
|
||||
sent = 0;
|
||||
/* sending the HTTP request */
|
||||
while(sent < len)
|
||||
{
|
||||
n = send(s, buf+sent, len-sent, 0);
|
||||
if(n < 0)
|
||||
{
|
||||
perror("send");
|
||||
closesocket(s);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sent += n;
|
||||
}
|
||||
}
|
||||
content = getHTTPResponse(s, size, status_code);
|
||||
closesocket(s);
|
||||
return content;
|
||||
}
|
||||
|
||||
/* parseURL()
|
||||
* arguments :
|
||||
* url : source string not modified
|
||||
* hostname : hostname destination string (size of MAXHOSTNAMELEN+1)
|
||||
* port : port (destination)
|
||||
* path : pointer to the path part of the URL
|
||||
*
|
||||
* Return values :
|
||||
* 0 - Failure
|
||||
* 1 - Success */
|
||||
int
|
||||
parseURL(const char * url,
|
||||
char * hostname, unsigned short * port,
|
||||
char * * path, unsigned int * scope_id)
|
||||
{
|
||||
char * p1, *p2, *p3;
|
||||
if(!url)
|
||||
return 0;
|
||||
p1 = strstr(url, "://");
|
||||
if(!p1)
|
||||
return 0;
|
||||
p1 += 3;
|
||||
if( (url[0]!='h') || (url[1]!='t')
|
||||
||(url[2]!='t') || (url[3]!='p'))
|
||||
return 0;
|
||||
memset(hostname, 0, MAXHOSTNAMELEN + 1);
|
||||
if(*p1 == '[')
|
||||
{
|
||||
/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */
|
||||
char * scope;
|
||||
scope = strchr(p1, '%');
|
||||
p2 = strchr(p1, ']');
|
||||
if(p2 && scope && scope < p2 && scope_id) {
|
||||
/* parse scope */
|
||||
#ifdef IF_NAMESIZE
|
||||
char tmp[IF_NAMESIZE];
|
||||
int l;
|
||||
scope++;
|
||||
/* "%25" is just '%' in URL encoding */
|
||||
if(scope[0] == '2' && scope[1] == '5')
|
||||
scope += 2; /* skip "25" */
|
||||
l = p2 - scope;
|
||||
if(l >= IF_NAMESIZE)
|
||||
l = IF_NAMESIZE - 1;
|
||||
memcpy(tmp, scope, l);
|
||||
tmp[l] = '\0';
|
||||
*scope_id = if_nametoindex(tmp);
|
||||
if(*scope_id == 0) {
|
||||
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||
}
|
||||
#else
|
||||
/* under windows, scope is numerical */
|
||||
char tmp[8];
|
||||
size_t l;
|
||||
scope++;
|
||||
/* "%25" is just '%' in URL encoding */
|
||||
if(scope[0] == '2' && scope[1] == '5')
|
||||
scope += 2; /* skip "25" */
|
||||
l = p2 - scope;
|
||||
if(l >= sizeof(tmp))
|
||||
l = sizeof(tmp) - 1;
|
||||
memcpy(tmp, scope, l);
|
||||
tmp[l] = '\0';
|
||||
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||
#endif
|
||||
}
|
||||
p3 = strchr(p1, '/');
|
||||
if(p2 && p3)
|
||||
{
|
||||
p2++;
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||
if(*p2 == ':')
|
||||
{
|
||||
*port = 0;
|
||||
p2++;
|
||||
while( (*p2 >= '0') && (*p2 <= '9'))
|
||||
{
|
||||
*port *= 10;
|
||||
*port += (unsigned short)(*p2 - '0');
|
||||
p2++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*port = 80;
|
||||
}
|
||||
*path = p3;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
p2 = strchr(p1, ':');
|
||||
p3 = strchr(p1, '/');
|
||||
if(!p3)
|
||||
return 0;
|
||||
if(!p2 || (p2>p3))
|
||||
{
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
|
||||
*port = 80;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||
*port = 0;
|
||||
p2++;
|
||||
while( (*p2 >= '0') && (*p2 <= '9'))
|
||||
{
|
||||
*port *= 10;
|
||||
*port += (unsigned short)(*p2 - '0');
|
||||
p2++;
|
||||
}
|
||||
}
|
||||
*path = p3;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *
|
||||
miniwget(const char * url, int * size,
|
||||
unsigned int scope_id, int * status_code)
|
||||
{
|
||||
unsigned short port;
|
||||
char * path;
|
||||
/* protocol://host:port/chemin */
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
*size = 0;
|
||||
if(!parseURL(url, hostname, &port, &path, &scope_id))
|
||||
return NULL;
|
||||
#ifdef DEBUG
|
||||
printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
|
||||
hostname, port, path, scope_id);
|
||||
#endif
|
||||
return miniwget3(hostname, port, path, size, 0, 0, "1.1", scope_id, status_code);
|
||||
}
|
||||
|
||||
void *
|
||||
miniwget_getaddr(const char * url, int * size,
|
||||
char * addr, int addrlen, unsigned int scope_id,
|
||||
int * status_code)
|
||||
{
|
||||
unsigned short port;
|
||||
char * path;
|
||||
/* protocol://host:port/path */
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
*size = 0;
|
||||
if(addr)
|
||||
addr[0] = '\0';
|
||||
if(!parseURL(url, hostname, &port, &path, &scope_id))
|
||||
return NULL;
|
||||
#ifdef DEBUG
|
||||
printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
|
||||
hostname, port, path, scope_id);
|
||||
#endif
|
||||
return miniwget3(hostname, port, path, size, addr, addrlen, "1.1", scope_id, status_code);
|
||||
}
|
54
thirdparty/miniupnpc/src/miniwget_private.h
vendored
Normal file
54
thirdparty/miniupnpc/src/miniwget_private.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/* $Id: miniwget_private.h,v 1.1 2018/04/06 10:17:58 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2018-2025 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef MINIWGET_INTERNAL_H_INCLUDED
|
||||
#define MINIWGET_INTERNAL_H_INCLUDED
|
||||
|
||||
/*! \file miniwget_private.h
|
||||
* \brief Lightweight HTTP client private API
|
||||
*/
|
||||
#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);
|
||||
|
||||
/*! \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
|
231
thirdparty/miniupnpc/src/minixml.c
vendored
Normal file
231
thirdparty/miniupnpc/src/minixml.c
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
/* $Id: minixml.c,v 1.12 2017/12/12 11:17:40 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* minixml.c : the minimum size a xml parser can be ! */
|
||||
/* Project : miniupnp
|
||||
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
|
||||
Copyright (c) 2005-2017, Thomas BERNARD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "minixml.h"
|
||||
|
||||
/* parseatt : used to parse the argument list
|
||||
* return 0 (false) in case of success and -1 (true) if the end
|
||||
* of the xmlbuffer is reached. */
|
||||
static int parseatt(struct xmlparser * p)
|
||||
{
|
||||
const char * attname;
|
||||
int attnamelen;
|
||||
const char * attvalue;
|
||||
int attvaluelen;
|
||||
while(p->xml < p->xmlend)
|
||||
{
|
||||
if(*p->xml=='/' || *p->xml=='>')
|
||||
return 0;
|
||||
if( !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
char sep;
|
||||
attname = p->xml;
|
||||
attnamelen = 0;
|
||||
while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
attnamelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(*(p->xml++) != '=')
|
||||
{
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(IS_WHITE_SPACE(*p->xml))
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
sep = *p->xml;
|
||||
if(sep=='\'' || sep=='\"')
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while(*p->xml != sep)
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& *p->xml != '>' && *p->xml != '/')
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*printf("%.*s='%.*s'\n",
|
||||
attnamelen, attname, attvaluelen, attvalue);*/
|
||||
if(p->attfunc)
|
||||
p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
|
||||
}
|
||||
p->xml++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parseelt parse the xml stream and
|
||||
* call the callback functions when needed... */
|
||||
static void parseelt(struct xmlparser * p)
|
||||
{
|
||||
int i;
|
||||
const char * elementname;
|
||||
while(p->xml < (p->xmlend - 1))
|
||||
{
|
||||
if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4)))
|
||||
{
|
||||
p->xml += 3;
|
||||
/* ignore comments */
|
||||
do
|
||||
{
|
||||
p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
while(memcmp(p->xml, "-->", 3) != 0);
|
||||
p->xml += 3;
|
||||
}
|
||||
else if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& (*p->xml!='>') && (*p->xml!='/')
|
||||
)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
/* to ignore namespace : */
|
||||
if(*p->xml==':')
|
||||
{
|
||||
i = 0;
|
||||
elementname = ++p->xml;
|
||||
}
|
||||
}
|
||||
if(i>0)
|
||||
{
|
||||
if(p->starteltfunc)
|
||||
p->starteltfunc(p->data, elementname, i);
|
||||
if(parseatt(p))
|
||||
return;
|
||||
if(*p->xml!='/')
|
||||
{
|
||||
const char * data;
|
||||
i = 0; data = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while( IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
/* CDATA are at least 9 + 3 characters long : <![CDATA[ ]]> */
|
||||
if((p->xmlend >= (p->xml + (9 + 3))) && (memcmp(p->xml, "<![CDATA[", 9) == 0))
|
||||
{
|
||||
/* CDATA handling */
|
||||
p->xml += 9;
|
||||
data = p->xml;
|
||||
i = 0;
|
||||
while(memcmp(p->xml, "]]>", 3) != 0)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc)
|
||||
p->datafunc(p->data, data, i);
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 1) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc && *(p->xml + 1) == '/')
|
||||
p->datafunc(p->data, data, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(*p->xml == '/')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while((*p->xml != '>'))
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(p->endeltfunc)
|
||||
p->endeltfunc(p->data, elementname, i);
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the parser must be initialized before calling this function */
|
||||
void parsexml(struct xmlparser * parser)
|
||||
{
|
||||
parser->xml = parser->xmlstart;
|
||||
parser->xmlend = parser->xmlstart + parser->xmlsize;
|
||||
parseelt(parser);
|
||||
}
|
||||
|
||||
|
37
thirdparty/miniupnpc/src/minixml.h
vendored
Normal file
37
thirdparty/miniupnpc/src/minixml.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */
|
||||
/* minimal xml parser
|
||||
*
|
||||
* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef MINIXML_H_INCLUDED
|
||||
#define MINIXML_H_INCLUDED
|
||||
#define IS_WHITE_SPACE(c) ((c)==' ' || (c)=='\t' || (c)=='\r' || (c)=='\n')
|
||||
|
||||
/* if a callback function pointer is set to NULL,
|
||||
* the function is not called */
|
||||
struct xmlparser {
|
||||
const char *xmlstart;
|
||||
const char *xmlend;
|
||||
const char *xml; /* pointer to current character */
|
||||
int xmlsize;
|
||||
void * data;
|
||||
void (*starteltfunc) (void *, const char *, int);
|
||||
void (*endeltfunc) (void *, const char *, int);
|
||||
void (*datafunc) (void *, const char *, int);
|
||||
void (*attfunc) (void *, const char *, int, const char *, int);
|
||||
};
|
||||
|
||||
/* parsexml()
|
||||
* the xmlparser structure must be initialized before the call
|
||||
* the following structure members have to be initialized :
|
||||
* xmlstart, xmlsize, data, *func
|
||||
* xml is for internal usage, xmlend is computed automatically */
|
||||
void parsexml(struct xmlparser *);
|
||||
|
||||
#endif
|
||||
|
163
thirdparty/miniupnpc/src/minixmlvalid.c
vendored
Normal file
163
thirdparty/miniupnpc/src/minixmlvalid.c
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
/* $Id: minixmlvalid.c,v 1.7 2015/07/15 12:41:15 nanard Exp $ */
|
||||
/* MiniUPnP Project
|
||||
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
|
||||
* minixmlvalid.c :
|
||||
* validation program for the minixml parser
|
||||
*
|
||||
* (c) 2006-2011 Thomas Bernard */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "minixml.h"
|
||||
|
||||
/* xml event structure */
|
||||
struct event {
|
||||
enum { ELTSTART, ELTEND, ATT, CHARDATA } type;
|
||||
const char * data;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct eventlist {
|
||||
int n;
|
||||
struct event * events;
|
||||
};
|
||||
|
||||
/* compare 2 xml event lists
|
||||
* return 0 if the two lists are equals */
|
||||
int evtlistcmp(struct eventlist * a, struct eventlist * b)
|
||||
{
|
||||
int i;
|
||||
struct event * ae, * be;
|
||||
if(a->n != b->n)
|
||||
{
|
||||
printf("event number not matching : %d != %d\n", a->n, b->n);
|
||||
/*return 1;*/
|
||||
}
|
||||
for(i=0; i<a->n; i++)
|
||||
{
|
||||
ae = a->events + i;
|
||||
be = b->events + i;
|
||||
if( (ae->type != be->type)
|
||||
||(ae->len != be->len)
|
||||
||memcmp(ae->data, be->data, ae->len))
|
||||
{
|
||||
printf("Found a difference : %d '%.*s' != %d '%.*s'\n",
|
||||
ae->type, ae->len, ae->data,
|
||||
be->type, be->len, be->data);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test data */
|
||||
static const char xmldata[] =
|
||||
"<xmlroot>\n"
|
||||
" <elt1 att1=\"attvalue1\" att2=\"attvalue2\">"
|
||||
"character data"
|
||||
"</elt1> \n \t"
|
||||
"<elt1b/>"
|
||||
"<elt1>\n<![CDATA[ <html>stuff !\n ]]> \n</elt1>\n"
|
||||
"<elt2a> \t<elt2b>chardata1</elt2b><elt2b> chardata2 </elt2b></elt2a>"
|
||||
"</xmlroot>";
|
||||
|
||||
static const struct event evtref[] =
|
||||
{
|
||||
{ELTSTART, "xmlroot", 7},
|
||||
{ELTSTART, "elt1", 4},
|
||||
/* attributes */
|
||||
{CHARDATA, "character data", 14},
|
||||
{ELTEND, "elt1", 4},
|
||||
{ELTSTART, "elt1b", 5},
|
||||
{ELTSTART, "elt1", 4},
|
||||
{CHARDATA, " <html>stuff !\n ", 16},
|
||||
{ELTEND, "elt1", 4},
|
||||
{ELTSTART, "elt2a", 5},
|
||||
{ELTSTART, "elt2b", 5},
|
||||
{CHARDATA, "chardata1", 9},
|
||||
{ELTEND, "elt2b", 5},
|
||||
{ELTSTART, "elt2b", 5},
|
||||
{CHARDATA, " chardata2 ", 11},
|
||||
{ELTEND, "elt2b", 5},
|
||||
{ELTEND, "elt2a", 5},
|
||||
{ELTEND, "xmlroot", 7}
|
||||
};
|
||||
|
||||
void startelt(void * data, const char * p, int l)
|
||||
{
|
||||
struct eventlist * evtlist = data;
|
||||
struct event * evt;
|
||||
evt = evtlist->events + evtlist->n;
|
||||
/*printf("startelt : %.*s\n", l, p);*/
|
||||
evt->type = ELTSTART;
|
||||
evt->data = p;
|
||||
evt->len = l;
|
||||
evtlist->n++;
|
||||
}
|
||||
|
||||
void endelt(void * data, const char * p, int l)
|
||||
{
|
||||
struct eventlist * evtlist = data;
|
||||
struct event * evt;
|
||||
evt = evtlist->events + evtlist->n;
|
||||
/*printf("endelt : %.*s\n", l, p);*/
|
||||
evt->type = ELTEND;
|
||||
evt->data = p;
|
||||
evt->len = l;
|
||||
evtlist->n++;
|
||||
}
|
||||
|
||||
void chardata(void * data, const char * p, int l)
|
||||
{
|
||||
struct eventlist * evtlist = data;
|
||||
struct event * evt;
|
||||
evt = evtlist->events + evtlist->n;
|
||||
/*printf("chardata : '%.*s'\n", l, p);*/
|
||||
evt->type = CHARDATA;
|
||||
evt->data = p;
|
||||
evt->len = l;
|
||||
evtlist->n++;
|
||||
}
|
||||
|
||||
int testxmlparser(const char * xml, int size)
|
||||
{
|
||||
int r;
|
||||
struct eventlist evtlist;
|
||||
struct eventlist evtlistref;
|
||||
struct xmlparser parser;
|
||||
evtlist.n = 0;
|
||||
evtlist.events = malloc(sizeof(struct event)*100);
|
||||
if(evtlist.events == NULL)
|
||||
{
|
||||
fprintf(stderr, "Memory allocation error.\n");
|
||||
return -1;
|
||||
}
|
||||
memset(&parser, 0, sizeof(parser));
|
||||
parser.xmlstart = xml;
|
||||
parser.xmlsize = size;
|
||||
parser.data = &evtlist;
|
||||
parser.starteltfunc = startelt;
|
||||
parser.endeltfunc = endelt;
|
||||
parser.datafunc = chardata;
|
||||
parsexml(&parser);
|
||||
printf("%d events\n", evtlist.n);
|
||||
/* compare */
|
||||
evtlistref.n = sizeof(evtref)/sizeof(struct event);
|
||||
evtlistref.events = (struct event *)evtref;
|
||||
r = evtlistcmp(&evtlistref, &evtlist);
|
||||
free(evtlist.events);
|
||||
return r;
|
||||
}
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
int r;
|
||||
(void)argc; (void)argv;
|
||||
|
||||
r = testxmlparser(xmldata, sizeof(xmldata)-1);
|
||||
if(r)
|
||||
printf("minixml validation test failed\n");
|
||||
return r;
|
||||
}
|
||||
|
177
thirdparty/miniupnpc/src/portlistingparse.c
vendored
Normal file
177
thirdparty/miniupnpc/src/portlistingparse.c
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
/* $Id: portlistingparse.c,v 1.12 2025/03/29 17:58:33 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2025 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif /* DEBUG */
|
||||
#include "portlistingparse.h"
|
||||
#include "minixml.h"
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
/* rename our private function because Haiku already defines a atoui() function */
|
||||
#define atoui atoui2
|
||||
#endif
|
||||
|
||||
/* list of the elements */
|
||||
static const struct {
|
||||
const portMappingElt code;
|
||||
const char * const str;
|
||||
} elements[] = {
|
||||
{ PortMappingEntry, "PortMappingEntry"},
|
||||
{ NewRemoteHost, "NewRemoteHost"},
|
||||
{ NewExternalPort, "NewExternalPort"},
|
||||
{ NewProtocol, "NewProtocol"},
|
||||
{ NewInternalPort, "NewInternalPort"},
|
||||
{ NewInternalClient, "NewInternalClient"},
|
||||
{ NewEnabled, "NewEnabled"},
|
||||
{ NewDescription, "NewDescription"},
|
||||
{ NewLeaseTime, "NewLeaseTime"},
|
||||
{ PortMappingEltNone, NULL}
|
||||
};
|
||||
|
||||
/* Helper function */
|
||||
static UNSIGNED_INTEGER
|
||||
atoui(const char * p, int l)
|
||||
{
|
||||
UNSIGNED_INTEGER r = 0;
|
||||
while(l > 0 && *p)
|
||||
{
|
||||
if(*p >= '0' && *p <= '9')
|
||||
r = r*10 + (*p - '0');
|
||||
else
|
||||
break;
|
||||
p++;
|
||||
l--;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Start element handler */
|
||||
static void
|
||||
startelt(void * d, const char * name, int l)
|
||||
{
|
||||
int i;
|
||||
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||
pdata->curelt = PortMappingEltNone;
|
||||
for(i = 0; elements[i].str; i++)
|
||||
{
|
||||
if(strlen(elements[i].str) == (size_t)l && memcmp(name, elements[i].str, l) == 0)
|
||||
{
|
||||
pdata->curelt = elements[i].code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(pdata->curelt == PortMappingEntry)
|
||||
{
|
||||
struct PortMapping * pm;
|
||||
pm = calloc(1, sizeof(struct PortMapping));
|
||||
if(pm == NULL)
|
||||
{
|
||||
/* malloc error */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: error allocating memory",
|
||||
"startelt");
|
||||
#endif /* DEBUG */
|
||||
return;
|
||||
}
|
||||
pm->l_next = pdata->l_head; /* insert in list */
|
||||
pdata->l_head = pm;
|
||||
}
|
||||
}
|
||||
|
||||
/* End element handler */
|
||||
static void
|
||||
endelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||
(void)name;
|
||||
(void)l;
|
||||
pdata->curelt = PortMappingEltNone;
|
||||
}
|
||||
|
||||
/* Data handler */
|
||||
static void
|
||||
data(void * d, const char * data, int l)
|
||||
{
|
||||
struct PortMapping * pm;
|
||||
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||
pm = pdata->l_head;
|
||||
if(!pm)
|
||||
return;
|
||||
if(l > 63)
|
||||
l = 63;
|
||||
switch(pdata->curelt)
|
||||
{
|
||||
case NewRemoteHost:
|
||||
memcpy(pm->remoteHost, data, l);
|
||||
pm->remoteHost[l] = '\0';
|
||||
break;
|
||||
case NewExternalPort:
|
||||
pm->externalPort = (unsigned short)atoui(data, l);
|
||||
break;
|
||||
case NewProtocol:
|
||||
if(l > 3)
|
||||
l = 3;
|
||||
memcpy(pm->protocol, data, l);
|
||||
pm->protocol[l] = '\0';
|
||||
break;
|
||||
case NewInternalPort:
|
||||
pm->internalPort = (unsigned short)atoui(data, l);
|
||||
break;
|
||||
case NewInternalClient:
|
||||
memcpy(pm->internalClient, data, l);
|
||||
pm->internalClient[l] = '\0';
|
||||
break;
|
||||
case NewEnabled:
|
||||
pm->enabled = (unsigned char)atoui(data, l);
|
||||
break;
|
||||
case NewDescription:
|
||||
memcpy(pm->description, data, l);
|
||||
pm->description[l] = '\0';
|
||||
break;
|
||||
case NewLeaseTime:
|
||||
pm->leaseTime = atoui(data, l);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Parse the PortMappingList XML document for IGD version 2
|
||||
*/
|
||||
void
|
||||
ParsePortListing(const char * buffer, int bufsize,
|
||||
struct PortMappingParserData * pdata)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
|
||||
memset(pdata, 0, sizeof(struct PortMappingParserData));
|
||||
/* init xmlparser */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = pdata;
|
||||
parser.starteltfunc = startelt;
|
||||
parser.endeltfunc = endelt;
|
||||
parser.datafunc = data;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
}
|
||||
|
||||
void
|
||||
FreePortListing(struct PortMappingParserData * pdata)
|
||||
{
|
||||
struct PortMapping * pm;
|
||||
while((pm = pdata->l_head) != NULL)
|
||||
{
|
||||
/* remove from list */
|
||||
pdata->l_head = pm->l_next;
|
||||
free(pm);
|
||||
}
|
||||
}
|
||||
|
106
thirdparty/miniupnpc/src/receivedata.c
vendored
Normal file
106
thirdparty/miniupnpc/src/receivedata.c
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/* $Id: receivedata.c,v 1.11 2025/05/25 21:56:49 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2011-2025 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else /* _WIN32 */
|
||||
#include <unistd.h>
|
||||
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#define socklen_t int
|
||||
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/select.h>
|
||||
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#if !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
#include <poll.h>
|
||||
#endif /* !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#include <errno.h>
|
||||
#define MINIUPNPC_IGNORE_EINTR
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "receivedata.h"
|
||||
|
||||
int
|
||||
receivedata(SOCKET socket,
|
||||
char * data, int length,
|
||||
int timeout, unsigned int * scope_id)
|
||||
{
|
||||
#ifdef MINIUPNPC_GET_SRC_ADDR
|
||||
struct sockaddr_storage src_addr;
|
||||
socklen_t src_addr_len = sizeof(src_addr);
|
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */
|
||||
int n;
|
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||
/* using poll */
|
||||
struct pollfd fds[1]; /* for the poll */
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
do {
|
||||
#endif /* MINIUPNPC_IGNORE_EINTR */
|
||||
fds[0].fd = socket;
|
||||
fds[0].events = POLLIN;
|
||||
n = poll(fds, 1, timeout);
|
||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||
} while(n < 0 && errno == EINTR);
|
||||
#endif /* MINIUPNPC_IGNORE_EINTR */
|
||||
if(n < 0) {
|
||||
PRINT_SOCKET_ERROR("poll");
|
||||
return -1;
|
||||
} else if(n == 0) {
|
||||
/* timeout */
|
||||
return 0;
|
||||
}
|
||||
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
/* using select under _WIN32 and amigaos */
|
||||
fd_set socketSet;
|
||||
TIMEVAL timeval;
|
||||
FD_ZERO(&socketSet);
|
||||
FD_SET(socket, &socketSet);
|
||||
timeval.tv_sec = timeout / 1000;
|
||||
timeval.tv_usec = (timeout % 1000) * 1000;
|
||||
n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval);
|
||||
if(n < 0) {
|
||||
PRINT_SOCKET_ERROR("select");
|
||||
return -1;
|
||||
} else if(n == 0) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||
#ifdef MINIUPNPC_GET_SRC_ADDR
|
||||
memset(&src_addr, 0, sizeof(src_addr));
|
||||
n = recvfrom(socket, data, length, 0,
|
||||
(struct sockaddr *)&src_addr, &src_addr_len);
|
||||
#else /* MINIUPNPC_GET_SRC_ADDR */
|
||||
n = recv(socket, data, length, 0);
|
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */
|
||||
if(n<0) {
|
||||
PRINT_SOCKET_ERROR("recv");
|
||||
}
|
||||
#ifdef MINIUPNPC_GET_SRC_ADDR
|
||||
if (src_addr.ss_family == AF_INET6) {
|
||||
const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr;
|
||||
#ifdef DEBUG
|
||||
printf("scope_id=%u\n", src_addr6->sin6_scope_id);
|
||||
#endif /* DEBUG */
|
||||
if(scope_id)
|
||||
*scope_id = src_addr6->sin6_scope_id;
|
||||
} else {
|
||||
if(scope_id)
|
||||
*scope_id = 0;
|
||||
}
|
||||
#else /* MINIUPNPC_GET_SRC_ADDR */
|
||||
if(scope_id)
|
||||
*scope_id = 0;
|
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */
|
||||
return n;
|
||||
}
|
||||
|
21
thirdparty/miniupnpc/src/receivedata.h
vendored
Normal file
21
thirdparty/miniupnpc/src/receivedata.h
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/* $Id: receivedata.h,v 1.3 2012/06/23 22:34:47 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2011-2018 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef RECEIVEDATA_H_INCLUDED
|
||||
#define RECEIVEDATA_H_INCLUDED
|
||||
|
||||
#include "miniupnpc_socketdef.h"
|
||||
|
||||
/* Reads data from the specified socket.
|
||||
* Returns the number of bytes read if successful, zero if no bytes were
|
||||
* read or if we timed out. Returns negative if there was an error. */
|
||||
int receivedata(SOCKET socket,
|
||||
char * data, int length,
|
||||
int timeout, unsigned int * scope_id);
|
||||
|
||||
#endif
|
||||
|
1211
thirdparty/miniupnpc/src/upnpcommands.c
vendored
Normal file
1211
thirdparty/miniupnpc/src/upnpcommands.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
thirdparty/miniupnpc/src/upnpdev.c
vendored
Normal file
23
thirdparty/miniupnpc/src/upnpdev.c
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
* copyright (c) 2005-2015 Thomas Bernard
|
||||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#include <stdlib.h>
|
||||
#include "upnpdev.h"
|
||||
|
||||
/* freeUPNPDevlist() should be used to
|
||||
* free the chained list returned by upnpDiscover() */
|
||||
void freeUPNPDevlist(struct UPNPDev * devlist)
|
||||
{
|
||||
struct UPNPDev * next;
|
||||
while(devlist)
|
||||
{
|
||||
next = devlist->pNext;
|
||||
free(devlist);
|
||||
devlist = next;
|
||||
}
|
||||
}
|
||||
|
187
thirdparty/miniupnpc/src/upnpreplyparse.c
vendored
Normal file
187
thirdparty/miniupnpc/src/upnpreplyparse.c
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
/* $Id: upnpreplyparse.c,v 1.22 2025/02/08 23:12:26 nanard Exp $ */
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2025 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "upnpreplyparse.h"
|
||||
#include "minixml.h"
|
||||
|
||||
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
|
||||
NameValueParserStartElt(void * d, const char * name, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
data->topelt = 1;
|
||||
if(l>63)
|
||||
l = 63;
|
||||
memcpy(data->curelt, name, l);
|
||||
data->curelt[l] = '\0';
|
||||
data->cdata = NULL;
|
||||
data->cdatalen = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
NameValueParserEndElt(void * d, const char * name, int namelen)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
struct NameValue * nv;
|
||||
(void)name;
|
||||
(void)namelen;
|
||||
if(!data->topelt)
|
||||
return;
|
||||
if(strcmp(data->curelt, "NewPortListing") != 0)
|
||||
{
|
||||
int l;
|
||||
/* standard case. Limited to n chars strings */
|
||||
l = data->cdatalen;
|
||||
nv = malloc(sizeof(struct NameValue) + l + 1);
|
||||
if(nv == NULL)
|
||||
{
|
||||
/* malloc error */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: error allocating memory",
|
||||
"NameValueParserEndElt");
|
||||
#endif /* DEBUG */
|
||||
return;
|
||||
}
|
||||
strncpy(nv->name, data->curelt, 64);
|
||||
nv->name[63] = '\0';
|
||||
if(data->cdata != NULL)
|
||||
{
|
||||
memcpy(nv->value, data->cdata, l);
|
||||
nv->value[l] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
nv->value[0] = '\0';
|
||||
}
|
||||
nv->l_next = data->l_head; /* insert in list */
|
||||
data->l_head = nv;
|
||||
}
|
||||
data->cdata = NULL;
|
||||
data->cdatalen = 0;
|
||||
data->topelt = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
NameValueParserGetData(void * d, const char * datas, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
if(strcmp(data->curelt, "NewPortListing") == 0)
|
||||
{
|
||||
/* specific case for NewPortListing which is a XML Document */
|
||||
free(data->portListing);
|
||||
data->portListing = malloc(l + 1);
|
||||
if(!data->portListing)
|
||||
{
|
||||
/* malloc error */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s: error allocating memory",
|
||||
"NameValueParserGetData");
|
||||
#endif /* DEBUG */
|
||||
return;
|
||||
}
|
||||
memcpy(data->portListing, datas, l);
|
||||
data->portListing[l] = '\0';
|
||||
data->portListingLength = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* standard case. */
|
||||
data->cdata = datas;
|
||||
data->cdatalen = l;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
memset(data, 0, sizeof(struct NameValueParserData));
|
||||
/* init xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = NameValueParserStartElt;
|
||||
parser.endeltfunc = NameValueParserEndElt;
|
||||
parser.datafunc = NameValueParserGetData;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
}
|
||||
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
if(pdata->portListing)
|
||||
{
|
||||
free(pdata->portListing);
|
||||
pdata->portListing = NULL;
|
||||
pdata->portListingLength = 0;
|
||||
}
|
||||
while((nv = pdata->l_head) != NULL)
|
||||
{
|
||||
pdata->l_head = nv->l_next;
|
||||
free(nv);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
for(nv = pdata->l_head;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->l_next)
|
||||
{
|
||||
if(strcmp(nv->name, name) == 0)
|
||||
p = nv->value;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* debug all-in-one function
|
||||
* do parsing then display to stdout */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
struct NameValue * nv;
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
for(nv = pdata.l_head;
|
||||
nv != NULL;
|
||||
nv = nv->l_next)
|
||||
{
|
||||
printf("%s = %s\n", nv->name, nv->value);
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
71
thirdparty/miniupnpc/src/win32_snprintf.h
vendored
Normal file
71
thirdparty/miniupnpc/src/win32_snprintf.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
||||
* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||
* (c) 2020 Pali Rohár
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef WIN32_SNPRINTF_H
|
||||
#define WIN32_SNPRINTF_H
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* snprintf is supported by:
|
||||
* - Visual Studio 2015 or new
|
||||
* - mingw32 with iso c ext
|
||||
* - mingw-w64 with ansi stdio
|
||||
* - mingw-w64 6.0.0 or new with ucrt
|
||||
* - mingw-w64 8.0.0 or new with iso c ext
|
||||
*/
|
||||
#if ( \
|
||||
(defined(_MSC_VER) && _MSC_VER < 1900) /* Visual Studio older than 2015 */ || \
|
||||
(defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && defined(__NO_ISOCEXT)) /* mingw32 without iso c ext */ || \
|
||||
(defined(__MINGW64_VERSION_MAJOR) && /* mingw-w64 not ... */ !( \
|
||||
(defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO != 0) /* ... with ansi stdio */ || \
|
||||
(__MINGW64_VERSION_MAJOR >= 6 && defined(_UCRT)) /* ... at least 6.0.0 with ucrt */ || \
|
||||
(__MINGW64_VERSION_MAJOR >= 8 && !defined(__NO_ISOCEXT))) /* ... at least 8.0.0 with iso c ext */ || \
|
||||
0) || \
|
||||
0)
|
||||
|
||||
/* _scprintf is supported by:
|
||||
* - Visual Studio 2002 or new
|
||||
* - msvcr70.dll or new
|
||||
* - msvcrt.dll on Windows XP or new
|
||||
*/
|
||||
#if ( \
|
||||
(defined(_MSC_VER) && _MSC_VER < 1300) /* Visual Studio older than 2002 */ || \
|
||||
(defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x700) /* msvcrt older than 7.0 */ || \
|
||||
0)
|
||||
#define CHECK_SCPRINTF 0
|
||||
#define IF_SCPRINTF(expr) 0
|
||||
#define ELSE_SCPRINTF(expr) expr
|
||||
#else
|
||||
#define CHECK_SCPRINTF 1
|
||||
#define IF_SCPRINTF(expr) expr
|
||||
#define ELSE_SCPRINTF(expr) 0
|
||||
#endif
|
||||
|
||||
/* Emulation of snprintf for win32 */
|
||||
#define snprintf(buf, size, fmt, ...) ( \
|
||||
(((size) != 0 && (buf) != NULL) ? ( /* _snprintf does not work with NULL buffer */ \
|
||||
_snprintf((buf), (size), (fmt), __VA_ARGS__), /* _snprintf returns -1 on overflow, so ignore its value */ \
|
||||
(((char *)buf)[(size_t)(size)-1] = 0), /* _snprintf does not fill nul byte on overflow */ \
|
||||
0) : 0), \
|
||||
(CHECK_SCPRINTF ? IF_SCPRINTF( \
|
||||
_scprintf((fmt), __VA_ARGS__) /* calculate return value for snprintf via _scprintf */ \
|
||||
) : ELSE_SCPRINTF( \
|
||||
((size) != 0 && (buf) != NULL) ? \
|
||||
strlen((buf)) /* return just length of buffer */ \
|
||||
: \
|
||||
1 /* no buffer, impossible to calculate, return just non-zero number */ \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* WIN32_SNPRINTF_H */
|
Reference in New Issue
Block a user