/******************************************************************************** * SampleUtil_Print * * Description: * Provides platform-specific print functionality. This function should be * called when you want to print content suitable for console output (i.e., * in a large text box or on a screen). If your device/operating system is * not supported here, you should add a port. * * Parameters: * Same as printf() * ********************************************************************************/ int SampleUtil_Print( char *fmt, ... ) { va_list ap; char buf[200]; int rc; va_start( ap, fmt ); rc = vsnprintf( buf, 200, fmt, ap ); va_end( ap ); ithread_mutex_lock( &display_mutex ); if( gPrintFun ) gPrintFun( buf ); ithread_mutex_unlock( &display_mutex ); return rc; }
/******************************************************************************** * TvCtrlPointRemoveAll * * Description: * Remove all devices from the global device list. * * Parameters: * None * ********************************************************************************/ int TvCtrlPointRemoveAll(void) { struct TvDeviceNode *curdevnode, *next; ithread_mutex_lock(&DeviceListMutex); curdevnode = GlobalDeviceList; GlobalDeviceList = NULL; while (curdevnode) { next = curdevnode->next; TvCtrlPointDeleteNode(curdevnode); curdevnode = next; } ithread_mutex_unlock(&DeviceListMutex); return TV_SUCCESS; }
/****************************************************************************** * DestroyResult *****************************************************************************/ static int DestroyResult (BrowseResult* const br) { if (br) { if (br->cds && br->cds->cache) ithread_mutex_lock (&br->cds->cache_mutex); // Cached data will be really freed by talloc // when its reference count drops to zero. if (talloc_free (br->children) == 0) Log_Printf (LOG_DEBUG, "ContentDir CACHE_FREE"); if (br->cds && br->cds->cache) ithread_mutex_unlock (&br->cds->cache_mutex); *br = (BrowseResult) { }; } return 0; }
int SampleUtil_Print(const char *fmt, ...) { #define MAX_BUF (8 * 1024) va_list ap; static char buf[MAX_BUF]; int rc; /* Protect both the display and the static buffer with the mutex */ ithread_mutex_lock(&display_mutex); va_start(ap, fmt); rc = vsnprintf(buf, MAX_BUF, fmt, ap); va_end(ap); if (gPrintFun) gPrintFun("%s", buf); ithread_mutex_unlock(&display_mutex); return rc; }
/*----------------------------------------------------------------------------*/ void FlushMRDevices(void) { int i; for (i = 0; i < MAX_RENDERERS; i++) { if (glMRDevices[i].InUse) DelMRDevice(&glMRDevices[i]); } } /*----------------------------------------------------------------------------*/ void DelMRDevice(struct sMR *p) { int i = 0; ithread_mutex_lock(&p->Mutex); p->Running = false; ithread_join(p->Thread, NULL); p->InUse = false; FlushActionList(p);
/* Fuction:Print; INPUT: fmt -- strings to print; RETURN:The total length of strings; */ int SA_Print( char *fmt, ... ) { va_list ap; char buf[8000]; int rc = 0; va_start( ap, fmt ); #ifdef DEBUG rc = vsnprintf( buf, 8000, fmt, ap ); #endif va_end( ap ); ithread_mutex_lock( &display_mutex ); if( gPrintFun ) gPrintFun( buf ); ithread_mutex_unlock( &display_mutex ); return rc; }
/**************************************************************************** * Function: ThreadPoolGetAttr * * Description: * Gets the current set of attributes * associated with the thread pool. * Parameters: * tp - valid thread pool pointer * out - non null pointer to store attributes * Returns: * 0 on success, nonzero on failure * Always returns 0. *****************************************************************************/ int ThreadPoolGetAttr( ThreadPool *tp, ThreadPoolAttr *out ) { assert( tp != NULL ); assert( out != NULL ); if( tp == NULL || out == NULL ) { return EINVAL; } if( !tp->shutdown ) { ithread_mutex_lock( &tp->mutex ); } *out = tp->attr; if( !tp->shutdown ) { ithread_mutex_unlock( &tp->mutex ); } return 0; }
/******************************************************************************** * upnp_igd_handle_event * * Description: * Handle a uPnP event that was received. Process the event and update * the appropriate service state table. * * Parameters: * igd_ctxt -- The upnp igd context * sid -- The subscription id for the event * eventkey -- The eventkey number for the event * changes -- The DOM document representing the changes * ********************************************************************************/ void upnp_igd_handle_event(upnp_igd_context* igd_ctxt, const char *sid, int eventkey, IXML_Document *changes) { upnp_igd_device_node *tmpdevnode; int service; ithread_mutex_lock(&igd_ctxt->devices_mutex); tmpdevnode = igd_ctxt->devices; while (tmpdevnode) { for (service = 0; service < IGD_SERVICE_SERVCOUNT; ++service) { if (strcmp(tmpdevnode->device.services[service].sid, sid) == 0) { upnp_igd_print(igd_ctxt, UPNP_IGD_DEBUG, "Received IGD %s Event: %d for SID %s", IGDServiceName[service], eventkey, sid); upnp_igd_state_update(igd_ctxt, tmpdevnode, service, changes, (char **)&tmpdevnode->device.services[service].variables); break; } } tmpdevnode = tmpdevnode->next; } ithread_mutex_unlock(&igd_ctxt->devices_mutex); }
/***************************************************************************** * Log_Printf *****************************************************************************/ int Log_Printf (Log_Level level, const char* fmt, ... ) { if (Log_IsActivated (level) && fmt) { va_list ap; char buf[4096] = ""; va_start (ap, fmt); int rc = vsnprintf (buf, sizeof(buf), fmt, ap); va_end (ap); if (rc >= 0) { ithread_mutex_lock (&g_log_mutex); gPrintFun (level, buf); ithread_mutex_unlock (&g_log_mutex); } return rc; } return -1; }
void upnp_context_add_callback(upnp_igd_context *igd_ctxt, upnp_igd_event event, void *arg) { upnp_igd_callback_event_node *node, *list; if(igd_ctxt->callback_fct != NULL) { // Create the node node = (upnp_igd_callback_event_node *) malloc(sizeof(upnp_igd_callback_event_node)); node->event.event = event; node->event.arg = arg; node->next = NULL; ithread_mutex_lock(&igd_ctxt->callback_mutex); // Append to the list if(igd_ctxt->callback_events == NULL) { igd_ctxt->callback_events = node; } else { list = igd_ctxt->callback_events; while(list->next != NULL) list = list->next; list->next = node; } ithread_mutex_unlock(&igd_ctxt->callback_mutex); } }
int upnp_append_variable(struct action_event *event, int varnum, const char *paramname) { const char *value; struct service *service = event->service; int retval = -1; //ENTER(); assert(event != NULL); assert(paramname != NULL); if (varnum >= service->variable_count) { #ifdef HAVE_LIBUPNP upnp_set_error(event, UPNP_E_INTERNAL_ERROR, "Internal Error - illegal variable number %d", varnum); #endif goto out; } #ifdef HAVE_LIBUPNP ithread_mutex_lock(service->service_mutex); #endif #if 0 fprintf(stderr, "\tHZ: %s = '%s'\n", service->variable_names[varnum], service->variable_values[varnum]); #endif value = service->variable_values[varnum]; assert(value != NULL); retval = upnp_add_response(event, paramname, value); #ifdef HAVE_LIBUPNP ithread_mutex_unlock(service->service_mutex); #endif out: //LEAVE(); return retval; }
if (!Device->Actions) Device->Actions = Action; else { p = Device->Actions; while (p->Next) p = p->Next; p->Next = Action; } ithread_mutex_unlock(&Device->ActionsMutex); } /*----------------------------------------------------------------------------*/ struct sAction *UnQueueAction(struct sMR *Device, bool Keep) { struct sAction *p = NULL; if (Keep) return Device->Actions; ithread_mutex_lock(&Device->ActionsMutex); if (Device->Actions) { p = Device->Actions; Device->Actions = Device->Actions->Next; } ithread_mutex_unlock(&Device->ActionsMutex);
void UpnpPrintf( IN Upnp_LogLevel DLevel, IN Dbg_Module Module, IN const char *DbgFileName, IN int DbgLineNo, IN const char *FmtStr, ... ) { va_list ArgList; if (!DebugAtThisLevel(DLevel, Module)) { return; } ithread_mutex_lock(&GlobalDebugMutex); va_start(ArgList, FmtStr); if (!DEBUG_TARGET) { if( DbgFileName ) { UpnpDisplayFileAndLine(stdout, DbgFileName, DbgLineNo); } vfprintf(stdout, FmtStr, ArgList); fflush(stdout); } else if (DLevel == 0) { if (DbgFileName) { UpnpDisplayFileAndLine(ErrFileHnd, DbgFileName, DbgLineNo); } vfprintf(ErrFileHnd, FmtStr, ArgList); fflush(ErrFileHnd); } else { if (DbgFileName) { UpnpDisplayFileAndLine(InfoFileHnd, DbgFileName, DbgLineNo); } vfprintf(InfoFileHnd, FmtStr, ArgList); fflush(InfoFileHnd); } va_end(ArgList); ithread_mutex_unlock(&GlobalDebugMutex); }
/******************************************************************************** * upnp_igd_handle_subscribe_update * * Description: * Handle a uPnP subscription update that was received. Find the * service the update belongs to, and update its subscription * timeout. * * Parameters: * igd_ctxt -- The upnp igd context * event_url -- The event URL for the subscription * sid -- The subscription id for the subscription * timeout -- The new timeout for the subscription * ********************************************************************************/ void upnp_igd_handle_subscribe_update(upnp_igd_context* igd_ctxt, const char *event_url, const Upnp_SID sid, int timeout) { upnp_igd_device_node *tmpdevnode; int service; ithread_mutex_lock(&igd_ctxt->devices_mutex); tmpdevnode = igd_ctxt->devices; while (tmpdevnode) { for (service = 0; service < IGD_SERVICE_SERVCOUNT; service++) { if (strcmp(tmpdevnode->device.services[service].event_url, event_url) == 0) { upnp_igd_print(igd_ctxt, UPNP_IGD_DEBUG, "Received IGD %s Event Renewal for event_url %s", IGDServiceName[service], event_url); upnp_igd_strncpy(tmpdevnode->device.services[service].sid, sid, sizeof(tmpdevnode->device.services[service].sid)); break; } } tmpdevnode = tmpdevnode->next; } ithread_mutex_unlock(&igd_ctxt->devices_mutex); return; }
/******************************************************************************** * TvCtrlPointRemoveDevice * * Description: * Remove a device from the global device list. * * Parameters: * UDN -- The Unique Device Name for the device to remove * ********************************************************************************/ int TvCtrlPointRemoveDevice( char *UDN ) { struct TvDeviceNode *curdevnode, *prevdevnode; ithread_mutex_lock( &DeviceListMutex ); curdevnode = GlobalDeviceList; if( !curdevnode ) { SampleUtil_Print ( "WARNING: TvCtrlPointRemoveDevice: Device list empty" ); } else { if( 0 == strcmp( curdevnode->device.UDN, UDN ) ) { GlobalDeviceList = curdevnode->next; TvCtrlPointDeleteNode( curdevnode ); } else { prevdevnode = curdevnode; curdevnode = curdevnode->next; while( curdevnode ) { if( strcmp( curdevnode->device.UDN, UDN ) == 0 ) { prevdevnode->next = curdevnode->next; TvCtrlPointDeleteNode( curdevnode ); break; } prevdevnode = curdevnode; curdevnode = curdevnode->next; } } } ithread_mutex_unlock( &DeviceListMutex ); return TV_SUCCESS; }
/************************************************************************ * Function: TimerThreadRemove * * Description: * Removes an event from the timer Q. * Events can only be removed * before they have been placed in the * thread pool. * * Parameters: * timer - valid timer thread pointer. * id - id of event to remove. * out - space for returned job (Can be NULL) * Return: * 0 on success. * INVALID_EVENT_ID on error. * ************************************************************************/ int TimerThreadRemove( TimerThread * timer, int id, ThreadPoolJob * out ) { int rc = INVALID_EVENT_ID; ListNode *tempNode = NULL; TimerEvent *temp = NULL; assert( timer != NULL ); if( timer == NULL ) { return EINVAL; } ithread_mutex_lock( &timer->mutex ); tempNode = ListHead( &timer->eventQ ); while( tempNode != NULL ) { temp = ( TimerEvent * ) tempNode->item; if( temp->id == id ) { ListDelNode( &timer->eventQ, tempNode, 0 ); if( out != NULL ) ( *out ) = temp->job; FreeTimerEvent( timer, temp ); rc = 0; break; } tempNode = ListNext( &timer->eventQ, tempNode ); } ithread_mutex_unlock( &timer->mutex ); return rc; }
int RemoveMiniServerInterface(int iface) { char addr[INET_ADDRSTRLEN] = { "\0" }; uint16_t port = 0; if (iface < 0 || iface > MAX_NETWORK_INTERFACES) return UPNP_E_INVALID_PARAM; ithread_mutex_lock(&gMiniServerMutex); get_address(gMiniSocket->miniServerSock4[iface], addr); port = gMiniSocket->miniServerPort4[iface]; sock_close(gMiniSocket->miniServerSock4[iface]); gMiniSocket->miniServerSock4[iface] = INVALID_SOCKET; sock_close(gMiniSocket->ssdpSock4[iface]); gMiniSocket->ssdpSock4[iface] = INVALID_SOCKET; sock_close(gMiniSocket->ssdpReqSock4[iface]); gMiniSocket->ssdpReqSock4[iface] = INVALID_SOCKET; ithread_mutex_unlock(&gMiniServerMutex); wake_miniserver(); UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__, "RemoveMiniServerInterface: %s:%d removed successfully from slot %d", addr, port, iface); return UPNP_E_SUCCESS; }
DBG_STATIC int xplaymode(struct action_event *event) { char *newmode; int rc = 0; if (upnp_obtain_instanceid(event, NULL)) { upnp_set_error(event, UPNP_TRANSPORT_E_INVALID_IID, "ID non-zero invalid"); return -1; } newmode = upnp_get_string(event, "NewPlayMode"); DBG_PRINT(DBG_LVL4, "Set NewPlayMode: %s\n", newmode); // Check MPD connection if (check_mpd_connection(TRUE) == STATUS_FAIL) return -1; ithread_mutex_lock(&transport_mutex); rc = output_playmode(newmode); if (rc != 0) { free(newmode); upnp_set_error(event, UPNP_TRANSPORT_E_PLAYMODE_NS, "Set playmode failed"); goto out; } transport_change_var(event, TRANSPORT_VAR_CUR_PLAY_MODE, newmode); free(newmode); out: ithread_mutex_unlock(&transport_mutex); return rc; }
static int handle_action_request(struct upnp_device *priv, struct Upnp_Action_Request *ar_event) { struct service *event_service; struct action *event_action; event_service = find_service(priv->upnp_device_descriptor, ar_event->ServiceID); event_action = find_action(event_service, ar_event->ActionName); if (event_action == NULL) { Log_error("upnp", "Unknown action '%s' for service '%s'", ar_event->ActionName, ar_event->ServiceID); ar_event->ActionResult = NULL; ar_event->ErrCode = 401; return -1; } // We want to send the LastChange event only after the action is // finished - just to be conservative, we don't know how clients // react to get LastChange notifictions while in the middle of // issuing an action. // // So we nest the change collector level here, so that we only send the // LastChange after the action is finished (). // // Note, this is, in fact, only a preparation and not yet working as // described above: we are still in the middle // of executing the event-callback while sending the last change // event implicitly when calling UPnPLastChangeCollector_finish() below. // It would be good to enqueue the upnp_device_notify() after // the action event is finished. if (event_service->last_change) { ithread_mutex_lock(event_service->service_mutex); UPnPLastChangeCollector_start(event_service->last_change); ithread_mutex_unlock(event_service->service_mutex); } #ifdef ENABLE_ACTION_LOGGING { char *action_request_xml = NULL; if (ar_event->ActionRequest) { action_request_xml = ixmlDocumenttoString( ar_event->ActionRequest); } Log_info("upnp", "Action '%s'; Request: %s", ar_event->ActionName, action_request_xml); free(action_request_xml); } #endif if (event_action->callback) { struct action_event event; int rc; event.request = ar_event; event.status = 0; event.service = event_service; event.device = priv; rc = (event_action->callback) (&event); if (rc == 0) { ar_event->ErrCode = UPNP_E_SUCCESS; #ifdef ENABLE_ACTION_LOGGING if (ar_event->ActionResult) { char *action_result_xml = NULL; action_result_xml = ixmlDocumenttoString( ar_event->ActionResult); Log_info("upnp", "Action '%s' OK; Response %s", ar_event->ActionName, action_result_xml); free(action_result_xml); } else { Log_info("upnp", "Action '%s' OK", ar_event->ActionName); } #endif } if (ar_event->ActionResult == NULL) { ar_event->ActionResult = UpnpMakeActionResponse(ar_event->ActionName, event_service->service_type, 0, NULL); } } else { Log_error("upnp", "Got a valid action, but no handler defined (!)\n" " ErrCode: %d\n" " Socket: %d\n" " ErrStr: '%s'\n" " ActionName: '%s'\n" " DevUDN: '%s'\n" " ServiceID: '%s'\n", ar_event->ErrCode, ar_event->Socket, ar_event->ErrStr, ar_event->ActionName, ar_event->DevUDN, ar_event->ServiceID); ar_event->ErrCode = UPNP_E_SUCCESS; } if (event_service->last_change) { // See comment above. ithread_mutex_lock(event_service->service_mutex); UPnPLastChangeCollector_finish(event_service->last_change); ithread_mutex_unlock(event_service->service_mutex); } return 0; }
/******************************************************************************** * upnp_igd_add_device * * Description: * If the device is not already included in the global device list, * add it. Otherwise, update its advertisement expiration timeout. * * Parameters: * igd_ctxt -- The upnp igd context * desc_doc -- The description document for the device * d_event -- event associated with the new device * ********************************************************************************/ void upnp_igd_add_device(upnp_igd_context *igd_ctxt, IXML_Document *desc_doc, struct Upnp_Discovery *d_event) { upnp_igd_device_node *deviceNode, *tmpdevnode; int found = 0; int ret; int service, var; char presURL[200]; char *serviceId; char *event_url; char *controlURL; Upnp_SID eventSID; char *deviceType = NULL; char *friendlyName = NULL; char *modelName = NULL; char *modelNumber = NULL; char *baseURL = NULL; char *relURL = NULL; char *UDN = NULL; UDN = upnp_igd_get_first_document_item(igd_ctxt, desc_doc, "UDN"); deviceType = upnp_igd_get_first_document_item(igd_ctxt, desc_doc, "deviceType"); friendlyName = upnp_igd_get_first_document_item(igd_ctxt, desc_doc, "friendlyName"); modelName = upnp_igd_get_first_document_item(igd_ctxt, desc_doc, "modelName"); modelNumber = upnp_igd_get_first_document_item(igd_ctxt, desc_doc, "modelNumber"); baseURL = upnp_igd_get_first_document_item(igd_ctxt, desc_doc, "URLBase"); relURL = upnp_igd_get_first_document_item(igd_ctxt, desc_doc, "presentationURL"); ret = UpnpResolveURL((baseURL ? baseURL : d_event->Location), relURL, presURL); if (UPNP_E_SUCCESS != ret) { upnp_igd_print(igd_ctxt, UPNP_IGD_ERROR, "Error generating presURL from %s + %s", baseURL, relURL); } ithread_mutex_lock(&igd_ctxt->devices_mutex); if (strcmp(deviceType, IGDDeviceType) == 0) { /* Check if this device is already in the list */ tmpdevnode = igd_ctxt->devices; while (tmpdevnode) { if (strcmp(tmpdevnode->device.udn, UDN) == 0) { found = 1; break; } tmpdevnode = tmpdevnode->next; } if (found) { /* The device is already there, so just update */ /* the advertisement timeout field */ tmpdevnode->device.advr_time_out = d_event->Expires; upnp_igd_print(igd_ctxt, UPNP_IGD_DEBUG, "IGD device: %s[%s] | Update expires(%d)", friendlyName, UDN, tmpdevnode->device.advr_time_out); } else { upnp_igd_print(igd_ctxt, UPNP_IGD_MESSAGE, "Add IGD device: %s[%s]", friendlyName, UDN); /* Create a new device node */ deviceNode = (upnp_igd_device_node *) malloc(sizeof(upnp_igd_device_node)); memset(deviceNode->device.services, '\0', sizeof(upnp_igd_service) * IGD_SERVICE_SERVCOUNT); strncpy(deviceNode->device.udn, UDN, sizeof(deviceNode->device.udn)); strncpy(deviceNode->device.desc_doc_url, d_event->Location, sizeof(deviceNode->device.desc_doc_url)); strncpy(deviceNode->device.friendly_name, friendlyName, sizeof(deviceNode->device.friendly_name)); strncpy(deviceNode->device.model_name, modelName, sizeof(deviceNode->device.model_name)); strncpy(deviceNode->device.model_number, modelNumber, sizeof(deviceNode->device.model_number)); strncpy(deviceNode->device.pres_url, presURL, sizeof(deviceNode->device.pres_url)); deviceNode->device.advr_time_out = d_event->Expires; // Reset values serviceId = NULL; event_url = NULL; controlURL = NULL; eventSID[0] = '\0'; for (service = 0; service < IGD_SERVICE_SERVCOUNT; service++) { if (upnp_igd_get_find_and_parse_service(igd_ctxt, desc_doc, d_event->Location, IGDServiceType[service], &serviceId, &event_url, &controlURL)) { upnp_igd_print(igd_ctxt, UPNP_IGD_DEBUG, "Subscribing to EventURL %s...",event_url); ret = UpnpSubscribe(igd_ctxt->upnp_handle, event_url, &IGDTimeOut[service], eventSID); if (ret == UPNP_E_SUCCESS) { upnp_igd_print(igd_ctxt, UPNP_IGD_DEBUG, "Subscribed to EventURL with SID=%s", eventSID); } else { upnp_igd_print(igd_ctxt, UPNP_IGD_ERROR, "Error Subscribing to EventURL -- %d", ret); strcpy(eventSID, ""); } } else { upnp_igd_print(igd_ctxt, UPNP_IGD_ERROR, "Could not find Service: %s", IGDServiceType[service]); } if(serviceId != NULL) { upnp_igd_strncpy(deviceNode->device.services[service].service_id, serviceId, sizeof(deviceNode->device.services[service].service_id)); } upnp_igd_strncpy(deviceNode->device.services[service].service_type, IGDServiceName[service], sizeof(deviceNode->device.services[service].service_type)); if(controlURL != NULL) { upnp_igd_strncpy(deviceNode->device.services[service].control_url, controlURL, sizeof(deviceNode->device.services[service].control_url)); } if(event_url != NULL) { upnp_igd_strncpy(deviceNode->device.services[service].event_url, event_url, sizeof(deviceNode->device.services[service].event_url)); } if(eventSID != NULL) { upnp_igd_strncpy(deviceNode->device.services[service].sid, eventSID, sizeof(deviceNode->device.services[service].sid)); } for (var = 0; var < IGDVarCount[service]; var++) { deviceNode->device.services[service].variables[var] = (char *)malloc(IGD_MAX_VAL_LEN); strcpy(deviceNode->device.services[service].variables[var], ""); } } deviceNode->next = NULL; /* Insert the new device node in the list */ if ((tmpdevnode = igd_ctxt->devices)) { while (tmpdevnode) { if (tmpdevnode->next) { tmpdevnode = tmpdevnode->next; } else { tmpdevnode->next = deviceNode; break; } } } else { igd_ctxt->devices = deviceNode; } // Ask some details upnp_igd_send_action(igd_ctxt, deviceNode, IGD_SERVICE_WANIPCONNECTION, "GetNATRSIPStatus", NULL, NULL, 0, upnp_igd_callback, igd_ctxt); // Usefull on some router upnp_igd_send_action(igd_ctxt, deviceNode, IGD_SERVICE_WANIPCONNECTION, "GetStatusInfo", NULL, NULL, 0, upnp_igd_callback, igd_ctxt); upnp_igd_send_action(igd_ctxt, deviceNode, IGD_SERVICE_WANIPCONNECTION, "GetExternalIPAddress", NULL, NULL, 0, upnp_igd_callback, igd_ctxt); upnp_context_add_callback(igd_ctxt, UPNP_IGD_DEVICE_ADDED, NULL); if (serviceId) free(serviceId); if (controlURL) free(controlURL); if (event_url) free(event_url); } } ithread_mutex_unlock(&igd_ctxt->devices_mutex); if (deviceType) free(deviceType); if (friendlyName) free(friendlyName); if (modelName) free(modelName); if (modelNumber) free(modelNumber); if (UDN) free(UDN); if (baseURL) free(baseURL); if (relURL) free(relURL); }
/******************************************************************************** * upnp_igd_set_device_timeout * * Description: * Set devices lease time * * Parameters: * igd_ctxt -- The upnp igd context * seconds -- The number of seconds * ********************************************************************************/ void upnp_igd_set_devices_timeout(upnp_igd_context *igd_ctxt, int seconds) { ithread_mutex_lock(&igd_ctxt->mutex); igd_ctxt->max_adv_timeout = seconds; igd_ctxt->timer_timeout = igd_ctxt->max_adv_timeout/2; ithread_mutex_unlock(&igd_ctxt->mutex); }
/************************************************************************ * Function: TimerThreadSchedule * * Description: * Schedules an event to run at a specified time. * * Parameters: * timer - valid timer thread pointer. * time_t - time of event. * either in absolute seconds, * or relative seconds in the future. * timeoutType - either ABS_SEC, or REL_SEC. * if REL_SEC, then the event * will be scheduled at the * current time + REL_SEC. * * func - function to schedule * arg - argument to function * priority - priority of job. * id - id of timer event. (out) * Return: * 0 on success, nonzero on failure * EOUTOFMEM if not enough memory to schedule job ************************************************************************/ int TimerThreadSchedule( TimerThread * timer, time_t timeout, TimeoutType type, ThreadPoolJob * job, Duration duration, int *id ) { int rc = EOUTOFMEM; int found = 0; int tempId = 0; ListNode *tempNode = NULL; TimerEvent *temp = NULL; TimerEvent *newEvent = NULL; assert( timer != NULL ); assert( job != NULL ); if( ( timer == NULL ) || ( job == NULL ) ) { return EINVAL; } CalculateEventTime( &timeout, type ); ithread_mutex_lock( &timer->mutex ); if( id == NULL ) id = &tempId; ( *id ) = INVALID_EVENT_ID; newEvent = CreateTimerEvent( timer, job, duration, timeout, timer->lastEventId ); if( newEvent == NULL ) { ithread_mutex_unlock( &timer->mutex ); return rc; } tempNode = ListHead( &timer->eventQ ); //add job to Q //Q is ordered by eventTime //with the head of the Q being the next event while( tempNode != NULL ) { temp = ( TimerEvent * ) tempNode->item; if( temp->eventTime >= timeout ) { if( ListAddBefore( &timer->eventQ, newEvent, tempNode ) != NULL ) rc = 0; found = 1; break; } tempNode = ListNext( &timer->eventQ, tempNode ); } //add to the end of Q if( !found ) { if( ListAddTail( &timer->eventQ, newEvent ) != NULL ) rc = 0; } //signal change in Q if( rc == 0 ) { ithread_cond_signal( &timer->condition ); } else { FreeTimerEvent( timer, newEvent ); } ( *id ) = timer->lastEventId++; ithread_mutex_unlock( &timer->mutex ); return rc; }
/******************************************************************************** * SampleUtil_PrintEvent * * Description: * Prints callback event structure details. * * Parameters: * EventType -- The type of callback event * Event -- The callback event structure * ********************************************************************************/ int SampleUtil_PrintEvent( IN Upnp_EventType EventType, IN void *Event ) { ithread_mutex_lock( &display_mutex ); SampleUtil_Print ( "\n\n\n======================================================================\n" ); SampleUtil_Print ( "----------------------------------------------------------------------\n" ); SampleUtil_PrintEventType( EventType ); switch ( EventType ) { /* SSDP */ case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: case UPNP_DISCOVERY_SEARCH_RESULT: { struct Upnp_Discovery *d_event = ( struct Upnp_Discovery * )Event; SampleUtil_Print( "ErrCode = %d\n", d_event->ErrCode ); SampleUtil_Print( "Expires = %d\n", d_event->Expires ); SampleUtil_Print( "DeviceId = %s\n", d_event->DeviceId ); SampleUtil_Print( "DeviceType = %s\n", d_event->DeviceType ); SampleUtil_Print( "ServiceType = %s\n", d_event->ServiceType ); SampleUtil_Print( "ServiceVer = %s\n", d_event->ServiceVer ); SampleUtil_Print( "Location = %s\n", d_event->Location ); SampleUtil_Print( "OS = %s\n", d_event->Os ); SampleUtil_Print( "Ext = %s\n", d_event->Ext ); } break; case UPNP_DISCOVERY_SEARCH_TIMEOUT: // Nothing to print out here break; /* SOAP */ case UPNP_CONTROL_ACTION_REQUEST: { struct Upnp_Action_Request *a_event = ( struct Upnp_Action_Request * )Event; char *xmlbuff = NULL; SampleUtil_Print( "ErrCode = %d\n", a_event->ErrCode ); SampleUtil_Print( "ErrStr = %s\n", a_event->ErrStr ); SampleUtil_Print( "ActionName = %s\n", a_event->ActionName ); SampleUtil_Print( "UDN = %s\n", a_event->DevUDN ); SampleUtil_Print( "ServiceID = %s\n", a_event->ServiceID ); if( a_event->ActionRequest ) { xmlbuff = ixmlPrintDocument( a_event->ActionRequest ); if( xmlbuff ) SampleUtil_Print( "ActRequest = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SampleUtil_Print( "ActRequest = (null)\n" ); } if( a_event->ActionResult ) { xmlbuff = ixmlPrintDocument( a_event->ActionResult ); if( xmlbuff ) SampleUtil_Print( "ActResult = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SampleUtil_Print( "ActResult = (null)\n" ); } } break; case UPNP_CONTROL_ACTION_COMPLETE: { struct Upnp_Action_Complete *a_event = ( struct Upnp_Action_Complete * )Event; char *xmlbuff = NULL; SampleUtil_Print( "ErrCode = %d\n", a_event->ErrCode ); SampleUtil_Print( "CtrlUrl = %s\n", a_event->CtrlUrl ); if( a_event->ActionRequest ) { xmlbuff = ixmlPrintDocument( a_event->ActionRequest ); if( xmlbuff ) SampleUtil_Print( "ActRequest = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SampleUtil_Print( "ActRequest = (null)\n" ); } if( a_event->ActionResult ) { xmlbuff = ixmlPrintDocument( a_event->ActionResult ); if( xmlbuff ) SampleUtil_Print( "ActResult = %s\n", xmlbuff ); if( xmlbuff ) ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } else { SampleUtil_Print( "ActResult = (null)\n" ); } } break; case UPNP_CONTROL_GET_VAR_REQUEST: { struct Upnp_State_Var_Request *sv_event = ( struct Upnp_State_Var_Request * )Event; SampleUtil_Print( "ErrCode = %d\n", sv_event->ErrCode ); SampleUtil_Print( "ErrStr = %s\n", sv_event->ErrStr ); SampleUtil_Print( "UDN = %s\n", sv_event->DevUDN ); SampleUtil_Print( "ServiceID = %s\n", sv_event->ServiceID ); SampleUtil_Print( "StateVarName= %s\n", sv_event->StateVarName ); SampleUtil_Print( "CurrentVal = %s\n", sv_event->CurrentVal ); } break; case UPNP_CONTROL_GET_VAR_COMPLETE: { struct Upnp_State_Var_Complete *sv_event = ( struct Upnp_State_Var_Complete * )Event; SampleUtil_Print( "ErrCode = %d\n", sv_event->ErrCode ); SampleUtil_Print( "CtrlUrl = %s\n", sv_event->CtrlUrl ); SampleUtil_Print( "StateVarName= %s\n", sv_event->StateVarName ); SampleUtil_Print( "CurrentVal = %s\n", sv_event->CurrentVal ); } break; /* GENA */ case UPNP_EVENT_SUBSCRIPTION_REQUEST: { struct Upnp_Subscription_Request *sr_event = ( struct Upnp_Subscription_Request * )Event; SampleUtil_Print( "ServiceID = %s\n", sr_event->ServiceId ); SampleUtil_Print( "UDN = %s\n", sr_event->UDN ); SampleUtil_Print( "SID = %s\n", sr_event->Sid ); } break; case UPNP_EVENT_RECEIVED: { struct Upnp_Event *e_event = ( struct Upnp_Event * )Event; char *xmlbuff = NULL; SampleUtil_Print( "SID = %s\n", e_event->Sid ); SampleUtil_Print( "EventKey = %d\n", e_event->EventKey ); xmlbuff = ixmlPrintDocument( e_event->ChangedVariables ); SampleUtil_Print( "ChangedVars = %s\n", xmlbuff ); ixmlFreeDOMString( xmlbuff ); xmlbuff = NULL; } break; case UPNP_EVENT_RENEWAL_COMPLETE: { struct Upnp_Event_Subscribe *es_event = ( struct Upnp_Event_Subscribe * )Event; SampleUtil_Print( "SID = %s\n", es_event->Sid ); SampleUtil_Print( "ErrCode = %d\n", es_event->ErrCode ); SampleUtil_Print( "TimeOut = %d\n", es_event->TimeOut ); } break; case UPNP_EVENT_SUBSCRIBE_COMPLETE: case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: { struct Upnp_Event_Subscribe *es_event = ( struct Upnp_Event_Subscribe * )Event; SampleUtil_Print( "SID = %s\n", es_event->Sid ); SampleUtil_Print( "ErrCode = %d\n", es_event->ErrCode ); SampleUtil_Print( "PublisherURL= %s\n", es_event->PublisherUrl ); SampleUtil_Print( "TimeOut = %d\n", es_event->TimeOut ); } break; case UPNP_EVENT_AUTORENEWAL_FAILED: case UPNP_EVENT_SUBSCRIPTION_EXPIRED: { struct Upnp_Event_Subscribe *es_event = ( struct Upnp_Event_Subscribe * )Event; SampleUtil_Print( "SID = %s\n", es_event->Sid ); SampleUtil_Print( "ErrCode = %d\n", es_event->ErrCode ); SampleUtil_Print( "PublisherURL= %s\n", es_event->PublisherUrl ); SampleUtil_Print( "TimeOut = %d\n", es_event->TimeOut ); } break; } SampleUtil_Print ( "----------------------------------------------------------------------\n" ); SampleUtil_Print ( "======================================================================\n\n\n\n" ); ithread_mutex_unlock( &display_mutex ); return ( 0 ); }
int wphoto_upnp_handshake(void) { int ret = -1, err; char descurl[256]; const char *desc_xml = "MobileDevDesc.xml"; struct timespec timer; int camera_responded_save; char *camera_url_save; int pinged_camera; ithread_mutex_init(&state_mutex, NULL); ithread_cond_init(&state_cond, NULL); camera_url = NULL; camera_responded = 0; err = UpnpInit(NULL, 0); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpInit", err); goto err_init; } server_ip = UpnpGetServerIpAddress(); server_port = UpnpGetServerPort(); if (init_xml_docs() < 0) { perror("init_xml_docs"); goto err_init; } printf("address: %s:%d\n", server_ip, server_port); snprintf(descurl, sizeof(descurl), "http://%s:%d/%s", server_ip, server_port, desc_xml); err = web_add_callback("/MobileDevDesc.xml", web_MobileDevDesc, NULL); if (err) { perror("web_add_callback"); goto err_init; } err = web_add_callback("/desc_iml/CameraConnectedMobile.xml", web_CameraConnectedMobile, NULL); if (err) { perror("web_add_callback"); goto err_init; } if (web_start() < 0) { printf("web_init error\n"); goto err_init; } err = UpnpRegisterRootDevice(descurl, upnp_device_event_handler, &device_handle, &device_handle); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpRegisterRootDevice", err); goto err_init; } err = UpnpRegisterClient(upnp_client_event_handler, &client_handle, &client_handle); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpRegisterClient", err); goto err_register; } clock_gettime(CLOCK_REALTIME, &timer); discovery_timeout = 1; camera_responded_save = 0; camera_url_save = NULL; pinged_camera = 0; do { int wait_err; if (!camera_responded_save) { err = UpnpSendAdvertisement(device_handle, 0); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpSendAdvertisement", err); goto err_register; } printf("NOTIFY sent\n"); } if (camera_url_save && !pinged_camera) if (ping_camera(camera_url_save) == 0) pinged_camera = 1; timer.tv_sec += ADVERTISEMENT_INTERVAL; wait: ithread_mutex_lock(&state_mutex); wait_err = 0; while (camera_responded == camera_responded_save && strcmp_null(camera_url, camera_url_save) == 0 && !discovery_timeout && wait_err == 0) wait_err = ithread_cond_timedwait( &state_cond, &state_mutex, &timer); camera_responded_save = camera_responded; if (strcmp_null(camera_url, camera_url_save) != 0) { free(camera_url_save); camera_url_save = strdup(camera_url); } /* * Once we have the camera url, we stop sending M-SEARCH * requests */ if (discovery_timeout && !camera_url_save) { err = UpnpSearchAsync(client_handle, MSEARCH_INTERVAL, CAMERA_SERVICE_NAME, (void*)42); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpSearchAsync", err); goto err_register; } printf("M-SEARCH sent\n"); } discovery_timeout = 0; ithread_mutex_unlock(&state_mutex); if (wait_err != ETIMEDOUT && (!pinged_camera || !camera_responded_save)) goto wait; } while (!pinged_camera || !camera_responded_save); return 0; err_register: UpnpUnRegisterRootDevice(device_handle); err_init: UpnpFinish(); return ret; }
/****************************************************************************** * BrowseOrSearchWithCache *****************************************************************************/ static const ContentDir_BrowseResult* BrowseOrSearchWithCache (ContentDir* cds, void* result_context, const char* objectId, const char* const criteria) { if (cds == NULL || objectId == NULL || criteria == NULL) return NULL; // ----------> BrowseResult* br = talloc (result_context, BrowseResult); if (br == NULL) return NULL; // ----------> *br = (BrowseResult) { .cds = cds }; if (cds->cache == NULL) { /* * No cache */ br->children = BrowseOrSearchAll (cds, br, objectId, criteria); } else { /* * Lookup and/or update cache */ ithread_mutex_lock (&cds->cache_mutex); char key_buffer [strlen(objectId) + strlen(criteria) + 2 ]; const char* key; if (criteria == CRITERIA_BROWSE_CHILDREN) { key = objectId; } else { // criteria == "BrowseMetadata" or Search criteria sprintf (key_buffer, "%s\t%s", objectId, criteria); key = key_buffer; } Children** cp = (Children**) Cache_Get (cds->cache, key); if (cp) { if (*cp) { // cache hit br->children = *cp; } else { // cache new (or expired) // Note: use the cache as parent context for // allocation of result. br->children = BrowseOrSearchAll (cds, cds->cache, objectId, criteria); // set cache *cp = br->children; } } // Add a reference to the cached result before returning it if (br->children) { talloc_increase_ref_count (br->children); talloc_set_destructor (br, DestroyResult); } ithread_mutex_unlock (&cds->cache_mutex); } if (br->children == NULL) { talloc_free (br); br = NULL; } return br; }
/******************************************************************************** * TvCtrlPointAddDevice * * Description: * If the device is not already included in the global device list, * add it. Otherwise, update its advertisement expiration timeout. * * Parameters: * DescDoc -- The description document for the device * location -- The location of the description document URL * expires -- The expiration time for this advertisement * ********************************************************************************/ void TvCtrlPointAddDevice( IXML_Document *DescDoc, const char *location, int expires) { char *deviceType = NULL; char *friendlyName = NULL; char presURL[200]; char *baseURL = NULL; char *relURL = NULL; char *UDN = NULL; char *serviceId[TV_SERVICE_SERVCOUNT] = { NULL, NULL }; char *eventURL[TV_SERVICE_SERVCOUNT] = { NULL, NULL }; char *controlURL[TV_SERVICE_SERVCOUNT] = { NULL, NULL }; Upnp_SID eventSID[TV_SERVICE_SERVCOUNT]; int TimeOut[TV_SERVICE_SERVCOUNT] = { default_timeout, default_timeout }; struct TvDeviceNode *deviceNode; struct TvDeviceNode *tmpdevnode; int ret = 1; int found = 0; int service; int var; ithread_mutex_lock(&DeviceListMutex); /* Read key elements from description document */ UDN = SampleUtil_GetFirstDocumentItem(DescDoc, "UDN"); deviceType = SampleUtil_GetFirstDocumentItem(DescDoc, "deviceType"); friendlyName = SampleUtil_GetFirstDocumentItem(DescDoc, "friendlyName"); baseURL = SampleUtil_GetFirstDocumentItem(DescDoc, "URLBase"); relURL = SampleUtil_GetFirstDocumentItem(DescDoc, "presentationURL"); ret = UpnpResolveURL((baseURL ? baseURL : location), relURL, presURL); if (UPNP_E_SUCCESS != ret) SampleUtil_Print("Error generating presURL from %s + %s\n", baseURL, relURL); if (strcmp(deviceType, TvDeviceType) == 0) { SampleUtil_Print("Found Tv device\n"); /* Check if this device is already in the list */ tmpdevnode = GlobalDeviceList; while (tmpdevnode) { if (strcmp(tmpdevnode->device.UDN, UDN) == 0) { found = 1; break; } tmpdevnode = tmpdevnode->next; } if (found) { /* The device is already there, so just update */ /* the advertisement timeout field */ tmpdevnode->device.AdvrTimeOut = expires; } else { for (service = 0; service < TV_SERVICE_SERVCOUNT; service++) { if (SampleUtil_FindAndParseService (DescDoc, location, TvServiceType[service], &serviceId[service], &eventURL[service], &controlURL[service])) { SampleUtil_Print ("Subscribing to EventURL %s...\n", eventURL[service]); ret = UpnpSubscribe(ctrlpt_handle, eventURL[service], &TimeOut[service], eventSID[service]); if (ret == UPNP_E_SUCCESS) { SampleUtil_Print ("Subscribed to EventURL with SID=%s\n", eventSID[service]); } else { SampleUtil_Print ("Error Subscribing to EventURL -- %d\n", ret); strcpy(eventSID[service], ""); } } else { SampleUtil_Print ("Error: Could not find Service: %s\n", TvServiceType[service]); } } /* Create a new device node */ deviceNode = (struct TvDeviceNode *) malloc(sizeof(struct TvDeviceNode)); strcpy(deviceNode->device.UDN, UDN); strcpy(deviceNode->device.DescDocURL, location); strcpy(deviceNode->device.FriendlyName, friendlyName); strcpy(deviceNode->device.PresURL, presURL); deviceNode->device.AdvrTimeOut = expires; for (service = 0; service < TV_SERVICE_SERVCOUNT; service++) { strcpy(deviceNode->device.TvService[service]. ServiceId, serviceId[service]); strcpy(deviceNode->device.TvService[service]. ServiceType, TvServiceType[service]); strcpy(deviceNode->device.TvService[service]. ControlURL, controlURL[service]); strcpy(deviceNode->device.TvService[service]. EventURL, eventURL[service]); strcpy(deviceNode->device.TvService[service]. SID, eventSID[service]); for (var = 0; var < TvVarCount[service]; var++) { deviceNode->device. TvService[service].VariableStrVal [var] = (char *)malloc(TV_MAX_VAL_LEN); strcpy(deviceNode->device. TvService[service].VariableStrVal [var], ""); } } deviceNode->next = NULL; /* Insert the new device node in the list */ if ((tmpdevnode = GlobalDeviceList)) { while (tmpdevnode) { if (tmpdevnode->next) { tmpdevnode = tmpdevnode->next; } else { tmpdevnode->next = deviceNode; break; } } } else { GlobalDeviceList = deviceNode; } /*Notify New Device Added */ SampleUtil_StateUpdate(NULL, NULL, deviceNode->device.UDN, DEVICE_ADDED); } } ithread_mutex_unlock(&DeviceListMutex); if (deviceType) free(deviceType); if (friendlyName) free(friendlyName); if (UDN) free(UDN); if (baseURL) free(baseURL); if (relURL) free(relURL); for (service = 0; service < TV_SERVICE_SERVCOUNT; service++) { if (serviceId[service]) free(serviceId[service]); if (controlURL[service]) free(controlURL[service]); if (eventURL[service]) free(eventURL[service]); } }
/******************************************************************************** * TvCtrlPointPrintDevice * * Description: * Print the identifiers and state table for a device from * the global device list. * * Parameters: * devnum -- The number of the device (order in the list, * starting with 1) * ********************************************************************************/ int TvCtrlPointPrintDevice(int devnum) { struct TvDeviceNode *tmpdevnode; int i = 0, service, var; char spacer[15]; if (devnum <= 0) { SampleUtil_Print( "Error in TvCtrlPointPrintDevice: " "invalid devnum = %d\n", devnum); return TV_ERROR; } ithread_mutex_lock(&DeviceListMutex); SampleUtil_Print("TvCtrlPointPrintDevice:\n"); tmpdevnode = GlobalDeviceList; while (tmpdevnode) { i++; if (i == devnum) break; tmpdevnode = tmpdevnode->next; } if (!tmpdevnode) { SampleUtil_Print( "Error in TvCtrlPointPrintDevice: " "invalid devnum = %d -- actual device count = %d\n", devnum, i); } else { SampleUtil_Print( " TvDevice -- %d\n" " | \n" " +- UDN = %s\n" " +- DescDocURL = %s\n" " +- FriendlyName = %s\n" " +- PresURL = %s\n" " +- Adver. TimeOut = %d\n", devnum, tmpdevnode->device.UDN, tmpdevnode->device.DescDocURL, tmpdevnode->device.FriendlyName, tmpdevnode->device.PresURL, tmpdevnode->device.AdvrTimeOut); for (service = 0; service < TV_SERVICE_SERVCOUNT; service++) { if (service < TV_SERVICE_SERVCOUNT - 1) sprintf(spacer, " | "); else sprintf(spacer, " "); SampleUtil_Print( " | \n" " +- Tv %s Service\n" "%s+- ServiceId = %s\n" "%s+- ServiceType = %s\n" "%s+- EventURL = %s\n" "%s+- ControlURL = %s\n" "%s+- SID = %s\n" "%s+- ServiceStateTable\n", TvServiceName[service], spacer, tmpdevnode->device.TvService[service].ServiceId, spacer, tmpdevnode->device.TvService[service].ServiceType, spacer, tmpdevnode->device.TvService[service].EventURL, spacer, tmpdevnode->device.TvService[service].ControlURL, spacer, tmpdevnode->device.TvService[service].SID, spacer); for (var = 0; var < TvVarCount[service]; var++) { SampleUtil_Print( "%s +- %-10s = %s\n", spacer, TvVarName[service][var], tmpdevnode->device.TvService[service].VariableStrVal[var]); } } } SampleUtil_Print("\n"); ithread_mutex_unlock(&DeviceListMutex); return TV_SUCCESS; }
static void service_unlock(void) { #ifdef HAVE_LIBUPNP ithread_mutex_unlock(&transport_mutex); #endif }
/**************************************************************************** * Function: TimerThreadWorker * * Description: * Implements timer thread. * Waits for next event to occur and schedules * associated job into threadpool. * Internal Only. * Parameters: * void * arg -> is cast to TimerThread * *****************************************************************************/ static void * TimerThreadWorker( void *arg ) { TimerThread *timer = ( TimerThread * ) arg; ListNode *head = NULL; TimerEvent *nextEvent = NULL; time_t currentTime = 0; time_t nextEventTime = 0; struct timespec timeToWait; int tempId; assert( timer != NULL ); ithread_mutex_lock( &timer->mutex ); while( 1 ) { //mutex should always be locked at top of loop //Check for shutdown if( timer->shutdown ) { timer->shutdown = 0; ithread_cond_signal( &timer->condition ); ithread_mutex_unlock( &timer->mutex ); return NULL; } nextEvent = NULL; //Get the next event if possible if( timer->eventQ.size > 0 ) { head = ListHead( &timer->eventQ ); nextEvent = ( TimerEvent * ) head->item; nextEventTime = nextEvent->eventTime; } currentTime = time( NULL ); //If time has elapsed, schedule job if( ( nextEvent != NULL ) && ( currentTime >= nextEventTime ) ) { if( nextEvent->persistent ) { ThreadPoolAddPersistent( timer->tp, &nextEvent->job, &tempId ); } else { ThreadPoolAdd( timer->tp, &nextEvent->job, &tempId ); } ListDelNode( &timer->eventQ, head, 0 ); FreeTimerEvent( timer, nextEvent ); continue; } if( nextEvent != NULL ) { timeToWait.tv_nsec = 0; timeToWait.tv_sec = nextEvent->eventTime; ithread_cond_timedwait( &timer->condition, &timer->mutex, &timeToWait ); } else { ithread_cond_wait( &timer->condition, &timer->mutex ); } } }
static int handle_subscription_request(struct upnp_device *priv, struct Upnp_Subscription_Request *sr_event) { struct service *srv; int rc; assert(priv != NULL); Log_info("upnp", "Subscription request for %s (%s)", sr_event->ServiceId, sr_event->UDN); srv = find_service(priv->upnp_device_descriptor, sr_event->ServiceId); if (srv == NULL) { Log_error("upnp", "%s: Unknown service '%s'", __FUNCTION__, sr_event->ServiceId); return -1; } int result = -1; ithread_mutex_lock(&(priv->device_mutex)); // There is really only one variable evented: LastChange const char *eventvar_names[] = { "LastChange", NULL }; const char *eventvar_values[] = { NULL, NULL }; // Build the current state of the variables as one gigantic initial // LastChange update. ithread_mutex_lock(srv->service_mutex); const int var_count = VariableContainer_get_num_vars(srv->variable_container); // TODO(hzeller): maybe use srv->last_change directly ? upnp_last_change_builder_t *builder = UPnPLastChangeBuilder_new(srv->event_xml_ns); for (int i = 0; i < var_count; ++i) { const char *name; const char *value = VariableContainer_get(srv->variable_container, i, &name); // Send over all variables except "LastChange" itself. Also all // A_ARG_TYPE variables are not evented. if (value && strcmp("LastChange", name) != 0 && strncmp("A_ARG_TYPE_", name, strlen("A_ARG_TYPE_")) != 0) { UPnPLastChangeBuilder_add(builder, name, value); } } ithread_mutex_unlock(srv->service_mutex); char *xml_value = UPnPLastChangeBuilder_to_xml(builder); Log_info("upnp", "Initial variable sync: %s", xml_value); eventvar_values[0] = xmlescape(xml_value, 0); free(xml_value); UPnPLastChangeBuilder_delete(builder); rc = UpnpAcceptSubscription(priv->device_handle, sr_event->UDN, sr_event->ServiceId, eventvar_names, eventvar_values, 1, sr_event->Sid); if (rc == UPNP_E_SUCCESS) { result = 0; } else { Log_error("upnp", "Accept Subscription Error: %s (%d)", UpnpGetErrorMessage(rc), rc); } ithread_mutex_unlock(&(priv->device_mutex)); free((char*)eventvar_values[0]); return result; }