int SearchByTarget(int Mx, char *St, void *Cookie) { char errorBuffer[ERROR_BUFFER_LEN]; int *id = NULL; int ret = 0; char ReqBufv4[BUFSIZE]; #ifdef UPNP_ENABLE_IPV6 char ReqBufv6[BUFSIZE]; char ReqBufv6UlaGua[BUFSIZE]; #endif struct sockaddr_storage __ss_v4; #ifdef UPNP_ENABLE_IPV6 struct sockaddr_storage __ss_v6; #endif struct sockaddr_in *destAddr4 = (struct sockaddr_in *)&__ss_v4; #ifdef UPNP_ENABLE_IPV6 struct sockaddr_in6 *destAddr6 = (struct sockaddr_in6 *)&__ss_v6; #endif fd_set wrSet; SsdpSearchArg *newArg = NULL; int timeTillRead = 0; int handle; struct Handle_Info *ctrlpt_info = NULL; enum SsdpSearchType requestType; unsigned long addrv4 = inet_addr(gIF_IPV4); SOCKET max_fd = 0; int retVal; /*ThreadData *ThData; */ ThreadPoolJob job; memset(&job, 0, sizeof(job)); requestType = ssdp_request_type1(St); if (requestType == SSDP_SERROR) return UPNP_E_INVALID_PARAM; UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, "Inside SearchByTarget\n"); timeTillRead = Mx; if (timeTillRead < MIN_SEARCH_TIME) timeTillRead = MIN_SEARCH_TIME; else if (timeTillRead > MAX_SEARCH_TIME) timeTillRead = MAX_SEARCH_TIME; retVal = CreateClientRequestPacket(ReqBufv4, sizeof(ReqBufv4), timeTillRead, St, AF_INET); if (retVal != UPNP_E_SUCCESS) return retVal; #ifdef UPNP_ENABLE_IPV6 retVal = CreateClientRequestPacket(ReqBufv6, sizeof(ReqBufv6), timeTillRead, St, AF_INET6); if (retVal != UPNP_E_SUCCESS) return retVal; retVal = CreateClientRequestPacketUlaGua(ReqBufv6UlaGua, sizeof(ReqBufv6UlaGua), timeTillRead, St, AF_INET6); if (retVal != UPNP_E_SUCCESS) return retVal; #endif memset(&__ss_v4, 0, sizeof(__ss_v4)); destAddr4->sin_family = (sa_family_t)AF_INET; inet_pton(AF_INET, SSDP_IP, &destAddr4->sin_addr); destAddr4->sin_port = htons(SSDP_PORT); #ifdef UPNP_ENABLE_IPV6 memset(&__ss_v6, 0, sizeof(__ss_v6)); destAddr6->sin6_family = (sa_family_t)AF_INET6; inet_pton(AF_INET6, SSDP_IPV6_SITELOCAL, &destAddr6->sin6_addr); destAddr6->sin6_port = htons(SSDP_PORT); destAddr6->sin6_scope_id = gIF_INDEX; #endif /* add search criteria to list */ HandleLock(); if (GetClientHandleInfo(&handle, &ctrlpt_info) != HND_CLIENT) { HandleUnlock(); return UPNP_E_INTERNAL_ERROR; } newArg = (SsdpSearchArg *) malloc(sizeof(SsdpSearchArg)); newArg->searchTarget = strdup(St); newArg->cookie = Cookie; newArg->requestType = requestType; id = (int *)malloc(sizeof(int)); TPJobInit(&job, (start_routine) searchExpired, id); TPJobSetPriority(&job, MED_PRIORITY); TPJobSetFreeFunction(&job, (free_routine) free); /* Schedule a timeout event to remove search Arg */ TimerThreadSchedule(&gTimerThread, timeTillRead, REL_SEC, &job, SHORT_TERM, id); newArg->timeoutEventId = *id; ListAddTail(&ctrlpt_info->SsdpSearchList, newArg); HandleUnlock(); /* End of lock */ FD_ZERO(&wrSet); if (gSsdpReqSocket4 != INVALID_SOCKET) { setsockopt(gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addrv4, sizeof(addrv4)); FD_SET(gSsdpReqSocket4, &wrSet); max_fd = max(max_fd, gSsdpReqSocket4); } #ifdef UPNP_ENABLE_IPV6 if (gSsdpReqSocket6 != INVALID_SOCKET) { setsockopt(gSsdpReqSocket6, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&gIF_INDEX, sizeof(gIF_INDEX)); FD_SET(gSsdpReqSocket6, &wrSet); max_fd = max(max_fd, gSsdpReqSocket6); } #endif ret = select(max_fd + 1, NULL, &wrSet, NULL, NULL); if (ret == -1) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, "SSDP_LIB: Error in select(): %s\n", errorBuffer); shutdown(gSsdpReqSocket4, SD_BOTH); UpnpCloseSocket(gSsdpReqSocket4); #ifdef UPNP_ENABLE_IPV6 shutdown(gSsdpReqSocket6, SD_BOTH); UpnpCloseSocket(gSsdpReqSocket6); #endif return UPNP_E_INTERNAL_ERROR; } #ifdef UPNP_ENABLE_IPV6 if (gSsdpReqSocket6 != INVALID_SOCKET && FD_ISSET(gSsdpReqSocket6, &wrSet)) { int NumCopy = 0; while (NumCopy < NUM_SSDP_COPY) { UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv6UlaGua); sendto(gSsdpReqSocket6, ReqBufv6UlaGua, strlen(ReqBufv6UlaGua), 0, (struct sockaddr *)&__ss_v6, sizeof(struct sockaddr_in6)); NumCopy++; imillisleep(SSDP_PAUSE); } NumCopy = 0; inet_pton(AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr); while (NumCopy < NUM_SSDP_COPY) { UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv6); sendto(gSsdpReqSocket6, ReqBufv6, strlen(ReqBufv6), 0, (struct sockaddr *)&__ss_v6, sizeof(struct sockaddr_in6)); NumCopy++; imillisleep(SSDP_PAUSE); } } #endif /* IPv6 */ if (gSsdpReqSocket4 != INVALID_SOCKET && FD_ISSET(gSsdpReqSocket4, &wrSet)) { int NumCopy = 0; while (NumCopy < NUM_SSDP_COPY) { UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv4); sendto(gSsdpReqSocket4, ReqBufv4, strlen(ReqBufv4), 0, (struct sockaddr *)&__ss_v4, sizeof(struct sockaddr_in)); NumCopy++; imillisleep(SSDP_PAUSE); } } return 1; }
/*! * \brief Thread job to Notify a control point. * * It validates the subscription and copies the subscription. Also make sure * that events are sent in order. * * \note calls the genaNotify to do the actual work. */ static void genaNotifyThread( /*! [in] notify thread structure containing all the headers and property set info. */ void *input) { subscription *sub; service_info *service; subscription sub_copy; notify_thread_struct *in = (notify_thread_struct *) input; int return_code; struct Handle_Info *handle_info; ThreadPoolJob job; memset(&job, 0, sizeof(job)); /* This should be a HandleLock and not a HandleReadLock otherwise if there * is a lot of notifications, then multiple threads will acquire a read * lock and the thread which sends the notification will be blocked forever * on the HandleLock at the end of this function. */ /*HandleReadLock(); */ HandleLock(); /* validate context */ if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) { free_notify_struct(in); HandleUnlock(); return; } if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) || !service->active || !(sub = GetSubscriptionSID(in->sid, service)) || copy_subscription(sub, &sub_copy) != HTTP_SUCCESS) { free_notify_struct(in); HandleUnlock(); return; } #ifdef UPNP_ENABLE_NOTIFICATION_REORDERING /*If the event is out of order push it back to the job queue */ if (in->eventKey != sub->ToSendEventKey) { TPJobInit(&job, (start_routine) genaNotifyThread, input); TPJobSetFreeFunction(&job, (free_function) free_notify_struct); TPJobSetPriority(&job, MED_PRIORITY); /* Sleep a little before creating another thread otherwise if there is * a lot of notifications to send, the device will take 100% of the CPU * to create threads and push them back to the job queue. */ imillisleep(1); ThreadPoolAdd(&gSendThreadPool, &job, NULL); freeSubscription(&sub_copy); HandleUnlock(); return; } #endif HandleUnlock(); /* send the notify */ return_code = genaNotify(in->headers, in->propertySet, &sub_copy); freeSubscription(&sub_copy); HandleLock(); if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) { free_notify_struct(in); HandleUnlock(); return; } /* validate context */ if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) || !service->active || !(sub = GetSubscriptionSID(in->sid, service))) { free_notify_struct(in); HandleUnlock(); return; } sub->ToSendEventKey++; if (sub->ToSendEventKey < 0) /* wrap to 1 for overflow */ sub->ToSendEventKey = 1; if (return_code == GENA_E_NOTIFY_UNACCEPTED_REMOVE_SUB) RemoveSubscriptionSID(in->sid, service); free_notify_struct(in); HandleUnlock(); }
int AdvertiseAndReply(int AdFlag, UpnpDevice_Handle Hnd, enum SsdpSearchType SearchType, struct sockaddr *DestAddr, char *DeviceType, char *DeviceUDN, char *ServiceType, int Exp) { int retVal = UPNP_E_SUCCESS; long unsigned int i; long unsigned int j; int defaultExp = DEFAULT_MAXAGE; struct Handle_Info *SInfo = NULL; char UDNstr[100]; char devType[100]; char servType[100]; IXML_NodeList *nodeList = NULL; IXML_NodeList *tmpNodeList = NULL; IXML_Node *tmpNode = NULL; IXML_Node *tmpNode2 = NULL; IXML_Node *textNode = NULL; const DOMString tmpStr; const DOMString dbgStr; int NumCopy = 0; memset(UDNstr, 0, sizeof(UDNstr)); memset(devType, 0, sizeof(devType)); memset(servType, 0, sizeof(servType)); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside AdvertiseAndReply with AdFlag = %d\n", AdFlag); /* Use a read lock */ HandleReadLock(); if (GetHandleInfo(Hnd, &SInfo) != HND_DEVICE) { retVal = UPNP_E_INVALID_HANDLE; goto end_function; } defaultExp = SInfo->MaxAge; /* parse the device list and send advertisements/replies */ while (NumCopy == 0 || (AdFlag && NumCopy < NUM_SSDP_COPY)) { if (NumCopy != 0) imillisleep(SSDP_PAUSE); NumCopy++; for (i = 0lu;; i++) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Entering new device list with i = %lu\n\n", i); tmpNode = ixmlNodeList_item(SInfo->DeviceList, i); if (!tmpNode) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting new device list with i = %lu\n\n", i); break; } dbgStr = ixmlNode_getNodeName(tmpNode); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Extracting device type once for %s\n", dbgStr); ixmlNodeList_free(nodeList); nodeList = ixmlElement_getElementsByTagName((IXML_Element *) tmpNode, "deviceType"); if (!nodeList) continue; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting UDN for %s\n", dbgStr); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting device type\n"); tmpNode2 = ixmlNodeList_item(nodeList, 0lu); if (!tmpNode2) continue; textNode = ixmlNode_getFirstChild(tmpNode2); if (!textNode) continue; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting device type \n"); tmpStr = ixmlNode_getNodeValue(textNode); if (!tmpStr) continue; strncpy(devType, tmpStr, sizeof(devType) - 1); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting device type = %s\n", devType); if (!tmpNode) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "TempNode is NULL\n"); } dbgStr = ixmlNode_getNodeName(tmpNode); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting UDN for %s\n", dbgStr); ixmlNodeList_free(nodeList); nodeList = ixmlElement_getElementsByTagName((IXML_Element *) tmpNode, "UDN"); if (!nodeList) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UDN not found!\n"); continue; } tmpNode2 = ixmlNodeList_item(nodeList, 0lu); if (!tmpNode2) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UDN not found!\n"); continue; } textNode = ixmlNode_getFirstChild(tmpNode2); if (!textNode) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UDN not found!\n"); continue; } tmpStr = ixmlNode_getNodeValue(textNode); if (!tmpStr) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UDN not found!\n"); continue; } strncpy(UDNstr, tmpStr, sizeof(UDNstr) - 1); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Sending UDNStr = %s \n", UDNstr); if (AdFlag) { /* send the device advertisement */ if (AdFlag == 1) { DeviceAdvertisement(devType, i == 0lu, NumCopy - 1, UDNstr, SInfo->DescURL, Exp, SInfo->DeviceAf, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else { /* AdFlag == -1 */ DeviceShutdown(devType, i == 0lu, NumCopy - 1, UDNstr, SInfo->DescURL, Exp, SInfo->DeviceAf, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } } else { switch (SearchType) { case SSDP_ALL: DeviceReply(DestAddr, devType, i == 0lu, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); break; case SSDP_ROOTDEVICE: if (i == 0lu) { SendReply(DestAddr, devType, 1, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, 0, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } break; case SSDP_DEVICEUDN: { if (DeviceUDN && strlen(DeviceUDN) != (size_t)0) { if (strcasecmp(DeviceUDN, UDNstr)) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceUDN=%s and search UDN=%s DID NOT match\n", UDNstr, DeviceUDN); break; } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceUDN=%s and search UDN=%s MATCH\n", UDNstr, DeviceUDN); SendReply(DestAddr, devType, 0, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, 0, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); break; } } } case SSDP_DEVICETYPE: { if (!strncasecmp(DeviceType, devType, strlen(DeviceType) - (size_t)2)) { if (atoi(strrchr(DeviceType, ':') + 1) < atoi(&devType[strlen(devType) - (size_t)1])) { /* the requested version is lower than the device version * must reply with the lower version number and the lower * description URL */ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceType=%s and search devType=%s MATCH\n", devType, DeviceType); SendReply(DestAddr, DeviceType, 0, NumCopy - 1, UDNstr, SInfo->LowerDescURL, defaultExp, 1, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else if (atoi(strrchr(DeviceType, ':') + 1) == atoi(&devType[strlen(devType) - (size_t)1])) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceType=%s and search devType=%s MATCH\n", devType, DeviceType); SendReply(DestAddr, DeviceType, 0, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, 1, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceType=%s and search devType=%s DID NOT MATCH\n", devType, DeviceType); } } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceType=%s and search devType=%s DID NOT MATCH\n", devType, DeviceType); } break; } default: break; } } /* send service advertisements for services corresponding * to the same device */ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Sending service Advertisement\n"); /* Correct service traversal such that each device's serviceList * is directly traversed as a child of its parent device. This * ensures that the service's alive message uses the UDN of * the parent device. */ tmpNode = ixmlNode_getFirstChild(tmpNode); while (tmpNode) { dbgStr = ixmlNode_getNodeName(tmpNode); if (!strncmp (dbgStr, SERVICELIST_STR, sizeof SERVICELIST_STR)) { break; } tmpNode = ixmlNode_getNextSibling(tmpNode); } ixmlNodeList_free(nodeList); if (!tmpNode) { nodeList = NULL; continue; } nodeList = ixmlElement_getElementsByTagName((IXML_Element *) tmpNode, "service"); if (!nodeList) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Service not found 3\n"); continue; } for (j = 0lu;; j++) { tmpNode = ixmlNodeList_item(nodeList, j); if (!tmpNode) { break; } ixmlNodeList_free(tmpNodeList); tmpNodeList = ixmlElement_getElementsByTagName((IXML_Element *) tmpNode, "serviceType"); if (!tmpNodeList) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "ServiceType not found \n"); continue; } tmpNode2 = ixmlNodeList_item(tmpNodeList, 0lu); if (!tmpNode2) continue; textNode = ixmlNode_getFirstChild(tmpNode2); if (!textNode) continue; /* servType is of format Servicetype:ServiceVersion */ tmpStr = ixmlNode_getNodeValue(textNode); if (!tmpStr) continue; strncpy(servType, tmpStr, sizeof(servType) - 1); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType = %s\n", servType); if (AdFlag) { if (AdFlag == 1) { ServiceAdvertisement(NumCopy - 1, UDNstr, servType, SInfo->DescURL, Exp, SInfo->DeviceAf, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else { /* AdFlag == -1 */ ServiceShutdown(NumCopy - 1, UDNstr, servType, SInfo->DescURL, Exp, SInfo->DeviceAf, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } } else { switch (SearchType) { case SSDP_ALL: ServiceReply(DestAddr, servType, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); break; case SSDP_SERVICE: if (ServiceType) { if (!strncasecmp(ServiceType, servType, strlen(ServiceType) - (size_t)2)) { if (atoi(strrchr(ServiceType, ':') + 1) < atoi(&servType[strlen(servType) - (size_t)1])) { /* the requested version is lower than the service version * must reply with the lower version number and the lower * description URL */ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType=%s and search servType=%s MATCH\n", ServiceType, servType); SendReply(DestAddr, ServiceType, 0, NumCopy - 1, UDNstr, SInfo->LowerDescURL, defaultExp, 1, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else if (atoi(strrchr (ServiceType, ':') + 1) == atoi(&servType[strlen(servType) - (size_t)1])) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType=%s and search servType=%s MATCH\n", ServiceType, servType); SendReply(DestAddr, ServiceType, 0, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, 1, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType=%s and search servType=%s DID NOT MATCH\n", ServiceType, servType); } } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType=%s and search servType=%s DID NOT MATCH\n", ServiceType, servType); } } break; default: break; } } } ixmlNodeList_free(tmpNodeList); tmpNodeList = NULL; ixmlNodeList_free(nodeList); nodeList = NULL; } } end_function: ixmlNodeList_free(tmpNodeList); ixmlNodeList_free(nodeList); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting AdvertiseAndReply.\n"); HandleUnlock(); return retVal; }