/******************************************************************************* * * 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. * ******************************************************************************/ #include "sample_util.h" #include #if !UPNP_HAVE_TOOLS # error "Need upnptools.h to compile samples ; try ./configure --enable-tools" #endif /* Function pointer to use for displaying formatted strings. Set on Initialization of device. */ int initialize = 1; print_string gPrintFun = NULL; state_update gStateUpdateFun = NULL; /*! mutex to control displaying of events */ ithread_mutex_t display_mutex; /******************************************************************************** * SampleUtil_Initialize * * Description: * Initializes the sample util. Must be called before any sample util * functions. May be called multiple times. * * Parameters: * print_function - print function to use in SampleUtil_Print * ********************************************************************************/ int SampleUtil_Initialize( print_string print_function ) { if( initialize ) { ithread_mutexattr_t attr; gPrintFun = print_function; ithread_mutexattr_init( &attr ); ithread_mutexattr_setkind_np( &attr, ITHREAD_MUTEX_RECURSIVE_NP ); ithread_mutex_init( &display_mutex, &attr ); ithread_mutexattr_destroy( &attr ); initialize = 0; } return UPNP_E_SUCCESS; } /******************************************************************************** * SampleUtil_RegisterUpdateFunction * * Description: * * Parameters: * ********************************************************************************/ int SampleUtil_RegisterUpdateFunction( state_update update_function ) { static int initialize = 1; //only intialize once if( initialize ) { gStateUpdateFun = update_function; initialize = 0; } return UPNP_E_SUCCESS; } /******************************************************************************** * SampleUtil_Finish * * Description: * Releases Resources held by sample util. * * Parameters: * ********************************************************************************/ int SampleUtil_Finish() { ithread_mutex_destroy( &display_mutex ); gPrintFun = NULL; initialize = 1; return UPNP_E_SUCCESS; } /******************************************************************************** * SampleUtil_GetElementValue * * Description: * Given a DOM node such as 11, this routine * extracts the value (e.g., 11) from the node and returns it as * a string. The string must be freed by the caller using * free. * * Parameters: * node -- The DOM node from which to extract the value * ********************************************************************************/ char * SampleUtil_GetElementValue( IN IXML_Element * element ) { IXML_Node *child = ixmlNode_getFirstChild( ( IXML_Node * ) element ); char *temp = NULL; if( ( child != 0 ) && ( ixmlNode_getNodeType( child ) == eTEXT_NODE ) ) { temp = strdup( ixmlNode_getNodeValue( child ) ); } return temp; } /******************************************************************************** * SampleUtil_GetFirstServiceList * * Description: * Given a DOM node representing a UPnP Device Description Document, * this routine parses the document and finds the first service list * (i.e., the service list for the root device). The service list * is returned as a DOM node list. * * Parameters: * node -- The DOM node from which to extract the service list * ********************************************************************************/ IXML_NodeList * SampleUtil_GetFirstServiceList( IN IXML_Document * doc ) { IXML_NodeList *ServiceList = NULL; IXML_NodeList *servlistnodelist = NULL; IXML_Node *servlistnode = NULL; servlistnodelist = ixmlDocument_getElementsByTagName( doc, "serviceList" ); if( servlistnodelist && ixmlNodeList_length( servlistnodelist ) ) { /* we only care about the first service list, from the root device */ servlistnode = ixmlNodeList_item( servlistnodelist, 0 ); /* create as list of DOM nodes */ ServiceList = ixmlElement_getElementsByTagName( ( IXML_Element * ) servlistnode, "service" ); } if( servlistnodelist ) ixmlNodeList_free( servlistnodelist ); return ServiceList; } /******************************************************************************** * SampleUtil_GetFirstDocumentItem * * Description: * Given a document node, this routine searches for the first element * named by the input string item, and returns its value as a string. * String must be freed by caller using free. * Parameters: * doc -- The DOM document from which to extract the value * item -- The item to search for * ********************************************************************************/ char * SampleUtil_GetFirstDocumentItem( IN IXML_Document * doc, IN const char *item ) { IXML_NodeList *nodeList = NULL; IXML_Node *textNode = NULL; IXML_Node *tmpNode = NULL; char *ret = NULL; nodeList = ixmlDocument_getElementsByTagName( doc, ( char * )item ); if( nodeList ) { if( ( tmpNode = ixmlNodeList_item( nodeList, 0 ) ) ) { textNode = ixmlNode_getFirstChild( tmpNode ); ret = strdup( ixmlNode_getNodeValue( textNode ) ); } } if( nodeList ) ixmlNodeList_free( nodeList ); return ret; } /******************************************************************************** * SampleUtil_GetFirstElementItem * * Description: * Given a DOM element, this routine searches for the first element * named by the input string item, and returns its value as a string. * The string must be freed using free. * Parameters: * node -- The DOM element from which to extract the value * item -- The item to search for * ********************************************************************************/ char * SampleUtil_GetFirstElementItem( IN IXML_Element * element, IN const char *item ) { IXML_NodeList *nodeList = NULL; IXML_Node *textNode = NULL; IXML_Node *tmpNode = NULL; char *ret = NULL; nodeList = ixmlElement_getElementsByTagName( element, ( char * )item ); if( nodeList == NULL ) { SampleUtil_Print( "Error finding %s in XML Node\n", item ); return NULL; } if( ( tmpNode = ixmlNodeList_item( nodeList, 0 ) ) == NULL ) { SampleUtil_Print( "Error finding %s value in XML Node\n", item ); ixmlNodeList_free( nodeList ); return NULL; } textNode = ixmlNode_getFirstChild( tmpNode ); ret = strdup( ixmlNode_getNodeValue( textNode ) ); if( !ret ) { SampleUtil_Print( "Error allocating memory for %s in XML Node\n", item ); ixmlNodeList_free( nodeList ); return NULL; } ixmlNodeList_free( nodeList ); return ret; } /******************************************************************************** * SampleUtil_PrintEventType * * Description: * Prints a callback event type as a string. * * Parameters: * S -- The callback event * ********************************************************************************/ void SampleUtil_PrintEventType( IN Upnp_EventType S ) { switch ( S ) { case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: SampleUtil_Print( "UPNP_DISCOVERY_ADVERTISEMENT_ALIVE\n" ); break; case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: SampleUtil_Print( "UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE\n" ); break; case UPNP_DISCOVERY_SEARCH_RESULT: SampleUtil_Print( "UPNP_DISCOVERY_SEARCH_RESULT\n" ); break; case UPNP_DISCOVERY_SEARCH_TIMEOUT: SampleUtil_Print( "UPNP_DISCOVERY_SEARCH_TIMEOUT\n" ); break; /* SOAP Stuff */ case UPNP_CONTROL_ACTION_REQUEST: SampleUtil_Print( "UPNP_CONTROL_ACTION_REQUEST\n" ); break; case UPNP_CONTROL_ACTION_COMPLETE: SampleUtil_Print( "UPNP_CONTROL_ACTION_COMPLETE\n" ); break; case UPNP_CONTROL_GET_VAR_REQUEST: SampleUtil_Print( "UPNP_CONTROL_GET_VAR_REQUEST\n" ); break; case UPNP_CONTROL_GET_VAR_COMPLETE: SampleUtil_Print( "UPNP_CONTROL_GET_VAR_COMPLETE\n" ); break; /* GENA Stuff */ case UPNP_EVENT_SUBSCRIPTION_REQUEST: SampleUtil_Print( "UPNP_EVENT_SUBSCRIPTION_REQUEST\n" ); break; case UPNP_EVENT_RECEIVED: SampleUtil_Print( "UPNP_EVENT_RECEIVED\n" ); break; case UPNP_EVENT_RENEWAL_COMPLETE: SampleUtil_Print( "UPNP_EVENT_RENEWAL_COMPLETE\n" ); break; case UPNP_EVENT_SUBSCRIBE_COMPLETE: SampleUtil_Print( "UPNP_EVENT_SUBSCRIBE_COMPLETE\n" ); break; case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: SampleUtil_Print( "UPNP_EVENT_UNSUBSCRIBE_COMPLETE\n" ); break; case UPNP_EVENT_AUTORENEWAL_FAILED: SampleUtil_Print( "UPNP_EVENT_AUTORENEWAL_FAILED\n" ); break; case UPNP_EVENT_SUBSCRIPTION_EXPIRED: SampleUtil_Print( "UPNP_EVENT_SUBSCRIPTION_EXPIRED\n" ); break; } } /******************************************************************************** * 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: { UpnpDiscovery *d_event = (UpnpDiscovery *)Event; SampleUtil_Print( "ErrCode = %d\n" "Expires = %d\n" "DeviceId = %s\n" "DeviceType = %s\n" "ServiceType = %s\n" "ServiceVer = %s\n" "Location = %s\n" "OS = %s\n" "Date = %s\n" "Ext = %s\n", UpnpDiscovery_get_ErrCode(d_event), UpnpDiscovery_get_Expires(d_event), UpnpString_get_String(UpnpDiscovery_get_DeviceID(d_event)), UpnpString_get_String(UpnpDiscovery_get_DeviceType(d_event)), UpnpString_get_String(UpnpDiscovery_get_ServiceType(d_event)), UpnpString_get_String(UpnpDiscovery_get_ServiceVer(d_event)), UpnpString_get_String(UpnpDiscovery_get_Location(d_event)), UpnpString_get_String(UpnpDiscovery_get_Os(d_event)), UpnpString_get_String(UpnpDiscovery_get_Date(d_event)), UpnpString_get_String(UpnpDiscovery_get_Ext(d_event))); } break; case UPNP_DISCOVERY_SEARCH_TIMEOUT: // Nothing to print out here break; /* SOAP */ case UPNP_CONTROL_ACTION_REQUEST: { UpnpActionRequest *a_event = (UpnpActionRequest *)Event; IXML_Document *actionRequestDoc = NULL; IXML_Document *actionResultDoc = NULL; char *xmlbuff = NULL; SampleUtil_Print( "ErrCode = %d\n" "ErrStr = %s\n" "ActionName = %s\n" "UDN = %s\n" "ServiceID = %s\n", UpnpActionRequest_get_ErrCode(a_event), UpnpString_get_String(UpnpActionRequest_get_ErrStr(a_event)), UpnpString_get_String(UpnpActionRequest_get_ActionName(a_event)), UpnpString_get_String(UpnpActionRequest_get_DevUDN(a_event)), UpnpString_get_String(UpnpActionRequest_get_ServiceID(a_event))); actionRequestDoc = UpnpActionRequest_get_ActionRequest(a_event); if ( actionRequestDoc ) { xmlbuff = ixmlPrintNode( (IXML_Node *)actionRequestDoc ); if ( xmlbuff ) { SampleUtil_Print( "ActRequest = %s\n", xmlbuff ); ixmlFreeDOMString( xmlbuff ); } xmlbuff = NULL; } else { SampleUtil_Print( "ActRequest = (null)\n" ); } actionResultDoc = UpnpActionRequest_get_ActionResult(a_event); if ( actionResultDoc ) { xmlbuff = ixmlPrintNode( (IXML_Node *)actionResultDoc ); if ( xmlbuff ) { SampleUtil_Print( "ActResult = %s\n", xmlbuff ); ixmlFreeDOMString( xmlbuff ); } xmlbuff = NULL; } else { SampleUtil_Print( "ActResult = (null)\n" ); } } break; case UPNP_CONTROL_ACTION_COMPLETE: { UpnpActionComplete *a_event = (UpnpActionComplete *)Event; char *xmlbuff = NULL; int errCode = UpnpActionComplete_get_ErrCode(a_event); const char *ctrlURL = UpnpString_get_String( UpnpActionComplete_get_CtrlUrl(a_event)); IXML_Document *actionRequest = UpnpActionComplete_get_ActionRequest(a_event); IXML_Document *actionResult = UpnpActionComplete_get_ActionResult(a_event); SampleUtil_Print( "ErrCode = %d\n" "CtrlUrl = %s\n", errCode, ctrlURL); if( actionRequest ) { xmlbuff = ixmlPrintNode((IXML_Node *)actionRequest); if( xmlbuff ) { SampleUtil_Print( "ActRequest = %s\n", xmlbuff ); ixmlFreeDOMString( xmlbuff ); } xmlbuff = NULL; } else { SampleUtil_Print( "ActRequest = (null)\n" ); } if( actionResult ) { xmlbuff = ixmlPrintNode((IXML_Node *)actionResult); if( xmlbuff ) { SampleUtil_Print( "ActResult = %s\n", xmlbuff ); ixmlFreeDOMString( xmlbuff ); } xmlbuff = NULL; } else { SampleUtil_Print( "ActResult = (null)\n" ); } } break; case UPNP_CONTROL_GET_VAR_REQUEST: { UpnpStateVarRequest *sv_event = (UpnpStateVarRequest *)Event; SampleUtil_Print( "ErrCode = %d\n" "ErrStr = %s\n" "UDN = %s\n" "ServiceID = %s\n" "StateVarName= %s\n" "CurrentVal = %s\n", UpnpStateVarRequest_get_ErrCode(sv_event), UpnpString_get_String(UpnpStateVarRequest_get_ErrStr(sv_event)), UpnpString_get_String(UpnpStateVarRequest_get_DevUDN(sv_event)), UpnpString_get_String(UpnpStateVarRequest_get_ServiceID(sv_event)), UpnpString_get_String(UpnpStateVarRequest_get_StateVarName(sv_event)), UpnpStateVarRequest_get_CurrentVal(sv_event)); } break; case UPNP_CONTROL_GET_VAR_COMPLETE: { UpnpStateVarComplete *sv_event = (UpnpStateVarComplete *)Event; SampleUtil_Print( "ErrCode = %d\n" "CtrlUrl = %s\n" "StateVarName= %s\n" "CurrentVal = %s\n", UpnpStateVarComplete_get_ErrCode(sv_event), UpnpString_get_String(UpnpStateVarComplete_get_CtrlUrl(sv_event)), UpnpString_get_String(UpnpStateVarComplete_get_StateVarName(sv_event)), UpnpStateVarComplete_get_CurrentVal(sv_event)); } break; /* GENA */ case UPNP_EVENT_SUBSCRIPTION_REQUEST: { UpnpSubscriptionRequest *sr_event = (UpnpSubscriptionRequest *)Event; SampleUtil_Print( "ServiceID = %s\n" "UDN = %s\n" "SID = %s\n", UpnpString_get_String(UpnpSubscriptionRequest_get_ServiceId(sr_event)), UpnpString_get_String(UpnpSubscriptionRequest_get_UDN(sr_event)), UpnpString_get_String(UpnpSubscriptionRequest_get_SID(sr_event))); } break; case UPNP_EVENT_RECEIVED: { UpnpEvent *e_event = (UpnpEvent *)Event; char *xmlbuff = NULL; xmlbuff = ixmlPrintNode( (IXML_Node *) UpnpEvent_get_ChangedVariables(e_event)); SampleUtil_Print( "SID = %s\n" "EventKey = %d\n" "ChangedVars = %s\n", UpnpString_get_String(UpnpEvent_get_SID(e_event)), UpnpEvent_get_EventKey(e_event), xmlbuff); ixmlFreeDOMString(xmlbuff); } break; case UPNP_EVENT_RENEWAL_COMPLETE: { UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event; SampleUtil_Print( "SID = %s\n" "ErrCode = %d\n" "TimeOut = %d\n", UpnpString_get_String(UpnpEventSubscribe_get_SID(es_event)), UpnpEventSubscribe_get_ErrCode(es_event), UpnpEventSubscribe_get_TimeOut(es_event)); } break; case UPNP_EVENT_SUBSCRIBE_COMPLETE: case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: { UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event; SampleUtil_Print( "SID = %s\n" "ErrCode = %d\n" "PublisherURL= %s\n" "TimeOut = %d\n", UpnpString_get_String(UpnpEventSubscribe_get_SID(es_event)), UpnpEventSubscribe_get_ErrCode(es_event), UpnpString_get_String(UpnpEventSubscribe_get_PublisherUrl(es_event)), UpnpEventSubscribe_get_TimeOut(es_event)); } break; case UPNP_EVENT_AUTORENEWAL_FAILED: case UPNP_EVENT_SUBSCRIPTION_EXPIRED: { UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event; SampleUtil_Print( "SID = %s\n" "ErrCode = %d\n" "PublisherURL= %s\n" "TimeOut = %d\n", UpnpString_get_String(UpnpEventSubscribe_get_SID(es_event)), UpnpEventSubscribe_get_ErrCode(es_event), UpnpString_get_String(UpnpEventSubscribe_get_PublisherUrl(es_event)), UpnpEventSubscribe_get_TimeOut(es_event)); } break; } SampleUtil_Print( "----------------------------------------------------------------------\n" "======================================================================\n\n\n\n" ); ithread_mutex_unlock( &display_mutex ); return 0; } /******************************************************************************** * SampleUtil_FindAndParseService * * Description: * This routine finds the first occurance of a service in a DOM representation * of a description document and parses it. * * Parameters: * DescDoc -- The DOM description document * location -- The location of the description document * serviceSearchType -- The type of service to search for * serviceId -- OUT -- The service ID * eventURL -- OUT -- The event URL for the service * controlURL -- OUT -- The control URL for the service * ********************************************************************************/ int SampleUtil_FindAndParseService( IN IXML_Document * DescDoc, IN const char *location, IN char *serviceType, OUT char **serviceId, OUT char **eventURL, OUT char **controlURL ) { int i, length, found = 0; int ret; char *tempServiceType = NULL; char *baseURL = NULL; const char *base = NULL; char *relcontrolURL = NULL, *releventURL = NULL; IXML_NodeList *serviceList = NULL; IXML_Element *service = NULL; baseURL = SampleUtil_GetFirstDocumentItem( DescDoc, "URLBase" ); if (baseURL) { base = baseURL; } else { base = location; } serviceList = SampleUtil_GetFirstServiceList( DescDoc ); length = ixmlNodeList_length( serviceList ); for( i = 0; i < length; i++ ) { service = ( IXML_Element * ) ixmlNodeList_item( serviceList, i ); tempServiceType = SampleUtil_GetFirstElementItem( ( IXML_Element * ) service, "serviceType" ); if( strcmp( tempServiceType, serviceType ) == 0 ) { SampleUtil_Print( "Found service: %s\n", serviceType ); *serviceId = SampleUtil_GetFirstElementItem( service, "serviceId" ); SampleUtil_Print( "serviceId: %s\n", ( *serviceId ) ); relcontrolURL = SampleUtil_GetFirstElementItem( service, "controlURL" ); releventURL = SampleUtil_GetFirstElementItem( service, "eventSubURL" ); *controlURL = malloc( strlen( base ) + strlen( relcontrolURL ) + 1 ); if( *controlURL ) { ret = UpnpResolveURL( base, relcontrolURL, *controlURL ); if( ret != UPNP_E_SUCCESS ) SampleUtil_Print ( "Error generating controlURL from %s + %s\n", base, relcontrolURL ); } *eventURL = malloc( strlen( base ) + strlen( releventURL ) + 1 ); if( *eventURL ) { ret = UpnpResolveURL( base, releventURL, *eventURL ); if( ret != UPNP_E_SUCCESS ) SampleUtil_Print ( "Error generating eventURL from %s + %s\n", base, releventURL ); } if( relcontrolURL ) free( relcontrolURL ); if( releventURL ) free( releventURL ); relcontrolURL = releventURL = NULL; found = 1; break; } if( tempServiceType ) free( tempServiceType ); tempServiceType = NULL; } if( tempServiceType ) free( tempServiceType ); if( serviceList ) ixmlNodeList_free( serviceList ); if( baseURL ) free( baseURL ); return ( found ); } // printf wrapper for portable code int uprint1( char *fmt, ... ) { va_list ap; char *buf = NULL; int size; va_start( ap, fmt ); size = vsnprintf( buf, 0, fmt, ap ); va_end( ap ); if( size > 0 ) { buf = ( char * )malloc( size + 1 ); if( vsnprintf( buf, size + 1, fmt, ap ) != size ) { free( buf ); buf = NULL; } } if( buf ) { ithread_mutex_lock( &display_mutex ); if( gPrintFun ) gPrintFun( buf ); ithread_mutex_unlock( &display_mutex ); free( buf ); } return size; } /******************************************************************************** * SampleUtil_Print * * Description: * Provides platform-specific print functionality. This function should be * called when you want to print content suitable for console output (i.e., * in a large text box or on a screen). If your device/operating system is * not supported here, you should add a port. * * Parameters: * Same as printf() * ********************************************************************************/ int SampleUtil_Print(char *fmt, ...) { #define MAX_BUF 1024 va_list ap; static char buf[MAX_BUF]; int rc; /* Protect both the display and the static buffer with the mutex */ ithread_mutex_lock(&display_mutex); va_start(ap, fmt); rc = vsnprintf(buf, MAX_BUF, fmt, ap); va_end(ap); if (gPrintFun) { gPrintFun(buf); } ithread_mutex_unlock(&display_mutex); return rc; } /******************************************************************************** * SampleUtil_StateUpdate * * Description: * * Parameters: * ********************************************************************************/ void SampleUtil_StateUpdate( const char *varName, const char *varValue, const char *UDN, eventType type ) { if( gStateUpdateFun ) gStateUpdateFun( varName, varValue, UDN, type ); // TBD: Add mutex here? }