📄 soap_device.c
字号:
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2003 Intel Corporation
// 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.
// * Neither name of Intel Corporation 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 INTEL 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.
//
///////////////////////////////////////////////////////////////////////////
#ifdef INCLUDE_DEVICE_APIS
#if EXCLUDE_SOAP == 0
#define SOAP_BODY "Body"
#define SOAP_URN "http://schemas.xmlsoap.org/soap/envelope/"
#define QUERY_STATE_VAR_URN "urn:schemas-upnp-org:control-1-0"
#include "config.h"
#include "upnpapi.h"
#include "parsetools.h"
#include "statcodes.h"
#include "httpparser.h"
#include "httpreadwrite.h"
#include "unixutil.h"
// timeout duration in secs for transmission/reception
#define SOAP_TIMEOUT UPNP_TIMEOUT
#define SREQ_HDR_NOT_FOUND -1
#define SREQ_BAD_HDR_FORMAT -2
#define SOAP_INVALID_ACTION 401
#define SOAP_INVALID_ARGS 402
#define SOAP_OUT_OF_SYNC 403
#define SOAP_INVALID_VAR 404
#define SOAP_ACTION_FAILED 501
static const char *Soap_Invalid_Action = "Invalid Action";
//static const char* Soap_Invalid_Args = "Invalid Args";
static const char *Soap_Action_Failed = "Action Failed";
static const char *Soap_Invalid_Var = "Invalid Var";
const char *ContentTypeHeader =
"CONTENT-TYPE: text/xml; charset=\"utf-8\"\n";
/****************************************************************************
* Function : get_request_type
*
* Parameters :
* IN http_message_t* request : HTTP request
* OUT memptr* action_name : SOAP action name
*
* Description : This function retrives the name of the SOAP action
*
* Return : int
* 0 if successful else returns appropriate error.
* Note :
****************************************************************************/
static XINLINE int
get_request_type( IN http_message_t * request,
OUT memptr * action_name )
{
memptr value;
memptr ns_value,
dummy_quote;
http_header_t *hdr;
char save_char;
char *s;
membuffer soap_action_name;
// find soapaction header
//
if( request->method == SOAPMETHOD_POST ) {
if( httpmsg_find_hdr( request, HDR_SOAPACTION, &value )
== NULL ) {
return SREQ_HDR_NOT_FOUND;
}
} else // M-POST
{
// get NS value from MAN header
hdr = httpmsg_find_hdr( request, HDR_MAN, &value );
if( hdr == NULL ) {
return SREQ_HDR_NOT_FOUND;
}
if( matchstr( value.buf, value.length, "%q%i ; ns = %s",
&dummy_quote, &ns_value ) != 0 ) {
return SREQ_BAD_HDR_FORMAT;
}
// create soapaction name header
membuffer_init( &soap_action_name );
if( ( membuffer_assign( &soap_action_name,
ns_value.buf, ns_value.length )
== UPNP_E_OUTOF_MEMORY ) ||
( membuffer_append_str( &soap_action_name,
"-SOAPACTION" ) ==
UPNP_E_OUTOF_MEMORY )
) {
membuffer_destroy( &soap_action_name );
return UPNP_E_OUTOF_MEMORY;
}
hdr = httpmsg_find_hdr_str( request, soap_action_name.buf );
membuffer_destroy( &soap_action_name );
if( hdr == NULL ) {
return SREQ_HDR_NOT_FOUND;
}
value.buf = hdr->value.buf;
value.length = hdr->value.length;
}
// determine type
//
save_char = value.buf[value.length];
value.buf[value.length] = '\0';
s = strchr( value.buf, '#' );
if( s == NULL ) {
value.buf[value.length] = save_char;
return SREQ_BAD_HDR_FORMAT;
}
s++; // move to value
if( matchstr( s, value.length - ( s - value.buf ), "%s",
action_name ) != PARSE_OK ) {
value.buf[value.length] = save_char;
return SREQ_BAD_HDR_FORMAT;
}
// action name or variable ?
if( memptr_cmp( action_name, "QueryStateVariable" ) == 0 ) {
// query variable
action_name->buf = NULL;
action_name->length = 0;
}
value.buf[value.length] = save_char; // restore
return 0;
}
/****************************************************************************
* Function : send_error_response
*
* Parameters :
* IN SOCKINFO *info : socket info
* IN int error_code : error code
* IN const char* err_msg : error message
* IN http_message_t* hmsg : HTTP request
*
* Description : This function sends SOAP error response
*
* Return : void
*
* Note :
****************************************************************************/
static void
send_error_response( IN SOCKINFO * info,
IN int error_code,
IN const char *err_msg,
IN http_message_t * hmsg )
{
int content_length;
int timeout_secs = SOAP_TIMEOUT;
int major,
minor;
const char *start_body =
"<s:Envelope\n"
"xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
"<s:Body>\n"
"<s:Fault>\n"
"<faultcode>s:Client</faultcode>\n"
"<faultstring>UPnPError</faultstring>\n"
"<detail>\n"
"<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n"
"<errorCode>";
const char *mid_body = "</errorCode>\n" "<errorDescription>";
const char *end_body =
"</errorDescription>\n"
"</UPnPError>\n"
"</detail>\n" "</s:Fault>\n" "</s:Body>\n" "</s:Envelope>\n";
char err_code_str[30];
membuffer headers;
sprintf( err_code_str, "%d", error_code );
// calc body len
content_length = strlen( start_body ) + strlen( err_code_str ) +
strlen( mid_body ) + strlen( err_msg ) + strlen( end_body );
http_CalcResponseVersion( hmsg->major_version, hmsg->minor_version,
&major, &minor );
// make headers
membuffer_init( &headers );
if( http_MakeMessage( &headers, major, minor,
"RNsDsSc" "sssss",
500,
content_length,
ContentTypeHeader,
"EXT:\r\n",
start_body, err_code_str, mid_body, err_msg,
end_body ) != 0 ) {
membuffer_destroy( &headers );
return; // out of mem
}
// send err msg
http_SendMessage( info, &timeout_secs, "b",
headers.buf, headers.length );
membuffer_destroy( &headers );
}
/****************************************************************************
* Function : send_var_query_response
*
* Parameters :
* IN SOCKINFO *info : socket info
* IN const char* var_value : value of the state variable
* IN http_message_t* hmsg : HTTP request
*
* Description : This function sends response of get var status
*
* Return : void
*
* Note :
****************************************************************************/
static XINLINE void
send_var_query_response( IN SOCKINFO * info,
IN const char *var_value,
IN http_message_t * hmsg )
{
int content_length;
int timeout_secs = SOAP_TIMEOUT;
int major,
minor;
const char *start_body =
"<s:Envelope\n"
"xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
"<s:Body>\n"
"<u:QueryStateVariableResponse "
"xmlns:u=\"urn:schemas-upnp-org:control-1-0\">\n" "<return>";
const char *end_body =
"</return>\n"
"</u:QueryStateVariableResponse>\n"
"</s:Body>\n" "</s:Envelope>\n";
membuffer response;
http_CalcResponseVersion( hmsg->major_version, hmsg->minor_version,
&major, &minor );
content_length = strlen( start_body ) + strlen( var_value ) +
strlen( end_body );
// make headers
membuffer_init( &response );
if( http_MakeMessage( &response, major, minor,
"RNsDsSc" "sss",
HTTP_OK,
content_length,
ContentTypeHeader,
"EXT:\r\n",
start_body, var_value, end_body ) != 0 ) {
membuffer_destroy( &response );
return; // out of mem
}
// send msg
http_SendMessage( info, &timeout_secs, "b",
response.buf, response.length );
membuffer_destroy( &response );
}
/****************************************************************************
* Function : get_action_node
*
* Parameters :
* IN IXML_Document *TempDoc : The root DOM node.
* IN char *NodeName : IXML_Node name to be searched.
* OUT IXML_Document ** RespNode : Response/Output node.
*
* Description : This function separates the action node from
* the root DOM node.
*
* Return : static XINLINE int
* 0 if successful, or -1 if fails.
*
* Note :
****************************************************************************/
static XINLINE int
get_action_node( IN IXML_Document * TempDoc,
IN char *NodeName,
OUT IXML_Document ** RespNode )
{
IXML_Node *EnvpNode = NULL;
IXML_Node *BodyNode = NULL;
IXML_Node *ActNode = NULL;
DOMString ActNodeName = NULL;
const DOMString nodeName;
int ret_code = -1; // error, by default
IXML_NodeList *nl = NULL;
DBGONLY( UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
"get_action_node(): node name =%s\n ", NodeName );
)
* RespNode = NULL;
// Got the Envelope node here
EnvpNode = ixmlNode_getFirstChild( ( IXML_Node * ) TempDoc );
if( EnvpNode == NULL ) {
goto error_handler;
}
nl = ixmlElement_getElementsByTagNameNS( ( IXML_Element * ) EnvpNode,
"*", "Body" );
if( nl == NULL ) {
goto error_handler;
}
BodyNode = ixmlNodeList_item( nl, 0 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -