Esempio n. 1
0
void gena_process_unsubscribe_request(
	SOCKINFO *info,
	http_message_t *request)
{
    Upnp_SID sid;
    service_info *service;
    struct Handle_Info *handle_info;
    UpnpDevice_Handle device_handle;

    memptr temp_hdr;
    membuffer event_url_path;

    /* if a CALLBACK or NT header is present, then it is an error */
    if( httpmsg_find_hdr( request, HDR_CALLBACK, NULL ) != NULL ||
        httpmsg_find_hdr( request, HDR_NT, NULL ) != NULL ) {
        error_respond( info, HTTP_BAD_REQUEST, request );
        return;
    }
    /* get SID */
    if( httpmsg_find_hdr( request, HDR_SID, &temp_hdr ) == NULL ||
        temp_hdr.length > SID_SIZE ) {
        error_respond( info, HTTP_PRECONDITION_FAILED, request );
        return;
    }
    memcpy( sid, temp_hdr.buf, temp_hdr.length );
    sid[temp_hdr.length] = '\0';

    /* lookup service by eventURL */
    membuffer_init( &event_url_path );
    if( membuffer_append( &event_url_path, request->uri.pathquery.buff,
                          request->uri.pathquery.size ) != 0 ) {
        error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request );
        return;
    }

    HandleLock();

    if( GetDeviceHandleInfoForPath(event_url_path.buf, info->foreign_sockaddr.ss_family,
								   &device_handle, &handle_info, &service) != HND_DEVICE ) {
        error_respond( info, HTTP_PRECONDITION_FAILED, request );
        membuffer_destroy( &event_url_path );
        HandleUnlock();
        return;
    }
    membuffer_destroy( &event_url_path );

    /* validate service */
    if( service == NULL ||
        !service->active || GetSubscriptionSID( sid, service ) == NULL )
    {
        error_respond( info, HTTP_PRECONDITION_FAILED, request );
        HandleUnlock();
        return;
    }

    RemoveSubscriptionSID(sid, service);
    error_respond(info, HTTP_OK, request);    /* success */

    HandleUnlock();
}
Esempio n. 2
0
int has_xml_content_type(http_message_t *hmsg)
{
	memptr hdr_value;

	assert(hmsg);

	/* find 'content-type' header which must have text/xml */
	if (httpmsg_find_hdr(hmsg, HDR_CONTENT_TYPE, &hdr_value) &&
	    matchstr(hdr_value.buf, hdr_value.length, "%itext%w/%wxml" ) == PARSE_OK) {
		return TRUE;
	}
	return FALSE;
}
Esempio n. 3
0
/*!
 * \brief Does some quick checking of the ssdp msg.
 *
 * \return TRUE if msg is valid, else FALSE.
 */
static UPNP_INLINE int valid_ssdp_msg(
	/*! [in] ssdp_thread_data structure. This structure contains SSDP
	 * request message. */
	http_message_t * hmsg)
{
	memptr hdr_value;

	/* check for valid methods - NOTIFY or M-SEARCH */
	if (hmsg->method != (http_method_t)HTTPMETHOD_NOTIFY &&
	    hmsg->method != (http_method_t)HTTPMETHOD_MSEARCH &&
	    hmsg->request_method != (http_method_t)HTTPMETHOD_MSEARCH) {
		return FALSE;
	}
	if (hmsg->request_method != (http_method_t)HTTPMETHOD_MSEARCH) {
		/* check PATH == "*" */
		if (hmsg->uri.type != (enum uriType)RELATIVE ||
		    strncmp("*", hmsg->uri.pathquery.buff,
			    hmsg->uri.pathquery.size) != 0) {
			return FALSE;
		}
		/* check HOST header */
		if (httpmsg_find_hdr(hmsg, HDR_HOST, &hdr_value) == NULL ||
		    (memptr_cmp(&hdr_value, "239.255.255.250:1900") != 0 &&
		     memptr_cmp(&hdr_value, "[FF02::C]:1900") != 0 &&
		     memptr_cmp(&hdr_value, "[ff02::c]:1900") != 0 &&
		     memptr_cmp(&hdr_value, "[FF05::C]:1900") != 0 &&
		     memptr_cmp(&hdr_value, "[ff05::c]:1900") != 0)) {
			UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
				   "Invalid HOST header from SSDP message\n");

			return FALSE;
		}
	}

	/* passed quick check */
	return TRUE;
}
Esempio n. 4
0
void gena_process_subscription_renewal_request(
	SOCKINFO *info,
	http_message_t *request)
{
    Upnp_SID sid;
    subscription *sub;
    int time_out = 1801;
    service_info *service;
    struct Handle_Info *handle_info;
    UpnpDevice_Handle device_handle;
    memptr temp_hdr;
    membuffer event_url_path;
    memptr timeout_hdr;

    /* if a CALLBACK or NT header is present, then it is an error */
    if( httpmsg_find_hdr( request, HDR_CALLBACK, NULL ) != NULL ||
        httpmsg_find_hdr( request, HDR_NT, NULL ) != NULL ) {
        error_respond( info, HTTP_BAD_REQUEST, request );
        return;
    }
    /* get SID */
    if( httpmsg_find_hdr( request, HDR_SID, &temp_hdr ) == NULL ||
        temp_hdr.length > SID_SIZE ) {
        error_respond( info, HTTP_PRECONDITION_FAILED, request );
        return;
    }
    memcpy( sid, temp_hdr.buf, temp_hdr.length );
    sid[temp_hdr.length] = '\0';

    /* lookup service by eventURL */
    membuffer_init( &event_url_path );
    if( membuffer_append( &event_url_path, request->uri.pathquery.buff,
                          request->uri.pathquery.size ) != 0 ) {
        error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request );
        return;
    }

    HandleLock();

    if (GetDeviceHandleInfoForPath(event_url_path.buf, info->foreign_sockaddr.ss_family,
								   &device_handle, &handle_info, &service) != HND_DEVICE ) {
        error_respond( info, HTTP_PRECONDITION_FAILED, request );
        membuffer_destroy( &event_url_path );
        HandleUnlock();
        return;
    }
    membuffer_destroy( &event_url_path );

    /* get subscription */
    if( service == NULL ||
        !service->active ||
        ( ( sub = GetSubscriptionSID( sid, service ) ) == NULL ) ) {
        error_respond( info, HTTP_PRECONDITION_FAILED, request );
        HandleUnlock();
        return;
    }

    UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__,
        "Renew request: Number of subscriptions already: %d\n "
        "Max Subscriptions allowed:%d\n",
        service->TotalSubscriptions,
        handle_info->MaxSubscriptions );
    /* too many subscriptions */
    if( handle_info->MaxSubscriptions != -1 &&
            service->TotalSubscriptions > handle_info->MaxSubscriptions ) {
        error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request );
        RemoveSubscriptionSID( sub->sid, service );
        HandleUnlock();
        return;
    }
    /* set the timeout */
    if( httpmsg_find_hdr( request, HDR_TIMEOUT, &timeout_hdr ) != NULL ) {
        if( matchstr( timeout_hdr.buf, timeout_hdr.length,
                      "%iSecond-%d%0", &time_out ) == PARSE_OK ) {

            /*nothing */

        } else if( memptr_cmp_nocase( &timeout_hdr, "Second-infinite" ) ==
                   0 ) {

            time_out = -1;      /* inifinite timeout */

        } else {
            time_out = DEFAULT_TIMEOUT; /* default is > 1800 seconds */

        }
    }

    /* replace infinite timeout with max timeout, if possible */
    if( handle_info->MaxSubscriptionTimeOut != -1 ) {
        if( time_out == -1 ||
            time_out > handle_info->MaxSubscriptionTimeOut ) {
            time_out = handle_info->MaxSubscriptionTimeOut;
        }
    }

    if( time_out == -1 ) {
        sub->expireTime = 0;
    } else {
        sub->expireTime = time( NULL ) + time_out;
    }

    if( respond_ok( info, time_out, sub, request ) != UPNP_E_SUCCESS ) {
        RemoveSubscriptionSID( sub->sid, service );
    }

    HandleUnlock();
}
Esempio n. 5
0
void gena_process_subscription_request(
	SOCKINFO *info,
	http_message_t *request)
{
	UpnpSubscriptionRequest *request_struct = UpnpSubscriptionRequest_new();
	Upnp_SID temp_sid;
	int return_code = 1;
	int time_out = 1801;
	service_info *service;
	subscription *sub;
	uuid_upnp uid;
	struct Handle_Info *handle_info;
	void *cookie;
	Upnp_FunPtr callback_fun;
	UpnpDevice_Handle device_handle;
	memptr nt_hdr;
	char *event_url_path = NULL;
	memptr callback_hdr;
	memptr timeout_hdr;
	int rc = 0;

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"Subscription Request Received:\n");

	if (httpmsg_find_hdr(request, HDR_NT, &nt_hdr) == NULL) {
		error_respond(info, HTTP_BAD_REQUEST, request);
		goto exit_function;
	}

	/* check NT header */
	/* Windows Millenium Interoperability: */
	/* we accept either upnp:event, or upnp:propchange for the NT header */
	if (memptr_cmp_nocase(&nt_hdr, "upnp:event") != 0) {
		error_respond(info, HTTP_PRECONDITION_FAILED, request);
		goto exit_function;
	}

	/* if a SID is present then the we have a bad request "incompatible headers" */
	if (httpmsg_find_hdr(request, HDR_SID, NULL) != NULL) {
		error_respond(info, HTTP_BAD_REQUEST, request);
		goto exit_function;
	}
	/* look up service by eventURL */
	event_url_path = str_alloc(request->uri.pathquery.buff, request->uri.pathquery.size);
	if (event_url_path == NULL) {
		error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
		goto exit_function;
	}

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"SubscriptionRequest for event URL path: %s\n",
		event_url_path);

	HandleLock();

	if (GetDeviceHandleInfoForPath(event_url_path, info->foreign_sockaddr.ss_family,
								   &device_handle, &handle_info, &service) != HND_DEVICE) {
		free(event_url_path);
		error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
		HandleUnlock();
		goto exit_function;
	}
	free(event_url_path);

	if (service == NULL || !service->active) {
		error_respond(info, HTTP_NOT_FOUND, request);
		HandleUnlock();
		goto exit_function;
	}

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
		"Subscription Request: Number of Subscriptions already %d\n "
		"Max Subscriptions allowed: %d\n",
		service->TotalSubscriptions,
		handle_info->MaxSubscriptions);

	/* too many subscriptions */
	if (handle_info->MaxSubscriptions != -1 &&
	    service->TotalSubscriptions >= handle_info->MaxSubscriptions) {
		error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
		HandleUnlock();
		goto exit_function;
	}
	/* generate new subscription */
	sub = (subscription *)malloc(sizeof (subscription));
	if (sub == NULL) {
		error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
		HandleUnlock();
		goto exit_function;
	}
	sub->ToSendEventKey = 0;
	sub->active = 0;
	sub->next = NULL;
	sub->DeliveryURLs.size = 0;
	sub->DeliveryURLs.URLs = NULL;
	sub->DeliveryURLs.parsedURLs = NULL;
	if (ListInit(&sub->outgoing, 0, free) != 0) {
		error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
		HandleUnlock();
		goto exit_function;
	}

	/* check for valid callbacks */
	if (httpmsg_find_hdr( request, HDR_CALLBACK, &callback_hdr) == NULL) {
		error_respond(info, HTTP_PRECONDITION_FAILED, request);
		freeSubscriptionList(sub);
		HandleUnlock();
		goto exit_function;
	}
	return_code = create_url_list(&callback_hdr, &sub->DeliveryURLs);
	if (return_code == 0) {
		error_respond(info, HTTP_PRECONDITION_FAILED, request);
		freeSubscriptionList(sub);
		HandleUnlock();
		goto exit_function;
	}
	if (return_code == UPNP_E_OUTOF_MEMORY) {
		error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
		freeSubscriptionList(sub);
		HandleUnlock();
		goto exit_function;
	}
	/* set the timeout */
	if (httpmsg_find_hdr(request, HDR_TIMEOUT, &timeout_hdr) != NULL) {
		if (matchstr(timeout_hdr.buf, timeout_hdr.length,
		    "%iSecond-%d%0", &time_out) == PARSE_OK) {
			/* nothing */
		} else if(memptr_cmp_nocase(&timeout_hdr, "Second-infinite") == 0) {
			/* infinite timeout */
			time_out = -1;
		} else {
			/* default is > 1800 seconds */
			time_out = DEFAULT_TIMEOUT;
		}
	}
	/* replace infinite timeout with max timeout, if possible */
	if (handle_info->MaxSubscriptionTimeOut != -1) {
		if (time_out == -1 ||
		    time_out > handle_info->MaxSubscriptionTimeOut) {
			time_out = handle_info->MaxSubscriptionTimeOut;
		}
	}
	if (time_out >= 0) {
		sub->expireTime = time(NULL) + time_out;
	} else {
		/* infinite time */
		sub->expireTime = 0;
	}

	/* generate SID */
	uuid_create(&uid);
	upnp_uuid_unpack(&uid, temp_sid);
	rc = snprintf(sub->sid, sizeof(sub->sid), "uuid:%s", temp_sid);

	/* respond OK */
	if (rc < 0 || (unsigned int) rc >= sizeof(sub->sid) ||
		(respond_ok(info, time_out,
		sub, request) != UPNP_E_SUCCESS)) {
		freeSubscriptionList(sub);
		HandleUnlock();
		goto exit_function;
	}
	/* add to subscription list */
	sub->next = service->subscriptionList;
	service->subscriptionList = sub;
	service->TotalSubscriptions++;

	/* finally generate callback for init table dump */
	UpnpSubscriptionRequest_strcpy_ServiceId(request_struct, service->serviceId);
	UpnpSubscriptionRequest_strcpy_UDN(request_struct, service->UDN);
	UpnpSubscriptionRequest_strcpy_SID(request_struct, sub->sid);

	/* copy callback */
	callback_fun = handle_info->Callback;
	cookie = handle_info->Cookie;

	HandleUnlock();

	/* make call back with request struct */
	/* in the future should find a way of mainting that the handle */
	/* is not unregistered in the middle of a callback */
	callback_fun(UPNP_EVENT_SUBSCRIPTION_REQUEST, request_struct, cookie);

exit_function:
	UpnpSubscriptionRequest_delete(request_struct);
}
Esempio n. 6
0
/************************************************************************
* Function : gena_process_notification_event
*																	
* Parameters:														
*	IN SOCKINFO *info: Socket structure containing the device socket 
*					information
*	IN http_message_t* event: The http message contains the GENA 
*								notification
*
* Description:														
*	This function processes NOTIFY events that are sent by devices. 
*	called by genacallback()
*
* Returns: void
*
* Note : called by genacallback()
****************************************************************************/
void
gena_process_notification_event( IN SOCKINFO * info,
                                 IN http_message_t * event )
{
    struct Upnp_Event event_struct;
    int eventKey;
    token sid;
    client_subscription *subscription;
    IXML_Document *ChangedVars;
    struct Handle_Info *handle_info;
    void *cookie;
    Upnp_FunPtr callback;
    UpnpClient_Handle client_handle;

    memptr sid_hdr;
    memptr nt_hdr,
      nts_hdr;
    memptr seq_hdr;

    // get SID
    if( httpmsg_find_hdr( event, HDR_SID, &sid_hdr ) == NULL ) {
        error_respond( info, HTTP_PRECONDITION_FAILED, event );

        return;
    }
    sid.buff = sid_hdr.buf;
    sid.size = sid_hdr.length;

    // get event key
    if( httpmsg_find_hdr( event, HDR_SEQ, &seq_hdr ) == NULL ||
        matchstr( seq_hdr.buf, seq_hdr.length, "%d%0", &eventKey )
        != PARSE_OK ) {
        error_respond( info, HTTP_BAD_REQUEST, event );

        return;
    }
    // get NT and NTS headers
    if( httpmsg_find_hdr( event, HDR_NT, &nt_hdr ) == NULL ||
        httpmsg_find_hdr( event, HDR_NTS, &nts_hdr ) == NULL ) {
        error_respond( info, HTTP_BAD_REQUEST, event );

        return;
    }
    // verify NT and NTS headers
    if( memptr_cmp( &nt_hdr, "upnp:event" ) != 0 ||
        memptr_cmp( &nts_hdr, "upnp:propchange" ) != 0 ) {
        error_respond( info, HTTP_PRECONDITION_FAILED, event );

        return;
    }
    // parse the content (should be XML)
    if( !has_xml_content_type( event ) ||
        event->msg.length == 0 ||
        ( ixmlParseBufferEx( event->entity.buf, &ChangedVars ) ) !=
        IXML_SUCCESS ) {
        error_respond( info, HTTP_BAD_REQUEST, event );

        return;
    }

    HandleLock(  );

    // get client info
    if( GetClientHandleInfo( &client_handle, &handle_info ) != HND_CLIENT ) {
        error_respond( info, HTTP_PRECONDITION_FAILED, event );
        HandleUnlock(  );
        ixmlDocument_free( ChangedVars );

        return;
    }
    // get subscription based on SID
    if( ( subscription = GetClientSubActualSID( handle_info->ClientSubList,
                                                &sid ) ) == NULL ) {
        if( eventKey == 0 ) {
            // wait until we've finished processing a subscription 
            //   (if we are in the middle)
            // this is to avoid mistakenly rejecting the first event if we 
            //   receive it before the subscription response
            HandleUnlock(  );

            // try and get Subscription Lock 
            //   (in case we are in the process of subscribing)
            SubscribeLock(  );

            // get HandleLock again
            HandleLock(  );

            if( GetClientHandleInfo( &client_handle, &handle_info )
                != HND_CLIENT ) {
                error_respond( info, HTTP_PRECONDITION_FAILED, event );
                SubscribeUnlock(  );
                HandleUnlock(  );
                ixmlDocument_free( ChangedVars );

                return;
            }

            if( ( subscription =
                  GetClientSubActualSID( handle_info->ClientSubList,
                                         &sid ) ) == NULL ) {
                error_respond( info, HTTP_PRECONDITION_FAILED, event );
                SubscribeUnlock(  );
                HandleUnlock(  );
                ixmlDocument_free( ChangedVars );

                return;
            }

            SubscribeUnlock(  );
        } else {
            error_respond( info, HTTP_PRECONDITION_FAILED, event );
            HandleUnlock(  );
            ixmlDocument_free( ChangedVars );

            return;
        }
    }

    error_respond( info, HTTP_OK, event );  // success

    // fill event struct
    strcpy( event_struct.Sid, subscription->sid );
    event_struct.EventKey = eventKey;
    event_struct.ChangedVariables = ChangedVars;

    // copy callback
    callback = handle_info->Callback;
    cookie = handle_info->Cookie;

    HandleUnlock(  );

    // make callback with event struct
    // In future, should find a way of mainting
    // that the handle is not unregistered in the middle of a
    // callback
    callback( UPNP_EVENT_RECEIVED, &event_struct, cookie );

    ixmlDocument_free( ChangedVars );
}
Esempio n. 7
0
/************************************************************************
* Function : gena_subscribe									
*																	
* Parameters:														
*	IN char *url: url of service to subscribe
*	INOUT int* timeout:subscription time desired (in secs)
*	IN char* renewal_sid:for renewal, this contains a currently h
*						 held subscription SID. For first time 
*						 subscription, this must be NULL
*	OUT char** sid: SID returned by the subscription or renew msg
*
* Description:														
*	This function subscribes or renew subscription
*
* Returns: int
*	return 0 if successful else returns appropriate error
***************************************************************************/
static int
gena_subscribe( IN char *url,
                INOUT int *timeout,
                IN char *renewal_sid,
                OUT char **sid )
{
    int return_code;
    memptr sid_hdr,
      timeout_hdr;
    char timeout_str[25];
    membuffer request;
    uri_type dest_url;
    http_parser_t response;

    *sid = NULL;                // init

    // request timeout to string
    if( ( timeout == NULL ) ||
        ( ( *timeout > 0 )
          && ( *timeout < CP_MINIMUM_SUBSCRIPTION_TIME ) ) ) {
        sprintf( timeout_str, "%d", CP_MINIMUM_SUBSCRIPTION_TIME );
    } else if( *timeout >= 0 ) {
        sprintf( timeout_str, "%d", *timeout );
    } else {
        strcpy( timeout_str, "infinite" );
    }

    // parse url
    return_code = http_FixStrUrl( url, strlen( url ), &dest_url );
    if( return_code != 0 ) {
        return return_code;
    }
    // make request msg
    membuffer_init( &request );
    request.size_inc = 30;
    if( renewal_sid ) {
        // renew subscription
        return_code = http_MakeMessage( &request, 1, 1,
                                        "q" "ssc" "ssc" "c",
                                        HTTPMETHOD_SUBSCRIBE, &dest_url,
                                        "SID: ", renewal_sid,
                                        "TIMEOUT: Second-", timeout_str );
    } else {
        // subscribe
        return_code = http_MakeMessage( &request, 1, 1,
                                        "q" "sssdsscc",
                                        HTTPMETHOD_SUBSCRIBE, &dest_url,
                                        "CALLBACK: <http://", LOCAL_HOST,
                                        ":", LOCAL_PORT,
                                        "/>\r\n" "NT: upnp:event\r\n"
                                        "TIMEOUT: Second-", timeout_str );
    }
    if( return_code != 0 ) {
        return return_code;
    }
    // send request and get reply
    return_code = http_RequestAndResponse( &dest_url, request.buf,
                                           request.length,
                                           HTTPMETHOD_SUBSCRIBE,
                                           HTTP_DEFAULT_TIMEOUT,
                                           &response );

    membuffer_destroy( &request );

    if( return_code != 0 ) {
        httpmsg_destroy( &response.msg );
        return return_code;
    }
    if( response.msg.status_code != HTTP_OK ) {
        httpmsg_destroy( &response.msg );
        return UPNP_E_SUBSCRIBE_UNACCEPTED;
    }
    // get SID and TIMEOUT
    if( httpmsg_find_hdr( &response.msg, HDR_SID, &sid_hdr ) == NULL ||
        sid_hdr.length == 0 ||
        httpmsg_find_hdr( &response.msg,
                          HDR_TIMEOUT, &timeout_hdr ) == NULL ||
        timeout_hdr.length == 0 ) {
        httpmsg_destroy( &response.msg );
        return UPNP_E_BAD_RESPONSE;
    }
    // save timeout
    if( matchstr( timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0",
                  timeout ) == PARSE_OK ) {
        // nothing  
    } else if( memptr_cmp_nocase( &timeout_hdr, "Second-infinite" ) == 0 ) {
        *timeout = -1;
    } else {
        httpmsg_destroy( &response.msg );
        return UPNP_E_BAD_RESPONSE;
    }

    // save SID
    *sid = str_alloc( sid_hdr.buf, sid_hdr.length );
    if( *sid == NULL ) {
        httpmsg_destroy( &response.msg );
        return UPNP_E_OUTOF_MEMORY;
    }

    httpmsg_destroy( &response.msg );
    return UPNP_E_SUCCESS;
}
Esempio n. 8
0
void ssdp_handle_ctrlpt_msg(http_message_t *hmsg, struct sockaddr_storage *dest_addr,
			    int timeout, void *cookie)
{
	int handle;
	struct Handle_Info *ctrlpt_info = NULL;
	memptr hdr_value;
	/* byebye or alive */
	int is_byebye;
	UpnpDiscovery *param = UpnpDiscovery_new();
	int expires;
	int ret;
	SsdpEvent event;
	int nt_found;
	int usn_found;
	int st_found;
	char save_char;
	Upnp_EventType event_type;
	Upnp_FunPtr ctrlpt_callback;
	void *ctrlpt_cookie;
	ListNode *node = NULL;
	SsdpSearchArg *searchArg = NULL;
	int matched = 0;
	SSDPResultData *threadData = NULL;
	ThreadPoolJob job;

	memset(&job, 0, sizeof(job));

	/* we are assuming that there can be only one client supported at a time */
	HandleReadLock();

	if (GetClientHandleInfo(&handle, &ctrlpt_info) != HND_CLIENT) {
		HandleUnlock();
		goto end_ssdp_handle_ctrlpt_msg;
	}
	/* copy */
	ctrlpt_callback = ctrlpt_info->Callback;
	ctrlpt_cookie = ctrlpt_info->Cookie;
	HandleUnlock();
	/* search timeout */
	if (timeout) {
		ctrlpt_callback(UPNP_DISCOVERY_SEARCH_TIMEOUT, NULL, cookie);
		goto end_ssdp_handle_ctrlpt_msg;
	}

	UpnpDiscovery_set_ErrCode(param, UPNP_E_SUCCESS);
	/* MAX-AGE, assume error */
	expires = -1;
	UpnpDiscovery_set_Expires(param, expires);
	if (httpmsg_find_hdr(hmsg, HDR_CACHE_CONTROL, &hdr_value) != NULL) {
		ret = matchstr(hdr_value.buf, hdr_value.length,
			"%imax-age = %d%0", &expires);
		UpnpDiscovery_set_Expires(param, expires);
		if (ret != PARSE_OK)
			goto end_ssdp_handle_ctrlpt_msg;
	}
	/* DATE */
	if (httpmsg_find_hdr(hmsg, HDR_DATE, &hdr_value) != NULL) {
		UpnpDiscovery_strcpy_Date(param, hdr_value.buf);
	}
	/* dest addr */
	UpnpDiscovery_set_DestAddr(param, dest_addr);
	/* EXT */
	if (httpmsg_find_hdr(hmsg, HDR_EXT, &hdr_value) != NULL) {
		UpnpDiscovery_strncpy_Ext(param, hdr_value.buf,
					  hdr_value.length);
	}
	/* LOCATION */
	if (httpmsg_find_hdr(hmsg, HDR_LOCATION, &hdr_value) != NULL) {
		UpnpDiscovery_strncpy_Location(param, hdr_value.buf,
					       hdr_value.length);
	}
	/* SERVER / USER-AGENT */
	if (httpmsg_find_hdr(hmsg, HDR_SERVER, &hdr_value) != NULL ||
	    httpmsg_find_hdr(hmsg, HDR_USER_AGENT, &hdr_value) != NULL) {
		UpnpDiscovery_strncpy_Os(param, hdr_value.buf,
					 hdr_value.length);
	}
	/* clear everything */
	event.UDN[0] = '\0';
	event.DeviceType[0] = '\0';
	event.ServiceType[0] = '\0';
	nt_found = FALSE;
	if (httpmsg_find_hdr(hmsg, HDR_NT, &hdr_value) != NULL) {
		save_char = hdr_value.buf[hdr_value.length];
		hdr_value.buf[hdr_value.length] = '\0';
		nt_found = (ssdp_request_type(hdr_value.buf, &event) == 0);
		hdr_value.buf[hdr_value.length] = save_char;
	}
	usn_found = FALSE;
	if (httpmsg_find_hdr(hmsg, HDR_USN, &hdr_value) != NULL) {
		save_char = hdr_value.buf[hdr_value.length];
		hdr_value.buf[hdr_value.length] = '\0';
		usn_found = (unique_service_name(hdr_value.buf, &event) == 0);
		hdr_value.buf[hdr_value.length] = save_char;
	}
	if (nt_found || usn_found) {
		UpnpDiscovery_strcpy_DeviceID(param, event.UDN);
		UpnpDiscovery_strcpy_DeviceType(param, event.DeviceType);
		UpnpDiscovery_strcpy_ServiceType(param, event.ServiceType);
	}
	/* ADVERT. OR BYEBYE */
	if (hmsg->is_request) {
		/* use NTS hdr to determine advert., or byebye */
		if (httpmsg_find_hdr(hmsg, HDR_NTS, &hdr_value) == NULL) {
			/* error; NTS header not found */
			goto end_ssdp_handle_ctrlpt_msg;
		}
		if (memptr_cmp(&hdr_value, "ssdp:alive") == 0) {
			is_byebye = FALSE;
		} else if (memptr_cmp(&hdr_value, "ssdp:byebye") == 0) {
			is_byebye = TRUE;
		} else {
			/* bad value */
			goto end_ssdp_handle_ctrlpt_msg;
		}
		if (is_byebye) {
			/* check device byebye */
			if (!nt_found || !usn_found) {
				/* bad byebye */
				goto end_ssdp_handle_ctrlpt_msg;
			}
			event_type = UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE;
		} else {
			/* check advertisement.
			 * Expires is valid if positive. This is for testing
			 * only. Expires should be greater than 1800 (30 mins) */
			if (!nt_found ||
			    !usn_found ||
			    UpnpString_get_Length(UpnpDiscovery_get_Location(param)) == 0 ||
			    UpnpDiscovery_get_Expires(param) <= 0) {
				/* bad advertisement */
				goto end_ssdp_handle_ctrlpt_msg;
			}
			event_type = UPNP_DISCOVERY_ADVERTISEMENT_ALIVE;
		}
		/* call callback */
		ctrlpt_callback(event_type, param, ctrlpt_cookie);
	} else {
		/* reply (to a SEARCH) */
		/* only checking to see if there is a valid ST header */
		st_found = FALSE;
		if (httpmsg_find_hdr(hmsg, HDR_ST, &hdr_value) != NULL) {
			save_char = hdr_value.buf[hdr_value.length];
			hdr_value.buf[hdr_value.length] = '\0';
			st_found =
			    ssdp_request_type(hdr_value.buf, &event) == 0;
			hdr_value.buf[hdr_value.length] = save_char;
		}
		if (hmsg->status_code != HTTP_OK ||
		    UpnpDiscovery_get_Expires(param) <= 0 ||
		    UpnpString_get_Length(UpnpDiscovery_get_Location(param)) == 0 ||
		    !usn_found || !st_found) {
			/* bad reply */
			goto end_ssdp_handle_ctrlpt_msg;
		}
		/* check each current search */
		HandleLock();
		if (GetClientHandleInfo(&handle, &ctrlpt_info) != HND_CLIENT) {
			HandleUnlock();
			goto end_ssdp_handle_ctrlpt_msg;
		}
		node = ListHead(&ctrlpt_info->SsdpSearchList);
		/* temporary add null termination */
		/*save_char = hdr_value.buf[ hdr_value.length ]; */
		/*hdr_value.buf[ hdr_value.length ] = '\0'; */
		while (node != NULL) {
			searchArg = node->item;
			/* check for match of ST header and search target */
			switch (searchArg->requestType) {
			case SSDP_ALL:
				matched = 1;
				break;
			case SSDP_ROOTDEVICE:
				matched =
				    (event.RequestType == SSDP_ROOTDEVICE);
				break;
			case SSDP_DEVICEUDN:
				matched = !strncmp(searchArg->searchTarget,
						   hdr_value.buf,
						   hdr_value.length);
				break;
			case SSDP_DEVICETYPE:{
					size_t m = min(hdr_value.length,
						       strlen
						       (searchArg->searchTarget));
					matched =
					    !strncmp(searchArg->searchTarget,
						     hdr_value.buf, m);
					break;
				}
			case SSDP_SERVICE:{
					size_t m = min(hdr_value.length,
						       strlen
						       (searchArg->searchTarget));
					matched =
					    !strncmp(searchArg->searchTarget,
						     hdr_value.buf, m);
					break;
				}
			default:
				matched = 0;
				break;
			}
			if (matched) {
				/* schedule call back */
				threadData = SSDPResultData_new();
				if (threadData != NULL) {
					SSDPResultData_set_Param(threadData,
								 param);
					SSDPResultData_set_Cookie(threadData,
								  searchArg->
								  cookie);
					SSDPResultData_set_CtrlptCallback
					    (threadData, ctrlpt_callback);
					TPJobInit(&job, (start_routine)
						  send_search_result,
						  threadData);
					TPJobSetPriority(&job, MED_PRIORITY);
					TPJobSetFreeFunction(&job,
							     (free_routine)
							     SSDPResultData_delete);
					ThreadPoolAdd(&gRecvThreadPool, &job,
						      NULL);
				}
			}
			node = ListNext(&ctrlpt_info->SsdpSearchList, node);
		}

		HandleUnlock();
		/*ctrlpt_callback( UPNP_DISCOVERY_SEARCH_RESULT, param, cookie ); */
	}

end_ssdp_handle_ctrlpt_msg:
	UpnpDiscovery_delete(param);
}
Esempio n. 9
0
/************************************************************************
* Function : ssdp_handle_device_request									
*																	
* Parameters:														
*		IN http_message_t* hmsg: SSDP search request from the control point
*		IN struct sockaddr_in* dest_addr: The address info of control point
*
* Description:														
*	This function handles the search request. It do the sanity checks of
*	the request and then schedules a thread to send a random time reply (
*	random within maximum time given by the control point to reply).
*
* Returns: void *
*	1 if successful else appropriate error
***************************************************************************/
void
ssdp_handle_device_request( IN http_message_t * hmsg,
                            IN struct sockaddr_in *dest_addr )
{
#define MX_FUDGE_FACTOR 10

    int handle;
    struct Handle_Info *dev_info = NULL;
    memptr hdr_value;
    int mx;
    char save_char;
    SsdpEvent event;
    int ret_code;
    SsdpSearchReply *threadArg = NULL;
    ThreadPoolJob job;
    int replyTime;
    int maxAge;

    // check man hdr
    if( httpmsg_find_hdr( hmsg, HDR_MAN, &hdr_value ) == NULL ||
        memptr_cmp( &hdr_value, "\"ssdp:discover\"" ) != 0 ) {
        return;                 // bad or missing hdr
    }
    // MX header
    if( httpmsg_find_hdr( hmsg, HDR_MX, &hdr_value ) == NULL ||
        ( mx = raw_to_int( &hdr_value, 10 ) ) < 0 ) {
        return;
    }
    // ST header
    if( httpmsg_find_hdr( hmsg, HDR_ST, &hdr_value ) == NULL ) {
        return;
    }
    save_char = hdr_value.buf[hdr_value.length];
    hdr_value.buf[hdr_value.length] = '\0';
    ret_code = ssdp_request_type( hdr_value.buf, &event );
    hdr_value.buf[hdr_value.length] = save_char;    // restore
    if( ret_code == -1 ) {
        return;                 // bad ST header
    }

    HandleLock(  );
    // device info
    if( GetDeviceHandleInfo( &handle, &dev_info ) != HND_DEVICE ) {
        HandleUnlock(  );
        return;                 // no info found
    }
    maxAge = dev_info->MaxAge;
    HandleUnlock(  );

    DBGONLY( UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "ssdp_handle_device_request with Cmd %d SEARCH\n",
                         event.Cmd );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "MAX-AGE     =  %d\n", maxAge );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "MX     =  %d\n", event.Mx );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "DeviceType   =  %s\n", event.DeviceType );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "DeviceUuid   =  %s\n", event.UDN );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "ServiceType =  %s\n", event.ServiceType ); )
Esempio n. 10
0
/************************************************************************
* Function : ssdp_handle_ctrlpt_msg											
*																	
* Parameters:														
*	IN http_message_t* hmsg: SSDP message from the device
*	IN struct sockaddr_in* dest_addr: Address of the device
*	IN xboolean timeout: timeout kept by the control point while sending 
*						search message
*	IN void* cookie: Cookie stored by the control point application. 
*					This cookie will be returned to the control point
*					in the callback 
*																	
* Description:														
*	This function handles the ssdp messages from the devices. These 
*	messages includes the search replies, advertisement of device coming 
*	alive and bye byes.
*
* Returns: void
*
***************************************************************************/
void
ssdp_handle_ctrlpt_msg( IN http_message_t * hmsg,
                        IN struct sockaddr_in *dest_addr,
                        IN xboolean timeout,    // only in search reply

                        IN void *cookie )   // only in search reply
{
    int handle;
    struct Handle_Info *ctrlpt_info = NULL;
    memptr hdr_value;
    xboolean is_byebye;         // byebye or alive
    struct Upnp_Discovery param;
    SsdpEvent event;
    xboolean nt_found,
      usn_found,
      st_found;
    char save_char;
    Upnp_EventType event_type;
    Upnp_FunPtr ctrlpt_callback;
    void *ctrlpt_cookie;
    ListNode *node = NULL;
    SsdpSearchArg *searchArg = NULL;
    int matched = 0;
    ResultData *threadData;
    ThreadPoolJob job;

    // we are assuming that there can be only one client supported at a time

    HandleLock(  );

    if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) {
        HandleUnlock(  );
        return;
    }
    // copy
    ctrlpt_callback = ctrlpt_info->Callback;
    ctrlpt_cookie = ctrlpt_info->Cookie;
    HandleUnlock(  );

    // search timeout
    if( timeout ) {
        ctrlpt_callback( UPNP_DISCOVERY_SEARCH_TIMEOUT, NULL, cookie );
        return;
    }

    param.ErrCode = UPNP_E_SUCCESS;

    // MAX-AGE
    param.Expires = -1;         // assume error
    if( httpmsg_find_hdr( hmsg, HDR_CACHE_CONTROL, &hdr_value ) != NULL ) {
        matchstr( hdr_value.buf, hdr_value.length,
                  "%imax-age = %d%0", &param.Expires );
    }

    // DATE
    param.Date[0] = '\0';
    if( httpmsg_find_hdr( hmsg, HDR_DATE, &hdr_value ) != NULL ) {
        linecopylen( param.Date, hdr_value.buf, hdr_value.length );
    }

    // dest addr
    param.DestAddr = dest_addr;

    // EXT
    param.Ext[0] = '\0';
    if( httpmsg_find_hdr( hmsg, HDR_EXT, &hdr_value ) != NULL ) {
        linecopylen( param.Ext, hdr_value.buf, hdr_value.length );
    }
    // LOCATION
    param.Location[0] = '\0';
    if( httpmsg_find_hdr( hmsg, HDR_LOCATION, &hdr_value ) != NULL ) {
        linecopylen( param.Location, hdr_value.buf, hdr_value.length );
    }
    // SERVER / USER-AGENT
    param.Os[0] = '\0';
    if( httpmsg_find_hdr( hmsg, HDR_SERVER, &hdr_value ) != NULL ||
        httpmsg_find_hdr( hmsg, HDR_USER_AGENT, &hdr_value ) != NULL ) {
        linecopylen( param.Os, hdr_value.buf, hdr_value.length );
    }
    // clear everything
    param.DeviceId[0] = '\0';
    param.DeviceType[0] = '\0';
    param.ServiceType[0] = '\0';

    param.ServiceVer[0] = '\0'; // not used; version is in ServiceType

    event.UDN[0] = '\0';
    event.DeviceType[0] = '\0';
    event.ServiceType[0] = '\0';

    nt_found = FALSE;

    if( httpmsg_find_hdr( hmsg, HDR_NT, &hdr_value ) != NULL ) {
        save_char = hdr_value.buf[hdr_value.length];
        hdr_value.buf[hdr_value.length] = '\0';

        nt_found = ( ssdp_request_type( hdr_value.buf, &event ) == 0 );

        hdr_value.buf[hdr_value.length] = save_char;
    }

    usn_found = FALSE;
    if( httpmsg_find_hdr( hmsg, HDR_USN, &hdr_value ) != NULL ) {
        save_char = hdr_value.buf[hdr_value.length];
        hdr_value.buf[hdr_value.length] = '\0';

        usn_found = ( unique_service_name( hdr_value.buf, &event ) == 0 );

        hdr_value.buf[hdr_value.length] = save_char;
    }

    if( nt_found || usn_found ) {
        strcpy( param.DeviceId, event.UDN );
        strcpy( param.DeviceType, event.DeviceType );
        strcpy( param.ServiceType, event.ServiceType );
    }

    // ADVERT. OR BYEBYE
    if( hmsg->is_request ) {
        // use NTS hdr to determine advert., or byebye
        //
        if( httpmsg_find_hdr( hmsg, HDR_NTS, &hdr_value ) == NULL ) {
            return;             // error; NTS header not found
        }
        if( memptr_cmp( &hdr_value, "ssdp:alive" ) == 0 ) {
            is_byebye = FALSE;
        } else if( memptr_cmp( &hdr_value, "ssdp:byebye" ) == 0 ) {
            is_byebye = TRUE;
        } else {
            return;             // bad value
        }

        if( is_byebye ) {
            // check device byebye
            if( !nt_found || !usn_found ) {
                return;         // bad byebye
            }
            event_type = UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE;
        } else {
            // check advertisement      
            // .Expires is valid if positive. This is for testing
            //  only. Expires should be greater than 1800 (30 mins)
            if( !nt_found ||
                !usn_found ||
                strlen( param.Location ) == 0 || param.Expires <= 0 ) {
                return;         // bad advertisement
            }

            event_type = UPNP_DISCOVERY_ADVERTISEMENT_ALIVE;
        }

        // call callback
        ctrlpt_callback( event_type, &param, ctrlpt_cookie );

    } else                      // reply (to a SEARCH)
    {
        // only checking to see if there is a valid ST header
        st_found = FALSE;
        if( httpmsg_find_hdr( hmsg, HDR_ST, &hdr_value ) != NULL ) {
            save_char = hdr_value.buf[hdr_value.length];
            hdr_value.buf[hdr_value.length] = '\0';
            st_found = ssdp_request_type( hdr_value.buf, &event ) == 0;
            hdr_value.buf[hdr_value.length] = save_char;
        }
        if( hmsg->status_code != HTTP_OK ||
            param.Expires <= 0 ||
            strlen( param.Location ) == 0 || !usn_found || !st_found ) {
            return;             // bad reply
        }
        //check each current search
        HandleLock(  );
        if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) {
            HandleUnlock(  );
            return;
        }
        node = ListHead( &ctrlpt_info->SsdpSearchList );

        //temporary add null termination
        //save_char = hdr_value.buf[ hdr_value.length ];
        //hdr_value.buf[ hdr_value.length ] = '\0';

        while( node != NULL ) {
            searchArg = node->item;
            matched = 0;
            //check for match of ST header and search target
            switch ( searchArg->requestType ) {
                case SSDP_ALL:
                    {
                        matched = 1;
                        break;
                    }
                case SSDP_ROOTDEVICE:
                    {
                        matched = ( event.RequestType == SSDP_ROOTDEVICE );
                        break;
                    }
                case SSDP_DEVICEUDN:
                    {
                        matched = !( strncmp( searchArg->searchTarget,
                                              hdr_value.buf,
                                              hdr_value.length ) );
                        break;
                    }
                case SSDP_DEVICETYPE:
                    {
                        int m = min( hdr_value.length,
                                     strlen( searchArg->searchTarget ) );

                        matched = !( strncmp( searchArg->searchTarget,
                                              hdr_value.buf, m ) );
                        break;
                    }
                case SSDP_SERVICE:
                    {
                        int m = min( hdr_value.length,
                                     strlen( searchArg->searchTarget ) );

                        matched = !( strncmp( searchArg->searchTarget,
                                              hdr_value.buf, m ) );
                        break;
                    }
                default:
                    {
                        matched = 0;
                        break;
                    }
            }

            if( matched ) {
                //schedule call back
                threadData =
                    ( ResultData * ) malloc( sizeof( ResultData ) );
                if( threadData != NULL ) {
                    threadData->param = param;
                    threadData->cookie = searchArg->cookie;
                    threadData->ctrlpt_callback = ctrlpt_callback;
                    TPJobInit( &job, ( start_routine ) send_search_result,
                               threadData );
                    TPJobSetPriority( &job, MED_PRIORITY );
                    TPJobSetFreeFunction( &job, ( free_routine ) free );
                    ThreadPoolAdd( &gRecvThreadPool, &job, NULL );
                }
            }
            node = ListNext( &ctrlpt_info->SsdpSearchList, node );
        }

        HandleUnlock(  );
        //ctrlpt_callback( UPNP_DISCOVERY_SEARCH_RESULT, &param, cookie );
    }
}
Esempio n. 11
0
/*!
 * \brief This function retrives the name of the SOAP action.
 *
 * \return 0 if successful else returns appropriate error.
 */
static UPNP_INLINE int get_request_type(
	/*! [in] HTTP request. */
	http_message_t *request,
	/*! [out] SOAP action name. */
	memptr *action_name)
{
	memptr value;
	memptr ns_value, dummy_quote;
	http_header_t *hdr;
	char save_char;
	char *s;
	membuffer soap_action_name;
	size_t n;

	/* find soapaction header */
	if (request->method == SOAPMETHOD_POST) {
		if (!httpmsg_find_hdr(request, HDR_SOAPACTION, &value))
			return SREQ_HDR_NOT_FOUND;
	} else {
		/* M-POST */
		/* get NS value from MAN header */
		hdr = httpmsg_find_hdr(request, HDR_MAN, &value);
		if (hdr == NULL)
			return SREQ_HDR_NOT_FOUND;
		if (matchstr(value.buf, value.length, "%q%i ; ns = %s",
			     &dummy_quote, &ns_value) != 0)
			return SREQ_BAD_HDR_FORMAT;
		/* create soapaction name header */
		membuffer_init(&soap_action_name);
		if (membuffer_assign(&soap_action_name,
			ns_value.buf, ns_value.length) == UPNP_E_OUTOF_MEMORY ||
		    membuffer_append_str(&soap_action_name,
			"-SOAPACTION") == UPNP_E_OUTOF_MEMORY) {
			membuffer_destroy(&soap_action_name);
			return UPNP_E_OUTOF_MEMORY;
		}
		hdr = httpmsg_find_hdr_str(request, soap_action_name.buf);
		membuffer_destroy(&soap_action_name);
		if (!hdr)
			return SREQ_HDR_NOT_FOUND;
		value.buf = hdr->value.buf;
		value.length = hdr->value.length;
	}
	/* determine type */
	save_char = value.buf[value.length];
	value.buf[value.length] = '\0';
	s = strchr(value.buf, '#');
	if (s == NULL) {
		value.buf[value.length] = save_char;
		return SREQ_BAD_HDR_FORMAT;
	}
	/* move to value */
	s++;
	n = value.length - (size_t)(s - value.buf);
	if (matchstr(s, n, "%s", action_name) != PARSE_OK) {
		value.buf[value.length] = save_char;
		return SREQ_BAD_HDR_FORMAT;
	}
	/* action name or variable ? */
	if (memptr_cmp(action_name, "QueryStateVariable") == 0) {
		/* query variable */
		action_name->buf = NULL;
		action_name->length = 0;
	}
	/* restore */
	value.buf[value.length] = save_char;

	return 0;
}
Esempio n. 12
0
/*!
 * \brief Checks the HTTP header of the SOAP request coming from the
 * control point.
 *
 * \return UPNP_E_SUCCESS if successful else returns appropriate error.
 */
static int check_soap_action_header(
	/*! [in] HTTP request. */
	http_message_t * request,
	/*! [in] URN. */
	const char *urn,
	/*! [out] Name of the SOAP action. */
	char **actionName)
{
	memptr header_name;
	http_header_t *soap_action_header = NULL;
	char *ns_compare = NULL;
	size_t tempSize = 0;
	int ret_code = UPNP_E_SUCCESS;
	char *temp_header_value = NULL;
	char *temp = NULL;
	char *temp2 = NULL;

	/* check soap action header */
	soap_action_header = httpmsg_find_hdr(request, HDR_SOAPACTION,
					      &header_name);
	if (!soap_action_header) {
		ret_code = UPNP_E_INVALID_ACTION;
		return ret_code;
	}
	if (soap_action_header->value.length <= 0) {
		ret_code = UPNP_E_INVALID_ACTION;
		return ret_code;
	}
	temp_header_value = malloc(soap_action_header->value.length + 1);
	if (!temp_header_value) {
		ret_code = UPNP_E_OUTOF_MEMORY;
		free(temp_header_value);
		return ret_code;
	}
	strncpy(temp_header_value, soap_action_header->value.buf,
		soap_action_header->value.length);
	temp_header_value[soap_action_header->value.length] = 0;
	temp = strchr(temp_header_value, '#');
	if (!temp) {
		free(temp_header_value);
		ret_code = UPNP_E_INVALID_ACTION;
		return ret_code;
	}

	(*temp) = 0;		/* temp make string */

	/* check to see if it is Query State Variable or
	 * Service Action */
	tempSize = strlen(urn) + 2;
	ns_compare = malloc(tempSize);
	if (!ns_compare) {
		ret_code = UPNP_E_OUTOF_MEMORY;
		free(temp_header_value);
		return ret_code;
	}
	snprintf(ns_compare, tempSize, "\"%s", urn);
	/* Don't check version number, to accept a request comming on a v1
	 * service  when publishing a v2 service */
	if (strncmp(temp_header_value, ns_compare, strlen(ns_compare) - 2))
		ret_code = UPNP_E_INVALID_ACTION;
	else {
		ret_code = UPNP_E_SUCCESS;
		temp++;
		temp2 = strchr(temp, '\"');
		/* remove ending " if present */
		if (temp2)
			(*temp2) = 0;
		if (*temp)
			(*actionName) = strdup(temp);
		if (!*actionName)
			ret_code = UPNP_E_OUTOF_MEMORY;
	}

	free(temp_header_value);
	free(ns_compare);
	return ret_code;
}
Esempio n. 13
0
void gena_process_notification_event(
	SOCKINFO *info,
	http_message_t *event)
{
	struct Upnp_Event event_struct;
	IXML_Document *ChangedVars = NULL;
	int eventKey;
	token sid;
	ClientSubscription *subscription = NULL;
	struct Handle_Info *handle_info;
	void *cookie;
	Upnp_FunPtr callback;
	UpnpClient_Handle client_handle;
	const UpnpString *tmpSID = NULL;

	memptr sid_hdr;
	memptr nt_hdr,
	nts_hdr;
	memptr seq_hdr;

	/* get SID */
	if (httpmsg_find_hdr(event, HDR_SID, &sid_hdr) == NULL) {
		error_respond(info, HTTP_PRECONDITION_FAILED, event);
		goto exit_function;
	}
	sid.buff = sid_hdr.buf;
	sid.size = sid_hdr.length;

	/* get event key */
	if (httpmsg_find_hdr(event, HDR_SEQ, &seq_hdr) == NULL ||
	    matchstr(seq_hdr.buf, seq_hdr.length, "%d%0", &eventKey) != PARSE_OK) {
		error_respond( info, HTTP_BAD_REQUEST, event );
		goto exit_function;
	}

	/* get NT and NTS headers */
	if (httpmsg_find_hdr(event, HDR_NT, &nt_hdr) == NULL ||
	    httpmsg_find_hdr(event, HDR_NTS, &nts_hdr) == NULL) {
		error_respond( info, HTTP_BAD_REQUEST, event );
		goto exit_function;
	}

	/* verify NT and NTS headers */
	if (memptr_cmp(&nt_hdr, "upnp:event") != 0 ||
	    memptr_cmp(&nts_hdr, "upnp:propchange") != 0) {
		error_respond(info, HTTP_PRECONDITION_FAILED, event);
		goto exit_function;
	}

	/* parse the content (should be XML) */
	if (!has_xml_content_type(event) ||
	    event->msg.length == 0 ||
	    ixmlParseBufferEx(event->entity.buf, &ChangedVars) != IXML_SUCCESS) {
		error_respond(info, HTTP_BAD_REQUEST, event);
		goto exit_function;
	}

	HandleLock();

	/* get client info */
	if (GetClientHandleInfo(&client_handle, &handle_info) != HND_CLIENT) {
		error_respond(info, HTTP_PRECONDITION_FAILED, event);
		HandleUnlock();
		goto exit_function;
	}

	/* get subscription based on SID */
	subscription = GetClientSubActualSID(handle_info->ClientSubList, &sid);
	if (subscription == NULL) {
		if (eventKey == 0) {
			/* wait until we've finished processing a subscription  */
			/*   (if we are in the middle) */
			/* this is to avoid mistakenly rejecting the first event if we  */
			/*   receive it before the subscription response */
			HandleUnlock();

			/* try and get Subscription Lock  */
			/*   (in case we are in the process of subscribing) */
			SubscribeLock();

			/* get HandleLock again */
			HandleLock();

			if (GetClientHandleInfo(&client_handle, &handle_info) != HND_CLIENT) {
				error_respond(info, HTTP_PRECONDITION_FAILED, event);
				SubscribeUnlock();
				HandleUnlock();
				goto exit_function;
			}

			subscription = GetClientSubActualSID(handle_info->ClientSubList, &sid);
			if (subscription == NULL) {
				error_respond( info, HTTP_PRECONDITION_FAILED, event );
				SubscribeUnlock();
				HandleUnlock();
				goto exit_function;
			}

			SubscribeUnlock();
		} else {
			error_respond( info, HTTP_PRECONDITION_FAILED, event );
			HandleUnlock();
			goto exit_function;
		}
	}

	/* success */
	error_respond(info, HTTP_OK, event);

	/* fill event struct */
	tmpSID = UpnpClientSubscription_get_SID(subscription);
	memset(event_struct.Sid, 0, sizeof(event_struct.Sid));
	strncpy(event_struct.Sid, UpnpString_get_String(tmpSID),
		sizeof(event_struct.Sid) - 1);
	event_struct.EventKey = eventKey;
	event_struct.ChangedVariables = ChangedVars;

	/* copy callback */
	callback = handle_info->Callback;
	cookie = handle_info->Cookie;

	HandleUnlock();

	/* make callback with event struct */
	/* In future, should find a way of mainting */
	/* that the handle is not unregistered in the middle of a */
	/* callback */
	callback(UPNP_EVENT_RECEIVED, &event_struct, cookie);

exit_function:
	ixmlDocument_free(ChangedVars);
}
Esempio n. 14
0
/*!
 * \brief Subscribes or renew subscription.
 *
 * \return 0 if successful, otherwise returns the appropriate error code.
 */
static int gena_subscribe(
	/*! [in] URL of service to subscribe. */
	IN const UpnpString *url,
	/*! [in,out] Subscription time desired (in secs). */
	INOUT int *timeout,
	/*! [in] for renewal, this contains a currently held subscription SID.
	 * For first time subscription, this must be NULL. */
	IN const UpnpString *renewal_sid,
	/*! [out] SID returned by the subscription or renew msg. */
	OUT UpnpString *sid)
{
	int return_code;
	int parse_ret = 0;
	int local_timeout = CP_MINIMUM_SUBSCRIPTION_TIME;
	memptr sid_hdr;
	memptr timeout_hdr;
	char timeout_str[25];
	membuffer request;
	uri_type dest_url;
	http_parser_t response;
	int rc = 0;

	UpnpString_clear(sid);

	/* request timeout to string */
	if (timeout == NULL) {
		timeout = &local_timeout;
	}
	if (*timeout < 0) {
		memset(timeout_str, 0, sizeof(timeout_str));
		strncpy(timeout_str, "infinite", sizeof(timeout_str) - 1);
	} else if(*timeout < CP_MINIMUM_SUBSCRIPTION_TIME) {
		rc = snprintf(timeout_str, sizeof(timeout_str),
			"%d", CP_MINIMUM_SUBSCRIPTION_TIME);
	} else {
		rc = snprintf(timeout_str, sizeof(timeout_str), "%d", *timeout);
	}
	if (rc < 0 || (unsigned int) rc >= sizeof(timeout_str))
		return UPNP_E_OUTOF_MEMORY;

	/* parse url */
	return_code = http_FixStrUrl(
		UpnpString_get_String(url),
		UpnpString_get_Length(url),
		&dest_url);
	if (return_code != 0) {
		return return_code;
	}

	/* make request msg */
	membuffer_init(&request);
	request.size_inc = 30;
	if (renewal_sid) {
		/* renew subscription */
		return_code = http_MakeMessage(
			&request, 1, 1,
			"q" "ssc" "sscc",
			HTTPMETHOD_SUBSCRIBE, &dest_url,
			"SID: ", UpnpString_get_String(renewal_sid),
			"TIMEOUT: Second-", timeout_str );
	} else {
		/* subscribe */
		if (dest_url.hostport.IPaddress.ss_family == AF_INET6) {
			struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&dest_url.hostport.IPaddress;
			return_code = http_MakeMessage(
				&request, 1, 1,
				"q" "sssdsc" "sc" "sscc",
				HTTPMETHOD_SUBSCRIBE, &dest_url,
				"CALLBACK: <http://[",
				(IN6_IS_ADDR_LINKLOCAL(&DestAddr6->sin6_addr) || strlen(gIF_IPV6_ULA_GUA) == 0) ?
					gIF_IPV6 : gIF_IPV6_ULA_GUA,
				"]:", LOCAL_PORT_V6, "/>",
				"NT: upnp:event",
				"TIMEOUT: Second-", timeout_str);
		} else {
			return_code = http_MakeMessage(
				&request, 1, 1,
				"q" "sssdsc" "sc" "sscc",
				HTTPMETHOD_SUBSCRIBE, &dest_url,
				"CALLBACK: <http://", gIF_IPV4, ":", LOCAL_PORT_V4, "/>",
				"NT: upnp:event",
				"TIMEOUT: Second-", timeout_str);
		}
	}
	if (return_code != 0) {
		return return_code;
	}

	/* send request and get reply */
	return_code = http_RequestAndResponse(&dest_url, request.buf,
		request.length,
		HTTPMETHOD_SUBSCRIBE,
		HTTP_DEFAULT_TIMEOUT,
		&response);
	membuffer_destroy(&request);

	if (return_code != 0) {
		httpmsg_destroy(&response.msg);

		return return_code;
	}
	if (response.msg.status_code != HTTP_OK) {
		httpmsg_destroy(&response.msg);

		return UPNP_E_SUBSCRIBE_UNACCEPTED;
	}

	/* get SID and TIMEOUT */
	if (httpmsg_find_hdr(&response.msg, HDR_SID, &sid_hdr) == NULL ||
	    sid_hdr.length == 0 ||
	    httpmsg_find_hdr( &response.msg, HDR_TIMEOUT, &timeout_hdr ) == NULL ||
	    timeout_hdr.length == 0 ) {
		httpmsg_destroy( &response.msg );

		return UPNP_E_BAD_RESPONSE;
	}

	/* save timeout */
	parse_ret = matchstr(timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0", timeout);
	if (parse_ret == PARSE_OK) {
		/* nothing to do */
	} else if (memptr_cmp_nocase(&timeout_hdr, "Second-infinite") == 0) {
		*timeout = -1;
	} else {
		httpmsg_destroy( &response.msg );

		return UPNP_E_BAD_RESPONSE;
	}

	/* save SID */
	UpnpString_set_StringN(sid, sid_hdr.buf, sid_hdr.length);
	if (UpnpString_get_String(sid) == NULL) {
		httpmsg_destroy(&response.msg);

		return UPNP_E_OUTOF_MEMORY;
	}
	httpmsg_destroy(&response.msg);

	return UPNP_E_SUCCESS;
}
Esempio n. 15
0
void ssdp_handle_device_request(http_message_t *hmsg, struct sockaddr_storage *dest_addr)
{
#define MX_FUDGE_FACTOR 10
	int handle;
	struct Handle_Info *dev_info = NULL;
	memptr hdr_value;
	int mx;
	char save_char;
	SsdpEvent event;
	int ret_code;
	SsdpSearchReply *threadArg = NULL;
	ThreadPoolJob job;
	int replyTime;
	int maxAge;

	memset(&job, 0, sizeof(job));

	/* check man hdr. */
	if (httpmsg_find_hdr(hmsg, HDR_MAN, &hdr_value) == NULL ||
	    memptr_cmp(&hdr_value, "\"ssdp:discover\"") != 0)
		/* bad or missing hdr. */
		return;
	/* MX header. */
	if (httpmsg_find_hdr(hmsg, HDR_MX, &hdr_value) == NULL ||
	    (mx = raw_to_int(&hdr_value, 10)) < 0)
		return;
	/* ST header. */
	if (httpmsg_find_hdr(hmsg, HDR_ST, &hdr_value) == NULL)
		return;
	save_char = hdr_value.buf[hdr_value.length];
	hdr_value.buf[hdr_value.length] = '\0';
	ret_code = ssdp_request_type(hdr_value.buf, &event);
	/* restore. */
	hdr_value.buf[hdr_value.length] = save_char;
	if (ret_code == -1)
		/* bad ST header. */
		return;

	HandleLock();
	/* device info. */
	switch (GetDeviceHandleInfo((int)dest_addr->ss_family,
				&handle, &dev_info)) {
	case HND_DEVICE:
		break;
	default:
		HandleUnlock();
		/* no info found. */
		return;
	}
	maxAge = dev_info->MaxAge;
	HandleUnlock();

	UpnpPrintf(UPNP_PACKET, API, __FILE__, __LINE__,
		   "MAX-AGE     =  %d\n", maxAge);
	UpnpPrintf(UPNP_PACKET, API, __FILE__, __LINE__,
		   "MX     =  %d\n", event.Mx);
	UpnpPrintf(UPNP_PACKET, API, __FILE__, __LINE__,
		   "DeviceType   =  %s\n", event.DeviceType);
	UpnpPrintf(UPNP_PACKET, API, __FILE__, __LINE__,
		   "DeviceUuid   =  %s\n", event.UDN);
	UpnpPrintf(UPNP_PACKET, API, __FILE__, __LINE__,
		   "ServiceType =  %s\n", event.ServiceType);
	threadArg = (SsdpSearchReply *)malloc(sizeof(SsdpSearchReply));
	if (threadArg == NULL)
		return;
	threadArg->handle = handle;
	memcpy(&threadArg->dest_addr, dest_addr, sizeof(threadArg->dest_addr));
	threadArg->event = event;
	threadArg->MaxAge = maxAge;

	TPJobInit(&job, advertiseAndReplyThread, threadArg);
	TPJobSetFreeFunction(&job, (free_routine) free);

	/* Subtract a percentage from the mx to allow for network and processing
	 * delays (i.e. if search is for 30 seconds, respond
	 * within 0 - 27 seconds). */
	if (mx >= 2)
		mx -= MAXVAL(1, mx / MX_FUDGE_FACTOR);
	if (mx < 1)
		mx = 1;
	replyTime = rand() % mx;
	TimerThreadSchedule(&gTimerThread, replyTime, REL_SEC, &job,
			    SHORT_TERM, NULL);
}
Esempio n. 16
0
/****************************************************************************
*	Function :	get_request_type
*
*	Parameters :
*			IN http_message_t* request :	HTTP request
*			OUT memptr* action_name :	SOAP action name
*
*	Description :	This function retrives the name of the SOAP action
*
*	Return : int
*		0 if successful else returns appropriate error.
*	Note :
****************************************************************************/
static XINLINE int
get_request_type( IN http_message_t * request,
                  OUT memptr * action_name )
{
    memptr value;
    memptr ns_value,
      dummy_quote;
    http_header_t *hdr;
    char save_char;
    char *s;
    membuffer soap_action_name;

    // find soapaction header
    //
    if( request->method == SOAPMETHOD_POST ) {
        if( httpmsg_find_hdr( request, HDR_SOAPACTION, &value )
            == NULL ) {
            return SREQ_HDR_NOT_FOUND;
        }
    } else                      // M-POST
    {
        // get NS value from MAN header
        hdr = httpmsg_find_hdr( request, HDR_MAN, &value );
        if( hdr == NULL ) {
            return SREQ_HDR_NOT_FOUND;
        }

        if( matchstr( value.buf, value.length, "%q%i ; ns = %s",
                      &dummy_quote, &ns_value ) != 0 ) {
            return SREQ_BAD_HDR_FORMAT;
        }
        // create soapaction name header
        membuffer_init( &soap_action_name );
        if( ( membuffer_assign( &soap_action_name,
                                ns_value.buf, ns_value.length )
              == UPNP_E_OUTOF_MEMORY ) ||
            ( membuffer_append_str( &soap_action_name,
                                    "-SOAPACTION" ) ==
              UPNP_E_OUTOF_MEMORY )
             ) {
            membuffer_destroy( &soap_action_name );
            return UPNP_E_OUTOF_MEMORY;
        }

        hdr = httpmsg_find_hdr_str( request, soap_action_name.buf );
        membuffer_destroy( &soap_action_name );
        if( hdr == NULL ) {
            return SREQ_HDR_NOT_FOUND;
        }

        value.buf = hdr->value.buf;
        value.length = hdr->value.length;
    }

    // determine type
    //
    save_char = value.buf[value.length];
    value.buf[value.length] = '\0';

    s = strchr( value.buf, '#' );
    if( s == NULL ) {
        value.buf[value.length] = save_char;
        return SREQ_BAD_HDR_FORMAT;
    }

    s++;                        // move to value

    if( matchstr( s, value.length - ( s - value.buf ), "%s",
                  action_name ) != PARSE_OK ) {
        value.buf[value.length] = save_char;
        return SREQ_BAD_HDR_FORMAT;
    }
    // action name or variable ?
    if( memptr_cmp( action_name, "QueryStateVariable" ) == 0 ) {
        // query variable
        action_name->buf = NULL;
        action_name->length = 0;
    }

    value.buf[value.length] = save_char;    // restore
    return 0;
}
Esempio n. 17
0
/****************************************************************************
*	Function :	check_soap_action_header
*
*	Parameters :
*		IN http_message_t *request : HTTP request
*		IN const char *urn :
*		OUT char **actionName :	 name of the SOAP action
*
*	Description :	This function checks the HTTP header of the SOAP request
*		coming from the control point
*
*	Return :	static int
*		UPNP_E_SUCCESS if successful else returns appropriate error
*
*	Note :
****************************************************************************/
static int
check_soap_action_header( IN http_message_t * request,
                          IN const char *urn,
                          OUT char **actionName )
{
    memptr header_name;
    http_header_t *soap_action_header = NULL;
    char *ns_compare = NULL;
    int tempSize = 0;
    int ret_code = UPNP_E_SUCCESS;
    char *temp_header_value = NULL;
    char *temp = NULL;
    char *temp2 = NULL;

    //check soap action header

    soap_action_header = httpmsg_find_hdr( request, HDR_SOAPACTION,
                                           &header_name );

    if( !soap_action_header ) {
        ret_code = UPNP_E_INVALID_ACTION;
        return ret_code;
    }

    if( soap_action_header->value.length <= 0 ) {
        ret_code = UPNP_E_INVALID_ACTION;
        return ret_code;
    }

    temp_header_value =
        ( char * )malloc( soap_action_header->value.length + 1 );

    if( !temp_header_value ) {
        ret_code = UPNP_E_OUTOF_MEMORY;
        free( temp_header_value );
        return ret_code;
    }

    strncpy( temp_header_value, soap_action_header->value.buf,
             soap_action_header->value.length );
    temp_header_value[soap_action_header->value.length] = 0;

    temp = strchr( temp_header_value, '#' );
    if( !temp ) {
        free( temp_header_value );
        ret_code = UPNP_E_INVALID_ACTION;
        return ret_code;
    }

    ( *temp ) = 0;              //temp make string

    //check to see if it is Query State Variable or
    //Service Action

    tempSize = strlen( urn ) + 2;

    ns_compare = ( char * )malloc( tempSize );

    if( !ns_compare ) {
        ret_code = UPNP_E_OUTOF_MEMORY;
        free( temp_header_value );
        return ret_code;
    }

    snprintf( ns_compare, tempSize, "\"%s", urn );

    if( strcmp( temp_header_value, ns_compare ) ) {
        ret_code = UPNP_E_INVALID_ACTION;
    } else {
        ret_code = UPNP_E_SUCCESS;
        temp++;
        temp2 = strchr( temp, '\"' );

        if( temp2 )             //remove ending " if present
        {
            ( *temp2 ) = 0;
        }

        if( *temp )
            ( *actionName ) = strdup( temp );
        if( !*actionName ) {
            ret_code = UPNP_E_OUTOF_MEMORY;
        }
    }

    free( temp_header_value );
    free( ns_compare );
    return ret_code;
}