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;
	char SERVER[200];
	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;
	/* get server info */
	get_sdk_info(SERVER, sizeof(SERVER));
	/* 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;
			dbgStr = ixmlNode_getNodeName(tmpNode);
			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, 0);
			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 == 0,
							    UDNstr,
							    SInfo->DescURL, Exp,
							    SInfo->DeviceAf);
				} else {
					/* AdFlag == -1 */
					DeviceShutdown(devType, i == 0, UDNstr,
						       SERVER, SInfo->DescURL,
						       Exp, SInfo->DeviceAf);
				}
			} else {
				switch (SearchType) {
				case SSDP_ALL:
					{
					    DeviceReply(DestAddr, devType, i == 0,
						    UDNstr, SInfo->DescURL,
						    defaultExp);
                                   }
					break;
				case SSDP_ROOTDEVICE:
					if (i == 0) {
						    SendReply(DestAddr, devType, 1,
							  UDNstr,
							  SInfo->DescURL,
							  defaultExp, 0);
					}
					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, UDNstr, SInfo->DescURL, defaultExp, 0);
							break;
						}
					}
				}
				case SSDP_DEVICETYPE: {
					if (!strncasecmp(DeviceType, devType, strlen(DeviceType) - 2)) {
							if (atoi(strrchr(DeviceType, ':') + 1)
						    == atoi(&devType[strlen(devType) - 1])) {
							/* the requested version is lower than the device version
							 * must reply with the lower version number */
							UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
								   "DeviceType=%s and search devType=%s MATCH\n",
								   devType, DeviceType);
							SendReply(DestAddr, DeviceType, 0, UDNstr, SInfo->DescURL,
								  defaultExp, 1);
						} 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(UDNstr,
							servType, SInfo->DescURL,
							Exp, SInfo->DeviceAf);
						} else {
						/* AdFlag == -1 */
						ServiceShutdown(UDNstr,
							servType, SInfo->DescURL,
							Exp, SInfo->DeviceAf);
						}
					}
				} else {
					switch (SearchType) {
					case SSDP_ALL:
					    {
						    ServiceReply(DestAddr, servType,
							     UDNstr,
							     SInfo->DescURL,
							     defaultExp);
						}
						break;
					case SSDP_SERVICE:
						if (ServiceType) {
							if (!strncasecmp(ServiceType, servType, strlen(ServiceType) - 2)) {
							        if (atoi(strrchr(ServiceType, ':') + 1) ==
								    atoi(&servType[strlen(servType) - 1])) {
									/* the requested version is lower than the service version
									 * must reply with the lower version number */
									UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
										   "ServiceType=%s and search servType=%s MATCH\n",
										   ServiceType, servType);
									SendReply(DestAddr, ServiceType, 0, UDNstr, SInfo->DescURL,
										  defaultExp, 1);
								} 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;
}
/*!
 * \brief
 */
static int create_ssdp_sock_v4(
	/*! [] SSDP IPv4 socket to be created. */
	SOCKET *ssdpSock)
{
	char errorBuffer[ERROR_BUFFER_LEN];
	int onOff;
	u_char ttl = (u_char)4;
	struct ip_mreq ssdpMcastAddr;
	struct sockaddr_storage __ss;
	struct sockaddr_in *ssdpAddr4 = (struct sockaddr_in *)&__ss;
	int ret = 0;
	struct in_addr addr;

	*ssdpSock = socket(AF_INET, SOCK_DGRAM, 0);
	if (*ssdpSock == INVALID_SOCKET) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in socket(): %s\n", errorBuffer);

		return UPNP_E_OUTOF_SOCKET;
	}
	onOff = 1;
	ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEADDR,
			 (char *)&onOff, sizeof(onOff));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() SO_REUSEADDR: %s\n",
			   errorBuffer);
		ret = UPNP_E_SOCKET_ERROR;
		goto error_handler;
	}
#if defined(BSD) || defined(__OSX__) || defined(__APPLE__)
	onOff = 1;
	ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEPORT,
			 (char *)&onOff, sizeof(onOff));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() SO_REUSEPORT: %s\n",
			   errorBuffer);
		ret = UPNP_E_SOCKET_ERROR;
		goto error_handler;
	}
#endif /* BSD, __OSX__, __APPLE__ */
	memset(&__ss, 0, sizeof(__ss));
	ssdpAddr4->sin_family = (sa_family_t)AF_INET;
	ssdpAddr4->sin_addr.s_addr = htonl(INADDR_ANY);
	ssdpAddr4->sin_port = htons(SSDP_PORT);
	ret = bind(*ssdpSock, (struct sockaddr *)ssdpAddr4, sizeof(*ssdpAddr4));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in bind(), addr=0x%08X, port=%d: %s\n",
			   INADDR_ANY, SSDP_PORT, errorBuffer);
		ret = UPNP_E_SOCKET_BIND;
		goto error_handler;
	}
	memset((void *)&ssdpMcastAddr, 0, sizeof(struct ip_mreq));
	ssdpMcastAddr.imr_interface.s_addr = inet_addr(gIF_IPV4);
	ssdpMcastAddr.imr_multiaddr.s_addr = inet_addr(SSDP_IP);
	ret = setsockopt(*ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
			 (char *)&ssdpMcastAddr, sizeof(struct ip_mreq));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() IP_ADD_MEMBERSHIP (join multicast group): %s\n",
			   errorBuffer);
		ret = UPNP_E_SOCKET_ERROR;
		goto error_handler;
	}
	/* Set multicast interface. */
	memset((void *)&addr, 0, sizeof(struct in_addr));
	addr.s_addr = inet_addr(gIF_IPV4);
	ret = setsockopt(*ssdpSock, IPPROTO_IP, IP_MULTICAST_IF,
			 (char *)&addr, sizeof addr);
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() IP_MULTICAST_IF (set multicast interface): %s\n",
			   errorBuffer);
		/* This is probably not a critical error, so let's continue. */
	}
	/* result is not checked becuase it will fail in WinMe and Win9x. */
	ret = setsockopt(*ssdpSock, IPPROTO_IP,
			 IP_MULTICAST_TTL, &ttl, sizeof(ttl));
	onOff = 1;
	ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_BROADCAST,
			 (char *)&onOff, sizeof(onOff));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() SO_BROADCAST (set broadcast): %s\n",
			   errorBuffer);
		ret = UPNP_E_NETWORK_ERROR;
		goto error_handler;
	}
	ret = UPNP_E_SUCCESS;

error_handler:
	if (ret != UPNP_E_SUCCESS) {
		if (shutdown(*ssdpSock, SD_BOTH) == -1) {
			strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
			UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
				   "Error in shutdown: %s\n", errorBuffer);
		}
		UpnpCloseSocket(*ssdpSock);
	}

	return ret;
}
/*!
 * \brief This function ...
 */
static int create_ssdp_sock_v6(
	/* [] SSDP IPv6 socket to be created. */
	SOCKET *ssdpSock)
{
	char errorBuffer[ERROR_BUFFER_LEN];
	struct ipv6_mreq ssdpMcastAddr;
	struct sockaddr_storage __ss;
	struct sockaddr_in6 *ssdpAddr6 = (struct sockaddr_in6 *)&__ss;
	int onOff;
	int ret = 0;

	*ssdpSock = socket(AF_INET6, SOCK_DGRAM, 0);
	if (*ssdpSock == INVALID_SOCKET) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in socket(): %s\n", errorBuffer);

		return UPNP_E_OUTOF_SOCKET;
	}
	onOff = 1;
	ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEADDR,
			 (char *)&onOff, sizeof(onOff));
	ret += setsockopt(*ssdpSock, IPPROTO_IPV6, IPV6_V6ONLY,
			 (char *)&onOff, sizeof(onOff));
	if (ret < 0) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() SO_REUSEADDR: %s\n",
			   errorBuffer);
		ret = UPNP_E_SOCKET_ERROR;
		goto error_handler;
	}
#if defined(BSD) || defined(__OSX__) || defined(__APPLE__)
	onOff = 1;
	ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEPORT,
			 (char *)&onOff, sizeof(onOff));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() SO_REUSEPORT: %s\n",
			   errorBuffer);
		ret = UPNP_E_SOCKET_ERROR;
		goto error_handler;
	}
#endif /* BSD, __OSX__, __APPLE__ */
	onOff = 1;
	ret = setsockopt(*ssdpSock, IPPROTO_IPV6, IPV6_V6ONLY,
			 (char *)&onOff, sizeof(onOff));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() IPV6_V6ONLY: %s\n",
			   errorBuffer);
		ret = UPNP_E_SOCKET_ERROR;
		goto error_handler;
	}
	memset(&__ss, 0, sizeof(__ss));
	ssdpAddr6->sin6_family = (sa_family_t)AF_INET6;
	ssdpAddr6->sin6_addr = in6addr_any;
	ssdpAddr6->sin6_scope_id = gIF_INDEX;
	ssdpAddr6->sin6_port = htons(SSDP_PORT);
	ret = bind(*ssdpSock, (struct sockaddr *)ssdpAddr6, sizeof(*ssdpAddr6));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in bind(), addr=0x%032lX, port=%d: %s\n",
			   0lu, SSDP_PORT, errorBuffer);
		ret = UPNP_E_SOCKET_BIND;
		goto error_handler;
	}
	memset((void *)&ssdpMcastAddr, 0, sizeof(ssdpMcastAddr));
	ssdpMcastAddr.ipv6mr_interface = gIF_INDEX;
	inet_pton(AF_INET6, SSDP_IPV6_LINKLOCAL,
		  &ssdpMcastAddr.ipv6mr_multiaddr);
	ret = setsockopt(*ssdpSock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
			(char *)&ssdpMcastAddr, sizeof(ssdpMcastAddr));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() IPV6_JOIN_GROUP (join multicast group): %s\n",
			   errorBuffer);
		ret = UPNP_E_SOCKET_ERROR;
		goto error_handler;
	}
	onOff = 1;
	ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_BROADCAST,
			 (char *)&onOff, sizeof(onOff));
	if (ret == -1) {
		strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
		UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
			   "Error in setsockopt() SO_BROADCAST (set broadcast): %s\n",
			   errorBuffer);
		ret = UPNP_E_NETWORK_ERROR;
		goto error_handler;
	}
	ret = UPNP_E_SUCCESS;

error_handler:
	if (ret != UPNP_E_SUCCESS) {
		if (shutdown(*ssdpSock, SD_BOTH) == -1) {
			strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
			UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
				   "Error in shutdown: %s\n", errorBuffer);
		}
		UpnpCloseSocket(*ssdpSock);
	}

	return ret;
}
Exemple #4
0
/************************************************************************
* Function : ssdp_handle_device_request									
*																	
* Parameters:														
*		IN http_message_t* hmsg: SSDP search request from the control point
*		IN struct sockaddr_in* dest_addr: The address info of control point
*
* Description:														
*	This function handles the search request. It do the sanity checks of
*	the request and then schedules a thread to send a random time reply (
*	random within maximum time given by the control point to reply).
*
* Returns: void *
*	1 if successful else appropriate error
***************************************************************************/
void
ssdp_handle_device_request( IN http_message_t * hmsg,
                            IN struct sockaddr_in *dest_addr )
{
#define MX_FUDGE_FACTOR 10

    int handle;
    struct Handle_Info *dev_info = NULL;
    memptr hdr_value;
    int mx;
    char save_char;
    SsdpEvent event;
    int ret_code;
    SsdpSearchReply *threadArg = NULL;
    ThreadPoolJob job;
    int replyTime;
    int maxAge;

    // check man hdr
    if( httpmsg_find_hdr( hmsg, HDR_MAN, &hdr_value ) == NULL ||
        memptr_cmp( &hdr_value, "\"ssdp:discover\"" ) != 0 ) {
        return;                 // bad or missing hdr
    }
    // MX header
    if( httpmsg_find_hdr( hmsg, HDR_MX, &hdr_value ) == NULL ||
        ( mx = raw_to_int( &hdr_value, 10 ) ) < 0 ) {
        return;
    }
    // ST header
    if( httpmsg_find_hdr( hmsg, HDR_ST, &hdr_value ) == NULL ) {
        return;
    }
    save_char = hdr_value.buf[hdr_value.length];
    hdr_value.buf[hdr_value.length] = '\0';
    ret_code = ssdp_request_type( hdr_value.buf, &event );
    hdr_value.buf[hdr_value.length] = save_char;    // restore
    if( ret_code == -1 ) {
        return;                 // bad ST header
    }

    HandleLock(  );
    // device info
    if( GetDeviceHandleInfo( &handle, &dev_info ) != HND_DEVICE ) {
        HandleUnlock(  );
        return;                 // no info found
    }
    maxAge = dev_info->MaxAge;
    HandleUnlock(  );

    DBGONLY( UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "ssdp_handle_device_request with Cmd %d SEARCH\n",
                         event.Cmd );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "MAX-AGE     =  %d\n", maxAge );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "MX     =  %d\n", event.Mx );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "DeviceType   =  %s\n", event.DeviceType );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "DeviceUuid   =  %s\n", event.UDN );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "ServiceType =  %s\n", event.ServiceType ); )
void readFromSSDPSocket(SOCKET socket)
{
	char *requestBuf = NULL;
	char staticBuf[BUFSIZE];
	struct sockaddr_storage __ss;
	ThreadPoolJob job;
	ssdp_thread_data *data = NULL;
	socklen_t socklen = sizeof(__ss);
	ssize_t byteReceived = 0;
	char ntop_buf[INET6_ADDRSTRLEN];

	memset(&job, 0, sizeof(job));

	requestBuf = staticBuf;
	/* in case memory can't be allocated, still drain the socket using a
	 * static buffer. */
	data = malloc(sizeof(ssdp_thread_data));
	if (data) {
		/* initialize parser */
#ifdef INCLUDE_CLIENT_APIS
		if (socket == gSsdpReqSocket4
	#ifdef UPNP_ENABLE_IPV6
		    || socket == gSsdpReqSocket6
	#endif /* UPNP_ENABLE_IPV6 */
		    )
			parser_response_init(&data->parser, HTTPMETHOD_MSEARCH);
		else
			parser_request_init(&data->parser);
#else /* INCLUDE_CLIENT_APIS */
		parser_request_init(&data->parser);
#endif /* INCLUDE_CLIENT_APIS */
		/* set size of parser buffer */
		if (membuffer_set_size(&data->parser.msg.msg, BUFSIZE) == 0)
			/* use this as the buffer for recv */
			requestBuf = data->parser.msg.msg.buf;
		else {
			free(data);
			data = NULL;
		}
	}
	byteReceived = recvfrom(socket, requestBuf, BUFSIZE - (size_t)1, 0,
				(struct sockaddr *)&__ss, &socklen);
	if (byteReceived > 0) {
		requestBuf[byteReceived] = '\0';
		switch (__ss.ss_family) {
		case AF_INET:
			inet_ntop(AF_INET,
				  &((struct sockaddr_in *)&__ss)->sin_addr,
				  ntop_buf, sizeof(ntop_buf));
			break;
#ifdef UPNP_ENABLE_IPV6
		case AF_INET6:
			inet_ntop(AF_INET6,
				  &((struct sockaddr_in6 *)&__ss)->sin6_addr,
				  ntop_buf, sizeof(ntop_buf));
			break;
#endif /* UPNP_ENABLE_IPV6 */
		default:
			memset(ntop_buf, 0, sizeof(ntop_buf));
			strncpy(ntop_buf, "<Invalid address family>",
				sizeof(ntop_buf) - 1);
		}
		UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
			   "Start of received response ----------------------------------------------------\n"
			   "%s\n"
			   "End of received response ------------------------------------------------------\n"
			   "From host %s\n", requestBuf, ntop_buf);
		/* add thread pool job to handle request */
		if (data != NULL) {
			data->parser.msg.msg.length += (size_t) byteReceived;
			/* null-terminate */
			data->parser.msg.msg.buf[byteReceived] = 0;
			memcpy(&data->dest_addr, &__ss, sizeof(__ss));
			TPJobInit(&job, (start_routine)
				  ssdp_event_handler_thread, data);
			TPJobSetFreeFunction(&job,
					     free_ssdp_event_handler_data);
			TPJobSetPriority(&job, MED_PRIORITY);
			if (ThreadPoolAdd(&gRecvThreadPool, &job, NULL) != 0)
				free_ssdp_event_handler_data(data);
		}
	} else
		free_ssdp_event_handler_data(data);
}
int genaSubscribe(
	UpnpClient_Handle client_handle,
	const UpnpString *PublisherURL,
	int *TimeOut,
	UpnpString *out_sid)
{
	int return_code = GENA_SUCCESS;
	ClientSubscription *newSubscription = UpnpClientSubscription_new();
	uuid_upnp uid;
	Upnp_SID temp_sid;
	Upnp_SID temp_sid2;
	UpnpString *ActualSID = UpnpString_new();
	UpnpString *EventURL = UpnpString_new();
	struct Handle_Info *handle_info;
	int rc = 0;

	memset(temp_sid, 0, sizeof(temp_sid));
	memset(temp_sid2, 0, sizeof(temp_sid2));

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUBSCRIBE BEGIN");

	UpnpString_clear(out_sid);

	HandleReadLock();
	/* validate handle */
	if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
		return_code = GENA_E_BAD_HANDLE;
		SubscribeLock();
		goto error_handler;
	}
	HandleUnlock();

	/* subscribe */
	SubscribeLock();
	return_code = gena_subscribe(PublisherURL, TimeOut, NULL, ActualSID);
	HandleLock();
	if (return_code != UPNP_E_SUCCESS) {
		UpnpPrintf( UPNP_CRITICAL, GENA, __FILE__, __LINE__,
			"SUBSCRIBE FAILED in transfer error code: %d returned\n",
			return_code );
		goto error_handler;
	}

	if(GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
		return_code = GENA_E_BAD_HANDLE;
		goto error_handler;
	}

	/* generate client SID */
	uuid_create(&uid );
	uuid_unpack(&uid, temp_sid);
	rc = snprintf(temp_sid2, sizeof(temp_sid2), "uuid:%s", temp_sid);
	if (rc < 0 || (unsigned int) rc >= sizeof(temp_sid2)) {
		return_code = UPNP_E_OUTOF_MEMORY;
		goto error_handler;
	}
	UpnpString_set_String(out_sid, temp_sid2);

	/* create event url */
	UpnpString_assign(EventURL, PublisherURL);

	/* fill subscription */
	if (newSubscription == NULL) {
		return_code = UPNP_E_OUTOF_MEMORY;
		goto error_handler;
	}
	UpnpClientSubscription_set_RenewEventId(newSubscription, -1);
	UpnpClientSubscription_set_SID(newSubscription, out_sid);
	UpnpClientSubscription_set_ActualSID(newSubscription, ActualSID);
	UpnpClientSubscription_set_EventURL(newSubscription, EventURL);
	UpnpClientSubscription_set_Next(newSubscription, handle_info->ClientSubList);
	handle_info->ClientSubList = newSubscription;

	/* schedule expiration event */
	return_code = ScheduleGenaAutoRenew(client_handle, *TimeOut, newSubscription);

error_handler:
		UpnpString_delete(ActualSID);
		UpnpString_delete(EventURL);
	if (return_code != UPNP_E_SUCCESS)
		UpnpClientSubscription_delete(newSubscription);
	HandleUnlock();
	SubscribeUnlock();

	return return_code;
}
int genaRenewSubscription(
	UpnpClient_Handle client_handle,
	const UpnpString *in_sid,
	int *TimeOut)
{
	int return_code = GENA_SUCCESS;
	ClientSubscription *sub = NULL;
	ClientSubscription *sub_copy = UpnpClientSubscription_new();
	struct Handle_Info *handle_info;
	UpnpString *ActualSID = UpnpString_new();
	ThreadPoolJob tempJob;

	HandleLock();

	/* validate handle and sid */
	if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
		HandleUnlock();

		return_code = GENA_E_BAD_HANDLE;
		goto exit_function;
	}

	sub = GetClientSubClientSID(handle_info->ClientSubList, in_sid);
	if (sub == NULL) {
		HandleUnlock();

		return_code = GENA_E_BAD_SID;
		goto exit_function;
	}

	/* remove old events */
	if (TimerThreadRemove(
		&gTimerThread,
		UpnpClientSubscription_get_RenewEventId(sub),
		&tempJob) == 0 ) {
		free_upnp_timeout((upnp_timeout *)tempJob.arg);
	}

	UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "REMOVED AUTO RENEW  EVENT");

	UpnpClientSubscription_set_RenewEventId(sub, -1);
	UpnpClientSubscription_assign(sub_copy, sub);

	HandleUnlock();

	return_code = gena_subscribe(
		UpnpClientSubscription_get_EventURL(sub_copy),
		TimeOut,
		UpnpClientSubscription_get_ActualSID(sub_copy),
		ActualSID);

	HandleLock();

	if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
		HandleUnlock();
		return_code = GENA_E_BAD_HANDLE;
		goto exit_function;
	}

	/* we just called GetHandleInfo, so we don't check for return value */
	/*GetHandleInfo(client_handle, &handle_info); */
	if (return_code != UPNP_E_SUCCESS) {
		/* network failure (remove client sub) */
		RemoveClientSubClientSID(&handle_info->ClientSubList, in_sid);
		free_client_subscription(sub_copy);
		HandleUnlock();
		goto exit_function;
	}

	/* get subscription */
	sub = GetClientSubClientSID(handle_info->ClientSubList, in_sid);
	if (sub == NULL) {
		free_client_subscription(sub_copy);
		HandleUnlock();
		return_code = GENA_E_BAD_SID;
		goto exit_function;
	}

	/* store actual sid */
	UpnpClientSubscription_set_ActualSID(sub, ActualSID);

	/* start renew subscription timer */
	return_code = ScheduleGenaAutoRenew(client_handle, *TimeOut, sub);
	if (return_code != GENA_SUCCESS) {
		RemoveClientSubClientSID(
			&handle_info->ClientSubList,
			UpnpClientSubscription_get_SID(sub));
	}
	free_client_subscription(sub_copy);
	HandleUnlock();

exit_function:
	UpnpString_delete(ActualSID);
	UpnpClientSubscription_delete(sub_copy);
	return return_code;
}
Exemple #8
0
/****************************************************************************
*	Function :	handle_query_variable
*
*	Parameters :
*		IN SOCKINFO *info :	Socket info
*		IN http_message_t* request : HTTP request
*		IN IXML_Document *xml_doc :	Document containing the variable request
*									SOAP message
*
*	Description :	This action handles the SOAP requests to querry the
*				state variables. This functionality has been deprecated in
*				the UPnP V1.0 architecture
*
*	Return :	void
*
*	Note :
****************************************************************************/
static UPNP_INLINE void
handle_query_variable( IN SOCKINFO * info,
                       IN http_message_t * request,
                       IN IXML_Document * xml_doc )
{
    Upnp_FunPtr soap_event_callback;
    void *cookie;
    char var_name[LINE_SIZE];
    struct Upnp_State_Var_Request variable;
    const char *err_str;
    int err_code;

    // get var name
    if( get_var_name( xml_doc, var_name ) != 0 ) {
        send_error_response( info, SOAP_INVALID_VAR,
                             Soap_Invalid_Var, request );
        return;
    }
    // get info for event
    if( get_device_info( request, 1, xml_doc, variable.DevUDN,
                         variable.ServiceID,
                         &soap_event_callback, &cookie ) != 0 ) {
        send_error_response( info, SOAP_INVALID_VAR,
                             Soap_Invalid_Var, request );
        return;
    }

    linecopy( variable.ErrStr, "" );
    variable.ErrCode = UPNP_E_SUCCESS;
    namecopy( variable.StateVarName, var_name );
    variable.CurrentVal = NULL;
    variable.CtrlPtIPAddr = info->foreign_ip_addr;

    // send event
    soap_event_callback( UPNP_CONTROL_GET_VAR_REQUEST, &variable, cookie );

    UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
                "Return from callback for var request\n" );

    // validate, and handle result
    if( variable.CurrentVal == NULL ) {
        err_code = SOAP_ACTION_FAILED;
        err_str = Soap_Action_Failed;
        send_error_response( info, SOAP_INVALID_VAR,
                             Soap_Invalid_Var, request );
        return;
    }
    if( variable.ErrCode != UPNP_E_SUCCESS ) {
        if( strlen( variable.ErrStr ) > 0 ) {
            err_code = SOAP_INVALID_VAR;
            err_str = Soap_Invalid_Var;
        } else {
            err_code = variable.ErrCode;
            err_str = variable.ErrStr;
        }
        send_error_response( info, err_code, err_str, request );
        return;
    }
    // send response
    send_var_query_response( info, variable.CurrentVal, request );
    ixmlFreeDOMString( variable.CurrentVal );

}
Exemple #9
0
/****************************************************************************
*	Function :	handle_invoke_action
*
*	Parameters :
*		IN SOCKINFO *info :	Socket info
*		IN http_message_t* request : HTTP Request
*		IN memptr action_name :	 Name of the SOAP Action
*		IN IXML_Document *xml_doc :	document containing the SOAP action
*									request
*
*	Description :	This functions handle the SOAP action request. It checks
*		the integrity of the SOAP action request and gives the call back to
*		the device application.
*
*	Return : void
*
*	Note :
****************************************************************************/
static void
handle_invoke_action( IN SOCKINFO * info,
                      IN http_message_t * request,
                      IN memptr action_name,
                      IN IXML_Document * xml_doc )
{
    char save_char;
    IXML_Document *resp_node = NULL;
    struct Upnp_Action_Request action;
    Upnp_FunPtr soap_event_callback;
    void *cookie = NULL;
    int err_code;
    const char *err_str;

    action.ActionResult = NULL;

    // null-terminate
    save_char = action_name.buf[action_name.length];
    action_name.buf[action_name.length] = '\0';

    // set default error
    err_code = SOAP_INVALID_ACTION;
    err_str = Soap_Invalid_Action;

    // get action node
    if( get_action_node( xml_doc, action_name.buf, &resp_node ) == -1 ) {
        goto error_handler;
    }
    // get device info for action event
    err_code = get_device_info( request, 0, xml_doc, action.DevUDN,
                                action.ServiceID, &soap_event_callback,
                                &cookie );

    if( err_code != UPNP_E_SUCCESS ) {
        goto error_handler;
    }

    namecopy( action.ActionName, action_name.buf );
    linecopy( action.ErrStr, "" );
    action.ActionRequest = resp_node;
    action.ActionResult = NULL;
    action.ErrCode = UPNP_E_SUCCESS;
    action.CtrlPtIPAddr = info->foreign_ip_addr;

    UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
                "Calling Callback\n" );

    soap_event_callback( UPNP_CONTROL_ACTION_REQUEST, &action, cookie );

    if( action.ErrCode != UPNP_E_SUCCESS ) {
        if( strlen( action.ErrStr ) <= 0 ) {
            err_code = SOAP_ACTION_FAILED;
            err_str = Soap_Action_Failed;
        } else {
            err_code = action.ErrCode;
            err_str = action.ErrStr;
        }
        goto error_handler;
    }
    // validate, and handle action error
    if( action.ActionResult == NULL ) {
        err_code = SOAP_ACTION_FAILED;
        err_str = Soap_Action_Failed;
        goto error_handler;
    }
    // send response
    send_action_response( info, action.ActionResult, request );

    err_code = 0;

    // error handling and cleanup
error_handler:
    ixmlDocument_free( action.ActionResult );
    ixmlDocument_free( resp_node );
    action_name.buf[action_name.length] = save_char;    // restore
    if( err_code != 0 ) {
        send_error_response( info, err_code, err_str, request );
    }
}
Exemple #10
0
/****************************************************************************
*	Function :	send_action_response
*
*	Parameters :
*		IN SOCKINFO *info :	socket info
*		IN IXML_Document *action_resp : The response document
*		IN http_message_t* request :	action request document
*
*	Description :	This function sends the SOAP response
*
*	Return : void
*
*	Note :
****************************************************************************/
static UPNP_INLINE void
send_action_response( IN SOCKINFO * info,
                      IN IXML_Document * action_resp,
                      IN http_message_t * request )
{
    char *xml_response = NULL;
    membuffer headers;
    int major,
        minor;
    int err_code;
    off_t content_length;
    int ret_code;
    int timeout_secs = SOAP_TIMEOUT;
    static char *start_body =
//        "<?xml version=\"1.0\"?>" required??
        "<s:Envelope xmlns:s=\"http://schemas.xmlsoap."
        "org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap."
        "org/soap/encoding/\"><s:Body>\n";
    static char *end_body = "</s:Body> </s:Envelope>";

    // init
    http_CalcResponseVersion( request->major_version,
                              request->minor_version, &major, &minor );
    membuffer_init( &headers );
    err_code = UPNP_E_OUTOF_MEMORY; // one error only

    // get xml
    xml_response = ixmlPrintNode( ( IXML_Node * ) action_resp );
    if( xml_response == NULL ) {
        goto error_handler;
    }

    content_length =
        strlen( start_body ) +
        strlen( xml_response ) +
        strlen( end_body );

    // make headers
    if (http_MakeMessage(
                &headers, major, minor,
                "RNsDsSXcc",
                HTTP_OK,   // status code
                content_length,
                ContentTypeHeader,
                "EXT:\r\n",
                X_USER_AGENT) != 0 ) {
        goto error_handler;
    }

    // send whole msg
    ret_code = http_SendMessage( info, &timeout_secs, "bbbb",
                                 headers.buf, headers.length,
                                 start_body, strlen( start_body ),
                                 xml_response, strlen( xml_response ),
                                 end_body, strlen( end_body ) );

    if( ret_code != 0 ) {
        UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
                    "Failed to send response: err code = %d\n",
                    ret_code );
    }

    err_code = 0;

error_handler:
    ixmlFreeDOMString( xml_response );
    membuffer_destroy( &headers );
    if( err_code != 0 ) {
        // only one type of error to worry about - out of mem
        send_error_response( info, SOAP_ACTION_FAILED, "Out of memory",
                             request );
    }
}
Exemple #11
0
/****************************************************************************
*	Function :	get_action_node
*
*	Parameters :
*		IN IXML_Document *TempDoc :	The root DOM node.
*		IN char *NodeName :	IXML_Node name to be searched.
*		OUT IXML_Document ** RespNode :	Response/Output node.
*
*	Description :	This function separates the action node from
*	the root DOM node.
*
*	Return :	static UPNP_INLINE int
*		0 if successful, or -1 if fails.
*
*	Note :
****************************************************************************/
static UPNP_INLINE int
get_action_node( IN IXML_Document * TempDoc,
                 IN char *NodeName,
                 OUT IXML_Document ** RespNode )
{
    IXML_Node *EnvpNode = NULL;
    IXML_Node *BodyNode = NULL;
    IXML_Node *ActNode = NULL;
    DOMString ActNodeName = NULL;
    const DOMString nodeName;
    int ret_code = -1;          // error, by default
    IXML_NodeList *nl = NULL;

    UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
                "get_action_node(): node name =%s\n ", NodeName );

    *RespNode = NULL;

    // Got the Envelope node here
    EnvpNode = ixmlNode_getFirstChild( ( IXML_Node * ) TempDoc );
    if( EnvpNode == NULL ) {
        goto error_handler;
    }

    nl = ixmlElement_getElementsByTagNameNS( ( IXML_Element * ) EnvpNode,
            "*", "Body" );

    if( nl == NULL ) {
        goto error_handler;
    }

    BodyNode = ixmlNodeList_item( nl, 0 );

    if( BodyNode == NULL ) {
        goto error_handler;
    }
    // Got action node here
    ActNode = ixmlNode_getFirstChild( BodyNode );
    if( ActNode == NULL ) {
        goto error_handler;
    }
    //Test whether this is the action node
    nodeName = ixmlNode_getNodeName( ActNode );
    if( nodeName == NULL ) {
        goto error_handler;
    }

    if( strstr( nodeName, NodeName ) == NULL ) {
        goto error_handler;
    } else {
        ActNodeName = ixmlPrintNode( ActNode );
        if( ActNodeName == NULL ) {
            goto error_handler;
        }

        ret_code = ixmlParseBufferEx( ActNodeName, RespNode );
        if( ret_code != IXML_SUCCESS ) {
            ixmlFreeDOMString( ActNodeName );
            ret_code = -1;
            goto error_handler;
        }
    }

    ret_code = 0;               // success

error_handler:

    ixmlFreeDOMString( ActNodeName );

    if( nl )
        ixmlNodeList_free( nl );
    return ret_code;
}
Exemple #12
0
/************************************************************************
*	Function :	getServiceList
*
*	Parameters :
*		IXML_Node *node ;	XML node information
*		service_info **end ; service added is returned to the output
*							parameter
*		char * URLBase ;	provides Base URL to resolve relative URL 
*
*	Description :	Returns pointer to service info after getting the 
*		sub-elements of the service info. 
*
*	Return : service_info * - pointer to the service info node ;
*
*	Note :
************************************************************************/
service_info *getServiceList(
	IXML_Node *node,
	service_info **end,
	char *URLBase)
{
	IXML_Node *serviceList = NULL;
	IXML_Node *current_service = NULL;
	IXML_Node *UDN = NULL;

	IXML_Node *serviceType = NULL;
	IXML_Node *serviceId = NULL;
	IXML_Node *SCPDURL = NULL;
	IXML_Node *controlURL = NULL;
	IXML_Node *eventURL = NULL;
	DOMString tempDOMString = NULL;
	service_info *head = NULL;
	service_info *current = NULL;
	service_info *previous = NULL;
	IXML_NodeList *serviceNodeList = NULL;
	long unsigned int NumOfServices = 0lu;
	long unsigned int i = 0lu;
	int fail = 0;

	if (getSubElement("UDN", node, &UDN) &&
	    getSubElement("serviceList", node, &serviceList)) {
		serviceNodeList = ixmlElement_getElementsByTagName(
			(IXML_Element *)serviceList, "service");
		if (serviceNodeList != NULL) {
			NumOfServices = ixmlNodeList_length(serviceNodeList);
			for (i = 0lu; i < NumOfServices; i++) {
				current_service =
				    ixmlNodeList_item(serviceNodeList, i);
				fail = 0;
				if (current) {
					current->next = malloc(sizeof(service_info));
					previous = current;
					current = current->next;
				} else {
					head = malloc(sizeof(service_info));
					current = head;
				}
				if (!current) {
					freeServiceList(head);
					ixmlNodeList_free(serviceNodeList);
					return NULL;
				}
				current->next = NULL;
				current->controlURL = NULL;
				current->eventURL = NULL;
				current->serviceType = NULL;
				current->serviceId = NULL;
				current->SCPDURL = NULL;
				current->active = 1;
				current->subscriptionList = NULL;
				current->TotalSubscriptions = 0;
				if (!(current->UDN = getElementValue(UDN)))
					fail = 1;
				if (!getSubElement("serviceType", current_service, &serviceType) ||
				    !(current->serviceType = getElementValue(serviceType)))
					fail = 1;
				if (!getSubElement("serviceId", current_service, &serviceId) ||
				    !(current->serviceId = getElementValue(serviceId)))
					fail = 1;
				if (!getSubElement("SCPDURL", current_service, &SCPDURL) ||
				    !(tempDOMString = getElementValue(SCPDURL)) ||
				    !(current->SCPDURL = resolve_rel_url(URLBase, tempDOMString)))
					fail = 1;
				ixmlFreeDOMString(tempDOMString);
				tempDOMString = NULL;
				if (!(getSubElement("controlURL", current_service, &controlURL)) ||
				    !(tempDOMString = getElementValue(controlURL)) ||
				    !(current->controlURL = resolve_rel_url(URLBase, tempDOMString))) {
					UpnpPrintf(UPNP_INFO, GENA, __FILE__,
						   __LINE__,
						   "BAD OR MISSING CONTROL URL");
					UpnpPrintf(UPNP_INFO, GENA, __FILE__,
						   __LINE__,
						   "CONTROL URL SET TO NULL IN SERVICE INFO");
					current->controlURL = NULL;
					fail = 0;
				}
				ixmlFreeDOMString(tempDOMString);
				tempDOMString = NULL;
				if (!getSubElement("eventSubURL", current_service, &eventURL) ||
				    !(tempDOMString = getElementValue(eventURL)) ||
				    !(current->eventURL = resolve_rel_url(URLBase, tempDOMString))) {
					UpnpPrintf(UPNP_INFO, GENA, __FILE__,
						   __LINE__,
						   "BAD OR MISSING EVENT URL");
					UpnpPrintf(UPNP_INFO, GENA, __FILE__,
						   __LINE__,
						   "EVENT URL SET TO NULL IN SERVICE INFO");
					current->eventURL = NULL;
					fail = 0;
				}
				ixmlFreeDOMString(tempDOMString);
				tempDOMString = NULL;
				if (fail) {
					freeServiceList(current);
					if (previous)
						previous->next = NULL;
					else
						head = NULL;
					current = previous;
				}
			}
			ixmlNodeList_free(serviceNodeList);
		}
		(*end) = current;
		return head;
	} else {
		(*end) = NULL;
		return NULL;
	}
}
Exemple #13
0
/****************************************************************************
*	Function :	handle_invoke_action
*
*	Parameters :
*		IN SOCKINFO *info :	Socket info
*		IN http_message_t* request : HTTP Request	
*		IN memptr action_name :	 Name of the SOAP Action
*		IN IXML_Document *xml_doc :	document containing the SOAP action 
*									request
*
*	Description :	This functions handle the SOAP action request. It checks 
*		the integrity of the SOAP action request and gives the call back to 
*		the device application.
*
*	Return : void
*
*	Note :
****************************************************************************/
static void
handle_invoke_action( IN SOCKINFO * info,
                      IN http_message_t * request,
                      IN memptr action_name,
                      IN IXML_Document * xml_doc )
{
    char save_char;
    IXML_Document *resp_node = NULL;
    struct Upnp_Action_Request action;
    Upnp_FunPtr soap_event_callback;
    void *cookie = NULL;
    int err_code;
    const char *err_str;

    action.ActionResult = NULL;

    // null-terminate
    save_char = action_name.buf[action_name.length];
    action_name.buf[action_name.length] = '\0';

    // set default error
    err_code = SOAP_INVALID_ACTION;
    err_str = Soap_Invalid_Action;

    // get action node
    if( get_action_node( xml_doc, action_name.buf, &resp_node ) == -1 ) {
        goto error_handler;
    }
    // get device info for action event
    err_code = get_device_info( request, 0, xml_doc, action.DevUDN,
                                action.ServiceID, &soap_event_callback,
                                &cookie );

    if( err_code != UPNP_E_SUCCESS ) {
        goto error_handler;
    }

	/* for user agent probe support! by HouXB, 22Oct10 */
	ListNode *node;
	http_header_t *header;

	node = ListHead(&request->headers);
	while( node != NULL ) 
	{
		header = ( http_header_t * ) node->item;
		if (!strncmp(USER_AGENT, header->name.buf, strlen(USER_AGENT)))
		{
			int aLen = (int)header->value.length;
			sprintf(action.UserAgent, "%.*s", aLen, header->value.buf );

			if(aLen <NAME_SIZE)
			{
				action.UserAgent[aLen] = '\0';
			}
			else
			{
				action.UserAgent[NAME_SIZE-1] = '\0';
			}
			/*  
			printf("\n####\nuser Agent found!\nallow len is:%d\nlen is: %d\nagent is:%s\n####\n", 
				NAME_SIZE, aLen, action.UserAgent);
			*/
			
			break;			
		}			
		node = ListNext( &request->headers , node );
	} 	
	/*end  for user agent probe support! by HouXB, 22Oct10 */
	
    namecopy( action.ActionName, action_name.buf );
    linecopy( action.ErrStr, "" );
    action.ActionRequest = resp_node;
    action.ActionResult = NULL;
    action.ErrCode = UPNP_E_SUCCESS;
    action.CtrlPtIPAddr = info->foreign_ip_addr;

    UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
                         "Calling Callback\n" );

    soap_event_callback( UPNP_CONTROL_ACTION_REQUEST, &action, cookie );

    if( action.ErrCode != UPNP_E_SUCCESS ) {
        if( strlen( action.ErrStr ) <= 0 ) {
            err_code = SOAP_ACTION_FAILED;
            err_str = Soap_Action_Failed;
        } else {
            err_code = action.ErrCode;
            err_str = action.ErrStr;
        }
        goto error_handler;
    }
    // validate, and handle action error
    if( action.ActionResult == NULL ) {
        err_code = SOAP_ACTION_FAILED;
        err_str = Soap_Action_Failed;
        goto error_handler;
    }
    // send response
    send_action_response( info, action.ActionResult, request );

    err_code = 0;

    // error handling and cleanup
  error_handler:
    ixmlDocument_free( action.ActionResult );
    ixmlDocument_free( resp_node );
    action_name.buf[action_name.length] = save_char;    // restore
    if( err_code != 0 ) {
        send_error_response( info, err_code, err_str, request );
    }
}
Exemple #14
0
/****************************************************************************
*	Function :	SoapSendActionEx
*
*	Parameters :
*		IN char* action_url :	device contrl URL 
*		IN char *service_type :	device service type
		IN IXML_Document *Header: Soap header
*		IN IXML_Document *action_node : SOAP action node ( SOAP body)	
*		OUT IXML_Document **response_node :	SOAP response node
*
*	Description :	This function is called by UPnP API to send the SOAP 
*		action request and waits till it gets the response from the device
*		pass the response to the API layer. This action is similar to the 
*		the SoapSendAction with only difference that it allows users to 
*		pass the SOAP header along the SOAP body ( soap action request)
*
*	Return :	int
*		returns UPNP_E_SUCCESS if successful else returns appropriate error
*	Note :
****************************************************************************/
int SoapSendActionEx(
	IN char *action_url,
	IN char *service_type,
	IN IXML_Document * header,
	IN IXML_Document * action_node,
	OUT IXML_Document ** response_node )
{
    char *xml_header_str = NULL;
    char *action_str = NULL;
    memptr name;
    membuffer request;
    membuffer responsename;
    int err_code;
    int ret_code;
    http_parser_t response;
    uri_type url;
    int upnp_error_code;
    char *upnp_error_str;
    int got_response = FALSE;
    const char *xml_start =
        "<s:Envelope "
        "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
        "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n";
    const char *xml_header_start =
        "<s:Header>\r\n";
    const char *xml_header_end =
        "</s:Header>\r\n";
    const char *xml_body_start =
        "<s:Body>";
    const char *xml_end =
        "</s:Body>\r\n"
        "</s:Envelope>\r\n";
    size_t xml_start_len;
    size_t xml_header_start_len;
    size_t xml_header_str_len;
    size_t xml_header_end_len;
    size_t xml_body_start_len;
    size_t action_str_len;
    size_t xml_end_len;
    off_t content_length;

    *response_node = NULL;      /* init */

    err_code = UPNP_E_OUTOF_MEMORY; /* default error */

    UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
        "Inside SoapSendActionEx():" );
    /* init */
    membuffer_init( &request );
    membuffer_init( &responsename );

    /* header string */
    xml_header_str = ixmlPrintNode( ( IXML_Node * ) header );
    if( xml_header_str == NULL ) {
        goto error_handler;
    }
    /* print action */
    action_str = ixmlPrintNode( ( IXML_Node * ) action_node );
    if( action_str == NULL ) {
        goto error_handler;
    }
    /* get action name */
    if( get_action_name( action_str, &name ) != 0 ) {
        err_code = UPNP_E_INVALID_ACTION;
        goto error_handler;
    }
    /* parse url */
    if( http_FixStrUrl( action_url, strlen( action_url ), &url ) != 0 ) {
        err_code = UPNP_E_INVALID_URL;
        goto error_handler;
    }

    UpnpPrintf( UPNP_INFO, SOAP, __FILE__, __LINE__,
        "path=%.*s, hostport=%.*s\n",
        (int)url.pathquery.size,
        url.pathquery.buff,
        (int)url.hostport.text.size,
        url.hostport.text.buff );

    xml_start_len = strlen( xml_start );
    xml_body_start_len = strlen( xml_body_start );
    xml_end_len = strlen( xml_end );
    action_str_len = strlen( action_str );

    xml_header_start_len = strlen( xml_header_start );
    xml_header_end_len = strlen( xml_header_end );
    xml_header_str_len = strlen( xml_header_str );

    /* make request msg */
    request.size_inc = 50;
    content_length = (off_t)(xml_start_len + xml_header_start_len +
	xml_header_str_len + xml_header_end_len +
        xml_body_start_len + action_str_len + xml_end_len);
    if (http_MakeMessage(
        &request, 1, 1,
        "q" "N" "s" "sssbsc" "Uc" "b" "b" "b" "b" "b" "b" "b",
        SOAPMETHOD_POST, &url,
        content_length,
        ContentTypeHeader,
        "SOAPACTION: \"", service_type, "#", name.buf, name.length, "\"",
        xml_start, xml_start_len,
        xml_header_start, xml_header_start_len,
        xml_header_str, xml_header_str_len,
        xml_header_end, xml_header_end_len,
        xml_body_start, xml_body_start_len,
        action_str, action_str_len,
        xml_end, xml_end_len ) != 0 ) {
        goto error_handler;
    }

    ret_code = soap_request_and_response( &request, &url, &response );
    got_response = TRUE;
    if( ret_code != UPNP_E_SUCCESS ) {
        err_code = ret_code;
        goto error_handler;
    }

    if( membuffer_append( &responsename, name.buf, name.length ) != 0 ||
        membuffer_append_str( &responsename, "Response" ) != 0 ) {
        goto error_handler;
    }
    /* get action node from the response */
    ret_code = get_response_value( &response.msg, SOAP_ACTION_RESP,
                                   responsename.buf, &upnp_error_code,
                                   ( IXML_Node ** ) response_node,
                                   &upnp_error_str );

    if( ret_code == SOAP_ACTION_RESP ) {
        err_code = UPNP_E_SUCCESS;
    } else if( ret_code == SOAP_ACTION_RESP_ERROR ) {
        err_code = upnp_error_code;
    } else {
        err_code = ret_code;
    }

  error_handler:

    ixmlFreeDOMString( action_str );
    ixmlFreeDOMString( xml_header_str );
    membuffer_destroy( &request );
    membuffer_destroy( &responsename );
    if( got_response ) {
        httpmsg_destroy( &response.msg );
    }

    return err_code;
}