Changeset 2956 for pjproject


Ignore:
Timestamp:
Oct 20, 2009 1:56:26 PM (15 years ago)
Author:
bennylp
Message:

Initial commit for ticket #937: Revamping of presence management to make it more efficient

Presence enhancements:

  • finer grained buddy lock object, instead of using global PJSUA-LIB's mutex
  • individual resubscription timer for buddies and also add random delay interval so that resubscriptions don't happen simultaneously (may hog processing and bandwidth).
  • in general reduced the use of global PJSUA-LIB's mutex for more efficiency
  • added last termination code in buddy info
  • use the RPID note's text for buddy's offline status rather than the default "offline" status, if available
  • resubscribe automatically on several termination causes as explained in the ticket (still untested)

General enhancements:

  • added pjsua_schedule_timer() and pjsua_cancel_timer() APIs
Location:
pjproject/trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r2907 r2956  
    26202620    pjsua_buddy_get_info(buddy_id, &info); 
    26212621 
    2622     PJ_LOG(3,(THIS_FILE, "%.*s status is %.*s (subscription state is %s)", 
     2622    PJ_LOG(3,(THIS_FILE, "%.*s status is %.*s, subscription state is %s " 
     2623                         "(last termination reason code=%d %.*s)", 
    26232624              (int)info.uri.slen, 
    26242625              info.uri.ptr, 
    26252626              (int)info.status_text.slen, 
    26262627              info.status_text.ptr, 
    2627               info.sub_state_name)); 
     2628              info.sub_state_name, 
     2629              info.sub_term_code, 
     2630              (int)info.sub_term_reason.slen, 
     2631              info.sub_term_reason.ptr)); 
    26282632} 
    26292633 
  • pjproject/trunk/pjsip/include/pjsip_simple.h

    r2394 r2956  
    3636 
    3737#include <pjsip-simple/evsub.h> 
     38#include <pjsip-simple/evsub_msg.h> 
    3839#include <pjsip-simple/iscomposing.h> 
    3940#include <pjsip-simple/presence.h> 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r2943 r2956  
    13981398 
    13991399/** 
     1400 * Schedule a timer entry. Note that the timer callback may be executed 
     1401 * by different thread, depending on whether worker thread is enabled or 
     1402 * not. 
     1403 * 
     1404 * @param entry         Timer heap entry. 
     1405 * @param delay     The interval to expire. 
     1406 * 
     1407 * @return              PJ_SUCCESS on success, or the appropriate error code. 
     1408 * 
     1409 * @see pjsip_endpt_schedule_timer() 
     1410 */ 
     1411PJ_DECL(pj_status_t) pjsua_schedule_timer(pj_timer_entry *entry, 
     1412                                          const pj_time_val *delay); 
     1413 
     1414 
     1415/** 
     1416 * Cancel the previously scheduled timer. 
     1417 * 
     1418 * @param entry         Timer heap entry. 
     1419 * 
     1420 * @see pjsip_endpt_cancel_timer() 
     1421 */ 
     1422PJ_DECL(void) pjsua_cancel_timer(pj_timer_entry *entry); 
     1423 
     1424 
     1425/** 
    14001426 * This is a utility function to display error message for the specified  
    14011427 * error code. The error message will be sent to the log. 
     
    31293155 
    31303156    /** 
    3131      * Specifies the last presence subscription terminatino reason. If  
     3157     * Specifies the last presence subscription termination code. This would 
     3158     * return the last status of the SUBSCRIBE request. If the subscription 
     3159     * is terminated with NOTIFY by the server, this value will be set to 
     3160     * 200, and subscription termination reason will be given in the 
     3161     * \a sub_term_reason field. 
     3162     */ 
     3163    unsigned            sub_term_code; 
     3164 
     3165    /** 
     3166     * Specifies the last presence subscription termination reason. If  
    31323167     * presence subscription is currently active, the value will be empty. 
    31333168     */ 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h

    r2945 r2956  
    186186    pjsip_dialog        *dlg;       /**< The underlying dialog.         */ 
    187187    pjsip_evsub         *sub;       /**< Buddy presence subscription    */ 
     188    unsigned             term_code; /**< Subscription termination code  */ 
    188189    pj_str_t             term_reason;/**< Subscription termination reason */ 
    189190    pjsip_pres_status    status;    /**< Buddy presence status.         */ 
    190  
     191    pj_timer_entry       timer;     /**< Resubscription timer           */ 
    191192} pjsua_buddy; 
    192193 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r2949 r2956  
    23192319} 
    23202320 
     2321/* 
     2322 * Schedule a timer entry.  
     2323 */ 
     2324PJ_DEF(pj_status_t) pjsua_schedule_timer( pj_timer_entry *entry, 
     2325                                          const pj_time_val *delay) 
     2326{ 
     2327    return pjsip_endpt_schedule_timer(pjsua_var.endpt, entry, delay); 
     2328} 
     2329 
     2330/* 
     2331 * Cancel the previously scheduled timer. 
     2332 * 
     2333 */ 
     2334PJ_DEF(void) pjsua_cancel_timer(pj_timer_entry *entry) 
     2335{ 
     2336    pjsip_endpt_cancel_timer(pjsua_var.endpt, entry); 
     2337} 
    23212338 
    23222339/**  
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c

    r2943 r2956  
    2525 
    2626 
    27 static void subscribe_buddy_presence(unsigned index); 
     27static void subscribe_buddy_presence(pjsua_buddy_id buddy_id); 
     28static void unsubscribe_buddy_presence(pjsua_buddy_id buddy_id); 
    2829 
    2930 
     
    3132 * Find buddy. 
    3233 */ 
    33 static pjsua_buddy_id pjsua_find_buddy(const pjsip_uri *uri) 
     34static pjsua_buddy_id find_buddy(const pjsip_uri *uri) 
    3435{ 
    3536    const pjsip_sip_uri *sip_uri; 
     
    6162} 
    6263 
     64#define LOCK_DIALOG     1 
     65#define LOCK_PJSUA      2 
     66#define LOCK_ALL        (LOCK_DIALOG | LOCK_PJSUA) 
     67 
     68/* Buddy lock object */ 
     69struct buddy_lock 
     70{ 
     71    pjsua_buddy     *buddy; 
     72    pjsip_dialog    *dlg; 
     73    pj_uint8_t       flag; 
     74}; 
     75 
     76/* Acquire lock to the specified buddy_id */ 
     77pj_status_t lock_buddy(const char *title, 
     78                       pjsua_buddy_id buddy_id, 
     79                       struct buddy_lock *lck, 
     80                       unsigned _unused_) 
     81{ 
     82    enum { MAX_RETRY=50 }; 
     83    pj_bool_t has_pjsua_lock = PJ_FALSE; 
     84    unsigned retry; 
     85 
     86    PJ_UNUSED_ARG(_unused_); 
     87 
     88    pj_bzero(lck, sizeof(*lck)); 
     89 
     90    for (retry=0; retry<MAX_RETRY; ++retry) { 
     91         
     92        if (PJSUA_TRY_LOCK() != PJ_SUCCESS) { 
     93            pj_thread_sleep(retry/10); 
     94            continue; 
     95        } 
     96 
     97        has_pjsua_lock = PJ_TRUE; 
     98        lck->flag = LOCK_PJSUA; 
     99        lck->buddy = &pjsua_var.buddy[buddy_id]; 
     100 
     101        if (lck->buddy->dlg == NULL) 
     102            return PJ_SUCCESS; 
     103 
     104        if (pjsip_dlg_try_inc_lock(lck->buddy->dlg) != PJ_SUCCESS) { 
     105            lck->flag = 0; 
     106            lck->buddy = NULL; 
     107            has_pjsua_lock = PJ_FALSE; 
     108            PJSUA_UNLOCK(); 
     109            pj_thread_sleep(retry/10); 
     110            continue; 
     111        } 
     112 
     113        lck->dlg = lck->buddy->dlg; 
     114        lck->flag = LOCK_DIALOG; 
     115        PJSUA_UNLOCK(); 
     116 
     117        break; 
     118    } 
     119 
     120    if (lck->flag == 0) { 
     121        if (has_pjsua_lock == PJ_FALSE) 
     122            PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire PJSUA mutex " 
     123                                 "(possibly system has deadlocked) in %s", 
     124                                 title)); 
     125        else 
     126            PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire dialog mutex " 
     127                                 "(possibly system has deadlocked) in %s", 
     128                                 title)); 
     129        return PJ_ETIMEDOUT; 
     130    } 
     131     
     132    return PJ_SUCCESS; 
     133} 
     134 
     135/* Release buddy lock */ 
     136static void unlock_buddy(struct buddy_lock *lck) 
     137{ 
     138    if (lck->flag & LOCK_DIALOG) 
     139        pjsip_dlg_dec_lock(lck->dlg); 
     140 
     141    if (lck->flag & LOCK_PJSUA) 
     142        PJSUA_UNLOCK(); 
     143} 
     144 
    63145 
    64146/* 
     
    87169    if (!uri) 
    88170        buddy_id = PJSUA_INVALID_ID; 
    89     else 
    90         buddy_id = pjsua_find_buddy(uri); 
     171    else { 
     172        PJSUA_LOCK(); 
     173        buddy_id = find_buddy(uri); 
     174        PJSUA_UNLOCK(); 
     175    } 
    91176 
    92177    pj_pool_release(pool); 
     
    140225{ 
    141226    unsigned total=0; 
     227    struct buddy_lock lck; 
    142228    pjsua_buddy *buddy; 
    143  
    144     PJ_ASSERT_RETURN(buddy_id>=0 &&  
    145                        buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy),  
    146                      PJ_EINVAL); 
    147  
    148     PJSUA_LOCK(); 
     229    pj_status_t status; 
     230 
     231    PJ_ASSERT_RETURN(pjsua_buddy_is_valid(buddy_id),  PJ_EINVAL); 
    149232 
    150233    pj_bzero(info, sizeof(pjsua_buddy_info)); 
    151234 
    152     buddy = &pjsua_var.buddy[buddy_id]; 
     235    status = lock_buddy("pjsua_buddy_get_info()", buddy_id, &lck, 0); 
     236    if (status != PJ_SUCCESS) 
     237        return status; 
     238 
     239    buddy = lck.buddy; 
    153240    info->id = buddy->index; 
    154241    if (pjsua_var.buddy[buddy_id].uri.slen == 0) { 
    155         PJSUA_UNLOCK(); 
     242        unlock_buddy(&lck); 
    156243        return PJ_SUCCESS; 
    157244    } 
     
    187274    } else { 
    188275        info->status = PJSUA_BUDDY_STATUS_OFFLINE; 
    189         info->status_text = pj_str("Offline"); 
     276        info->rpid = buddy->status.info[0].rpid; 
     277 
     278        if (info->rpid.note.slen) 
     279            info->status_text = info->rpid.note; 
     280        else 
     281            info->status_text = pj_str("Offline"); 
    190282    } 
    191283 
     
    194286 
    195287    /* subscription state and termination reason */ 
     288    info->sub_term_code = buddy->term_code; 
    196289    if (buddy->sub) { 
    197290        info->sub_state = pjsip_evsub_get_state(buddy->sub); 
     
    219312    } 
    220313 
    221     PJSUA_UNLOCK(); 
     314    unlock_buddy(&lck); 
    222315    return PJ_SUCCESS; 
    223316} 
     
    229322                                               void *user_data) 
    230323{ 
    231     PJ_ASSERT_RETURN(buddy_id>=0 &&  
    232                        buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), 
    233                      PJ_EINVAL); 
    234  
    235     PJSUA_LOCK(); 
     324    struct buddy_lock lck; 
     325    pj_status_t status; 
     326 
     327    PJ_ASSERT_RETURN(pjsua_buddy_is_valid(buddy_id), PJ_EINVAL); 
     328 
     329    status = lock_buddy("pjsua_buddy_set_user_data()", buddy_id, &lck, 0); 
     330    if (status != PJ_SUCCESS) 
     331        return status; 
    236332 
    237333    pjsua_var.buddy[buddy_id].user_data = user_data; 
    238334 
    239     PJSUA_UNLOCK(); 
     335    unlock_buddy(&lck); 
    240336 
    241337    return PJ_SUCCESS; 
     
    248344PJ_DEF(void*) pjsua_buddy_get_user_data(pjsua_buddy_id buddy_id) 
    249345{ 
     346    struct buddy_lock lck; 
     347    pj_status_t status; 
    250348    void *user_data; 
    251349 
    252     PJ_ASSERT_RETURN(buddy_id>=0 &&  
    253                        buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), 
    254                      NULL); 
    255  
    256     PJSUA_LOCK(); 
     350    PJ_ASSERT_RETURN(pjsua_buddy_is_valid(buddy_id), NULL); 
     351 
     352    status = lock_buddy("pjsua_buddy_get_user_data()", buddy_id, &lck, 0); 
     353    if (status != PJ_SUCCESS) 
     354        return NULL; 
    257355 
    258356    user_data = pjsua_var.buddy[buddy_id].user_data; 
    259357 
    260     PJSUA_UNLOCK(); 
     358    unlock_buddy(&lck); 
    261359 
    262360    return user_data; 
     
    383481PJ_DEF(pj_status_t) pjsua_buddy_del(pjsua_buddy_id buddy_id) 
    384482{ 
     483    struct buddy_lock lck; 
     484    pj_status_t status; 
     485 
    385486    PJ_ASSERT_RETURN(buddy_id>=0 &&  
    386487                        buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), 
     
    391492    } 
    392493 
     494    status = lock_buddy("pjsua_buddy_del()", buddy_id, &lck, 0); 
     495    if (status != PJ_SUCCESS) 
     496        return status; 
     497 
    393498    /* Unsubscribe presence */ 
    394499    pjsua_buddy_subscribe_pres(buddy_id, PJ_FALSE); 
    395  
    396     PJSUA_LOCK(); 
    397500 
    398501    /* Not interested with further events for this buddy */ 
     
    409512    reset_buddy(buddy_id); 
    410513 
    411     PJSUA_UNLOCK(); 
     514    unlock_buddy(&lck); 
    412515    return PJ_SUCCESS; 
    413516} 
     
    420523                                                pj_bool_t subscribe) 
    421524{ 
    422     pjsua_buddy *buddy; 
    423  
    424     PJ_ASSERT_RETURN(buddy_id>=0 &&  
    425                         buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), 
    426                      PJ_EINVAL); 
    427  
    428     PJSUA_LOCK(); 
    429  
    430     buddy = &pjsua_var.buddy[buddy_id]; 
    431     buddy->monitor = subscribe; 
    432  
    433     PJSUA_UNLOCK(); 
    434  
    435     pjsua_pres_refresh(); 
    436  
     525    struct buddy_lock lck; 
     526    pj_status_t status; 
     527 
     528    PJ_ASSERT_RETURN(pjsua_buddy_is_valid(buddy_id), PJ_EINVAL); 
     529 
     530    status = lock_buddy("pjsua_buddy_subscribe_pres()", buddy_id, &lck, 0); 
     531    if (status != PJ_SUCCESS) 
     532        return status; 
     533 
     534    lck.buddy->monitor = subscribe; 
     535 
     536    pjsua_buddy_update_pres(buddy_id); 
     537 
     538    unlock_buddy(&lck); 
    437539    return PJ_SUCCESS; 
    438540} 
     
    444546PJ_DEF(pj_status_t) pjsua_buddy_update_pres(pjsua_buddy_id buddy_id) 
    445547{ 
    446     pjsua_buddy *buddy; 
    447  
    448     PJ_ASSERT_RETURN(buddy_id>=0 &&  
    449                         buddy_id<(int)PJ_ARRAY_SIZE(pjsua_var.buddy), 
    450                      PJ_EINVAL); 
    451  
    452     PJSUA_LOCK(); 
    453  
    454     buddy = &pjsua_var.buddy[buddy_id]; 
    455  
    456     /* Return error if buddy's presence monitoring is not enabled */ 
    457     if (!buddy->monitor) { 
    458         PJSUA_UNLOCK(); 
    459         return PJ_EINVALIDOP; 
     548    struct buddy_lock lck; 
     549    pj_status_t status; 
     550 
     551    PJ_ASSERT_RETURN(pjsua_buddy_is_valid(buddy_id), PJ_EINVAL); 
     552 
     553    status = lock_buddy("pjsua_buddy_update_pres()", buddy_id, &lck, 0); 
     554    if (status != PJ_SUCCESS) 
     555        return status; 
     556 
     557    /* Is this an unsubscribe request? */ 
     558    if (!lck.buddy->monitor) { 
     559        unsubscribe_buddy_presence(buddy_id); 
     560        unlock_buddy(&lck); 
     561        return PJ_SUCCESS; 
    460562    } 
    461563 
    462564    /* Ignore if presence is already active for the buddy */ 
    463     if (buddy->sub) { 
    464         PJSUA_UNLOCK(); 
     565    if (lck.buddy->sub) { 
     566        unlock_buddy(&lck); 
    465567        return PJ_SUCCESS; 
    466568    } 
     
    469571    subscribe_buddy_presence(buddy_id); 
    470572 
    471     PJSUA_UNLOCK(); 
     573    unlock_buddy(&lck); 
    472574 
    473575    return PJ_SUCCESS; 
     
    806908        pjsua_buddy_id buddy_id; 
    807909 
    808         buddy_id = pjsua_find_buddy(rdata->msg_info.from->uri); 
     910        buddy_id = find_buddy(rdata->msg_info.from->uri); 
    809911 
    810912        (*pjsua_var.ua_cfg.cb.on_incoming_subscribe)(acc_id, uapres, buddy_id, 
     
    9521054 
    9531055    /* Subscribe to buddy's presence if we're not subscribed */ 
    954     buddy_id = pjsua_find_buddy(srv_pres->dlg->remote.info->uri); 
     1056    buddy_id = find_buddy(srv_pres->dlg->remote.info->uri); 
    9551057    if (buddy_id != PJSUA_INVALID_ID) { 
    9561058        pjsua_buddy *b = &pjsua_var.buddy[buddy_id]; 
     
    12811383 */ 
    12821384 
     1385static void buddy_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry) 
     1386{ 
     1387    pjsua_buddy *buddy = (pjsua_buddy*)entry->user_data; 
     1388 
     1389    PJ_UNUSED_ARG(th); 
     1390 
     1391    entry->id = PJ_FALSE; 
     1392    pjsua_buddy_update_pres(buddy->index); 
     1393} 
     1394 
     1395/* Reschedule subscription refresh timer or terminate the subscription 
     1396 * refresh timer for the specified buddy. 
     1397 */ 
     1398static void buddy_resubscribe(pjsua_buddy *buddy, pj_bool_t resched, 
     1399                              unsigned msec_interval) 
     1400{ 
     1401    if (buddy->timer.id) { 
     1402        pjsua_cancel_timer(&buddy->timer); 
     1403        buddy->timer.id = PJ_FALSE; 
     1404    } 
     1405 
     1406    if (resched) { 
     1407        pj_time_val delay; 
     1408 
     1409        pj_timer_entry_init(&buddy->timer, 0, buddy, &buddy_timer_cb); 
     1410        delay.sec = 0; 
     1411        delay.msec = msec_interval; 
     1412        pj_time_val_normalize(&delay); 
     1413 
     1414        if (pjsua_schedule_timer(&buddy->timer, &delay)==PJ_SUCCESS) 
     1415            buddy->timer.id = PJ_TRUE; 
     1416    } 
     1417} 
     1418 
    12831419/* Callback called when *client* subscription state has changed. */ 
    12841420static void pjsua_evsub_on_state( pjsip_evsub *sub, pjsip_event *event) 
     
    12881424    PJ_UNUSED_ARG(event); 
    12891425 
    1290     PJSUA_LOCK(); 
    1291  
     1426    /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has 
     1427     *   a dialog attached to it, lock_buddy() will use the dialog 
     1428     *   lock, which we are currently holding! 
     1429     */ 
    12921430    buddy = (pjsua_buddy*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
    12931431    if (buddy) { 
     
    12991437 
    13001438        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { 
     1439            int resub_delay = -1; 
     1440 
    13011441            if (buddy->term_reason.ptr == NULL) { 
    13021442                buddy->term_reason.ptr = (char*)  
     
    13071447                       pjsip_evsub_get_termination_reason(sub),  
    13081448                       PJSUA_BUDDY_SUB_TERM_REASON_LEN); 
     1449 
     1450            buddy->term_code = 200; 
     1451 
     1452            /* Determine whether to resubscribe automatically */ 
     1453            if (event->type==PJSIP_EVENT_TSX_STATE) { 
     1454                const pjsip_transaction *tsx = event->body.tsx_state.tsx; 
     1455                if (pjsip_method_cmp(&tsx->method,  
     1456                                     &pjsip_subscribe_method)==0) 
     1457                { 
     1458                    buddy->term_code = tsx->status_code; 
     1459                    switch (tsx->status_code) { 
     1460                    case PJSIP_SC_CALL_TSX_DOES_NOT_EXIST: 
     1461                        /* 481: we refreshed too late? resubscribe 
     1462                         * immediately. 
     1463                         */ 
     1464                        resub_delay = 500; 
     1465                        break; 
     1466                    } 
     1467                } else if (pjsip_method_cmp(&tsx->method, 
     1468                                            &pjsip_notify_method)==0) 
     1469                { 
     1470                    if (pj_stricmp2(&buddy->term_reason, "deactivated")==0 || 
     1471                        pj_stricmp2(&buddy->term_reason, "timeout")==0) { 
     1472                        /* deactivated: The subscription has been terminated,  
     1473                         * but the subscriber SHOULD retry immediately with  
     1474                         * a new subscription. 
     1475                         */ 
     1476                        /* timeout: The subscription has been terminated  
     1477                         * because it was not refreshed before it expired. 
     1478                         * Clients MAY re-subscribe immediately. The  
     1479                         * "retry-after" parameter has no semantics for  
     1480                         * "timeout". 
     1481                         */ 
     1482                        resub_delay = 500; 
     1483                    }  
     1484                    else if (pj_stricmp2(&buddy->term_reason, "probation")==0|| 
     1485                             pj_stricmp2(&buddy->term_reason, "giveup")==0) { 
     1486                        /* probation: The subscription has been terminated,  
     1487                         * but the client SHOULD retry at some later time.   
     1488                         * If a "retry-after" parameter is also present, the  
     1489                         * client SHOULD wait at least the number of seconds  
     1490                         * specified by that parameter before attempting to re- 
     1491                         * subscribe. 
     1492                         */ 
     1493                        /* giveup: The subscription has been terminated because 
     1494                         * the notifier could not obtain authorization in a  
     1495                         * timely fashion.  If a "retry-after" parameter is  
     1496                         * also present, the client SHOULD wait at least the 
     1497                         * number of seconds specified by that parameter before 
     1498                         * attempting to re-subscribe; otherwise, the client  
     1499                         * MAY retry immediately, but will likely get put back 
     1500                         * into pending state. 
     1501                         */ 
     1502                        const pjsip_sub_state_hdr *sub_hdr; 
     1503                        pj_str_t sub_state = { "Subscription-State", 18 }; 
     1504                        const pjsip_msg *msg; 
     1505 
     1506                        msg = event->body.tsx_state.src.rdata->msg_info.msg; 
     1507                        sub_hdr = (const pjsip_sub_state_hdr*) 
     1508                                  pjsip_msg_find_hdr_by_name(msg, &sub_state, 
     1509                                                             NULL); 
     1510                        if (sub_hdr && sub_hdr->retry_after > 0) 
     1511                            resub_delay = sub_hdr->retry_after * 1000; 
     1512                    } 
     1513 
     1514                } 
     1515            } 
     1516 
     1517            /* For other cases of subscription termination, if resubscribe 
     1518             * timer is not set, schedule with default expiration (plus minus 
     1519             * some random value, to avoid sending SUBSCRIBEs all at once) 
     1520             */ 
     1521            if (resub_delay == -1) { 
     1522                pj_assert(PJSUA_PRES_TIMER >= 3); 
     1523                resub_delay = PJSUA_PRES_TIMER*1000 - 2500 + (pj_rand()%5000); 
     1524            } 
     1525 
     1526            buddy_resubscribe(buddy, PJ_TRUE, resub_delay); 
     1527                                   
    13091528        } else { 
     1529            buddy->term_code = 0; 
    13101530            buddy->term_reason.slen = 0; 
    13111531        } 
     
    13191539            buddy->sub = NULL; 
    13201540            buddy->status.info_cnt = 0; 
     1541            buddy->dlg = NULL; 
    13211542            pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); 
    13221543        } 
    13231544    } 
    1324  
    1325     PJSUA_UNLOCK(); 
    13261545} 
    13271546 
     
    13351554    pjsip_contact_hdr *contact_hdr; 
    13361555 
    1337     PJSUA_LOCK(); 
    1338  
     1556    /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has 
     1557     *   a dialog attached to it, lock_buddy() will use the dialog 
     1558     *   lock, which we are currently holding! 
     1559     */ 
    13391560    buddy = (pjsua_buddy*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
    13401561    if (!buddy) { 
    1341         PJSUA_UNLOCK(); 
    13421562        return; 
    13431563    } 
     
    13481568    if (buddy->contact.slen != 0) { 
    13491569        /* Contact already set */ 
    1350         PJSUA_UNLOCK(); 
    13511570        return; 
    13521571    } 
     
    13581577        pjsip_method_cmp(&tsx->method, pjsip_get_subscribe_method())!=0) 
    13591578    { 
    1360         PJSUA_UNLOCK(); 
    13611579        return; 
    13621580    } 
     
    13671585                                     PJSIP_H_CONTACT, NULL); 
    13681586    if (!contact_hdr) { 
    1369         PJSUA_UNLOCK(); 
    13701587        return; 
    13711588    } 
     
    13791596    if (buddy->contact.slen < 0) 
    13801597        buddy->contact.slen = 0; 
    1381  
    1382     PJSUA_UNLOCK(); 
    13831598} 
    13841599 
     
    13941609    pjsua_buddy *buddy; 
    13951610 
    1396     PJSUA_LOCK(); 
    1397  
     1611    /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has 
     1612     *   a dialog attached to it, lock_buddy() will use the dialog 
     1613     *   lock, which we are currently holding! 
     1614     */ 
    13981615    buddy = (pjsua_buddy*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
    13991616    if (buddy) { 
     
    14101627    PJ_UNUSED_ARG(res_hdr); 
    14111628    PJ_UNUSED_ARG(p_body); 
    1412  
    1413     PJSUA_UNLOCK(); 
    14141629} 
    14151630 
     
    14371652 
    14381653/* It does what it says.. */ 
    1439 static void subscribe_buddy_presence(unsigned index) 
     1654static void subscribe_buddy_presence(pjsua_buddy_id buddy_id) 
    14401655{ 
    14411656    pj_pool_t *tmp_pool = NULL; 
     
    14471662    pj_status_t status; 
    14481663 
    1449     buddy = &pjsua_var.buddy[index]; 
     1664    buddy = &pjsua_var.buddy[buddy_id]; 
    14501665    acc_id = pjsua_acc_find_for_outgoing(&buddy->uri); 
    14511666 
     
    14531668 
    14541669    PJ_LOG(4,(THIS_FILE, "Using account %d for buddy %d subscription", 
    1455                          acc_id, index)); 
     1670                         acc_id, buddy_id)); 
    14561671 
    14571672    /* Generate suitable Contact header unless one is already set in 
     
    14941709                                    PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub); 
    14951710    if (status != PJ_SUCCESS) { 
    1496         pjsua_var.buddy[index].sub = NULL; 
     1711        buddy->sub = NULL; 
    14971712        pjsua_perror(THIS_FILE, "Unable to create presence client",  
    14981713                     status); 
     
    15651780 
    15661781/* It does what it says... */ 
    1567 static void unsubscribe_buddy_presence(unsigned index) 
     1782static void unsubscribe_buddy_presence(pjsua_buddy_id buddy_id) 
    15681783{ 
    15691784    pjsua_buddy *buddy; 
     
    15711786    pj_status_t status; 
    15721787 
    1573     buddy = &pjsua_var.buddy[index]; 
     1788    buddy = &pjsua_var.buddy[buddy_id]; 
    15741789 
    15751790    if (buddy->sub == NULL) 
     
    15771792 
    15781793    if (pjsip_evsub_get_state(buddy->sub) == PJSIP_EVSUB_STATE_TERMINATED) { 
    1579         pjsua_var.buddy[index].sub = NULL; 
     1794        buddy->sub = NULL; 
    15801795        return; 
    15811796    } 
     
    15951810} 
    15961811 
    1597  
    1598 /* Lock all buddies */ 
    1599 #define LOCK_BUDDIES    unsigned cnt_ = 0; \ 
    1600                         pjsip_dialog *dlg_list_[PJSUA_MAX_BUDDIES]; \ 
    1601                         unsigned i_; \ 
    1602                         for (i_=0; i_<PJ_ARRAY_SIZE(pjsua_var.buddy);++i_) { \ 
    1603                             if (pjsua_var.buddy[i_].sub) { \ 
    1604                                 dlg_list_[cnt_++] = pjsua_var.buddy[i_].dlg; \ 
    1605                                 pjsip_dlg_inc_lock(pjsua_var.buddy[i_].dlg); \ 
    1606                             } \ 
    1607                         } \ 
    1608                         PJSUA_LOCK(); 
    1609  
    1610 /* Unlock all buddies */ 
    1611 #define UNLOCK_BUDDIES  PJSUA_UNLOCK(); \ 
    1612                         for (i_=0; i_<cnt_; ++i_) { \ 
    1613                             pjsip_dlg_dec_lock(dlg_list_[i_]); \ 
    1614                         } 
    1615                          
    1616  
    1617  
    16181812/* It does what it says.. */ 
    1619 static void refresh_client_subscriptions(void) 
     1813static pj_status_t refresh_client_subscriptions(void) 
    16201814{ 
    16211815    unsigned i; 
    1622  
    1623     LOCK_BUDDIES; 
     1816    pj_status_t status; 
    16241817 
    16251818    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) { 
    1626  
    1627         if (!pjsua_var.buddy[i].uri.slen) 
     1819        struct buddy_lock lck; 
     1820 
     1821        if (!pjsua_buddy_is_valid(i)) 
    16281822            continue; 
     1823 
     1824        status = lock_buddy("refresh_client_subscriptions()", i, &lck, 0); 
     1825        if (status != PJ_SUCCESS) 
     1826            return status; 
    16291827 
    16301828        if (pjsua_var.buddy[i].monitor && !pjsua_var.buddy[i].sub) { 
     
    16351833 
    16361834        } 
    1637     } 
    1638  
    1639     UNLOCK_BUDDIES; 
     1835 
     1836        unlock_buddy(&lck); 
     1837    } 
     1838 
     1839    return PJ_SUCCESS; 
    16401840} 
    16411841 
     
    16551855 
    16561856    entry->id = PJ_FALSE; 
    1657     refresh_client_subscriptions(); 
     1857 
     1858    /* #937: No need to do bulk client refresh, as buddies have their 
     1859     *       own individual timer now. 
     1860     */ 
     1861    //refresh_client_subscriptions(); 
    16581862 
    16591863    pjsip_endpt_schedule_timer(pjsua_var.endpt, entry, &delay); 
     
    17081912 
    17091913/* 
    1710  * Refresh presence subscriptions 
    1711  */ 
    1712 void pjsua_pres_refresh() 
    1713 { 
    1714     unsigned i; 
    1715  
    1716     refresh_client_subscriptions(); 
    1717  
    1718     for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { 
    1719         if (pjsua_var.acc[i].valid) 
    1720             pjsua_pres_update_acc(i, PJ_FALSE); 
    1721     } 
    1722 } 
    1723  
    1724  
    1725 /* 
    17261914 * Shutdown presence. 
    17271915 */ 
     
    17471935    } 
    17481936 
    1749     pjsua_pres_refresh(); 
    1750 } 
     1937    refresh_client_subscriptions(); 
     1938 
     1939    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { 
     1940        if (pjsua_var.acc[i].valid) 
     1941            pjsua_pres_update_acc(i, PJ_FALSE); 
     1942    } 
     1943} 
Note: See TracChangeset for help on using the changeset viewer.