void gena_process_unsubscribe_request( SOCKINFO *info, http_message_t *request) { Upnp_SID sid; service_info *service; struct Handle_Info *handle_info; UpnpDevice_Handle device_handle; memptr temp_hdr; membuffer event_url_path; /* if a CALLBACK or NT header is present, then it is an error */ if( httpmsg_find_hdr( request, HDR_CALLBACK, NULL ) != NULL || httpmsg_find_hdr( request, HDR_NT, NULL ) != NULL ) { error_respond( info, HTTP_BAD_REQUEST, request ); return; } /* get SID */ if( httpmsg_find_hdr( request, HDR_SID, &temp_hdr ) == NULL || temp_hdr.length > SID_SIZE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); return; } memcpy( sid, temp_hdr.buf, temp_hdr.length ); sid[temp_hdr.length] = '\0'; /* lookup service by eventURL */ membuffer_init( &event_url_path ); if( membuffer_append( &event_url_path, request->uri.pathquery.buff, request->uri.pathquery.size ) != 0 ) { error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request ); return; } HandleLock(); if( GetDeviceHandleInfoForPath(event_url_path.buf, info->foreign_sockaddr.ss_family, &device_handle, &handle_info, &service) != HND_DEVICE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); membuffer_destroy( &event_url_path ); HandleUnlock(); return; } membuffer_destroy( &event_url_path ); /* validate service */ if( service == NULL || !service->active || GetSubscriptionSID( sid, service ) == NULL ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); HandleUnlock(); return; } RemoveSubscriptionSID(sid, service); error_respond(info, HTTP_OK, request); /* success */ HandleUnlock(); }
/* Takes data streamed from libcurl and writes it to a Ruby string buffer. */ static size_t session_write_handler(char* stream, size_t size, size_t nmemb, membuffer* buf) { int rc = membuffer_append(buf, stream, size * nmemb); /* return 0 to signal that we could not append data to our buffer */ if (MB_OK != rc) { return 0; } /* otherwise, return the number of bytes appended */ return size * nmemb; }
void gena_process_subscription_renewal_request( SOCKINFO *info, http_message_t *request) { Upnp_SID sid; subscription *sub; int time_out = 1801; service_info *service; struct Handle_Info *handle_info; UpnpDevice_Handle device_handle; memptr temp_hdr; membuffer event_url_path; memptr timeout_hdr; /* if a CALLBACK or NT header is present, then it is an error */ if( httpmsg_find_hdr( request, HDR_CALLBACK, NULL ) != NULL || httpmsg_find_hdr( request, HDR_NT, NULL ) != NULL ) { error_respond( info, HTTP_BAD_REQUEST, request ); return; } /* get SID */ if( httpmsg_find_hdr( request, HDR_SID, &temp_hdr ) == NULL || temp_hdr.length > SID_SIZE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); return; } memcpy( sid, temp_hdr.buf, temp_hdr.length ); sid[temp_hdr.length] = '\0'; /* lookup service by eventURL */ membuffer_init( &event_url_path ); if( membuffer_append( &event_url_path, request->uri.pathquery.buff, request->uri.pathquery.size ) != 0 ) { error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request ); return; } HandleLock(); if (GetDeviceHandleInfoForPath(event_url_path.buf, info->foreign_sockaddr.ss_family, &device_handle, &handle_info, &service) != HND_DEVICE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); membuffer_destroy( &event_url_path ); HandleUnlock(); return; } membuffer_destroy( &event_url_path ); /* get subscription */ if( service == NULL || !service->active || ( ( sub = GetSubscriptionSID( sid, service ) ) == NULL ) ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); HandleUnlock(); return; } UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "Renew request: Number of subscriptions already: %d\n " "Max Subscriptions allowed:%d\n", service->TotalSubscriptions, handle_info->MaxSubscriptions ); /* too many subscriptions */ if( handle_info->MaxSubscriptions != -1 && service->TotalSubscriptions > handle_info->MaxSubscriptions ) { error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request ); RemoveSubscriptionSID( sub->sid, service ); HandleUnlock(); return; } /* set the timeout */ if( httpmsg_find_hdr( request, HDR_TIMEOUT, &timeout_hdr ) != NULL ) { if( matchstr( timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0", &time_out ) == PARSE_OK ) { /*nothing */ } else if( memptr_cmp_nocase( &timeout_hdr, "Second-infinite" ) == 0 ) { time_out = -1; /* inifinite timeout */ } else { time_out = DEFAULT_TIMEOUT; /* default is > 1800 seconds */ } } /* replace infinite timeout with max timeout, if possible */ if( handle_info->MaxSubscriptionTimeOut != -1 ) { if( time_out == -1 || time_out > handle_info->MaxSubscriptionTimeOut ) { time_out = handle_info->MaxSubscriptionTimeOut; } } if( time_out == -1 ) { sub->expireTime = 0; } else { sub->expireTime = time( NULL ) + time_out; } if( respond_ok( info, time_out, sub, request ) != UPNP_E_SUCCESS ) { RemoveSubscriptionSID( sub->sid, service ); } HandleUnlock(); }
/*! * \brief Receives the HTTP post message. * * \return * \li \c HTTP_INTERNAL_SERVER_ERROR * \li \c HTTP_UNAUTHORIZED * \li \c HTTP_BAD_REQUEST * \li \c HTTP_SERVICE_UNAVAILABLE * \li \c HTTP_OK */ static int http_RecvPostMessage( /*! HTTP Parser object. */ http_parser_t *parser, /*! [in] Socket Information object. */ SOCKINFO *info, /*! File where received data is copied to. */ char *filename, /*! Send Instruction object which gives information whether the file * is a virtual file or not. */ struct SendInstruction *Instr) { size_t Data_Buf_Size = 1024; char Buf[1024]; int Timeout = 0; FILE *Fp; parse_status_t status = PARSE_OK; int ok_on_close = FALSE; size_t entity_offset = 0; int num_read = 0; int ret_code = HTTP_OK; if (Instr && Instr->IsVirtualFile) { Fp = (virtualDirCallback.open) (filename, UPNP_WRITE); if (Fp == NULL) return HTTP_INTERNAL_SERVER_ERROR; } else { Fp = fopen(filename, "wb"); if (Fp == NULL) return HTTP_UNAUTHORIZED; } parser->position = POS_ENTITY; do { /* first parse what has already been gotten */ if (parser->position != POS_COMPLETE) status = parser_parse_entity(parser); if (status == PARSE_INCOMPLETE_ENTITY) { /* read until close */ ok_on_close = TRUE; } else if ((status != PARSE_SUCCESS) && (status != PARSE_CONTINUE_1) && (status != PARSE_INCOMPLETE)) { /* error */ ret_code = HTTP_BAD_REQUEST; goto ExitFunction; } /* read more if necessary entity */ while (entity_offset + Data_Buf_Size > parser->msg.entity.length && parser->position != POS_COMPLETE) { num_read = sock_read(info, Buf, sizeof(Buf), &Timeout); if (num_read > 0) { /* append data to buffer */ if (membuffer_append(&parser->msg.msg, Buf, (size_t)num_read) != 0) { /* set failure status */ parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR; ret_code = HTTP_INTERNAL_SERVER_ERROR; goto ExitFunction; } status = parser_parse_entity(parser); if (status == PARSE_INCOMPLETE_ENTITY) { /* read until close */ ok_on_close = TRUE; } else if ((status != PARSE_SUCCESS) && (status != PARSE_CONTINUE_1) && (status != PARSE_INCOMPLETE)) { ret_code = HTTP_BAD_REQUEST; goto ExitFunction; } } else if (num_read == 0) { if (ok_on_close) { UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, "<<< (RECVD) <<<\n%s\n-----------------\n", parser->msg.msg.buf); print_http_headers(&parser->msg); parser->position = POS_COMPLETE; } else { /* partial msg or response */ parser->http_error_code = HTTP_BAD_REQUEST; ret_code = HTTP_BAD_REQUEST; goto ExitFunction; } } else { ret_code = HTTP_SERVICE_UNAVAILABLE; goto ExitFunction; } } if ((entity_offset + Data_Buf_Size) > parser->msg.entity.length) { Data_Buf_Size = parser->msg.entity.length - entity_offset; } memcpy(Buf, &parser->msg.msg.buf[parser->entity_start_position + entity_offset], Data_Buf_Size); entity_offset += Data_Buf_Size; if (Instr && Instr->IsVirtualFile) { int n = virtualDirCallback.write(Fp, Buf, Data_Buf_Size); if (n < 0) { ret_code = HTTP_INTERNAL_SERVER_ERROR; goto ExitFunction; } } else { size_t n = fwrite(Buf, 1, Data_Buf_Size, Fp); if (n != Data_Buf_Size) { ret_code = HTTP_INTERNAL_SERVER_ERROR; goto ExitFunction; } } } while (parser->position != POS_COMPLETE || entity_offset != parser->msg.entity.length); ExitFunction: if (Instr && Instr->IsVirtualFile) { virtualDirCallback.close(Fp); } else { fclose(Fp); } return ret_code; }
/************************************************************************ * Function : config_description_doc * * Parameters : * INOUT IXML_Document *doc ;IMXL description document to be * configured * IN const char* ip_str ; string containing the IP port number * OUT char** root_path_str ; buffer to hold the root path * of the configured description document * INOUT IXML_Document *doc : Description document * IN const char* ip_str : ipaddress string * OUT char** root_path_str : root path string * * Description : Configure the description document. Add the standard * format and then add information from the root device and any * child nodes. * * Return : int ; * UPNP_E_SUCCESS - On Success * UPNP_E_OUTOF_MEMORY - Default Error * UPNP_E_INVALID_DESC - Invalid child node * UPNP_E_INVALID_URL - Invalid node information * * Note : ************************************************************************/ static int config_description_doc( INOUT IXML_Document * doc, IN const char *ip_str, OUT char **root_path_str ) { xboolean addNew = FALSE; IXML_NodeList *baseList; IXML_Element *element = NULL; IXML_Element *newElement = NULL; IXML_Node *textNode = NULL; IXML_Node *rootNode = NULL; IXML_Node *urlbase_node = NULL; char *urlBaseStr = "URLBase"; const DOMString domStr = NULL; uri_type uri; int err_code; int len; membuffer url_str; membuffer root_path; membuffer_init( &url_str ); membuffer_init( &root_path ); err_code = UPNP_E_OUTOF_MEMORY; // default error baseList = ixmlDocument_getElementsByTagName( doc, urlBaseStr ); if( baseList == NULL ) { // urlbase not found -- create new one addNew = TRUE; element = ixmlDocument_createElement( doc, urlBaseStr ); if( element == NULL ) { goto error_handler; } if( membuffer_append_str( &url_str, "http://" ) != 0 || membuffer_append_str( &url_str, ip_str ) != 0 || membuffer_append_str( &url_str, "/" ) != 0 || membuffer_append_str( &root_path, "/" ) != 0 ) { goto error_handler; } rootNode = ixmlNode_getFirstChild( ( IXML_Node * ) doc ); if( rootNode == NULL ) { err_code = UPNP_E_INVALID_DESC; goto error_handler; } err_code = ixmlNode_appendChild( rootNode, ( IXML_Node * ) element ); if( err_code != IXML_SUCCESS ) { goto error_handler; } textNode = ixmlDocument_createTextNode( doc, ( char * )url_str.buf ); if( textNode == NULL ) { goto error_handler; } err_code = ixmlNode_appendChild( ( IXML_Node * ) element, textNode ); if( err_code != IXML_SUCCESS ) { goto error_handler; } } else { // urlbase found urlbase_node = ixmlNodeList_item( baseList, 0 ); assert( urlbase_node != NULL ); textNode = ixmlNode_getFirstChild( urlbase_node ); if( textNode == NULL ) { err_code = UPNP_E_INVALID_DESC; goto error_handler; } domStr = ixmlNode_getNodeValue( textNode ); if( domStr == NULL ) { err_code = UPNP_E_INVALID_URL; goto error_handler; } len = parse_uri( domStr, strlen( domStr ), &uri ); if( len < 0 || uri.type != ABSOLUTE ) { err_code = UPNP_E_INVALID_URL; goto error_handler; } if( membuffer_assign( &url_str, uri.scheme.buff, uri.scheme.size ) != 0 || membuffer_append_str( &url_str, "://" ) != 0 || membuffer_append_str( &url_str, ip_str ) != 0 ) { goto error_handler; } // add leading '/' if missing from relative path if( ( uri.pathquery.size > 0 && uri.pathquery.buff[0] != '/' ) || ( uri.pathquery.size == 0 ) ) { if( membuffer_append_str( &url_str, "/" ) != 0 || membuffer_append_str( &root_path, "/" ) != 0 ) { goto error_handler; } } if( membuffer_append( &url_str, uri.pathquery.buff, uri.pathquery.size ) != 0 || membuffer_append( &root_path, uri.pathquery.buff, uri.pathquery.size ) != 0 ) { goto error_handler; } // add trailing '/' if missing if( url_str.buf[url_str.length - 1] != '/' ) { if( membuffer_append( &url_str, "/", 1 ) != 0 ) { goto error_handler; } } err_code = ixmlNode_setNodeValue( textNode, url_str.buf ); if( err_code != IXML_SUCCESS ) { goto error_handler; } } *root_path_str = membuffer_detach( &root_path ); // return path err_code = UPNP_E_SUCCESS; error_handler: if( err_code != UPNP_E_SUCCESS ) { ixmlElement_free( newElement ); } ixmlNodeList_free( baseList ); membuffer_destroy( &root_path ); membuffer_destroy( &url_str ); return err_code; }
/*! * \brief Receives the HTTP post message. * * \return * \li \c HTTP_INTERNAL_SERVER_ERROR * \li \c HTTP_UNAUTHORIZED * \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE * \li \c HTTP_OK */ static int http_RecvPostMessage( /*! HTTP Parser object. */ http_parser_t *parser, /*! [in] Socket Information object. */ SOCKINFO *info, /*! File where received data is copied to. */ char *filename, /*! Send Instruction object which gives information whether the file * is a virtual file or not. */ struct SendInstruction *Instr) { char *Buf = NULL; // char Buf[1024]; int Timeout = 0; OSAL_FILE *Fp; //parse_status_t status = PARSE_OK; int ok_on_close = FALSE; int num_read = 0; int ret_code = HTTP_OK; long wrcb; if (Instr && Instr->IsVirtualFile) { struct File_Info finfo; /* * give parser into extra_head of get_info to parsing continually */ if (parser->scanner.msg->length - parser->scanner.cursor < 512) { // the buffer run out, and all of header may not receive yet. // try to read again. char *buffer; buffer = (char*)osal_malloc(2048); if (!buffer) {printc(BG_RED("%s %d:ERROR\n"), __func__, __LINE__);return 0;} num_read = sock_read(info, buffer, 2048, &Timeout); if (num_read > 0) { membuffer_append(&parser->msg.msg, buffer, (size_t)num_read); } osal_free(buffer); } virtualDirCallback.get_info(filename, &parser->msg, (char**)parser, &finfo, NULL); // to tell our HTTP Request Message Fp = (virtualDirCallback.open) (filename, UPNP_WRITE); if (Fp == NULL) return HTTP_INTERNAL_SERVER_ERROR; } else { Fp = osal_fopen(filename, "wb"); if (Fp == NULL) return HTTP_UNAUTHORIZED; parser->position = POS_ENTITY; } wrcb = 0; /* read more if necessary entity */ if (Instr && Instr->IsVirtualFile) { // get current total written size wrcb = virtualDirCallback.write(Fp, NULL, 0); // the wrcb is total size of data that had been written after the file opend // Instr->RecvWriteSize is Content-Length if (wrcb == Instr->RecvWriteSize) { // got all of data ret_code = HTTP_OK; parser->position = POS_COMPLETE; } } Buf = osal_malloc(1024); while (wrcb < Instr->RecvWriteSize) { num_read = sock_read(info, Buf, 1024, &Timeout); if (num_read > 0) { if (Instr && Instr->IsVirtualFile) { // wrcb = virtualDirCallback.write(Fp, Buf, num_read); if (wrcb < 0) { ret_code = HTTP_INTERNAL_SERVER_ERROR; goto ExitFunction; } // the wrcb is total size of data that had been written after the file opend // Instr->RecvWriteSize is Content-Length if (wrcb == Instr->RecvWriteSize) { // got all of data ret_code = HTTP_OK; parser->position = POS_COMPLETE; } } else { size_t n = osal_fwrite(Buf, 1, num_read, Fp); if (n != num_read) { ret_code = HTTP_INTERNAL_SERVER_ERROR; goto ExitFunction; } } } else if (num_read == 0) { if (ok_on_close) { UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, "<<< (RECVD) <<<\n%s\n-----------------\n", parser->msg.msg.buf); print_http_headers(&parser->msg); parser->position = POS_COMPLETE; } else { /* partial msg or response */ parser->http_error_code = HTTP_BAD_REQUEST; ret_code = HTTP_BAD_REQUEST; goto ExitFunction; } } else { //ret_code = num_read; printc("TIME OUT total read %d\n", wrcb); ret_code = HTTP_PARTIAL_CONTENT; goto ExitFunction; } } ExitFunction: if (Instr && Instr->IsVirtualFile) { virtualDirCallback.close(Fp); } else { osal_fclose(Fp); } if (Buf) osal_free(Buf); return ret_code; }
/**************************************************************************** * 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; }