/** * Find a device from the control point by the exact type of the device. * This function searches for devices, whose *complete type string* * matches the given string, including version number. For example: * "urn:schemas-upnp-org:device:FooDevice:1". If you need to disregard * the version, use \ref mupnp_controlpoint_getdevicebytype * * \param ctrlPoint Controlpoint in question * \param exacttype Type of the device * */ mUpnpDevice* mupnp_controlpoint_getdevicebyexacttype(mUpnpControlPoint* ctrlPoint, const char* exacttype) { mUpnpDevice* dev = NULL; mUpnpDevice* childDev = NULL; mupnp_log_debug_l4("Entering...\n"); if (mupnp_strlen(exacttype) <= 0 || ctrlPoint == NULL) { return NULL; } for (dev = mupnp_controlpoint_getdevices(ctrlPoint); dev != NULL; dev = mupnp_device_next(dev)) { if (mupnp_strcmp(mupnp_device_getdevicetype(dev), exacttype) == 0) { return dev; } childDev = mupnp_device_getdevicebyexacttype(dev, exacttype); if (childDev != NULL) { return childDev; } } mupnp_log_debug_l4("Leaving...\n"); return NULL; }
/** * Find a device from the controlpoint by the UDN of the device. * * \param ctrlPoint Controlpoint in question * \param udn Type of the device * */ mUpnpDevice *mupnp_controlpoint_getdevicebyudn(mUpnpControlPoint *ctrlPoint, char *udn) { mUpnpDevice *dev = NULL; mUpnpDevice *childDev = NULL; mupnp_log_debug_l4("Entering...\n"); if (mupnp_strlen(udn) <= 0 || ctrlPoint == NULL) { return NULL; } for (dev = mupnp_controlpoint_getdevices(ctrlPoint); dev != NULL; dev = mupnp_device_next(dev)) { if (mupnp_strcmp(mupnp_device_getudn(dev), udn) == 0) { return dev; } childDev = mupnp_device_getdevicebyudn(dev, udn); if (childDev != NULL) { return childDev; } } mupnp_log_debug_l4("Leaving...\n"); return NULL; }
int mupnp_net_interface_cmp(mUpnpNetworkInterface *netIfA, mUpnpNetworkInterface *netIfB) { mupnp_log_debug_l4("Entering...\n"); if (netIfA == NULL && netIfB == NULL) return 0; if (netIfA == NULL && netIfB != NULL) return 1; if (netIfA != NULL && netIfB == NULL) return -1; return mupnp_strcmp(mupnp_net_interface_getaddress(netIfA), mupnp_net_interface_getaddress(netIfB)); mupnp_log_debug_l4("Leaving...\n"); }
/** * Find a device from the controlpoint by the type of the device. * This function searches for devices, whose *type part* (i.e. not including * the version) of the device type string matches the given string. * For example: "urn:schemas-upnp-org:device:FooDevice". If you need * to know the version of a device, use \ref mupnp_devicetype_getversion * * \param ctrlPoint Controlpoint in question * \param type Type of the device * */ mUpnpDevice *mupnp_controlpoint_getdevicebytype(mUpnpControlPoint *ctrlPoint, char *type) { mUpnpDevice *dev = NULL; mUpnpDevice *childDev = NULL; const char* typeString = NULL; char* part = NULL; mupnp_log_debug_l4("Entering...\n"); if (mupnp_strlen(type) <= 0 || ctrlPoint == NULL) { return NULL; } for (dev = mupnp_controlpoint_getdevices(ctrlPoint); dev != NULL; dev = mupnp_device_next(dev)) { typeString = mupnp_device_getdevicetype(dev); if (typeString != NULL) { part = mupnp_devicetype_getschematype(typeString); if (mupnp_strcmp(part, type) == 0) { free(part); return dev; } else { free(part); } } childDev = mupnp_device_getdevicebytype(dev, type); if (childDev != NULL) { return childDev; } } mupnp_log_debug_l4("Leaving...\n"); return NULL; }
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 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); }
bool mupnp_controlpoint_ipchanged(mUpnpControlPoint *ctrlPoint) { mUpnpNetworkInterfaceList *current, *added, *removed; mUpnpNetworkInterface *netIf; mUpnpDevice *dev, *tmp; mUpnpSSDPPacket *ssdpPkt; char *address; mupnp_log_debug_l4("Entering...\n"); current = mupnp_net_interfacelist_new(); added = mupnp_net_interfacelist_new(); removed = mupnp_net_interfacelist_new(); if (current == NULL || added == NULL || removed == NULL) { if (current != NULL) mupnp_net_interfacelist_delete(current); if (added != NULL) mupnp_net_interfacelist_delete(added); if (removed != NULL) mupnp_net_interfacelist_delete(removed); return false; } /* Get Interface changes */ mupnp_net_gethostinterfaces(current); mupnp_net_interfacelist_getchanges(ctrlPoint->ifCache, current, added, removed); /* Remove all devices registered through old interface */ for (netIf = mupnp_net_interfacelist_gets(removed); netIf != NULL; netIf = mupnp_net_interface_next(netIf)) { mupnp_controlpoint_lock(ctrlPoint); tmp = mupnp_controlpoint_getdevices(ctrlPoint); while (tmp != NULL) { dev = tmp; tmp = mupnp_device_next(dev); ssdpPkt = mupnp_device_getssdppacket(dev); address = mupnp_ssdp_packet_getlocaladdress(ssdpPkt); if (address != NULL && mupnp_strcmp(address, mupnp_net_interface_getaddress(netIf)) == 0) { /* This device has been received from the removed interface, so it does not exist */ mupnp_controlpoint_unlock(ctrlPoint); mupnp_controlpoint_removedevicebyssdppacket(ctrlPoint, ssdpPkt); mupnp_controlpoint_lock(ctrlPoint); address = NULL; dev = NULL; ssdpPkt = NULL; } } mupnp_controlpoint_unlock(ctrlPoint); } /* Launch new M-SEARCH */ mupnp_controlpoint_search(ctrlPoint, MUPNP_ST_ROOT_DEVICE); /**** Cache current interfaces ****/ mupnp_net_gethostinterfaces(ctrlPoint->ifCache); mupnp_net_interfacelist_delete(current); mupnp_net_interfacelist_delete(added); mupnp_net_interfacelist_delete(removed); mupnp_log_debug_l4("Leaving...\n"); return true; }
void mupnp_device_ssdpmessagereceived(mUpnpDevice *dev, mUpnpSSDPPacket *ssdpPkt, int filter) { BOOL isRootDev; const char *ssdpST; const char *devUDN, *devType; char ssdpMsg[MUPNP_SSDP_HEADER_LINE_MAXSIZE]; char deviceUSN[MUPNP_SSDP_HEADER_LINE_MAXSIZE]; #if defined WINCE size_t n; #else int n; #endif mUpnpService *service; mUpnpDevice *childDev; const char *ssdpMXString; int ssdpMX; const char *ssdpTargetAddr; mupnp_log_debug_l4("Entering...\n"); ssdpMXString = mupnp_http_headerlist_getvalue(ssdpPkt->headerList, CG_HTTP_MX); ssdpST = mupnp_ssdp_packet_getst(ssdpPkt); /* Check if this ssdp packet has already been checked + filtered */ if (filter) { /**************************************** * Request line * Check the request line for errors, this is not ideal as it currently only * checks for the presence of the strings and not the order. ***************************************/ /**** check for M-SEARCH and return if not found ****/ if (mupnp_strstr(mupnp_string_getvalue(ssdpPkt->dgmPkt->data), CG_HTTP_MSEARCH) < 0) return; /**** check for * and return if not found ****/ if (mupnp_strstr(mupnp_string_getvalue(ssdpPkt->dgmPkt->data), "*") < 0) return; /**** check HTTP version and return if not found ****/ if (mupnp_strstr(mupnp_string_getvalue(ssdpPkt->dgmPkt->data), CG_HTTP_VER11) < 0) return; /**************************************** * check HOST header, should always be 239.255.255.250:1900, return if incorrect ***************************************/ ssdpTargetAddr = mupnp_ssdp_packet_gethost(ssdpPkt); if (mupnp_strcmp(ssdpTargetAddr, MUPNP_SSDP_MULTICAST_ADDRESS) != 0 && !mupnp_net_isipv6address(ssdpTargetAddr) ) return; /**************************************** * check MAN header, return if incorrect ***************************************/ if (mupnp_ssdp_packet_isdiscover(ssdpPkt) == FALSE) return; /**************************************** * check MX header, return if incorrect ***************************************/ if (ssdpMXString == NULL || mupnp_strlen(ssdpMXString)==0) /* return if the MX value does not exist or is empty */ return; /* check if MX value is not an integer */ for (n=0; n<strlen(ssdpMXString); n++) { if (isdigit(ssdpMXString[n]) == 0) /* MX value contains a non-digit so is invalid */ return; } /**************************************** * check ST header and if empty return ***************************************/ if (mupnp_strlen(ssdpST) <= 0) return; /* Check if we have received this search recently * and ignore duplicates. */ if ( filter_duplicate_m_search(ssdpPkt) ) return; ssdpMX = mupnp_ssdp_packet_getmx(ssdpPkt); mupnp_log_debug("Sleeping for a while... (MX:%d)\n", ssdpMX); mupnp_waitrandom((ssdpMX*1000)/4); } isRootDev = mupnp_device_isrootdevice(dev); if (mupnp_st_isalldevice(ssdpST) == TRUE) { /* for root device only */ if (isRootDev == TRUE) { mupnp_device_getnotifydevicent(dev, ssdpMsg, sizeof(ssdpMsg)); mupnp_device_getnotifydeviceusn(dev, deviceUSN, sizeof(deviceUSN)); mupnp_device_postsearchresponse(dev, ssdpPkt, ssdpMsg, deviceUSN); } /* for all devices send */ /* device type : device version */ mupnp_device_getnotifydevicetypent(dev, ssdpMsg, sizeof(ssdpMsg)); mupnp_device_getnotifydevicetypeusn(dev, deviceUSN, sizeof(deviceUSN)); mupnp_device_postsearchresponse(dev, ssdpPkt, ssdpMsg, deviceUSN); /* device UUID */ mupnp_device_postsearchresponse(dev, ssdpPkt, mupnp_device_getudn(dev), mupnp_device_getudn(dev)); } else if (mupnp_st_isrootdevice(ssdpST) == TRUE) { if (isRootDev == TRUE) { mupnp_device_getnotifydeviceusn(dev, deviceUSN, sizeof(deviceUSN)); mupnp_device_postsearchresponse(dev, ssdpPkt, MUPNP_ST_ROOT_DEVICE, deviceUSN); } } else if (mupnp_st_isuuiddevice(ssdpST) == TRUE) { devUDN = mupnp_device_getudn(dev); if (mupnp_streq(ssdpST, devUDN) == TRUE) mupnp_device_postsearchresponse(dev, ssdpPkt, devUDN, devUDN); } else if (mupnp_st_isurn(ssdpST) == TRUE) { devType = mupnp_device_getdevicetype(dev); if (mupnp_streq(ssdpST, devType) == TRUE) { mupnp_device_getnotifydevicetypeusn(dev, deviceUSN, sizeof(deviceUSN)); mupnp_device_postsearchresponse(dev, ssdpPkt, devType, deviceUSN); } } for (service=mupnp_device_getservices(dev); service != NULL; service = mupnp_service_next(service)) mupnp_service_ssdpmessagereceived(service, ssdpPkt); for (childDev = mupnp_device_getdevices(dev); childDev != NULL; childDev = mupnp_device_next(childDev)) mupnp_device_ssdpmessagereceived(childDev, ssdpPkt, FALSE); mupnp_log_debug_l4("Leaving...\n"); }
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"); }