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