Download presentation
Presentation is loading. Please wait.
Published byChester Casey Modified over 9 years ago
1
Universal Plug and Play Dirk Grunwald University of Colorado
2
Outline u What problem is UPNP trying to solve? u What are the components in UPNP? u Example u Programming API
3
What is UPNP? u Architecture for pervasive peer-to-peer network connectivity of intelligent appliances Allows appliances to present “controls” to computers Peer-to-peer – does not use a central registry Largely based on IETF standards
4
What is UPNP - Example u UPNP supports “devices” and “control points”. A device may have multiple “services” u Sample Device A TV registers itself as a “device” The TV exports a “Control Service” for volume, power, channel It exports a “Picture” service for color, tint, contrast and brightness
5
What is UPNP - Example u An intelligent TV Remote or PC may be a “controller” u Both devices and controllers may exist in an “unmanaged” network (no DNS or DHCP) AutoIP is a mechanism to allocate an IP address Multicast DNS is used to decenteralize name service
6
Important Actions in UPNP u Discover devices & services u Get a description of the device u Control discovered devices u Be informed of events indicating changes in the device u Use a presentation prepared by the device to present a control
7
Overview - Discovery u Based on SSDP (simple service discovery protocol – IETF draft) u When a device is added to the network, that device can advertise its services to control points u When a control point is added, it can search for existing devices u Discovery exchanges information about the device type, an identifier and a URL for more detailed information
8
Overview - Description u A control point retrieves a description using the URL provided during discovery u An XML document describes the device and services Vendor specific info, manufacturer information (model name, version), serial number, URL’s for vendor specific web sites
9
Overview - Control u Control point can send actions to a device’s service Send Control Message to Control URL Control messages encodded in XML using the Simple Object Access Protocol (SOAP)
10
Overview - Eventing u A service description includes variables that model the service state Publish / subscribe model Special first event provides initial values u Events are formatted in XML using GENA (General Event Notification Architecture)
11
Overview - Presentation u A device can offer a URL for presentation Control point can retrieve the page, load into a browser and allow user to control or observe the device UPNP only covers retrieving the page
12
Overview - Components
13
What’s Next u Walk through specific activities u Intersperse code snips from TV example
14
Icons for Protocol Example Service Root Device #1 Device Service Root Device #2 Device Control Point #1 Control Point #2 Control Point #3
15
Actions When New Device Is Added Service Root Device #1 Device Control Point #1 1.Device Initialization 2.Announcement 1.Start periodic re- announcements 3.Service actions 4.Disconnect
16
Actions When New Controller Added Service Root Device #1 Device Control Point #2 1.Control Initialization 2.Search for devices 1.Start periodic timeout checker 3.Issue actions 4.Disconnect
17
Coding the Device
18
Control Flow in Device Main InitializeAnnounceCommand Loop Periodic Announce CallbackEventHandler HandleSubscriptionRequest HandleGetVarRequest HandleActionRequest … Thread started by UPNP system Thread started by Device application
19
Device Initialization if (ret = UpnpInit(ip_address, port)) { printf("Error with UpnpInit -- %d\n", ret); UpnpFinish(); exit(1); } Specified host IP address or NULL Specified port (NULL defaults to 80) Cleanup routine – must be last API routine called
20
Device Registration UpnpRegisterRootDevice(desc_doc_url, TvDeviceCallbackEventHandler, &device_handle,&device_handle))); … TvDeviceStateTableInit(desc_doc_url); … URL With device description Routine to handle asynchronous events Void* passed to asynch handler routine OUT UpnpDevice_Handle used to identify device in API
21
Device State Table Initialization if (UpnpDownloadXmlDoc(DescDocURL, &DescDoc) != UPNP_E_SUCCESS) { printf("Error Parsing %s\n", DescDocURL); ret = UPNP_E_INVALID_DESC; } This returns a UpnpDownloadXmlDoc item, which is a parsed DOM document. The application needs to free this data. Each device is described by an XML document. The device needs to know where that document lives
22
Device Description URL 1 0 http://192.168.1.1 urn:schemas-upnp-org:device:tvdevice:1 UPnP Television Emulator... model information......exported services... tvdevicepres.html
23
Device Info urn:schemas-upnp-org:device:tvdevice:1 UPnP Television Emulator TV Manufacturer Name http://www.manufacturer.com UPnP Television Device Emulator 1.0 TVEmulator 1.0 http://www.manufacturer.com/TVEmulator/ 123456789001 uuid:Upnp-TVEmulator-1_0-1234567890001 123456789
24
Device Service List urn:upnp-org:serviceId:tvcontrol1 …Remainder of TV Controller Device Specification… urn:schemas-upnp-org:service:tvpicture:1 …Remainder of TV Controller Device Specification…
25
Device Service Description urn:schemas-upnp-org:service:tvcontrol:1 urn:upnp-org:serviceId:tvcontrol1 http://192.168.1.1:5431/upnp/control/tvcontrol1 http://192.168.1.1:5431/upnp/event/tvcontrol1 http://192.168.1.1/tvcontrolSCPD.xml Address specified by application “Service Control Protocol Definition” What controls / events are available?
26
Device SCPD ?xml version="1.0"?> … … More state variables … PowerOn … More action items …
27
State Variables Specify Type, Range and Initial Value Channel i4 1 100 1 1
28
Actions Specify Arguments, Values SetChannel NewChannel Channel in
29
Device state represented by strings in this sample application * Global arrays for storing Tv Control Service variable names, values, and defaults */ char *tvc_varname[] = {"Power","Channel","Volume"}; char tvc_varval[3][5]; char *tvc_varval_def[] = {"0", "1", "5"}; /* Global arrays for storing Tv Picture Service variable names, values, and defaults */ char *tvp_varname[] = {"Color","Tint","Contrast","Brightness"}; char tvp_varval[4][5]; char *tvp_varval_def[] = {"5","5","5","5"}; Filled in with default value later
30
Supplemental Routines Simplify Document Access SampleUtil_FindAndParseService(DescDoc, TvControlServiceType, &servid_ctrl, &evnturl_ctrl,&ctrlurl_ctrl); udn = SampleUtil_GetFirstDocumentItem(DescDoc, "UDN"); strcpy(tvcontrol_service.UDN, udn); strcpy(tvcontrol_service.ServiceId, servid_ctrl); strcpy(tvcontrol_service.ServiceType, TvControlServiceType); tvcontrol_service.VariableCount=3; for (i=0; i<tvcontrol_service.VariableCount; i++) { tvcontrol_service.VariableName[i] = tvc_varname[i]; tvcontrol_service.VariableStrVal[i] = tvc_varval[i]; strcpy(tvcontrol_service.VariableStrVal[i], tvc_varval_def[i]); } Variables maintained as strings in example
31
Coding the Device Where were we? u Device has initialized the UPNP system u Device has registered the root device, making it available to receive messages u Device has read the device description and initialized state variables Probably should have used the values in the SCPD
32
Device Announcement UpnpSendAdvertisement(device_handle, default_advr_expire; Each advertisement has a default timeout, expressed in an integral number of seonds UpnpDevice_Handle used to identify device in API
33
Details about SSDP / Announcment u Broadcasts to 239.255.255.250:1900 “Site local” multicast address u Messages delivered using HTTPMU and HTTPU
34
Thread is spawned for Device (Re)Announcement code = pthread_create( &advr_thread, NULL, TvCtrlPointAdvrLoop, NULL ); void* TvCtrlPointAdvrLoop(void *args) { int ret; while (1) { sleep(default_advr_interval); if (ret = UpnpSendAdvertisement(device_handle, default_advr_expire)) printf("Error sending updated advert : %d\n", ret); printf("Updated Advertisements Sent\n"); } The application starts a thread to periodically renew advertisements. This could also be done with timers & signals or other mechanisms.
35
The Main thread now enters a command loop void TvDeviceCommandLoop() { int stoploop=0; char cmdline[100]; char cmd[100]; int i; while (!stoploop) { sprintf(cmdline, ""); sprintf(cmd, ""); printf("\n>> "); // Get a command line fgets(cmdline, 100, stdin); sscanf(cmdline, "%s", &cmd); if (strcasecmp(cmd, "exit") == 0) { printf("Shutting down...\n"); UpnpUnRegisterRootDevice(device_handle); UpnpFinish(); exit(0); } else { printf("\n Unknown command: %s\n\n", cmd); printf(" Valid Commands:\n"); printf(" Exit\n\n"); }
36
The UPNP thread periodically called the “callback handler” int TvDeviceCallbackEventHandler(Upnp_EventType EventType, void *Event, void *Cookie) { struct Upnp_Event * event; /* Print a summary of the event received */ SampleUtil_PrintEvent(EventType, Event); switch ( EventType) { case UPNP_EVENT_SUBSCRIPTION_REQUEST: TvDeviceHandleSubscriptionRequest( (struct Upnp_Subscription_Request *) Event); break; case UPNP_CONTROL_GET_VAR_REQUEST: TvDeviceHandleGetVarRequest( (struct Upnp_State_Var_Request *) Event); break; case UPNP_CONTROL_ACTION_REQUEST: TvDeviceHandleActionRequest( (struct Upnp_Action_Request *) Event); break; …
37
Accepting a subscription sends out current value of state variable int TvDeviceHandleSubscriptionRequest(struct Upnp_Subscription_Request *sr_event) { pthread_mutex_lock(&TVDevMutex); if ((strcmp(sr_event->UDN,tvcontrol_service.UDN) == 0) && (strcmp(sr_event->ServiceId, tvcontrol_service.ServiceId) == 0)) { /* This is a request for the TvDevice Control Service */ UpnpAcceptSubscription( device_handle sr_event->UDN, sr_event->ServiceId, (char **)tvcontrol_service.VariableName, (char **)tvcontrol_service.VariableStrVal, tvcontrol_service.VariableCount, sr_event->Sid); } else if ().. {.. } pthread_mutex_unlock(&TVDevMutex); return(1); } This identifies the controller being registered
38
State changing routines notify subscribed listeners int TvDeviceSetChannel(int channel) { if (channel 100) { printf("error: can't change to channel %d\n", channel); return(0); } /* Vendor-specific code to set the channel goes here */ pthread_mutex_lock(&TVDevMutex); sprintf(tvcontrol_service.VariableStrVal[1], "%d", channel); /* Send updated channel setting notification to subscribed control points */ UpnpNotify(device_handle, tvcontrol_service.UDN, tvcontrol_service.ServiceId, (char **)&tvcontrol_service.VariableName[1], (char **)&tvcontrol_service.VariableStrVal[1], 1); pthread_mutex_unlock(&TVDevMutex); return(1); } Number of variables in change list List of variable that changed In a real application, you’d actually do something useful here
39
Asynchronous State Changes u This example only contains synchronous event changes (caused by an external controller) u The device may change by itself (e.g. GPS) Just call UpnpNotify in device change routine
40
The device copys values for GetVarRequest int TvDeviceHandleGetVarRequest( struct Upnp_State_Var_Request *cgv_event) { int i; int getvar_succeeded = 0; cgv_event->CurrentVal = NULL; pthread_mutex_lock(&TVDevMutex); if ((strcmp(cgv_event->DevUDN,tvcontrol_service.UDN)==0) && (strcmp(cgv_event->ServiceID, tvcontrol_service.ServiceId)==0)) { /* Request for variable in the TvDevice Control Service */ for (i=0; i< tvcontrol_service.VariableCount; i++) { if (strcmp(cgv_event->StateVarName, tvcontrol_service.VariableName[i])==0) { getvar_succeeded = 1; cgv_event->CurrentVal = (Upnp_DOMString) malloc(sizeof(tvcontrol_service.VariableStrVal[i])); strcpy(cgv_event->CurrentVal, tvcontrol_service.VariableStrVal[i]); break; } … Check for correct device Copy value to event datatype
41
The application is responsible for decoding and performing actions int TvDeviceHandleActionRequest(struct Upnp_Action_Request *ca_event) { Upnp_DOMString bufReq; char result_str[500]; char service_type[500]; char *value=NULL; /* Defaults if action not found */ int action_succeeded = -1; int err=401; ca_event->ErrCode = 0; ca_event->ActionResult = NULL; if ((strcmp(ca_event->DevUDN,tvcontrol_service.UDN)==0) && (strcmp(ca_event->ServiceID,tvcontrol_service.ServiceId)==0)) { /* Request for action in the TvDevice Control Service */ strcpy(service_type, tvcontrol_service.ServiceType); if (strcmp(ca_event->ActionName, "PowerOn") == 0) { action_succeeded = TvDevicePowerOn(); } else if (strcmp(ca_event->ActionName, "PowerOff") == 0) { action_succeeded = TvDevicePowerOff(); } else Check for correct device
42
The application is responsible for decoding and performing actions } else if (strcmp(ca_event->ActionName, "SetChannel") == 0) { if (value = SampleUtil_GetFirstDocumentItem( ca_event->ActionRequest, "Channel")) { action_succeeded = TvDeviceSetChannel(atoi(value)); } else { // invalid args error err = 402; action_succeeded = 0; } The support routines provide assistance for extracting the values from the DOM document This greatly simplifies the parsing of complex actions. Note that TvDeviceSetChannel will UpnpNotify any subscribers of the changed value
43
Coding the Client
44
High Level View of Client u Initialize UPNP system u Register u Ask devices to advertise themselves u Subscribe to any devices we find by advertisement u Accept user commands to examine variables of devices or cause actions
45
Client Registration UpnpInit(ip_address, port); UpnpRegisterClient(TvCtrlPointCallbackEventHandler, &ctrlpt_handle, &ctrlpt_handle) … Routine to handle asynchronous events Void* passed to asynch handler routine OUT UpnpClient_Handle used to identify controller in API
46
Client Requests Notification /* Search for all devices of type tvdevice version 1, waiting for up to 5 seconds for the response */ /* ret = UpnpSearchAsync(ctrlpt_handle, 5, "urn:schemas-upnp-org:device:tvdevice:1", NULL); */ /* Search for all services of type tvcontrol version 1, waiting for up to 5 seconds for the response */ /* ret = UpnpSearchAsync(ctrlpt_handle, 5, “urn:schemas-upnp-org:service:tvcontrol:1”, NULL); */ /* Search for all root devices, waiting for up to 5 seconds for the response */ ret = UpnpSearchAsync(ctrlpt_handle, 5, "upnp:rootdevice", NULL); If the device is found, the callback routine will be called
47
Notifications Invoke Callback int TvCtrlPointCallbackEventHandler(Upnp_EventType EventType, void *Event, void *Cookie) { struct Upnp_Event * event; int ret; SampleUtil_PrintEvent(EventType, Event); switch ( EventType) { /* SSDP Stuff */ case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_SEARCH_RESULT: { if ((ret=UpnpDownloadXmlDoc(d_event->Location, &DescDoc)) != UPNP_E_SUCCESS) { printf("Error obtaining device description from %s -- error = %d\n", d_event->Location, ret ); } else { TvCtrlPointAddDevice(DescDoc, d_event->Location, d_event->Expires); } Controller downloads device description from specified URL Keeps private device list
48
This client uses a single callback routine int TvCtrlPointCallbackEventHandler(Upnp_EventType EventType, void *Event, void *Cookie) { switch ( EventType) { /* SSDP Stuff */ case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_SEARCH_RESULT: case UPNP_DISCOVERY_SEARCH_TIMEOUT: case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: /* SOAP Stuff */ case UPNP_CONTROL_ACTION_COMPLETE: case UPNP_CONTROL_GET_VAR_COMPLETE: /* GENA Stuff */ case UPNP_EVENT_RECEIVED: case UPNP_EVENT_SUBSCRIBE_COMPLETE: case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: case UPNP_EVENT_RENEWAL_COMPLETE: /* ignore these cases, since this is not a device */ case UPNP_EVENT_SUBSCRIPTION_REQUEST: case UPNP_CONTROL_GET_VAR_REQUEST: case UPNP_CONTROL_ACTION_REQUEST: }
49
Client starts thread to keep subscriptions fresh pthread_create( &timer_thread, NULL, TvCtrlPointTimerLoop, NULL );.. void* TvCtrlPointTimerLoop(void *args) { int incr = 30; // how often to verify the timeouts while (1) { sleep(incr); TvCtrlPointVerifyTimeouts(incr); } Subscribes to all services that we know about, possibly renewing subscriptions or asking for new subscriptions.
50
If a previously announced device expires, it subscribes again.. if (strcmp(curdevnode->device.TvControl.SID, "") != 0) { /* We have a valid TvControl SID, so lets check the subscription timeout */ curdevnode->device.TvControl.SubsTimeOut -= incr; if (curdevnode->device.TvControl.SubsTimeOut <= 0) { /* The subscription has expired, so delete it and request a new one */ strcpy(curdevnode->device.TvControl.SID, ""); ret = UpnpSubscribeAsync(ctrlpt_handle, curdevnode->device.TvControl.EventURL, default_timeout, TvCtrlPointCallbackEventHandler, NULL); } Async means that callback will be called later
51
But if the device is only about to expire, it renews subscription } else if (curdevnode->device.TvControl.SubsTimeOut < 2*incr) { /* The subscription is about to expire, so try to renew it */ ret = UpnpRenewSubscriptionAsync(ctrlpt_handle, default_timeout, curdevnode->device.TvControl.SID, TvCtrlPointCallbackEventHandler, NULL); This routine may eventually be called with a RENEWAL_EVENT_COMPLETE event
52
Mean while, the main thread is accepting user commands void TvCtrlPointCommandLoop() { while (!stoploop) {.. fgets(cmdline, 100, stdin);... if (cmdfound) { switch(cmdnum) { case PRTHELP: TvCtrlPointPrintHelp(); break; case POWON: if (arg1 == arg_val_err) invalid_args = 1; else TvCtrlPointSendControlAction(arg1, "PowerOn"); break;
53
..and sending actions to the device… int TvCtrlPointSendControlAction(int devnum, char *actionname) { struct TvDeviceNode *devnode; char ActionXml[250]; Upnp_Document actionNode=NULL; int ret=0; pthread_mutex_lock(&DeviceListMutex); if (!TvCtrlPointGetDevice(devnum, &devnode)) { ret = 0;; } else { sprintf(ActionXml, " ", actionname, TvControlServiceType, actionname); actionNode = UpnpParse_Buffer( ActionXml); ret = UpnpSendActionAsync( ctrlpt_handle, devnode->device.TvControl.ControlURL, "tvcontrol:1", devnode->device.DevUUID, actionNode, TvCtrlPointCallbackEventHandler, NULL); Format action requestion and turn into a DOM document for UpnpSendAction
54
..or requesting values from the device. int TvCtrlPointControlGetVar(int devnum, char* varname) { struct TvDeviceNode *devnode; int ret=0; pthread_mutex_lock(&DeviceListMutex); if (!TvCtrlPointGetDevice(devnum, &devnode)) { ret = 0;; } else { ret = UpnpGetServiceVarStatusAsync( ctrlpt_handle, devnode->device.TvControl.ControlURL, varname, TvCtrlPointCallbackEventHandler, NULL); The value is eventually returned to this callback routine
55
The actions are acknowledged to the callback routine /* SOAP Stuff */ case UPNP_CONTROL_ACTION_COMPLETE: { struct Upnp_Action_Complete *a_event = (struct Upnp_Action_Complete * ) Event; if (a_event->ErrCode != UPNP_E_SUCCESS) printf("Error in Action Complete Callback -- %d\n", a_event->ErrCode); /* No need for any processing here, just print out results. Service state table updates are handled by events. */ } break; case UPNP_CONTROL_GET_VAR_COMPLETE: { struct Upnp_State_Var_Complete *sv_event = (struct Upnp_State_Var_Complete * ) Event; if (sv_event->ErrCode != UPNP_E_SUCCESS) printf("Error in Get Var Complete Callback -- %d\n", sv_event->ErrCode); } break;
56
Actual variable values are passed by events case UPNP_EVENT_RECEIVED: { struct Upnp_Event *e_event = (struct Upnp_Event * ) Event; TvCtrlPointHandleEvent(e_event->Sid, e_event->EventKey, e_event->ChangedVariables); } break;
57
That are passed to service specific decoders.. void TvCtrlPointHandleEvent(SID sid, int evntkey, Upnp_Document changes) { struct TvDeviceNode *tmpdevnode; pthread_mutex_lock(&DeviceListMutex); tmpdevnode = GlobalDeviceList; while (tmpdevnode) { if (strcmp(tmpdevnode->device.TvControl.SID,sid) == 0) { printf("Received TvControl Event: %d for SID %s\n", evntkey, sid); TvControlStateUpdate(changes, (char **)&tmpdevnode->device.TvControl.VariableStrVal); break; } else if (strcmp(tmpdevnode->device.TvPicture.SID,sid) == 0) { printf("Received TvPicture Event: %d for SID %s\n", evntkey, sid); TvPictureStateUpdate(changes, (char **)&tmpdevnode->device.TvPicture.VariableStrVal); break; } tmpdevnode = tmpdevnode->next; } pthread_mutex_unlock(&DeviceListMutex); }
58
Review Of Concepts and Coding Style
59
Review u Discovery / description / control / events / presentation u Discovery is by multicast u Control & Events are unicast support routines provide encoding / decoding u Services and controllers are written using an asynchronous, multithreaded application model
60
System Requirements u Web server to transmit device & and control descriptions Does not need to be on device! u HTTP / HTTPU / HTTPMU parser Built into library u DOM / XML parser Combination of CDOM and sample code handles this
61
Unanswered Questions u What about security? Basic UPNP library abstracts away communication layer Authentication / permission models? u What about “far away access”? If you know the service exists on a device, you can simply query it using HTTPU But, that’s not supported in current UPNP library
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.