/** * Do an M-SEARCH to look for devices in the network. * * @param ctrlPoint The control point in question * @param target The Search Target parameter (ex. "ssdp:all") */ bool mupnp_controlpoint_search(mUpnpControlPoint *ctrlPoint, const char *target) { mUpnpSSDPRequest *ssdpReq; mUpnpSSDPResponseServerList *ssdpResServerList; int i = 0; bool retval = false; mupnp_log_debug_l4("Entering...\n"); ssdpReq = mupnp_ssdprequest_new(); mupnp_ssdprequest_setmethod(ssdpReq, MUPNP_HTTP_MSEARCH); mupnp_ssdprequest_setst(ssdpReq, target); mupnp_ssdprequest_setmx(ssdpReq, mupnp_controlpoint_getssdpsearchmx(ctrlPoint)); mupnp_ssdprequest_setman(ssdpReq, MUPNP_MAN_DISCOVER); mupnp_log_debug("Announcing %d times.\n", mupnp_ssdp_getannouncecount()); mupnp_ssdprequest_print(ssdpReq); for (i = 0; i < mupnp_ssdp_getannouncecount(); i++) { ssdpResServerList = mupnp_controlpoint_getssdpresponseserverlist(ctrlPoint); retval = ( mupnp_ssdpresponse_serverlist_post(ssdpResServerList, ssdpReq ) || retval ); mupnp_wait(MUPNP_CONTROLPOINT_SSDP_MIN_DELAY); } mupnp_ssdprequest_delete(ssdpReq); mupnp_log_debug_l4("Leaving...\n"); return retval; }
int mupnp_net_gethostinterfaces(mUpnpNetworkInterfaceList* netIfList) { mupnp_log_debug_l4("Entering...\n"); mUpnpNetworkInterface* netIf; FILE* fd; int s; char buffer[256 + 1]; char ifaddr[20 + 1]; char* ifname; char* sep; mupnp_net_interfacelist_clear(netIfList); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) return 0; fd = fopen(PATH_PROC_NET_DEV, "r"); fgets(buffer, sizeof(buffer) - 1, fd); fgets(buffer, sizeof(buffer) - 1, fd); while (!feof(fd)) { ifname = buffer; sep; if (fgets(buffer, sizeof(buffer) - 1, fd) == NULL) break; sep = strrchr(buffer, ':'); if (sep) *sep = 0; while (*ifname == ' ') ifname++; struct ifreq req; strcpy(req.ifr_name, ifname); if (ioctl(s, SIOCGIFFLAGS, &req) < 0) continue; if (!(req.ifr_flags & IFF_UP)) continue; if (req.ifr_flags & IFF_LOOPBACK) continue; if (ioctl(s, SIOCGIFADDR, &req) < 0) continue; strncpy(ifaddr, inet_ntoa(((struct sockaddr_in*)&req.ifr_addr)->sin_addr), sizeof(ifaddr) - 1); netIf = mupnp_net_interface_new(); mupnp_net_interface_setname(netIf, ifname); mupnp_net_interface_setaddress(netIf, ifaddr); mupnp_net_interfacelist_add(netIfList, netIf); mupnp_log_debug("Interface name: %s, address: %s\n", ifname, ifaddr); //cout << ifname << ", " << ifaddr << endl; } fclose(fd); close(s); return mupnp_net_interfacelist_size(netIfList); mupnp_log_debug_l4("Leaving...\n"); }
static int simple_string_hash(char *str, int table_size) { int sum=0; mupnp_log_debug_l4("Entering...\n"); if (str==NULL) return -1; mupnp_log_debug("Calculating hash from string |%s|, table size: %d\n", str, table_size); /* Sum up all the characters in the string */ for( ; *str; str++) sum += *str; mupnp_log_debug_l4("Leaving...\n"); return sum % table_size; }
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"); }
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"); }
int mupnp_net_gethostinterfaces(mUpnpNetworkInterfaceList* netIfList) { mUpnpNetworkInterface* netIf; struct ifaddrs* ifaddr; char addr[NI_MAXHOST + 1]; char netmask[NI_MAXHOST + 1]; char* ifname; struct ifaddrs* i; #if defined(HAVE_SOCKADDR_DL) struct sockaddr_dl* dladdr; #elif defined(HAVE_SIOCGIFHWADDR) int sock; struct ifreq ifr; #endif mupnp_log_debug_l4("Entering...\n"); mupnp_net_interfacelist_clear(netIfList); if (getifaddrs(&ifaddr) != 0) { mupnp_log_debug("No addresses for interfaces!\n"); return 0; } for (i = ifaddr; i != NULL; i = i->ifa_next) { // Thanks for Ricardo Rivldo (04/10/12) // - for some reason, vmware and virtualbox \"virtual\" interfaces does not return ifa_addr if (i->ifa_addr == NULL || i->ifa_netmask == NULL) continue; // Thanks for Tobias.Gansen (01/15/06) if (i->ifa_addr->sa_family != AF_INET) continue; if (!(i->ifa_flags & IFF_UP)) continue; if (i->ifa_flags & IFF_LOOPBACK) continue; if (getnameinfo(i->ifa_addr, sizeof(struct sockaddr), addr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) continue; if (getnameinfo(i->ifa_netmask, sizeof(struct sockaddr), netmask, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) continue; ifname = i->ifa_name; mupnp_log_debug("Interface name: %s, address: %s\n", ifname, addr); netIf = mupnp_net_interface_new(); mupnp_net_interface_setname(netIf, ifname); mupnp_net_interface_setaddress(netIf, addr); mupnp_net_interface_setnetmask(netIf, netmask); #if defined(HAVE_SOCKADDR_DL) dladdr = (struct sockaddr_dl*)(i->ifa_addr); mupnp_net_interface_setmacaddress(netIf, LLADDR(dladdr)); #elif defined(HAVE_SIOCGIFHWADDR) sock = socket(AF_INET, SOCK_DGRAM, 0); strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); ifr.ifr_addr.sa_family = AF_INET; ioctl(sock, SIOCGIFHWADDR, &ifr); mupnp_net_interface_setmacaddress(netIf, ifr.ifr_hwaddr.sa_data); close(sock); #endif mupnp_net_interfacelist_add(netIfList, netIf); } freeifaddrs(ifaddr); mupnp_log_debug_l4("Leaving...\n"); return mupnp_net_interfacelist_size(netIfList); }
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"); }