Changeset 780


Ignore:
Timestamp:
Oct 18, 2006 5:16:34 PM (18 years ago)
Author:
bennylp
Message:

Some changes to REFER handling in PJSUA-LIB:

  • added callback to report call transfer progress
  • changed the call transfer request callback name in pjsua
  • added "--norefersub" option in pjsua.
  • fixed bug when call transfer is done more than once in the same dialog (dialog usage can not be added)

Also removed 7xx status from the SIP status codes.

And added pjsip_parse_status_line() to parse sipfrag.

Location:
pjproject/trunk
Files:
7 edited

Legend:

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

    r777 r780  
    3838    pjsua_logging_config    log_cfg; 
    3939    pjsua_media_config      media_cfg; 
     40    pj_bool_t               no_refersub; 
    4041    pj_bool_t               no_tcp; 
    4142    pj_bool_t               no_udp; 
     
    161162    puts  ("  --thread-cnt=N      Number of worker threads (default:1)"); 
    162163    puts  ("  --duration=SEC      Set maximum call duration (default:no limit)"); 
     164    puts  ("  --norefersub        Suppress event subscription when transfering calls"); 
    163165 
    164166    puts  (""); 
     
    288290           OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS,  
    289291           OPT_DURATION, OPT_NO_TCP, OPT_NO_UDP, OPT_THREAD_CNT, 
     292           OPT_NOREFERSUB, 
    290293    }; 
    291294    struct pj_getopt_option long_options[] = { 
     
    302305        { "no-tcp",     0, 0, OPT_NO_TCP}, 
    303306        { "no-udp",     0, 0, OPT_NO_UDP}, 
     307        { "norefersub", 0, 0, OPT_NOREFERSUB}, 
    304308        { "proxy",      1, 0, OPT_PROXY}, 
    305309        { "outbound",   1, 0, OPT_OUTBOUND_PROXY}, 
     
    457461            break; 
    458462 
     463        case OPT_NOREFERSUB: /* norefersub */ 
     464            cfg->no_refersub = PJ_TRUE; 
     465            break; 
     466 
    459467        case OPT_NO_TCP: /* no-tcp */ 
    460468            if (cfg->no_udp) { 
     
    948956    } 
    949957 
     958    /* No TCP ? */ 
     959    if (config->no_tcp) { 
     960        pj_strcat2(&cfg, "--no-tcp\n"); 
     961    } 
     962 
     963    /* No UDP ? */ 
     964    if (config->no_udp) { 
     965        pj_strcat2(&cfg, "--no-udp\n"); 
     966    } 
    950967 
    951968    /* STUN */ 
     
    10901107    } 
    10911108 
     1109    /* norefersub ? */ 
     1110    if (config->no_refersub) { 
     1111        pj_strcat2(&cfg, "--norefersub\n"); 
     1112    } 
     1113 
     1114 
    10921115    pj_strcat2(&cfg, "\n#\n# Buddies:\n#\n"); 
    10931116 
     
    14711494              (int)from->slen, from->ptr, 
    14721495              (is_typing?"is typing..":"has stopped typing"))); 
     1496} 
     1497 
     1498 
     1499/** 
     1500 * Call transfer request status. 
     1501 */ 
     1502static void on_call_transfer_status(pjsua_call_id call_id, 
     1503                                    int status_code, 
     1504                                    const pj_str_t *status_text, 
     1505                                    pj_bool_t final, 
     1506                                    pj_bool_t *p_cont) 
     1507{ 
     1508    PJ_LOG(3,(THIS_FILE, "Call %d: transfer status=%d (%.*s) %s", 
     1509              call_id, status_code, 
     1510              (int)status_text->slen, status_text->ptr, 
     1511              (final ? "[final]" : ""))); 
     1512 
     1513    if (status_code/100 == 2) { 
     1514        PJ_LOG(3,(THIS_FILE,  
     1515                  "Call %d: call transfered successfully, disconnecting call", 
     1516                  call_id)); 
     1517        pjsua_call_hangup(call_id, PJSIP_SC_GONE, NULL, NULL); 
     1518        *p_cont = PJ_FALSE; 
     1519    } 
    14731520} 
    14741521 
     
    21482195                } 
    21492196 
    2150                 /* Add Refer-Sub: false in outgoing REFER request */ 
    21512197                pjsua_msg_data_init(&msg_data); 
    2152                 pjsip_generic_string_hdr_init2(&refer_sub, &STR_REFER_SUB, 
    2153                                                &STR_FALSE); 
    2154                 pj_list_push_back(&msg_data.hdr_list, &refer_sub); 
    2155  
     2198                if (app_config.no_refersub) { 
     2199                    /* Add Refer-Sub: false in outgoing REFER request */ 
     2200                    pjsip_generic_string_hdr_init2(&refer_sub, &STR_REFER_SUB, 
     2201                                                   &STR_FALSE); 
     2202                    pj_list_push_back(&msg_data.hdr_list, &refer_sub); 
     2203                } 
    21562204                if (result.nb_result != NO_NB) { 
    21572205                    if (result.nb_result == -1 || result.nb_result == 0) 
     
    21682216                    pjsua_call_xfer( current_call, &tmp, &msg_data); 
    21692217                } 
    2170  
    2171                 /* Hangup call regardless of xfer status */ 
    2172                 pjsua_call_hangup(current_call, PJSIP_SC_GONE, NULL, NULL); 
    21732218            } 
    21742219            break; 
     
    24622507    app_config.cfg.cb.on_pager = &on_pager; 
    24632508    app_config.cfg.cb.on_typing = &on_typing; 
     2509    app_config.cfg.cb.on_call_transfer_status = &on_call_transfer_status; 
    24642510 
    24652511    /* Initialize pjsua */ 
  • pjproject/trunk/pjsip/include/pjsip/sip_msg.h

    r736 r780  
    432432    PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE = 606, 
    433433 
    434     PJSIP_SC_TSX_TIMEOUT = 701, 
     434    PJSIP_SC_TSX_TIMEOUT = PJSIP_SC_REQUEST_TIMEOUT, 
    435435    /*PJSIP_SC_TSX_RESOLVE_ERROR = 702,*/ 
    436     PJSIP_SC_TSX_TRANSPORT_ERROR = 703 
     436    PJSIP_SC_TSX_TRANSPORT_ERROR = PJSIP_SC_SERVICE_UNAVAILABLE 
    437437 
    438438} pjsip_status_code; 
  • pjproject/trunk/pjsip/include/pjsip/sip_parser.h

    r622 r780  
    2525 */ 
    2626 
    27 #include <pjsip/sip_types.h> 
     27#include <pjsip/sip_msg.h> 
    2828#include <pjlib-util/scanner.h> 
    2929#include <pj/list.h> 
     
    190190                                     char *buf, pj_size_t size, 
    191191                                     unsigned options); 
     192 
     193/** 
     194 * Parse SIP status line. 
     195 * 
     196 * @param buf           Text buffer to parse. 
     197 * @param size          The size of the buffer. 
     198 * @param status_line   Structure to receive the parsed elements. 
     199 * 
     200 * @return              PJ_SUCCESS if a status line is parsed successfully. 
     201 */ 
     202PJ_DECL(pj_status_t) pjsip_parse_status_line(char *buf, pj_size_t size, 
     203                                             pjsip_status_line *status_line); 
     204 
    192205 
    193206/** 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r753 r780  
    310310     * transfer. 
    311311     */ 
    312     void (*on_call_transfered)(pjsua_call_id call_id, 
    313                                const pj_str_t *dst, 
    314                                pjsip_status_code *code); 
     312    void (*on_call_transfer_request)(pjsua_call_id call_id, 
     313                                     const pj_str_t *dst, 
     314                                     pjsip_status_code *code); 
     315 
     316    /** 
     317     * Notify application of the status of previously sent call 
     318     * transfer request. Application can monitor the status of the 
     319     * call transfer request, for example to decide whether to  
     320     * terminate existing call. 
     321     * 
     322     * @param call_id       Call ID. 
     323     * @param status_code   Status progress of the transfer request. 
     324     * @param status_text   Status progress text. 
     325     * @param final         If non-zero, no further notification will 
     326     *                      be reported. The status_code specified in 
     327     *                      this callback is the final status. 
     328     * @param p_cont        Initially will be set to non-zero, application 
     329     *                      can set this to FALSE if it no longer wants 
     330     *                      to receie further notification (for example, 
     331     *                      after it hangs up the call). 
     332     */ 
     333    void (*on_call_transfer_status)(pjsua_call_id call_id, 
     334                                    int status_code, 
     335                                    const pj_str_t *status_text, 
     336                                    pj_bool_t final, 
     337                                    pj_bool_t *p_cont); 
    315338 
    316339    /** 
  • pjproject/trunk/pjsip/src/pjsip/sip_dialog.c

    r729 r780  
    794794    for (index=0; index<dlg->usage_cnt; ++index) { 
    795795        if (dlg->usage[index] == mod) { 
    796             pj_assert(!"This module is already registered"); 
     796            /* Module may be registered more than once in the same dialog. 
     797             * For example, when call transfer fails, application may retry 
     798             * call transfer on the same dialog. 
     799             * So return PJ_SUCCESS here. 
     800             */ 
     801            PJ_LOG(4,(dlg->obj_name,  
     802                      "Module %.*s already registered as dialog usage, " 
     803                      "updating the data %p", 
     804                      (int)mod->name.slen, mod->name.ptr, mod_data)); 
     805            dlg->mod_data[mod->id] = mod_data; 
     806 
    797807            pjsip_dlg_dec_lock(dlg); 
    798             return PJSIP_ETYPEEXISTS; 
     808            return PJ_SUCCESS; 
     809 
     810            //pj_assert(!"This module is already registered"); 
     811            //pjsip_dlg_dec_lock(dlg); 
     812            //return PJSIP_ETYPEEXISTS; 
    799813        } 
    800814 
  • pjproject/trunk/pjsip/src/pjsip/sip_parser.c

    r735 r780  
    14721472} 
    14731473 
     1474 
     1475/* 
     1476 * Public API to parse SIP status line. 
     1477 */ 
     1478PJ_DEF(pj_status_t) pjsip_parse_status_line( char *buf, pj_size_t size, 
     1479                                             pjsip_status_line *status_line) 
     1480{ 
     1481    pj_scanner scanner; 
     1482    PJ_USE_EXCEPTION; 
     1483 
     1484    pj_bzero(status_line, sizeof(*status_line)); 
     1485    pj_scan_init(&scanner, buf, size, 0, &on_syntax_error); 
     1486 
     1487    PJ_TRY { 
     1488        int_parse_status_line(&scanner, status_line); 
     1489    }  
     1490    PJ_CATCH_ANY { 
     1491        /* Tolerate the error if it is caused only by missing newline */ 
     1492        if (status_line->code == 0 && status_line->reason.slen == 0) { 
     1493            pj_scan_fini(&scanner); 
     1494            return PJSIP_EINVALIDMSG; 
     1495        } 
     1496    } 
     1497    PJ_END; 
     1498 
     1499    pj_scan_fini(&scanner); 
     1500    return PJ_SUCCESS; 
     1501} 
     1502 
     1503 
    14741504/* Parse ending of header. */ 
    14751505static void parse_hdr_end( pj_scanner *scanner ) 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r738 r780  
    7272 * has changed. 
    7373 */ 
    74 static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event); 
     74static void xfer_client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event); 
     75static void xfer_server_on_evsub_state( pjsip_evsub *sub, pjsip_event *event); 
     76 
     77/* 
     78 * Callback called by event framework when NOTIFY is received for outgoing 
     79 * REFER subscription. 
     80 */ 
     81static void xfer_on_rx_notify(pjsip_evsub *sub,  
     82                              pjsip_rx_data *rdata, 
     83                              int *p_st_code, 
     84                              pj_str_t **p_st_text, 
     85                              pjsip_hdr *res_hdr, 
     86                              pjsip_msg_body **p_body); 
    7587 
    7688/* 
     
    10791091    /* Create xfer client subscription. */ 
    10801092    pj_bzero(&xfer_cb, sizeof(xfer_cb)); 
    1081     xfer_cb.on_evsub_state = &xfer_on_evsub_state; 
     1093    xfer_cb.on_evsub_state = &xfer_client_on_evsub_state; 
    10821094 
    10831095    status = pjsip_xfer_create_uac(call->inv->dlg, &xfer_cb, &sub); 
     
    10871099        return status; 
    10881100    } 
     1101 
     1102    /* Associate this call with the client subscription */ 
     1103    pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, call); 
    10891104 
    10901105    /* 
     
    21452160 * has changed. 
    21462161 */ 
    2147 static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event) 
     2162static void xfer_client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event) 
     2163{ 
     2164     
     2165    PJ_UNUSED_ARG(event); 
     2166 
     2167    /* 
     2168     * When subscription is accepted (got 200/OK to REFER), check if  
     2169     * subscription suppressed. 
     2170     */ 
     2171    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) { 
     2172 
     2173        pjsip_rx_data *rdata; 
     2174        pjsip_generic_string_hdr *refer_sub; 
     2175        const pj_str_t REFER_SUB = { "Refer-Sub", 9 }; 
     2176        pjsua_call *call; 
     2177 
     2178        call = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
     2179 
     2180        /* Must be receipt of response message */ 
     2181        pj_assert(event->type == PJSIP_EVENT_TSX_STATE &&  
     2182                  event->body.tsx_state.type == PJSIP_EVENT_RX_MSG); 
     2183        rdata = event->body.tsx_state.src.rdata; 
     2184 
     2185        /* Find Refer-Sub header */ 
     2186        refer_sub = (pjsip_generic_string_hdr*) 
     2187                    pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,  
     2188                                               &REFER_SUB, NULL); 
     2189 
     2190        /* Check if subscription is suppressed */ 
     2191        if (refer_sub && pj_stricmp2(&refer_sub->hvalue, "false")==0) { 
     2192            /* Since no subscription is desired, assume that call has been 
     2193             * transfered successfully. 
     2194             */ 
     2195            if (call && pjsua_var.ua_cfg.cb.on_call_transfer_status) { 
     2196                const pj_str_t ACCEPTED = { "Accepted", 8 }; 
     2197                pj_bool_t cont = PJ_FALSE; 
     2198                (*pjsua_var.ua_cfg.cb.on_call_transfer_status)(call->index,  
     2199                                                               200, 
     2200                                                               &ACCEPTED, 
     2201                                                               PJ_TRUE, 
     2202                                                               &cont); 
     2203            } 
     2204 
     2205            /* Yes, subscription is suppressed. 
     2206             * Terminate our subscription now. 
     2207             */ 
     2208            PJ_LOG(4,(THIS_FILE, "Xfer subscription suppressed, terminating " 
     2209                                 "event subcription...")); 
     2210            pjsip_evsub_terminate(sub, PJ_TRUE); 
     2211 
     2212        } else { 
     2213            /* Notify application about call transfer progress.  
     2214             * Initially notify with 100/Accepted status. 
     2215             */ 
     2216            if (call && pjsua_var.ua_cfg.cb.on_call_transfer_status) { 
     2217                const pj_str_t ACCEPTED = { "Accepted", 8 }; 
     2218                pj_bool_t cont = PJ_FALSE; 
     2219                (*pjsua_var.ua_cfg.cb.on_call_transfer_status)(call->index,  
     2220                                                               100, 
     2221                                                               &ACCEPTED, 
     2222                                                               PJ_FALSE, 
     2223                                                               &cont); 
     2224            } 
     2225        } 
     2226    } 
     2227    /* 
     2228     * On incoming NOTIFY, notify application about call transfer progress. 
     2229     */ 
     2230    else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE || 
     2231             pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)  
     2232    { 
     2233        pjsua_call *call; 
     2234        pjsip_msg *msg; 
     2235        pjsip_msg_body *body; 
     2236        pjsip_status_line status_line; 
     2237        pj_bool_t is_last; 
     2238        pj_bool_t cont; 
     2239        pj_status_t status; 
     2240 
     2241        call = pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); 
     2242 
     2243        /* When subscription is terminated, clear the xfer_sub member of  
     2244         * the inv_data. 
     2245         */ 
     2246        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { 
     2247            pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); 
     2248            PJ_LOG(4,(THIS_FILE, "Xfer client subscription terminated")); 
     2249 
     2250        } 
     2251 
     2252        if (!call || !event || !pjsua_var.ua_cfg.cb.on_call_transfer_status) { 
     2253            /* Application is not interested with call progress status */ 
     2254            return; 
     2255        } 
     2256 
     2257        /* This better be a NOTIFY request */ 
     2258        if (event->type == PJSIP_EVENT_TSX_STATE && 
     2259            event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) 
     2260        { 
     2261            pjsip_rx_data *rdata; 
     2262 
     2263            rdata = event->body.tsx_state.src.rdata; 
     2264 
     2265            /* Check if there's body */ 
     2266            msg = rdata->msg_info.msg; 
     2267            body = msg->body; 
     2268            if (!body) { 
     2269                PJ_LOG(4,(THIS_FILE,  
     2270                          "Warning: received NOTIFY without message body")); 
     2271                return; 
     2272            } 
     2273 
     2274            /* Check for appropriate content */ 
     2275            if (pj_stricmp2(&body->content_type.type, "message") != 0 || 
     2276                pj_stricmp2(&body->content_type.subtype, "sipfrag") != 0) 
     2277            { 
     2278                PJ_LOG(4,(THIS_FILE,  
     2279                          "Warning: received NOTIFY with non message/sipfrag " 
     2280                          "content")); 
     2281                return; 
     2282            } 
     2283 
     2284            /* Try to parse the content */ 
     2285            status = pjsip_parse_status_line(body->data, body->len,  
     2286                                             &status_line); 
     2287            if (status != PJ_SUCCESS) { 
     2288                PJ_LOG(4,(THIS_FILE,  
     2289                          "Warning: received NOTIFY with invalid " 
     2290                          "message/sipfrag content")); 
     2291                return; 
     2292            } 
     2293 
     2294        } else { 
     2295            status_line.code = 500; 
     2296            status_line.reason = *pjsip_get_status_text(500); 
     2297        } 
     2298 
     2299        /* Notify application */ 
     2300        is_last = (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED); 
     2301        cont = !is_last; 
     2302        (*pjsua_var.ua_cfg.cb.on_call_transfer_status)(call->index,  
     2303                                                       status_line.code, 
     2304                                                       &status_line.reason, 
     2305                                                       is_last, &cont); 
     2306 
     2307        if (!cont) { 
     2308            pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); 
     2309        } 
     2310    } 
     2311} 
     2312 
     2313 
     2314/* 
     2315 * Callback called by event framework when the xfer subscription state 
     2316 * has changed. 
     2317 */ 
     2318static void xfer_server_on_evsub_state( pjsip_evsub *sub, pjsip_event *event) 
    21482319{ 
    21492320     
     
    21642335        call->xfer_sub = NULL; 
    21652336 
    2166         PJ_LOG(4,(THIS_FILE, "Xfer subscription terminated")); 
    2167  
    2168     } 
    2169     /* 
    2170      * When subscription is accepted (got 200/OK to REFER), check if  
    2171      * subscription suppressed. 
    2172      */ 
    2173     else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) { 
    2174  
    2175         pjsip_rx_data *rdata; 
    2176         pjsip_generic_string_hdr *refer_sub; 
    2177         const pj_str_t REFER_SUB = { "Refer-Sub", 9 }; 
    2178  
    2179         /* Must be receipt of response message */ 
    2180         pj_assert(event->type == PJSIP_EVENT_TSX_STATE &&  
    2181                   event->body.tsx_state.type == PJSIP_EVENT_RX_MSG); 
    2182         rdata = event->body.tsx_state.src.rdata; 
    2183  
    2184         /* Find Refer-Sub header */ 
    2185         refer_sub = (pjsip_generic_string_hdr*) 
    2186                     pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,  
    2187                                                &REFER_SUB, NULL); 
    2188  
    2189         /* Check if subscription is suppressed */ 
    2190         if (refer_sub && pj_stricmp2(&refer_sub->hvalue, "false")==0) { 
    2191             /* Yes, subscription is suppressed. 
    2192              * Terminate our subscription now. 
    2193              */ 
    2194             PJ_LOG(4,(THIS_FILE, "Xfer subscription suppressed, terminating " 
    2195                                  "event subcription...")); 
    2196             pjsip_evsub_terminate(sub, PJ_TRUE); 
    2197         } 
     2337        PJ_LOG(4,(THIS_FILE, "Xfer server subscription terminated")); 
    21982338    } 
    21992339} 
     
    22472387    /* Notify callback */ 
    22482388    code = PJSIP_SC_OK; 
    2249     if (pjsua_var.ua_cfg.cb.on_call_transfered) 
    2250         (*pjsua_var.ua_cfg.cb.on_call_transfered)(existing_call->index, 
    2251                                                   &refer_to->hvalue, &code); 
     2389    if (pjsua_var.ua_cfg.cb.on_call_transfer_request) 
     2390        (*pjsua_var.ua_cfg.cb.on_call_transfer_request)(existing_call->index, 
     2391                                                        &refer_to->hvalue,  
     2392                                                        &code); 
    22522393 
    22532394    if (code < 200) 
     
    23052446        /* Init callback */ 
    23062447        pj_bzero(&xfer_cb, sizeof(xfer_cb)); 
    2307         xfer_cb.on_evsub_state = &xfer_on_evsub_state; 
     2448        xfer_cb.on_evsub_state = &xfer_server_on_evsub_state; 
    23082449 
    23092450        /* Init additional header list to be sent with REFER response */ 
Note: See TracChangeset for help on using the changeset viewer.