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#ifdef INCLUDE_DEVICE_APIS 33#if EXCLUDE_SOAP == 0 34 35#define SOAP_BODY "Body" 36#define SOAP_URN "http://schemas.xmlsoap.org/soap/envelope/" 37 38#define QUERY_STATE_VAR_URN "urn:schemas-upnp-org:control-1-0" 39 40#include "config.h" 41#include "upnpapi.h" 42#include "parsetools.h" 43#include "statcodes.h" 44#include "httpparser.h" 45#include "httpreadwrite.h" 46#include "unixutil.h" 47 48// timeout duration in secs for transmission/reception 49#define SOAP_TIMEOUT UPNP_TIMEOUT 50 51#define SREQ_HDR_NOT_FOUND -1 52#define SREQ_BAD_HDR_FORMAT -2 53 54#define SOAP_INVALID_ACTION 401 55#define SOAP_INVALID_ARGS 402 56#define SOAP_OUT_OF_SYNC 403 57#define SOAP_INVALID_VAR 404 58#define SOAP_ACTION_FAILED 501 59 60static const char *Soap_Invalid_Action = "Invalid Action"; 61 62//static const char* Soap_Invalid_Args = "Invalid Args"; 63static const char *Soap_Action_Failed = "Action Failed"; 64static const char *Soap_Invalid_Var = "Invalid Var"; 65 66const char *ContentTypeHeader = 67 "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"; 68 69/**************************************************************************** 70* Function : get_request_type 71* 72* Parameters : 73* IN http_message_t* request : HTTP request 74* OUT memptr* action_name : SOAP action name 75* 76* Description : This function retrives the name of the SOAP action 77* 78* Return : int 79* 0 if successful else returns appropriate error. 80* Note : 81****************************************************************************/ 82static XINLINE int 83get_request_type( IN http_message_t * request, 84 OUT memptr * action_name ) 85{ 86 memptr value; 87 memptr ns_value, 88 dummy_quote; 89 http_header_t *hdr; 90 char save_char; 91 char *s; 92 membuffer soap_action_name; 93 94 // find soapaction header 95 // 96 if( request->method == SOAPMETHOD_POST ) { 97 if( httpmsg_find_hdr( request, HDR_SOAPACTION, &value ) 98 == NULL ) { 99 return SREQ_HDR_NOT_FOUND; 100 } 101 } else // M-POST 102 { 103 // get NS value from MAN header 104 hdr = httpmsg_find_hdr( request, HDR_MAN, &value ); 105 if( hdr == NULL ) { 106 return SREQ_HDR_NOT_FOUND; 107 } 108 109 if( matchstr( value.buf, value.length, "%q%i ; ns = %s", 110 &dummy_quote, &ns_value ) != 0 ) { 111 return SREQ_BAD_HDR_FORMAT; 112 } 113 // create soapaction name header 114 membuffer_init( &soap_action_name ); 115 if( ( membuffer_assign( &soap_action_name, 116 ns_value.buf, ns_value.length ) 117 == UPNP_E_OUTOF_MEMORY ) || 118 ( membuffer_append_str( &soap_action_name, 119 "-SOAPACTION" ) == 120 UPNP_E_OUTOF_MEMORY ) 121 ) { 122 membuffer_destroy( &soap_action_name ); 123 return UPNP_E_OUTOF_MEMORY; 124 } 125 126 hdr = httpmsg_find_hdr_str( request, soap_action_name.buf ); 127 membuffer_destroy( &soap_action_name ); 128 if( hdr == NULL ) { 129 return SREQ_HDR_NOT_FOUND; 130 } 131 132 value.buf = hdr->value.buf; 133 value.length = hdr->value.length; 134 } 135 136 // determine type 137 // 138 save_char = value.buf[value.length]; 139 value.buf[value.length] = '\0'; 140 141 s = strchr( value.buf, '#' ); 142 if( s == NULL ) { 143 value.buf[value.length] = save_char; 144 return SREQ_BAD_HDR_FORMAT; 145 } 146 147 s++; // move to value 148 149 if( matchstr( s, value.length - ( s - value.buf ), "%s", 150 action_name ) != PARSE_OK ) { 151 value.buf[value.length] = save_char; 152 return SREQ_BAD_HDR_FORMAT; 153 } 154 // action name or variable ? 155 if( memptr_cmp( action_name, "QueryStateVariable" ) == 0 ) { 156 // query variable 157 action_name->buf = NULL; 158 action_name->length = 0; 159 } 160 161 value.buf[value.length] = save_char; // restore 162 return 0; 163} 164 165/**************************************************************************** 166* Function : send_error_response 167* 168* Parameters : 169* IN SOCKINFO *info : socket info 170* IN int error_code : error code 171* IN const char* err_msg : error message 172* IN http_message_t* hmsg : HTTP request 173* 174* Description : This function sends SOAP error response 175* 176* Return : void 177* 178* Note : 179****************************************************************************/ 180static void 181send_error_response( IN SOCKINFO * info, 182 IN int error_code, 183 IN const char *err_msg, 184 IN http_message_t * hmsg ) 185{ 186 int content_length; 187 int timeout_secs = SOAP_TIMEOUT; 188 int major, 189 minor; 190 const char *start_body = 191 "<s:Envelope\n" 192 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" 193 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" 194 "<s:Body>\n" 195 "<s:Fault>\n" 196 "<faultcode>s:Client</faultcode>\n" 197 "<faultstring>UPnPError</faultstring>\n" 198 "<detail>\n" 199 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n" 200 "<errorCode>"; 201 202 const char *mid_body = "</errorCode>\n" "<errorDescription>"; 203 204 const char *end_body = 205 "</errorDescription>\n" 206 "</UPnPError>\n" 207 "</detail>\n" "</s:Fault>\n" "</s:Body>\n" "</s:Envelope>\n"; 208 209 char err_code_str[30]; 210 211 membuffer headers; 212 213 sprintf( err_code_str, "%d", error_code ); 214 215 // calc body len 216 content_length = strlen( start_body ) + strlen( err_code_str ) + 217 strlen( mid_body ) + strlen( err_msg ) + strlen( end_body ); 218 219 http_CalcResponseVersion( hmsg->major_version, hmsg->minor_version, 220 &major, &minor ); 221 222 // make headers 223 membuffer_init( &headers ); 224 if( http_MakeMessage( &headers, major, minor, 225 "RNsDsSc" "sssss", 226 500, 227 content_length, 228 ContentTypeHeader, 229 "EXT:\r\n", 230 start_body, err_code_str, mid_body, err_msg, 231 end_body ) != 0 ) { 232 membuffer_destroy( &headers ); 233 return; // out of mem 234 } 235 // send err msg 236 http_SendMessage( info, &timeout_secs, "b", 237 headers.buf, headers.length ); 238 239 membuffer_destroy( &headers ); 240} 241 242/**************************************************************************** 243* Function : send_var_query_response 244* 245* Parameters : 246* IN SOCKINFO *info : socket info 247* IN const char* var_value : value of the state variable 248* IN http_message_t* hmsg : HTTP request 249* 250* Description : This function sends response of get var status 251* 252* Return : void 253* 254* Note : 255****************************************************************************/ 256static XINLINE void 257send_var_query_response( IN SOCKINFO * info, 258 IN const char *var_value, 259 IN http_message_t * hmsg ) 260{ 261 int content_length; 262 int timeout_secs = SOAP_TIMEOUT; 263 int major, 264 minor; 265 const char *start_body = 266 "<s:Envelope\n" 267 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" 268 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" 269 "<s:Body>\n" 270 "<u:QueryStateVariableResponse " 271 "xmlns:u=\"urn:schemas-upnp-org:control-1-0\">\n" "<return>"; 272 273 const char *end_body = 274 "</return>\n" 275 "</u:QueryStateVariableResponse>\n" 276 "</s:Body>\n" "</s:Envelope>\n"; 277 278 membuffer response; 279 280 http_CalcResponseVersion( hmsg->major_version, hmsg->minor_version, 281 &major, &minor ); 282 283 content_length = strlen( start_body ) + strlen( var_value ) + 284 strlen( end_body ); 285 286 // make headers 287 membuffer_init( &response ); 288 if( http_MakeMessage( &response, major, minor, 289 "RNsDsSc" "sss", 290 HTTP_OK, 291 content_length, 292 ContentTypeHeader, 293 "EXT:\r\n", 294 start_body, var_value, end_body ) != 0 ) { 295 membuffer_destroy( &response ); 296 return; // out of mem 297 } 298 // send msg 299 http_SendMessage( info, &timeout_secs, "b", 300 response.buf, response.length ); 301 302 membuffer_destroy( &response ); 303} 304 305/**************************************************************************** 306* Function : get_action_node 307* 308* Parameters : 309* IN IXML_Document *TempDoc : The root DOM node. 310* IN char *NodeName : IXML_Node name to be searched. 311* OUT IXML_Document ** RespNode : Response/Output node. 312* 313* Description : This function separates the action node from 314* the root DOM node. 315* 316* Return : static XINLINE int 317* 0 if successful, or -1 if fails. 318* 319* Note : 320****************************************************************************/ 321static XINLINE int 322get_action_node( IN IXML_Document * TempDoc, 323 IN char *NodeName, 324 OUT IXML_Document ** RespNode ) 325{ 326 IXML_Node *EnvpNode = NULL; 327 IXML_Node *BodyNode = NULL; 328 IXML_Node *ActNode = NULL; 329 DOMString ActNodeName = NULL; 330 const DOMString nodeName; 331 int ret_code = -1; // error, by default 332 IXML_NodeList *nl = NULL; 333 334 DBGONLY( UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, 335 "get_action_node(): node name =%s\n ", NodeName ); 336 ) 337 338 * RespNode = NULL; 339 340 // Got the Envelope node here 341 EnvpNode = ixmlNode_getFirstChild( ( IXML_Node * ) TempDoc ); 342 if( EnvpNode == NULL ) { 343 goto error_handler; 344 } 345 346 nl = ixmlElement_getElementsByTagNameNS( ( IXML_Element * ) EnvpNode, 347 "*", "Body" ); 348 349 if( nl == NULL ) { 350 goto error_handler; 351 } 352 353 BodyNode = ixmlNodeList_item( nl, 0 ); 354 355 if( BodyNode == NULL ) { 356 goto error_handler; 357 } 358 // Got action node here 359 ActNode = ixmlNode_getFirstChild( BodyNode ); 360 if( ActNode == NULL ) { 361 goto error_handler; 362 } 363 //Test whether this is the action node 364 nodeName = ixmlNode_getNodeName( ActNode ); 365 if( nodeName == NULL ) { 366 goto error_handler; 367 } 368 369 if( strstr( nodeName, NodeName ) == NULL ) { 370 goto error_handler; 371 } else { 372 ActNodeName = ixmlPrintDocument( ActNode ); 373 if( ActNodeName == NULL ) { 374 goto error_handler; 375 } 376 377 ret_code = ixmlParseBufferEx( ActNodeName, RespNode ); 378 if( ret_code != IXML_SUCCESS ) { 379 ixmlFreeDOMString( ActNodeName ); 380 ret_code = -1; 381 goto error_handler; 382 } 383 } 384 385 ret_code = 0; // success 386 387 error_handler: 388 389 ixmlFreeDOMString( ActNodeName ); 390 391 if( nl ) 392 ixmlNodeList_free( nl ); 393 return ret_code; 394} 395 396/**************************************************************************** 397* Function : check_soap_body 398* 399* Parameters : 400* IN IXML_Document *doc : soap body xml document 401* IN const char *urn : 402* IN const char *actionName : Name of the requested action 403* 404* Description : This function checks the soap body xml came in the 405* SOAP request. 406* 407* Return : int 408* UPNP_E_SUCCESS if successful else returns appropriate error 409* 410* Note : 411****************************************************************************/ 412static int 413check_soap_body( IN IXML_Document * doc, 414 IN const char *urn, 415 IN const char *actionName ) 416{ 417 IXML_NodeList *nl = NULL; 418 IXML_Node *bodyNode = NULL; 419 IXML_Node *actionNode = NULL; 420 const DOMString ns = NULL; 421 const DOMString name = NULL; 422 423 int ret_code = UPNP_E_INVALID_ACTION; 424 425 nl = ixmlDocument_getElementsByTagNameNS( doc, SOAP_URN, SOAP_BODY ); 426 427 if( nl ) { 428 bodyNode = ixmlNodeList_item( nl, 0 ); 429 if( bodyNode ) { 430 actionNode = ixmlNode_getFirstChild( bodyNode ); 431 if( actionNode ) { 432 ns = ixmlNode_getNamespaceURI( actionNode ); 433 name = ixmlNode_getLocalName( actionNode ); 434 435 if( ( !strcmp( actionName, name ) ) 436 && ( !strcmp( urn, ns ) ) ) { 437 ret_code = UPNP_E_SUCCESS; 438 } 439 } 440 } 441 ixmlNodeList_free( nl ); 442 } 443 return ret_code; 444 445} 446 447/**************************************************************************** 448* Function : check_soap_action_header 449* 450* Parameters : 451* IN http_message_t *request : HTTP request 452* IN const char *urn : 453* OUT char **actionName : name of the SOAP action 454* 455* Description : This function checks the HTTP header of the SOAP request 456* coming from the control point 457* 458* Return : static int 459* UPNP_E_SUCCESS if successful else returns appropriate error 460* 461* Note : 462****************************************************************************/ 463static int 464check_soap_action_header( IN http_message_t * request, 465 IN const char *urn, 466 OUT char **actionName ) 467{ 468 memptr header_name; 469 http_header_t *soap_action_header = NULL; 470 char *ns_compare = NULL; 471 int tempSize = 0; 472 int ret_code = UPNP_E_SUCCESS; 473 char *temp_header_value = NULL; 474 char *temp = NULL; 475 char *temp2 = NULL; 476 477 //check soap action header 478 479 soap_action_header = httpmsg_find_hdr( request, HDR_SOAPACTION, 480 &header_name ); 481 482 if( !soap_action_header ) { 483 ret_code = UPNP_E_INVALID_ACTION; 484 return ret_code; 485 } 486 487 if( soap_action_header->value.length <= 0 ) { 488 ret_code = UPNP_E_INVALID_ACTION; 489 return ret_code; 490 } 491 492 temp_header_value = 493 ( char * )malloc( soap_action_header->value.length + 1 ); 494 495 if( !temp_header_value ) { 496 ret_code = UPNP_E_OUTOF_MEMORY; 497 return ret_code; 498 } 499 500 strncpy( temp_header_value, soap_action_header->value.buf, 501 soap_action_header->value.length ); 502 temp_header_value[soap_action_header->value.length] = 0; 503 504 temp = strchr( temp_header_value, '#' ); 505 if( !temp ) { 506 free( temp_header_value ); 507 ret_code = UPNP_E_INVALID_ACTION; 508 return ret_code; 509 } 510 511 ( *temp ) = 0; //temp make string 512 513 //check to see if it is Query State Variable or 514 //Service Action 515 516 tempSize = strlen( urn ) + 2; 517 518 ns_compare = ( char * )malloc( tempSize ); 519 520 if( !ns_compare ) { 521 ret_code = UPNP_E_OUTOF_MEMORY; 522 free( temp_header_value ); 523 return ret_code; 524 } 525 526// snprintf( ns_compare, tempSize, "\"%s", urn ); Shearer 527 if (temp_header_value[0] == '\"') 528 snprintf( ns_compare, tempSize, "\"%s", urn ); 529 else 530 snprintf(ns_compare, tempSize, "%s", urn); 531 532 if( strcmp( temp_header_value, ns_compare ) ) { 533 ret_code = UPNP_E_INVALID_ACTION; 534 } else { 535 ret_code = UPNP_E_SUCCESS; 536 temp++; 537 temp2 = strchr( temp, '\"' ); 538 539 if( temp2 ) //remove ending " if present 540 { 541 ( *temp2 ) = 0; 542 } 543 544 if( *temp ) 545 ( *actionName ) = strdup( temp ); 546 if( !*actionName ) { 547 ret_code = UPNP_E_OUTOF_MEMORY; 548 } 549 } 550 551 free( temp_header_value ); 552 free( ns_compare ); 553 return ret_code; 554} 555 556/**************************************************************************** 557* Function : get_device_info 558* 559* Parameters : 560* IN http_message_t* request : HTTP request 561* IN int isQuery : flag for a querry 562* IN IXML_Document *actionDoc : action request document 563* OUT char device_udn[LINE_SIZE] : Device UDN string 564* OUT char service_id[LINE_SIZE] : Service ID string 565* OUT Upnp_FunPtr *callback : callback function of the device 566* application 567* OUT void** cookie : cookie stored by device application 568* 569* Description : This function retrives all the information needed to 570* process the incoming SOAP request. It finds the device and service info 571* and also the callback function to hand-over the request to the device 572* application. 573* 574* Return : int 575* UPNP_E_SUCCESS if successful else returns appropriate error 576* 577* Note : 578****************************************************************************/ 579static int 580get_device_info( IN http_message_t * request, 581 IN int isQuery, 582 IN IXML_Document * actionDoc, 583 OUT char device_udn[LINE_SIZE], 584 OUT char service_id[LINE_SIZE], 585 OUT Upnp_FunPtr * callback, 586 OUT void **cookie ) 587{ 588 struct Handle_Info *device_info; 589 int device_hnd; 590 service_info *serv_info; 591 char save_char; 592 int ret_code = -1; // error by default 593 char *control_url; 594 char *actionName = NULL; 595 596 // null-terminate pathquery of url 597 control_url = request->uri.pathquery.buff; 598 save_char = control_url[request->uri.pathquery.size]; 599 control_url[request->uri.pathquery.size] = '\0'; 600 601 HandleLock( ); 602 603 if( GetDeviceHandleInfo( &device_hnd, &device_info ) != HND_DEVICE ) { 604 goto error_handler; 605 } 606 607 if( ( serv_info = 608 FindServiceControlURLPath( &device_info->ServiceTable, 609 control_url ) ) == NULL ) { 610 goto error_handler; 611 } 612 613 if( isQuery ) { 614 ret_code = check_soap_action_header( request, QUERY_STATE_VAR_URN, 615 &actionName ); 616 if( ( ret_code != UPNP_E_SUCCESS ) 617 && ( ret_code != UPNP_E_OUTOF_MEMORY ) ) { 618 ret_code = UPNP_E_INVALID_ACTION; 619 goto error_handler; 620 } 621 //check soap body 622 ret_code = 623 check_soap_body( actionDoc, QUERY_STATE_VAR_URN, actionName ); 624 if(actionName) 625 free( actionName ); 626 if( ret_code != UPNP_E_SUCCESS ) { 627 goto error_handler; 628 } 629 } else { 630 ret_code = check_soap_action_header( request, 631 serv_info->serviceType, 632 &actionName ); 633 if( ( ret_code != UPNP_E_SUCCESS ) 634 && ( ret_code != UPNP_E_OUTOF_MEMORY ) ) { 635 ret_code = UPNP_E_INVALID_SERVICE; 636 goto error_handler; 637 } 638 //check soap body 639 ret_code = 640 check_soap_body( actionDoc, serv_info->serviceType, 641 actionName ); 642 if(actionName) 643 free( actionName ); 644 if( ret_code != UPNP_E_SUCCESS ) { 645 ret_code = UPNP_E_INVALID_SERVICE; 646 goto error_handler; 647 } 648 } 649 650 namecopy( service_id, serv_info->serviceId ); 651 namecopy( device_udn, serv_info->UDN ); 652 *callback = device_info->Callback; 653 *cookie = device_info->Cookie; 654 655 ret_code = 0; 656 657 error_handler: 658 control_url[request->uri.pathquery.size] = save_char; // restore 659 HandleUnlock( ); 660 return ret_code; 661} 662 663/**************************************************************************** 664* Function : send_action_response 665* 666* Parameters : 667* IN SOCKINFO *info : socket info 668* IN IXML_Document *action_resp : The response document 669* IN http_message_t* request : action request document 670* 671* Description : This function sends the SOAP response 672* 673* Return : void 674* 675* Note : 676****************************************************************************/ 677static XINLINE void 678send_action_response( IN SOCKINFO * info, 679 IN IXML_Document * action_resp, 680 IN http_message_t * request ) 681{ 682 char *xml_response = NULL; 683 membuffer headers; 684 int major, 685 minor; 686 int err_code; 687 int content_length; 688 int ret_code; 689 int timeout_secs = SOAP_TIMEOUT; 690 static char *start_body = 691 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap." 692 "org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap." 693 "org/soap/encoding/\"><s:Body>\n"; 694 static char *end_body = "</s:Body> </s:Envelope>"; 695 696 // init 697 http_CalcResponseVersion( request->major_version, 698 request->minor_version, &major, &minor ); 699 membuffer_init( &headers ); 700 err_code = UPNP_E_OUTOF_MEMORY; // one error only 701 // get xml 702 xml_response = ixmlPrintDocument( ( IXML_Node * ) action_resp ); 703 if( xml_response == NULL ) { 704 goto error_handler; 705 } 706 707 content_length = strlen( start_body ) + strlen( xml_response ) + 708 strlen( end_body ); 709 // make headers 710 if( http_MakeMessage( &headers, major, minor, "RNsDsSc", HTTP_OK, // status code 711 content_length, ContentTypeHeader, "EXT:\r\n" // EXT header 712 ) != 0 ) { 713 goto error_handler; 714 } 715 // send whole msg 716 ret_code = http_SendMessage( info, &timeout_secs, "bbbb", 717 headers.buf, headers.length, 718 start_body, strlen( start_body ), 719 xml_response, strlen( xml_response ), 720 end_body, strlen( end_body ) ); 721 722 DBGONLY( if( ret_code != 0 ) { 723 UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, 724 "Failed to send response: err code = %d\n", 725 ret_code );} 726 ) 727 728 err_code = 0; 729 730 error_handler: 731 ixmlFreeDOMString( xml_response ); 732 membuffer_destroy( &headers ); 733 if( err_code != 0 ) { 734 // only one type of error to worry about - out of mem 735 send_error_response( info, SOAP_ACTION_FAILED, "Out of memory", 736 request ); 737 } 738} 739 740/**************************************************************************** 741* Function : get_var_name 742* 743* Parameters : 744* IN IXML_Document *TempDoc : Document containing variable request 745* OUT char* VarName : Name of the state varible 746* 747* Description : This function finds the name of the state variable 748* asked in the SOAP request. 749* 750* Return : int 751* returns 0 if successful else returns -1. 752* Note : 753****************************************************************************/ 754static XINLINE int 755get_var_name( IN IXML_Document * TempDoc, 756 OUT char *VarName ) 757{ 758 IXML_Node *EnvpNode = NULL; 759 IXML_Node *BodyNode = NULL; 760 IXML_Node *StNode = NULL; 761 IXML_Node *VarNameNode = NULL; 762 IXML_Node *VarNode = NULL; 763 const DOMString StNodeName = NULL; 764 DOMString Temp = NULL; 765 int ret_val = -1; 766 767 // Got the Envelop node here 768 EnvpNode = ixmlNode_getFirstChild( ( IXML_Node * ) TempDoc ); 769 if( EnvpNode == NULL ) { 770 goto error_handler; 771 } 772 // Got Body here 773 BodyNode = ixmlNode_getFirstChild( EnvpNode ); 774 if( BodyNode == NULL ) { 775 goto error_handler; 776 } 777 // Got action node here 778 StNode = ixmlNode_getFirstChild( BodyNode ); 779 if( StNode == NULL ) { 780 goto error_handler; 781 } 782 //Test whether this is the action node 783 StNodeName = ixmlNode_getNodeName( StNode ); 784 if( StNodeName == NULL || strstr( StNodeName, 785 "QueryStateVariable" ) == NULL ) { 786 goto error_handler; 787 } 788 789 VarNameNode = ixmlNode_getFirstChild( StNode ); 790 if( VarNameNode == NULL ) { 791 goto error_handler; 792 } 793 794 VarNode = ixmlNode_getFirstChild( VarNameNode ); 795 Temp = ixmlNode_getNodeValue( VarNode ); 796 linecopy( VarName, Temp ); 797 798 DBGONLY( UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, 799 "Received query for variable name %s\n", 800 VarName ); 801 ) 802 803 ret_val = 0; // success 804 805 error_handler: 806 return ret_val; 807} 808 809/**************************************************************************** 810* Function : handle_query_variable 811* 812* Parameters : 813* IN SOCKINFO *info : Socket info 814* IN http_message_t* request : HTTP request 815* IN IXML_Document *xml_doc : Document containing the variable request 816* SOAP message 817* 818* Description : This action handles the SOAP requests to querry the 819* state variables. This functionality has been deprecated in 820* the UPnP V1.0 architecture 821* 822* Return : void 823* 824* Note : 825****************************************************************************/ 826static XINLINE void 827handle_query_variable( IN SOCKINFO * info, 828 IN http_message_t * request, 829 IN IXML_Document * xml_doc ) 830{ 831 Upnp_FunPtr soap_event_callback; 832 void *cookie; 833 char var_name[LINE_SIZE]; 834 struct Upnp_State_Var_Request variable; 835 const char *err_str; 836 int err_code; 837 838 // get var name 839 if( get_var_name( xml_doc, var_name ) != 0 ) { 840 send_error_response( info, SOAP_INVALID_VAR, 841 Soap_Invalid_Var, request ); 842 return; 843 } 844 // get info for event 845 if( get_device_info( request, 1, xml_doc, variable.DevUDN, 846 variable.ServiceID, 847 &soap_event_callback, &cookie ) != 0 ) { 848 send_error_response( info, SOAP_INVALID_VAR, 849 Soap_Invalid_Var, request ); 850 return; 851 } 852 853 linecopy( variable.ErrStr, "" ); 854 variable.ErrCode = UPNP_E_SUCCESS; 855 namecopy( variable.StateVarName, var_name ); 856 variable.CurrentVal = NULL; 857 variable.CtrlPtIPAddr = info->foreign_ip_addr; 858 859 // send event 860 soap_event_callback( UPNP_CONTROL_GET_VAR_REQUEST, &variable, cookie ); 861 862 DBGONLY( UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, 863 "Return from callback for var request\n" ) ); 864 865 // validate, and handle result 866 if( variable.CurrentVal == NULL ) { 867 err_code = SOAP_ACTION_FAILED; 868 err_str = Soap_Action_Failed; 869 send_error_response( info, SOAP_INVALID_VAR, 870 Soap_Invalid_Var, request ); 871 return; 872 } 873 if( variable.ErrCode != UPNP_E_SUCCESS ) { 874 if( strlen( variable.ErrStr ) > 0 ) { 875 err_code = SOAP_INVALID_VAR; 876 err_str = Soap_Invalid_Var; 877 } else { 878 err_code = variable.ErrCode; 879 err_str = variable.ErrStr; 880 } 881 send_error_response( info, err_code, err_str, request ); 882 return; 883 } 884 // send response 885 send_var_query_response( info, variable.CurrentVal, request ); 886 ixmlFreeDOMString( variable.CurrentVal ); 887 888} 889 890/**************************************************************************** 891* Function : handle_invoke_action 892* 893* Parameters : 894* IN SOCKINFO *info : Socket info 895* IN http_message_t* request : HTTP Request 896* IN memptr action_name : Name of the SOAP Action 897* IN IXML_Document *xml_doc : document containing the SOAP action 898* request 899* 900* Description : This functions handle the SOAP action request. It checks 901* the integrity of the SOAP action request and gives the call back to 902* the device application. 903* 904* Return : void 905* 906* Note : 907****************************************************************************/ 908static void 909handle_invoke_action( IN SOCKINFO * info, 910 IN http_message_t * request, 911 IN memptr action_name, 912 IN IXML_Document * xml_doc ) 913{ 914 char save_char; 915 IXML_Document *resp_node = NULL; 916 struct Upnp_Action_Request action; 917 Upnp_FunPtr soap_event_callback; 918 void *cookie = NULL; 919 int err_code; 920 const char *err_str; 921 922 action.ActionResult = NULL; 923 924 // null-terminate 925 save_char = action_name.buf[action_name.length]; 926 action_name.buf[action_name.length] = '\0'; 927 928 // set default error 929 err_code = SOAP_INVALID_ACTION; 930 err_str = Soap_Invalid_Action; 931 932 // get action node 933 if( get_action_node( xml_doc, action_name.buf, &resp_node ) == -1 ) { 934 goto error_handler; 935 } 936 // get device info for action event 937 err_code = get_device_info( request, 0, xml_doc, action.DevUDN, 938 action.ServiceID, &soap_event_callback, 939 &cookie ); 940 941 if( err_code != UPNP_E_SUCCESS ) { 942 goto error_handler; 943 } 944 945 namecopy( action.ActionName, action_name.buf ); 946 linecopy( action.ErrStr, "" ); 947 action.ActionRequest = resp_node; 948 action.ActionResult = NULL; 949 action.ErrCode = UPNP_E_SUCCESS; 950 action.CtrlPtIPAddr = info->foreign_ip_addr; 951 952 DBGONLY( UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, 953 "Calling Callback\n" ) ); 954 soap_event_callback( UPNP_CONTROL_ACTION_REQUEST, &action, cookie ); 955 if( action.ErrCode != UPNP_E_SUCCESS ) { 956 if( strlen( action.ErrStr ) <= 0 ) { 957 err_code = SOAP_ACTION_FAILED; 958 err_str = Soap_Action_Failed; 959 } else { 960 err_code = action.ErrCode; 961 err_str = action.ErrStr; 962 } 963 goto error_handler; 964 } 965 // validate, and handle action error 966 if( action.ActionResult == NULL ) { 967 err_code = SOAP_ACTION_FAILED; 968 err_str = Soap_Action_Failed; 969 goto error_handler; 970 } 971 // send response 972 send_action_response( info, action.ActionResult, request ); 973 err_code = 0; 974 975 // error handling and cleanup 976 error_handler: 977 if(action.ActionResult) 978 ixmlDocument_free( action.ActionResult ); 979 if(resp_node) 980 ixmlDocument_free( resp_node ); 981 action_name.buf[action_name.length] = save_char; // restore 982 if( err_code != 0 ) { 983 send_error_response( info, err_code, err_str, request ); 984 } 985} 986 987/**************************************************************************** 988* Function : soap_device_callback 989* 990* Parameters : 991* IN http_parser_t *parser : Parsed request received by the device 992* IN http_message_t* request : HTTP request 993* INOUT SOCKINFO *info : socket info 994* 995* Description : This is a callback called by minisever after receiving 996* the request from the control point. This function will start 997* processing the request. It calls handle_invoke_action to handle the 998* SOAP action 999* 1000* Return : void 1001* 1002* Note : 1003****************************************************************************/ 1004void 1005soap_device_callback( IN http_parser_t * parser, 1006 IN http_message_t * request, 1007 INOUT SOCKINFO * info ) 1008{ 1009 int err_code; 1010 const char *err_str; 1011 memptr action_name; 1012 IXML_Document *xml_doc = NULL; 1013 1014 // set default error 1015 err_code = SOAP_INVALID_ACTION; 1016 err_str = Soap_Invalid_Action; 1017 1018 // validate: content-type == text/xml 1019 if( !has_xml_content_type( request ) ) { 1020 goto error_handler; 1021 } 1022 // type of request 1023 if( get_request_type( request, &action_name ) != 0 ) { 1024 goto error_handler; 1025 } 1026 // parse XML 1027 err_code = ixmlParseBufferEx( request->entity.buf, &xml_doc ); 1028 if( err_code != IXML_SUCCESS ) { 1029 if( err_code == IXML_INSUFFICIENT_MEMORY ) { 1030 err_code = UPNP_E_OUTOF_MEMORY; 1031 } else { 1032 err_code = SOAP_ACTION_FAILED; 1033 } 1034 1035 err_str = "XML error"; 1036 goto error_handler; 1037 } 1038 1039 if( action_name.length == 0 ) { 1040 // query var 1041 handle_query_variable( info, request, xml_doc ); 1042 } else { 1043 // invoke action 1044 handle_invoke_action( info, request, action_name, xml_doc ); 1045 } 1046 1047 err_code = 0; // no error 1048 1049 error_handler: 1050 if(xml_doc) 1051 ixmlDocument_free( xml_doc ); 1052 if( err_code != 0 ) { 1053 send_error_response( info, err_code, err_str, request ); 1054 } 1055} 1056 1057#endif // EXCLUDE_SOAP 1058 1059#endif // INCLUDE_DEVICE_APIS 1060