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

gena_ctrlpt.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_GENA == 0
#ifdef INCLUDE_CLIENT_APIS


#include "EventSubscribe.h"
#include "gena.h"
#include "httpparser.h"
#include "httpreadwrite.h"
#include "parsetools.h"
#include "statcodes.h"
#include "sysdep.h"
#include "uuid.h"
#include "upnpapi.h"


extern ithread_mutex_t GlobalClientSubscribeMutex;


/*!
 * \brief This is a thread function to send the renewal just before the
 * subscription times out.
 */
static void GenaAutoRenewSubscription(
      /*! [in] Thread data(upnp_timeout *) needed to send the renewal. */
      IN void *input)
{
      upnp_timeout *event = (upnp_timeout *) input;
      UpnpEventSubscribe *sub_struct = (UpnpEventSubscribe *)event->Event;
      void *cookie;
      Upnp_FunPtr callback_fun;
      struct Handle_Info *handle_info;
      int send_callback = 0;
      int eventType = 0;
      int timeout = 0;
      int errCode = 0;

      if (AUTO_RENEW_TIME == 0) {
            UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUB EXPIRED");
            UpnpEventSubscribe_set_ErrCode(sub_struct, UPNP_E_SUCCESS);
            send_callback = 1;
            eventType = UPNP_EVENT_SUBSCRIPTION_EXPIRED;
      } else {
            UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA AUTO RENEW");
            errCode = genaRenewSubscription(
                  event->handle,
                  UpnpEventSubscribe_get_SID(sub_struct),
                  &timeout);
            UpnpEventSubscribe_set_ErrCode(sub_struct, errCode);
            UpnpEventSubscribe_set_TimeOut(sub_struct, timeout);
            if (errCode != UPNP_E_SUCCESS &&
                errCode != GENA_E_BAD_SID &&
                errCode != GENA_E_BAD_HANDLE) {
                  send_callback = 1;
                  eventType = UPNP_EVENT_AUTORENEWAL_FAILED;
            }
      }

      if (send_callback) {
            HandleReadLock();
            if( GetHandleInfo( event->handle, &handle_info ) != HND_CLIENT ) {
                  HandleUnlock();
                  free_upnp_timeout(event);

                  return;
            }
            UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "HANDLE IS VALID");

            // make callback
            callback_fun = handle_info->Callback;
            cookie = handle_info->Cookie;
            HandleUnlock();
            callback_fun(eventType, event->Event, cookie);
      }

      free_upnp_timeout(event);
}


/*!
 * \brief Schedules a job to renew the subscription just before time out.
 *
 * \return GENA_E_SUCCESS if successful, otherwise returns the appropriate
 *    error code.
 */
static int ScheduleGenaAutoRenew(
      /*! [in] Handle that also contains the subscription list. */
      IN int client_handle,
      /*! [in] The time out value of the subscription. */
      IN int TimeOut,
      /*! [in] Subscription being renewed. */
      IN ClientSubscription *sub)
{
      UpnpEventSubscribe *RenewEventStruct = NULL;
      upnp_timeout *RenewEvent = NULL;
      int return_code = GENA_SUCCESS;
      ThreadPoolJob job;

      if( TimeOut == UPNP_INFINITE ) {
            return GENA_SUCCESS;
      }

      RenewEventStruct = UpnpEventSubscribe_new();
      if( RenewEventStruct == NULL ) {
            return UPNP_E_OUTOF_MEMORY;
      }

      RenewEvent = (upnp_timeout *) malloc(sizeof(upnp_timeout));
      if( RenewEvent == NULL ) {
            free( RenewEventStruct );
            return UPNP_E_OUTOF_MEMORY;
      }

      // schedule expire event
      UpnpEventSubscribe_set_ErrCode(RenewEventStruct, UPNP_E_SUCCESS);
      UpnpEventSubscribe_set_TimeOut(RenewEventStruct, TimeOut);
      UpnpEventSubscribe_set_SID(RenewEventStruct, UpnpClientSubscription_get_SID(sub));
      UpnpEventSubscribe_set_PublisherUrl(RenewEventStruct, UpnpClientSubscription_get_EventURL(sub));

      // RenewEvent->EventType=UPNP_EVENT_SUBSCRIPTION_EXPIRE;
      RenewEvent->handle = client_handle;
      RenewEvent->Event = RenewEventStruct;

      TPJobInit(&job, (start_routine) GenaAutoRenewSubscription, RenewEvent);
      TPJobSetFreeFunction(&job, (free_routine)free_upnp_timeout);
      TPJobSetPriority(&job, MED_PRIORITY);

      // Schedule the job
      return_code = TimerThreadSchedule(
            &gTimerThread,
            TimeOut - AUTO_RENEW_TIME,
            REL_SEC,
            &job, SHORT_TERM,
            &(RenewEvent->eventId));
      if (return_code != UPNP_E_SUCCESS) {
            free(RenewEvent);
            free(RenewEventStruct);

            return return_code;
      }

      UpnpClientSubscription_set_RenewEventId(sub, RenewEvent->eventId);

      return GENA_SUCCESS;
}


/*!
 * \brief Sends the UNSUBCRIBE gena request and recieves the response from the
 *    device and returns it as a parameter.
 *
 * \returns 0 if successful, otherwise returns the appropriate error code.
 */
static int gena_unsubscribe(
      /*! [in] Event URL of the service. */
      IN const UpnpString *url,
      /*! [in] The subcription ID. */
      IN const UpnpString *sid,
      /*! [out] The UNSUBCRIBE response from the device. */
      OUT http_parser_t *response )
{
      int return_code;
      uri_type dest_url;
      membuffer request;

      // parse url
      return_code = http_FixStrUrl(
            UpnpString_get_String(url),
            UpnpString_get_Length(url),
            &dest_url);
      if (return_code != 0) {
            return return_code;
      }

      // make request msg
      membuffer_init(&request);
      request.size_inc = 30;
      return_code = http_MakeMessage(
            &request, 1, 1,
            "q" "ssc" "Uc",
            HTTPMETHOD_UNSUBSCRIBE, &dest_url,
            "SID: ", UpnpString_get_String(sid));

      // Not able to make the message so destroy the existing buffer
      if (return_code != 0) {
            membuffer_destroy(&request);

            return return_code;
      }

      // send request and get reply
      return_code = http_RequestAndResponse(
            &dest_url, request.buf, request.length,
            HTTPMETHOD_UNSUBSCRIBE, HTTP_DEFAULT_TIMEOUT, response);
      membuffer_destroy(&request);
      if (return_code != 0) {
            httpmsg_destroy(&response->msg);
      }

      if (return_code == 0 && response->msg.status_code != HTTP_OK) {
            return_code = UPNP_E_UNSUBSCRIBE_UNACCEPTED;
            httpmsg_destroy(&response->msg);
      }

      return return_code;
}


/*!
 * \brief Subscribes or renew subscription.
 *
 * \return 0 if successful, otherwise returns the appropriate error code.
 */
static int gena_subscribe(
      /*! [in] URL of service to subscribe. */
      IN const UpnpString *url,
      /*! [in,out] Subscription time desired (in secs). */
      INOUT int *timeout,
      /*! [in] for renewal, this contains a currently held subscription SID.
       * For first time subscription, this must be NULL. */
      IN const UpnpString *renewal_sid,
      /*! [out] SID returned by the subscription or renew msg. */
      OUT UpnpString *sid)
{
      int return_code;
      int parse_ret = 0;
      int local_timeout = CP_MINIMUM_SUBSCRIPTION_TIME;
      memptr sid_hdr;
      memptr timeout_hdr;
      char timeout_str[25];
      membuffer request;
      uri_type dest_url;
      http_parser_t response;

      UpnpString_clear(sid);

      // request timeout to string
      if (timeout == NULL) {
            timeout = &local_timeout;
      }
      if (*timeout < 0) {
            strcpy(timeout_str, "infinite");
      } else if(*timeout < CP_MINIMUM_SUBSCRIPTION_TIME) {
            sprintf(timeout_str, "%d", CP_MINIMUM_SUBSCRIPTION_TIME);
      } else {
            sprintf(timeout_str, "%d", *timeout);
      }

      // parse url
      return_code = http_FixStrUrl(
            UpnpString_get_String(url),
            UpnpString_get_Length(url),
            &dest_url);
      if (return_code != 0) {
            return return_code;
      }

      // make request msg
      membuffer_init(&request);
      request.size_inc = 30;
      if (renewal_sid) {
            // renew subscription
            return_code = http_MakeMessage(
                  &request, 1, 1,
                  "q" "ssc" "sscc",
                  HTTPMETHOD_SUBSCRIBE, &dest_url,
                  "SID: ", renewal_sid,
                  "TIMEOUT: Second-", timeout_str );
      } else {
            // subscribe
            if( dest_url.hostport.IPaddress.ss_family == AF_INET6 ) {
                  return_code = http_MakeMessage(
                        &request, 1, 1,
                        "q" "sssdsc" "sc" "sscc",
                        HTTPMETHOD_SUBSCRIBE, &dest_url,
                        "CALLBACK: <http://[", gIF_IPV6, "]:", LOCAL_PORT_V6, "/>",
                        "NT: upnp:event",
                        "TIMEOUT: Second-", timeout_str );
            } else {
                  return_code = http_MakeMessage(
                        &request, 1, 1,
                        "q" "sssdsc" "sc" "sscc",
                        HTTPMETHOD_SUBSCRIBE, &dest_url,
                        "CALLBACK: <http://", gIF_IPV4, ":", LOCAL_PORT_V4, "/>",
                        "NT: upnp:event",
                        "TIMEOUT: Second-", timeout_str);
            }
      }
      if (return_code != 0) {
            return return_code;
      }

      // send request and get reply
      return_code = http_RequestAndResponse(&dest_url, request.buf,
            request.length,
            HTTPMETHOD_SUBSCRIBE,
            HTTP_DEFAULT_TIMEOUT,
            &response);
      membuffer_destroy(&request);

      if (return_code != 0) {
            httpmsg_destroy(&response.msg);

            return return_code;
      }
      if (response.msg.status_code != HTTP_OK) {
            httpmsg_destroy(&response.msg);

            return UPNP_E_SUBSCRIBE_UNACCEPTED;
      }

      // get SID and TIMEOUT
      if (httpmsg_find_hdr(&response.msg, HDR_SID, &sid_hdr) == NULL ||
          sid_hdr.length == 0 ||
          httpmsg_find_hdr( &response.msg, HDR_TIMEOUT, &timeout_hdr ) == NULL ||
          timeout_hdr.length == 0 ) {
            httpmsg_destroy( &response.msg );

            return UPNP_E_BAD_RESPONSE;
      }

      // save timeout
      parse_ret = matchstr(timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0", timeout);
      if (parse_ret == PARSE_OK) {
            // nothing to do
      } else if (memptr_cmp_nocase(&timeout_hdr, "Second-infinite") == 0) {
            *timeout = -1;
      } else {
            httpmsg_destroy( &response.msg );

            return UPNP_E_BAD_RESPONSE;
      }

      // save SID
      UpnpString_set_StringN(sid, sid_hdr.buf, sid_hdr.length);
      if (UpnpString_get_String(sid) == NULL) {
            httpmsg_destroy(&response.msg);

            return UPNP_E_OUTOF_MEMORY;
      }
      httpmsg_destroy(&response.msg);

      return UPNP_E_SUCCESS;
}


int genaUnregisterClient(UpnpClient_Handle client_handle)
{
      ClientSubscription *sub_copy = UpnpClientSubscription_new();
      int return_code = UPNP_E_SUCCESS;
      struct Handle_Info *handle_info = NULL;
      http_parser_t response;

      while (TRUE) {
            HandleLock();

            if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
                  HandleUnlock();
                  return_code = GENA_E_BAD_HANDLE;
                  goto exit_function;
            }
            if (handle_info->ClientSubList == NULL) {
                  return_code = UPNP_E_SUCCESS;
                  break;
            }
            UpnpClientSubscription_assign(sub_copy, handle_info->ClientSubList);
            RemoveClientSubClientSID(
                  &handle_info->ClientSubList,
                  UpnpClientSubscription_get_SID(sub_copy));

            HandleUnlock();

            return_code = gena_unsubscribe(
                  UpnpClientSubscription_get_EventURL(sub_copy),
                  UpnpClientSubscription_get_ActualSID(sub_copy),
                  &response);
            if (return_code == 0) {
                  httpmsg_destroy(&response.msg);
            }
            free_client_subscription(sub_copy);
      }

      freeClientSubList(handle_info->ClientSubList);
      HandleUnlock();

exit_function:
      UpnpClientSubscription_delete(sub_copy);
      return return_code;
}


#ifdef INCLUDE_CLIENT_APIS
int genaUnSubscribe(
      UpnpClient_Handle client_handle,
      const UpnpString *in_sid)
{
      ClientSubscription *sub = NULL;
      int return_code = GENA_SUCCESS;
      struct Handle_Info *handle_info;
      ClientSubscription *sub_copy = UpnpClientSubscription_new();
      http_parser_t response;

      // validate handle and sid
      HandleLock();
      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;
      }
      UpnpClientSubscription_assign(sub_copy, sub);
      HandleUnlock();

      return_code = gena_unsubscribe(
            UpnpClientSubscription_get_EventURL(sub_copy),
            UpnpClientSubscription_get_ActualSID(sub_copy),
            &response);
      if (return_code == 0) {
            httpmsg_destroy(&response.msg);
      }
      free_client_subscription(sub_copy);

      HandleLock();
      if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
            HandleUnlock();
            return_code = GENA_E_BAD_HANDLE;
            goto exit_function;
      }
      RemoveClientSubClientSID(&handle_info->ClientSubList, in_sid);
      HandleUnlock();

exit_function:
      UpnpClientSubscription_delete(sub_copy);
      return return_code;
      }
#endif /* INCLUDE_CLIENT_APIS */


#ifdef INCLUDE_CLIENT_APIS
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;

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

      UpnpString_clear(out_sid);

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

            return GENA_E_BAD_HANDLE;
      }
      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);
      sprintf(temp_sid2, "uuid:%s", temp_sid);
      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:
      if (return_code != UPNP_E_SUCCESS) {
            UpnpString_delete(ActualSID);
            UpnpString_delete(EventURL);
            UpnpClientSubscription_delete(newSubscription);
      }
      HandleUnlock();
      SubscribeUnlock();

      return return_code;
}
#endif /* INCLUDE_CLIENT_APIS */


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;
}


void gena_process_notification_event(
      SOCKINFO *info,
      http_message_t *event)
{
      UpnpEvent *event_struct = UpnpEvent_new();
      IXML_Document *ChangedVars = NULL;
      int eventKey;
      token sid;
      ClientSubscription *subscription = NULL;
      struct Handle_Info *handle_info;
      void *cookie;
      Upnp_FunPtr callback;
      UpnpClient_Handle client_handle;

      memptr sid_hdr;
      memptr nt_hdr,
      nts_hdr;
      memptr seq_hdr;

      // get SID
      if (httpmsg_find_hdr(event, HDR_SID, &sid_hdr) == NULL) {
            error_respond(info, HTTP_PRECONDITION_FAILED, event);
            goto exit_function;
      }
      sid.buff = sid_hdr.buf;
      sid.size = sid_hdr.length;

      // get event key
      if (httpmsg_find_hdr(event, HDR_SEQ, &seq_hdr) == NULL ||
          matchstr(seq_hdr.buf, seq_hdr.length, "%d%0", &eventKey) != PARSE_OK) {
            error_respond( info, HTTP_BAD_REQUEST, event );
            goto exit_function;
      }

      // get NT and NTS headers
      if (httpmsg_find_hdr(event, HDR_NT, &nt_hdr) == NULL ||
          httpmsg_find_hdr(event, HDR_NTS, &nts_hdr) == NULL) {
            error_respond( info, HTTP_BAD_REQUEST, event );
            goto exit_function;
      }

      // verify NT and NTS headers
      if (memptr_cmp(&nt_hdr, "upnp:event") != 0 ||
          memptr_cmp(&nts_hdr, "upnp:propchange") != 0) {
            error_respond(info, HTTP_PRECONDITION_FAILED, event);
            goto exit_function;
      }

      // parse the content (should be XML)
      if (!has_xml_content_type(event) ||
          event->msg.length == 0 ||
          ixmlParseBufferEx(event->entity.buf, &ChangedVars) != IXML_SUCCESS) {
            error_respond(info, HTTP_BAD_REQUEST, event);
            goto exit_function;
      }

      HandleLock();

      // get client info
      if (GetClientHandleInfo(&client_handle, &handle_info) != HND_CLIENT) {
            error_respond(info, HTTP_PRECONDITION_FAILED, event);
            HandleUnlock();
            goto exit_function;
      }

      // get subscription based on SID
      subscription = GetClientSubActualSID(handle_info->ClientSubList, &sid);
      if (subscription == NULL) {
            if (eventKey == 0) {
                  // wait until we've finished processing a subscription 
                  //   (if we are in the middle)
                  // this is to avoid mistakenly rejecting the first event if we 
                  //   receive it before the subscription response
                  HandleUnlock();

                  // try and get Subscription Lock 
                  //   (in case we are in the process of subscribing)
                  SubscribeLock();

                  // get HandleLock again
                  HandleLock();

                  if (GetClientHandleInfo(&client_handle, &handle_info) != HND_CLIENT) {
                        error_respond(info, HTTP_PRECONDITION_FAILED, event);
                        SubscribeUnlock();
                        HandleUnlock();
                        goto exit_function;
                  }

                  subscription = GetClientSubActualSID(handle_info->ClientSubList, &sid);
                  if (subscription == NULL) {
                        error_respond( info, HTTP_PRECONDITION_FAILED, event );
                        SubscribeUnlock();
                        HandleUnlock();
                        goto exit_function;
                  }

                  SubscribeUnlock();
            } else {
                  error_respond( info, HTTP_PRECONDITION_FAILED, event );
                  HandleUnlock();
                  goto exit_function;
            }
      }

      // success
      error_respond(info, HTTP_OK, event);

      // fill event struct
      UpnpEvent_set_EventKey(event_struct, eventKey);
      UpnpEvent_set_ChangedVariables(event_struct, ChangedVars);
      UpnpEvent_set_SID(event_struct, UpnpClientSubscription_get_SID(subscription));

      // copy callback
      callback = handle_info->Callback;
      cookie = handle_info->Cookie;

      HandleUnlock();

      // make callback with event struct
      // In future, should find a way of mainting
      // that the handle is not unregistered in the middle of a
      // callback
      callback(UPNP_EVENT_RECEIVED, event_struct, cookie);

exit_function:
      ixmlDocument_free(ChangedVars);
      UpnpEvent_delete(event_struct);
}


#endif /* INCLUDE_CLIENT_APIS */
#endif /* EXCLUDE_GENA */


Generated by  Doxygen 1.6.0   Back to index