/*! * \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; }
/************************************************************************ * 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; }
/************************************************************************ * 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; }
/**************************************************************************** * 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; }