/** * Parse the service description from the service's SCPD URL. Do not call * this from user applications. * * @param service The service in question * @return true if successful; otherwise false */ bool mupnp_controlpoint_parsescservicescpd(mUpnpService *service) { mUpnpNetURL *scpdURL; bool scpdParseSuccess; mupnp_log_debug_l4("Entering...\n"); scpdURL = mupnp_service_getscpdurl(service); if ( NULL == scpdURL ) return false; mupnp_log_debug_s("SCPD URL: %s\n", mupnp_net_url_getrequest(scpdURL)); scpdParseSuccess = mupnp_service_parsedescriptionurl(service, scpdURL); mupnp_net_url_delete(scpdURL); if (scpdParseSuccess == true) return true; #if defined(MUPNP_USE_STDDCP) if (mupnp_service_hasstddcp(service)) { char *stdDCP = mupnp_service_getstddcp(service); scpdParseSuccess = mupnp_service_parsedescription(service, stdDCP, mupnp_strlen(stdDCP)); } #endif mupnp_log_debug_l4("Leaving...\n"); return scpdParseSuccess; }
void mupnp_ssdp_packet_print(mUpnpSSDPPacket *ssdpPkt) { mUpnpHttpHeader *header; mupnp_log_debug_l4("Entering...\n"); mupnp_log_debug_s("ssdp from %s %d\n", mupnp_ssdp_packet_getremoteaddress(ssdpPkt), mupnp_ssdp_packet_getremoteport(ssdpPkt)); /**** print headers ****/ for (header = mupnp_http_headerlist_gets(ssdpPkt->headerList); header != NULL; header = mupnp_http_header_next(header)) { mupnp_log_debug_s("%s: %s\n", mupnp_http_header_getname(header), mupnp_http_header_getvalue(header)); } mupnp_log_debug_l4("Leaving...\n"); }
void mupnp_http_response_print(mUpnpHttpResponse* httpRes) { mupnp_log_debug_l4("Entering...\n"); mupnp_log_debug_s("%s %d %s\n", mupnp_http_response_getversion(httpRes), mupnp_http_response_getstatuscode(httpRes), mupnp_http_response_getreasonphrase(httpRes)); mupnp_http_packet_print((mUpnpHttpPacket*)httpRes); mupnp_log_debug_l4("Leaving...\n"); }
/** * Add a listener to the event listener list * * @param eventListenerList The event listener list * @param listener The listener to add * */ void mupnp_eventlistenerlist_add(mUpnpEventListenerList* eventListenerList, MUPNP_EVENT_LISTENER listener) { mUpnpEventListenerList* list_node; mupnp_log_debug_l4("Entering...\n"); if (listener == NULL) return; list_node = (mUpnpEventListenerList*)malloc(sizeof(mUpnpEventListenerList)); if (NULL != list_node) { memset(list_node, 0, sizeof(mUpnpEventListenerList)); list_node->listener = listener; mupnp_list_node_init((mUpnpList*)list_node); mupnp_list_add((mUpnpList*)eventListenerList, (mUpnpList*)list_node); } else mupnp_log_debug_s("Memory allocation failure!\n"); mupnp_log_debug_l4("Leaving...\n"); }
mUpnpXmlNode *mupnp_soap_request_getbodynode(mUpnpSoapRequest *soapReq) { mUpnpXmlNode *envNode; mUpnpXmlNode *bodyNode = NULL; mUpnpXmlAttribute *attr; char *name; mUpnpStringTokenizer *tok; char *nsPrefix; size_t bodyLen; char *body; mupnp_log_debug_l4("Entering...\n"); envNode = mupnp_soap_request_getenvelopenode(soapReq); if (envNode == NULL) return NULL; if (mupnp_xml_node_haschildnodes(envNode) == false) return NULL; /* We cannot assume the namespace prefix for Body is 's'. According to spec, it could be anything... */ for (attr = mupnp_xml_node_getattributes(envNode); attr != NULL; attr = mupnp_xml_attribute_next(attr)) { /* First, find the namespace declaration attribute. */ /* Note: We must take a copy of the attr name. Tokenizer doesn't do it (by default) */ name = mupnp_strdup( mupnp_xml_attribute_getname(attr) ); tok = mupnp_string_tokenizer_new(name, ":"); nsPrefix = mupnp_string_tokenizer_nexttoken(tok); if ( -1 != mupnp_strstr(nsPrefix, "xmlns")) { /* This attribute is a namespace declaration. Check is it the one defined for SOAP. */ if (mupnp_strcmp(mupnp_xml_attribute_getvalue(attr), MUPNP_SOAP_XMLNS_URL) == 0) { /* This namespace declaration is correct. Use it to find the body node... */ if (mupnp_string_tokenizer_hasmoretoken(tok)) { /* There is a prefix */ nsPrefix = mupnp_string_tokenizer_nexttoken(tok); bodyLen = mupnp_strlen(nsPrefix) + mupnp_strlen(MUPNP_SOAP_DELIM) + mupnp_strlen(MUPNP_SOAP_BODY) + 1; /* +1 for trailing '\0'*/ body = (char*)malloc(bodyLen); if ( NULL == body ) { mupnp_log_debug_s("Memory allocation failure!\n"); return NULL; } #if defined(HAVE_SNPRINTF) snprintf(body, bodyLen, "%s%s%s", nsPrefix, MUPNP_SOAP_DELIM, MUPNP_SOAP_BODY); #else sprintf(body, "%s%s%s", nsPrefix, MUPNP_SOAP_DELIM, MUPNP_SOAP_BODY); #endif bodyNode = mupnp_xml_node_getchildnode(envNode, body); free(body); } else { /* No prefix */ bodyNode = mupnp_xml_node_getchildnode(envNode, MUPNP_SOAP_BODY); } /* Free memory before leaving the loop */ mupnp_string_tokenizer_delete(tok); free(name); break; } } mupnp_string_tokenizer_delete(tok); free(name); } mupnp_log_debug_l4("Leaving...\n"); return bodyNode; }
static bool mupnp_service_notifymain(mUpnpService* service, mUpnpStateVariable* statVar) { mUpnpSubscriber* sub; mUpnpSubscriber** subArray; int subArrayCnt; int n; mupnp_log_debug_l4("Entering...\n"); mupnp_service_lock(service); /**** Remove expired subscribers ****/ subArrayCnt = mupnp_service_getnsubscribers(service); subArray = (mUpnpSubscriber**)malloc(sizeof(mUpnpSubscriber*) * subArrayCnt); if (NULL == subArray) { mupnp_log_debug_s("Memory allocation problem!\n"); mupnp_service_unlock(service); return false; } sub = mupnp_service_getsubscribers(service); for (n = 0; n < subArrayCnt; n++) { subArray[n] = sub; sub = mupnp_subscriber_next(sub); } for (n = 0; n < subArrayCnt; n++) { sub = subArray[n]; if (sub == NULL) continue; if (mupnp_subscriber_isexpired(sub) == true) mupnp_service_removesubscriber(service, sub); } free(subArray); /**** Notify to subscribers ****/ subArrayCnt = mupnp_service_getnsubscribers(service); subArray = (mUpnpSubscriber**)malloc(sizeof(mUpnpSubscriber*) * subArrayCnt); if (NULL == subArray) { mupnp_log_debug_s("Memory allocation problem!\n"); mupnp_service_unlock(service); return false; } sub = mupnp_service_getsubscribers(service); for (n = 0; n < subArrayCnt; n++) { subArray[n] = sub; sub = mupnp_subscriber_next(sub); } for (n = 0; n < subArrayCnt; n++) { sub = subArray[n]; if (sub == NULL) continue; if (statVar) { if (mupnp_subscriber_notify(sub, statVar) == false) { /**** remove invalid the subscriber but don't remove in NMPR specification ****/ mupnp_service_removesubscriber(service, sub); } } else { if (mupnp_subscriber_notifyall(sub, service) == false) { /**** remove invalid the subscriber but don't remove in NMPR specification ****/ mupnp_service_removesubscriber(service, sub); } } } free(subArray); mupnp_service_unlock(service); mupnp_log_debug_l4("Leaving...\n"); return true; }
static void mupnp_http_server_clientthread(mUpnpThread *thread) { mUpnpHttpServerClientData *clientData; mUpnpHttpServer *httpServer; mUpnpSocket *clientSock; void *httpServerUserData; mUpnpHttpRequest *httpReq; char *version = NULL; mupnp_log_debug_l4("Entering...\n"); clientData = (mUpnpHttpServerClientData *)mupnp_thread_getuserdata(thread); httpServer = clientData->httpServer; clientSock = clientData->clientSock; httpServerUserData = mupnp_http_server_getuserdata(httpServer); httpReq = mupnp_http_request_new(); mupnp_http_request_setsocket(httpReq, clientSock); /**** Thanks for Makela Aapo (10/31/05) ****/ while (mupnp_http_request_read(httpReq, clientSock) == true && mupnp_thread_isrunnable(thread) == true) { /* Check some validity of the request */ version = mupnp_http_request_getversion(httpReq); if (mupnp_strcmp(version, MUPNP_HTTP_VER11) == 0) { /* According to HTTP/1.1 spec, we must not tolerate HTTP/1.1 request without HOST-header */ if (mupnp_http_request_gethost(httpReq) == NULL) { mupnp_http_request_postbadrequest(httpReq); continue; } } if (httpServer->listener != NULL) { mupnp_http_request_setuserdata(httpReq, httpServerUserData); httpServer->listener(httpReq); } /* Close connection according to HTTP version and headers */ if (mupnp_strcmp(version, MUPNP_HTTP_VER10) == 0) { /* Terminate connection after HTTP/1.0 request */ break; } /* We are having HTTP/1.1 or better => terminate, if requested */ if (mupnp_http_request_iskeepaliveconnection(httpReq) == false) { break; } } mupnp_log_debug_s("Dropping HTTP client\n"); mupnp_http_request_delete(httpReq); mupnp_socket_close(clientSock); mupnp_socket_delete(clientSock); mupnp_http_server_clientdata_delete(clientData); mupnp_thread_setuserdata(thread, NULL); // This code frequently crashes. mutex lock referencing free'd memory. mupnp_http_server_lock(httpServer); mupnp_thread_remove(thread); mupnp_http_server_unlock(httpServer); mupnp_log_debug_l4("Leaving...\n"); mupnp_thread_delete(thread); }
/** * Stop the control point. Stops sending/receiveing/responding to any messages. * * @param ctrlPoint The control point to stop * * @return true if successful; otherwise false * */ bool mupnp_controlpoint_stop(mUpnpControlPoint *ctrlPoint) { mUpnpDevice *dev = NULL; mUpnpSSDPServerList *ssdpServerList; mUpnpSSDPResponseServerList *ssdpResServerList; mUpnpHttpServerList *httpServerList; const char *udn = NULL; MUPNP_DEVICE_LISTENER listener = mupnp_controlpoint_getdevicelistener(ctrlPoint); mupnp_log_debug_l4("Entering...\n"); /* Stop expiration handling */ mupnp_thread_stop_with_cond(ctrlPoint->expThread, ctrlPoint->expCond); mupnp_log_debug_s("Expiration thread stopped.\n"); /**** SSDP Server ****/ ssdpServerList = mupnp_controlpoint_getssdpserverlist(ctrlPoint); mupnp_log_debug_s("Stopping ssdp servers.\n"); mupnp_ssdp_serverlist_setlistener(ssdpServerList, NULL); mupnp_ssdp_serverlist_setuserdata(ssdpServerList, NULL); mupnp_ssdp_serverlist_stop(ssdpServerList); mupnp_log_debug_s("Done\n"); mupnp_ssdp_serverlist_close(ssdpServerList); mupnp_ssdp_serverlist_clear(ssdpServerList); /**** SSDP Response Server ****/ ssdpResServerList = mupnp_controlpoint_getssdpresponseserverlist(ctrlPoint); mupnp_log_debug_s("Stopping ssdp response servers.\n"); mupnp_ssdpresponse_serverlist_setlistener(ssdpResServerList, NULL); mupnp_ssdpresponse_serverlist_setuserdata(ssdpResServerList, NULL); mupnp_ssdpresponse_serverlist_stop(ssdpResServerList); mupnp_log_debug_s("Done\n"); mupnp_ssdpresponse_serverlist_close(ssdpResServerList); mupnp_ssdpresponse_serverlist_clear(ssdpResServerList); /**** HTTP Server ****/ httpServerList = mupnp_controlpoint_gethttpserverlist(ctrlPoint); mupnp_log_debug_s("Stopping http servers.\n"); mupnp_http_serverlist_setlistener(httpServerList, NULL); mupnp_http_serverlist_stop(httpServerList); mupnp_log_debug_s("Done\n"); mupnp_http_serverlist_close(httpServerList); mupnp_http_serverlist_clear(httpServerList); mupnp_controlpoint_lock(ctrlPoint); mupnp_log_debug_s("Got controlpoint lock.\n"); /* Unsubscribe from all services */ for (dev = mupnp_controlpoint_getdevices(ctrlPoint); dev != NULL; dev = mupnp_device_next(dev)) { udn = mupnp_device_getudn(dev); /* Call device listener for each device */ if (udn != NULL && listener != NULL) { mupnp_controlpoint_unlock(ctrlPoint); listener(ctrlPoint, udn, mUpnpDeviceStatusRemoved); mupnp_controlpoint_lock(ctrlPoint); } } /* Empty device cache */ mupnp_devicelist_clear(ctrlPoint->deviceList); mupnp_log_debug_s("Device list cleared.\n"); mupnp_controlpoint_unlock(ctrlPoint); mupnp_log_debug_l4("Leaving...\n"); return true; }
static int filter_duplicate_m_search(mUpnpSSDPPacket *ssdpPkt) { mUpnpTime *timestamps = ssdpPkt->timestamps; size_t s_length; int loc; const char *st; char *id_string, *r_address, port[6]; mUpnpTime curr_time; mupnp_log_debug_l4("Entering...\n"); /* Initializing hash table to zero */ if (!ssdpPkt->initialized) { ssdpPkt->initialized = 1; memset(timestamps, '\0', MUPNP_SSDP_FILTER_TABLE_SIZE * sizeof( mUpnpTime )); } r_address = mupnp_string_getvalue(ssdpPkt->dgmPkt->remoteAddress); st = mupnp_ssdp_packet_getst(ssdpPkt); sprintf(port, "%d", ssdpPkt->dgmPkt->remotePort); /* Catenating remote address string with ssdp ST header field. */ s_length = strlen( r_address ) + strlen( st ) + strlen( port ); id_string = (char *)malloc( s_length + 1 ); if ( NULL == id_string ) { mupnp_log_debug_s("Memory allocation problem!\n"); return FALSE; } memset(id_string, '\0', s_length + 1); mupnp_strcat(id_string, r_address ); mupnp_strcat(id_string, port); mupnp_strcat(id_string, st ); loc = simple_string_hash(id_string, MUPNP_SSDP_FILTER_TABLE_SIZE); mupnp_log_debug("Calculated hash: %d\n", loc); free(id_string); curr_time = mupnp_getcurrentsystemtime(); if ( 0 == timestamps[loc] ) { timestamps[loc] = curr_time; mupnp_log_debug("First packet... Updating hash table.\n"); return FALSE; } else if ( ( curr_time - timestamps[loc] ) < MUPNP_DEVICE_M_SEARCH_FILTER_INTERVAL ) { mupnp_log_debug("Filtering packet!\n"); timestamps[loc] = curr_time; return TRUE; } else { timestamps[loc] = curr_time; mupnp_log_debug("Old timestamp found, just updating it.\n"); return FALSE; } mupnp_log_debug_l4("Leaving...\n"); }
char* mupnp_net_selectaddr(struct sockaddr* remoteaddr) { struct ifaddrs *ifaddrs, *ifaddr; uint32_t laddr, lmask, raddr; char *address_candidate = NULL, *auto_ip_address_candidate = NULL; raddr = ntohl(((struct sockaddr_in*)remoteaddr)->sin_addr.s_addr); if (0 != getifaddrs(&ifaddrs)) { return NULL; } for (ifaddr = ifaddrs; NULL != ifaddr; ifaddr = ifaddr->ifa_next) { if (ifaddr->ifa_addr == NULL) continue; if (!(ifaddr->ifa_flags & IFF_UP)) continue; if (ifaddr->ifa_flags & IFF_LOOPBACK) continue; if (ifaddr->ifa_flags & IFF_POINTOPOINT) continue; laddr = ntohl(((struct sockaddr_in*)ifaddr->ifa_addr)->sin_addr.s_addr); if (NULL != (struct sockaddr_in*)ifaddr->ifa_netmask) lmask = ntohl(((struct sockaddr_in*)ifaddr->ifa_netmask)->sin_addr.s_addr); else { mupnp_log_debug_s("No netmask for address %u!\n", laddr); continue; } /* Checking if we have an exact subnet match */ if ((laddr & lmask) == (raddr & lmask)) { if (NULL != address_candidate) free(address_candidate); address_candidate = mupnp_strdup( inet_ntoa((struct in_addr)((struct sockaddr_in*)ifaddr->ifa_addr)->sin_addr)); mupnp_log_debug_s("Address match! Selecting local address (%u)\n", laddr); break; } /* Checking if we have and auto ip address */ if ((laddr & lmask) == MUPNP_NET_SOCKET_AUTO_IP_NET) { mupnp_log_debug_s("Found auto ip address. Selecting it for second address candidate (%u)\n", laddr); if (NULL != auto_ip_address_candidate) free(auto_ip_address_candidate); auto_ip_address_candidate = mupnp_strdup( inet_ntoa((struct in_addr)((struct sockaddr_in*)ifaddr->ifa_addr)->sin_addr)); } /* Good. We have others than auto ips present. */ else { mupnp_log_debug_s("Didn't have an exact subnet match, but non auto ip address anyway... (%u)\n", laddr); if (NULL != address_candidate) free(address_candidate); address_candidate = mupnp_strdup( inet_ntoa((struct in_addr)((struct sockaddr_in*)ifaddr->ifa_addr)->sin_addr)); } } freeifaddrs(ifaddrs); if (NULL != address_candidate) { if (NULL != auto_ip_address_candidate) free(auto_ip_address_candidate); return address_candidate; } if (NULL != auto_ip_address_candidate) { if (NULL != address_candidate) free(address_candidate); return auto_ip_address_candidate; } /* Starting to feel desperate and returning local address.*/ return mupnp_strdup("127.0.0.1"); }
BOOL mupnp_http_persistentconnection_put(char *host, int port, void *data) { mUpnpHttpPersistentConnection *new_node = NULL, *node = NULL; mupnp_log_debug_l4("Entering...\n"); /* If we dont have cache, then just exit */ if (cache == NULL) { mupnp_log_debug("(put) No cache! Persistent connections not initialized?\n"); return FALSE; } /* Check if we already have this one cached */ for (node = (mUpnpHttpPersistentConnection*)mupnp_list_gets((mUpnpList*)cache); node != NULL; node = (mUpnpHttpPersistentConnection*)mupnp_list_next((mUpnpList*)node)) { if (mupnp_strcmp(mupnp_string_getvalue(node->host), host) == 0 && node->port == port) { /* If also data is the same, then update just timestamp */ if (node->cacheData == data) { node->timestamp = mupnp_getcurrentsystemtime(); return TRUE; } mupnp_log_debug_s("Found cached persistent connection for %s:%d\n", mupnp_string_getvalue(node->host), node->port); new_node = node; mupnp_list_remove((mUpnpList*)new_node); break; } } /* We didn't find it */ if (new_node == NULL) { /* Check if we have already too many cached things */ if (mupnp_list_size((mUpnpList*)cache) >= CG_HTTP_PERSISTENT_CACHE_SIZE) { /* Take last node (not refreshed for a long time) */ new_node = (mUpnpHttpPersistentConnection *)mupnp_list_next((mUpnpList *)cache); mupnp_list_remove((mUpnpList*)new_node); mupnp_http_persistentconnection_delete(new_node); new_node = NULL; mupnp_log_debug_s("Max persistent HTTP connection cache reached.\n"); } if (new_node == NULL) { if (data == NULL) return TRUE; new_node = mupnp_http_persistentconnection_new(); if (new_node == NULL) return FALSE; mupnp_log_debug_s("Adding persistent HTTP Connection %s:%d to cache\n", host, port); mupnp_log_debug_s("Persistent connections: %d\n", mupnp_list_size((mUpnpList*)cache)); } } if (data != NULL) { /* Set appropriate values for the node */ mupnp_string_setvalue(new_node->host, host); new_node->port = port; new_node->cacheData = data; new_node->timestamp = mupnp_getcurrentsystemtime(); mupnp_list_add((mUpnpList*)cache, (mUpnpList*)new_node); } else { /* remove and delete node */ mupnp_http_persistentconnection_delete(new_node); } return TRUE; mupnp_log_debug_l4("Leaving...\n"); }
void *mupnp_http_persistentconnection_get(char *host, int port) { mUpnpHttpPersistentConnection *node; mUpnpTime sys_time = mupnp_getcurrentsystemtime(); BOOL iterate; mupnp_log_debug_l4("Entering...\n"); /* If we dont have cache, then just exit */ if (cache == NULL) { mupnp_log_debug("(get) No cache! Persistent connections not initialized?\n"); return NULL; } /* Clear all expired nodes */ do { iterate = FALSE; for (node = (mUpnpHttpPersistentConnection*)mupnp_list_gets((mUpnpList*)cache); node != NULL; node = (mUpnpHttpPersistentConnection*)mupnp_list_next((mUpnpList*)node)) { if (sys_time > node->timestamp + CG_HTTP_PERSISTENT_TIMEOUT_PERIOD) { mupnp_log_debug_s("Timeout for persistent HTTP Connection to %s:%d " "(timestamp: %d)\n", mupnp_string_getvalue(node->host), node->port, node->timestamp); mupnp_list_remove((mUpnpList*)node); mupnp_http_persistentconnection_delete(node); iterate = TRUE; break; } } } while (iterate); /* Get persistent node */ for (node = (mUpnpHttpPersistentConnection*)mupnp_list_gets((mUpnpList*)cache); node != NULL; node = (mUpnpHttpPersistentConnection*)mupnp_list_next((mUpnpList*)node)) { if (mupnp_strcmp(mupnp_string_getvalue(node->host), host) == 0 && node->port == port) { /* Node was required, remove and add again to refresh cache */ mupnp_list_remove((mUpnpList*)node); mupnp_list_add((mUpnpList*)cache, (mUpnpList*)node); node->timestamp = mupnp_getcurrentsystemtime(); mupnp_log_debug_s("Persistent HTTP Connection cache HIT for %s:%d\n", host, port); return node->cacheData; } } mupnp_log_debug_s("Persistent HTTP Connection cache MISS for %s:%d\n", host, port); return NULL; mupnp_log_debug_l4("Leaving...\n"); }
bool mupnp_xml_parse(mUpnpXmlParser* parser, mUpnpXmlNodeList* nodeList, const char* data, size_t len) { #if defined DEBUG_XML_RESULT mUpnpString* resdata = NULL; #endif XML_Parser p; mUpnpExpatData expatData; #ifdef MUPNP_SHOW_TIMINGS struct timeval start_time, end_time, elapsed_time; #endif mupnp_log_debug_l4("Entering...\n"); #ifdef MUPNP_SHOW_TIMINGS gettimeofday(&start_time, NULL); #endif if (!data || len <= 0) return false; p = XML_ParserCreate(NULL); if (!p) return false; /* Fix to get expat parser to work with DLink-routers */ if (data[len - 1] == 0) len--; expatData.rootNode = NULL; expatData.currNode = NULL; XML_SetUserData(p, &expatData); XML_SetElementHandler(p, mupnp_expat_element_start, mupnp_expat_element_end); XML_SetCharacterDataHandler(p, mupnp_expat_character_data); parser->parseResult = XML_Parse(p, data, len, 1); XML_ParserFree(p); if (parser->parseResult == 0 /*XML_STATUS_ERROR*/) { if (expatData.rootNode != NULL) mupnp_xml_node_delete(expatData.rootNode); #if defined DEBUG_XML_RESULT resdata = mupnp_string_new(); mupnp_string_naddvalue(resdata, data, len); printf("XML parse Error on data %s\n time used = %ds\n", mupnp_string_getvalue(resdata), time(NULL) - startTime); mupnp_string_delete(resdata); #endif return false; } mupnp_xml_nodelist_add(nodeList, expatData.rootNode); #ifdef MUPNP_SHOW_TIMINGS gettimeofday(&end_time, NULL); timersub(&end_time, &start_time, &elapsed_time); mupnp_log_debug_s("Parsing XML completed. Elapsed time: " "%ld msec\n", ((elapsed_time.tv_sec * 1000) + (elapsed_time.tv_usec / 1000))); mupnp_total_elapsed_time += (elapsed_time.tv_sec * 1000000) + (elapsed_time.tv_usec); mupnp_log_debug_s("Total elapsed time: %ld msec\n", mupnp_total_elapsed_time / 1000); #endif #if defined DEBUG_XML_RESULT resdata = mupnp_string_new(); mupnp_string_naddvalue(resdata, data, len); printf("XML parse success - time used %ds\n", time(NULL) - startTime); mupnp_string_delete(resdata); #endif return true; mupnp_log_debug_l4("Leaving...\n"); }