/**************************************************************************** * Function : soap_device_callback * * Parameters : * IN http_parser_t *parser : Parsed request received by the device * IN http_message_t* request : HTTP request * INOUT SOCKINFO *info : socket info * * Description : This is a callback called by minisever after receiving * the request from the control point. This function will start * processing the request. It calls handle_invoke_action to handle the * SOAP action * * Return : void * * Note : ****************************************************************************/ void soap_device_callback( IN http_parser_t * parser, IN http_message_t * request, INOUT SOCKINFO * info ) { int err_code; const char *err_str; memptr action_name; IXML_Document *xml_doc = NULL; // set default error err_code = SOAP_INVALID_ACTION; err_str = Soap_Invalid_Action; // validate: content-type == text/xml if( !has_xml_content_type( request ) ) { goto error_handler; } // type of request if( get_request_type( request, &action_name ) != 0 ) { goto error_handler; } // parse XML err_code = ixmlParseBufferEx( request->entity.buf, &xml_doc ); if( err_code != IXML_SUCCESS ) { if( err_code == IXML_INSUFFICIENT_MEMORY ) { err_code = UPNP_E_OUTOF_MEMORY; } else { err_code = SOAP_ACTION_FAILED; } err_str = "XML error"; goto error_handler; } if( action_name.length == 0 ) { // query var handle_query_variable( info, request, xml_doc ); } else { // invoke action handle_invoke_action( info, request, action_name, xml_doc ); } err_code = 0; // no error error_handler: ixmlDocument_free( xml_doc ); if( err_code != 0 ) { send_error_response( info, err_code, err_str, request ); } }
/*! * \brief This is a callback called by minisever after receiving the request * from the control point. This function will start processing the request. * It calls handle_invoke_action to handle the SOAP action. */ void soap_device_callback( int iface, /*! [in] Parsed request received by the device. */ http_parser_t *parser, /*! [in] HTTP request. */ http_message_t *request, /*! [in,out] Socket info. */ SOCKINFO *info) { int err_code; const char *err_str; memptr action_name; IXML_Document *xml_doc = NULL; /* set default error */ err_code = SOAP_INVALID_ACTION; err_str = Soap_Invalid_Action; /* validate: content-type == text/xml */ if (!has_xml_content_type(request)) goto error_handler; /* type of request */ if (get_request_type(request, &action_name) != 0) goto error_handler; /* parse XML */ err_code = ixmlParseBufferEx(request->entity.buf, &xml_doc); if (err_code != IXML_SUCCESS) { if (err_code == IXML_INSUFFICIENT_MEMORY) err_code = UPNP_E_OUTOF_MEMORY; else err_code = SOAP_ACTION_FAILED; err_str = "XML error"; goto error_handler; } if (action_name.length == 0) /* query var */ handle_query_variable(iface, info, request, xml_doc); else /* invoke action */ handle_invoke_action(iface, info, request, action_name, xml_doc); /* no error */ err_code = 0; error_handler: ixmlDocument_free(xml_doc); if (err_code != 0) send_error_response(info, err_code, err_str, request); return; parser = parser; }
/************************************************************************ * Function : gena_process_notification_event * * Parameters: * IN SOCKINFO *info: Socket structure containing the device socket * information * IN http_message_t* event: The http message contains the GENA * notification * * Description: * This function processes NOTIFY events that are sent by devices. * called by genacallback() * * Returns: void * * Note : called by genacallback() ****************************************************************************/ void gena_process_notification_event( IN SOCKINFO * info, IN http_message_t * event ) { struct Upnp_Event event_struct; int eventKey; token sid; client_subscription *subscription; IXML_Document *ChangedVars; struct Handle_Info *handle_info; void *cookie; Upnp_FunPtr callback; UpnpClient_Handle client_handle; memptr sid_hdr; memptr nt_hdr, nts_hdr; memptr seq_hdr; // get SID if( httpmsg_find_hdr( event, HDR_SID, &sid_hdr ) == NULL ) { error_respond( info, HTTP_PRECONDITION_FAILED, event ); return; } sid.buff = sid_hdr.buf; sid.size = sid_hdr.length; // get event key if( httpmsg_find_hdr( event, HDR_SEQ, &seq_hdr ) == NULL || matchstr( seq_hdr.buf, seq_hdr.length, "%d%0", &eventKey ) != PARSE_OK ) { error_respond( info, HTTP_BAD_REQUEST, event ); return; } // get NT and NTS headers if( httpmsg_find_hdr( event, HDR_NT, &nt_hdr ) == NULL || httpmsg_find_hdr( event, HDR_NTS, &nts_hdr ) == NULL ) { error_respond( info, HTTP_BAD_REQUEST, event ); return; } // verify NT and NTS headers if( memptr_cmp( &nt_hdr, "upnp:event" ) != 0 || memptr_cmp( &nts_hdr, "upnp:propchange" ) != 0 ) { error_respond( info, HTTP_PRECONDITION_FAILED, event ); return; } // parse the content (should be XML) if( !has_xml_content_type( event ) || event->msg.length == 0 || ( ixmlParseBufferEx( event->entity.buf, &ChangedVars ) ) != IXML_SUCCESS ) { error_respond( info, HTTP_BAD_REQUEST, event ); return; } HandleLock( ); // get client info if( GetClientHandleInfo( &client_handle, &handle_info ) != HND_CLIENT ) { error_respond( info, HTTP_PRECONDITION_FAILED, event ); HandleUnlock( ); ixmlDocument_free( ChangedVars ); return; } // get subscription based on SID if( ( subscription = GetClientSubActualSID( handle_info->ClientSubList, &sid ) ) == NULL ) { if( eventKey == 0 ) { // wait until we've finished processing a subscription // (if we are in the middle) // this is to avoid mistakenly rejecting the first event if we // receive it before the subscription response HandleUnlock( ); // try and get Subscription Lock // (in case we are in the process of subscribing) SubscribeLock( ); // get HandleLock again HandleLock( ); if( GetClientHandleInfo( &client_handle, &handle_info ) != HND_CLIENT ) { error_respond( info, HTTP_PRECONDITION_FAILED, event ); SubscribeUnlock( ); HandleUnlock( ); ixmlDocument_free( ChangedVars ); return; } if( ( subscription = GetClientSubActualSID( handle_info->ClientSubList, &sid ) ) == NULL ) { error_respond( info, HTTP_PRECONDITION_FAILED, event ); SubscribeUnlock( ); HandleUnlock( ); ixmlDocument_free( ChangedVars ); return; } SubscribeUnlock( ); } else { error_respond( info, HTTP_PRECONDITION_FAILED, event ); HandleUnlock( ); ixmlDocument_free( ChangedVars ); return; } } error_respond( info, HTTP_OK, event ); // success // fill event struct strcpy( event_struct.Sid, subscription->sid ); event_struct.EventKey = eventKey; event_struct.ChangedVariables = ChangedVars; // copy callback callback = handle_info->Callback; cookie = handle_info->Cookie; HandleUnlock( ); // make callback with event struct // In future, should find a way of mainting // that the handle is not unregistered in the middle of a // callback callback( UPNP_EVENT_RECEIVED, &event_struct, cookie ); ixmlDocument_free( ChangedVars ); }
/**************************************************************************** * Function : get_response_value * * Parameters : * IN http_message_t* hmsg : HTTP response message * IN int code : return code in the HTTP response * IN char*name : name of the action * OUT int *upnp_error_code : UPnP error code * OUT IXML_Node ** action_value : SOAP response node * OUT DOMString * str_value : state varible value ( in the case of * querry state variable request) * * Description : This function handles the response coming back from the * device. This function parses the response and gives back the SOAP * response node. * * Return : int * return the type of the SOAP message if successful else returns * appropriate error. * * Note : ****************************************************************************/ static int get_response_value( IN http_message_t * hmsg, IN int code, IN char *name, OUT int *upnp_error_code, OUT IXML_Node ** action_value, OUT DOMString * str_value ) { IXML_Node *node = NULL; IXML_Node *root_node = NULL; IXML_Node *error_node = NULL; IXML_Document *doc = NULL; char *node_str = NULL; const char *temp_str = NULL; DOMString error_node_str = NULL; int err_code; xboolean done = FALSE; char *names[5]; const DOMString nodeValue; err_code = UPNP_E_BAD_RESPONSE; // default error // only 200 and 500 status codes are relevant if( ( hmsg->status_code != HTTP_OK && hmsg->status_code != HTTP_INTERNAL_SERVER_ERROR ) || !has_xml_content_type( hmsg ) ) { goto error_handler; } if( ixmlParseBufferEx( hmsg->entity.buf, &doc ) != IXML_SUCCESS ) { goto error_handler; } root_node = ixmlNode_getFirstChild( ( IXML_Node * ) doc ); if( root_node == NULL ) { goto error_handler; } if( code == SOAP_ACTION_RESP ) { // // try reading soap action response // assert( action_value != NULL ); *action_value = NULL; names[0] = "Envelope"; names[1] = "Body"; names[2] = name; if( dom_find_deep_node( names, 3, root_node, &node ) == UPNP_E_SUCCESS ) { node_str = ixmlPrintNode( node ); if( node_str == NULL ) { err_code = UPNP_E_OUTOF_MEMORY; goto error_handler; } if( ixmlParseBufferEx( node_str, ( IXML_Document ** ) action_value ) != IXML_SUCCESS ) { err_code = UPNP_E_BAD_RESPONSE; goto error_handler; } err_code = SOAP_ACTION_RESP; done = TRUE; } } else if( code == SOAP_VAR_RESP ) { // try reading var response assert( str_value != NULL ); *str_value = NULL; names[0] = "Envelope"; names[1] = "Body"; names[2] = "QueryStateVariableResponse"; names[3] = "return"; if( dom_find_deep_node( names, 4, root_node, &node ) == UPNP_E_SUCCESS ) { nodeValue = get_node_value( node ); if( nodeValue == NULL ) { goto error_handler; } *str_value = ixmlCloneDOMString( nodeValue ); err_code = SOAP_VAR_RESP; done = TRUE; } } if( !done ) { // not action or var resp; read error code and description *str_value = NULL; names[0] = "Envelope"; names[1] = "Body"; names[2] = "Fault"; names[3] = "detail"; names[4] = "UPnPError"; if( dom_find_deep_node( names, 5, root_node, &error_node ) != UPNP_E_SUCCESS ) { goto error_handler; } if( dom_find_node( "errorCode", error_node, &node ) != UPNP_E_SUCCESS ) { goto error_handler; } temp_str = get_node_value( node ); if( temp_str == NULL ) { goto error_handler; } *upnp_error_code = atoi( temp_str ); if( *upnp_error_code > 400 ) { err_code = *upnp_error_code; goto error_handler; // bad SOAP error code } if( code == SOAP_VAR_RESP ) { if( dom_find_node( "errorDescription", error_node, &node ) != UPNP_E_SUCCESS ) { goto error_handler; } nodeValue = get_node_value( node ); if( nodeValue == NULL ) { goto error_handler; } *str_value = ixmlCloneDOMString( nodeValue ); if( *str_value == NULL ) { goto error_handler; } err_code = SOAP_VAR_RESP_ERROR; } else if( code == SOAP_ACTION_RESP ) { error_node_str = ixmlPrintNode( error_node ); if( error_node_str == NULL ) { err_code = UPNP_E_OUTOF_MEMORY; goto error_handler; } if( ixmlParseBufferEx( error_node_str, ( IXML_Document ** ) action_value ) != IXML_SUCCESS ) { err_code = UPNP_E_BAD_RESPONSE; goto error_handler; } err_code = SOAP_ACTION_RESP_ERROR; } } error_handler: ixmlDocument_free( doc ); ixmlFreeDOMString( node_str ); ixmlFreeDOMString( error_node_str ); return err_code; }
void gena_process_notification_event( SOCKINFO *info, http_message_t *event) { struct Upnp_Event event_struct; IXML_Document *ChangedVars = NULL; int eventKey; token sid; ClientSubscription *subscription = NULL; struct Handle_Info *handle_info; void *cookie; Upnp_FunPtr callback; UpnpClient_Handle client_handle; const UpnpString *tmpSID = NULL; memptr sid_hdr; memptr nt_hdr, nts_hdr; memptr seq_hdr; /* get SID */ if (httpmsg_find_hdr(event, HDR_SID, &sid_hdr) == NULL) { error_respond(info, HTTP_PRECONDITION_FAILED, event); goto exit_function; } sid.buff = sid_hdr.buf; sid.size = sid_hdr.length; /* get event key */ if (httpmsg_find_hdr(event, HDR_SEQ, &seq_hdr) == NULL || matchstr(seq_hdr.buf, seq_hdr.length, "%d%0", &eventKey) != PARSE_OK) { error_respond( info, HTTP_BAD_REQUEST, event ); goto exit_function; } /* get NT and NTS headers */ if (httpmsg_find_hdr(event, HDR_NT, &nt_hdr) == NULL || httpmsg_find_hdr(event, HDR_NTS, &nts_hdr) == NULL) { error_respond( info, HTTP_BAD_REQUEST, event ); goto exit_function; } /* verify NT and NTS headers */ if (memptr_cmp(&nt_hdr, "upnp:event") != 0 || memptr_cmp(&nts_hdr, "upnp:propchange") != 0) { error_respond(info, HTTP_PRECONDITION_FAILED, event); goto exit_function; } /* parse the content (should be XML) */ if (!has_xml_content_type(event) || event->msg.length == 0 || ixmlParseBufferEx(event->entity.buf, &ChangedVars) != IXML_SUCCESS) { error_respond(info, HTTP_BAD_REQUEST, event); goto exit_function; } HandleLock(); /* get client info */ if (GetClientHandleInfo(&client_handle, &handle_info) != HND_CLIENT) { error_respond(info, HTTP_PRECONDITION_FAILED, event); HandleUnlock(); goto exit_function; } /* get subscription based on SID */ subscription = GetClientSubActualSID(handle_info->ClientSubList, &sid); if (subscription == NULL) { if (eventKey == 0) { /* wait until we've finished processing a subscription */ /* (if we are in the middle) */ /* this is to avoid mistakenly rejecting the first event if we */ /* receive it before the subscription response */ HandleUnlock(); /* try and get Subscription Lock */ /* (in case we are in the process of subscribing) */ SubscribeLock(); /* get HandleLock again */ HandleLock(); if (GetClientHandleInfo(&client_handle, &handle_info) != HND_CLIENT) { error_respond(info, HTTP_PRECONDITION_FAILED, event); SubscribeUnlock(); HandleUnlock(); goto exit_function; } subscription = GetClientSubActualSID(handle_info->ClientSubList, &sid); if (subscription == NULL) { error_respond( info, HTTP_PRECONDITION_FAILED, event ); SubscribeUnlock(); HandleUnlock(); goto exit_function; } SubscribeUnlock(); } else { error_respond( info, HTTP_PRECONDITION_FAILED, event ); HandleUnlock(); goto exit_function; } } /* success */ error_respond(info, HTTP_OK, event); /* fill event struct */ tmpSID = UpnpClientSubscription_get_SID(subscription); memset(event_struct.Sid, 0, sizeof(event_struct.Sid)); strncpy(event_struct.Sid, UpnpString_get_String(tmpSID), sizeof(event_struct.Sid) - 1); event_struct.EventKey = eventKey; event_struct.ChangedVariables = ChangedVars; /* copy callback */ callback = handle_info->Callback; cookie = handle_info->Cookie; HandleUnlock(); /* make callback with event struct */ /* In future, should find a way of mainting */ /* that the handle is not unregistered in the middle of a */ /* callback */ callback(UPNP_EVENT_RECEIVED, &event_struct, cookie); exit_function: ixmlDocument_free(ChangedVars); }