upnp UpnpSendAdvertisement详解

公羊凌
2023-12-01
/*!
 * \brief Sends out the discovery announcements for all devices and services
 * for a device.
 *
 * Each announcement is made with the same expiration time.
 *
 * This is a synchronous call.
 *
 * \return An integer representing one of the following:
 *     \li \c UPNP_E_SUCCESS: The operation completed successfully.
 *     \li \c UPNP_E_INVALID_HANDLE: The handle is not a valid 
 *             device handle.
 *     \li \c UPNP_E_OUTOF_MEMORY: There are insufficient resources to 
 *             send future advertisements.
 */
EXPORT_SPEC int UpnpSendAdvertisement(
/*! The device handle for which to send out the announcements. */
UpnpDevice_Handle Hnd,
/*! The expiration age, in seconds, of the announcements. */

int Exp);


如upnp.h的注释,此函数是device广告自己的接口。第一个参数是deviceHandle,第二个参数是有效期,秒为单位。

具体实现如下:

int UpnpSendAdvertisement(UpnpDevice_Handle Hnd, int Exp)
{
    return UpnpSendAdvertisementLowPower (Hnd, Exp, -1, -1, -1);
}

int UpnpSendAdvertisementLowPower(UpnpDevice_Handle Hnd, int Exp,
    int PowerState, int SleepPeriod, int RegistrationState)
{
    struct Handle_Info *SInfo = NULL;
    int retVal = 0,*ptrMx;
    upnp_timeout *adEvent;
    ThreadPoolJob job;

    ........
    HandleLock();
    switch( GetHandleInfo( Hnd, &SInfo ) ) {
    case HND_DEVICE:
        break;
    default:
        HandleUnlock();
        return UPNP_E_INVALID_HANDLE;
    }
    if( Exp < 1 )
        Exp = DEFAULT_MAXAGE;
    SInfo->MaxAge = Exp;
    SInfo->PowerState = PowerState;
    if( SleepPeriod < 0 )
        SleepPeriod = -1;
    SInfo->SleepPeriod = SleepPeriod;
    SInfo->RegistrationState = RegistrationState;
    HandleUnlock();
    retVal = AdvertiseAndReply( 1, Hnd, ( enum SsdpSearchType )0,         /*sendto 239.255.255.250:1900地址发送ssdp:alive消息,通过hnd带上deviceinfo,具体可以参考      
                                ( struct sockaddr * )NULL, ( char * )NULL,                        AdvertiseAndReply实现*/
                                ( char * )NULL, ( char * )NULL, Exp );

    if( retVal != UPNP_E_SUCCESS )
        return retVal;
    ptrMx = ( int * )malloc( sizeof( int ) );
    if( ptrMx == NULL )
        return UPNP_E_OUTOF_MEMORY;
    adEvent = ( upnp_timeout * ) malloc( sizeof( upnp_timeout ) );

    *ptrMx = Exp;                                                                                /*从这里看到的信息是:讲hnd跟exp存到了adEvent里面。用于AutoAdvertise里面使用*/
    adEvent->handle = Hnd;                                                          /*AutoAdvertise顾名思义,就是自动发广告的意思。而AutoAdvertise就是UpnpSendAdvertisement*/
    adEvent->Event = ptrMx;          

#ifdef SSDP_PACKET_DISTRIBUTE                                                                                    /*此处从宏注释中可以看出,意思是为了ssdp packets顺利到达ctrl point*/
    TPJobInit( &job, ( start_routine ) AutoAdvertise, adEvent );
    TPJobSetFreeFunction( &job, ( free_routine ) free_upnp_timeout );
    TPJobSetPriority( &job, MED_PRIORITY );
    if( ( retVal = TimerThreadSchedule( &gTimerThread,
                                        ( ( Exp / 2 ) -
                                          ( AUTO_ADVERTISEMENT_TIME ) ),
                                        REL_SEC, &job, SHORT_TERM,
                                        &( adEvent->eventId ) ) )
#else
........//省略
#endif


    HandleUnlock();

    return retVal;
}

void AutoAdvertise(void *input)

{
upnp_timeout *event = (upnp_timeout *)input;


UpnpSendAdvertisement(event->handle, *((int *)event->Event));
free_upnp_timeout(event);
}


好的,现在大概思路非常清晰了。

1 UpnpSendAdvertisement通过AdvertiseAndReply往239.255.255.250:1900 地址发送ssdp:alive为messageType的discovery消息。

2 UpnpSendAdvertisement为了增加ssdp消息到达ctrl point的可能性,以及循环发ssdp消息,嵌套调用了AutoAdvertise,即UpnpSendAdvertisement。

3 以默认的100s exp有效期为参考,整体的时间点划分是:发布一个ssdp packets,exp/2-30=20s后再发布一条,然后再20s发布一条。。。。,即以exp/2-30的周期发送。

注意:如果exp小于62 相当于周期为0,即不停的发。。。。可以看如下意思是:根据abs绝对时间轴来run event动作。time时间最小(早)的先执行。

    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))
                rc = 0;
            found = 1;
            break;
        }
        tempNode = ListNext( &timer->eventQ, tempNode );
    }

 类似资料: