// Called by the UPnP Remote I/O Microstack // Implements the SetPeerOverride call, lets a CP connect this RIO client to // a new URI. If this RIO client is currently connected, it will disconnect and // switch to the new URI. void UpnpRemoteIOClient_RemoteIO_SetPeerOverride(void* upnptoken,char* PeerConnection) { struct parser_result* ParsedAddress = NULL; char* RemoteIOSessionPath = NULL; char* RemoteIOSessionAddress = NULL; int address = 0; if (upnptoken && (PeerConnection == NULL || (int)strlen(PeerConnection) < 7)) { UpnpResponse_Error(upnptoken,700,"Invalid PeerConnection"); return; } sem_wait(&RemoteIOLock); if (RIO->PeerConnection == NULL || strcmp(RIO->PeerConnection,PeerConnection) != 0) { if (RIO->PeerConnection != NULL) { // Disconnect the socket ILibAsyncSocket_Disconnect(RIO->Session); free(RIO->PeerConnection); } // Set the new session URI RIO->PeerConnection = (char*)malloc((int)strlen(PeerConnection) + 1); strcpy(RIO->PeerConnection,PeerConnection); // Event the new connection UpnpSetState_RemoteIOClient_RemoteIO_PeerConnection(RIO->RIOmicroStack,RIO->PeerConnection); // Connect session ParseUri(RIO->PeerConnection,&RemoteIOSessionAddress,&RIO->SessionPort,&RemoteIOSessionPath); free(RemoteIOSessionPath); ParsedAddress = ILibParseString(RemoteIOSessionAddress,0,(int)strlen(RemoteIOSessionAddress),".",1); address = atoi(ParsedAddress->FirstResult->data); address += atoi(ParsedAddress->FirstResult->NextResult->data) << 8; address += atoi(ParsedAddress->FirstResult->NextResult->NextResult->data) << 16; address += atoi(ParsedAddress->FirstResult->NextResult->NextResult->NextResult->data) << 24; ILibAsyncSocket_ConnectTo(RIO->Session,0,address,RIO->SessionPort,NULL,NULL); ILibDestructParserResults(ParsedAddress); free(RemoteIOSessionAddress); sem_post(&RemoteIOLock); // Event the user if (RemoteIOConnectionChanged != NULL) RemoteIOConnectionChanged(RIO->PeerConnection); } else { sem_post(&RemoteIOLock); } if(upnptoken) {UpnpResponse_RemoteIOClient_RemoteIO_SetPeerOverride(upnptoken);} }
// Called by the UPnP Remote I/O Microstack // Implements the RegisterChannel call, lets the CP un-register a RIO channel. void UpnpRemoteIOClient_ChannelManager_UnregisterChannel(void* upnptoken,char* PeerConnection) { // Scan the channel list for an existing channel struct RemoteIOChannel* channelprevious = NULL; struct RemoteIOChannel* channelindex = RIO->ChannelList; printf("UnRegisterChannel: %s\r\n",PeerConnection); if (PeerConnection == NULL) { if (upnptoken != NULL) UpnpResponse_Error(upnptoken,800,"Invalid PeerConnection URI"); return; } sem_wait(&RemoteIOLock); while (channelindex != NULL) { // Look for a match if (strcmp(channelindex->uri,PeerConnection) == 0) break; channelprevious = channelindex; channelindex = channelindex->next; } // Delete the channel from the list, and free the channel struct if (channelindex != NULL) { ILibLifeTime_Remove(RIO->RIOLifeTime,channelindex); if (channelprevious == NULL) { RIO->ChannelList = channelindex->next; } else { channelprevious->next = channelindex->next; } free(channelindex->name); free(channelindex->uri); free(channelindex); // Set the channels to be evented if (RIO->EventModerationSet == 0) { ILibLifeTime_Add(RIO->RIOLifeTime,NULL,2,&RemoteIO_EventChannelList, NULL); RIO->EventModerationSet = 1; } } if (upnptoken != NULL) UpnpResponse_RemoteIOClient_ChannelManager_UnregisterChannel(upnptoken); sem_post(&RemoteIOLock); }
// Called by the UPnP Remote I/O Microstack // Implements the ForceDisconnect call, lets a CP connect this RIO client // to a URI if, and only if, this RIO client is not currently connected. void UpnpRemoteIO_SetPeerInterlock(void* upnptoken,char* PeerConnection) { struct parser_result* ParsedAddress = NULL; char* RemoteIOSessionPath = NULL; char* RemoteIOSessionAddress = NULL; int address = 0; if (PeerConnection == NULL || (int)strlen(PeerConnection) < 7) { UpnpResponse_Error(upnptoken,700,"Invalid PeerConnection"); return; } sem_wait(&RemoteIOLock); if (RIO->PeerConnection == NULL) { RIO->PeerConnection = (char*)RIO_MALLOC((int)strlen(PeerConnection) + 1); strcpy(RIO->PeerConnection,PeerConnection); // Event the new connection UpnpSetState_RemoteIO_PeerConnection(RIO->RIOmicroStack,RIO->PeerConnection); // Connect session ParseUri(RIO->PeerConnection,&RemoteIOSessionAddress,&RIO->SessionPort,&RemoteIOSessionPath); RIO_FREE(RemoteIOSessionPath); ParsedAddress = ILibParseString(RemoteIOSessionAddress,0,(int)strlen(RemoteIOSessionAddress),".",1); address = atoi(ParsedAddress->FirstResult->data); address += atoi(ParsedAddress->FirstResult->NextResult->data) << 8; address += atoi(ParsedAddress->FirstResult->NextResult->NextResult->data) << 16; address += atoi(ParsedAddress->FirstResult->NextResult->NextResult->NextResult->data) << 24; ILibConnectTo(RIO->Session,0,address,RIO->SessionPort); ILibDestructParserResults(ParsedAddress); RIO_FREE(RemoteIOSessionAddress); UpnpResponse_RemoteIO_SetPeerInterlock(upnptoken,RIO->PeerConnection); sem_post(&RemoteIOLock); // Event the user if (RemoteIOConnectionChanged != NULL) RemoteIOConnectionChanged(RIO->PeerConnection); } else { UpnpResponse_RemoteIO_SetPeerInterlock(upnptoken,RIO->PeerConnection); sem_post(&RemoteIOLock); } }
void UpnpConnectionManager_GetCurrentConnectionInfo(void* upnptoken,int ConnectionID) { /* * HTTP connections are stateless, from the perspective of UPnP AV. * This is largely because we can't really monitor connection lifetime * of HTTP traffic in the UPnP AV sense, without risking memory leaks. * * TODO: Low priority - Add support for connection-lifetime aware protocols. */ #ifdef _DEBUG printf("UPnP Invoke: UpnpConnectionManager_GetCurrentConnectionInfo(%u);\r\n",ConnectionID); #endif UpnpResponse_Error(upnptoken, (int) MSL_Error_ConnectionDoesNotExist, MSL_ErrorMsg_ConnectionDoesNotExist); }
/* see header file */ void MSL_ForResponse_RespondError(struct MSL_CdsQuery *cdsQuery, int errorCode, const char *errorMsg) { ASSERT(cdsQuery != NULL); UpnpResponse_Error(cdsQuery->UpnpToken, errorCode, errorMsg); }
void UpnpContentDirectory_Browse(void* upnptoken,char* ObjectID,char* BrowseFlag,char* Filter,unsigned int StartingIndex,unsigned int RequestedCount,char* SortCriteria) { struct MSL_CdsQuery *browseArgs; int errorCode; const char *errorMsg; enum MSL_Enum_QueryTypes browseChildren; int size; #ifdef _DEBUG printf("UPnP Invoke: UpnpContentDirectory_Browse();\r\n"); #endif /* * Validate arguments. */ errorCode = 0; errorMsg = NULL; if (stricmp(BrowseFlag, CDS_STRING_BROWSE_DIRECT_CHILDREN) == 0) { browseChildren = MSL_Query_BrowseDirectChildren; } else if (stricmp(BrowseFlag, CDS_STRING_BROWSE_METADATA) == 0) { browseChildren = MSL_Query_BrowseMetadata; } else { fprintf(stderr, "WARNING: UpnpContentDirectory_Browse(): Possible error with generated microstack. Encountered BrowseFlag='%s'\r\n", BrowseFlag); errorCode = MSL_ERROR_CODE_INVALID_BROWSEFLAG; errorMsg = MSL_ERROR_MSG_INVALID_BROWSEFLAG; } if ((errorCode != 0) || (errorMsg != NULL)) { /* ensure that the error code and message map to something */ if (errorCode == 0) { errorCode = MSL_ERROR_CODE_INTERNAL; } if (errorMsg == NULL) { errorMsg = MSL_ERROR_MSG_INTERNAL; } UpnpResponse_Error(upnptoken, errorCode, errorMsg); } else { /* * Input arguments valid at UPnP layer. * Create an MSL_CdsQuery object and execute * the browse callback so that application can return results. */ browseArgs = (struct MSL_CdsQuery*) MSL_MALLOC (sizeof(struct MSL_CdsQuery)); memset(browseArgs, 0, sizeof(struct MSL_CdsQuery)); browseArgs->QueryType = browseChildren; size = (int) strlen(Filter)+1; browseArgs->Filter = (char*) MSL_MALLOC(size); memcpy(browseArgs->Filter, Filter, size); browseArgs->MediaServerObject = MSL_TheMslObj; size = (int) strlen(ObjectID)+1; browseArgs->ObjectID = (char*) MSL_MALLOC(size); memcpy(browseArgs->ObjectID, ObjectID, size); /* Be sure to unescape it first. */ ILibInPlaceXmlUnEscape(browseArgs->ObjectID); browseArgs->RequestedCount = RequestedCount; size = (int) strlen(SortCriteria)+1; browseArgs->SortCriteria = (char*) MSL_MALLOC(size); memcpy(browseArgs->SortCriteria, SortCriteria, size); browseArgs->StartingIndex = StartingIndex; browseArgs->UpnpToken = upnptoken; browseArgs->UserObject = NULL; browseArgs->IpAddrList = NULL; MSL_Helper_PopulateIpInfo(MSL_TheMslObj, browseArgs); if (MSL_Callback_OnQuery != NULL) { MSL_Callback_OnQuery(browseArgs); } } }
// Called by the UPnP Remote I/O Microstack // Implements the RegisterChannel call, lets the CP register a new RIO channels for a // certain amont of time. The CP must re-register the channel from time-to-time to // prevent the channel from expiring. void UpnpRemoteIOClient_ChannelManager_RegisterChannel(void* upnptoken,char* Name,char* PeerConnection,int Timeout) { // Scan the channel list for an existing channel struct RemoteIOChannel* channelindex = RIO->ChannelList; struct RemoteIOChannel* newchannel; printf("RegisterChannel[%s] (%d): %s\r\n",PeerConnection,Timeout,Name); if (PeerConnection == NULL) { if (upnptoken != NULL) UpnpResponse_Error(upnptoken,800,"Invalid PeerConnection URI"); return; } sem_wait(&RemoteIOLock); while (channelindex != NULL) { // Look for a match if (strcmp(channelindex->uri,PeerConnection) == 0) break; channelindex = channelindex->next; } if (channelindex != NULL) { // Update the expiration time ILibLifeTime_Remove(RIO->RIOLifeTime,channelindex); #ifdef _WIN32_WCE channelindex->expiration = (GetTickCount() / 1000) + Timeout; ILibLifeTime_Add(RIO->RIOLifeTime,channelindex,Timeout,&RemoteIO_ChannelExpireSink, NULL); #elif WIN32 channelindex->expiration = (GetTickCount() / 1000) + Timeout; ILibLifeTime_Add(RIO->RIOLifeTime,channelindex,Timeout,&RemoteIO_ChannelExpireSink, NULL); #elif _POSIX gettimeofday(&(channelindex->expiration),NULL); (channelindex->expiration).tv_sec += (int)Timeout; ILibLifeTime_Add(RIO->RIOLifeTime,channelindex,Timeout,&RemoteIO_ChannelExpireSink, NULL); #endif } else { // Add a new channel to the channel list newchannel = (struct RemoteIOChannel*)malloc(sizeof(struct RemoteIOChannel)); newchannel->name = (char*)malloc(strlen(Name)+1); strcpy(newchannel->name,Name); newchannel->uri = (char*)malloc(strlen(PeerConnection)+1); strcpy(newchannel->uri,PeerConnection); #ifdef _WIN32_WCE newchannel->expiration = (GetTickCount() / 1000) + Timeout; ILibLifeTime_Add(RIO->RIOLifeTime,newchannel,Timeout,&RemoteIO_ChannelExpireSink, NULL); #elif WIN32 newchannel->expiration = (GetTickCount() / 1000) + Timeout; ILibLifeTime_Add(RIO->RIOLifeTime,newchannel,Timeout,&RemoteIO_ChannelExpireSink, NULL); #elif _POSIX gettimeofday(&(newchannel->expiration),NULL); (newchannel->expiration).tv_sec += (int)Timeout; ILibLifeTime_Add(RIO->RIOLifeTime,newchannel,Timeout,&RemoteIO_ChannelExpireSink, NULL); #endif newchannel->next = RIO->ChannelList; RIO->ChannelList = newchannel; // Set the channels to be evented if (RIO->EventModerationSet == 0) { ILibLifeTime_Add(RIO->RIOLifeTime,NULL,2,&RemoteIO_EventChannelList, NULL); RIO->EventModerationSet = 1; } } UpnpResponse_RemoteIOClient_ChannelManager_RegisterChannel(upnptoken); sem_post(&RemoteIOLock); }