Пример #1
0
char *mupnp_service_getstddcp(mUpnpService *service)
{
	char *serviceType = mupnp_service_getservicetype(service);
	if (mupnp_streq(serviceType, "urn:schemas-upnp-org:service:ContentDirectory:1"))
		return MUPNP_AV_CONTENTDIRECTORY_SERVICE_DESCRIPTION;
	if (mupnp_streq(serviceType, "urn:schemas-upnp-org:service:ConnectionManager:1"))
		return MUPNP_AV_CONNECTIONMANAGER_SERVICE_DESCRIPTION;
	if (mupnp_streq(serviceType, "urn:schemas-upnp-org:service:AVTransport:1"))
		return MUPNP_AV_AVTRANSPORT_SERVICE_DESCRIPTION;
	return NULL;
}
Пример #2
0
void mupnp_service_ssdpmessagereceived(mUpnpService *service, mUpnpSSDPPacket *ssdpPkt)
{
    mUpnpDevice *dev;
    const char *ssdpST;
    const char *serviceType;
    char serviceNT[MUPNP_SSDP_HEADER_LINE_MAXSIZE];
    char serviceUSN[MUPNP_SSDP_HEADER_LINE_MAXSIZE];

    mupnp_log_debug_l4("Entering...\n");

    ssdpST = mupnp_ssdp_packet_getst(ssdpPkt);
    if (mupnp_strlen(ssdpST) <= 0)
        return;

    dev = mupnp_service_getdevice(service);

    mupnp_service_getnotifyservicetypent(service, serviceNT, sizeof(serviceNT));
    mupnp_service_getnotifyservicetypeusn(service, serviceUSN, sizeof(serviceUSN));

    if (mupnp_st_isalldevice(ssdpST) == true) {
        mupnp_device_postsearchresponse(dev, ssdpPkt, serviceNT, serviceUSN);
    }
    else if (mupnp_st_isurn(ssdpST)  == true) {
        serviceType = mupnp_service_getservicetype(service);
        if (mupnp_streq(ssdpST, serviceType) == true)
            mupnp_device_postsearchresponse(dev, ssdpPkt, serviceType, serviceUSN);
    }

    mupnp_log_debug_l4("Leaving...\n");
}
Пример #3
0
bool mupnp_upnpav_dms_queryreceived(mUpnpStateVariable *statVar)
{
	mUpnpDevice *dev;
	mUpnpService *service;
	mUpnpAvServer *dms;
	CG_UPNPAV_STATEVARIABLE_LISTNER userQueryListener;

	service = mupnp_statevariable_getservice(statVar);
	if (!service)
		return false;

	dev = (mUpnpDevice *)mupnp_service_getdevice(service);
	if (!dev)
		return false;

	dms = (mUpnpAvServer *)mupnp_device_getuserdata(dev);
	if (!dms)
		return false;

	userQueryListener = mupnp_upnpav_dms_getquerylistener(dms);
	if (userQueryListener) {
		if (userQueryListener(statVar))
			return true;
	}

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMS_CONTENTDIRECTORY_SERVICE_TYPE))
		return mupnp_upnpav_dms_condir_queryreceived(statVar);

	return false;
}
Пример #4
0
// Used for xbox360 support, see README.360
bool mupnp_upnpav_dms_medrec_actionreceived(mUpnpAction *action)
{
    char *actionName;
    mUpnpArgument *arg;

    actionName = (char*)mupnp_action_getname(action);

    if (mupnp_strlen(actionName) <= 0)
        return false;


    if (mupnp_streq(actionName, CG_UPNPAV_DMS_MEDIARECEIVER_IS_AUTHORIZED )) {
        arg = mupnp_action_getargumentbyname(action,
                                               CG_UPNPAV_DMS_MEDIARECEIVER_RESULT);
        if (!arg)
            return false;
        mupnp_argument_setvalue(arg, "1");
        return true;
    }

    if (mupnp_streq(actionName, CG_UPNPAV_DMS_MEDIARECEIVER_IS_VALIDATED)) {
        arg = mupnp_action_getargumentbyname(action,
                                               CG_UPNPAV_DMS_MEDIARECEIVER_RESULT);
        if (!arg)
            return false;
        mupnp_argument_setvalue(arg, "1");
        return true;
    }

    if (mupnp_streq(actionName, CG_UPNPAV_DMS_MEDIARECEIVER_REGISTER_DEVICE)) {
        arg = mupnp_action_getargumentbyname(action,
                                               CG_UPNPAV_DMS_MEDIARECEIVER_REGISTRATION_RESP_MSG);
        if (!arg)
            return false;
        // Specifications say to return base64 message.
        mupnp_argument_setvalue(arg, "1");
        return true;
    }


    return true;
}
Пример #5
0
bool mupnp_upnpav_dms_condir_queryreceived(mUpnpStateVariable *var)
{
	mUpnpAvServer *dms;
	mUpnpDevice *dev;
	char *varName;
	char intBuf[MUPNP_STRING_INTEGER_BUFLEN];

	varName = (char*)mupnp_statevariable_getname(var);
	if (mupnp_strlen(varName) <= 0)
		return false;

	dev = (mUpnpDevice *)mupnp_service_getdevice(mupnp_statevariable_getservice(var));
	if (!dev)
		return false;

	dms = (mUpnpAvServer *)mupnp_device_getuserdata(dev);
	if (!dms)
		return false;

	/* Sort Capabilities */
	if (mupnp_streq(varName, CG_UPNPAV_DMS_CONTENTDIRECTORY_SORT_CAPABILITIES)) {
		mupnp_statevariable_setvalue(var, "");
		return true;
	}

	/* Search Capabilities */
	if (mupnp_streq(varName, CG_UPNPAV_DMS_CONTENTDIRECTORY_SEARCH_CAPABILITIES)) {
		mupnp_statevariable_setvalue(var, "");
		return true;
	}

	/* System Update ID */
	if (mupnp_streq(varName, CG_UPNPAV_DMS_CONTENTDIRECTORY_SYSTEM_UPDATE_ID)) {
		mupnp_statevariable_setvalue(var, mupnp_int2str(mupnp_upnpav_dms_condir_getsystemupdateid(dms), intBuf, MUPNP_STRING_INTEGER_BUFLEN));
		return true;
	}

	return false;
}
Пример #6
0
bool mupnp_upnpav_dmr_queryreceived(mUpnpStateVariable *statVar)
{
	mUpnpDevice *dev;
	mUpnpService *service;
	mUpnpAvRenderer *dmr;
	CG_UPNPAV_STATEVARIABLE_LISTNER userQueryListener;

	service = mupnp_statevariable_getservice(statVar);
	if (!service)
		return false;

	dev = (mUpnpDevice *)mupnp_service_getdevice(service);
	if (!dev)
		return false;

	dmr = (mUpnpAvRenderer *)mupnp_device_getuserdata(dev);
	if (!dmr)
		return false;

	userQueryListener = mupnp_upnpav_dmr_getquerylistener(dmr);
	if (userQueryListener) {
		if (userQueryListener(statVar))
			return true;
	}

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMR_AVTRANSPORT_SERVICE_TYPE))
		return mupnp_upnpav_dmr_avtransport_queryreceived(statVar);

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMR_RENDERINGCONTROL_SERVICE_TYPE))
		return mupnp_upnpav_dmr_renderingctrl_queryreceived(statVar);

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMR_CONNECTIONMANAGER_SERVICE_TYPE))
		return mupnp_upnpav_dmr_conmgr_queryreceived(statVar);

	return false;
}
Пример #7
0
bool mupnp_upnpav_dmr_actionreceived(mUpnpAction *action)
{
	mUpnpDevice *dev;
	mUpnpService *service;
	mUpnpAvRenderer *dmr;
	CG_UPNPAV_ACTION_LISTNER userActionListener;

	service = mupnp_action_getservice(action);
	if (!service)
		return false;

	dev = (mUpnpDevice *)mupnp_service_getdevice(service);
	if (!dev)
		return false;

	dmr = (mUpnpAvRenderer *)mupnp_device_getuserdata(dev);
	if (!dmr)
		return false;

	userActionListener = mupnp_upnpav_dmr_getactionlistener(dmr);
	if (userActionListener) {
		if (userActionListener(action))
			return true;
	}

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMR_AVTRANSPORT_SERVICE_TYPE))
		return mupnp_upnpav_dmr_avtransport_actionreceived(action);

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMR_RENDERINGCONTROL_SERVICE_TYPE))
		return mupnp_upnpav_dmr_renderingctrl_actionreceived(action);

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMR_CONNECTIONMANAGER_SERVICE_TYPE))
		return mupnp_upnpav_dmr_conmgr_actionreceived(action);

	return false;
}
Пример #8
0
bool mupnp_upnpav_dms_actionreceived(mUpnpAction *action)
{
	mUpnpDevice *dev;
	mUpnpService *service;
	mUpnpAvServer *dms;
	CG_UPNPAV_ACTION_LISTNER userActionListener;

	service = mupnp_action_getservice(action);
	if (!service)
		return false;

	dev = (mUpnpDevice *)mupnp_service_getdevice(service);
	if (!dev)
		return false;

	dms = (mUpnpAvServer *)mupnp_device_getuserdata(dev);
	if (!dms)
		return false;

	userActionListener = mupnp_upnpav_dms_getactionlistener(dms);
	if (userActionListener) {
		if (userActionListener(action))
			return true;
	}

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMS_CONTENTDIRECTORY_SERVICE_TYPE))
		return mupnp_upnpav_dms_condir_actionreceived(action);

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMS_MEDIARECEIVER_SERVICE_TYPE))
		return mupnp_upnpav_dms_medrec_actionreceived(action);

	if (mupnp_streq(mupnp_service_getservicetype(service), CG_UPNPAV_DMS_CONNECTIONMANAGER_SERVICE_TYPE))
		return mupnp_upnpav_dms_conmgr_actionreceived(action);

	return false;
}
Пример #9
0
mUpnpDictionaryElement *mupnp_dictionary_getelement(mUpnpDictionary *dir, const char *key)
{
	mUpnpDictionaryElement *dirElem;
	char *dirElemKey;

	mupnp_log_debug_l4("Entering...\n");

	if (NULL == dir || mupnp_strlen(key) <= 0 )
		return NULL;
	
	for (dirElem = mupnp_dictionary_gets(dir); dirElem != NULL; dirElem = mupnp_dictionary_element_next(dirElem)) {
			dirElemKey = mupnp_dictionary_element_getkey(dirElem);
			if (mupnp_strlen(dirElemKey) <= 0)
				continue;
			if (mupnp_streq(dirElemKey, key) == TRUE)
				return dirElem;
	}

	mupnp_log_debug_l4("Leaving...\n");

	return NULL;
}
Пример #10
0
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");
}
Пример #11
0
int mupnp_net_gethostinterfaces(mUpnpNetworkInterfaceList* netIfList)
{
#if !defined(MUPNP_USE_WIN32_GETHOSTADDRESSES) && !defined(MUPNP_USE_WIN32_GETADAPTERSINFO)
  mUpnpNetworkInterface* netIf;
  SOCKET sd;
  int nNumInterfaces;
  INTERFACE_INFO InterfaceList[20];
  unsigned long nBytesReturned, *pnBytesReturned = &nBytesReturned;
  struct sockaddr_in* pAddress;
  struct sockaddr_in* pNetmask;
  char* host;
  char* netmask;
  u_long nFlags;
  int i;

  mupnp_socket_startup();
  mupnp_net_interfacelist_clear(netIfList);

  sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
  //Theo Beisch WINSOCK2API WSASocket will return INVALID_SOCKET on error, not SOCKET_ERROR
  if (sd == INVALID_SOCKET) {
    return 0;
  }

  if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR)
    return 0;

  nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
  for (i = 0; i < nNumInterfaces; ++i) {
    nFlags = InterfaceList[i].iiFlags;
    //if (CyberNet::HostInterface::USE_ONLY_IPV4_ADDR == false) {
    if (nFlags & IFF_LOOPBACK)
      continue;
    //}
    if (!(nFlags & IFF_UP))
      continue;
    //if (IsUseAddress(host) == false)
    //	continue;

    netIf = mupnp_net_interface_new();

    pAddress = (struct sockaddr_in*)&(InterfaceList[i].iiAddress);
    host = inet_ntoa(pAddress->sin_addr);
    mupnp_net_interface_setaddress(netIf, host);

    pNetmask = (struct sockaddr_in*)&(InterfaceList[i].iiNetmask);
    netmask = inet_ntoa(pNetmask->sin_addr);
    mupnp_net_interface_setnetmask(netIf, netmask);

    mupnp_net_interfacelist_add(netIfList, netIf);
  }

#elif defined(MUPNP_USE_WIN32_GETADAPTERSINFO)
#pragma comment(lib, "Iphlpapi.lib")

  mUpnpNetworkInterface* netIf;
  PIP_ADAPTER_INFO pAdapterInfo = NULL, pAdapter = NULL;
  ULONG ulOutBufLen;
  DWORD dwRetVal;
  DWORD nOfInterfaces;

  mupnp_socket_startup();
  mupnp_net_interfacelist_clear(netIfList);

  ulOutBufLen = sizeof(IP_ADAPTER_INFO);
  pAdapterInfo = (IP_ADAPTER_INFO*)malloc(ulOutBufLen);
  if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
    free(pAdapterInfo);
    pAdapterInfo = (IP_ADAPTER_INFO*)malloc(ulOutBufLen);
  }

  if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
    for (pAdapter = pAdapterInfo, nOfInterfaces = 0; pAdapter; pAdapter = pAdapter->Next, ++nOfInterfaces) {
      if (pAdapter->Type == MIB_IF_TYPE_LOOPBACK)
        continue;
      if (mupnp_streq(pAdapter->IpAddressList.IpAddress.String, "0.0.0.0"))
        continue;
      netIf = mupnp_net_interface_new();
      mupnp_net_interface_setaddress(netIf, pAdapter->IpAddressList.IpAddress.String);
      mupnp_net_interface_setnetmask(netIf, pAdapter->IpAddressList.IpMask.String);
      if (pAdapter->AddressLength == MUPNP_NET_MACADDR_SIZE)
        mupnp_net_interface_setmacaddress(netIf, pAdapter->Address);
      mupnp_net_interfacelist_add(netIfList, netIf);
    }
  }
  free(pAdapterInfo);

#elif defined(MUPNP_USE_WIN32_GETHOSTADDRESSES)
#pragma comment(lib, "Iphlpapi.lib")

  IP_ADAPTER_ADDRESSES *pAdapterAddresses, *ai;
  DWORD ifFlags;
  ULONG outBufLen;
  IP_ADAPTER_UNICAST_ADDRESS* uai;
  SOCKET_ADDRESS sockaddr;
  SOCKADDR* saddr;
  INT saddrlen;
  char addr[NI_MAXHOST];
  char port[NI_MAXSERV];
  int namInfoRet;
  int ifIdx;
  mUpnpNetworkInterface* netIf;

  mupnp_socket_startup();
  mupnp_net_interfacelist_clear(netIfList);

  outBufLen = 0;
  ifFlags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;

  GetAdaptersAddresses(AF_UNSPEC, ifFlags, NULL, NULL, &outBufLen);
  pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)LocalAlloc(LMEM_ZEROINIT, outBufLen);
  GetAdaptersAddresses(AF_UNSPEC, ifFlags, NULL, pAdapterAddresses, &outBufLen);
  ai = pAdapterAddresses;
  while (ai != NULL) {
    if (ai->OperStatus != IfOperStatusUp) {
      ai = ai->Next;
      continue;
    }
    if (ai->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
      ai = ai->Next;
      continue;
    }
    if (ai->IfType == IF_TYPE_TUNNEL) {
      ai = ai->Next;
      continue;
    }
    uai = ai->FirstUnicastAddress;
    while (uai != NULL) {
      sockaddr = uai->Address;
      saddr = sockaddr.lpSockaddr;
      saddrlen = sockaddr.iSockaddrLength;
      namInfoRet = getnameinfo(saddr, saddrlen, addr, sizeof(addr), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
      if (namInfoRet == 0) {
        //if (IsUseAddress(addr) == true) {
        ifIdx = 0;
        if (mupnp_net_isipv6address(addr) == true)
          ifIdx = mupnp_net_getipv6scopeid(addr);
        netIf = mupnp_net_interface_new();
        mupnp_net_interface_setaddress(netIf, addr);
        if (ai->PhysicalAddressLength == MUPNP_NET_MACADDR_SIZE)
          mupnp_net_interface_setmacaddress(netIf, ai->PhysicalAddress);
        mupnp_net_interface_setindex(netIf, ifIdx);
        mupnp_net_interfacelist_add(netIfList, netIf);
        //}
      }
      else {
        int err = WSAGetLastError();
      }
      uai = uai->Next;
    }
    ai = ai->Next;
  }
  LocalFree(pAdapterAddresses);

#endif

  return mupnp_net_interfacelist_size(netIfList);
}
Пример #12
0
bool mupnp_upnpav_dms_condir_actionreceived(mUpnpAction *action)
{
	mUpnpAvServer *dms;
	mUpnpDevice *dev;
	char *actionName;
	mUpnpArgument *arg;
	char *argValue;
	char intBuf[MUPNP_STRING_INTEGER_BUFLEN];

	actionName = (char*)mupnp_action_getname(action);
	if (mupnp_strlen(actionName) <= 0)
		return false;

	dev = (mUpnpDevice *)mupnp_service_getdevice(mupnp_action_getservice(action));
	if (!dev)
		return false;

	dms = (mUpnpAvServer *)mupnp_device_getuserdata(dev);
	if (!dms)
		return false;

	/* Browse */
	if (mupnp_streq(actionName, CG_UPNPAV_DMS_CONTENTDIRECTORY_BROWSE))
	{
		arg = mupnp_action_getargumentbyname(action, CG_UPNPAV_DMS_CONTENTDIRECTORY_BROWSE_BROWSE_FLAG);
		if (!arg)
			return false;
		argValue = mupnp_argument_getvalue(arg);
		if (mupnp_streq(argValue, CG_UPNPAV_DMS_CONTENTDIRECTORY_BROWSE_BROWSE_METADATA))
			return mupnp_upnpav_dms_condir_browsemetadata(dms, action);
		if (mupnp_streq(argValue, CG_UPNPAV_DMS_CONTENTDIRECTORY_BROWSE_BROWSE_DIRECT_CHILDREN))
			return mupnp_upnpav_dms_condir_browsedirectchildren(dms, action);
		return false;
	}

	/* Search */
	if (mupnp_streq(actionName, CG_UPNPAV_DMS_CONTENTDIRECTORY_SEARCH)) {
		/* Not Implemented */
		return false;
	}

	/* Sort Capabilities */
	if (mupnp_streq(actionName, CG_UPNPAV_DMS_CONTENTDIRECTORY_GET_SORT_CAPABILITIES)) {
		arg = mupnp_action_getargumentbyname(action, CG_UPNPAV_DMS_CONTENTDIRECTORY_SORT_CAPS);
		if (!arg)
			return false;
		mupnp_argument_setvalue(arg, "");
		return true;
	}

	/* Search Capabilities */
	if (mupnp_streq(actionName, CG_UPNPAV_DMS_CONTENTDIRECTORY_GET_SEARCH_CAPABILITIES)) {
		arg = mupnp_action_getargumentbyname(action, CG_UPNPAV_DMS_CONTENTDIRECTORY_SEARCH_CAPS);
		if (!arg)
			return false;
		mupnp_argument_setvalue(arg, "");
		return true;
	}

	/* System Update ID */
	if (mupnp_streq(actionName, CG_UPNPAV_DMS_CONTENTDIRECTORY_GET_SYSTEM_UPDATE_ID)) {
		arg = mupnp_action_getargumentbyname(action, CG_UPNPAV_DMS_CONTENTDIRECTORY_ID);
		if (!arg)
			return false;
		mupnp_argument_setvalue(arg, mupnp_int2str(mupnp_upnpav_dms_condir_getsystemupdateid(dms), intBuf, MUPNP_STRING_INTEGER_BUFLEN));
		return true;
	}

	return false;
}