/*! * \brief Separates the action node from the root DOM node. * * \return 0 if successful, or -1 if fails. */ static UPNP_INLINE int get_action_node( /*! [in] The root DOM node. */ IXML_Document *TempDoc, /*! [in] IXML_Node name to be searched. */ char *NodeName, /*! [out] Response/Output node. */ 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; 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) goto error_handler; nl = ixmlElement_getElementsByTagNameNS((IXML_Element *)EnvpNode, "*", "Body"); if (!nl) goto error_handler; BodyNode = ixmlNodeList_item(nl, 0); if (!BodyNode) goto error_handler; /* Got action node here */ ActNode = ixmlNode_getFirstChild(BodyNode); if (!ActNode) goto error_handler; /* Test whether this is the action node */ nodeName = ixmlNode_getNodeName(ActNode); if (!nodeName) goto error_handler; if (!strstr(nodeName, NodeName)) goto error_handler; else { ActNodeName = ixmlPrintNode(ActNode); if (!ActNodeName) goto error_handler; ret_code = ixmlParseBufferEx(ActNodeName, RespNode); if (ret_code != IXML_SUCCESS) { ixmlFreeDOMString(ActNodeName); ret_code = -1; goto error_handler; } } /* success */ ret_code = 0; error_handler: ixmlFreeDOMString(ActNodeName); if (nl) ixmlNodeList_free(nl); return ret_code; }
/************************************************************************ * Function : freeService * * Parameters : * service_info *in ; service information that is to be freed * * Description : Free's memory allocated for the various components * of the service entry in the service table. * * Return : void ; * * Note : ************************************************************************/ void freeService( service_info * in ) { if( in ) { if( in->serviceType ) ixmlFreeDOMString( in->serviceType ); if( in->serviceId ) ixmlFreeDOMString( in->serviceId ); if( in->SCPDURL ) free( in->SCPDURL ); if( in->controlURL ) free( in->controlURL ); if( in->eventURL ) free( in->eventURL ); if( in->UDN ) ixmlFreeDOMString( in->UDN ); if( in->subscriptionList ) freeSubscriptionList( in->subscriptionList ); in->TotalSubscriptions = 0; free( in ); } }
/************************************************************************ * Function : freeServiceList * * Parameters : * service_info * head ; Head of the service list to be freed * * Description : Free's memory allocated for the various components * of each service entry in the service table. * * Return : void ; * * Note : ************************************************************************/ void freeServiceList( service_info * head ) { service_info *next = NULL; while( head ) { if( head->serviceType ) ixmlFreeDOMString( head->serviceType ); if( head->serviceId ) ixmlFreeDOMString( head->serviceId ); if( head->SCPDURL ) free( head->SCPDURL ); if( head->controlURL ) free( head->controlURL ); if( head->eventURL ) free( head->eventURL ); if( head->UDN ) ixmlFreeDOMString( head->UDN ); if( head->subscriptionList ) freeSubscriptionList( head->subscriptionList ); head->TotalSubscriptions = 0; next = head->next; free( head ); head = next; } }
int main (int argc, char* argv[]) { int i; if (argc < 2) { fprintf (stderr, "Usage: %s [xml files to load]\n", argv[0]); exit (EXIT_FAILURE); } for (i = 1; i < argc; i++) { int rc; IXML_Document* doc = NULL; DOMString s; char* p; printf ("Test \"%s\" \n", argv[i]); printf (" Loading ... "); fflush (stdout); rc = ixmlLoadDocumentEx (argv[i], &doc); if (rc != IXML_SUCCESS) { fprintf (stderr, "** error : can't load document %s : " "error %d (%s)\n", argv[i], rc, get_ixml_error_string (rc)); exit (EXIT_FAILURE); } printf ("OK\n"); printf (" Printing ... "); fflush (stdout); s = ixmlPrintDocument (doc); if (s == NULL || s[0] == '\0') { fprintf (stderr, "** error : can't print loaded document %s\n", argv[i]); exit (EXIT_FAILURE); } p = s + strlen(s)-1; while (isspace(*p) && p > s) p--; if (*s != '<' || *p != '>') { fprintf (stderr, "** error : malformed printed document '%s' :" "%s\n", argv[i], s); exit (EXIT_FAILURE); } printf ("OK\n"); ixmlFreeDOMString (s); ixmlDocument_free (doc); } exit (EXIT_SUCCESS); }
/************************************************************************ * Function : removeServiceTable * * Parameters : * IXML_Node *node ; XML node information * service_table *in ; service table from which services will be * removed * * Description : This function assumes that services for a particular * root device are placed linearly in the service table, and in the * order in which they are found in the description document * all services for this root device are removed from the list * * Return : int ; * * Note : ************************************************************************/ int removeServiceTable( IXML_Node * node, service_table * in ) { IXML_Node *root = NULL; IXML_Node *currentUDN = NULL; DOMString UDN = NULL; IXML_NodeList *deviceList = NULL; service_info *current_service = NULL; service_info *start_search = NULL; service_info *prev_service = NULL; long unsigned int NumOfDevices = 0lu; long unsigned int i = 0lu; if( getSubElement( "root", node, &root ) ) { current_service = in->serviceList; start_search = in->serviceList; deviceList = ixmlElement_getElementsByTagName( ( IXML_Element * ) root, "device" ); if( deviceList != NULL ) { NumOfDevices = ixmlNodeList_length( deviceList ); for( i = 0lu; i < NumOfDevices; i++ ) { if( ( start_search ) && ( ( getSubElement( "UDN", node, ¤tUDN ) ) && ( UDN = getElementValue( currentUDN ) ) ) ) { current_service = start_search; /*Services are put in the service table in the order in which they appear in the */ /*description document, therefore we go through the list only once to remove a particular */ /*root device */ while( ( current_service ) && ( strcmp( current_service->UDN, UDN ) ) ) { current_service = current_service->next; if( current_service != NULL) prev_service = current_service->next; } while( ( current_service ) && ( !strcmp( current_service->UDN, UDN ) ) ) { if( prev_service ) { prev_service->next = current_service->next; } else { in->serviceList = current_service->next; } if( current_service == in->endServiceList ) in->endServiceList = prev_service; start_search = current_service->next; freeService( current_service ); current_service = start_search; } ixmlFreeDOMString( UDN ); UDN = NULL; } } ixmlNodeList_free( deviceList ); } } return 1; }
/************************************************************************ * Function : freeServiceTable * * Parameters : * service_table * table ; Service table whose memory needs to be * freed * * Description : Free's dynamic memory in table. * (does not free table, only memory within the structure) * * Return : void ; * * Note : ************************************************************************/ void freeServiceTable( service_table * table ) { ixmlFreeDOMString( table->URLBase ); freeServiceList( table->serviceList ); table->serviceList = NULL; table->endServiceList = NULL; }
/************************************************************************ * Function : configure_urlbase * * Parameters : * INOUT IXML_Document *doc ; IXML Description document * IN const struct sockaddr_in* serverAddr ; socket address object * providing the IP address and port information * IN const char* alias ; string containing the alias * IN time_t last_modified ; time when the XML document was * downloaded * OUT char docURL[LINE_SIZE] ; buffer to hold the URL of the * document. * INOUT IXML_Document *doc:dom document whose urlbase is to be modified * IN const struct sockaddr_in* serverAddr : ip address and port of * the miniserver * IN const char* alias : a name to be used for the temp; e.g.:"foo.xml" * IN time_t last_modified : time * OUT char docURL[LINE_SIZE] : document URL * * Description : Configure the full URL for the description document. * Create the URL document and add alias, description information. * The doc is added to the web server to be served using the given * alias. * * Return : int ; * UPNP_E_SUCCESS - On Success * UPNP_E_OUTOF_MEMORY - Default Error * * Note : ************************************************************************/ int configure_urlbase( INOUT IXML_Document * doc, IN const struct sockaddr_in *serverAddr, IN const char *alias, IN time_t last_modified, OUT char docURL[LINE_SIZE] ) { char *root_path = NULL; char *new_alias = NULL; char *xml_str = NULL; int err_code; char ipaddr_port[LINE_SIZE]; err_code = UPNP_E_OUTOF_MEMORY; // default error // get IP address and port addrToString( serverAddr, ipaddr_port ); // config url-base in 'doc' err_code = config_description_doc( doc, ipaddr_port, &root_path ); if( err_code != UPNP_E_SUCCESS ) { goto error_handler; } // calc alias err_code = calc_alias( alias, root_path, &new_alias ); if( err_code != UPNP_E_SUCCESS ) { goto error_handler; } // calc full url for desc doc err_code = calc_descURL( ipaddr_port, new_alias, docURL ); if( err_code != UPNP_E_SUCCESS ) { goto error_handler; } // xml doc to str xml_str = ixmlPrintDocument( doc ); if( xml_str == NULL ) { goto error_handler; } UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "desc url: %s\n", docURL ); UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "doc = %s\n", xml_str ); // store in web server err_code = web_server_set_alias( new_alias, xml_str, strlen( xml_str ), last_modified ); error_handler: free( root_path ); free( new_alias ); if( err_code != UPNP_E_SUCCESS ) { ixmlFreeDOMString( xml_str ); } return err_code; }
/*! * \brief Frees memory used in notify_threads if the reference count is 0, * otherwise decrements the refrence count. */ static void free_notify_struct( /*! [in] Notify structure. */ notify_thread_struct *input) { (*input->reference_count)--; if (*input->reference_count == 0) { free(input->headers); ixmlFreeDOMString(input->propertySet); free(input->servId); free(input->UDN); free(input->reference_count); } free(input); }
int MediaServer::sendActionCb( Upnp_EventType eventType, void *p_event, void *p_cookie ) { if( eventType != UPNP_CONTROL_ACTION_COMPLETE ) return 0; IXML_Document** pp_sendActionResult = (IXML_Document** )p_cookie; Upnp_Action_Complete *p_result = (Upnp_Action_Complete *)p_event; /* The only way to dup the result is to print it and parse it again */ DOMString tmpStr = ixmlPrintNode( ( IXML_Node * ) p_result->ActionResult ); if (tmpStr == NULL) return 0; *pp_sendActionResult = ixmlParseBuffer( tmpStr ); ixmlFreeDOMString( tmpStr ); return 0; }
/****************************************************************************** * XMLUtil_GetNodeString *****************************************************************************/ char* XMLUtil_GetNodeString (void* context, const IXML_Node* node) { char* ret = NULL; if (node) { DOMString s = ixmlPrintNode (discard_const_p (IXML_Node,node)); if (s) { ret = talloc_strdup (context, s); ixmlFreeDOMString (s); } else { ret = talloc_strdup (context, "(error)"); } } else { ret = talloc_strdup (context, "(null)"); } return ret; }
/*! * \brief Release memory allocated for the global web server root directory * and the global XML document. Resets the flag bWebServerState to * WEB_SERVER_DISABLED. * * \return Integer. */ static int get_file_info( /*! [in] Filename having the description document. */ const char *filename, /*! [out] File information object having file attributes such as filelength, * when was the file last modified, whether a file or a directory and * whether the file or directory is readable. */ struct File_Info *info) { int code; struct osal_stat_t s; OSAL_FILE *fp; int rc = 0; struct tm date; char buffer[ASCTIME_R_BUFFER_SIZE]; ixmlFreeDOMString(info->content_type); info->content_type = NULL; code = osal_stat(filename, &s); if (code == -1) return -1; if (S_ISDIR(s.st_mode)) info->is_directory = TRUE; else if (S_ISREG(s.st_mode)) info->is_directory = FALSE; else return -1; if (info->is_directory == FALSE) { fp = osal_fopen(filename, "r"); if (fp == NULL) return -1; osal_fclose(fp); /* check readable */ info->is_readable = 1; info->file_length = s.st_size; info->last_modified = s.st_mtime; rc = get_content_type(filename, &info->content_type); UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, "file info: %s, length: %lld, last_mod=%s readable=%d\n", filename, (long long)info->file_length, asctime_r(http_gmtime_r(&info->last_modified, &date), buffer), info->is_readable); } return rc; }
static void FreeExtraHTTPHeaders( /*! [in] extra HTTP headers to free. */ struct Extra_Headers *ExtraHeaders) { struct Extra_Headers *extra_headers = ExtraHeaders; if (!ExtraHeaders) { return; } while (extra_headers->name) { free(extra_headers->name); if (extra_headers->value) free(extra_headers->value); if (extra_headers->resp) ixmlFreeDOMString(extra_headers->resp); extra_headers++; } free(ExtraHeaders); }
/****************************************************************************** * XMLUtil_GetDocumentString *****************************************************************************/ char* XMLUtil_GetDocumentString (void* context, const IXML_Document* doc) { // TBD XXX // TBD prepend <?xml version="1.0"?> if not already done ??? // TBD XXX char* ret = NULL; if (doc) { DOMString s = ixmlPrintDocument (doc); if (s) { ret = talloc_strdup (context, s); ixmlFreeDOMString (s); } else { ret = talloc_strdup (context, "(error)"); } } else { ret = talloc_strdup (context, "(null)"); } return ret; }
void rtpxmlFreeDOMString(DOMString buf) { ixmlFreeDOMString(buf); }
/************************************************************************ * Function : getServiceList * * Parameters : * IXML_Node *node ; XML node information * service_info **end ; service added is returned to the output * parameter * char * URLBase ; provides Base URL to resolve relative URL * * Description : Returns pointer to service info after getting the * sub-elements of the service info. * * Return : service_info * - pointer to the service info node ; * * Note : ************************************************************************/ service_info * getServiceList( IXML_Node * node, service_info ** end, char *URLBase ) { IXML_Node *serviceList = NULL; IXML_Node *current_service = NULL; IXML_Node *UDN = NULL; IXML_Node *serviceType = NULL; IXML_Node *serviceId = NULL; IXML_Node *SCPDURL = NULL; IXML_Node *controlURL = NULL; IXML_Node *eventURL = NULL; DOMString tempDOMString = NULL; service_info *head = NULL; service_info *current = NULL; service_info *previous = NULL; IXML_NodeList *serviceNodeList = NULL; int NumOfServices = 0; int i = 0; int fail = 0; if( getSubElement( "UDN", node, &UDN ) && getSubElement( "serviceList", node, &serviceList ) ) { serviceNodeList = ixmlElement_getElementsByTagName( ( IXML_Element * ) serviceList, "service" ); if( serviceNodeList != NULL ) { NumOfServices = ixmlNodeList_length( serviceNodeList ); for( i = 0; i < NumOfServices; i++ ) { current_service = ixmlNodeList_item( serviceNodeList, i ); fail = 0; if( current ) { current->next = ( service_info * ) malloc( sizeof( service_info ) ); previous = current; current = current->next; } else { head = ( service_info * ) malloc( sizeof( service_info ) ); current = head; } if( !current ) { freeServiceList( head ); return NULL; } current->next = NULL; current->controlURL = NULL; current->eventURL = NULL; current->serviceType = NULL; current->serviceId = NULL; current->SCPDURL = NULL; current->active = 1; current->subscriptionList = NULL; current->TotalSubscriptions = 0; if( !( current->UDN = getElementValue( UDN ) ) ) fail = 1; if( ( !getSubElement( "serviceType", current_service, &serviceType ) ) || ( !( current->serviceType = getElementValue( serviceType ) ) ) ) fail = 1; if( ( !getSubElement( "serviceId", current_service, &serviceId ) ) || ( ! ( current->serviceId = getElementValue( serviceId ) ) ) ) fail = 1; if( ( ! ( getSubElement ( "SCPDURL", current_service, &SCPDURL ) ) ) || ( !( tempDOMString = getElementValue( SCPDURL ) ) ) || ( ! ( current->SCPDURL = resolve_rel_url( URLBase, tempDOMString ) ) ) ) fail = 1; ixmlFreeDOMString( tempDOMString ); tempDOMString = NULL; if( ( ! ( getSubElement ( "controlURL", current_service, &controlURL ) ) ) || ( !( tempDOMString = getElementValue( controlURL ) ) ) || ( ! ( current->controlURL = resolve_rel_url( URLBase, tempDOMString ) ) ) ) { UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "BAD OR MISSING CONTROL URL" ); UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "CONTROL URL SET TO NULL IN SERVICE INFO" ); current->controlURL = NULL; fail = 0; } ixmlFreeDOMString( tempDOMString ); tempDOMString = NULL; if( ( ! ( getSubElement ( "eventSubURL", current_service, &eventURL ) ) ) || ( !( tempDOMString = getElementValue( eventURL ) ) ) || ( ! ( current->eventURL = resolve_rel_url( URLBase, tempDOMString ) ) ) ) { UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "BAD OR MISSING EVENT URL" ); UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "EVENT URL SET TO NULL IN SERVICE INFO" ); current->eventURL = NULL; fail = 0; } ixmlFreeDOMString( tempDOMString ); tempDOMString = NULL; if( fail ) { freeServiceList( current ); if( previous ) previous->next = NULL; else head = NULL; current = previous; } } ixmlNodeList_free( serviceNodeList ); } ( *end ) = current; return head; } else return NULL; }
/**************************************************************************** * Function : handle_query_variable * * Parameters : * IN SOCKINFO *info : Socket info * IN http_message_t* request : HTTP request * IN IXML_Document *xml_doc : Document containing the variable request * SOAP message * * Description : This action handles the SOAP requests to querry the * state variables. This functionality has been deprecated in * the UPnP V1.0 architecture * * Return : void * * Note : ****************************************************************************/ static UPNP_INLINE void handle_query_variable( IN SOCKINFO * info, IN http_message_t * request, IN IXML_Document * xml_doc ) { Upnp_FunPtr soap_event_callback; void *cookie; char var_name[LINE_SIZE]; struct Upnp_State_Var_Request variable; const char *err_str; int err_code; // get var name if( get_var_name( xml_doc, var_name ) != 0 ) { send_error_response( info, SOAP_INVALID_VAR, Soap_Invalid_Var, request ); return; } // get info for event if( get_device_info( request, 1, xml_doc, variable.DevUDN, variable.ServiceID, &soap_event_callback, &cookie ) != 0 ) { send_error_response( info, SOAP_INVALID_VAR, Soap_Invalid_Var, request ); return; } linecopy( variable.ErrStr, "" ); variable.ErrCode = UPNP_E_SUCCESS; namecopy( variable.StateVarName, var_name ); variable.CurrentVal = NULL; variable.CtrlPtIPAddr = info->foreign_ip_addr; // send event soap_event_callback( UPNP_CONTROL_GET_VAR_REQUEST, &variable, cookie ); UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, "Return from callback for var request\n" ); // validate, and handle result if( variable.CurrentVal == NULL ) { err_code = SOAP_ACTION_FAILED; err_str = Soap_Action_Failed; send_error_response( info, SOAP_INVALID_VAR, Soap_Invalid_Var, request ); return; } if( variable.ErrCode != UPNP_E_SUCCESS ) { if( strlen( variable.ErrStr ) > 0 ) { err_code = SOAP_INVALID_VAR; err_str = Soap_Invalid_Var; } else { err_code = variable.ErrCode; err_str = variable.ErrStr; } send_error_response( info, err_code, err_str, request ); return; } // send response send_var_query_response( info, variable.CurrentVal, request ); ixmlFreeDOMString( variable.CurrentVal ); }
/** Prints contents of XML node to debug log. */ static void printXMLContents(IXML_Node* node, const char* title) { DOMString str = ixmlPrintNode(node); log_debug("\n%s:\n%s",title, str); ixmlFreeDOMString(str); }
/* We take ownership of propertySet and will free it */ static int genaInitNotifyCommon( UpnpDevice_Handle device_handle, char *UDN, char *servId, DOMString propertySet, const Upnp_SID sid) { int ret = GENA_SUCCESS; int line = 0; int *reference_count = NULL; char *UDN_copy = NULL; char *servId_copy = NULL; char *headers = NULL; notify_thread_struct *thread_struct = NULL; subscription *sub = NULL; service_info *service = NULL; struct Handle_Info *handle_info; ThreadPoolJob *job = NULL; UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA BEGIN INITIAL NOTIFY COMMON"); job = (ThreadPoolJob *)malloc(sizeof(ThreadPoolJob)); if (job == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } memset(job, 0, sizeof(ThreadPoolJob)); reference_count = (int *)malloc(sizeof (int)); if (reference_count == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } *reference_count = 0; UDN_copy = strdup(UDN); if (UDN_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } servId_copy = strdup(servId); if (servId_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } HandleLock(); if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) { line = __LINE__; ret = GENA_E_BAD_HANDLE; goto ExitFunction; } service = FindServiceId(&handle_info->ServiceTable, servId, UDN); if (service == NULL) { line = __LINE__; ret = GENA_E_BAD_SERVICE; goto ExitFunction; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "FOUND SERVICE IN INIT NOTFY: UDN %s, ServID: %s", UDN, servId); sub = GetSubscriptionSID(sid, service); if (sub == NULL || sub->active) { line = __LINE__; ret = GENA_E_BAD_SID; goto ExitFunction; } UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "FOUND SUBSCRIPTION IN INIT NOTIFY: SID %s", sid); sub->active = 1; headers = AllocGenaHeaders(propertySet); if (headers == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } /* schedule thread for initial notification */ thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct)); if (thread_struct == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } else { *reference_count = 1; thread_struct->servId = servId_copy; thread_struct->UDN = UDN_copy; thread_struct->headers = headers; thread_struct->propertySet = propertySet; memset(thread_struct->sid, 0, sizeof(thread_struct->sid)); strncpy(thread_struct->sid, sid, sizeof(thread_struct->sid) - 1); thread_struct->ctime = time(0); thread_struct->reference_count = reference_count; thread_struct->device_handle = device_handle; TPJobInit(job, (start_routine)genaNotifyThread, thread_struct); TPJobSetFreeFunction(job, (free_routine)free_notify_struct); TPJobSetPriority(job, MED_PRIORITY); ret = ThreadPoolAdd(&gSendThreadPool, job, NULL); if (ret != 0) { if (ret == EOUTOFMEM) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } } else { ListNode *node = ListAddTail(&sub->outgoing, job); if (node != NULL) { ((ThreadPoolJob *)node->item)->jobId = STALE_JOBID; line = __LINE__; ret = GENA_SUCCESS; } else { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } } } ExitFunction: if (ret != GENA_SUCCESS) { free(job); free(thread_struct); free(headers); ixmlFreeDOMString(propertySet); free(servId_copy); free(UDN_copy); free(reference_count); } HandleUnlock(); UpnpPrintf(UPNP_INFO, GENA, __FILE__, line, "GENA END INITIAL NOTIFY COMMON, ret = %d", ret); return ret; }
/**************************************************************************** * 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 UPNP_INLINE int * 0 if successful, or -1 if fails. * * Note : ****************************************************************************/ static UPNP_INLINE 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; 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 ); if( BodyNode == NULL ) { goto error_handler; } // Got action node here ActNode = ixmlNode_getFirstChild( BodyNode ); if( ActNode == NULL ) { goto error_handler; } //Test whether this is the action node nodeName = ixmlNode_getNodeName( ActNode ); if( nodeName == NULL ) { goto error_handler; } if( strstr( nodeName, NodeName ) == NULL ) { goto error_handler; } else { ActNodeName = ixmlPrintNode( ActNode ); if( ActNodeName == NULL ) { goto error_handler; } ret_code = ixmlParseBufferEx( ActNodeName, RespNode ); if( ret_code != IXML_SUCCESS ) { ixmlFreeDOMString( ActNodeName ); ret_code = -1; goto error_handler; } } ret_code = 0; // success error_handler: ixmlFreeDOMString( ActNodeName ); if( nl ) ixmlNodeList_free( nl ); return ret_code; }
int genaNotifyAll( UpnpDevice_Handle device_handle, char *UDN, char *servId, char **VarNames, char **VarValues, int var_count) { int ret = GENA_SUCCESS; int line = 0; int *reference_count = NULL; char *UDN_copy = NULL; char *servId_copy = NULL; DOMString propertySet = NULL; char *headers = NULL; notify_thread_struct *thread_struct = NULL; subscription *finger = NULL; service_info *service = NULL; struct Handle_Info *handle_info; ThreadPoolJob job; memset(&job, 0, sizeof(job)); UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA BEGIN NOTIFY ALL"); reference_count = (int *)malloc(sizeof (int)); if (reference_count == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } *reference_count = 0; UDN_copy = strdup(UDN); if (UDN_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } servId_copy = strdup(servId); if( servId_copy == NULL ) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } ret = GeneratePropertySet(VarNames, VarValues, var_count, &propertySet); if (ret != XML_SUCCESS) { line = __LINE__; goto ExitFunction; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENERATED PROPERTY SET IN EXT NOTIFY: %s", propertySet); headers = AllocGenaHeaders(propertySet); if (headers == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } HandleLock(); if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) { line = __LINE__; ret = GENA_E_BAD_HANDLE; } else { service = FindServiceId(&handle_info->ServiceTable, servId, UDN); if (service != NULL) { finger = GetFirstSubscription(service); while (finger) { thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct)); if (thread_struct == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; break; } (*reference_count)++; thread_struct->reference_count = reference_count; thread_struct->UDN = UDN_copy; thread_struct->servId = servId_copy; thread_struct->headers = headers; thread_struct->propertySet = propertySet; memset(thread_struct->sid, 0, sizeof(thread_struct->sid)); strncpy(thread_struct->sid, finger->sid, sizeof(thread_struct->sid) - 1); thread_struct->eventKey = finger->eventKey++; thread_struct->device_handle = device_handle; /* if overflow, wrap to 1 */ if (finger->eventKey < 0) { finger->eventKey = 1; } TPJobInit(&job, (start_routine)genaNotifyThread, thread_struct); TPJobSetFreeFunction(&job, (free_routine)free_notify_struct); TPJobSetPriority(&job, MED_PRIORITY); ret = ThreadPoolAdd(&gSendThreadPool, &job, NULL); if (ret != 0) { line = __LINE__; if (ret == EOUTOFMEM) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } break; } finger = GetNextSubscription(service, finger); } } else { line = __LINE__; ret = GENA_E_BAD_SERVICE; } } ExitFunction: if (ret != GENA_SUCCESS || *reference_count == 0) { free(headers); ixmlFreeDOMString(propertySet); free(servId_copy); free(UDN_copy); free(reference_count); } HandleUnlock(); UpnpPrintf(UPNP_INFO, GENA, __FILE__, line, "GENA END NOTIFY ALL, ret = %d", ret); return ret; }
/*! * \brief Handles the SOAP requests to querry the state variables. * This functionality has been deprecated in the UPnP V1.0 architecture. */ static UPNP_INLINE void handle_query_variable( int iface, /*! [in] Socket info. */ SOCKINFO *info, /*! [in] HTTP request. */ http_message_t *request, /*! [in] Document containing the variable request SOAP message. */ IXML_Document *xml_doc) { Upnp_FunPtr soap_event_callback; void *cookie; char var_name[LINE_SIZE]; struct Upnp_State_Var_Request variable; const char *err_str; int err_code; /* get var name */ if (get_var_name(xml_doc, var_name) != 0) { send_error_response(info, SOAP_INVALID_VAR, Soap_Invalid_Var, request); return; } /* get info for event */ err_code = get_device_info(iface, request, 1, xml_doc, info->foreign_sockaddr.ss_family, variable.DevUDN, variable.ServiceID, &soap_event_callback, &cookie); if (err_code != 0) { send_error_response(info, SOAP_INVALID_VAR, Soap_Invalid_Var, request); return; } linecopy(variable.ErrStr, ""); variable.ErrCode = UPNP_E_SUCCESS; namecopy(variable.StateVarName, var_name); variable.CurrentVal = NULL; variable.CtrlPtIPAddr = info->foreign_sockaddr; /* send event */ soap_event_callback(UPNP_CONTROL_GET_VAR_REQUEST, &variable, cookie); UpnpPrintf(UPNP_INFO, SOAP, __FILE__, __LINE__, "Return from callback for var request\n"); /* validate, and handle result */ if (variable.CurrentVal == NULL) { send_error_response(info, SOAP_INVALID_VAR, Soap_Invalid_Var, request); return; } if (variable.ErrCode != UPNP_E_SUCCESS) { if (strlen(variable.ErrStr) > 0) { err_code = SOAP_INVALID_VAR; err_str = Soap_Invalid_Var; } else { err_code = variable.ErrCode; err_str = variable.ErrStr; } send_error_response(info, err_code, err_str, request); return; } /* send response */ send_var_query_response(info, variable.CurrentVal, request); ixmlFreeDOMString(variable.CurrentVal); }
/*! * \brief Sends the SOAP action response. */ static UPNP_INLINE void send_action_response( /*! [in] Socket info. */ SOCKINFO *info, /*! [in] The response document. */ IXML_Document *action_resp, /*! [in] Action request document. */ http_message_t *request) { char *xml_response = NULL; membuffer headers; int major, minor; int err_code; off_t content_length; int ret_code; int timeout_secs = SOAP_TIMEOUT; static const char *start_body = "<?xml version=\"1.0\"?>" "<s:Envelope xmlns:s=\"http://schemas.xmlsoap." "org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap." "org/soap/encoding/\"><s:Body>\n"; static const char *end_body = "</s:Body> </s:Envelope>"; /* init */ http_CalcResponseVersion(request->major_version, request->minor_version, &major, &minor); membuffer_init(&headers); err_code = UPNP_E_OUTOF_MEMORY; /* one error only */ /* get xml */ xml_response = ixmlPrintNode((IXML_Node *) action_resp); if (!xml_response) goto error_handler; content_length = (off_t)(strlen(start_body) + strlen(xml_response) + strlen(end_body)); /* make headers */ if (http_MakeMessage(&headers, major, minor, "RNsDsSXcc", HTTP_OK, /* status code */ content_length, ContentTypeHeader, "EXT:\r\n", X_USER_AGENT) != 0) { goto error_handler; } /* send whole msg */ ret_code = http_SendMessage( info, &timeout_secs, "bbbb", headers.buf, headers.length, start_body, strlen(start_body), xml_response, strlen(xml_response), end_body, strlen(end_body)); if (ret_code != 0) { UpnpPrintf(UPNP_INFO, SOAP, __FILE__, __LINE__, "Failed to send response: err code = %d\n", ret_code); } err_code = 0; error_handler: ixmlFreeDOMString(xml_response); membuffer_destroy(&headers); if (err_code != 0) { /* only one type of error to worry about - out of mem */ send_error_response(info, SOAP_ACTION_FAILED, "Out of memory", request); } }
/******************************************************************************** * SampleUtil_PrintEvent * * Description: * Prints callback event structure details. * * Parameters: * EventType -- The type of callback event * Event -- The callback event structure * ********************************************************************************/ int SampleUtil_PrintEvent( IN Upnp_EventType EventType, IN void *Event ) { ithread_mutex_lock( &display_mutex ); SampleUtil_Print ( "\n\n\n======================================================================\n" ); SampleUtil_Print ( "----------------------------------------------------------------------\n" ); SampleUtil_PrintEventType( EventType ); switch ( EventType ) { /* SSDP */ case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: case UPNP_DISCOVERY_SEARCH_RESULT: { struct Upnp_Discovery *d_event = ( struct Upnp_Discovery * )Event; SampleUtil_Print( "ErrCode = %d\n", d_event->ErrCode ); SampleUtil_Print( "Expires = %d\n", d_event->Expires ); SampleUtil_Print( "DeviceId = %s\n", d_event->DeviceId ); SampleUtil_Print( "DeviceType = %s\n", d_event->DeviceType ); SampleUtil_Print( "ServiceType = %s\n", d_event->ServiceType ); SampleUtil_Print( "ServiceVer = %s\n", d_event->ServiceVer ); SampleUtil_Print( "Location = %s\n", d_event->Location ); SampleUtil_Print( "OS = %s\n", d_event->Os ); SampleUtil_Print( "Ext = %s\n", d_event->Ext ); } break; case UPNP_DISCOVERY_SEARCH_TIMEOUT: // Nothing to print out here break; /* SOAP */ case UPNP_CONTROL_ACTION_REQUEST: { struct Upnp_Action_Request *a_event = ( struct Upnp_Action_Request * )Event; char *xmlbuff = NULL; SampleUtil_Print( "ErrCode = %d\n", a_event->ErrCode ); SampleUtil_Print( "ErrStr = %s\n", a_event->ErrStr ); SampleUtil_Print( "ActionName = %s\n", a_event->ActionName ); SampleUtil_Print( "UDN = %s\n", a_event->DevUDN ); SampleUtil_Print( "ServiceID = %s\n", a_event->ServiceID ); if( a_event->ActionRequest ) { xmlbuff = ixmlPrintDocument( a_event->ActionRequest ); if( xmlbuff ) SampleUtil_Print( "ActRequest = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SampleUtil_Print( "ActRequest = (null)\n" ); } if( a_event->ActionResult ) { xmlbuff = ixmlPrintDocument( a_event->ActionResult ); if( xmlbuff ) SampleUtil_Print( "ActResult = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SampleUtil_Print( "ActResult = (null)\n" ); } } break; case UPNP_CONTROL_ACTION_COMPLETE: { struct Upnp_Action_Complete *a_event = ( struct Upnp_Action_Complete * )Event; char *xmlbuff = NULL; SampleUtil_Print( "ErrCode = %d\n", a_event->ErrCode ); SampleUtil_Print( "CtrlUrl = %s\n", a_event->CtrlUrl ); if( a_event->ActionRequest ) { xmlbuff = ixmlPrintDocument( a_event->ActionRequest ); if( xmlbuff ) SampleUtil_Print( "ActRequest = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SampleUtil_Print( "ActRequest = (null)\n" ); } if( a_event->ActionResult ) { xmlbuff = ixmlPrintDocument( a_event->ActionResult ); if( xmlbuff ) SampleUtil_Print( "ActResult = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SampleUtil_Print( "ActResult = (null)\n" ); } } break; case UPNP_CONTROL_GET_VAR_REQUEST: { struct Upnp_State_Var_Request *sv_event = ( struct Upnp_State_Var_Request * )Event; SampleUtil_Print( "ErrCode = %d\n", sv_event->ErrCode ); SampleUtil_Print( "ErrStr = %s\n", sv_event->ErrStr ); SampleUtil_Print( "UDN = %s\n", sv_event->DevUDN ); SampleUtil_Print( "ServiceID = %s\n", sv_event->ServiceID ); SampleUtil_Print( "StateVarName= %s\n", sv_event->StateVarName ); SampleUtil_Print( "CurrentVal = %s\n", sv_event->CurrentVal ); } break; case UPNP_CONTROL_GET_VAR_COMPLETE: { struct Upnp_State_Var_Complete *sv_event = ( struct Upnp_State_Var_Complete * )Event; SampleUtil_Print( "ErrCode = %d\n", sv_event->ErrCode ); SampleUtil_Print( "CtrlUrl = %s\n", sv_event->CtrlUrl ); SampleUtil_Print( "StateVarName= %s\n", sv_event->StateVarName ); SampleUtil_Print( "CurrentVal = %s\n", sv_event->CurrentVal ); } break; /* GENA */ case UPNP_EVENT_SUBSCRIPTION_REQUEST: { struct Upnp_Subscription_Request *sr_event = ( struct Upnp_Subscription_Request * )Event; SampleUtil_Print( "ServiceID = %s\n", sr_event->ServiceId ); SampleUtil_Print( "UDN = %s\n", sr_event->UDN ); SampleUtil_Print( "SID = %s\n", sr_event->Sid ); } break; case UPNP_EVENT_RECEIVED: { struct Upnp_Event *e_event = ( struct Upnp_Event * )Event; char *xmlbuff = NULL; SampleUtil_Print( "SID = %s\n", e_event->Sid ); SampleUtil_Print( "EventKey = %d\n", e_event->EventKey ); xmlbuff = ixmlPrintDocument( e_event->ChangedVariables ); SampleUtil_Print( "ChangedVars = %s\n", xmlbuff ); ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } break; case UPNP_EVENT_RENEWAL_COMPLETE: { struct Upnp_Event_Subscribe *es_event = ( struct Upnp_Event_Subscribe * )Event; SampleUtil_Print( "SID = %s\n", es_event->Sid ); SampleUtil_Print( "ErrCode = %d\n", es_event->ErrCode ); SampleUtil_Print( "TimeOut = %d\n", es_event->TimeOut ); } break; case UPNP_EVENT_SUBSCRIBE_COMPLETE: case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: { struct Upnp_Event_Subscribe *es_event = ( struct Upnp_Event_Subscribe * )Event; SampleUtil_Print( "SID = %s\n", es_event->Sid ); SampleUtil_Print( "ErrCode = %d\n", es_event->ErrCode ); SampleUtil_Print( "PublisherURL= %s\n", es_event->PublisherUrl ); SampleUtil_Print( "TimeOut = %d\n", es_event->TimeOut ); } break; case UPNP_EVENT_AUTORENEWAL_FAILED: case UPNP_EVENT_SUBSCRIPTION_EXPIRED: { struct Upnp_Event_Subscribe *es_event = ( struct Upnp_Event_Subscribe * )Event; SampleUtil_Print( "SID = %s\n", es_event->Sid ); SampleUtil_Print( "ErrCode = %d\n", es_event->ErrCode ); SampleUtil_Print( "PublisherURL= %s\n", es_event->PublisherUrl ); SampleUtil_Print( "TimeOut = %d\n", es_event->TimeOut ); } break; } SampleUtil_Print ( "----------------------------------------------------------------------\n" ); SampleUtil_Print ( "======================================================================\n\n\n\n" ); ithread_mutex_unlock( &display_mutex ); return ( 0 ); }
void upnp_igd_print_event(upnp_igd_context *igd_ctxt, upnp_igd_print_level level, Upnp_EventType EventType, void *Event) { ithread_mutex_lock(&igd_ctxt->print_mutex); upnp_igd_print(igd_ctxt, level, "======================================================================"); upnp_igd_print_event_type(igd_ctxt, level, EventType); switch (EventType) { /* SSDP */ case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: case UPNP_DISCOVERY_SEARCH_RESULT: { struct Upnp_Discovery *d_event = (struct Upnp_Discovery *)Event; upnp_igd_print(igd_ctxt, level, "ErrCode = %s(%d)", UpnpGetErrorMessage(d_event->ErrCode), d_event->ErrCode); upnp_igd_print(igd_ctxt, level, "Expires = %d", d_event->Expires); upnp_igd_print(igd_ctxt, level, "DeviceId = %s", d_event->DeviceId); upnp_igd_print(igd_ctxt, level, "DeviceType = %s", d_event->DeviceType); upnp_igd_print(igd_ctxt, level, "ServiceType = %s", d_event->ServiceType); upnp_igd_print(igd_ctxt, level, "ServiceVer = %s", d_event->ServiceVer); upnp_igd_print(igd_ctxt, level, "Location = %s", d_event->Location); upnp_igd_print(igd_ctxt, level, "OS = %s", d_event->Os); upnp_igd_print(igd_ctxt, level, "Ext = %s", d_event->Ext); break; } case UPNP_DISCOVERY_SEARCH_TIMEOUT: /* Nothing to print out here */ break; /* SOAP */ case UPNP_CONTROL_ACTION_REQUEST: { struct Upnp_Action_Request *a_event = (struct Upnp_Action_Request *)Event; char *xmlbuff = NULL; upnp_igd_print(igd_ctxt, level, "ErrCode = %s(%d)", UpnpGetErrorMessage(a_event->ErrCode), a_event->ErrCode); upnp_igd_print(igd_ctxt, level, "ErrStr = %s", a_event->ErrStr); upnp_igd_print(igd_ctxt, level, "ActionName = %s", a_event->ActionName); upnp_igd_print(igd_ctxt, level, "UDN = %s", a_event->DevUDN); upnp_igd_print(igd_ctxt, level, "ServiceID = %s", a_event->ServiceID); if (a_event->ActionRequest) { xmlbuff = ixmlPrintNode((IXML_Node *)a_event->ActionRequest); if (xmlbuff) { upnp_igd_print(igd_ctxt, level, "ActRequest = %s", xmlbuff); ixmlFreeDOMString(xmlbuff); } xmlbuff = NULL; } else { upnp_igd_print(igd_ctxt, level, "ActRequest = (null)"); } if (a_event->ActionResult) { xmlbuff = ixmlPrintNode((IXML_Node *)a_event->ActionResult); if (xmlbuff) { upnp_igd_print(igd_ctxt, level, "ActResult = %s", xmlbuff); ixmlFreeDOMString(xmlbuff); } xmlbuff = NULL; } else { upnp_igd_print(igd_ctxt, level, "ActResult = (null)"); } break; } case UPNP_CONTROL_ACTION_COMPLETE: { struct Upnp_Action_Complete *a_event = (struct Upnp_Action_Complete *)Event; char *xmlbuff = NULL; upnp_igd_print(igd_ctxt, level, "ErrCode = %s(%d)", UpnpGetErrorMessage(a_event->ErrCode), a_event->ErrCode); upnp_igd_print(igd_ctxt, level, "CtrlUrl = %s", a_event->CtrlUrl); if (a_event->ActionRequest) { xmlbuff = ixmlPrintNode((IXML_Node *)a_event->ActionRequest); if (xmlbuff) { upnp_igd_print(igd_ctxt, level, "ActRequest = %s", xmlbuff); ixmlFreeDOMString(xmlbuff); } xmlbuff = NULL; } else { upnp_igd_print(igd_ctxt, level, "ActRequest = (null)"); } if (a_event->ActionResult) { xmlbuff = ixmlPrintNode((IXML_Node *)a_event->ActionResult); if (xmlbuff) { upnp_igd_print(igd_ctxt, level, "ActResult = %s", xmlbuff); ixmlFreeDOMString(xmlbuff); } xmlbuff = NULL; } else { upnp_igd_print(igd_ctxt, level, "ActResult = (null)"); } break; } case UPNP_CONTROL_GET_VAR_REQUEST: { struct Upnp_State_Var_Request *sv_event = (struct Upnp_State_Var_Request *)Event; upnp_igd_print(igd_ctxt, level, "ErrCode = %s(%d)", UpnpGetErrorMessage(sv_event->ErrCode), sv_event->ErrCode); upnp_igd_print(igd_ctxt, level, "ErrStr = %s", sv_event->ErrStr); upnp_igd_print(igd_ctxt, level, "UDN = %s", sv_event->DevUDN); upnp_igd_print(igd_ctxt, level, "ServiceID = %s", sv_event->ServiceID); upnp_igd_print(igd_ctxt, level, "StateVarName= %s", sv_event->StateVarName); upnp_igd_print(igd_ctxt, level, "CurrentVal = %s", sv_event->CurrentVal); break; } case UPNP_CONTROL_GET_VAR_COMPLETE: { struct Upnp_State_Var_Complete *sv_event = (struct Upnp_State_Var_Complete *)Event; upnp_igd_print(igd_ctxt, level, "ErrCode = %s(%d)", UpnpGetErrorMessage(sv_event->ErrCode), sv_event->ErrCode); upnp_igd_print(igd_ctxt, level, "CtrlUrl = %s", sv_event->CtrlUrl); upnp_igd_print(igd_ctxt, level, "StateVarName= %s", sv_event->StateVarName); upnp_igd_print(igd_ctxt, level, "CurrentVal = %s", sv_event->CurrentVal); break; } /* GENA */ case UPNP_EVENT_SUBSCRIPTION_REQUEST: { struct Upnp_Subscription_Request *sr_event = (struct Upnp_Subscription_Request *)Event; upnp_igd_print(igd_ctxt, level, "ServiceID = %s", sr_event->ServiceId); upnp_igd_print(igd_ctxt, level, "UDN = %s", sr_event->UDN); upnp_igd_print(igd_ctxt, level, "SID = %s", sr_event->Sid); break; } case UPNP_EVENT_RECEIVED: { struct Upnp_Event *e_event = (struct Upnp_Event *)Event; char *xmlbuff = NULL; upnp_igd_print(igd_ctxt, level, "SID = %s", e_event->Sid); upnp_igd_print(igd_ctxt, level, "EventKey = %d", e_event->EventKey); xmlbuff = ixmlPrintNode((IXML_Node *)e_event->ChangedVariables); upnp_igd_print(igd_ctxt, level, "ChangedVars = %s", xmlbuff); ixmlFreeDOMString(xmlbuff); xmlbuff = NULL; break; } case UPNP_EVENT_RENEWAL_COMPLETE: { struct Upnp_Event_Subscribe *es_event = (struct Upnp_Event_Subscribe *)Event; upnp_igd_print(igd_ctxt, level, "SID = %s", es_event->Sid); upnp_igd_print(igd_ctxt, level, "ErrCode = %s(%d)", UpnpGetErrorMessage(es_event->ErrCode), es_event->ErrCode); upnp_igd_print(igd_ctxt, level, "TimeOut = %d", es_event->TimeOut); break; } case UPNP_EVENT_SUBSCRIBE_COMPLETE: case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: { struct Upnp_Event_Subscribe *es_event = (struct Upnp_Event_Subscribe *)Event; upnp_igd_print(igd_ctxt, level, "SID = %s", es_event->Sid); upnp_igd_print(igd_ctxt, level, "ErrCode = %s(%d)", UpnpGetErrorMessage(es_event->ErrCode), es_event->ErrCode); upnp_igd_print(igd_ctxt, level, "PublisherURL= %s", es_event->PublisherUrl); upnp_igd_print(igd_ctxt, level, "TimeOut = %d", es_event->TimeOut); break; } case UPNP_EVENT_AUTORENEWAL_FAILED: case UPNP_EVENT_SUBSCRIPTION_EXPIRED: { struct Upnp_Event_Subscribe *es_event = (struct Upnp_Event_Subscribe *)Event; upnp_igd_print(igd_ctxt, level, "SID = %s", es_event->Sid); upnp_igd_print(igd_ctxt, level, "ErrCode = %s(%d)", UpnpGetErrorMessage(es_event->ErrCode), es_event->ErrCode); upnp_igd_print(igd_ctxt, level, "PublisherURL= %s", es_event->PublisherUrl); upnp_igd_print(igd_ctxt, level, "TimeOut = %d", es_event->TimeOut); break; } } upnp_igd_print(igd_ctxt, level,"======================================================================"); ithread_mutex_unlock(&igd_ctxt->print_mutex); }
int genaInitNotifyExt( UpnpDevice_Handle device_handle, char *UDN, char *servId, IXML_Document *PropSet, const Upnp_SID sid) { int ret = GENA_SUCCESS; int line = 0; int *reference_count = NULL; char *UDN_copy = NULL; char *servId_copy = NULL; DOMString propertySet = NULL; char *headers = NULL; notify_thread_struct *thread_struct = NULL; subscription *sub = NULL; service_info *service = NULL; struct Handle_Info *handle_info; ThreadPoolJob job; memset(&job, 0, sizeof(job)); UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA BEGIN INITIAL NOTIFY EXT"); reference_count = (int *)malloc(sizeof (int)); if (reference_count == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } *reference_count = 0; UDN_copy = strdup(UDN); if (UDN_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } servId_copy = strdup(servId); if( servId_copy == NULL ) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } HandleLock(); if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) { line = __LINE__; ret = GENA_E_BAD_HANDLE; goto ExitFunction; } service = FindServiceId(&handle_info->ServiceTable, servId, UDN); if (service == NULL) { line = __LINE__; ret = GENA_E_BAD_SERVICE; goto ExitFunction; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "FOUND SERVICE IN INIT NOTFY EXT: UDN %s, ServID: %s", UDN, servId); sub = GetSubscriptionSID(sid, service); if (sub == NULL || sub->active) { line = __LINE__; ret = GENA_E_BAD_SID; goto ExitFunction; } UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "FOUND SUBSCRIPTION IN INIT NOTIFY EXT: SID %s", sid); sub->active = 1; if (PropSet == 0) { line = __LINE__; ret = GENA_SUCCESS; goto ExitFunction; } propertySet = ixmlPrintNode((IXML_Node *)PropSet); if (propertySet == NULL) { line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto ExitFunction; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENERATED PROPERTY SET IN INIT EXT NOTIFY: %s", propertySet); headers = AllocGenaHeaders(propertySet); if (headers == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } /* schedule thread for initial notification */ thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct)); if (thread_struct == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } else { *reference_count = 1; thread_struct->servId = servId_copy; thread_struct->UDN = UDN_copy; thread_struct->headers = headers; thread_struct->propertySet = propertySet; memset(thread_struct->sid, 0, sizeof(thread_struct->sid)); strncpy(thread_struct->sid, sid, sizeof(thread_struct->sid) - 1); thread_struct->eventKey = sub->eventKey++; thread_struct->reference_count = reference_count; thread_struct->device_handle = device_handle; TPJobInit(&job, (start_routine)genaNotifyThread, thread_struct); TPJobSetFreeFunction(&job, (free_routine)free_notify_struct); TPJobSetPriority(&job, MED_PRIORITY); ret = ThreadPoolAdd(&gSendThreadPool, &job, NULL); if (ret != 0) { if (ret == EOUTOFMEM) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } } else { line = __LINE__; ret = GENA_SUCCESS; } } ExitFunction: if (ret != GENA_SUCCESS || PropSet == 0) { free(thread_struct); free(headers); ixmlFreeDOMString(propertySet); free(servId_copy); free(UDN_copy); free(reference_count); } HandleUnlock(); UpnpPrintf(UPNP_INFO, GENA, __FILE__, line, "GENA END INITIAL NOTIFY EXT, ret = %d", ret); return ret; }
/* Function:Prints a callback event type as a string; INPUT: S -- The callback event; SUCCESS:0; ERROR:-1; */ int PrintEvent( IN Upnp_EventType EventType, IN void *Event ) { ithread_mutex_lock( &display_mutex ); SA_Print ( "\n\n\n======================================================================\n" ); SA_Print ( "----------------------------------------------------------------------\n" ); PrintEventType( EventType ); switch ( EventType ) { /* SSDP */ case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: case UPNP_DISCOVERY_SEARCH_RESULT: { struct Upnp_Discovery *d_event = ( struct Upnp_Discovery * )Event; SA_Print( "ErrCode = %d\n", d_event->ErrCode ); SA_Print( "Expires = %d\n", d_event->Expires ); SA_Print( "DeviceId = %s\n", d_event->DeviceId ); SA_Print( "DeviceType = %s\n", d_event->DeviceType ); SA_Print( "ServiceType = %s\n", d_event->ServiceType ); SA_Print( "ServiceVer = %s\n", d_event->ServiceVer ); SA_Print( "Location = %s\n", d_event->Location ); SA_Print( "OS = %s\n", d_event->Os ); SA_Print( "Ext = %s\n", d_event->Ext ); sem_post(&ServerSem); } break; case UPNP_DISCOVERY_SEARCH_TIMEOUT: // Nothing to print out here break; /* SOAP */ case UPNP_CONTROL_ACTION_REQUEST: { struct Upnp_Action_Request *a_event = ( struct Upnp_Action_Request * )Event; char *xmlbuff = NULL; SA_Print( "ErrCode = %d\n", a_event->ErrCode ); SA_Print( "ErrStr = %s\n", a_event->ErrStr ); SA_Print( "ActionName = %s\n", a_event->ActionName ); SA_Print( "UDN = %s\n", a_event->DevUDN ); SA_Print( "ServiceID = %s\n", a_event->ServiceID ); if( a_event->ActionRequest ) { xmlbuff = ixmlPrintNode( ( IXML_Node * ) a_event->ActionRequest ); if( xmlbuff ) SA_Print( "ActRequest = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SA_Print( "ActRequest = (null)\n" ); } if( a_event->ActionResult ) { xmlbuff = ixmlPrintNode( ( IXML_Node * ) a_event->ActionResult ); if( xmlbuff ) SA_Print( "ActResult = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SA_Print( "ActResult = (null)\n" ); } } break; case UPNP_CONTROL_ACTION_COMPLETE: { struct Upnp_Action_Complete *a_event = ( struct Upnp_Action_Complete * )Event; char *xmlbuff = NULL; SA_Print( "ErrCode = %d\n", a_event->ErrCode ); SA_Print( "CtrlUrl = %s\n", a_event->CtrlUrl ); if( a_event->ActionRequest ) { xmlbuff = ixmlPrintNode( ( IXML_Node * ) a_event->ActionRequest ); if( xmlbuff ) SA_Print( "ActRequest = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SA_Print( "ActRequest = (null)\n" ); } if( a_event->ActionResult ) { xmlbuff = ixmlPrintNode( ( IXML_Node * ) a_event->ActionResult ); if( xmlbuff ) SA_Print( "ActResult = %s\n", xmlbuff ); if(strncmp(NowCommand,"Browse",6) == 0) { FNode *Now = (FNode *)malloc(sizeof(FNode)); FNode *Last = NowNode; NowNode -> LeftChild = Now; IXML_Document *document = ixmlParseBuffer(XMLP_GetFirstDocumentItem(a_event->ActionResult,"Result")); IXML_NodeList *ContainerList = ixmlElement_getElementsByTagName( ( IXML_Element * ) document, "container" ); IXML_Node *ContainerNode = ixmlNodeList_item(ContainerList,0); IXML_NodeList *FileList = ixmlElement_getElementsByTagName( ( IXML_Element * ) document, "item" ); IXML_Node *FileNode = ixmlNodeList_item(FileList,0); int ContainerLength = ixmlNodeList_length(ContainerList); int FileLength = ixmlNodeList_length(FileList); if(ContainerLength) { int i=0; for(i=0;i<ContainerLength;i++) { char *Container_id = ixmlElement_getAttribute(( IXML_Element * ) ContainerNode,"id"); IXML_NodeList *Title = ixmlElement_getElementsByTagName( ( IXML_Element * ) ContainerNode, "dc:title" ); IXML_Node *TitleNode = ixmlNodeList_item(Title,0); TitleNode= ixmlNode_getFirstChild(TitleNode); char *TitleName = strdup(ixmlNode_getNodeValue(TitleNode)); SA_Print("%s %s\n", Container_id,TitleName); Now -> Type = 0; strcpy(Now -> Name,TitleName); strcpy(Now -> Url,Container_id); Now -> LeftChild = NULL; Now -> Brother = NULL; Now -> Brother = (FNode *)malloc(sizeof(FNode)); Last = Now; Now = Now -> Brother; ContainerNode = ixmlNode_getNextSibling(ContainerNode); } } if(FileLength) { int j=0; for(j=0;j<FileLength;j++) { IXML_NodeList *Path = ixmlElement_getElementsByTagName( ( IXML_Element * ) FileNode, "res" ); IXML_Node *PathNode = ixmlNodeList_item(Path,0); PathNode= ixmlNode_getFirstChild(PathNode); char *PathName = strdup(ixmlNode_getNodeValue(PathNode)); IXML_NodeList *Title = ixmlElement_getElementsByTagName( ( IXML_Element * ) FileNode, "dc:title" ); IXML_Node *TitleNode = ixmlNodeList_item(Title,0); TitleNode= ixmlNode_getFirstChild(TitleNode); char *TitleName = strdup(ixmlNode_getNodeValue(TitleNode)); SA_Print( "%s %s\n", PathName,TitleName); Now -> Type = 1; strcpy(Now -> Name,TitleName); strcpy(Now -> Url,PathName); Now -> LeftChild = NULL; Now -> Brother = NULL; Now -> Brother = (FNode *)malloc(sizeof(FNode)); Last = Now; Now = Now -> Brother; FileNode = ixmlNode_getNextSibling(FileNode); } } Last -> Brother = NULL; Last -> LeftChild = NULL; free(Now); Now = NULL; } if( xmlbuff ) { ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } } else { SA_Print( "ActResult = (null)\n" ); } sem_post(&BrowseSem); } break; /* GENA */ case UPNP_EVENT_SUBSCRIPTION_REQUEST: { struct Upnp_Subscription_Request *sr_event = ( struct Upnp_Subscription_Request * )Event; SA_Print( "ServiceID = %s\n", sr_event->ServiceId ); SA_Print( "UDN = %s\n", sr_event->UDN ); SA_Print( "SID = %s\n", sr_event->Sid ); } break; case UPNP_EVENT_RECEIVED: break; case UPNP_EVENT_RENEWAL_COMPLETE: { struct Upnp_Event_Subscribe *es_event = ( struct Upnp_Event_Subscribe * )Event; SA_Print( "SID = %s\n", es_event->Sid ); SA_Print( "ErrCode = %d\n", es_event->ErrCode ); SA_Print( "TimeOut = %d\n", es_event->TimeOut ); } break; case UPNP_EVENT_SUBSCRIBE_COMPLETE: case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: { struct Upnp_Event_Subscribe *es_event = ( struct Upnp_Event_Subscribe * )Event; SA_Print( "SID = %s\n", es_event->Sid ); SA_Print( "ErrCode = %d\n", es_event->ErrCode ); SA_Print( "PublisherURL= %s\n", es_event->PublisherUrl ); SA_Print( "TimeOut = %d\n", es_event->TimeOut ); } break; case UPNP_EVENT_AUTORENEWAL_FAILED: case UPNP_EVENT_SUBSCRIPTION_EXPIRED: { struct Upnp_Event_Subscribe *es_event = ( struct Upnp_Event_Subscribe * )Event; SA_Print( "SID = %s\n", es_event->Sid ); SA_Print( "ErrCode = %d\n", es_event->ErrCode ); SA_Print( "PublisherURL= %s\n", es_event->PublisherUrl ); SA_Print( "TimeOut = %d\n", es_event->TimeOut ); } break; default: break; } SA_Print ( "----------------------------------------------------------------------\n" ); SA_Print ( "======================================================================\n\n\n\n" ); ithread_mutex_unlock( &display_mutex ); return ( 0 ); }
/*! * \brief Processes the request and returns the result in the output parameters. * * \return * \li \c HTTP_BAD_REQUEST * \li \c HTTP_INTERNAL_SERVER_ERROR * \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE * \li \c HTTP_FORBIDDEN * \li \c HTTP_NOT_FOUND * \li \c HTTP_NOT_ACCEPTABLE * \li \c HTTP_OK */ static int process_request( /*! [in] HTTP Request message. */ http_message_t *req, /*! [out] Tpye of response. */ enum resp_type *rtype, /*! [out] Headers. */ membuffer *headers, /*! [out] Get filename from request document. */ membuffer *filename, /*! [out] Xml alias document from the request document. */ struct xml_alias_t *alias, /*! [out] Send Instruction object where the response is set up. */ struct SendInstruction *RespInstr) { int code; int err_code; char *request_doc; struct File_Info finfo; int using_alias; int using_virtual_dir; uri_type *url; const char *temp_str; int resp_major; int resp_minor; int alias_grabbed; size_t dummy; const char *extra_headers = NULL; print_http_headers(req); url = &req->uri; assert(req->method == HTTPMETHOD_GET || req->method == HTTPMETHOD_HEAD || req->method == HTTPMETHOD_POST || req->method == HTTPMETHOD_SIMPLEGET); /* init */ memset(&finfo, 0, sizeof(finfo)); request_doc = NULL; finfo.content_type = NULL; alias_grabbed = FALSE; err_code = HTTP_INTERNAL_SERVER_ERROR; /* default error */ using_virtual_dir = FALSE; using_alias = FALSE; http_CalcResponseVersion(req->major_version, req->minor_version, &resp_major, &resp_minor); /* */ /* remove dots */ /* */ request_doc = malloc(url->pathquery.size + 1); if (request_doc == NULL) { goto error_handler; /* out of mem */ } memcpy(request_doc, url->pathquery.buff, url->pathquery.size); request_doc[url->pathquery.size] = '\0'; dummy = url->pathquery.size; remove_escaped_chars(request_doc, &dummy); code = remove_dots(request_doc, url->pathquery.size); if (code != 0) { err_code = HTTP_FORBIDDEN; goto error_handler; } if (*request_doc != '/') { /* no slash */ err_code = HTTP_BAD_REQUEST; goto error_handler; } if (isFileInVirtualDir(request_doc)) { using_virtual_dir = TRUE; RespInstr->IsVirtualFile = 1; if (membuffer_assign_str(filename, request_doc) != 0) { goto error_handler; } } else { /* try using alias */ if (is_valid_alias(&gAliasDoc)) { alias_grab(alias); alias_grabbed = TRUE; using_alias = get_alias(request_doc, alias, &finfo); if (using_alias == TRUE) { finfo.content_type = ixmlCloneDOMString("text/xml"); if (finfo.content_type == NULL) { goto error_handler; } } } } if (using_virtual_dir) { if (req->method != HTTPMETHOD_POST) { /* get file info */ if (virtualDirCallback. get_info(filename->buf, &finfo) != 0) { err_code = HTTP_NOT_FOUND; goto error_handler; } /* try index.html if req is a dir */ if (finfo.is_directory) { if (filename->buf[filename->length - 1] == '/') { temp_str = "index.html"; } else { temp_str = "/index.html"; } if (membuffer_append_str(filename, temp_str) != 0) { goto error_handler; } /* get info */ if ((virtualDirCallback. get_info(filename->buf, &finfo) != UPNP_E_SUCCESS) || finfo.is_directory) { err_code = HTTP_NOT_FOUND; goto error_handler; } } /* not readable */ if (!finfo.is_readable) { err_code = HTTP_FORBIDDEN; goto error_handler; } /* finally, get content type */ /* if ( get_content_type(filename->buf, &content_type) != 0 ) */ /*{ */ /* goto error_handler; */ /* } */ } } else if (!using_alias) { if (gDocumentRootDir.length == 0) { goto error_handler; } /* */ /* get file name */ /* */ /* filename str */ if (membuffer_assign_str(filename, gDocumentRootDir.buf) != 0 || membuffer_append_str(filename, request_doc) != 0) { goto error_handler; /* out of mem */ } /* remove trailing slashes */ while (filename->length > 0 && filename->buf[filename->length - 1] == '/') { membuffer_delete(filename, filename->length - 1, 1); } if (req->method != HTTPMETHOD_POST) { /* get info on file */ if (get_file_info(filename->buf, &finfo) != 0) { err_code = HTTP_NOT_FOUND; goto error_handler; } /* try index.html if req is a dir */ if (finfo.is_directory) { if (filename->buf[filename->length - 1] == '/') { temp_str = "index.html"; } else { temp_str = "/index.html"; } if (membuffer_append_str(filename, temp_str) != 0) { goto error_handler; } /* get info */ if (get_file_info(filename->buf, &finfo) != 0 || finfo.is_directory) { err_code = HTTP_NOT_FOUND; goto error_handler; } } /* not readable */ if (!finfo.is_readable) { err_code = HTTP_FORBIDDEN; goto error_handler; } } /* finally, get content type */ /* if ( get_content_type(filename->buf, &content_type) != 0 ) */ /* { */ /* goto error_handler; */ /* } */ } RespInstr->ReadSendSize = finfo.file_length; /* Check other header field. */ if ((code = CheckOtherHTTPHeaders(req, RespInstr, finfo.file_length)) != HTTP_OK) { err_code = code; goto error_handler; } if (req->method == HTTPMETHOD_POST) { *rtype = RESP_POST; err_code = HTTP_OK; goto error_handler; } /*extra_headers = UpnpFileInfo_get_ExtraHeaders(finfo); */ if (!extra_headers) { extra_headers = ""; } /* Check if chunked encoding should be used. */ if (using_virtual_dir && finfo.file_length == UPNP_USING_CHUNKED) { /* Chunked encoding is only supported by HTTP 1.1 clients */ if (resp_major == 1 && resp_minor == 1) { RespInstr->IsChunkActive = 1; } else { /* The virtual callback indicates that we should use * chunked encoding however the client doesn't support * it. Return with an internal server error. */ err_code = HTTP_NOT_ACCEPTABLE; goto error_handler; } } if (RespInstr->IsRangeActive && RespInstr->IsChunkActive) { /* Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */ /* Transfer-Encoding: chunked */ if (http_MakeMessage(headers, resp_major, resp_minor, "R" "T" "GKLD" "s" "tcS" "Xc" "sCc", HTTP_PARTIAL_CONTENT, /* status code */ finfo.content_type, /* content type */ RespInstr, /* range info */ RespInstr, /* language info */ "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT, extra_headers) != 0) { goto error_handler; } } else if (RespInstr->IsRangeActive && !RespInstr->IsChunkActive) { /* Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */ if (http_MakeMessage(headers, resp_major, resp_minor, "R" "N" "T" "GLD" "s" "tcS" "Xc" "sCc", HTTP_PARTIAL_CONTENT, /* status code */ RespInstr->ReadSendSize, /* content length */ finfo.content_type, /* content type */ RespInstr, /* range info */ RespInstr, /* language info */ "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT, extra_headers) != 0) { goto error_handler; } } else if (!RespInstr->IsRangeActive && RespInstr->IsChunkActive) { /* Transfer-Encoding: chunked */ if (http_MakeMessage(headers, resp_major, resp_minor, "RK" "TLD" "s" "tcS" "Xc" "sCc", HTTP_OK, /* status code */ finfo.content_type, /* content type */ RespInstr, /* language info */ "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT, extra_headers) != 0) { goto error_handler; } } else { /* !RespInstr->IsRangeActive && !RespInstr->IsChunkActive */ if (RespInstr->ReadSendSize >= 0) { if (http_MakeMessage(headers, resp_major, resp_minor, "R" "N" "TLD" "s" "tcS" "Xc" "sCc", HTTP_OK, /* status code */ RespInstr->ReadSendSize, /* content length */ finfo.content_type, /* content type */ RespInstr, /* language info */ "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT, extra_headers) != 0) { goto error_handler; } } else { if (http_MakeMessage(headers, resp_major, resp_minor, "R" "TLD" "s" "tcS" "Xc" "sCc", HTTP_OK, /* status code */ finfo.content_type, /* content type */ RespInstr, /* language info */ "LAST-MODIFIED: ", &finfo.last_modified, X_USER_AGENT, extra_headers) != 0) { goto error_handler; } } } if (req->method == HTTPMETHOD_HEAD) { *rtype = RESP_HEADERS; } else if (using_alias) { /* GET xml */ *rtype = RESP_XMLDOC; } else if (using_virtual_dir) { *rtype = RESP_WEBDOC; } else { /* GET filename */ *rtype = RESP_FILEDOC; } /* simple get http 0.9 as specified in http 1.0 */ /* don't send headers */ if (req->method == HTTPMETHOD_SIMPLEGET) { membuffer_destroy(headers); } err_code = HTTP_OK; error_handler: free(request_doc); ixmlFreeDOMString(finfo.content_type); if (err_code != HTTP_OK && alias_grabbed) { alias_release(alias); } return err_code; }
/**************************************************************************** * 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; }
/* We take ownership of propertySet and will free it */ static int genaNotifyAllCommon( UpnpDevice_Handle device_handle, char *UDN, char *servId, DOMString propertySet) { int ret = GENA_SUCCESS; int line = 0; int *reference_count = NULL; char *UDN_copy = NULL; char *servId_copy = NULL; char *headers = NULL; notify_thread_struct *thread_struct = NULL; subscription *finger = NULL; service_info *service = NULL; struct Handle_Info *handle_info; UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA BEGIN NOTIFY ALL COMMON"); /* Keep this allocation first */ reference_count = (int *)malloc(sizeof (int)); if (reference_count == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } *reference_count = 0; UDN_copy = strdup(UDN); if (UDN_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } servId_copy = strdup(servId); if( servId_copy == NULL ) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } headers = AllocGenaHeaders(propertySet); if (headers == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } HandleLock(); if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) { line = __LINE__; ret = GENA_E_BAD_HANDLE; } else { service = FindServiceId(&handle_info->ServiceTable, servId, UDN); if (service != NULL) { finger = GetFirstSubscription(service); while (finger) { ThreadPoolJob *job = NULL; ListNode *node; thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct)); if (thread_struct == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; break; } (*reference_count)++; thread_struct->reference_count = reference_count; thread_struct->UDN = UDN_copy; thread_struct->servId = servId_copy; thread_struct->headers = headers; thread_struct->propertySet = propertySet; memset(thread_struct->sid, 0, sizeof(thread_struct->sid)); strncpy(thread_struct->sid, finger->sid, sizeof(thread_struct->sid) - 1); thread_struct->ctime = time(0); thread_struct->device_handle = device_handle; maybeDiscardEvents(&finger->outgoing); job = (ThreadPoolJob *)malloc(sizeof(ThreadPoolJob)); if (job == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; break; } memset(job, 0, sizeof(ThreadPoolJob)); TPJobInit(job, (start_routine)genaNotifyThread, thread_struct); TPJobSetFreeFunction(job, (free_routine)free_notify_struct); TPJobSetPriority(job, MED_PRIORITY); node = ListAddTail(&finger->outgoing, job); /* If there is only one element on the list (which we just added), need to kickstart the threadpool */ if (ListSize(&finger->outgoing) == 1) { ret = ThreadPoolAdd(&gSendThreadPool, job, NULL); if (ret != 0) { line = __LINE__; if (ret == EOUTOFMEM) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } break; } if (node) { ((ThreadPoolJob *)(node->item))->jobId = STALE_JOBID; } } finger = GetNextSubscription(service, finger); } } else { line = __LINE__; ret = GENA_E_BAD_SERVICE; } } ExitFunction: /* The only case where we want to free memory here is if the struct was never queued. Else, let the normal cleanup take place. reference_count is allocated first so it's ok to do nothing if it's 0 */ if (reference_count && *reference_count == 0) { free(headers); ixmlFreeDOMString(propertySet); free(servId_copy); free(UDN_copy); free(reference_count); } HandleUnlock(); UpnpPrintf(UPNP_INFO, GENA, __FILE__, line, "GENA END NOTIFY ALL COMMON, ret = %d", ret); return ret; }
/**************************************************************************** * Function : SoapSendActionEx * * Parameters : * IN char* action_url : device contrl URL * IN char *service_type : device service type IN IXML_Document *Header: Soap header * IN IXML_Document *action_node : SOAP action node ( SOAP body) * OUT IXML_Document **response_node : SOAP response node * * Description : This function is called by UPnP API to send the SOAP * action request and waits till it gets the response from the device * pass the response to the API layer. This action is similar to the * the SoapSendAction with only difference that it allows users to * pass the SOAP header along the SOAP body ( soap action request) * * Return : int * returns UPNP_E_SUCCESS if successful else returns appropriate error * Note : ****************************************************************************/ int SoapSendActionEx( IN char *action_url, IN char *service_type, IN IXML_Document * header, IN IXML_Document * action_node, OUT IXML_Document ** response_node ) { char *xml_header_str = NULL; char *action_str = NULL; memptr name; membuffer request; membuffer responsename; int err_code; int ret_code; http_parser_t response; uri_type url; int upnp_error_code; char *upnp_error_str; int got_response = FALSE; const char *xml_start = "<s:Envelope " "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n"; const char *xml_header_start = "<s:Header>\r\n"; const char *xml_header_end = "</s:Header>\r\n"; const char *xml_body_start = "<s:Body>"; const char *xml_end = "</s:Body>\r\n" "</s:Envelope>\r\n"; size_t xml_start_len; size_t xml_header_start_len; size_t xml_header_str_len; size_t xml_header_end_len; size_t xml_body_start_len; size_t action_str_len; size_t xml_end_len; off_t content_length; *response_node = NULL; /* init */ err_code = UPNP_E_OUTOF_MEMORY; /* default error */ UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, "Inside SoapSendActionEx():" ); /* init */ membuffer_init( &request ); membuffer_init( &responsename ); /* header string */ xml_header_str = ixmlPrintNode( ( IXML_Node * ) header ); if( xml_header_str == NULL ) { goto error_handler; } /* print action */ action_str = ixmlPrintNode( ( IXML_Node * ) action_node ); if( action_str == NULL ) { goto error_handler; } /* get action name */ if( get_action_name( action_str, &name ) != 0 ) { err_code = UPNP_E_INVALID_ACTION; goto error_handler; } /* parse url */ if( http_FixStrUrl( action_url, strlen( action_url ), &url ) != 0 ) { err_code = UPNP_E_INVALID_URL; goto error_handler; } UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__, "path=%.*s, hostport=%.*s\n", (int)url.pathquery.size, url.pathquery.buff, (int)url.hostport.text.size, url.hostport.text.buff ); xml_start_len = strlen( xml_start ); xml_body_start_len = strlen( xml_body_start ); xml_end_len = strlen( xml_end ); action_str_len = strlen( action_str ); xml_header_start_len = strlen( xml_header_start ); xml_header_end_len = strlen( xml_header_end ); xml_header_str_len = strlen( xml_header_str ); /* make request msg */ request.size_inc = 50; content_length = (off_t)(xml_start_len + xml_header_start_len + xml_header_str_len + xml_header_end_len + xml_body_start_len + action_str_len + xml_end_len); if (http_MakeMessage( &request, 1, 1, "q" "N" "s" "sssbsc" "Uc" "b" "b" "b" "b" "b" "b" "b", SOAPMETHOD_POST, &url, content_length, ContentTypeHeader, "SOAPACTION: \"", service_type, "#", name.buf, name.length, "\"", xml_start, xml_start_len, xml_header_start, xml_header_start_len, xml_header_str, xml_header_str_len, xml_header_end, xml_header_end_len, xml_body_start, xml_body_start_len, action_str, action_str_len, xml_end, xml_end_len ) != 0 ) { goto error_handler; } ret_code = soap_request_and_response( &request, &url, &response ); got_response = TRUE; if( ret_code != UPNP_E_SUCCESS ) { err_code = ret_code; goto error_handler; } if( membuffer_append( &responsename, name.buf, name.length ) != 0 || membuffer_append_str( &responsename, "Response" ) != 0 ) { goto error_handler; } /* get action node from the response */ ret_code = get_response_value( &response.msg, SOAP_ACTION_RESP, responsename.buf, &upnp_error_code, ( IXML_Node ** ) response_node, &upnp_error_str ); if( ret_code == SOAP_ACTION_RESP ) { err_code = UPNP_E_SUCCESS; } else if( ret_code == SOAP_ACTION_RESP_ERROR ) { err_code = upnp_error_code; } else { err_code = ret_code; } error_handler: ixmlFreeDOMString( action_str ); ixmlFreeDOMString( xml_header_str ); membuffer_destroy( &request ); membuffer_destroy( &responsename ); if( got_response ) { httpmsg_destroy( &response.msg ); } return err_code; }