/*! * \brief Creates a HTTP request packet. Depending on the input parameter, * it either creates a service advertisement request or service shutdown * request etc. */ static void CreateServicePacket( /*! [in] type of the message (Search Reply, Advertisement * or Shutdown). */ int msg_type, /*! [in] ssdp type. */ const char *nt, /*! [in] unique service name ( go in the HTTP Header). */ char *usn, /*! [in] Location URL. */ char *location, /*! [in] Service duration in sec. */ int duration, /*! [out] Output buffer filled with HTTP statement. */ char **packet, /*! [in] Address family of the HTTP request. */ int AddressFamily, /*! [in] PowerState as defined by UPnP Low Power. */ int PowerState, /*! [in] SleepPeriod as defined by UPnP Low Power. */ int SleepPeriod, /*! [in] RegistrationState as defined by UPnP Low Power. */ int RegistrationState) { int ret_code; const char *nts; membuffer buf; /* Notf == 0 means service shutdown, * Notf == 1 means service advertisement, * Notf == 2 means reply */ membuffer_init(&buf); buf.size_inc = (size_t)30; *packet = NULL; if (msg_type == MSGTYPE_REPLY) { if (PowerState > 0) { #ifdef UPNP_HAVE_OPTSSDP ret_code = http_MakeMessage(&buf, 1, 1, "R" "sdc" "D" "sc" "ssc" "ssc" "ssc" "S" "Xc" "ssc" "ssc" "sdc" "sdc" "sdcc", HTTP_OK, "CACHE-CONTROL: max-age=", duration, "EXT:", "LOCATION: ", location, "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01", "01-NLS: ", gUpnpSdkNLSuuid, X_USER_AGENT, "ST: ", nt, "USN: ", usn, "Powerstate: ", PowerState, "SleepPeriod: ", SleepPeriod, "RegistrationState: ", RegistrationState); #else ret_code = http_MakeMessage(&buf, 1, 1, "R" "sdc" "D" "sc" "ssc" "S" "ssc" "ssc" "sdc" "sdc" "sdcc", HTTP_OK, "CACHE-CONTROL: max-age=", duration, "EXT:", "LOCATION: ", location, "ST: ", nt, "USN: ", usn, "Powerstate: ", PowerState, "SleepPeriod: ", SleepPeriod, "RegistrationState: ", RegistrationState); #endif /* UPNP_HAVE_OPTSSDP */ } else { #ifdef UPNP_HAVE_OPTSSDP ret_code = http_MakeMessage(&buf, 1, 1, "R" "sdc" "D" "sc" "ssc" "ssc" "ssc" "S" "Xc" "ssc" "sscc", HTTP_OK, "CACHE-CONTROL: max-age=", duration, "EXT:", "LOCATION: ", location, "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01", "01-NLS: ", gUpnpSdkNLSuuid, X_USER_AGENT, "ST: ", nt, "USN: ", usn); #else ret_code = http_MakeMessage(&buf, 1, 1, "R" "sdc" "D" "sc" "ssc" "S" "ssc" "sscc", HTTP_OK, "CACHE-CONTROL: max-age=", duration, "EXT:", "LOCATION: ", location, "ST: ", nt, "USN: ", usn); #endif /* UPNP_HAVE_OPTSSDP */ } if (ret_code != 0) { return; } } else if (msg_type == MSGTYPE_ADVERTISEMENT || msg_type == MSGTYPE_SHUTDOWN) { const char *host = NULL; if (msg_type == MSGTYPE_ADVERTISEMENT) nts = "ssdp:alive"; else /* shutdown */ nts = "ssdp:byebye"; /* NOTE: The CACHE-CONTROL and LOCATION headers are not present in * a shutdown msg, but are present here for MS WinMe interop. */ switch (AddressFamily) { case AF_INET: host = SSDP_IP; break; default: if (isUrlV6UlaGua(location)) host = "[" SSDP_IPV6_SITELOCAL "]"; else host = "[" SSDP_IPV6_LINKLOCAL "]"; } if (PowerState > 0) { #ifdef UPNP_HAVE_OPTSSDP ret_code = http_MakeMessage(&buf, 1, 1, "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "ssc" "ssc" "S" "Xc" "ssc" "sdc" "sdc" "sdcc", HTTPMETHOD_NOTIFY, "*", (size_t) 1, "HOST: ", host, ":", SSDP_PORT, "CACHE-CONTROL: max-age=", duration, "LOCATION: ", location, "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01", "01-NLS: ", gUpnpSdkNLSuuid, "NT: ", nt, "NTS: ", nts, X_USER_AGENT, "USN: ", usn, "Powerstate: ", PowerState, "SleepPeriod: ", SleepPeriod, "RegistrationState: ", RegistrationState); #else ret_code = http_MakeMessage(&buf, 1, 1, "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "S" "ssc" "sdc" "sdc" "sdcc", HTTPMETHOD_NOTIFY, "*", (size_t) 1, "HOST: ", host, ":", SSDP_PORT, "CACHE-CONTROL: max-age=", duration, "LOCATION: ", location, "NT: ", nt, "NTS: ", nts, "USN: ", usn, "Powerstate: ", PowerState, "SleepPeriod: ", SleepPeriod, "RegistrationState: ", RegistrationState); #endif /* UPNP_HAVE_OPTSSDP */ } else { #ifdef UPNP_HAVE_OPTSSDP ret_code = http_MakeMessage(&buf, 1, 1, "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "ssc" "ssc" "S" "Xc" "sscc", HTTPMETHOD_NOTIFY, "*", (size_t) 1, "HOST: ", host, ":", SSDP_PORT, "CACHE-CONTROL: max-age=", duration, "LOCATION: ", location, "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01", "01-NLS: ", gUpnpSdkNLSuuid, "NT: ", nt, "NTS: ", nts, X_USER_AGENT, "USN: ", usn); #else ret_code = http_MakeMessage(&buf, 1, 1, "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "S" "sscc", HTTPMETHOD_NOTIFY, "*", (size_t) 1, "HOST: ", host, ":", SSDP_PORT, "CACHE-CONTROL: max-age=", duration, "LOCATION: ", location, "NT: ", nt, "NTS: ", nts, "USN: ", usn); #endif /* UPNP_HAVE_OPTSSDP */ } if (ret_code) return; } else /* unknown msg */ assert(0); /* return msg */ *packet = membuffer_detach(&buf); membuffer_destroy(&buf); return; }
/************************************************************************ * 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; }