Logo Search packages:      
Sourcecode: libupnp4 version File versions  Download package

upnptools.c

Go to the documentation of this file.
/**************************************************************************
 *
 * Copyright (c) 2000-2003 Intel Corporation 
 * All rights reserved. 
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met: 
 *
 * - Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer. 
 * - Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution. 
 * - Neither name of Intel Corporation nor the names of its contributors 
 * may be used to endorse or promote products derived from this software 
 * without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **************************************************************************/


#include "config.h"


/*!
 * \file
 */


#if EXCLUDE_DOM == 0


#include "upnp.h"
#include "upnptools.h"


#include "uri.h"


#include <stdarg.h>
#include <stdio.h>


/*! Maximum action header buffer length. */
00056 #define HEADER_LENGTH 2000


/*!
 * \brief Structure to maintain a error code and string associated with the
 * error code.
 */
00063 struct ErrorString {
      /*! Error code. */
00065       int rc;
      /*! Error description. */
00067       const char *rcError;
};


/*!
 * \brief Array of error structures.
 */
00074 struct ErrorString ErrorMessages[] = {
      {UPNP_E_SUCCESS, "UPNP_E_SUCCESS"},
      {UPNP_E_INVALID_HANDLE, "UPNP_E_INVALID_HANDLE"},
      {UPNP_E_INVALID_PARAM, "UPNP_E_INVALID_PARAM"},
      {UPNP_E_OUTOF_HANDLE, "UPNP_E_OUTOF_HANDLE"},
      {UPNP_E_OUTOF_CONTEXT, "UPNP_E_OUTOF_CONTEXT"},
      {UPNP_E_OUTOF_MEMORY, "UPNP_E_OUTOF_MEMOR"},
      {UPNP_E_INIT, "UPNP_E_INIT"},
      {UPNP_E_BUFFER_TOO_SMALL, "UPNP_E_BUFFER_TOO_SMALL"},
      {UPNP_E_INVALID_DESC, "UPNP_E_INVALID_DESC"},
      {UPNP_E_INVALID_URL, "UPNP_E_INVALID_URL"},
      {UPNP_E_INVALID_SID, "UPNP_E_INVALID_SID"},
      {UPNP_E_INVALID_DEVICE, "UPNP_E_INVALID_DEVICE"},
      {UPNP_E_INVALID_SERVICE, "UPNP_E_INVALID_SERVICE"},
      {UPNP_E_BAD_RESPONSE, "UPNP_E_BAD_RESPONSE"},
      {UPNP_E_BAD_REQUEST, "UPNP_E_BAD_REQUEST"},
      {UPNP_E_INVALID_ACTION, "UPNP_E_INVALID_ACTION"},
      {UPNP_E_FINISH, "UPNP_E_FINISH"},
      {UPNP_E_INIT_FAILED, "UPNP_E_INIT_FAILED"},
      {UPNP_E_BAD_HTTPMSG, "UPNP_E_BAD_HTTPMSG"},
      {UPNP_E_NETWORK_ERROR, "UPNP_E_NETWORK_ERROR"},
      {UPNP_E_SOCKET_WRITE, "UPNP_E_SOCKET_WRITE"},
      {UPNP_E_SOCKET_READ, "UPNP_E_SOCKET_READ"},
      {UPNP_E_SOCKET_BIND, "UPNP_E_SOCKET_BIND"},
      {UPNP_E_SOCKET_CONNECT, "UPNP_E_SOCKET_CONNECT"},
      {UPNP_E_OUTOF_SOCKET, "UPNP_E_OUTOF_SOCKET"},
      {UPNP_E_LISTEN, "UPNP_E_LISTEN"},
      {UPNP_E_EVENT_PROTOCOL, "UPNP_E_EVENT_PROTOCOL"},
      {UPNP_E_SUBSCRIBE_UNACCEPTED, "UPNP_E_SUBSCRIBE_UNACCEPTED"},
      {UPNP_E_UNSUBSCRIBE_UNACCEPTED, "UPNP_E_UNSUBSCRIBE_UNACCEPTED"},
      {UPNP_E_NOTIFY_UNACCEPTED, "UPNP_E_NOTIFY_UNACCEPTED"},
      {UPNP_E_INTERNAL_ERROR, "UPNP_E_INTERNAL_ERROR"},
      {UPNP_E_INVALID_ARGUMENT, "UPNP_E_INVALID_ARGUMENT"},
      {UPNP_E_OUTOF_BOUNDS, "UPNP_E_OUTOF_BOUNDS"},
};


const char *UpnpGetErrorMessage(int rc)
{
      int i;

      for (i = 0; i < sizeof (ErrorMessages) / sizeof (ErrorMessages[0]); ++i) {
            if (rc == ErrorMessages[i].rc) {
                  return ErrorMessages[i].rcError;
            }
      }

      return "Unknown error code";
}


/*!
 * \todo There is some unnecessary allocation and deallocation going on here
 * because of the way resolve_rel_url() was originally written and used. In the
 * future it would be nice to clean this up.
 */
00130 int UpnpResolveURL(
      const char *BaseURL,
      const char *RelURL,
      char *AbsURL)
{
      int ret = UPNP_E_SUCCESS;
      char *tempRel = NULL;

      if (RelURL == NULL) {
            ret = UPNP_E_INVALID_PARAM;
            goto ExitFunction;
      }

      tempRel = resolve_rel_url((char *)BaseURL, (char *)RelURL);
      if (tempRel) {
            strcpy(AbsURL, tempRel);
            free(tempRel);
      } else {
            ret = UPNP_E_INVALID_URL;
      }

ExitFunction:
      return UPNP_E_SUCCESS;
}


/*!
 * \brief Adds the argument in the action request or response.
 *
 * This function creates the action request or response if it is a first
 * argument, otherwise it will add the argument in the document.
 *
 * \returns UPNP_E_SUCCESS if successful, otherwise the appropriate error.
 */
00164 static int addToAction(
      /*! [in] flag to tell if the ActionDoc is for response or request. */
      int response,
      /*! [in,out] Request or response document. */
      IXML_Document **ActionDoc,
      /*! [in] Name of the action request or response. */
      const char *ActionName,
      /*! [in] Service type. */
      const char *ServType,
      /*! [in] Name of the argument. */
      const char *ArgName,
      /*! [in] Value of the argument. */
      const char *ArgValue)
{
      char *ActBuff = NULL;
      IXML_Node *node = NULL;
      IXML_Element *Ele = NULL;
      IXML_Node *Txt = NULL;
      int rc = 0;

      if (ActionName == NULL || ServType == NULL) {
            return UPNP_E_INVALID_PARAM;
      }

      if (*ActionDoc == NULL) {
            ActBuff = (char *)malloc(HEADER_LENGTH);
            if (ActBuff == NULL) {
                  return UPNP_E_OUTOF_MEMORY;
            }

            if (response) {
                  sprintf(ActBuff,
                        "<u:%sResponse xmlns:u=\"%s\">\r\n</u:%sResponse>",
                        ActionName, ServType, ActionName);
            } else {
                  sprintf(ActBuff,
                        "<u:%s xmlns:u=\"%s\">\r\n</u:%s>",
                        ActionName, ServType, ActionName);
            }

            rc = ixmlParseBufferEx(ActBuff, ActionDoc);
            free(ActBuff);
            if (rc != IXML_SUCCESS) {
                  if (rc == IXML_INSUFFICIENT_MEMORY) {
                        return UPNP_E_OUTOF_MEMORY;
                  } else {
                        return UPNP_E_INVALID_DESC;
                  }
            }
      }

      if (ArgName != NULL /*&& ArgValue != NULL */) {
            node = ixmlNode_getFirstChild((IXML_Node *)*ActionDoc);
            Ele = ixmlDocument_createElement(*ActionDoc, ArgName);
            if(ArgValue) {
                  Txt = ixmlDocument_createTextNode(*ActionDoc, ArgValue);
                  ixmlNode_appendChild((IXML_Node *)Ele, Txt);
            }
            ixmlNode_appendChild(node, (IXML_Node *)Ele);
      }

      return UPNP_E_SUCCESS;
}


/*!
 * \brief Creates the action request or response from the argument list.
 *
 * \return Action request or response document if successful, otherwise
 *    returns NULL
 */
00235 static IXML_Document *makeAction(
      /*! [in] flag to tell if the ActionDoc is for response or request. */
      int response,
      /*! [in] Name of the action request or response. */
      const char *ActionName,
      /*! [in] Service type. */
      const char *ServType,
      /*! [in] Number of arguments in the action request or response. */
      int NumArg,
      /*! [in] pointer to the first argument. */
      const char *Arg,
      /*! [in] Argument list. */
      va_list ArgList)
{
      const char *ArgName;
      const char *ArgValue;
      char *ActBuff;
      int Idx = 0;
      IXML_Document *ActionDoc;
      IXML_Node *node;
      IXML_Element *Ele;
      IXML_Node *Txt = NULL;

      if (ActionName == NULL || ServType == NULL) {
            return NULL;
      }

      ActBuff = (char *)malloc(HEADER_LENGTH);
      if (ActBuff == NULL) {
            return NULL;
      }

      if (response) {
            sprintf(ActBuff,
                  "<u:%sResponse xmlns:u=\"%s\">\r\n</u:%sResponse>",
                  ActionName, ServType, ActionName);
      } else {
            sprintf(ActBuff,
                  "<u:%s xmlns:u=\"%s\">\r\n</u:%s>",
                  ActionName, ServType, ActionName);
      }
      if (ixmlParseBufferEx(ActBuff, &ActionDoc) != IXML_SUCCESS) {
            free(ActBuff);
            return NULL;
      }

      free(ActBuff);
      if(ActionDoc == NULL) {
            return NULL;
      }

      if (NumArg > 0) {
            //va_start(ArgList, Arg);
            ArgName = Arg;
            for ( ; ; ) {
                  ArgValue = va_arg(ArgList, const char *);
                  if (ArgName != NULL) {
                        node = ixmlNode_getFirstChild((IXML_Node *)ActionDoc);
                        Ele = ixmlDocument_createElement(ActionDoc, ArgName);
                        if (ArgValue) {
                              Txt = ixmlDocument_createTextNode(ActionDoc, ArgValue);
                              ixmlNode_appendChild((IXML_Node *)Ele, Txt);
                        }
                        ixmlNode_appendChild(node, (IXML_Node *)Ele);
                  }
                  if (++Idx < NumArg) {
                        ArgName = va_arg(ArgList, const char *);
                  } else {
                        break;
                  }
            }
            //va_end(ArgList);
      }

      return ActionDoc;
}


IXML_Document *UpnpMakeAction(
      const char *ActionName,
      const char *ServType,
      int NumArg,
      const char *Arg,
      ...)
{
      va_list ArgList;
      IXML_Document *out = NULL;

      va_start(ArgList, Arg);
      out = makeAction(0, ActionName, ServType, NumArg, Arg, ArgList);
      va_end(ArgList);

      return out;
}


IXML_Document *UpnpMakeActionResponse(
      const char *ActionName,
      const char *ServType,
      int NumArg,
      const char *Arg,
      ...)
{
      va_list ArgList;
      IXML_Document *out = NULL;

      va_start(ArgList, Arg);
      out = makeAction(1, ActionName, ServType, NumArg, Arg, ArgList);
      va_end(ArgList);

      return out;
}


int UpnpAddToAction(
      IXML_Document **ActionDoc,
      const char *ActionName,
      const char *ServType,
      const char *ArgName,
      const char *ArgValue)
{
      return addToAction(0, ActionDoc, ActionName, ServType, ArgName, ArgValue);
}


int UpnpAddToActionResponse(
      IXML_Document **ActionResponse,
      const char *ActionName,
      const char *ServType,
      const char *ArgName,
      const char *ArgValue)
{
      return addToAction(1, ActionResponse, ActionName, ServType, ArgName, ArgValue);
}


IXML_Document *UpnpCreatePropertySet(
      int NumArg,
      const char *Arg,
      ...)
{
      va_list ArgList;
      int Idx = 0;
      char BlankDoc[] =
            "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">"
            "</e:propertyset>";
      const char *ArgName,
      *ArgValue;
      IXML_Node *node;
      IXML_Element *Ele;
      IXML_Element *Ele1;
      IXML_Node *Txt;
      IXML_Document *PropSet;

      if(ixmlParseBufferEx(BlankDoc, &PropSet) != IXML_SUCCESS) {
            return NULL;
      }

      if (NumArg < 1) {
            return PropSet;
      }

      va_start(ArgList, Arg);
      ArgName = Arg;
      while (Idx++ != NumArg) {
            ArgValue = va_arg(ArgList, const char *);
            if (ArgName != NULL /*&& ArgValue != NULL */) {
                  node = ixmlNode_getFirstChild((IXML_Node *)PropSet);
                  Ele1 = ixmlDocument_createElement(PropSet, "e:property");
                  Ele = ixmlDocument_createElement(PropSet, ArgName);
                  if (ArgValue) {
                        Txt = ixmlDocument_createTextNode(PropSet, ArgValue);
                        ixmlNode_appendChild((IXML_Node *)Ele, Txt);
                  }
                  ixmlNode_appendChild((IXML_Node *)Ele1, (IXML_Node *)Ele);
                  ixmlNode_appendChild(             node, (IXML_Node *)Ele1);
            }
            ArgName = va_arg(ArgList, const char *);
      }
      va_end(ArgList);

      return PropSet;
}


int UpnpAddToPropertySet(
      IXML_Document **PropSet,
      const char *ArgName,
      const char *ArgValue)
{
      char BlankDoc[] =
            "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">"
            "</e:propertyset>";
      IXML_Node *node;
      IXML_Element *Ele;
      IXML_Element *Ele1;
      IXML_Node *Txt;
      int rc;

      if (ArgName == NULL) {
            return UPNP_E_INVALID_PARAM;
      }

      if (*PropSet == NULL) {
            rc = ixmlParseBufferEx(BlankDoc, PropSet);
            if (rc != IXML_SUCCESS) {
                  return UPNP_E_OUTOF_MEMORY;
            }
      }

      node = ixmlNode_getFirstChild((IXML_Node *)*PropSet);

      Ele1 = ixmlDocument_createElement(*PropSet, "e:property");
      Ele = ixmlDocument_createElement(*PropSet, ArgName);

      if (ArgValue) {
            Txt = ixmlDocument_createTextNode(*PropSet, ArgValue);
            ixmlNode_appendChild((IXML_Node *)Ele, Txt);
      }

      ixmlNode_appendChild((IXML_Node *)Ele1, (IXML_Node *)Ele);
      ixmlNode_appendChild(node, (IXML_Node *)Ele1);

      return UPNP_E_SUCCESS;
}


#endif /* EXCLUDE_DOM == 0 */


Generated by  Doxygen 1.6.0   Back to index