Exemple #1
0
bool UPnP::NetScan(int waitSec)
{
	int res;
	m_addedDev = false;
	res = UpnpSearchAsync(CtrlPnt, waitSec, MEDIASERVERS, this);

	if(res != UPNP_E_SUCCESS)
	{
		Log::err("UpnpSearchAsync error: %s",UpnpGetErrorMessage(res));
	}

	res = UpnpSearchAsync(CtrlPnt, waitSec, MEDIARENDERERS, this);

	if(res != UPNP_E_SUCCESS)
	{
		Log::err("UpnpSearchAsync error: %s", UpnpGetErrorMessage(res));
	}

	//wait
	return true;//cfg->GetXml(deviceList);
	/*
	    res = UpnpSearchAsync( CtrlPnt, waitSec, ALL_DEVICE_TYPES, this );
	    if( res != UPNP_E_SUCCESS )
	    {
	        std::cerr<<"UpnpSearchAsync error: "<<UpnpGetErrorMessage( res )<<std::endl;
	    }
	        return deviceList;

	    */
}
Exemple #2
0
bool UPnP::init()
{
	int res;

	if((res = UpnpInit(0, 0)) != UPNP_E_SUCCESS)
	{
		Log::err("UpnpInit error: %s",UpnpGetErrorMessage(res));
		return false;
	}

	if((res = UpnpRegisterClient(Callback, this, &CtrlPnt)) != UPNP_E_SUCCESS)
	{
		Log::err("UpnpRegisterClient error: %s",UpnpGetErrorMessage(res));
		return false;
	}

	deviceList = new DeviceList();
	cfg = new Config("config.xml", &deviceList, CtrlPnt);

	if((res = UpnpSetMaxContentLength(atoi(cfg->UpnpMaxContentLength.c_str()))) != UPNP_E_SUCCESS)
	{
		Log::err("UpnpSetMaxContentLength error: %s",UpnpGetErrorMessage(res));
		return false;
	}

	isInited = true;
	return isInited;
}
Exemple #3
0
UpnpInstanceWrapper *UpnpInstanceWrapper::get(vlc_object_t *p_obj, Upnp_FunPtr callback, SD::MediaServerList *opaque)
{
    vlc_mutex_locker lock( &s_lock );
    if ( s_instance == NULL )
    {
        UpnpInstanceWrapper* instance = new(std::nothrow) UpnpInstanceWrapper;
        if ( unlikely( !instance ) )
            return NULL;

    #ifdef UPNP_ENABLE_IPV6
        char* psz_miface = var_InheritString( p_obj, "miface" );
        msg_Info( p_obj, "Initializing libupnp on '%s' interface", psz_miface );
        int i_res = UpnpInit2( psz_miface, 0 );
        free( psz_miface );
    #else
        /* If UpnpInit2 isnt available, initialize on first IPv4-capable interface */
        int i_res = UpnpInit( 0, 0 );
    #endif
        if( i_res != UPNP_E_SUCCESS )
        {
            msg_Err( p_obj, "Initialization failed: %s", UpnpGetErrorMessage( i_res ) );
            delete instance;
            return NULL;
        }

        ixmlRelaxParser( 1 );

        /* Register a control point */
        i_res = UpnpRegisterClient( Callback, instance, &instance->handle_ );
        if( i_res != UPNP_E_SUCCESS )
        {
            msg_Err( p_obj, "Client registration failed: %s", UpnpGetErrorMessage( i_res ) );
            delete instance;
            return NULL;
        }

        /* libupnp does not treat a maximum content length of 0 as unlimited
         * until 64dedf (~ pupnp v1.6.7) and provides no sane way to discriminate
         * between versions */
        if( (i_res = UpnpSetMaxContentLength( INT_MAX )) != UPNP_E_SUCCESS )
        {
            msg_Err( p_obj, "Failed to set maximum content length: %s",
                    UpnpGetErrorMessage( i_res ));
            delete instance;
            return NULL;
        }
        s_instance = instance;
    }
    s_instance->refcount_++;
    // This assumes a single UPNP SD instance
    if (callback && opaque)
    {
        assert(!s_instance->callback_ && !s_instance->opaque_);
        s_instance->opaque_ = opaque;
        s_instance->callback_ = callback;
    }
    return s_instance;
}
Exemple #4
0
/*
 * Initializes UPNP instance.
 */
static int Open( vlc_object_t *p_this )
{
    int i_res;
    services_discovery_t *p_sd = ( services_discovery_t* )p_this;
    services_discovery_sys_t *p_sys  = ( services_discovery_sys_t * )
            calloc( 1, sizeof( services_discovery_sys_t ) );

    if( !( p_sd->p_sys = p_sys ) )
        return VLC_ENOMEM;

    /* Initialize on first IPv4-capable adapter and first open port
     * TODO: use UpnpInit2() to utilize IPv6.
     */
    i_res = UpnpInit( 0, 0 );
    if( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Initialization failed: %s", UpnpGetErrorMessage( i_res ) );
        free( p_sys );
        return VLC_EGENERIC;
    }

    p_sys->p_server_list = new MediaServerList( p_sd );
    vlc_mutex_init( &p_sys->callback_lock );

    /* Register a control point */
    i_res = UpnpRegisterClient( Callback, p_sd, &p_sys->client_handle );
    if( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Client registration failed: %s", UpnpGetErrorMessage( i_res ) );
        Close( (vlc_object_t*) p_sd );
        return VLC_EGENERIC;
    }

    /* Search for media servers */
    i_res = UpnpSearchAsync( p_sys->client_handle, 5,
            MEDIA_SERVER_DEVICE_TYPE, p_sd );
    if( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Error sending search request: %s", UpnpGetErrorMessage( i_res ) );
        Close( (vlc_object_t*) p_sd );
        return VLC_EGENERIC;
    }

    /* libupnp does not treat a maximum content length of 0 as unlimited
     * until 64dedf (~ pupnp v1.6.7) and provides no sane way to discriminate
     * between versions */
    if( (i_res = UpnpSetMaxContentLength( INT_MAX )) != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Failed to set maximum content length: %s",
                UpnpGetErrorMessage( i_res ));

        Close( (vlc_object_t*) p_sd );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}
static gboolean initialize_device(struct upnp_device_descriptor *device_def,
				  struct upnp_device *result_device,
				  const char *ip_address,
				  unsigned short port)
{
	int rc;
	char *buf;

	rc = UpnpInit(ip_address, port);
	if (UPNP_E_SUCCESS != rc) {
		Log_error("upnp", "UpnpInit(ip=%s, port=%d) Error: %s (%d)",
			  ip_address, port, UpnpGetErrorMessage(rc), rc);
		return FALSE;
	}
	Log_info("upnp", "Registered IP=%s port=%d\n",
		 UpnpGetServerIpAddress(), UpnpGetServerPort());

	rc = UpnpEnableWebserver(TRUE);
	if (UPNP_E_SUCCESS != rc) {
		Log_error("upnp", "UpnpEnableWebServer() Error: %s (%d)",
			  UpnpGetErrorMessage(rc), rc);
		return FALSE;
	}

	if (!webserver_register_callbacks())
	  return FALSE;

	rc = UpnpAddVirtualDir("/upnp");
	if (UPNP_E_SUCCESS != rc) {
		Log_error("upnp", "UpnpAddVirtualDir() Error: %s (%d)",
			  UpnpGetErrorMessage(rc), rc);
		return FALSE;
	}

       	buf = upnp_create_device_desc(device_def);
	rc = UpnpRegisterRootDevice2(UPNPREG_BUF_DESC,
				     buf, strlen(buf), 1,
				     &event_handler, result_device,
				     &(result_device->device_handle));
	free(buf);

	if (UPNP_E_SUCCESS != rc) {
		Log_error("upnp", "UpnpRegisterRootDevice2() Error: %s (%d)",
			  UpnpGetErrorMessage(rc), rc);
		return FALSE;
	}

	rc = UpnpSendAdvertisement(result_device->device_handle, 100);
	if (UPNP_E_SUCCESS != rc) {
		Log_error("unpp", "Error sending advertisements: %s (%d)",
			  UpnpGetErrorMessage(rc), rc);
		return FALSE;
	}

	return TRUE;
}
Exemple #6
0
/*
 * Initializes UPNP instance.
 */
static int Open( vlc_object_t *p_this )
{
    services_discovery_t *p_sd = ( services_discovery_t* )p_this;
    services_discovery_sys_t *p_sys  = ( services_discovery_sys_t * )
            calloc( 1, sizeof( services_discovery_sys_t ) );

    if( !( p_sd->p_sys = p_sys ) )
        return VLC_ENOMEM;

    p_sys->p_server_list = new(std::nothrow) SD::MediaServerList( p_sd );
    if ( unlikely( p_sys->p_server_list == NULL ) )
    {
        return VLC_ENOMEM;
    }

    p_sys->p_upnp = UpnpInstanceWrapper::get( p_this, SD::MediaServerList::Callback, p_sys->p_server_list );
    if ( !p_sys->p_upnp )
    {
        Close( p_this );
        return VLC_EGENERIC;
    }

    /* Search for media servers */
    int i_res = UpnpSearchAsync( p_sys->p_upnp->handle(), 5,
            MEDIA_SERVER_DEVICE_TYPE, p_sys->p_upnp );
    if( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Error sending search request: %s", UpnpGetErrorMessage( i_res ) );
        Close( p_this );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}
Exemple #7
0
/**
 * Subscribes current client handle to Content Directory Service.
 * CDS exports the server shares to clients.
 */
void MediaServer::subscribeToContentDirectory()
{
    const char* psz_url = getContentDirectoryEventURL();
    if ( !psz_url )
    {
        msg_Dbg( _p_sd, "No subscription url set!" );
        return;
    }

    int i_timeout = 1810;
    Upnp_SID sid;

    int i_res = UpnpSubscribe( _p_sd->p_sys->client_handle, psz_url, &i_timeout, sid );

    if ( i_res == UPNP_E_SUCCESS )
    {
        _i_subscription_timeout = i_timeout;
        memcpy( _subscription_id, sid, sizeof( Upnp_SID ) );
    }
    else
    {
        msg_Dbg( _p_sd, "Subscribe failed: '%s': %s",
                getFriendlyName(), UpnpGetErrorMessage( i_res ) );
    }
}
Exemple #8
0
void MediaServer::subscribeToContentDirectory()
{
    const char* url = getContentDirectoryEventURL();
    if ( !url || strcmp( url, "" ) == 0 )
    {
        msg_Dbg( _p_sd, "No subscription url set!" );
        return;
    }

    int timeOut = 1810;
    Upnp_SID sid;

    int res = UpnpSubscribe( _p_sd->p_sys->clientHandle, url, &timeOut, sid );

    if ( res == UPNP_E_SUCCESS )
    {
        _subscriptionTimeOut = timeOut;
        memcpy( _subscriptionID, sid, sizeof( Upnp_SID ) );
    }
    else
    {
        msg_Dbg( _p_sd,
                "%s:%d: WARNING: '%s': %s", __FILE__, __LINE__,
                getFriendlyName(), UpnpGetErrorMessage( res ) );
    }
}
Exemple #9
0
// Get the requested index from the stack and verify it being a proper Device
// throws an error if it fails.
// HARD ERROR
UpnpDevice_Handle checkdevice(lua_State *L, int idx)
{
	pLuaDevice dev;
	luaL_checkudata(L, idx, LPNP_DEVICE_MT);
	if (! UPnPStarted) luaL_error(L, UpnpGetErrorMessage(UPNP_E_FINISH));
	dev = (pLuaDevice)lua_touserdata(L, idx);
	return dev->device;
}
Exemple #10
0
// Get the requested index from the stack and verify it being a proper Client
// throws an error if it fails.
// HARD ERROR
UpnpClient_Handle checkclient(lua_State *L, int idx)
{
	pLuaClient client;
	luaL_checkudata(L, idx, LPNP_CLIENT_MT);
	if (! UPnPStarted) luaL_error(L,  UpnpGetErrorMessage(UPNP_E_FINISH));
	client = (pLuaClient)lua_touserdata(L, idx);
	return client->client;
}
gboolean webserver_register_callbacks(void) {
  int rc = UpnpSetVirtualDirCallbacks(&virtual_dir_callbacks);
  if (UPNP_E_SUCCESS != rc) {
    Log_error("webserver", "UpnpSetVirtualDirCallbacks() Error: %s (%d)",
	      UpnpGetErrorMessage(rc), rc);
    return FALSE;
  }
  return TRUE;
}
Exemple #12
0
/*
 * Handles servers listing UPnP events
 */
int MediaServerList::Callback( Upnp_EventType event_type, void* p_event, void* p_user_data )
{
    MediaServerList* self = static_cast<MediaServerList*>( p_user_data );
    services_discovery_t* p_sd = self->p_sd_;

    switch( event_type )
    {
    case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
    case UPNP_DISCOVERY_SEARCH_RESULT:
    {
        struct Upnp_Discovery* p_discovery = ( struct Upnp_Discovery* )p_event;

        IXML_Document *p_description_doc = NULL;

        int i_res;
        i_res = UpnpDownloadXmlDoc( p_discovery->Location, &p_description_doc );
        if ( i_res != UPNP_E_SUCCESS )
        {
            msg_Warn( p_sd, "Could not download device description! "
                            "Fetching data from %s failed: %s",
                            p_discovery->Location, UpnpGetErrorMessage( i_res ) );
            return i_res;
        }
        self->parseNewServer( p_description_doc, p_discovery->Location );
        ixmlDocument_free( p_description_doc );
    }
    break;

    case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
    {
        struct Upnp_Discovery* p_discovery = ( struct Upnp_Discovery* )p_event;

        self->removeServer( p_discovery->DeviceId );
    }
    break;

    case UPNP_EVENT_SUBSCRIBE_COMPLETE:
        msg_Warn( p_sd, "subscription complete" );
        break;

    case UPNP_DISCOVERY_SEARCH_TIMEOUT:
        msg_Warn( p_sd, "search timeout" );
        break;

    case UPNP_EVENT_RECEIVED:
    case UPNP_EVENT_AUTORENEWAL_FAILED:
    case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
        // Those are for the access part
        break;

    default:
        msg_Err( p_sd, "Unhandled event, please report ( type=%d )", event_type );
        break;
    }

    return UPNP_E_SUCCESS;
}
Exemple #13
0
static int Open( vlc_object_t *p_this )
{
    int res;
    services_discovery_t *p_sd = ( services_discovery_t* )p_this;
    services_discovery_sys_t *p_sys  = ( services_discovery_sys_t * )
            calloc( 1, sizeof( services_discovery_sys_t ) );

    if(!(p_sd->p_sys = p_sys))
        return VLC_ENOMEM;

    res = UpnpInit( 0, 0 );
    if( res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
        free( p_sys );
        return VLC_EGENERIC;
    }

    p_sys->serverList = new MediaServerList( p_sd );
    vlc_mutex_init( &p_sys->callbackLock );

    res = UpnpRegisterClient( Callback, p_sd, &p_sys->clientHandle );
    if( res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
        Close( (vlc_object_t*) p_sd );
        return VLC_EGENERIC;
    }

    res = UpnpSearchAsync( p_sys->clientHandle, 5,
            MEDIA_SERVER_DEVICE_TYPE, p_sd );

    if( res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "%s", UpnpGetErrorMessage( res ) );
        Close( (vlc_object_t*) p_sd );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}
int upnp_add_response(struct action_event *event,
		      const char *key, const char *value)
{
	int result = -1;
	char *val;
#ifdef HAVE_LIBUPNP
	int rc;
#endif

	//ENTER();

	assert(event != NULL);
	assert(key != NULL);

	if (event->status) {
		goto out;
	}

	val = strdup(value);
	if (val == NULL) {
		/* report memory failure */
		event->status = -1;
#ifdef HAVE_LIBUPNP
		event->request->ActionResult = NULL;
		event->request->ErrCode = UPNP_SOAP_E_ACTION_FAILED;
		strcpy(event->request->ErrStr, strerror(errno));
#endif
		goto out;
	}

#ifdef HAVE_LIBUPNP
	rc =
	    UpnpAddToActionResponse(&event->request->ActionResult,
				    event->request->ActionName,
				    event->service->type, key, val);

	if (rc != UPNP_E_SUCCESS) {
		/* report custom error */
		event->request->ActionResult = NULL;
		event->request->ErrCode = UPNP_SOAP_E_ACTION_FAILED;
		strcpy(event->request->ErrStr, UpnpGetErrorMessage(rc));
		goto out;
	}

	result = 0;
#endif
out:
	if (val != NULL) {
		free(val);
	}
	//LEAVE();
	return result;
}
Exemple #15
0
static void *
SearchThread( void *p_data )
{
    services_discovery_t *p_sd = ( services_discovery_t* )p_data;
    services_discovery_sys_t *p_sys  = p_sd->p_sys;

    /* Search for media servers */
    int i_res = UpnpSearchAsync( p_sys->p_upnp->handle(), 5,
                                 MEDIA_SERVER_DEVICE_TYPE, p_sys->p_upnp );
    if( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Error sending search request: %s", UpnpGetErrorMessage( i_res ) );
        return NULL;
    }

    /* Search for Sat Ip servers*/
    i_res = UpnpSearchAsync( p_sys->p_upnp->handle(), 5,
                             SATIP_SERVER_DEVICE_TYPE, p_sys->p_upnp );
    if( i_res != UPNP_E_SUCCESS )
        msg_Err( p_sd, "Error sending search request: %s", UpnpGetErrorMessage( i_res ) );
    return NULL;
}
Exemple #16
0
// Pushes nil + UPnP error, call from a return statement; eg:  
//     return pushUPnPerror(L, errno, soap);
// SOFT ERROR
int pushUPnPerror(lua_State *L, int err, IXML_Document* respdoc)
{
	lua_checkstack(L,3);
	lua_pushnil(L);
	lua_pushstring(L, UpnpGetErrorMessage(err));
	lua_pushinteger(L, err);
	if (err > 0)	// SOAP error, also add document containing error
	{
		pushLuaDocument(L, respdoc);
		return 4;
	}
	return 3;
}
Exemple #17
0
int
upnp_add_response(struct action_event *event, char *key, const char *value)
{
	int rc = 0;
	char *val = NULL;
	int result = -1;

	ENTER();

	if (event->status) {
		goto out;
	}

	val = strdup(value);
	if (val == NULL) {
		/* report memory failure */
		event->status = -1;
		event->request->ActionResult = NULL;
		event->request->ErrCode = UPNP_SOAP_E_ACTION_FAILED;
		strcpy(event->request->ErrStr, strerror(errno));
		goto out;
	}

	rc =
	    UpnpAddToActionResponse(&event->request->ActionResult,
				    event->request->ActionName,
				    event->service->type, key, val);
	if (rc != UPNP_E_SUCCESS) {
		/* report custom error */
		event->request->ActionResult = NULL;
		event->request->ErrCode = UPNP_SOAP_E_ACTION_FAILED;
		strcpy(event->request->ErrStr, UpnpGetErrorMessage(rc));
		goto out;
	}

	result = 0;
out:
	LEAVE();
	free(val);
	return result;
}
int upnp_add_response(struct action_event *event,
		      const char *key, const char *value)
{
	assert(event != NULL);
	assert(key != NULL);
	assert(value != NULL);

	if (event->status) {
		return -1;
	}

	int rc;
	rc = UpnpAddToActionResponse(&event->request->ActionResult,
				     event->request->ActionName,
				     event->service->service_type, key, value);
	if (rc != UPNP_E_SUCCESS) {
		/* report custom error */
		event->request->ActionResult = NULL;
		event->request->ErrCode = UPNP_SOAP_E_ACTION_FAILED;
		strcpy(event->request->ErrStr, UpnpGetErrorMessage(rc));
		return -1;
	}
	return 0;
}
static int handle_subscription_request(struct upnp_device *priv,
                                       struct Upnp_Subscription_Request
                                              *sr_event)
{
	struct service *srv;
	int rc;

	assert(priv != NULL);

	Log_info("upnp", "Subscription request for %s (%s)",
		 sr_event->ServiceId, sr_event->UDN);

	srv = find_service(priv->upnp_device_descriptor, sr_event->ServiceId);
	if (srv == NULL) {
		Log_error("upnp", "%s: Unknown service '%s'", __FUNCTION__,
			  sr_event->ServiceId);
		return -1;
	}

	int result = -1;
	ithread_mutex_lock(&(priv->device_mutex));

	// There is really only one variable evented: LastChange
	const char *eventvar_names[] = {
		"LastChange",
		NULL
	};
	const char *eventvar_values[] = {
		NULL, NULL
	};

	// Build the current state of the variables as one gigantic initial
	// LastChange update.
	ithread_mutex_lock(srv->service_mutex);
	const int var_count =
		VariableContainer_get_num_vars(srv->variable_container);
	// TODO(hzeller): maybe use srv->last_change directly ?
	upnp_last_change_builder_t *builder = UPnPLastChangeBuilder_new(srv->event_xml_ns);
	for (int i = 0; i < var_count; ++i) {
		const char *name;
		const char *value =
			VariableContainer_get(srv->variable_container, i, &name);
		// Send over all variables except "LastChange" itself. Also all
		// A_ARG_TYPE variables are not evented.
		if (value && strcmp("LastChange", name) != 0
		    && strncmp("A_ARG_TYPE_", name, strlen("A_ARG_TYPE_")) != 0) {
			UPnPLastChangeBuilder_add(builder, name, value);
		}
	}
	ithread_mutex_unlock(srv->service_mutex);
	char *xml_value = UPnPLastChangeBuilder_to_xml(builder);
	Log_info("upnp", "Initial variable sync: %s", xml_value);
	eventvar_values[0] = xmlescape(xml_value, 0);
	free(xml_value);
	UPnPLastChangeBuilder_delete(builder);

	rc = UpnpAcceptSubscription(priv->device_handle,
				    sr_event->UDN, sr_event->ServiceId,
				    eventvar_names, eventvar_values, 1,
				    sr_event->Sid);
	if (rc == UPNP_E_SUCCESS) {
		result = 0;
	} else {
		Log_error("upnp", "Accept Subscription Error: %s (%d)",
			  UpnpGetErrorMessage(rc), rc);
	}

	ithread_mutex_unlock(&(priv->device_mutex));

	free((char*)eventvar_values[0]);

	return result;
}
int SampleUtil_PrintEvent(Upnp_EventType EventType, void *Event)
{
	ithread_mutex_lock(&display_mutex);

	SampleUtil_Print(
		"======================================================================\n"
		"----------------------------------------------------------------------\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     =  %s(%d)\n",
			UpnpGetErrorMessage(d_event->ErrCode), 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     =  %s(%d)\n",
			UpnpGetErrorMessage(a_event->ErrCode), 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 = ixmlPrintNode((IXML_Node *)a_event->ActionRequest);
			if (xmlbuff) {
				SampleUtil_Print("ActRequest  =  %s\n", xmlbuff);
				ixmlFreeDOMString(xmlbuff);
			}
			xmlbuff = NULL;
		} else {
			SampleUtil_Print("ActRequest  =  (null)\n");
		}
		if (a_event->ActionResult) {
			xmlbuff = ixmlPrintNode((IXML_Node *)a_event->ActionResult);
			if (xmlbuff) {
				SampleUtil_Print("ActResult   =  %s\n", 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     =  %s(%d)\n",  
			UpnpGetErrorMessage(a_event->ErrCode), a_event->ErrCode);
		SampleUtil_Print("CtrlUrl     =  %s\n", a_event->CtrlUrl);
		if (a_event->ActionRequest) {
			xmlbuff = ixmlPrintNode((IXML_Node *)a_event->ActionRequest);
			if (xmlbuff) {
				SampleUtil_Print("ActRequest  =  %s\n", xmlbuff);
				ixmlFreeDOMString(xmlbuff);
			}
			xmlbuff = NULL;
		} else {
			SampleUtil_Print("ActRequest  =  (null)\n");
		}
		if (a_event->ActionResult) {
			xmlbuff = ixmlPrintNode((IXML_Node *)a_event->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: {
		struct Upnp_State_Var_Request *sv_event =
			(struct Upnp_State_Var_Request *)Event;

		SampleUtil_Print("ErrCode     =  %s(%d)\n",
			UpnpGetErrorMessage(sv_event->ErrCode), 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     =  %s(%d)\n",
			UpnpGetErrorMessage(sv_event->ErrCode), 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 = ixmlPrintNode((IXML_Node *)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     =  %s(%d)\n",
			UpnpGetErrorMessage(es_event->ErrCode), 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     =  %s(%d)\n",
			UpnpGetErrorMessage(es_event->ErrCode), 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     =  %s(%d)\n",  
			UpnpGetErrorMessage(es_event->ErrCode), es_event->ErrCode);
		SampleUtil_Print("PublisherURL=  %s\n", es_event->PublisherUrl);
		SampleUtil_Print("TimeOut     =  %d\n", es_event->TimeOut);
		break;
	}
	}
	SampleUtil_Print(
		"----------------------------------------------------------------------\n"
		"======================================================================\n"
		"\n\n\n");

	ithread_mutex_unlock(&display_mutex);

	return 0;
}
Exemple #21
0
/*
 * Handles all UPnP events
 */
static int Callback( Upnp_EventType event_type, void* p_event, void* p_user_data )
{
    services_discovery_t* p_sd = ( services_discovery_t* ) p_user_data;
    services_discovery_sys_t* p_sys = p_sd->p_sys;
    vlc_mutex_locker locker( &p_sys->callback_lock );

    switch( event_type )
    {
    case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
    case UPNP_DISCOVERY_SEARCH_RESULT:
    {
        struct Upnp_Discovery* p_discovery = ( struct Upnp_Discovery* )p_event;

        IXML_Document *p_description_doc = 0;

        int i_res;
        i_res = UpnpDownloadXmlDoc( p_discovery->Location, &p_description_doc );
        if ( i_res != UPNP_E_SUCCESS )
        {
            msg_Warn( p_sd, "Could not download device description! "
                            "Fetching data from %s failed: %s",
                            p_discovery->Location, UpnpGetErrorMessage( i_res ) );
            return i_res;
        }

        MediaServer::parseDeviceDescription( p_description_doc,
                p_discovery->Location, p_sd );

        ixmlDocument_free( p_description_doc );
    }
    break;

    case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
    {
        struct Upnp_Discovery* p_discovery = ( struct Upnp_Discovery* )p_event;

        p_sys->p_server_list->removeServer( p_discovery->DeviceId );

    }
    break;

    case UPNP_EVENT_RECEIVED:
    {
        Upnp_Event* p_e = ( Upnp_Event* )p_event;

        MediaServer* p_server = p_sys->p_server_list->getServerBySID( p_e->Sid );
        if ( p_server ) p_server->fetchContents();
    }
    break;

    case UPNP_EVENT_AUTORENEWAL_FAILED:
    case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
    {
        /* Re-subscribe. */

        Upnp_Event_Subscribe* p_s = ( Upnp_Event_Subscribe* )p_event;

        MediaServer* p_server = p_sys->p_server_list->getServerBySID( p_s->Sid );
        if ( p_server ) p_server->subscribeToContentDirectory();
    }
    break;

    case UPNP_EVENT_SUBSCRIBE_COMPLETE:
        msg_Warn( p_sd, "subscription complete" );
        break;

    case UPNP_DISCOVERY_SEARCH_TIMEOUT:
        msg_Warn( p_sd, "search timeout" );
        break;

    default:
        msg_Err( p_sd, "Unhandled event, please report ( type=%d )", event_type );
        break;
    }

    return UPNP_E_SUCCESS;
}
Exemple #22
0
IXML_Document* MediaServer::_browseAction( const char* pObjectID,
                                           const char* pBrowseFlag,
                                           const char* pFilter,
                                           const char* pStartingIndex,
                                           const char* pRequestedCount,
                                           const char* pSortCriteria )
{
    IXML_Document* action = 0;
    IXML_Document* response = 0;
    const char* url = getContentDirectoryControlURL();
    
    if ( !url || strcmp( url, "" ) == 0 )
    {
        msg_Dbg( _p_sd, "No subscription url set!" );
        return 0;
    }

    char* ObjectID = strdup( pObjectID );
    char* BrowseFlag = strdup( pBrowseFlag );
    char* Filter = strdup( pFilter );
    char* StartingIndex = strdup( pStartingIndex );
    char* RequestedCount = strdup( pRequestedCount );
    char* SortCriteria = strdup( pSortCriteria );
    char* serviceType = strdup( CONTENT_DIRECTORY_SERVICE_TYPE );

    int res;

    res = UpnpAddToAction( &action, "Browse",
            serviceType, "ObjectID", ObjectID );
    
    if ( res != UPNP_E_SUCCESS ) 
    {
        msg_Dbg( _p_sd,
                 "%s:%d: ERROR: %s", __FILE__, __LINE__,
                 UpnpGetErrorMessage( res ) );
        goto browseActionCleanup;
    }

    res = UpnpAddToAction( &action, "Browse",
            serviceType, "BrowseFlag", BrowseFlag );
    
    if ( res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd,
             "%s:%d: ERROR: %s", __FILE__, __LINE__,
             UpnpGetErrorMessage( res ) );
        goto browseActionCleanup;
    }

    res = UpnpAddToAction( &action, "Browse",
            serviceType, "Filter", Filter );
    
    if ( res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd,
             "%s:%d: ERROR: %s", __FILE__, __LINE__,
             UpnpGetErrorMessage( res ) );
        goto browseActionCleanup;
    }

    res = UpnpAddToAction( &action, "Browse",
            serviceType, "StartingIndex", StartingIndex );

    if ( res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd,
             "%s:%d: ERROR: %s", __FILE__, __LINE__,
             UpnpGetErrorMessage( res ) );
        goto browseActionCleanup;
    }

    res = UpnpAddToAction( &action, "Browse",
            serviceType, "RequestedCount", RequestedCount );

    if ( res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd,
                "%s:%d: ERROR: %s", __FILE__, __LINE__,
                UpnpGetErrorMessage( res ) ); goto browseActionCleanup; }

    res = UpnpAddToAction( &action, "Browse",
            serviceType, "SortCriteria", SortCriteria );
    
    if ( res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd,
             "%s:%d: ERROR: %s", __FILE__, __LINE__,
             UpnpGetErrorMessage( res ) );
        goto browseActionCleanup;
    }

    res = UpnpSendAction( _p_sd->p_sys->clientHandle,
              url,
              CONTENT_DIRECTORY_SERVICE_TYPE,
              0,
              action,
              &response );
    
    if ( res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd,
                "%s:%d: ERROR: %s when trying the send() action with URL: %s",
                __FILE__, __LINE__,
                UpnpGetErrorMessage( res ), url );

        ixmlDocument_free( response );
        response = 0;
    }

 browseActionCleanup:

    free( ObjectID );
    free( BrowseFlag );
    free( Filter );
    free( StartingIndex );
    free( RequestedCount );
    free( SortCriteria );

    free( serviceType );

    ixmlDocument_free( action );
    return response;
}
Exemple #23
0
void upnp_perror(const char *message, int err)
{
	fprintf(stderr, "%s: %s (%d)\n", message, UpnpGetErrorMessage(err), err);
};
Exemple #24
0
/*
 * Initializes UPNP instance.
 */
static int Open( vlc_object_t *p_this )
{
    int i_res;
    services_discovery_t *p_sd = ( services_discovery_t* )p_this;
    services_discovery_sys_t *p_sys  = ( services_discovery_sys_t * )
            calloc( 1, sizeof( services_discovery_sys_t ) );

    if( !( p_sd->p_sys = p_sys ) )
        return VLC_ENOMEM;

#ifdef UPNP_ENABLE_IPV6
    char* psz_miface;
    psz_miface = var_InheritString( p_sd, "miface" );
    msg_Info( p_sd, "Initializing libupnp on '%s' interface", psz_miface );
    i_res = UpnpInit2( psz_miface, 0 );
    free( psz_miface );
#else
    /* If UpnpInit2 isnt available, initialize on first IPv4-capable interface */
    i_res = UpnpInit( 0, 0 );
#endif
    if( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Initialization failed: %s", UpnpGetErrorMessage( i_res ) );
        free( p_sys );
        return VLC_EGENERIC;
    }

    ixmlRelaxParser( 1 );

    p_sys->p_server_list = new MediaServerList( p_sd );
    vlc_mutex_init( &p_sys->callback_lock );

    /* Register a control point */
    i_res = UpnpRegisterClient( Callback, p_sd, &p_sys->client_handle );
    if( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Client registration failed: %s", UpnpGetErrorMessage( i_res ) );
        Close( (vlc_object_t*) p_sd );
        return VLC_EGENERIC;
    }

    /* Search for media servers */
    i_res = UpnpSearchAsync( p_sys->client_handle, 5,
            MEDIA_SERVER_DEVICE_TYPE, p_sd );
    if( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Error sending search request: %s", UpnpGetErrorMessage( i_res ) );
        Close( (vlc_object_t*) p_sd );
        return VLC_EGENERIC;
    }

    /* libupnp does not treat a maximum content length of 0 as unlimited
     * until 64dedf (~ pupnp v1.6.7) and provides no sane way to discriminate
     * between versions */
    if( (i_res = UpnpSetMaxContentLength( INT_MAX )) != UPNP_E_SUCCESS )
    {
        msg_Err( p_sd, "Failed to set maximum content length: %s",
                UpnpGetErrorMessage( i_res ));

        Close( (vlc_object_t*) p_sd );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}
Exemple #25
0
/* Access part */
IXML_Document* MediaServer::_browseAction( const char* psz_object_id_,
        const char* psz_browser_flag_,
        const char* psz_filter_,
        const char* psz_requested_count_,
        const char* psz_sort_criteria_ )
{
    IXML_Document* p_action = NULL;
    IXML_Document* p_response = NULL;
    Upnp_i11e_cb *i11eCb = NULL;
    access_sys_t *sys = (access_sys_t *)m_access->p_sys;

    int i_res;

    if ( vlc_killed() )
        return NULL;

    i_res = UpnpAddToAction( &p_action, "Browse",
                             CONTENT_DIRECTORY_SERVICE_TYPE, "ObjectID", psz_object_id_ ? psz_object_id_ : "0" );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( m_access, "AddToAction 'ObjectID' failed: %s",
                 UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
                             CONTENT_DIRECTORY_SERVICE_TYPE, "BrowseFlag", psz_browser_flag_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( m_access, "AddToAction 'BrowseFlag' failed: %s",
                 UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
                             CONTENT_DIRECTORY_SERVICE_TYPE, "Filter", psz_filter_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( m_access, "AddToAction 'Filter' failed: %s",
                 UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
                             CONTENT_DIRECTORY_SERVICE_TYPE, "StartingIndex", "0" );
    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( m_access, "AddToAction 'StartingIndex' failed: %s",
                 UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
                             CONTENT_DIRECTORY_SERVICE_TYPE, "RequestedCount", psz_requested_count_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( m_access, "AddToAction 'RequestedCount' failed: %s",
                 UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
                             CONTENT_DIRECTORY_SERVICE_TYPE, "SortCriteria", psz_sort_criteria_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( m_access, "AddToAction 'SortCriteria' failed: %s",
                 UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    /* Setup an interruptible callback that will call sendActionCb if not
     * interrupted by vlc_interrupt_kill */
    i11eCb = new Upnp_i11e_cb( sendActionCb, &p_response );
    i_res = UpnpSendActionAsync( sys->p_upnp->handle(),
                                 m_psz_root,
                                 CONTENT_DIRECTORY_SERVICE_TYPE,
                                 NULL, /* ignored in SDK, must be NULL */
                                 p_action,
                                 Upnp_i11e_cb::run, i11eCb );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( m_access, "%s when trying the send() action with URL: %s",
                 UpnpGetErrorMessage( i_res ), m_access->psz_location );
    }
    /* Wait for the callback to fill p_response or wait for an interrupt */
    i11eCb->waitAndRelease();

browseActionCleanup:
    ixmlDocument_free( p_action );
    return p_response;
}
Exemple #26
0
/* Access part */
IXML_Document* MediaServer::_browseAction( const char* psz_object_id_,
                                           const char* psz_browser_flag_,
                                           const char* psz_filter_,
                                           const char* psz_requested_count_,
                                           const char* psz_sort_criteria_ )
{
    IXML_Document* p_action = NULL;
    IXML_Document* p_response = NULL;
    const char* psz_url = url_.c_str();

    if ( url_.empty() )
    {
        msg_Dbg( access_, "No subscription url set!" );
        return NULL;
    }

    int i_res;

    i_res = UpnpAddToAction( &p_action, "Browse",
            CONTENT_DIRECTORY_SERVICE_TYPE, "ObjectID", psz_object_id_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( access_, "AddToAction 'ObjectID' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            CONTENT_DIRECTORY_SERVICE_TYPE, "StartingIndex", "0" );
    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( access_, "AddToAction 'StartingIndex' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            CONTENT_DIRECTORY_SERVICE_TYPE, "BrowseFlag", psz_browser_flag_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( access_, "AddToAction 'BrowseFlag' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            CONTENT_DIRECTORY_SERVICE_TYPE, "Filter", psz_filter_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( access_, "AddToAction 'Filter' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            CONTENT_DIRECTORY_SERVICE_TYPE, "RequestedCount", psz_requested_count_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( access_, "AddToAction 'RequestedCount' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            CONTENT_DIRECTORY_SERVICE_TYPE, "SortCriteria", psz_sort_criteria_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( access_, "AddToAction 'SortCriteria' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpSendAction( access_->p_sys->p_upnp->handle(),
              psz_url,
              CONTENT_DIRECTORY_SERVICE_TYPE,
              NULL, /* ignored in SDK, must be NULL */
              p_action,
              &p_response );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( access_, "%s when trying the send() action with URL: %s",
                UpnpGetErrorMessage( i_res ), psz_url );

        ixmlDocument_free( p_response );
        p_response = NULL;
    }

browseActionCleanup:
    ixmlDocument_free( p_action );
    return p_response;
}
Exemple #27
0
std::string CUPnPLib::GetUPnPErrorMessage(int code) const
{
	return UpnpGetErrorMessage(code);
}
Exemple #28
0
/*
 * Constructs UpnpAction to browse available content.
 */
IXML_Document* MediaServer::_browseAction( const char* psz_object_id_,
                                           const char* psz_browser_flag_,
                                           const char* psz_filter_,
                                           const char* psz_starting_index_,
                                           const char* psz_requested_count_,
                                           const char* psz_sort_criteria_ )
{
    IXML_Document* p_action = 0;
    IXML_Document* p_response = 0;
    const char* psz_url = getContentDirectoryControlURL();

    if ( !psz_url )
    {
        msg_Dbg( _p_sd, "No subscription url set!" );
        return 0;
    }

    char* psz_service_type = strdup( CONTENT_DIRECTORY_SERVICE_TYPE );

    psz_service_type[strlen( psz_service_type ) - 1] =
	_i_content_directory_service_version;

    int i_res;

    i_res = UpnpAddToAction( &p_action, "Browse",
            psz_service_type, "ObjectID", psz_object_id_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd, "AddToAction 'ObjectID' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            psz_service_type, "BrowseFlag", psz_browser_flag_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd, "AddToAction 'BrowseFlag' failed: %s", 
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            psz_service_type, "Filter", psz_filter_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd, "AddToAction 'Filter' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            psz_service_type, "StartingIndex", psz_starting_index_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd, "AddToAction 'StartingIndex' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            psz_service_type, "RequestedCount", psz_requested_count_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd, "AddToAction 'RequestedCount' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpAddToAction( &p_action, "Browse",
            psz_service_type, "SortCriteria", psz_sort_criteria_ );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Dbg( _p_sd, "AddToAction 'SortCriteria' failed: %s",
                UpnpGetErrorMessage( i_res ) );
        goto browseActionCleanup;
    }

    i_res = UpnpSendAction( _p_sd->p_sys->client_handle,
              psz_url,
              psz_service_type,
              0, /* ignored in SDK, must be NULL */
              p_action,
              &p_response );

    if ( i_res != UPNP_E_SUCCESS )
    {
        msg_Err( _p_sd, "%s when trying the send() action with URL: %s",
                UpnpGetErrorMessage( i_res ), psz_url );

        ixmlDocument_free( p_response );
        p_response = 0;
    }

browseActionCleanup:

    free( psz_service_type );

    ixmlDocument_free( p_action );
    return p_response;
}