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