Example #1
0
/************************************************************************
 * Function: handle_request
 *
 * Parameters:
 *	void *args - Request Message to be handled
 *
 * Description:
 * 	Receive the request and dispatch it for handling
 *
 * Return: void
 ************************************************************************/
static void
handle_request( void *args )
{
    SOCKINFO info;
    int http_error_code;
    int ret_code;
    int major = 1;
    int minor = 1;
    http_parser_t parser;
    http_message_t *hmsg = NULL;
    int timeout = HTTP_DEFAULT_TIMEOUT;
    struct mserv_request_t *request = ( struct mserv_request_t * )args;
    int connfd = request->connfd;

    dlnaPrintf( DLNA_INFO, MSERV, __FILE__, __LINE__,
        "miniserver %d: READING\n", connfd );
    //parser_request_init( &parser ); ////LEAK_FIX_MK
    hmsg = &parser.msg;

    if( sock_init_with_ip( &info, connfd, request->foreign_ip_addr,
                           request->foreign_ip_port ) != DLNA_E_SUCCESS ) {
        free( request );
        httpmsg_destroy( hmsg );
        return;
    }
    // read
    ret_code = http_RecvMessage( &info, &parser, HTTPMETHOD_UNKNOWN,
                                 &timeout, &http_error_code );
    if( ret_code != 0 ) {
        goto error_handler;
    }

    dlnaPrintf( DLNA_INFO, MSERV, __FILE__, __LINE__,
        "miniserver %d: PROCESSING...\n", connfd );
    // dispatch
    http_error_code = dispatch_request( &info, &parser );
    if( http_error_code != 0 ) {
        goto error_handler;
    }

    http_error_code = 0;

  error_handler:
    if( http_error_code > 0 ) {
        if( hmsg ) {
            major = hmsg->major_version;
            minor = hmsg->minor_version;
        }
        handle_error( &info, http_error_code, major, minor );
    }

    dlnaPrintf( DLNA_INFO, MSERV, __FILE__, __LINE__,
        "miniserver %d: COMPLETE\n", connfd );
    sock_destroy( &info, SD_BOTH ); //should shutdown completely

    httpmsg_destroy( hmsg );
    free( request );
}
Example #2
0
/*!
 * \brief Receive the request and dispatch it for handling.
 */
static void handle_request(
	/*! [in] Request Message to be handled. */
	void *args)
{
	SOCKINFO info;
	int http_error_code;
	int ret_code;
	int major = 1;
	int minor = 1;
	http_parser_t parser;
	http_message_t *hmsg = NULL;
	int timeout = HTTP_DEFAULT_TIMEOUT;
	struct mserv_request_t *request = (struct mserv_request_t *)args;
	SOCKET connfd = request->connfd;

	UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
		"miniserver %d: READING\n", connfd );
	/* parser_request_init( &parser ); */ /* LEAK_FIX_MK */
	hmsg = &parser.msg;
	ret_code = sock_init_with_ip(
		&info, connfd, (struct sockaddr *)&request->foreign_sockaddr);
	if (ret_code != UPNP_E_SUCCESS) {
		free(request);
		httpmsg_destroy(hmsg);
		return;
	}
	/* read */
	ret_code = http_RecvMessage(
		&info, &parser, HTTPMETHOD_UNKNOWN, &timeout, &http_error_code);
	if (ret_code != 0) {
		goto error_handler;
	}
	UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
		"miniserver %d: PROCESSING...\n", connfd);
	/* dispatch */
	http_error_code = dispatch_request(&info, &parser);
	if (http_error_code != 0) {
		goto error_handler;
	}
	http_error_code = 0;

error_handler:
	if (http_error_code > 0) {
		if (hmsg) {
			major = hmsg->major_version;
			minor = hmsg->minor_version;
		}
		handle_error(&info, http_error_code, major, minor);
	}
	sock_destroy(&info, SD_BOTH);
	httpmsg_destroy(hmsg);
	free(request);

	UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
		"miniserver %d: COMPLETE\n", connfd);
}
/*!
 * \brief Sends the UNSUBCRIBE gena request and recieves the response from the
 * 	device and returns it as a parameter.
 *
 * \returns 0 if successful, otherwise returns the appropriate error code.
 */
static int gena_unsubscribe(
	/*! [in] Event URL of the service. */
	IN const UpnpString *url,
	/*! [in] The subcription ID. */
	IN const UpnpString *sid,
	/*! [out] The UNSUBCRIBE response from the device. */
	OUT http_parser_t *response )
{
	int return_code;
	uri_type dest_url;
	membuffer request;

	/* 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;
	return_code = http_MakeMessage(
		&request, 1, 1,
		"q" "ssc" "Uc",
		HTTPMETHOD_UNSUBSCRIBE, &dest_url,
		"SID: ", UpnpString_get_String(sid));

	/* Not able to make the message so destroy the existing buffer */
	if (return_code != 0) {
		membuffer_destroy(&request);

		return return_code;
	}

	/* send request and get reply */
	return_code = http_RequestAndResponse(
		&dest_url, request.buf, request.length,
		HTTPMETHOD_UNSUBSCRIBE, HTTP_DEFAULT_TIMEOUT, response);
	membuffer_destroy(&request);
	if (return_code != 0) {
		httpmsg_destroy(&response->msg);
	}

	if (return_code == 0 && response->msg.status_code != HTTP_OK) {
		return_code = UPNP_E_UNSUBSCRIBE_UNACCEPTED;
		httpmsg_destroy(&response->msg);
	}

	return return_code;
}
Example #4
0
/************************************************************************
* Function : gena_unsubscribe									
*																	
* Parameters:														
*	IN char *url: Event URL of the service
*	IN char *sid: The subcription ID.
*	OUT http_parser_t* response: The UNSUBCRIBE response from the device
*
* Description:														
*	This function sends the UNSUBCRIBE gena request and recieves the 
*	response from the device and returns it as a parameter
*
* Returns: int
*	return 0 if successful else returns appropriate error
***************************************************************************/
static int
gena_unsubscribe( IN char *url,
                  IN char *sid,
                  OUT http_parser_t * response )
{
    int return_code;
    uri_type dest_url;
    membuffer request;

    // 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;
    return_code = http_MakeMessage( &request, 1, 1,
                                    "q" "ssc" "U" "c",
                                    HTTPMETHOD_UNSUBSCRIBE, &dest_url,
                                    "SID: ", sid );

    //Not able to make the message so destroy the existing buffer
    if( return_code != 0 ) {
        membuffer_destroy( &request );
        return return_code;
    }
    // send request and get reply
    return_code = http_RequestAndResponse( &dest_url, request.buf,
                                           request.length,
                                           HTTPMETHOD_UNSUBSCRIBE,
                                           HTTP_DEFAULT_TIMEOUT,
                                           response );

    membuffer_destroy( &request );

    if( return_code != 0 )
        httpmsg_destroy( &response->msg );

    if( return_code == 0 && response->msg.status_code != HTTP_OK ) {
        return_code = UPNP_E_UNSUBSCRIBE_UNACCEPTED;
        httpmsg_destroy( &response->msg );
    }

    return return_code;
}
Example #5
0
/************************************************************************
* Function : process_reply											
*																	
* Parameters:														
*		IN char* request_buf: the response came from the device
*		IN int buf_len: The length of the response buffer
*	    IN struct sockaddr_in* dest_addr: The address of the device
*		IN void *cookie : cookie passed by the control point application
*							at the time of sending search message
*
* Description:														
*	This function processes reply recevied from a search
*
* Returns: void
*
***************************************************************************/
static XINLINE void
process_reply( IN char *request_buf,
               IN int buf_len,
               IN struct sockaddr_in *dest_addr,
               IN void *cookie )
{
    http_parser_t parser;

    parser_response_init( &parser, HTTPMETHOD_MSEARCH );

    // parse
    if( parser_append( &parser, request_buf, buf_len ) != PARSE_SUCCESS ) {
        httpmsg_destroy( &parser.msg );
        return;
    }
    // handle reply
    ssdp_handle_ctrlpt_msg( &parser.msg, dest_addr, FALSE, cookie );

    // done
    httpmsg_destroy( &parser.msg );
}
Example #6
0
/************************************************************************
* Function : genaUnSubscribe
*																	
* Parameters:														
*	IN UpnpClient_Handle client_handle: UPnP client handle
*	IN SID in_sid: The subscription ID
*
* Description:														
*	This function unsubscribes a SID. It first validates the SID and 
*	client_handle,copies the subscription, sends UNSUBSCRIBE http request 
*	to service processes request and finally removes the subscription
*
* Returns: int
*	return UPNP_E_SUCCESS if service response is OK else 
*	returns appropriate error
***************************************************************************/
int
genaUnSubscribe( IN UpnpClient_Handle client_handle,
                 IN const Upnp_SID in_sid )
{
    client_subscription *sub;
    int return_code = GENA_SUCCESS;
    struct Handle_Info *handle_info;
    client_subscription sub_copy;
    http_parser_t response;

    HandleLock(  );

    // validate handle and sid

    if( GetHandleInfo( client_handle, &handle_info ) != HND_CLIENT ) {
        HandleUnlock(  );
        return GENA_E_BAD_HANDLE;
    }

    if( ( sub =
          GetClientSubClientSID( handle_info->ClientSubList, in_sid ) )
        == NULL ) {
        HandleUnlock(  );
        return GENA_E_BAD_SID;
    }

    return_code = copy_client_subscription( sub, &sub_copy );

    HandleUnlock(  );

    return_code = gena_unsubscribe( sub_copy.EventURL, sub_copy.ActualSID,
                                    &response );

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

    free_client_subscription( &sub_copy );

    HandleLock(  );

    if( GetHandleInfo( client_handle, &handle_info ) != HND_CLIENT ) {
        HandleUnlock(  );
        return GENA_E_BAD_HANDLE;
    }

    RemoveClientSubClientSID( &handle_info->ClientSubList, in_sid );

    HandleUnlock(  );

    return return_code;
}
Example #7
0
/****************************************************************************
*	Function :	soap_request_and_response
*
*	Parameters :
*		IN membuffer* request :	request that will be sent to the device
*		IN uri_type* destination_url :	destination address string
*		OUT http_parser_t *response :	response from the device
*
*	Description :	This function sends the control point's request to the 
*		device and receives a response from it.
*
*	Return : int
*
*	Note :
****************************************************************************/
static int
soap_request_and_response( IN membuffer * request,
                           IN uri_type * destination_url,
                           OUT http_parser_t * response )
{
    int ret_code;

    ret_code = http_RequestAndResponse( destination_url, request->buf,
                                        request->length,
                                        SOAPMETHOD_POST,
                                        UPNP_TIMEOUT, response );
    if( ret_code != 0 ) {
        httpmsg_destroy( &response->msg );
        return ret_code;
    }
    /* method-not-allowed error */
    if( response->msg.status_code == HTTP_METHOD_NOT_ALLOWED ) {
        ret_code = add_man_header( request );   /* change to M-POST msg */
        if( ret_code != 0 ) {
            return ret_code;
        }

        httpmsg_destroy( &response->msg );  /* about to reuse response */

        /* try again */
        ret_code = http_RequestAndResponse( destination_url, request->buf,
                                            request->length,
                                            HTTPMETHOD_MPOST,
                                            UPNP_TIMEOUT,
                                            response );
        if( ret_code != 0 ) {
            httpmsg_destroy( &response->msg );
        }

    }

    return ret_code;
}
Example #8
0
/*!
 * \brief Frees the ssdp request.
 */
static void free_ssdp_event_handler_data(
	/*! [in] ssdp_thread_data structure. This structure contains SSDP
	 * request message. */
	void *the_data)
{
	ssdp_thread_data *data = (ssdp_thread_data *) the_data;

	if (data != NULL) {
		http_message_t *hmsg = &data->parser.msg;
		/* free data */
		httpmsg_destroy(hmsg);
		free(data);
	}
}
int genaUnSubscribe(
	UpnpClient_Handle client_handle,
	const UpnpString *in_sid)
{
	ClientSubscription *sub = NULL;
	int return_code = GENA_SUCCESS;
	struct Handle_Info *handle_info;
	ClientSubscription *sub_copy = UpnpClientSubscription_new();
	http_parser_t response;

	/* validate handle and sid */
	HandleLock();
	if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
		HandleUnlock();
		return_code = GENA_E_BAD_HANDLE;
		goto exit_function;
	}
	sub = GetClientSubClientSID(handle_info->ClientSubList, in_sid);
	if (sub == NULL) {
		HandleUnlock();
		return_code = GENA_E_BAD_SID;
		goto exit_function;
	}
	UpnpClientSubscription_assign(sub_copy, sub);
	HandleUnlock();

	return_code = gena_unsubscribe(
		UpnpClientSubscription_get_EventURL(sub_copy),
		UpnpClientSubscription_get_ActualSID(sub_copy),
		&response);
	if (return_code == 0) {
		httpmsg_destroy(&response.msg);
	}
	free_client_subscription(sub_copy);

	HandleLock();
	if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
		HandleUnlock();
		return_code = GENA_E_BAD_HANDLE;
		goto exit_function;
	}
	RemoveClientSubClientSID(&handle_info->ClientSubList, in_sid);
	HandleUnlock();

exit_function:
	UpnpClientSubscription_delete(sub_copy);
	return return_code;
}
Example #10
0
/*!
 * \brief Function to Notify a particular subscription of a particular event.
 *
 * In general the service should NOT be blocked around this call (this may
 * cause deadlock with a client).
 *
 * NOTIFY http request is sent and the reply is processed.
 *
 * \return GENA_SUCCESS if the event was delivered, otherwise returns the
 * 	appropriate error code.
 */
static int genaNotify(
	/*! [in] Null terminated, includes all headers (including \\r\\n) except SID and SEQ. */
	char *headers,
	/*! [in] The evented XML. */
	char *propertySet,
	/*! [in] subscription to be Notified, assumes this is valid for life of function. */
	subscription *sub)
{
	size_t i;
	membuffer mid_msg;
	uri_type *url;
	http_parser_t response;
	int return_code = -1;

	membuffer_init(&mid_msg);
	if (http_MakeMessage(&mid_msg, 1, 1,
			     "s" "ssc" "sdcc",
			     headers,
			     "SID: ", sub->sid,
			     "SEQ: ", sub->ToSendEventKey) != 0) {
		membuffer_destroy(&mid_msg);
		return UPNP_E_OUTOF_MEMORY;
	}
	/* send a notify to each url until one goes thru */
	for (i = 0; i < sub->DeliveryURLs.size; i++) {
		url = &sub->DeliveryURLs.parsedURLs[i];
		return_code = notify_send_and_recv(
			url, &mid_msg, propertySet, &response);
		if (return_code == UPNP_E_SUCCESS)
			break;
	}
	membuffer_destroy(&mid_msg);
	if (return_code == UPNP_E_SUCCESS) {
		if (response.msg.status_code == HTTP_OK)
			return_code = GENA_SUCCESS;
		else {
			if (response.msg.status_code == HTTP_PRECONDITION_FAILED)
				/*Invalid SID gets removed */
				return_code = GENA_E_NOTIFY_UNACCEPTED_REMOVE_SUB;
			else
				return_code = GENA_E_NOTIFY_UNACCEPTED;
		}
		httpmsg_destroy(&response.msg);
	}

	return return_code;
}
Example #11
0
/************************************************************************
* Function : genaUnregisterClient									
*																	
* Parameters:														
*	IN UpnpClient_Handle client_handle: Handle containing all the control
*			point related information
*
* Description:														
*	This function unsubcribes all the outstanding subscriptions and cleans
*	the subscription list. This function is called when control point 
*	unregisters.
*
* Returns: int
*	return UPNP_E_SUCCESS if successful else returns appropriate error
***************************************************************************/
int
genaUnregisterClient( IN UpnpClient_Handle client_handle )
{
    client_subscription sub_copy;
    int return_code = UPNP_E_SUCCESS;
    struct Handle_Info *handle_info = NULL;
    http_parser_t response;

    while( TRUE ) {
        HandleLock(  );
        if( GetHandleInfo( client_handle, &handle_info ) != HND_CLIENT ) {
            HandleUnlock(  );
            return GENA_E_BAD_HANDLE;
        }

        if( handle_info->ClientSubList == NULL ) {
            return_code = UPNP_E_SUCCESS;
            break;
        }

        return_code = copy_client_subscription( handle_info->ClientSubList,
                                                &sub_copy );
        if( return_code != HTTP_SUCCESS ) {
            break;
        }

        RemoveClientSubClientSID( &handle_info->ClientSubList,
                                  sub_copy.sid );

        HandleUnlock(  );

		return_code = gena_unsubscribe( sub_copy.EventURL,
										sub_copy.ActualSID, &response );
		if( return_code == 0 ) {
			httpmsg_destroy( &response.msg );
		}

        free_client_subscription( &sub_copy );
    }

    freeClientSubList( handle_info->ClientSubList );
    HandleUnlock(  );
    return return_code;
}
int genaUnregisterClient(UpnpClient_Handle client_handle)
{
	ClientSubscription *sub_copy = UpnpClientSubscription_new();
	int return_code = UPNP_E_SUCCESS;
	struct Handle_Info *handle_info = NULL;
	http_parser_t response;

	while (TRUE) {
		HandleLock();

		if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
			HandleUnlock();
			return_code = GENA_E_BAD_HANDLE;
			goto exit_function;
		}
		if (handle_info->ClientSubList == NULL) {
			return_code = UPNP_E_SUCCESS;
			break;
		}
		UpnpClientSubscription_assign(sub_copy, handle_info->ClientSubList);
		RemoveClientSubClientSID(
			&handle_info->ClientSubList,
			UpnpClientSubscription_get_SID(sub_copy));

		HandleUnlock();

		return_code = gena_unsubscribe(
			UpnpClientSubscription_get_EventURL(sub_copy),
			UpnpClientSubscription_get_ActualSID(sub_copy),
			&response);
		if (return_code == 0) {
			httpmsg_destroy(&response.msg);
		}
		free_client_subscription(sub_copy);
	}

	freeClientSubList(handle_info->ClientSubList);
	HandleUnlock();

exit_function:
	UpnpClientSubscription_delete(sub_copy);
	return return_code;
}
Example #13
0
/*!
 * \brief Sends the notify message and returns a reply.
 *
 * \return on success returns UPNP_E_SUCCESS, otherwise returns a UPNP error.
 *
 * \note called by genaNotify
 */
static UPNP_INLINE int notify_send_and_recv(
	/*! [in] subscription callback URL (URL of the control point). */
	uri_type *destination_url,
	/*! [in] Common HTTP headers. */
	membuffer *mid_msg,
	/*! [in] The evented XML. */
	char *propertySet,
	/*! [out] The response from the control point. */
	http_parser_t *response)
{
	uri_type url;
	SOCKET conn_fd;
	membuffer start_msg;
	int ret_code;
	int err_code;
	int timeout;
	SOCKINFO info;
	const char *CRLF = "\r\n";

	/* connect */
	UpnpPrintf(UPNP_ALL, GENA, __FILE__, __LINE__,
		"gena notify to: %.*s\n",
		(int)destination_url->hostport.text.size,
		destination_url->hostport.text.buff);

	conn_fd = http_Connect(destination_url, &url);
	if (conn_fd < 0)
		/* return UPNP error */
		return UPNP_E_SOCKET_CONNECT;
	ret_code = sock_init(&info, conn_fd);
	if (ret_code) {
		sock_destroy(&info, SD_BOTH);
		return ret_code;
	}
	/* make start line and HOST header */
	membuffer_init(&start_msg);
	if (http_MakeMessage(
			&start_msg, 1, 1,
			"q" "s",
			HTTPMETHOD_NOTIFY, &url,
			mid_msg->buf) != 0) {
		membuffer_destroy(&start_msg);
		sock_destroy(&info, SD_BOTH);
		return UPNP_E_OUTOF_MEMORY;
	}
	timeout = GENA_NOTIFICATION_SENDING_TIMEOUT;
	/* send msg (note: end of notification will contain "\r\n" twice) */
	ret_code = http_SendMessage(&info, &timeout,
		"bbb",
		start_msg.buf, start_msg.length,
		propertySet, strlen(propertySet),
		CRLF, strlen(CRLF));
	if (ret_code) {
		membuffer_destroy(&start_msg);
		sock_destroy(&info, SD_BOTH);
		return ret_code;
	}
	timeout = GENA_NOTIFICATION_ANSWERING_TIMEOUT;
	ret_code = http_RecvMessage(&info, response,
		HTTPMETHOD_NOTIFY, &timeout, &err_code);
	if (ret_code) {
		membuffer_destroy(&start_msg);
		sock_destroy(&info, SD_BOTH);
		httpmsg_destroy(&response->msg);
		return ret_code;
	}
	/* should shutdown completely when closing socket */
	sock_destroy(&info, SD_BOTH);
	membuffer_destroy(&start_msg);

	return UPNP_E_SUCCESS;
}
Example #14
0
/****************************************************************************
*	Function :	SoapGetServiceVarStatus
*
*	Parameters :
*			IN  char * action_url :	Address to send this variable 
*									query message.
*			IN  char *var_name : Name of the variable.
*			OUT char **var_value :	Output value.
*
*	Description :	This function creates a status variable query message 
*		send it to the specified URL. It also collect the response.
*
*	Return :	int
*
*	Note :
****************************************************************************/
int
SoapGetServiceVarStatus( IN char *action_url,
                         IN char *var_name,
                         OUT char **var_value )
{
    const memptr host;                /* value for HOST header */
    const memptr path;                /* ctrl path in first line in msg */
    uri_type url;
    membuffer request;
    int ret_code;
    http_parser_t response;
    int upnp_error_code;
    off_t content_length;
    const char *xml_start =
        "<s:Envelope "
        "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
        "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n"
        "<s:Body>\r\n"
        "<u:QueryStateVariable xmlns:u=\"urn:schemas-upnp-org:control-1-0\">\r\n"
        "<u:varName>";
    const char *xml_end =
        "</u:varName>\r\n"
        "</u:QueryStateVariable>\r\n"
        "</s:Body>\r\n"
        "</s:Envelope>\r\n";

    *var_value = NULL;          /* return NULL in case of an error */
    membuffer_init( &request );
    /* get host hdr and url path */
    if( get_host_and_path( action_url, &host, &path, &url ) == -1 ) {
        return UPNP_E_INVALID_URL;
    }
    /* make headers */
    request.size_inc = 50;
    content_length = (off_t)(strlen(xml_start) + strlen(var_name) +
	strlen(xml_end));
    if (http_MakeMessage(
	&request, 1, 1,
	"Q" "sbc" "N" "s" "sc" "Ucc" "sss",
	SOAPMETHOD_POST, path.buf, path.length,
	"HOST: ", host.buf, host.length,
	content_length,
	ContentTypeHeader,
	"SOAPACTION: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"",
	xml_start, var_name, xml_end ) != 0 ) {
        return UPNP_E_OUTOF_MEMORY;
    }
    /* send msg and get reply */
    ret_code = soap_request_and_response( &request, &url, &response );
    membuffer_destroy( &request );
    if( ret_code != UPNP_E_SUCCESS ) {
        return ret_code;
    }
    /* get variable value from the response */
    ret_code = get_response_value( &response.msg, SOAP_VAR_RESP, NULL,
                                   &upnp_error_code, NULL, var_value );
    httpmsg_destroy( &response.msg );
    if( ret_code == SOAP_VAR_RESP ) {
        return UPNP_E_SUCCESS;
    } else if( ret_code == SOAP_VAR_RESP_ERROR ) {
        return upnp_error_code;
    } else {
        return ret_code;
    }
}
Example #15
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;
}
/*!
 * \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;
}
Example #17
0
/****************************************************************************
*	Function :	SoapSendActionEx
*
*	Parameters :
*		IN char* action_url :	device contrl URL 
*		IN char *service_type :	device service type
		IN IXML_Document *Header: Soap header
*		IN IXML_Document *action_node : SOAP action node ( SOAP body)	
*		OUT IXML_Document **response_node :	SOAP response node
*
*	Description :	This function is called by UPnP API to send the SOAP 
*		action request and waits till it gets the response from the device
*		pass the response to the API layer. This action is similar to the 
*		the SoapSendAction with only difference that it allows users to 
*		pass the SOAP header along the SOAP body ( soap action request)
*
*	Return :	int
*		returns UPNP_E_SUCCESS if successful else returns appropriate error
*	Note :
****************************************************************************/
int SoapSendActionEx(
	IN char *action_url,
	IN char *service_type,
	IN IXML_Document * header,
	IN IXML_Document * action_node,
	OUT IXML_Document ** response_node )
{
    char *xml_header_str = NULL;
    char *action_str = NULL;
    memptr name;
    membuffer request;
    membuffer responsename;
    int err_code;
    int ret_code;
    http_parser_t response;
    uri_type url;
    int upnp_error_code;
    char *upnp_error_str;
    int got_response = FALSE;
    const char *xml_start =
        "<s:Envelope "
        "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
        "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n";
    const char *xml_header_start =
        "<s:Header>\r\n";
    const char *xml_header_end =
        "</s:Header>\r\n";
    const char *xml_body_start =
        "<s:Body>";
    const char *xml_end =
        "</s:Body>\r\n"
        "</s:Envelope>\r\n";
    size_t xml_start_len;
    size_t xml_header_start_len;
    size_t xml_header_str_len;
    size_t xml_header_end_len;
    size_t xml_body_start_len;
    size_t action_str_len;
    size_t xml_end_len;
    off_t content_length;

    *response_node = NULL;      /* init */

    err_code = UPNP_E_OUTOF_MEMORY; /* default error */

    UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
        "Inside SoapSendActionEx():" );
    /* init */
    membuffer_init( &request );
    membuffer_init( &responsename );

    /* header string */
    xml_header_str = ixmlPrintNode( ( IXML_Node * ) header );
    if( xml_header_str == NULL ) {
        goto error_handler;
    }
    /* print action */
    action_str = ixmlPrintNode( ( IXML_Node * ) action_node );
    if( action_str == NULL ) {
        goto error_handler;
    }
    /* get action name */
    if( get_action_name( action_str, &name ) != 0 ) {
        err_code = UPNP_E_INVALID_ACTION;
        goto error_handler;
    }
    /* parse url */
    if( http_FixStrUrl( action_url, strlen( action_url ), &url ) != 0 ) {
        err_code = UPNP_E_INVALID_URL;
        goto error_handler;
    }

    UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
        "path=%.*s, hostport=%.*s\n",
        (int)url.pathquery.size,
        url.pathquery.buff,
        (int)url.hostport.text.size,
        url.hostport.text.buff );

    xml_start_len = strlen( xml_start );
    xml_body_start_len = strlen( xml_body_start );
    xml_end_len = strlen( xml_end );
    action_str_len = strlen( action_str );

    xml_header_start_len = strlen( xml_header_start );
    xml_header_end_len = strlen( xml_header_end );
    xml_header_str_len = strlen( xml_header_str );

    /* make request msg */
    request.size_inc = 50;
    content_length = (off_t)(xml_start_len + xml_header_start_len +
	xml_header_str_len + xml_header_end_len +
        xml_body_start_len + action_str_len + xml_end_len);
    if (http_MakeMessage(
        &request, 1, 1,
        "q" "N" "s" "sssbsc" "Uc" "b" "b" "b" "b" "b" "b" "b",
        SOAPMETHOD_POST, &url,
        content_length,
        ContentTypeHeader,
        "SOAPACTION: \"", service_type, "#", name.buf, name.length, "\"",
        xml_start, xml_start_len,
        xml_header_start, xml_header_start_len,
        xml_header_str, xml_header_str_len,
        xml_header_end, xml_header_end_len,
        xml_body_start, xml_body_start_len,
        action_str, action_str_len,
        xml_end, xml_end_len ) != 0 ) {
        goto error_handler;
    }

    ret_code = soap_request_and_response( &request, &url, &response );
    got_response = TRUE;
    if( ret_code != UPNP_E_SUCCESS ) {
        err_code = ret_code;
        goto error_handler;
    }

    if( membuffer_append( &responsename, name.buf, name.length ) != 0 ||
        membuffer_append_str( &responsename, "Response" ) != 0 ) {
        goto error_handler;
    }
    /* get action node from the response */
    ret_code = get_response_value( &response.msg, SOAP_ACTION_RESP,
                                   responsename.buf, &upnp_error_code,
                                   ( IXML_Node ** ) response_node,
                                   &upnp_error_str );

    if( ret_code == SOAP_ACTION_RESP ) {
        err_code = UPNP_E_SUCCESS;
    } else if( ret_code == SOAP_ACTION_RESP_ERROR ) {
        err_code = upnp_error_code;
    } else {
        err_code = ret_code;
    }

  error_handler:

    ixmlFreeDOMString( action_str );
    ixmlFreeDOMString( xml_header_str );
    membuffer_destroy( &request );
    membuffer_destroy( &responsename );
    if( got_response ) {
        httpmsg_destroy( &response.msg );
    }

    return err_code;
}