UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
urlconfig.cpp
Go to the documentation of this file.
1/**************************************************************************
2 *
3 * Copyright (c) 2000-2003 Intel Corporation
4 * All rights reserved.
5 * Copyright (c) 2012 France Telecom All rights reserved.
6 * Copyright (C) 2021 GPL 3 and higher by Ingo Höft, <Ingo@Hoeft-online.de>
7 * Redistribution only with this Copyright remark. Last modified: 2025-05-16
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * - Neither name of Intel Corporation nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
29 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 **************************************************************************/
34// Last compare with pupnp original source file on 2022-11-10, ver 1.14.14
41#include <urlconfig.hpp>
42
43#include <unixutil.hpp>
44#include <upnpdebug.hpp>
45#include <uri.hpp>
46#include <webserver.hpp>
47
49#include <cassert>
50#include <cstdio>
52
53
54namespace {
55
56using compa::uriType::Absolute;
57
68inline int addrToString( //
69 const sockaddr* addr,
71 char* ipaddr_port,
73 size_t ipaddr_port_size)
74{
75 char buf_ntop[INET6_ADDRSTRLEN];
76 int rc = 0;
77
78 if (addr->sa_family == AF_INET) {
79 struct sockaddr_in* sa4 = (struct sockaddr_in*)addr;
80 inet_ntop(AF_INET, &sa4->sin_addr, buf_ntop, sizeof(buf_ntop));
81 rc = snprintf(ipaddr_port, ipaddr_port_size, "%s:%d", buf_ntop,
82 (int)ntohs(sa4->sin_port));
83 } else if (addr->sa_family == AF_INET6) {
84 struct sockaddr_in6* sa6 = (struct sockaddr_in6*)addr;
85 inet_ntop(AF_INET6, &sa6->sin6_addr, buf_ntop, sizeof(buf_ntop));
86 rc = snprintf(ipaddr_port, ipaddr_port_size, "[%s]:%d", buf_ntop,
87 (int)ntohs(sa6->sin6_port));
88 }
90 // if (rc < 0 || (unsigned int)rc >= ipaddr_port_size)
91 if (rc < 0 || (unsigned int)rc > ipaddr_port_size)
93 return UPNP_E_SUCCESS;
94}
95
105inline int calc_alias( //
106 const char* alias,
107 const char* rootPath,
108 char** newAlias
110) {
111 const char* aliasPtr;
112 size_t root_len;
113 const char* temp_str;
114 size_t new_alias_len;
115 char* alias_temp;
116
117 assert(rootPath);
118 assert(alias);
119
120 /* add / suffix, if missing */
121 root_len = strlen(rootPath);
122 if (root_len == 0 || rootPath[root_len - 1] != '/')
123 temp_str = "/";
124 else
125 temp_str = ""; /* suffix already present */
126 /* discard / prefix, if present */
127 if (alias[0] == '/')
128 aliasPtr = alias + 1;
129 else
130 aliasPtr = alias;
131 new_alias_len = root_len + strlen(temp_str) + strlen(aliasPtr) + (size_t)1;
132 alias_temp = (char*)malloc(new_alias_len);
133 if (alias_temp == nullptr)
134 return UPNP_E_OUTOF_MEMORY;
135 memset(alias_temp, 0, new_alias_len);
136 snprintf(alias_temp, new_alias_len, "%s%s%s", rootPath, temp_str, aliasPtr);
137
138 *newAlias = alias_temp;
139 return UPNP_E_SUCCESS;
140}
141
150inline int calc_descURL( //
151 const char* ipPortStr,
152 const char* alias,
153 char descURL[LINE_SIZE]
155) {
156 size_t len;
157 const char* http_scheme = "http://";
158
159 assert(ipPortStr != NULL && strlen(ipPortStr) > 0);
160 assert(alias != NULL && strlen(alias) > 0);
161
162 len = strlen(http_scheme) + strlen(ipPortStr) + strlen(alias) + (size_t)1;
163 if (len > (size_t)LINE_SIZE)
164 return UPNP_E_URL_TOO_BIG;
165 snprintf(descURL, len, "%s%s%s", http_scheme, ipPortStr, alias);
166 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "desc url: %s\n", descURL);
167
168 return UPNP_E_SUCCESS;
169}
170
186 IXML_Document* doc,
188 const char* ip_str,
191 char** root_path_str) {
192 IXML_NodeList* baseList;
193 IXML_Element* element = NULL;
194 IXML_Node* textNode = NULL;
195 IXML_Node* rootNode = NULL;
196 IXML_Node* urlbase_node = NULL;
197 const char* urlBaseStr = "URLBase";
198 const DOMString domStr = NULL;
199 uri_type uri;
200 int err_code;
201 int len;
202 membuffer url_str;
203 membuffer root_path;
204
205 membuffer_init(&url_str);
206 membuffer_init(&root_path);
207 err_code = UPNP_E_OUTOF_MEMORY; /* default error */
208 baseList = ixmlDocument_getElementsByTagName(doc, urlBaseStr);
209 if (baseList == NULL) {
210 /* urlbase not found -- create new one */
211 element = ixmlDocument_createElement(doc, urlBaseStr);
212 if (element == NULL) {
213 goto error_handler;
214 }
215 if (membuffer_append_str(&url_str, "http://") != 0 ||
216 membuffer_append_str(&url_str, ip_str) != 0 ||
217 membuffer_append_str(&url_str, "/") != 0 ||
218 membuffer_append_str(&root_path, "/") != 0) {
219 goto error_handler;
220 }
221 rootNode = ixmlNode_getFirstChild((IXML_Node*)doc);
222 if (rootNode == NULL) {
223 err_code = UPNP_E_INVALID_DESC;
224 goto error_handler;
225 }
226 err_code = ixmlNode_appendChild(rootNode, (IXML_Node*)element);
227 if (err_code != IXML_SUCCESS) {
228 err_code = UPNP_E_INVALID_DESC;
229 goto error_handler;
230 }
231 textNode = ixmlDocument_createTextNode(doc, (char*)url_str.buf);
232 if (textNode == NULL) {
233 goto error_handler;
234 }
235 err_code = ixmlNode_appendChild((IXML_Node*)element, textNode);
236 if (err_code != IXML_SUCCESS) {
237 err_code = UPNP_E_INTERNAL_ERROR;
238 goto error_handler;
239 }
240 } else {
241 /* urlbase found */
242 urlbase_node = ixmlNodeList_item(baseList, 0lu);
243 assert(urlbase_node != NULL);
244 textNode = ixmlNode_getFirstChild(urlbase_node);
245 if (textNode == NULL) {
246 err_code = UPNP_E_INVALID_DESC;
247 goto error_handler;
248 }
249 domStr = ixmlNode_getNodeValue(textNode);
250 if (domStr == NULL) {
251 err_code = UPNP_E_INVALID_URL;
252 goto error_handler;
253 }
254 len = parse_uri(domStr, strlen(domStr), &uri);
255 if (len < 0 || uri.type != Absolute) {
256 err_code = UPNP_E_INVALID_URL;
257 goto error_handler;
258 }
259 if (membuffer_assign(&url_str, uri.scheme.buff, uri.scheme.size) != 0 ||
260 membuffer_append_str(&url_str, "://") != 0 ||
261 membuffer_append_str(&url_str, ip_str) != 0) {
262 goto error_handler;
263 }
264 /* add leading '/' if missing from relative path */
265 if ((uri.pathquery.size > 0 && uri.pathquery.buff[0] != '/') ||
266 (uri.pathquery.size == 0)) {
267 if (membuffer_append_str(&url_str, "/") != 0 ||
268 membuffer_append_str(&root_path, "/") != 0) {
269 goto error_handler;
270 }
271 }
272 if (membuffer_append(&url_str, uri.pathquery.buff,
273 uri.pathquery.size) != 0 ||
274 membuffer_append(&root_path, uri.pathquery.buff,
275 uri.pathquery.size) != 0) {
276 goto error_handler;
277 }
278 /* add trailing '/' if missing */
279 if (url_str.buf[url_str.length - 1] != '/') {
280 if (membuffer_append(&url_str, "/", (size_t)1) != 0) {
281 goto error_handler;
282 }
283 }
284 err_code = ixmlNode_setNodeValue(textNode, url_str.buf);
285 if (err_code != IXML_SUCCESS) {
286 err_code = UPNP_E_OUTOF_MEMORY;
287 goto error_handler;
288 }
289 }
290 *root_path_str = membuffer_detach(&root_path); /* return path */
291 err_code = UPNP_E_SUCCESS;
292
293error_handler:
294 if (err_code != UPNP_E_SUCCESS) {
295 ixmlElement_free(element);
296 }
297 ixmlNodeList_free(baseList);
298 membuffer_destroy(&root_path);
299 membuffer_destroy(&url_str);
300
301 return err_code;
302}
303
305} // anonymous namespace
306
307int configure_urlbase(IXML_Document* doc, const sockaddr* serverAddr,
308 const char* alias, time_t last_modified,
309 char docURL[LINE_SIZE]) {
310 char* root_path = NULL;
311 char* new_alias = NULL;
312 char* xml_str = NULL;
313 int err_code;
314 char ipaddr_port[LINE_SIZE];
315
316 /* get IP address and port */
317 err_code = addrToString(serverAddr, ipaddr_port, sizeof(ipaddr_port));
318 if (err_code != UPNP_E_SUCCESS) {
319 goto error_handler;
320 }
321
322 /* config url-base in 'doc' */
323 err_code = config_description_doc(doc, ipaddr_port, &root_path);
324 if (err_code != UPNP_E_SUCCESS) {
325 goto error_handler;
326 }
327 /* calc alias */
328 err_code = calc_alias(alias, root_path, &new_alias);
329 if (err_code != UPNP_E_SUCCESS) {
330 goto error_handler;
331 }
332 /* calc full url for desc doc */
333 err_code = calc_descURL(ipaddr_port, new_alias, docURL);
334 if (err_code != UPNP_E_SUCCESS) {
335 goto error_handler;
336 }
337 /* xml doc to str */
338 xml_str = ixmlPrintDocument(doc);
339 if (xml_str == NULL) {
340 goto error_handler;
341 }
342
343 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "desc url: %s\n", docURL);
344 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "doc = %s\n", xml_str);
345 /* store in web server */
346 err_code = web_server_set_alias(new_alias, xml_str, strlen(xml_str),
347 last_modified);
348
349error_handler:
350 free(root_path);
351 free(new_alias);
352
353 if (err_code != UPNP_E_SUCCESS) {
354 ixmlFreeDOMString(xml_str);
355 }
356 return err_code;
357}
#define LINE_SIZE
Definition API.hpp:45
#define UPNP_E_BUFFER_TOO_SMALL
The operation completed successfully.
Definition API.hpp:115
int web_server_set_alias(const char *a_alias_name, const char *a_alias_content, size_t a_alias_content_length, time_t a_last_modified)
Replaces current alias with the given alias.
token scheme
Member variable.
Definition uri.hpp:96
size_t size
Size of the buffer.
Definition uri.hpp:78
compa::uriType type
Member variable.
Definition uri.hpp:95
const char * buff
Buffer.
Definition uri.hpp:77
token pathquery
Member variable.
Definition uri.hpp:98
Represents a URI used in parse_uri and elsewhere.
Definition uri.hpp:92
Data structure common to all types of nodes.
Definition ixml.hpp:132
Data structure representing a list of nodes.
Definition ixml.hpp:193
Data structure representing an Element node.
Definition ixml.hpp:169
Data structure representing the DOM Document.
Definition ixml.hpp:155
PUPNP_Api int ixmlNode_appendChild(IXML_Node *nodeptr, IXML_Node *newChild)
Appends a child Node to the list of children of a Node.
Definition node.cpp:611
PUPNP_Api int ixmlNode_setNodeValue(IXML_Node *nodeptr, const char *newNodeValue)
Assigns a new value to a Node.
Definition node.cpp:304
PUPNP_Api IXML_Element * ixmlDocument_createElement(IXML_Document *doc, const DOMString tagName)
Creates a new Element node with the given tag name.
Definition document.cpp:141
#define DOMString
The type of DOM strings.
Definition ixml.hpp:47
PUPNP_Api IXML_Node * ixmlDocument_createTextNode(IXML_Document *doc, const DOMString data)
Creates a new Text node with the given data.
Definition document.cpp:237
PUPNP_Api const DOMString ixmlNode_getNodeValue(IXML_Node *nodeptr)
Returns the value of the Node as a string.
Definition node.cpp:296
PUPNP_Api IXML_NodeList * ixmlDocument_getElementsByTagName(IXML_Document *doc, const DOMString tagName)
Returns a NodeList of all Elements that match the given tag name in the order in which they were enco...
Definition document.cpp:452
PUPNP_Api DOMString ixmlPrintDocument(IXML_Document *doc)
Renders a Node and all sub-elements into an XML document representation.
Definition ixml.cpp:322
PUPNP_Api void ixmlFreeDOMString(DOMString buf)
Frees a DOMString.
Definition ixml.cpp:418
PUPNP_Api void ixmlNodeList_free(IXML_NodeList *nList)
Frees a NodeList object.
Definition nodeList.cpp:129
PUPNP_Api void ixmlElement_free(IXML_Element *element)
Frees the given Element and any subtree of the Element.
Definition element.cpp:654
PUPNP_Api IXML_Node * ixmlNode_getFirstChild(IXML_Node *nodeptr)
Retrieves the first child Node of a Node.
Definition node.cpp:342
PUPNP_Api IXML_Node * ixmlNodeList_item(IXML_NodeList *nList, unsigned long index)
Retrieves a Node from a NodeList specified by a numerical index.
Definition nodeList.cpp:49
void membuffer_destroy(membuffer *m)
Free's memory allocated for membuffer* m.
void membuffer_init(membuffer *m)
Wrapper to membuffer_initialize().
int membuffer_append(membuffer *m, const void *buf, size_t buf_len)
Invokes function to appends data from a constant buffer to the buffer.
char * membuffer_detach(membuffer *m)
Detaches current buffer and returns it. The caller must free the returned buffer using free()....
int membuffer_append_str(membuffer *m, const char *c_str)
Invokes function to appends data from a constant string to the buffer.
int membuffer_assign(membuffer *m, const void *buf, size_t buf_len)
Allocate memory to membuffer *m and copy the contents of the in parameter const void *buf.
size_t length
length of buffer without terminating null byte (read-only).
Definition membuffer.hpp:65
char * buf
mem buffer; must not write beyond buf[length-1] (read/write).
Definition membuffer.hpp:63
Maintains a block of dynamically allocated memory.
Definition membuffer.hpp:61
#define UPNP_E_SUCCESS
The operation completed successfully.
Definition messages.hpp:27
#define UPNP_E_OUTOF_MEMORY
Not enough resources are currently available to complete the operation.
Definition messages.hpp:57
#define UPNP_E_INVALID_URL
An URL passed into the function is invalid.
Definition messages.hpp:83
#define UPNP_E_INVALID_DESC
The description document passed to UpnpRegisterRootDevice, UpnpRegisterRootDevice2 UpnpRegisterRootDe...
Definition messages.hpp:74
#define UPNP_E_URL_TOO_BIG
The URL passed into a function is too long.
Definition messages.hpp:135
#define UPNP_E_INTERNAL_ERROR
Generic error code for internal conditions not covered by other error codes.
Definition messages.hpp:319
int config_description_doc(IXML_Document *doc, const char *ip_str, char **root_path_str)
Configure the description document.
int calc_descURL(const char *ipPortStr, const char *alias, char descURL[LINE_SIZE])
Determines the description URL.
int addrToString(const sockaddr *addr, char *ipaddr_port, size_t ipaddr_port_size)
Converts an Internet address to a string and stores it in a buffer.
Definition urlconfig.cpp:68
int calc_alias(const char *alias, const char *rootPath, char **newAlias)
Determine alias based urlbase's root path.
Unix-specific network utilities.
Manage Debug messages with levels "critical" to "all".
UPnPsdk_VIS void UpnpPrintf(Upnp_LogLevel DLevel, Dbg_Module Module, const char *DbgFileName, int DbgLineNo, const char *FmtStr,...)
Prints the debug statement.
int parse_uri(const char *in, size_t max, uri_type *out)
Parses a uri as defined in RFC 2396 (explaining URIs).
Definition uri.cpp:733
int configure_urlbase(IXML_Document *doc, const sockaddr *serverAddr, const char *alias, time_t last_modified, char docURL[LINE_SIZE])
Configure the full URL for the description document.
Configure the full URL for the description document.