/************************************************************************ * Function : map_str_to_int * * Parameters : * IN const char* name ; string containing the name to be matched * IN size_t name_len ; size of the string to be matched * IN str_int_entry* table ; table of entries that need to be * matched. * IN int num_entries ; number of entries in the table that need * to be searched. * IN xboolean case_sensitive ; whether the case should be case * sensitive or not * * Description : Match the given name with names from the entries in the * table. Returns the index of the table when the entry is found. * * Return : int ; * index - On Success * -1 - On failure * * Note : ************************************************************************/ int map_str_to_int( IN const char *name, IN size_t name_len, IN str_int_entry * table, IN int num_entries, IN xboolean case_sensitive ) { int top, mid, bot; int cmp; memptr name_ptr; name_ptr.buf = ( char * )name; name_ptr.length = name_len; top = 0; bot = num_entries - 1; while( top <= bot ) { mid = ( top + bot ) / 2; if( case_sensitive ) { //cmp = strcmp( name, table[mid].name ); cmp = memptr_cmp( &name_ptr, table[mid].name ); } else { //cmp = strcasecmp( name, table[mid].name ); cmp = memptr_cmp_nocase( &name_ptr, table[mid].name ); } if( cmp > 0 ) { top = mid + 1; // look below mid } else if( cmp < 0 ) { bot = mid - 1; // look above mid } else // cmp == 0 { return mid; // match; return table index } } return -1; // header name not found }
void gena_process_subscription_renewal_request( SOCKINFO *info, http_message_t *request) { Upnp_SID sid; subscription *sub; int time_out = 1801; service_info *service; struct Handle_Info *handle_info; UpnpDevice_Handle device_handle; memptr temp_hdr; membuffer event_url_path; memptr timeout_hdr; /* if a CALLBACK or NT header is present, then it is an error */ if( httpmsg_find_hdr( request, HDR_CALLBACK, NULL ) != NULL || httpmsg_find_hdr( request, HDR_NT, NULL ) != NULL ) { error_respond( info, HTTP_BAD_REQUEST, request ); return; } /* get SID */ if( httpmsg_find_hdr( request, HDR_SID, &temp_hdr ) == NULL || temp_hdr.length > SID_SIZE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); return; } memcpy( sid, temp_hdr.buf, temp_hdr.length ); sid[temp_hdr.length] = '\0'; /* lookup service by eventURL */ membuffer_init( &event_url_path ); if( membuffer_append( &event_url_path, request->uri.pathquery.buff, request->uri.pathquery.size ) != 0 ) { error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request ); return; } HandleLock(); if (GetDeviceHandleInfoForPath(event_url_path.buf, info->foreign_sockaddr.ss_family, &device_handle, &handle_info, &service) != HND_DEVICE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); membuffer_destroy( &event_url_path ); HandleUnlock(); return; } membuffer_destroy( &event_url_path ); /* get subscription */ if( service == NULL || !service->active || ( ( sub = GetSubscriptionSID( sid, service ) ) == NULL ) ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); HandleUnlock(); return; } UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "Renew 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 ); RemoveSubscriptionSID( sub->sid, service ); HandleUnlock(); return; } /* 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 ) { time_out = -1; /* inifinite timeout */ } else { time_out = DEFAULT_TIMEOUT; /* default is > 1800 seconds */ } } /* 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 == -1 ) { sub->expireTime = 0; } else { sub->expireTime = time( NULL ) + time_out; } if( respond_ok( info, time_out, sub, request ) != UPNP_E_SUCCESS ) { RemoveSubscriptionSID( sub->sid, service ); } HandleUnlock(); }
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); }
/************************************************************************ * Function : gena_subscribe * * Parameters: * IN char *url: url of service to subscribe * INOUT int* timeout:subscription time desired (in secs) * IN char* renewal_sid:for renewal, this contains a currently h * held subscription SID. For first time * subscription, this must be NULL * OUT char** sid: SID returned by the subscription or renew msg * * Description: * This function subscribes or renew subscription * * Returns: int * return 0 if successful else returns appropriate error ***************************************************************************/ static int gena_subscribe( IN char *url, INOUT int *timeout, IN char *renewal_sid, OUT char **sid ) { int return_code; memptr sid_hdr, timeout_hdr; char timeout_str[25]; membuffer request; uri_type dest_url; http_parser_t response; *sid = NULL; // init // request timeout to string if( ( timeout == NULL ) || ( ( *timeout > 0 ) && ( *timeout < CP_MINIMUM_SUBSCRIPTION_TIME ) ) ) { sprintf( timeout_str, "%d", CP_MINIMUM_SUBSCRIPTION_TIME ); } else if( *timeout >= 0 ) { sprintf( timeout_str, "%d", *timeout ); } else { strcpy( timeout_str, "infinite" ); } // parse url return_code = http_FixStrUrl( url, strlen( 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" "ssc" "c", HTTPMETHOD_SUBSCRIBE, &dest_url, "SID: ", renewal_sid, "TIMEOUT: Second-", timeout_str ); } else { // subscribe return_code = http_MakeMessage( &request, 1, 1, "q" "sssdsscc", HTTPMETHOD_SUBSCRIBE, &dest_url, "CALLBACK: <http://", LOCAL_HOST, ":", LOCAL_PORT, "/>\r\n" "NT: upnp:event\r\n" "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 if( matchstr( timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0", timeout ) == PARSE_OK ) { // nothing } else if( memptr_cmp_nocase( &timeout_hdr, "Second-infinite" ) == 0 ) { *timeout = -1; } else { httpmsg_destroy( &response.msg ); return UPNP_E_BAD_RESPONSE; } // save SID *sid = str_alloc( sid_hdr.buf, sid_hdr.length ); if( *sid == NULL ) { httpmsg_destroy( &response.msg ); return UPNP_E_OUTOF_MEMORY; } httpmsg_destroy( &response.msg ); return UPNP_E_SUCCESS; }
/*! * \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; int rc = 0; UpnpString_clear(sid); /* request timeout to string */ if (timeout == NULL) { timeout = &local_timeout; } if (*timeout < 0) { memset(timeout_str, 0, sizeof(timeout_str)); strncpy(timeout_str, "infinite", sizeof(timeout_str) - 1); } else if(*timeout < CP_MINIMUM_SUBSCRIPTION_TIME) { rc = snprintf(timeout_str, sizeof(timeout_str), "%d", CP_MINIMUM_SUBSCRIPTION_TIME); } else { rc = snprintf(timeout_str, sizeof(timeout_str), "%d", *timeout); } if (rc < 0 || (unsigned int) rc >= sizeof(timeout_str)) return UPNP_E_OUTOF_MEMORY; /* 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: ", UpnpString_get_String(renewal_sid), "TIMEOUT: Second-", timeout_str ); } else { /* subscribe */ if (dest_url.hostport.IPaddress.ss_family == AF_INET6) { struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&dest_url.hostport.IPaddress; return_code = http_MakeMessage( &request, 1, 1, "q" "sssdsc" "sc" "sscc", HTTPMETHOD_SUBSCRIBE, &dest_url, "CALLBACK: <http://[", (IN6_IS_ADDR_LINKLOCAL(&DestAddr6->sin6_addr) || strlen(gIF_IPV6_ULA_GUA) == 0) ? gIF_IPV6 : gIF_IPV6_ULA_GUA, "]:", 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; }