pupnp (libupnp) snapshot from SourceForge: git clone git://pupnp.git.sourceforge...
[igd2-for-linux:pandonghui1211s-igd2-for-linux.git] / pupnp_branch-1.6.x / upnp / src / urlconfig / urlconfig.c
1 /**************************************************************************
2  *
3  * Copyright (c) 2000-2003 Intel Corporation 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions are met: 
8  *
9  * - Redistributions of source code must retain the above copyright notice, 
10  * this list of conditions and the following disclaimer. 
11  * - Redistributions in binary form must reproduce the above copyright notice, 
12  * this list of conditions and the following disclaimer in the documentation 
13  * and/or other materials provided with the distribution. 
14  * - Neither name of Intel Corporation nor the names of its contributors 
15  * may be used to endorse or promote products derived from this software 
16  * without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  **************************************************************************/
31
32
33 #include "config.h"
34
35
36 #include "membuffer.h"
37 #include "unixutil.h"
38 #include "upnp.h"
39 #include "upnpdebug.h"
40 #include "UpnpInet.h"
41 #include "uri.h"
42 #include "urlconfig.h"
43 #include "util.h"
44 #include "webserver.h"
45
46
47 #include <assert.h>
48 #include <stdio.h>
49
50
51 #ifdef WIN32
52 #else
53         #include <arpa/inet.h>
54         #include <sys/types.h>
55         #include <sys/socket.h>
56 #endif
57
58
59 /************************************************************************
60 *       Function :      addrToString
61 *
62 *       Parameters :
63 *               IN const struct sockaddr_in* addr ;     socket address object with 
64 *                                       the IP Address and port information
65 *               OUT char ipaddr_port[] ;        character array which will hold the 
66 *                                       IP Address  in a string format.
67 *
68 *       Description : Converts an Internet address to a string and stores it 
69 *               a buffer.
70 *
71 *       Return : void ;
72 *
73 *       Note :
74 ************************************************************************/
75 static UPNP_INLINE void
76 addrToString( IN const struct sockaddr_in *addr,
77               OUT char ipaddr_port[] )
78 {
79     sprintf( ipaddr_port, "%s:%d", inet_ntoa( addr->sin_addr ),
80              ntohs( addr->sin_port ) );
81 }
82
83 /************************************************************************
84 *       Function :      calc_alias
85 *
86 *       Parameters :
87 *               IN const char* alias ;  String containing the alias
88 *               IN const char* rootPath ;       String containing the root path
89 *               OUT char** newAlias ;   String pointer to hold the modified new
90 *                                       alias
91 *
92 *       Description : Determine alias based urlbase's root path.
93 *
94 *       Return : int ;
95 *               UPNP_E_SUCCESS - On Success.
96 *               UPNP_E_OUTOF_MEMORY - On Failure to allocate memory for new alias
97 *
98 *       Note : 'newAlias' should be freed using free()
99 ************************************************************************/
100 static UPNP_INLINE int
101 calc_alias( IN const char *alias,
102             IN const char *rootPath,
103             OUT char **newAlias )
104 {
105     const char *aliasPtr;
106     size_t root_len;
107     char *temp_str;
108     size_t new_alias_len;
109     char *alias_temp;
110
111     assert( rootPath );
112     assert( alias );
113
114     // add / suffix, if missing
115     root_len = strlen( rootPath );
116     if( root_len == 0 || rootPath[root_len - 1] != '/' ) {
117         temp_str = "/";
118     } else {
119         temp_str = "";          // suffix already present
120     }
121
122     // discard / prefix, if present
123     if( alias[0] == '/' ) {
124         aliasPtr = alias + 1;
125     } else {
126         aliasPtr = alias;
127     }
128
129     new_alias_len = root_len + strlen( temp_str ) + strlen( aliasPtr );
130     alias_temp = ( char * )malloc( new_alias_len + 1 );
131     if( alias_temp == NULL ) {
132         return UPNP_E_OUTOF_MEMORY;
133     }
134
135     strcpy( alias_temp, rootPath );
136     strcat( alias_temp, temp_str );
137     strcat( alias_temp, aliasPtr );
138
139     *newAlias = alias_temp;
140     return UPNP_E_SUCCESS;
141 }
142
143 /************************************************************************
144 *       Function :      calc_descURL
145 *
146 *       Parameters :
147 *               IN const char* ipPortStr ;      String containing the port number
148 *               IN const char* alias ;          String containing the alias
149 *               OUT char descURL[LINE_SIZE] ;   buffer to hold the calculated 
150 *                                       description URL
151 *
152 *       Description : Determines the description URL
153 *
154 *       Return : int ;
155 *               UPNP_E_SUCCESS - On Success
156 *               UPNP_E_URL_TOO_BIG - length of the URL is determined to be to
157 *               exceeding the limit.
158 *
159 *       Note :
160 ************************************************************************/
161 static UPNP_INLINE int
162 calc_descURL( IN const char *ipPortStr,
163               IN const char *alias,
164               OUT char descURL[LINE_SIZE] )
165 {
166     size_t len;
167     const char *http_scheme = "http://";
168
169     assert( ipPortStr != NULL && strlen( ipPortStr ) > 0 );
170     assert( alias != NULL && strlen( alias ) > 0 );
171
172     len = strlen( http_scheme ) + strlen( ipPortStr ) + strlen( alias );
173
174     if( len > ( LINE_SIZE - 1 ) ) {
175         return UPNP_E_URL_TOO_BIG;
176     }
177     strcpy( descURL, http_scheme );
178     strcat( descURL, ipPortStr );
179     strcat( descURL, alias );
180
181     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
182         "desc url: %s\n", descURL );
183
184     return UPNP_E_SUCCESS;
185 }
186
187 /************************************************************************
188 *       Function :      config_description_doc
189 *
190 *       Parameters :
191 *               INOUT IXML_Document *doc ;IMXL description document to be 
192 *                                       configured      
193 *               IN const char* ip_str ; string containing the IP port number
194 *               OUT char** root_path_str ;      buffer to hold the root path
195 *                                       of the configured description document
196 *               INOUT IXML_Document *doc :      Description document
197 *               IN const char* ip_str : ipaddress string
198 *               OUT char** root_path_str :      root path string
199 *
200 *       Description : Configure the description document. Add the standard 
201 *               format and then add information from the root device and any
202 *               child nodes.
203 *
204 *       Return : int ;
205 *               UPNP_E_SUCCESS - On Success
206 *               UPNP_E_OUTOF_MEMORY - Default Error
207 *               UPNP_E_INVALID_DESC - Invalid child node                
208 *               UPNP_E_INVALID_URL - Invalid node information
209 *
210 *       Note :
211 ************************************************************************/
212 static int
213 config_description_doc( INOUT IXML_Document * doc,
214                         IN const char *ip_str,
215                         OUT char **root_path_str )
216 {
217     xboolean addNew = FALSE;
218     IXML_NodeList *baseList;
219     IXML_Element *element = NULL;
220     IXML_Element *newElement = NULL;
221     IXML_Node *textNode = NULL;
222     IXML_Node *rootNode = NULL;
223     IXML_Node *urlbase_node = NULL;
224     char *urlBaseStr = "URLBase";
225     const DOMString domStr = NULL;
226     uri_type uri;
227     int err_code;
228     int len;
229     membuffer url_str;
230     membuffer root_path;
231
232     membuffer_init( &url_str );
233     membuffer_init( &root_path );
234
235     err_code = UPNP_E_OUTOF_MEMORY; // default error
236
237     baseList = ixmlDocument_getElementsByTagName( doc, urlBaseStr );
238     if( baseList == NULL ) {
239         // urlbase not found -- create new one
240         addNew = TRUE;
241         element = ixmlDocument_createElement( doc, urlBaseStr );
242         if( element == NULL ) {
243             goto error_handler;
244         }
245
246         if( membuffer_append_str( &url_str, "http://" ) != 0 ||
247             membuffer_append_str( &url_str, ip_str ) != 0 ||
248             membuffer_append_str( &url_str, "/" ) != 0 ||
249             membuffer_append_str( &root_path, "/" ) != 0 ) {
250             goto error_handler;
251         }
252
253         rootNode = ixmlNode_getFirstChild( ( IXML_Node * ) doc );
254         if( rootNode == NULL ) {
255             err_code = UPNP_E_INVALID_DESC;
256             goto error_handler;
257         }
258
259         err_code =
260             ixmlNode_appendChild( rootNode, ( IXML_Node * ) element );
261         if( err_code != IXML_SUCCESS ) {
262             goto error_handler;
263         }
264
265         textNode =
266             ixmlDocument_createTextNode( doc, ( char * )url_str.buf );
267         if( textNode == NULL ) {
268             goto error_handler;
269         }
270
271         err_code =
272             ixmlNode_appendChild( ( IXML_Node * ) element, textNode );
273         if( err_code != IXML_SUCCESS ) {
274             goto error_handler;
275         }
276
277     } else {
278         // urlbase found
279         urlbase_node = ixmlNodeList_item( baseList, 0 );
280         assert( urlbase_node != NULL );
281
282         textNode = ixmlNode_getFirstChild( urlbase_node );
283         if( textNode == NULL ) {
284             err_code = UPNP_E_INVALID_DESC;
285             goto error_handler;
286         }
287
288         domStr = ixmlNode_getNodeValue( textNode );
289         if( domStr == NULL ) {
290             err_code = UPNP_E_INVALID_URL;
291             goto error_handler;
292         }
293
294         len = parse_uri( domStr, strlen( domStr ), &uri );
295         if( len < 0 || uri.type != ABSOLUTE ) {
296             err_code = UPNP_E_INVALID_URL;
297             goto error_handler;
298         }
299
300         if( membuffer_assign( &url_str, uri.scheme.buff,
301                               uri.scheme.size ) != 0 ||
302             membuffer_append_str( &url_str, "://" ) != 0 ||
303             membuffer_append_str( &url_str, ip_str ) != 0 ) {
304             goto error_handler;
305         }
306         // add leading '/' if missing from relative path
307         if( ( uri.pathquery.size > 0 && uri.pathquery.buff[0] != '/' ) ||
308             ( uri.pathquery.size == 0 )
309              ) {
310             if( membuffer_append_str( &url_str, "/" ) != 0 ||
311                 membuffer_append_str( &root_path, "/" ) != 0 ) {
312                 goto error_handler;
313             }
314         }
315
316         if( membuffer_append( &url_str, uri.pathquery.buff,
317                               uri.pathquery.size ) != 0 ||
318             membuffer_append( &root_path, uri.pathquery.buff,
319                               uri.pathquery.size ) != 0 ) {
320             goto error_handler;
321         }
322         // add trailing '/' if missing
323         if( url_str.buf[url_str.length - 1] != '/' ) {
324             if( membuffer_append( &url_str, "/", 1 ) != 0 ) {
325                 goto error_handler;
326             }
327         }
328
329         err_code = ixmlNode_setNodeValue( textNode, url_str.buf );
330         if( err_code != IXML_SUCCESS ) {
331             goto error_handler;
332         }
333     }
334
335     *root_path_str = membuffer_detach( &root_path );    // return path
336     err_code = UPNP_E_SUCCESS;
337
338   error_handler:
339     if( err_code != UPNP_E_SUCCESS ) {
340         ixmlElement_free( newElement );
341     }
342
343     ixmlNodeList_free( baseList );
344
345     membuffer_destroy( &root_path );
346     membuffer_destroy( &url_str );
347
348     return err_code;
349 }
350
351 /************************************************************************
352 *       Function :      configure_urlbase
353 *
354 *       Parameters :
355 *               INOUT IXML_Document *doc ;      IXML Description document
356 *               IN const struct sockaddr_in* serverAddr ;       socket address object
357 *                                       providing the IP address and port information
358 *               IN const char* alias ;  string containing the alias
359 *               IN time_t last_modified ;       time when the XML document was 
360 *                                       downloaded
361 *               OUT char docURL[LINE_SIZE] ;    buffer to hold the URL of the 
362 *                                       document.
363 *               INOUT IXML_Document *doc:dom document whose urlbase is to be modified
364 *               IN const struct sockaddr_in* serverAddr : ip address and port of 
365 *                                                                                                       the miniserver
366 *               IN const char* alias : a name to be used for the temp; e.g.:"foo.xml"
367 *               IN time_t last_modified :       time
368 *               OUT char docURL[LINE_SIZE] :    document URL
369 *
370 *       Description : Configure the full URL for the description document.
371 *               Create the URL document and add alias, description information.
372 *               The doc is added to the web server to be served using the given 
373 *               alias.
374 *
375 *       Return : int ;
376 *               UPNP_E_SUCCESS - On Success
377 *               UPNP_E_OUTOF_MEMORY - Default Error
378 *
379 *       Note :
380 ************************************************************************/
381 int
382 configure_urlbase( INOUT IXML_Document * doc,
383                    IN const struct sockaddr_in *serverAddr,
384                    IN const char *alias,
385                    IN time_t last_modified,
386                    OUT char docURL[LINE_SIZE] )
387 {
388     char *root_path = NULL;
389     char *new_alias = NULL;
390     char *xml_str = NULL;
391     int err_code;
392     char ipaddr_port[LINE_SIZE];
393
394     err_code = UPNP_E_OUTOF_MEMORY; // default error
395
396     // get IP address and port
397     addrToString( serverAddr, ipaddr_port );
398
399     // config url-base in 'doc'
400     err_code = config_description_doc( doc, ipaddr_port, &root_path );
401     if( err_code != UPNP_E_SUCCESS ) {
402         goto error_handler;
403     }
404     // calc alias
405     err_code = calc_alias( alias, root_path, &new_alias );
406     if( err_code != UPNP_E_SUCCESS ) {
407         goto error_handler;
408     }
409     // calc full url for desc doc
410     err_code = calc_descURL( ipaddr_port, new_alias, docURL );
411     if( err_code != UPNP_E_SUCCESS ) {
412         goto error_handler;
413     }
414     // xml doc to str
415     xml_str = ixmlPrintDocument( doc );
416     if( xml_str == NULL ) {
417         goto error_handler;
418     }
419
420     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
421         "desc url: %s\n", docURL );
422     UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
423         "doc = %s\n", xml_str );
424     // store in web server
425     err_code =
426         web_server_set_alias( new_alias, xml_str, strlen( xml_str ),
427                               last_modified );
428
429 error_handler:
430     free( root_path );
431     free( new_alias );
432
433     if( err_code != UPNP_E_SUCCESS ) {
434         ixmlFreeDOMString( xml_str );
435     }
436     return err_code;
437 }