/************************************************************************ * Function : freeServiceList * * Parameters : * service_info * head ; Head of the service list to be freed * * Description : Free's memory allocated for the various components * of each service entry in the service table. * * Return : void ; * * Note : ************************************************************************/ void freeServiceList( service_info * head ) { service_info *next = NULL; while( head ) { if( head->serviceType ) ixmlFreeDOMString( head->serviceType ); if( head->serviceId ) ixmlFreeDOMString( head->serviceId ); if( head->SCPDURL ) free( head->SCPDURL ); if( head->controlURL ) free( head->controlURL ); if( head->eventURL ) free( head->eventURL ); if( head->UDN ) ixmlFreeDOMString( head->UDN ); if( head->subscriptionList ) freeSubscriptionList( head->subscriptionList ); head->TotalSubscriptions = 0; next = head->next; free( head ); head = next; } }
/************************************************************************ * Function : freeService * * Parameters : * service_info *in ; service information that is to be freed * * Description : Free's memory allocated for the various components * of the service entry in the service table. * * Return : void ; * * Note : ************************************************************************/ void freeService( service_info * in ) { if( in ) { if( in->serviceType ) ixmlFreeDOMString( in->serviceType ); if( in->serviceId ) ixmlFreeDOMString( in->serviceId ); if( in->SCPDURL ) free( in->SCPDURL ); if( in->controlURL ) free( in->controlURL ); if( in->eventURL ) free( in->eventURL ); if( in->UDN ) ixmlFreeDOMString( in->UDN ); if( in->subscriptionList ) freeSubscriptionList( in->subscriptionList ); in->TotalSubscriptions = 0; free( in ); } }
/************************************************************************ * Function : GetNextSubscription * * Parameters : * service_info * service ; service object providing the list of * subscriptions * subscription *current ; current subscription object * * Description : Get current and valid subscription from the service * table. * * Return : subscription * - Pointer to the next subscription node; * * Note : ************************************************************************/ subscription * GetNextSubscription( service_info * service, subscription * current ) { time_t current_time; subscription *next = NULL; subscription *previous = NULL; int notDone = 1; //get the current_time time( ¤t_time ); while( ( notDone ) && ( current ) ) { previous = current; current = current->next; if( current == NULL ) { notDone = 0; next = current; } else if( ( current->expireTime != 0 ) && ( current->expireTime < current_time ) ) { previous->next = current->next; current->next = NULL; freeSubscriptionList( current ); current = previous; service->TotalSubscriptions--; } else if( current->active ) { notDone = 0; next = current; } } return next; }
subscription *GetSubscriptionSID(const Upnp_SID sid, service_info *service) { subscription *next = service->subscriptionList; subscription *previous = NULL; subscription *found = NULL; time_t current_time; while( ( next ) && ( found == NULL ) ) { if( !strcmp( next->sid, sid ) ) found = next; else { previous = next; next = next->next; } } if( found ) { /*get the current_time */ time( ¤t_time ); if( ( found->expireTime != 0 ) && ( found->expireTime < current_time ) ) { if( previous ) previous->next = found->next; else service->subscriptionList = found->next; found->next = NULL; freeSubscriptionList( found ); found = NULL; service->TotalSubscriptions--; } } return found; }
/************************************************************************ * Function : RemoveSubscriptionSID * * Parameters : * Upnp_SID sid ; subscription ID * service_info * service ; service object providing the list of * subscriptions * * Description : Remove the subscription represented by the * const Upnp_SID sid parameter from the service table and update * the service table. * * Return : void ; * * Note : ************************************************************************/ void RemoveSubscriptionSID( Upnp_SID sid, service_info * service ) { subscription *finger = service->subscriptionList; subscription *previous = NULL; while( finger ) { if( !( strcmp( sid, finger->sid ) ) ) { if( previous ) previous->next = finger->next; else service->subscriptionList = finger->next; finger->next = NULL; freeSubscriptionList( finger ); finger = NULL; service->TotalSubscriptions--; } else { previous = finger; finger = finger->next; } } }
void gena_process_subscription_request( SOCKINFO *info, http_message_t *request) { UpnpSubscriptionRequest *request_struct = UpnpSubscriptionRequest_new(); Upnp_SID temp_sid; int return_code = 1; int time_out = 1801; service_info *service; subscription *sub; uuid_upnp uid; struct Handle_Info *handle_info; void *cookie; Upnp_FunPtr callback_fun; UpnpDevice_Handle device_handle; memptr nt_hdr; char *event_url_path = NULL; memptr callback_hdr; memptr timeout_hdr; int rc = 0; UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "Subscription Request Received:\n"); if (httpmsg_find_hdr(request, HDR_NT, &nt_hdr) == NULL) { error_respond(info, HTTP_BAD_REQUEST, request); goto exit_function; } /* check NT header */ /* Windows Millenium Interoperability: */ /* we accept either upnp:event, or upnp:propchange for the NT header */ if (memptr_cmp_nocase(&nt_hdr, "upnp:event") != 0) { error_respond(info, HTTP_PRECONDITION_FAILED, request); goto exit_function; } /* if a SID is present then the we have a bad request "incompatible headers" */ if (httpmsg_find_hdr(request, HDR_SID, NULL) != NULL) { error_respond(info, HTTP_BAD_REQUEST, request); goto exit_function; } /* look up service by eventURL */ event_url_path = str_alloc(request->uri.pathquery.buff, request->uri.pathquery.size); if (event_url_path == NULL) { error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request); goto exit_function; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "SubscriptionRequest for event URL path: %s\n", event_url_path); HandleLock(); if (GetDeviceHandleInfoForPath(event_url_path, info->foreign_sockaddr.ss_family, &device_handle, &handle_info, &service) != HND_DEVICE) { free(event_url_path); error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request); HandleUnlock(); goto exit_function; } free(event_url_path); if (service == NULL || !service->active) { error_respond(info, HTTP_NOT_FOUND, request); HandleUnlock(); goto exit_function; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "Subscription Request: Number of Subscriptions already %d\n " "Max Subscriptions allowed: %d\n", service->TotalSubscriptions, handle_info->MaxSubscriptions); /* too many subscriptions */ if (handle_info->MaxSubscriptions != -1 && service->TotalSubscriptions >= handle_info->MaxSubscriptions) { error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request); HandleUnlock(); goto exit_function; } /* generate new subscription */ sub = (subscription *)malloc(sizeof (subscription)); if (sub == NULL) { error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request); HandleUnlock(); goto exit_function; } sub->ToSendEventKey = 0; sub->active = 0; sub->next = NULL; sub->DeliveryURLs.size = 0; sub->DeliveryURLs.URLs = NULL; sub->DeliveryURLs.parsedURLs = NULL; if (ListInit(&sub->outgoing, 0, free) != 0) { error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request); HandleUnlock(); goto exit_function; } /* check for valid callbacks */ if (httpmsg_find_hdr( request, HDR_CALLBACK, &callback_hdr) == NULL) { error_respond(info, HTTP_PRECONDITION_FAILED, request); freeSubscriptionList(sub); HandleUnlock(); goto exit_function; } return_code = create_url_list(&callback_hdr, &sub->DeliveryURLs); if (return_code == 0) { error_respond(info, HTTP_PRECONDITION_FAILED, request); freeSubscriptionList(sub); HandleUnlock(); goto exit_function; } if (return_code == UPNP_E_OUTOF_MEMORY) { error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request); freeSubscriptionList(sub); HandleUnlock(); goto exit_function; } /* set the timeout */ if (httpmsg_find_hdr(request, HDR_TIMEOUT, &timeout_hdr) != NULL) { if (matchstr(timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0", &time_out) == PARSE_OK) { /* nothing */ } else if(memptr_cmp_nocase(&timeout_hdr, "Second-infinite") == 0) { /* infinite timeout */ time_out = -1; } else { /* default is > 1800 seconds */ time_out = DEFAULT_TIMEOUT; } } /* replace infinite timeout with max timeout, if possible */ if (handle_info->MaxSubscriptionTimeOut != -1) { if (time_out == -1 || time_out > handle_info->MaxSubscriptionTimeOut) { time_out = handle_info->MaxSubscriptionTimeOut; } } if (time_out >= 0) { sub->expireTime = time(NULL) + time_out; } else { /* infinite time */ sub->expireTime = 0; } /* generate SID */ uuid_create(&uid); upnp_uuid_unpack(&uid, temp_sid); rc = snprintf(sub->sid, sizeof(sub->sid), "uuid:%s", temp_sid); /* respond OK */ if (rc < 0 || (unsigned int) rc >= sizeof(sub->sid) || (respond_ok(info, time_out, sub, request) != UPNP_E_SUCCESS)) { freeSubscriptionList(sub); HandleUnlock(); goto exit_function; } /* add to subscription list */ sub->next = service->subscriptionList; service->subscriptionList = sub; service->TotalSubscriptions++; /* finally generate callback for init table dump */ UpnpSubscriptionRequest_strcpy_ServiceId(request_struct, service->serviceId); UpnpSubscriptionRequest_strcpy_UDN(request_struct, service->UDN); UpnpSubscriptionRequest_strcpy_SID(request_struct, sub->sid); /* copy callback */ callback_fun = handle_info->Callback; cookie = handle_info->Cookie; HandleUnlock(); /* make call back with request struct */ /* in the future should find a way of mainting that the handle */ /* is not unregistered in the middle of a callback */ callback_fun(UPNP_EVENT_SUBSCRIPTION_REQUEST, request_struct, cookie); exit_function: UpnpSubscriptionRequest_delete(request_struct); }