/******************************************************************************** * TvCtrlPointGetVar * * Description: * Send a GetVar request to the specified service of a device. * * Parameters: * service -- The service * devnum -- The number of the device (order in the list, * starting with 1) * varname -- The name of the variable to request. * ********************************************************************************/ int TvCtrlPointGetVar(int service, int devnum, const char *varname) { struct TvDeviceNode *devnode; int rc; ithread_mutex_lock(&DeviceListMutex); rc = TvCtrlPointGetDevice(devnum, &devnode); if (TV_SUCCESS == rc) { rc = UpnpGetServiceVarStatusAsync( ctrlpt_handle, devnode->device.TvService[service].ControlURL, varname, TvCtrlPointCallbackEventHandler, NULL); if (rc != UPNP_E_SUCCESS) { SampleUtil_Print( "Error in UpnpGetServiceVarStatusAsync -- %d\n", rc); rc = TV_ERROR; } } ithread_mutex_unlock(&DeviceListMutex); return rc; }
/******************************************************************************** * upnp_igd_get_var * * Description: * Send a GetVar request to the specified service of a device. * * Parameters: * igd_ctxt -- The upnp igd context * device_node -- The device * service -- The service * variable -- The variable to request. * fun -- Callback function * cookie -- Callback cookie * ********************************************************************************/ int upnp_igd_get_var(upnp_igd_context* igd_ctxt, upnp_igd_device_node *device_node, int service, int variable, Upnp_FunPtr fun, const void *cookie) { int ret; upnp_igd_print(igd_ctxt, UPNP_IGD_DEBUG, "Get %s.%s from IGD device %s[%s]", IGDServiceName[service], IGDVarName[service][variable], device_node->device.friendly_name, device_node->device.udn); ret = UpnpGetServiceVarStatusAsync(igd_ctxt->upnp_handle, device_node->device.services[service].control_url, IGDVarName[service][variable], fun, cookie); if (ret != UPNP_E_SUCCESS) { upnp_igd_print(igd_ctxt, UPNP_IGD_ERROR, "Error in UpnpGetServiceVarStatusAsync -- %d", ret); ret = -1; } return 0; }
/******************************************************************************** * WscUPnPCPHandleEvent * * Description: * Handle a UPnP event that was received. Process the event and update * the appropriate service state table. * * Parameters: * sid -- The subscription id for the event * eventkey -- The eventkey number for the event * changes -- The DOM document representing the changes * * Return: * None ********************************************************************************/ void WscUPnPCPHandleEvent( IN Upnp_SID sid, IN int evntkey, IN IXML_Document * changes) { struct upnpDeviceNode *devNode; char *inStr = NULL, *pWscU2KMsg = NULL; unsigned char *decodeStr = NULL; int decodeLen, wscU2KMsgLen; unsigned int UPnPDevIP = 0; devNode = WscDeviceList; while (devNode) { if(strcmp(devNode->device.services.SID, sid) == 0) { devNode->device.timeCount = devNode->device.AdvrTimeOut; UPnPDevIP = devNode->device.ipAddr; DBGPRINTF(RT_DBG_INFO, "Received WscService Event: %d for SID %s\n", evntkey, sid); WscStateVarUpdate(devNode, changes); inStr = devNode->device.services.StateVarVal[WSC_EVENT_WLANEVENT]; if (inStr) { #define WSC_EVENT_WLANEVENT_MSG_LEN_MIN 18 // The first byte is the msg type, the next 17 bytes is the MAC address in xx:xx format DBGPRINTF(RT_DBG_INFO, "\tWLANEvent=%s!\n", devNode->device.services.StateVarVal[WSC_EVENT_WLANEVENT]); decodeLen = ILibBase64Decode((unsigned char *)inStr, strlen(inStr), &decodeStr); if((decodeLen > WSC_EVENT_WLANEVENT_MSG_LEN_MIN) && (ioctl_sock >= 0)) { RTMP_WSC_U2KMSG_HDR *msgHdr; WscEnvelope *msgEnvelope; int msgQIdx = -1; decodeLen -= WSC_EVENT_WLANEVENT_MSG_LEN_MIN; /* Prepare the msg buffers */ wscU2KMsgLen = wscU2KMsgCreate(&pWscU2KMsg, (char *)(decodeStr + WSC_EVENT_WLANEVENT_MSG_LEN_MIN), decodeLen, EAP_FRAME_TYPE_WSC); if (wscU2KMsgLen == 0) goto done; /* Prepare the msg envelope */ if ((msgEnvelope = wscEnvelopeCreate()) == NULL) goto done; msgEnvelope->callBack = wscCPPutMessage; /* Lock the msgQ and check if we can get a valid mailbox to insert our request! */ if (wscMsgQInsert(msgEnvelope, &msgQIdx) != WSC_SYS_SUCCESS) goto done; // Fill the session ID to the U2KMsg buffer header. msgHdr = (RTMP_WSC_U2KMSG_HDR *)pWscU2KMsg; msgHdr->envID = msgEnvelope->envID; // copy the Addr1 & Addr2 memcpy(msgHdr->Addr1, HostMacAddr, MAC_ADDR_LEN); memcpy(msgHdr->Addr2, &UPnPDevIP, sizeof(unsigned int)); // Now send the msg to kernel space. DBGPRINTF(RT_DBG_INFO, "(%s):Ready to send pWscU2KMsg(len=%d) to kernel by ioctl(%d)!\n", __FUNCTION__, wscU2KMsgLen, ioctl_sock); //wsc_hexdump("U2KMsg", pWscU2KMsg, wscU2KMsgLen); if(wsc_set_oid(RT_OID_WSC_EAPMSG, pWscU2KMsg, wscU2KMsgLen) != 0) wscEnvelopeRemove(msgEnvelope, msgQIdx); } } if (devNode->device.services.StateVarVal[WSC_EVENT_APSTATUS] != NULL) DBGPRINTF(RT_DBG_INFO, "\tAPStatus=%s!\n", devNode->device.services.StateVarVal[WSC_EVENT_APSTATUS]); if (devNode->device.services.StateVarVal[WSC_EVENT_STASTATUS] != NULL) DBGPRINTF(RT_DBG_INFO, "\tSTAStatus=%s!\n", devNode->device.services.StateVarVal[WSC_EVENT_STASTATUS]); break; } devNode = devNode->next; } done: } /******************************************************************************** * WscUPnPCPHandleSubscribeUpdate * * Description: * Handle a UPnP subscription update that was received. Find the * service the update belongs to, and update its subscription * timeout. * * Parameters: * eventURL -- The event URL for the subscription * sid -- The subscription id for the subscription * timeout -- The new timeout for the subscription * * Return: * None ********************************************************************************/ void WscUPnPCPHandleSubscribeUpdate( IN char *eventURL, IN Upnp_SID sid, IN int timeout) { struct upnpDeviceNode *tmpdevnode; tmpdevnode = WscDeviceList; while (tmpdevnode) { if( strcmp(tmpdevnode->device.services.EventURL, eventURL) == 0) { DBGPRINTF(RT_DBG_INFO, "Received WscService Event Renewal for eventURL %s\n", eventURL); strcpy(tmpdevnode->device.services.SID, sid); break; } tmpdevnode = tmpdevnode->next; } } /******************************************************************************** * WscUPnPCPDeviceHandler * * Description: * The callback handler registered with the SDK while registering the Control Point. * This callback funtion detects the type of callback, and passes the request on to * the appropriate function. * * Parameters: * EventType -- The type of callback event * Event -- Data structure containing event data * Cookie -- Optional data specified during callback registration * * Return: * Always zero ********************************************************************************/ int WscUPnPCPDeviceHandler( IN Upnp_EventType EventType, IN void *Event, IN void *Cookie) { //wsc_PrintEvent( EventType, Event ); switch (EventType) { /* SSDP Stuff */ case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_SEARCH_RESULT: { struct Upnp_Discovery *d_event = (struct Upnp_Discovery *)Event; unsigned int ipAddr = 0; if (d_event->ErrCode != UPNP_E_SUCCESS) { DBGPRINTF(RT_DBG_ERROR, "Error in Discovery Adv Callback -- %d\n", d_event->ErrCode); } else { if (strcmp(d_event->DeviceType, WscDeviceTypeStr) == 0) { //We just need to take care about the WscDeviceTypeStr DBGPRINTF(RT_DBG_INFO, "Receive a Advertisement from a WFADevice(URL=%s)\n", d_event->Location); if (WscUPnPCPAddDevice(WscDeviceTypeStr, d_event, &ipAddr) == WSC_SYS_SUCCESS) { WscUPnPCPDumpList(); // Printing the Wsc Device List for debug WscUPnPCPSendAction(ipAddr,"GetDeviceInfo", NULL, NULL, 0); } } } break; } case UPNP_DISCOVERY_SEARCH_TIMEOUT: // Nothing to do here.. break; case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: { struct Upnp_Discovery *d_event = (struct Upnp_Discovery *)Event; if (d_event->ErrCode != UPNP_E_SUCCESS) { DBGPRINTF(RT_DBG_ERROR, "Error in Discovery ByeBye Callback -- %d\n", d_event->ErrCode); } else { DBGPRINTF(RT_DBG_INFO, "Received ByeBye for Device: %s\n", d_event->DeviceId); WscUPnPCPRemoveDevice(d_event->DeviceId); //Dump it for debug WscUPnPCPDumpList(); } break; } /* 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) DBGPRINTF(RT_DBG_ERROR, "Error in Action Complete Callback -- %d\n", a_event->ErrCode); else { DBGPRINTF(RT_DBG_INFO, "Get event:UPNP_CONTROL_ACTION_COMPLETE!\n"); WscUPnPCPHandleActionResponse(a_event); } 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) { DBGPRINTF(RT_DBG_ERROR, "Error in Get Var Complete Callback -- %d\n", sv_event->ErrCode); } else { WscUPnPCPHandleGetVar(sv_event->CtrlUrl, sv_event->StateVarName, sv_event->CurrentVal); } break; } /* GENA Stuff */ case UPNP_EVENT_RECEIVED: { struct Upnp_Event *e_event = (struct Upnp_Event *)Event; DBGPRINTF(RT_DBG_INFO, "Get event:UPNP_EVENT_RECEIVED!\n"); WscUPnPCPHandleEvent(e_event->Sid, e_event->EventKey, e_event->ChangedVariables); break; } case UPNP_EVENT_SUBSCRIBE_COMPLETE: case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: case UPNP_EVENT_RENEWAL_COMPLETE: { struct Upnp_Event_Subscribe *es_event = (struct Upnp_Event_Subscribe *)Event; if (es_event->ErrCode != UPNP_E_SUCCESS) { DBGPRINTF(RT_DBG_ERROR, "Error in Event Subscribe Callback -- %d\n", es_event->ErrCode); } else { WscUPnPCPHandleSubscribeUpdate(es_event->PublisherUrl, es_event->Sid, es_event->TimeOut); } break; } case UPNP_EVENT_AUTORENEWAL_FAILED: case UPNP_EVENT_SUBSCRIPTION_EXPIRED: { int TimeOut = DEF_SUBSCRIPTION_TIMEOUT; Upnp_SID newSID; int ret; struct Upnp_Event_Subscribe *es_event = (struct Upnp_Event_Subscribe *)Event; ret = UpnpSubscribe(WscCPHandle, es_event->PublisherUrl, &TimeOut, newSID); if (ret == UPNP_E_SUCCESS) { DBGPRINTF(RT_DBG_INFO, "Subscribed to EventURL with SID=%s\n", newSID); WscUPnPCPHandleSubscribeUpdate(es_event->PublisherUrl, newSID, TimeOut); } else { DBGPRINTF(RT_DBG_ERROR, "Error Subscribing to EventURL -- %d\n", ret); } break; } /* 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: break; } return 0; } /******************************************************************************** * WscUPnPCPGetVar * * Description: * Send a GetVar request to the specified service of a device. * * Parameters: * ipAddr -- The IP address of the device. * varname -- The name of the variable to request. * * Return: * UPNP_E_SUCCESS - if success * WSC_SYS_ERROR - if failure ********************************************************************************/ int WscUPnPCPGetVar( IN uint32 ipAddr, IN char *varname) { struct upnpDeviceNode *devnode; int rc; rc = WscUPnPCPGetDevice(ipAddr, &devnode); if (rc == WSC_SYS_SUCCESS) { rc = UpnpGetServiceVarStatusAsync( WscCPHandle, devnode->device.services.ControlURL, varname, WscUPnPCPDeviceHandler, NULL); if( rc != UPNP_E_SUCCESS ) { DBGPRINTF(RT_DBG_ERROR, "Error in UpnpGetServiceVarStatusAsync -- %d\n", rc); rc = WSC_SYS_ERROR; } } return rc; } #if 0 int WscUPnPCPGetVarSampleCode( IN int devnum) { return WscUPnPCPGetVar(devnum, "Power"); } #endif /******************************************************************************** * WscUPnPCPVerifyTimeouts * * Description: * Checks the advertisement each device in the global device list. * If an advertisement expires, the device is removed from the list. * If an advertisement is about to expire, a search request is sent * for that device. * * Parameters: * incr -- The increment to subtract from the timeouts each time the * function is called. * * Return: * None ********************************************************************************/ void WscUPnPCPVerifyTimeouts(int incr) { struct upnpDeviceNode *prevdevnode, *curdevnode; int ret, timeLeft; prevdevnode = NULL; curdevnode = WscDeviceList; while (curdevnode) { curdevnode->device.timeCount += incr; timeLeft = curdevnode->device.AdvrTimeOut - curdevnode->device.timeCount; if (timeLeft <= 0) { /* This advertisement has expired, so we should remove the device from the list */ if (WscDeviceList == curdevnode) WscDeviceList = curdevnode->next; else prevdevnode->next = curdevnode->next; DBGPRINTF(RT_DBG_INFO, "%s(), delete the node(ipAddr=0x%08x)!\n", __FUNCTION__, curdevnode->device.ipAddr); WscUPnPCPDeleteNode(curdevnode); curdevnode = prevdevnode ? prevdevnode->next : WscDeviceList; } else { if (timeLeft < 3 * incr) { /* This advertisement is about to expire, so send out a search request for this device UDN to try to renew */ ret = UpnpSearchAsync(WscCPHandle, incr, curdevnode->device.UDN, NULL); if (ret != UPNP_E_SUCCESS) DBGPRINTF(RT_DBG_ERROR, "Err sending SearchReq for Device UDN: %s -- err = %d\n", curdevnode->device.UDN, ret); } prevdevnode = curdevnode; curdevnode = curdevnode->next; } } } /******************************************************************************** * WscUPnPCPHouseKeep * * Description: * Function that runs in its own thread and monitors advertisement * and subscription timeouts for devices in the global device list. * * Parameters: * None * * Return: * UPNP_E_SUCCESS - if success * WSC_SYS_ERROR - if failure ********************************************************************************/ void *WscUPnPCPHouseKeep(void *args) { int incr = 30; // how often to verify the timeouts, in seconds while(1) { sleep(incr); WscUPnPCPVerifyTimeouts(incr); } }