/************************************************************************ * Function : genaUnSubscribe * * Parameters: * IN UpnpClient_Handle client_handle: UPnP client handle * IN SID in_sid: The subscription ID * * Description: * This function unsubscribes a SID. It first validates the SID and * client_handle,copies the subscription, sends UNSUBSCRIBE http request * to service processes request and finally removes the subscription * * Returns: int * return UPNP_E_SUCCESS if service response is OK else * returns appropriate error ***************************************************************************/ int genaUnSubscribe( IN UpnpClient_Handle client_handle, IN const Upnp_SID in_sid ) { client_subscription *sub; int return_code = GENA_SUCCESS; struct Handle_Info *handle_info; client_subscription sub_copy; http_parser_t response; HandleLock( ); // validate handle and sid if( GetHandleInfo( client_handle, &handle_info ) != HND_CLIENT ) { HandleUnlock( ); return GENA_E_BAD_HANDLE; } if( ( sub = GetClientSubClientSID( handle_info->ClientSubList, in_sid ) ) == NULL ) { HandleUnlock( ); return GENA_E_BAD_SID; } return_code = copy_client_subscription( sub, &sub_copy ); HandleUnlock( ); return_code = gena_unsubscribe( sub_copy.EventURL, sub_copy.ActualSID, &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 GENA_E_BAD_HANDLE; } RemoveClientSubClientSID( &handle_info->ClientSubList, in_sid ); HandleUnlock( ); return return_code; }
//----------------------------------------------------------------------------- // Purpose: Calculates the center of an edge. // Input : pEdge - //----------------------------------------------------------------------------- void CSSolid::CalcEdgeCenter(CSSEdge *pEdge) { SSHANDLEINFO hi; GetHandleInfo(&hi, pEdge->hvStart); Vector &pt1 = m_Vertices[hi.iIndex].pos; GetHandleInfo(&hi, pEdge->hvEnd); Vector &pt2 = m_Vertices[hi.iIndex].pos; for (int i = 0; i < 3; i++) { pEdge->ptCenter[i] = (pt1[i] + pt2[i]) / 2.0f; } }
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; }
BOOL CSSolid::SplitFace(SSHANDLE h1, SSHANDLE h2) { SSHANDLEINFO hi; GetHandleInfo(&hi, h1); if(m_nFaces == MAX_FACES-1) return FALSE; BOOL bRvl = FALSE; if(hi.Type == shtEdge) { // edge-based face split bRvl = SplitFaceByEdges((CSSEdge*) hi.pData, (CSSEdge*) GetHandleData(h2)); } else if(hi.Type == shtVertex) { // vertex-based face split bRvl = SplitFaceByVertices((CSSVertex*) hi.pData, (CSSVertex*) GetHandleData(h2)); } return bRvl; }
// Create point list, but return indices instead of positions -> PINT CSSolid::CreatePointIndexList(CSSFace & face, PINT piPoints) { PINT pts; int nPts = 0; if(piPoints) pts = piPoints; else pts = new int[face.nEdges+1]; SSHANDLEINFO hi; for(int i = 0; i < face.nEdges; i++) { // calc next edge so we can see which is the next clockwise point int iNextEdge = i+1; if(iNextEdge == face.nEdges) iNextEdge = 0; CSSEdge * edgeCur = (CSSEdge*) GetHandleData(face.Edges[i]); CSSEdge * edgeNext = (CSSEdge*) GetHandleData(face.Edges[iNextEdge]); SSHANDLE hVertex = GetConnectionVertex(edgeCur, edgeNext); ASSERT(hVertex); GetHandleInfo(&hi, hVertex); pts[i] = hi.iIndex; } return pts; }
// 2D Hit Test -> SSHANDLE CSSolid::HitTest(CPoint pt, SSHANDLEINFO *pInfo) { SSHANDLE hnd = 0; // do a hit test on all handles: if(m_bShowVertices) for(int i = 0; i < m_nVertices; i++) { CSSVertex &v = m_Vertices[i]; if(PtInRect(&v.m_r, pt)) { hnd = v.id; break; } } if(!hnd && m_bShowEdges) for(int i = 0; i < m_nEdges; i++) { CSSEdge &e = m_Edges[i]; if(PtInRect(&e.m_r, pt)) { hnd = e.id; break; } } if(hnd && pInfo) GetHandleInfo(pInfo, hnd); return hnd; }
PVOID CSSolid::GetHandleData(SSHANDLE id) { SSHANDLEINFO hi; if(!GetHandleInfo(&hi, id)) return NULL; return hi.pData; }
/*! * \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; struct Upnp_Event_Subscribe *sub_struct = (struct Upnp_Event_Subscribe *)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; UpnpString *tmpSID = UpnpString_new(); if (AUTO_RENEW_TIME == 0) { UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUB EXPIRED"); sub_struct->ErrCode = UPNP_E_SUCCESS; send_callback = 1; eventType = UPNP_EVENT_SUBSCRIPTION_EXPIRED; } else { UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA AUTO RENEW"); timeout = sub_struct->TimeOut; UpnpString_set_String(tmpSID, sub_struct->Sid); errCode = genaRenewSubscription( event->handle, tmpSID, &timeout); sub_struct->ErrCode = errCode; sub_struct->TimeOut = 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); goto end_function; } 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); end_function: UpnpString_delete(tmpSID); return; }
/************************************************************************ * Function : GenaAutoRenewSubscription * * Parameters: * IN void *input: Thread data(upnp_timeout *) needed to send the renewal * * Description: * This is a thread function to send the renewal just before the * subscription times out. * * Returns: VOID * ***************************************************************************/ static void GenaAutoRenewSubscription( IN void *input ) { upnp_timeout *event = ( upnp_timeout * ) input; void *cookie; Upnp_FunPtr callback_fun; struct Handle_Info *handle_info; struct Upnp_Event_Subscribe *sub_struct = ( struct Upnp_Event_Subscribe * ) event->Event; int send_callback = 0; int eventType = 0; if( AUTO_RENEW_TIME == 0 ) { DBGONLY( UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUB EXPIRED" ) ); sub_struct->ErrCode = UPNP_E_SUCCESS; send_callback = 1; eventType = UPNP_EVENT_SUBSCRIPTION_EXPIRED; } else { DBGONLY( UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "GENA AUTO RENEW" ) ); if( ( ( sub_struct->ErrCode = genaRenewSubscription( event->handle, sub_struct-> Sid, &sub_struct-> TimeOut ) ) != UPNP_E_SUCCESS ) && ( sub_struct->ErrCode != GENA_E_BAD_SID ) && ( sub_struct->ErrCode != GENA_E_BAD_HANDLE ) ) { send_callback = 1; eventType = UPNP_EVENT_AUTORENEWAL_FAILED; } } if( send_callback ) { HandleLock( ); if( GetHandleInfo( event->handle, &handle_info ) != HND_CLIENT ) { HandleUnlock( ); free_upnp_timeout( event ); return; } DBGONLY( UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "HANDLE IS VALID" ) ); callback_fun = handle_info->Callback; cookie = handle_info->Cookie; HandleUnlock( ); //make callback callback_fun( eventType, event->Event, cookie ); } free_upnp_timeout( event ); }
// Move handle(s) to a new location -> void CSSolid::MoveSelectedHandles(const Vector &Delta) { SSHANDLE MoveVertices[128]; int nMoveVertices = 0; SSHANDLEINFO hi; for(int i = 0; i < m_nVertices; i++) { if(m_Vertices[i].m_bSelected) MoveVertices[nMoveVertices++] = m_Vertices[i].id; } for(i = 0; i < m_nEdges; i++) { CSSEdge* pEdge = &m_Edges[i]; if(!pEdge->m_bSelected) // make sure it's selected continue; // add edge's vertices to the movement list BOOL bAddStart = TRUE, bAddEnd = TRUE; for(int i2 = 0; i2 < nMoveVertices; i2++) { if(pEdge->hvStart == MoveVertices[i2]) bAddStart = FALSE; // already got this one if(pEdge->hvEnd == MoveVertices[i2]) bAddEnd = FALSE; // already got this one } if(bAddStart) MoveVertices[nMoveVertices++] = pEdge->hvStart; if(bAddEnd) MoveVertices[nMoveVertices++] = pEdge->hvEnd; } // move vertices now for(i = 0; i < nMoveVertices; i++) { GetHandleInfo(&hi, MoveVertices[i]); CSSVertex* pVertex = (CSSVertex*) hi.pData; SetVertexPosition(hi.iIndex, pVertex->pos[0] + Delta[0], pVertex->pos[1] + Delta[1], pVertex->pos[2] + Delta[2]); } // calculate center of moved edges int nEdges; CSSEdge ** ppEdges = FindAffectedEdges(MoveVertices, nMoveVertices, nEdges); for(i = 0; i < nEdges; i++) { CalcEdgeCenter(ppEdges[i]); } }
/************************************************************************ * Function : genaUnregisterClient * * Parameters: * IN UpnpClient_Handle client_handle: Handle containing all the control * point related information * * Description: * This function unsubcribes all the outstanding subscriptions and cleans * the subscription list. This function is called when control point * unregisters. * * Returns: int * return UPNP_E_SUCCESS if successful else returns appropriate error ***************************************************************************/ int genaUnregisterClient( IN UpnpClient_Handle client_handle ) { client_subscription sub_copy; 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 GENA_E_BAD_HANDLE; } if( handle_info->ClientSubList == NULL ) { return_code = UPNP_E_SUCCESS; break; } return_code = copy_client_subscription( handle_info->ClientSubList, &sub_copy ); if( return_code != HTTP_SUCCESS ) { break; } RemoveClientSubClientSID( &handle_info->ClientSubList, sub_copy.sid ); HandleUnlock( ); return_code = gena_unsubscribe( sub_copy.EventURL, sub_copy.ActualSID, &response ); if( return_code == 0 ) { httpmsg_destroy( &response.msg ); } free_client_subscription( &sub_copy ); } freeClientSubList( handle_info->ClientSubList ); HandleUnlock( ); return return_code; }
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; }
/*! * \brief Unregisters a device. * * \return UPNP_E_SUCCESS on success, GENA_E_BAD_HANDLE on failure. */ int genaUnregisterDevice( /*! [in] Device handle. */ UpnpDevice_Handle device_handle) { int ret = 0; struct Handle_Info *handle_info; HandleLock(); if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) { UpnpPrintf(UPNP_CRITICAL, GENA, __FILE__, __LINE__, "genaUnregisterDevice: BAD Handle: %d\n", device_handle); ret = GENA_E_BAD_HANDLE; } else { freeServiceTable(&handle_info->ServiceTable); ret = UPNP_E_SUCCESS; } HandleUnlock(); return ret; }
/* We take ownership of propertySet and will free it */ static int genaNotifyAllCommon( UpnpDevice_Handle device_handle, char *UDN, char *servId, DOMString propertySet) { int ret = GENA_SUCCESS; int line = 0; int *reference_count = NULL; char *UDN_copy = NULL; char *servId_copy = NULL; char *headers = NULL; notify_thread_struct *thread_struct = NULL; subscription *finger = NULL; service_info *service = NULL; struct Handle_Info *handle_info; UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA BEGIN NOTIFY ALL COMMON"); /* Keep this allocation first */ reference_count = (int *)malloc(sizeof (int)); if (reference_count == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } *reference_count = 0; UDN_copy = strdup(UDN); if (UDN_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } servId_copy = strdup(servId); if( servId_copy == NULL ) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } headers = AllocGenaHeaders(propertySet); if (headers == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } HandleLock(); if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) { line = __LINE__; ret = GENA_E_BAD_HANDLE; } else { service = FindServiceId(&handle_info->ServiceTable, servId, UDN); if (service != NULL) { finger = GetFirstSubscription(service); while (finger) { ThreadPoolJob *job = NULL; ListNode *node; thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct)); if (thread_struct == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; break; } (*reference_count)++; thread_struct->reference_count = reference_count; thread_struct->UDN = UDN_copy; thread_struct->servId = servId_copy; thread_struct->headers = headers; thread_struct->propertySet = propertySet; memset(thread_struct->sid, 0, sizeof(thread_struct->sid)); strncpy(thread_struct->sid, finger->sid, sizeof(thread_struct->sid) - 1); thread_struct->ctime = time(0); thread_struct->device_handle = device_handle; maybeDiscardEvents(&finger->outgoing); job = (ThreadPoolJob *)malloc(sizeof(ThreadPoolJob)); if (job == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; break; } memset(job, 0, sizeof(ThreadPoolJob)); TPJobInit(job, (start_routine)genaNotifyThread, thread_struct); TPJobSetFreeFunction(job, (free_routine)free_notify_struct); TPJobSetPriority(job, MED_PRIORITY); node = ListAddTail(&finger->outgoing, job); /* If there is only one element on the list (which we just added), need to kickstart the threadpool */ if (ListSize(&finger->outgoing) == 1) { ret = ThreadPoolAdd(&gSendThreadPool, job, NULL); if (ret != 0) { line = __LINE__; if (ret == EOUTOFMEM) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } break; } if (node) { ((ThreadPoolJob *)(node->item))->jobId = STALE_JOBID; } } finger = GetNextSubscription(service, finger); } } else { line = __LINE__; ret = GENA_E_BAD_SERVICE; } } ExitFunction: /* The only case where we want to free memory here is if the struct was never queued. Else, let the normal cleanup take place. reference_count is allocated first so it's ok to do nothing if it's 0 */ if (reference_count && *reference_count == 0) { free(headers); ixmlFreeDOMString(propertySet); free(servId_copy); free(UDN_copy); free(reference_count); } HandleUnlock(); UpnpPrintf(UPNP_INFO, GENA, __FILE__, line, "GENA END NOTIFY ALL COMMON, ret = %d", ret); return ret; }
/* We take ownership of propertySet and will free it */ static int genaInitNotifyCommon( UpnpDevice_Handle device_handle, char *UDN, char *servId, DOMString propertySet, const Upnp_SID sid) { int ret = GENA_SUCCESS; int line = 0; int *reference_count = NULL; char *UDN_copy = NULL; char *servId_copy = NULL; char *headers = NULL; notify_thread_struct *thread_struct = NULL; subscription *sub = NULL; service_info *service = NULL; struct Handle_Info *handle_info; ThreadPoolJob *job = NULL; UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA BEGIN INITIAL NOTIFY COMMON"); job = (ThreadPoolJob *)malloc(sizeof(ThreadPoolJob)); if (job == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } memset(job, 0, sizeof(ThreadPoolJob)); reference_count = (int *)malloc(sizeof (int)); if (reference_count == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } *reference_count = 0; UDN_copy = strdup(UDN); if (UDN_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } servId_copy = strdup(servId); if (servId_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } HandleLock(); if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) { line = __LINE__; ret = GENA_E_BAD_HANDLE; goto ExitFunction; } service = FindServiceId(&handle_info->ServiceTable, servId, UDN); if (service == NULL) { line = __LINE__; ret = GENA_E_BAD_SERVICE; goto ExitFunction; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "FOUND SERVICE IN INIT NOTFY: UDN %s, ServID: %s", UDN, servId); sub = GetSubscriptionSID(sid, service); if (sub == NULL || sub->active) { line = __LINE__; ret = GENA_E_BAD_SID; goto ExitFunction; } UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "FOUND SUBSCRIPTION IN INIT NOTIFY: SID %s", sid); sub->active = 1; headers = AllocGenaHeaders(propertySet); if (headers == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } /* schedule thread for initial notification */ thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct)); if (thread_struct == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } else { *reference_count = 1; thread_struct->servId = servId_copy; thread_struct->UDN = UDN_copy; thread_struct->headers = headers; thread_struct->propertySet = propertySet; memset(thread_struct->sid, 0, sizeof(thread_struct->sid)); strncpy(thread_struct->sid, sid, sizeof(thread_struct->sid) - 1); thread_struct->ctime = time(0); thread_struct->reference_count = reference_count; thread_struct->device_handle = device_handle; TPJobInit(job, (start_routine)genaNotifyThread, thread_struct); TPJobSetFreeFunction(job, (free_routine)free_notify_struct); TPJobSetPriority(job, MED_PRIORITY); ret = ThreadPoolAdd(&gSendThreadPool, job, NULL); if (ret != 0) { if (ret == EOUTOFMEM) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } } else { ListNode *node = ListAddTail(&sub->outgoing, job); if (node != NULL) { ((ThreadPoolJob *)node->item)->jobId = STALE_JOBID; line = __LINE__; ret = GENA_SUCCESS; } else { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } } } ExitFunction: if (ret != GENA_SUCCESS) { free(job); free(thread_struct); free(headers); ixmlFreeDOMString(propertySet); free(servId_copy); free(UDN_copy); free(reference_count); } HandleUnlock(); UpnpPrintf(UPNP_INFO, GENA, __FILE__, line, "GENA END INITIAL NOTIFY COMMON, ret = %d", ret); return ret; }
int genaNotifyAll( UpnpDevice_Handle device_handle, char *UDN, char *servId, char **VarNames, char **VarValues, int var_count) { int ret = GENA_SUCCESS; int line = 0; int *reference_count = NULL; char *UDN_copy = NULL; char *servId_copy = NULL; DOMString propertySet = NULL; char *headers = NULL; notify_thread_struct *thread_struct = NULL; subscription *finger = NULL; service_info *service = NULL; struct Handle_Info *handle_info; ThreadPoolJob job; memset(&job, 0, sizeof(job)); UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA BEGIN NOTIFY ALL"); reference_count = (int *)malloc(sizeof (int)); if (reference_count == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } *reference_count = 0; UDN_copy = strdup(UDN); if (UDN_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } servId_copy = strdup(servId); if( servId_copy == NULL ) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } ret = GeneratePropertySet(VarNames, VarValues, var_count, &propertySet); if (ret != XML_SUCCESS) { line = __LINE__; goto ExitFunction; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENERATED PROPERTY SET IN EXT NOTIFY: %s", propertySet); headers = AllocGenaHeaders(propertySet); if (headers == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } HandleLock(); if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) { line = __LINE__; ret = GENA_E_BAD_HANDLE; } else { service = FindServiceId(&handle_info->ServiceTable, servId, UDN); if (service != NULL) { finger = GetFirstSubscription(service); while (finger) { thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct)); if (thread_struct == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; break; } (*reference_count)++; thread_struct->reference_count = reference_count; thread_struct->UDN = UDN_copy; thread_struct->servId = servId_copy; thread_struct->headers = headers; thread_struct->propertySet = propertySet; memset(thread_struct->sid, 0, sizeof(thread_struct->sid)); strncpy(thread_struct->sid, finger->sid, sizeof(thread_struct->sid) - 1); thread_struct->eventKey = finger->eventKey++; thread_struct->device_handle = device_handle; /* if overflow, wrap to 1 */ if (finger->eventKey < 0) { finger->eventKey = 1; } TPJobInit(&job, (start_routine)genaNotifyThread, thread_struct); TPJobSetFreeFunction(&job, (free_routine)free_notify_struct); TPJobSetPriority(&job, MED_PRIORITY); ret = ThreadPoolAdd(&gSendThreadPool, &job, NULL); if (ret != 0) { line = __LINE__; if (ret == EOUTOFMEM) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } break; } finger = GetNextSubscription(service, finger); } } else { line = __LINE__; ret = GENA_E_BAD_SERVICE; } } ExitFunction: if (ret != GENA_SUCCESS || *reference_count == 0) { free(headers); ixmlFreeDOMString(propertySet); free(servId_copy); free(UDN_copy); free(reference_count); } HandleUnlock(); UpnpPrintf(UPNP_INFO, GENA, __FILE__, line, "GENA END NOTIFY ALL, ret = %d", ret); return ret; }
/*! * \brief Thread job to Notify a control point. * * It validates the subscription and copies the subscription. Also make sure * that events are sent in order. * * \note calls the genaNotify to do the actual work. */ static void genaNotifyThread( /*! [in] notify thread structure containing all the headers and property set info. */ void *input) { subscription *sub; service_info *service; subscription sub_copy; notify_thread_struct *in = (notify_thread_struct *) input; int return_code; struct Handle_Info *handle_info; /* This should be a HandleLock and not a HandleReadLock otherwise if there * is a lot of notifications, then multiple threads will acquire a read * lock and the thread which sends the notification will be blocked forever * on the HandleLock at the end of this function. */ /*HandleReadLock(); */ HandleLock(); /* validate context */ if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) { free_notify_struct(in); HandleUnlock(); return; } if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) || !service->active || !(sub = GetSubscriptionSID(in->sid, service)) || copy_subscription(sub, &sub_copy) != HTTP_SUCCESS) { free_notify_struct(in); HandleUnlock(); return; } HandleUnlock(); /* send the notify */ return_code = genaNotify(in->headers, in->propertySet, &sub_copy); freeSubscription(&sub_copy); HandleLock(); if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) { free_notify_struct(in); HandleUnlock(); return; } /* validate context */ if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) || !service->active || !(sub = GetSubscriptionSID(in->sid, service))) { free_notify_struct(in); HandleUnlock(); return; } sub->ToSendEventKey++; if (sub->ToSendEventKey < 0) /* wrap to 1 for overflow */ sub->ToSendEventKey = 1; /* Remove head of event queue. Possibly activate next */ { ListNode *node = ListHead(&sub->outgoing); if (node) ListDelNode(&sub->outgoing, node, 1); if (ListSize(&sub->outgoing) > 0) { ThreadPoolJob *job; ListNode *node = ListHead(&sub->outgoing); job = (ThreadPoolJob*)node->item; /* The new head of queue should not have already been added to the pool, else something is very wrong */ assert(job->jobId != STALE_JOBID); ThreadPoolAdd(&gSendThreadPool, job, NULL); job->jobId = STALE_JOBID; } } if (return_code == GENA_E_NOTIFY_UNACCEPTED_REMOVE_SUB) RemoveSubscriptionSID(in->sid, service); free_notify_struct(in); HandleUnlock(); }
/*! * \brief Thread job to Notify a control point. * * It validates the subscription and copies the subscription. Also make sure * that events are sent in order. * * \note calls the genaNotify to do the actual work. */ static void genaNotifyThread( /*! [in] notify thread structure containing all the headers and property set info. */ void *input) { subscription *sub; service_info *service; subscription sub_copy; notify_thread_struct *in = (notify_thread_struct *) input; int return_code; struct Handle_Info *handle_info; ThreadPoolJob job; memset(&job, 0, sizeof(job)); /* This should be a HandleLock and not a HandleReadLock otherwise if there * is a lot of notifications, then multiple threads will acquire a read * lock and the thread which sends the notification will be blocked forever * on the HandleLock at the end of this function. */ /*HandleReadLock(); */ HandleLock(); /* validate context */ if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) { free_notify_struct(in); HandleUnlock(); return; } if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) || !service->active || !(sub = GetSubscriptionSID(in->sid, service)) || copy_subscription(sub, &sub_copy) != HTTP_SUCCESS) { free_notify_struct(in); HandleUnlock(); return; } #ifdef UPNP_ENABLE_NOTIFICATION_REORDERING /*If the event is out of order push it back to the job queue */ if (in->eventKey != sub->ToSendEventKey) { TPJobInit(&job, (start_routine) genaNotifyThread, input); TPJobSetFreeFunction(&job, (free_function) free_notify_struct); TPJobSetPriority(&job, MED_PRIORITY); /* Sleep a little before creating another thread otherwise if there is * a lot of notifications to send, the device will take 100% of the CPU * to create threads and push them back to the job queue. */ imillisleep(1); ThreadPoolAdd(&gSendThreadPool, &job, NULL); freeSubscription(&sub_copy); HandleUnlock(); return; } #endif HandleUnlock(); /* send the notify */ return_code = genaNotify(in->headers, in->propertySet, &sub_copy); freeSubscription(&sub_copy); HandleLock(); if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) { free_notify_struct(in); HandleUnlock(); return; } /* validate context */ if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) || !service->active || !(sub = GetSubscriptionSID(in->sid, service))) { free_notify_struct(in); HandleUnlock(); return; } sub->ToSendEventKey++; if (sub->ToSendEventKey < 0) /* wrap to 1 for overflow */ sub->ToSendEventKey = 1; if (return_code == GENA_E_NOTIFY_UNACCEPTED_REMOVE_SUB) RemoveSubscriptionSID(in->sid, service); free_notify_struct(in); HandleUnlock(); }
int genaInitNotifyExt( UpnpDevice_Handle device_handle, char *UDN, char *servId, IXML_Document *PropSet, const Upnp_SID sid) { int ret = GENA_SUCCESS; int line = 0; int *reference_count = NULL; char *UDN_copy = NULL; char *servId_copy = NULL; DOMString propertySet = NULL; char *headers = NULL; notify_thread_struct *thread_struct = NULL; subscription *sub = NULL; service_info *service = NULL; struct Handle_Info *handle_info; ThreadPoolJob job; memset(&job, 0, sizeof(job)); UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA BEGIN INITIAL NOTIFY EXT"); reference_count = (int *)malloc(sizeof (int)); if (reference_count == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } *reference_count = 0; UDN_copy = strdup(UDN); if (UDN_copy == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } servId_copy = strdup(servId); if( servId_copy == NULL ) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } HandleLock(); if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) { line = __LINE__; ret = GENA_E_BAD_HANDLE; goto ExitFunction; } service = FindServiceId(&handle_info->ServiceTable, servId, UDN); if (service == NULL) { line = __LINE__; ret = GENA_E_BAD_SERVICE; goto ExitFunction; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "FOUND SERVICE IN INIT NOTFY EXT: UDN %s, ServID: %s", UDN, servId); sub = GetSubscriptionSID(sid, service); if (sub == NULL || sub->active) { line = __LINE__; ret = GENA_E_BAD_SID; goto ExitFunction; } UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "FOUND SUBSCRIPTION IN INIT NOTIFY EXT: SID %s", sid); sub->active = 1; if (PropSet == 0) { line = __LINE__; ret = GENA_SUCCESS; goto ExitFunction; } propertySet = ixmlPrintNode((IXML_Node *)PropSet); if (propertySet == NULL) { line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto ExitFunction; } UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENERATED PROPERTY SET IN INIT EXT NOTIFY: %s", propertySet); headers = AllocGenaHeaders(propertySet); if (headers == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; goto ExitFunction; } /* schedule thread for initial notification */ thread_struct = (notify_thread_struct *)malloc(sizeof (notify_thread_struct)); if (thread_struct == NULL) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } else { *reference_count = 1; thread_struct->servId = servId_copy; thread_struct->UDN = UDN_copy; thread_struct->headers = headers; thread_struct->propertySet = propertySet; memset(thread_struct->sid, 0, sizeof(thread_struct->sid)); strncpy(thread_struct->sid, sid, sizeof(thread_struct->sid) - 1); thread_struct->eventKey = sub->eventKey++; thread_struct->reference_count = reference_count; thread_struct->device_handle = device_handle; TPJobInit(&job, (start_routine)genaNotifyThread, thread_struct); TPJobSetFreeFunction(&job, (free_routine)free_notify_struct); TPJobSetPriority(&job, MED_PRIORITY); ret = ThreadPoolAdd(&gSendThreadPool, &job, NULL); if (ret != 0) { if (ret == EOUTOFMEM) { line = __LINE__; ret = UPNP_E_OUTOF_MEMORY; } } else { line = __LINE__; ret = GENA_SUCCESS; } } ExitFunction: if (ret != GENA_SUCCESS || PropSet == 0) { free(thread_struct); free(headers); ixmlFreeDOMString(propertySet); free(servId_copy); free(UDN_copy); free(reference_count); } HandleUnlock(); UpnpPrintf(UPNP_INFO, GENA, __FILE__, line, "GENA END INITIAL NOTIFY EXT, ret = %d", ret); return ret; }
/************************************************************************ * Function : genaRenewSubscription * * Parameters: * IN UpnpClient_Handle client_handle: Client handle * IN const Upnp_SID in_sid: subscription ID * INOUT int * TimeOut: requested Duration, if -1, then "infinite". * in the OUT case: actual Duration granted * by Service, -1 for infinite * * Description: * This function renews a SID. It first validates the SID and * client_handle and copies the subscription. It sends RENEW * (modified SUBSCRIBE) http request to service and processes * the response. * * Returns: int * return UPNP_E_SUCCESS if service response is OK else * returns appropriate error ***************************************************************************/ int genaRenewSubscription( IN UpnpClient_Handle client_handle, IN const Upnp_SID in_sid, INOUT int *TimeOut ) { int return_code = GENA_SUCCESS; client_subscription *sub; client_subscription sub_copy; struct Handle_Info *handle_info; char *ActualSID; ThreadPoolJob tempJob; HandleLock( ); // validate handle and sid if( GetHandleInfo( client_handle, &handle_info ) != HND_CLIENT ) { HandleUnlock( ); return GENA_E_BAD_HANDLE; } if( ( sub = GetClientSubClientSID( handle_info->ClientSubList, in_sid ) ) == NULL ) { HandleUnlock( ); return GENA_E_BAD_SID; } // remove old events if( TimerThreadRemove( &gTimerThread, sub->RenewEventId, &tempJob ) == 0 ) { free_upnp_timeout( ( upnp_timeout * ) tempJob.arg ); } DBGONLY( UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "REMOVED AUTO RENEW EVENT" ) ); sub->RenewEventId = -1; return_code = copy_client_subscription( sub, &sub_copy ); HandleUnlock( ); if( return_code != HTTP_SUCCESS ) { return return_code; } return_code = gena_subscribe( sub_copy.EventURL, TimeOut, sub_copy.ActualSID, &ActualSID ); HandleLock( ); if( GetHandleInfo( client_handle, &handle_info ) != HND_CLIENT ) { HandleUnlock( ); if( return_code == UPNP_E_SUCCESS ) { free( ActualSID ); } return GENA_E_BAD_HANDLE; } // 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( ); return return_code; } // get subscription if( ( sub = GetClientSubClientSID( handle_info->ClientSubList, in_sid ) ) == NULL ) { free( ActualSID ); free_client_subscription( &sub_copy ); HandleUnlock( ); return GENA_E_BAD_SID; } // store actual sid free( sub->ActualSID ); sub->ActualSID = ActualSID; // start renew subscription timer return_code = ScheduleGenaAutoRenew( client_handle, *TimeOut, sub ); if( return_code != GENA_SUCCESS ) { RemoveClientSubClientSID( &handle_info->ClientSubList, sub->sid ); } free_client_subscription( &sub_copy ); HandleUnlock( ); return return_code; }
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; int rc = 0; memset(temp_sid, 0, sizeof(temp_sid)); memset(temp_sid2, 0, sizeof(temp_sid2)); UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUBSCRIBE BEGIN"); UpnpString_clear(out_sid); HandleReadLock(); /* validate handle */ if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) { return_code = GENA_E_BAD_HANDLE; SubscribeLock(); goto error_handler; } 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); rc = snprintf(temp_sid2, sizeof(temp_sid2), "uuid:%s", temp_sid); if (rc < 0 || (unsigned int) rc >= sizeof(temp_sid2)) { return_code = UPNP_E_OUTOF_MEMORY; goto error_handler; } 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: UpnpString_delete(ActualSID); UpnpString_delete(EventURL); if (return_code != UPNP_E_SUCCESS) UpnpClientSubscription_delete(newSubscription); HandleUnlock(); SubscribeUnlock(); return return_code; }
/************************************************************************ * Function : genaSubscribe * * Parameters: * IN UpnpClient_Handle client_handle: * IN char * PublisherURL: NULL Terminated, of the form : * "http://134.134.156.80:4000/RedBulb/Event" * INOUT int * TimeOut: requested Duration, if -1, then "infinite". * in the OUT case: actual Duration granted * by Service, -1 for infinite * OUT Upnp_SID out_sid:sid of subscription, memory passed in by caller * * Description: * This function subscribes to a PublisherURL ( also mentioned as EventURL * some places). It sends SUBSCRIBE http request to service processes * request. Finally adds a Subscription to * the clients subscription list, if service responds with OK * * Returns: int * return UPNP_E_SUCCESS if service response is OK else * returns appropriate error ***************************************************************************/ int genaSubscribe( IN UpnpClient_Handle client_handle, IN char *PublisherURL, INOUT int *TimeOut, OUT Upnp_SID out_sid ) { int return_code = GENA_SUCCESS; client_subscription *newSubscription = NULL; uuid_upnp uid; Upnp_SID temp_sid; char *ActualSID = NULL; struct Handle_Info *handle_info; char *EventURL = NULL; DBGONLY( UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUBSCRIBE BEGIN" ) ); HandleLock( ); memset( out_sid, 0, sizeof( Upnp_SID ) ); // 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 ) { DBGONLY( 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( out_sid, "uuid:%s", temp_sid ); // create event url EventURL = ( char * )malloc( strlen( PublisherURL ) + 1 ); if( EventURL == NULL ) { return_code = UPNP_E_OUTOF_MEMORY; goto error_handler; } strcpy( EventURL, PublisherURL ); // fill subscription newSubscription = ( client_subscription * ) malloc( sizeof( client_subscription ) ); if( newSubscription == NULL ) { return_code = UPNP_E_OUTOF_MEMORY; goto error_handler; } newSubscription->EventURL = EventURL; newSubscription->ActualSID = ActualSID; strcpy( newSubscription->sid, out_sid ); newSubscription->RenewEventId = -1; newSubscription->next = 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 ) { free( ActualSID ); free( EventURL ); free( newSubscription ); } HandleUnlock( ); SubscribeUnlock( ); return return_code; }
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; }
int AdvertiseAndReply(int AdFlag, UpnpDevice_Handle Hnd, enum SsdpSearchType SearchType, struct sockaddr *DestAddr, char *DeviceType, char *DeviceUDN, char *ServiceType, int Exp) { int retVal = UPNP_E_SUCCESS; long unsigned int i; long unsigned int j; int defaultExp = DEFAULT_MAXAGE; struct Handle_Info *SInfo = NULL; char UDNstr[100]; char devType[100]; char servType[100]; IXML_NodeList *nodeList = NULL; IXML_NodeList *tmpNodeList = NULL; IXML_Node *tmpNode = NULL; IXML_Node *tmpNode2 = NULL; IXML_Node *textNode = NULL; const DOMString tmpStr; const DOMString dbgStr; int NumCopy = 0; memset(UDNstr, 0, sizeof(UDNstr)); memset(devType, 0, sizeof(devType)); memset(servType, 0, sizeof(servType)); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside AdvertiseAndReply with AdFlag = %d\n", AdFlag); /* Use a read lock */ HandleReadLock(); if (GetHandleInfo(Hnd, &SInfo) != HND_DEVICE) { retVal = UPNP_E_INVALID_HANDLE; goto end_function; } defaultExp = SInfo->MaxAge; /* parse the device list and send advertisements/replies */ while (NumCopy == 0 || (AdFlag && NumCopy < NUM_SSDP_COPY)) { if (NumCopy != 0) imillisleep(SSDP_PAUSE); NumCopy++; for (i = 0lu;; i++) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Entering new device list with i = %lu\n\n", i); tmpNode = ixmlNodeList_item(SInfo->DeviceList, i); if (!tmpNode) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting new device list with i = %lu\n\n", i); break; } dbgStr = ixmlNode_getNodeName(tmpNode); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Extracting device type once for %s\n", dbgStr); ixmlNodeList_free(nodeList); nodeList = ixmlElement_getElementsByTagName((IXML_Element *) tmpNode, "deviceType"); if (!nodeList) continue; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting UDN for %s\n", dbgStr); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting device type\n"); tmpNode2 = ixmlNodeList_item(nodeList, 0lu); if (!tmpNode2) continue; textNode = ixmlNode_getFirstChild(tmpNode2); if (!textNode) continue; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting device type \n"); tmpStr = ixmlNode_getNodeValue(textNode); if (!tmpStr) continue; strncpy(devType, tmpStr, sizeof(devType) - 1); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting device type = %s\n", devType); if (!tmpNode) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "TempNode is NULL\n"); } dbgStr = ixmlNode_getNodeName(tmpNode); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Extracting UDN for %s\n", dbgStr); ixmlNodeList_free(nodeList); nodeList = ixmlElement_getElementsByTagName((IXML_Element *) tmpNode, "UDN"); if (!nodeList) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UDN not found!\n"); continue; } tmpNode2 = ixmlNodeList_item(nodeList, 0lu); if (!tmpNode2) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UDN not found!\n"); continue; } textNode = ixmlNode_getFirstChild(tmpNode2); if (!textNode) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UDN not found!\n"); continue; } tmpStr = ixmlNode_getNodeValue(textNode); if (!tmpStr) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UDN not found!\n"); continue; } strncpy(UDNstr, tmpStr, sizeof(UDNstr) - 1); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Sending UDNStr = %s \n", UDNstr); if (AdFlag) { /* send the device advertisement */ if (AdFlag == 1) { DeviceAdvertisement(devType, i == 0lu, NumCopy - 1, UDNstr, SInfo->DescURL, Exp, SInfo->DeviceAf, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else { /* AdFlag == -1 */ DeviceShutdown(devType, i == 0lu, NumCopy - 1, UDNstr, SInfo->DescURL, Exp, SInfo->DeviceAf, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } } else { switch (SearchType) { case SSDP_ALL: DeviceReply(DestAddr, devType, i == 0lu, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); break; case SSDP_ROOTDEVICE: if (i == 0lu) { SendReply(DestAddr, devType, 1, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, 0, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } break; case SSDP_DEVICEUDN: { if (DeviceUDN && strlen(DeviceUDN) != (size_t)0) { if (strcasecmp(DeviceUDN, UDNstr)) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceUDN=%s and search UDN=%s DID NOT match\n", UDNstr, DeviceUDN); break; } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceUDN=%s and search UDN=%s MATCH\n", UDNstr, DeviceUDN); SendReply(DestAddr, devType, 0, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, 0, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); break; } } } case SSDP_DEVICETYPE: { if (!strncasecmp(DeviceType, devType, strlen(DeviceType) - (size_t)2)) { if (atoi(strrchr(DeviceType, ':') + 1) < atoi(&devType[strlen(devType) - (size_t)1])) { /* the requested version is lower than the device version * must reply with the lower version number and the lower * description URL */ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceType=%s and search devType=%s MATCH\n", devType, DeviceType); SendReply(DestAddr, DeviceType, 0, NumCopy - 1, UDNstr, SInfo->LowerDescURL, defaultExp, 1, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else if (atoi(strrchr(DeviceType, ':') + 1) == atoi(&devType[strlen(devType) - (size_t)1])) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceType=%s and search devType=%s MATCH\n", devType, DeviceType); SendReply(DestAddr, DeviceType, 0, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, 1, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceType=%s and search devType=%s DID NOT MATCH\n", devType, DeviceType); } } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceType=%s and search devType=%s DID NOT MATCH\n", devType, DeviceType); } break; } default: break; } } /* send service advertisements for services corresponding * to the same device */ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Sending service Advertisement\n"); /* Correct service traversal such that each device's serviceList * is directly traversed as a child of its parent device. This * ensures that the service's alive message uses the UDN of * the parent device. */ tmpNode = ixmlNode_getFirstChild(tmpNode); while (tmpNode) { dbgStr = ixmlNode_getNodeName(tmpNode); if (!strncmp (dbgStr, SERVICELIST_STR, sizeof SERVICELIST_STR)) { break; } tmpNode = ixmlNode_getNextSibling(tmpNode); } ixmlNodeList_free(nodeList); if (!tmpNode) { nodeList = NULL; continue; } nodeList = ixmlElement_getElementsByTagName((IXML_Element *) tmpNode, "service"); if (!nodeList) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Service not found 3\n"); continue; } for (j = 0lu;; j++) { tmpNode = ixmlNodeList_item(nodeList, j); if (!tmpNode) { break; } ixmlNodeList_free(tmpNodeList); tmpNodeList = ixmlElement_getElementsByTagName((IXML_Element *) tmpNode, "serviceType"); if (!tmpNodeList) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "ServiceType not found \n"); continue; } tmpNode2 = ixmlNodeList_item(tmpNodeList, 0lu); if (!tmpNode2) continue; textNode = ixmlNode_getFirstChild(tmpNode2); if (!textNode) continue; /* servType is of format Servicetype:ServiceVersion */ tmpStr = ixmlNode_getNodeValue(textNode); if (!tmpStr) continue; strncpy(servType, tmpStr, sizeof(servType) - 1); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType = %s\n", servType); if (AdFlag) { if (AdFlag == 1) { ServiceAdvertisement(NumCopy - 1, UDNstr, servType, SInfo->DescURL, Exp, SInfo->DeviceAf, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else { /* AdFlag == -1 */ ServiceShutdown(NumCopy - 1, UDNstr, servType, SInfo->DescURL, Exp, SInfo->DeviceAf, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } } else { switch (SearchType) { case SSDP_ALL: ServiceReply(DestAddr, servType, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); break; case SSDP_SERVICE: if (ServiceType) { if (!strncasecmp(ServiceType, servType, strlen(ServiceType) - (size_t)2)) { if (atoi(strrchr(ServiceType, ':') + 1) < atoi(&servType[strlen(servType) - (size_t)1])) { /* the requested version is lower than the service version * must reply with the lower version number and the lower * description URL */ UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType=%s and search servType=%s MATCH\n", ServiceType, servType); SendReply(DestAddr, ServiceType, 0, NumCopy - 1, UDNstr, SInfo->LowerDescURL, defaultExp, 1, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else if (atoi(strrchr (ServiceType, ':') + 1) == atoi(&servType[strlen(servType) - (size_t)1])) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType=%s and search servType=%s MATCH\n", ServiceType, servType); SendReply(DestAddr, ServiceType, 0, NumCopy - 1, UDNstr, SInfo->DescURL, defaultExp, 1, SInfo->PowerState, SInfo->SleepPeriod, SInfo->RegistrationState); } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType=%s and search servType=%s DID NOT MATCH\n", ServiceType, servType); } } else { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType=%s and search servType=%s DID NOT MATCH\n", ServiceType, servType); } } break; default: break; } } } ixmlNodeList_free(tmpNodeList); tmpNodeList = NULL; ixmlNodeList_free(nodeList); nodeList = NULL; } } end_function: ixmlNodeList_free(tmpNodeList); ixmlNodeList_free(nodeList); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting AdvertiseAndReply.\n"); HandleUnlock(); return retVal; }