Ignore:
Timestamp:
Sep 15, 2017 5:32:08 AM (7 years ago)
Author:
riza
Message:

Re #2041: Implement API to handle IP address change.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r5636 r5649  
    306306 
    307307    cfg->media_stun_use = PJSUA_STUN_RETRY_ON_FAILURE; 
     308    cfg->ip_change_cfg.shutdown_tp = PJ_TRUE; 
     309    cfg->ip_change_cfg.hangup_calls = PJ_FALSE; 
     310    cfg->ip_change_cfg.reinvite_flags = PJSUA_CALL_REINIT_MEDIA | 
     311                                        PJSUA_CALL_UPDATE_CONTACT | 
     312                                        PJSUA_CALL_UPDATE_VIA; 
    308313} 
    309314 
     
    23682373        pj_memcpy(&tcp_cfg.sockopt_params, &cfg->sockopt_params, 
    23692374                  sizeof(tcp_cfg.sockopt_params)); 
    2370          
     2375 
    23712376        /* Create the TCP transport */ 
    23722377        status = pjsip_tcp_transport_start3(pjsua_var.endpt, &tcp_cfg, &tcp); 
     
    24262431            a_name.host = cfg->public_addr; 
    24272432 
    2428         status = pjsip_tls_transport_start2(pjsua_var.endpt, 
    2429                                             &cfg->tls_setting, 
     2433        status = pjsip_tls_transport_start2(pjsua_var.endpt, &cfg->tls_setting, 
    24302434                                            &local_addr, &a_name, 1, &tls); 
    24312435        if (status != PJ_SUCCESS) { 
     
    27122716 
    27132717 
     2718PJ_DEF(pj_status_t) pjsua_transport_lis_start(pjsua_transport_id id, 
     2719                                             const pjsua_transport_config *cfg) 
     2720{ 
     2721    pj_status_t status = PJ_SUCCESS; 
     2722    pjsip_transport_type_e tp_type; 
     2723 
     2724    /* Make sure id is in range. */ 
     2725    PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),  
     2726                     PJ_EINVAL); 
     2727 
     2728    /* Make sure that transport exists */ 
     2729    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL); 
     2730 
     2731    tp_type = pjsua_var.tpdata[id].type & ~PJSIP_TRANSPORT_IPV6; 
     2732  
     2733    if ((tp_type == PJSIP_TRANSPORT_TLS) || (tp_type == PJSIP_TRANSPORT_TCP)) { 
     2734        pj_sockaddr bind_addr; 
     2735        pjsip_host_port addr_name; 
     2736        pjsip_tpfactory *factory = pjsua_var.tpdata[id].data.factory; 
     2737         
     2738        int af = pjsip_transport_type_get_af(factory->type); 
     2739 
     2740        if (cfg->port) 
     2741            pj_sockaddr_set_port(&bind_addr, (pj_uint16_t)cfg->port); 
     2742 
     2743        if (cfg->bound_addr.slen) { 
     2744            status = pj_sockaddr_set_str_addr(af,  
     2745                                              &bind_addr, 
     2746                                              &cfg->bound_addr); 
     2747            if (status != PJ_SUCCESS) { 
     2748                pjsua_perror(THIS_FILE,  
     2749                             "Unable to resolve transport bound address",  
     2750                             status); 
     2751                return status; 
     2752            } 
     2753        } 
     2754 
     2755        /* Set published name */ 
     2756        if (cfg->public_addr.slen) 
     2757            addr_name.host = cfg->public_addr; 
     2758 
     2759        if (tp_type == PJSIP_TRANSPORT_TCP) { 
     2760            status = pjsip_tcp_transport_lis_start(factory, &bind_addr, 
     2761                                                   &addr_name); 
     2762        } 
     2763#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0 
     2764        else { 
     2765            status = pjsip_tls_transport_lis_start(factory, &bind_addr, 
     2766                                                   &addr_name);  
     2767        } 
     2768#endif   
     2769    } else if (tp_type == PJSIP_TRANSPORT_UDP) { 
     2770        status = PJ_SUCCESS; 
     2771    } else { 
     2772        status = PJ_EINVAL; 
     2773    } 
     2774    return status; 
     2775} 
     2776 
     2777 
    27142778/* 
    27152779 * Add additional headers etc in msg_data specified by application 
     
    28632927        sel->u.listener = tpdata->data.factory; 
    28642928    } 
     2929} 
     2930 
     2931 
     2932PJ_DEF(void) pjsua_ip_change_param_default(pjsua_ip_change_param *param) 
     2933{ 
     2934    pj_bzero(param, sizeof(*param)); 
     2935    param->restart_listener = PJ_TRUE; 
     2936    param->restart_lis_delay = PJSUA_TRANSPORT_RESTART_DELAY_TIME; 
    28652937} 
    28662938 
     
    32723344} 
    32733345 
     3346 
     3347/* Forward declaration. */ 
     3348static void restart_listener_cb(void *user_data); 
     3349 
     3350 
     3351static pj_status_t handle_ip_change_on_acc() 
     3352{ 
     3353    int i = 0; 
     3354    pj_status_t status = PJ_SUCCESS; 
     3355    pj_bool_t acc_done[PJSUA_MAX_ACC]; 
     3356 
     3357    /* Reset ip_change_active flag. */ 
     3358    for (; i < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { 
     3359        pjsua_var.acc[i].ip_change_op = PJSUA_IP_CHANGE_OP_NULL; 
     3360        acc_done[i] = PJ_FALSE; 
     3361    }     
     3362     
     3363    for (i = 0; i < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { 
     3364        pj_bool_t shutdown_transport = PJ_FALSE; 
     3365        pjsip_regc_info regc_info; 
     3366        char acc_id[PJSUA_MAX_ACC * 4]; 
     3367        pjsua_acc *acc = &pjsua_var.acc[i]; 
     3368        pjsip_transport *transport = NULL; 
     3369        pjsua_acc_id shut_acc_ids[PJSUA_MAX_ACC]; 
     3370        unsigned shut_acc_cnt = 0; 
     3371 
     3372        if (!acc->valid || (acc_done[i])) 
     3373            continue; 
     3374 
     3375        if (acc->regc) {                     
     3376            pjsip_regc_get_info(acc->regc, &regc_info); 
     3377            if ((regc_info.transport) && 
     3378                ((regc_info.transport->flag & PJSIP_TRANSPORT_DATAGRAM) == 0)) 
     3379            { 
     3380                transport = regc_info.transport; 
     3381                shutdown_transport = acc->cfg.ip_change_cfg.shutdown_tp; 
     3382                shut_acc_ids[shut_acc_cnt++] = acc->index; 
     3383            }    
     3384        } else if (acc->reg_last_code != PJSIP_SC_BAD_GATEWAY && 
     3385                   acc->reg_last_code != PJSIP_SC_REQUEST_TIMEOUT && 
     3386                   acc->reg_last_code != PJSIP_SC_INTERNAL_SERVER_ERROR && 
     3387                   acc->reg_last_code != PJSIP_SC_BAD_GATEWAY && 
     3388                   acc->reg_last_code != PJSIP_SC_SERVICE_UNAVAILABLE && 
     3389                   acc->reg_last_code != PJSIP_SC_SERVER_TIMEOUT && 
     3390                   acc->reg_last_code != PJSIP_SC_TEMPORARILY_UNAVAILABLE)  
     3391        { 
     3392            continue; 
     3393        }  
     3394        pj_ansi_snprintf(acc_id, sizeof(acc_id), "#%d", i);      
     3395 
     3396        if (transport) { 
     3397            unsigned j = i + 1; 
     3398 
     3399            /* Find other account that uses the same transport. */ 
     3400            for (; j < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++j) { 
     3401                pjsip_regc_info tmp_regc_info; 
     3402                pjsua_acc *next_acc = &pjsua_var.acc[j]; 
     3403 
     3404                if (!next_acc->valid || !next_acc->regc || 
     3405                    (next_acc->ip_change_op > PJSUA_IP_CHANGE_OP_NULL))  
     3406                { 
     3407                    continue; 
     3408                } 
     3409 
     3410                pjsip_regc_get_info(next_acc->regc, &tmp_regc_info); 
     3411                if (transport == tmp_regc_info.transport) { 
     3412                    char tmp_buf[PJSUA_MAX_ACC * 4]; 
     3413 
     3414                    pj_ansi_strncpy(tmp_buf, acc_id, sizeof(acc_id)); 
     3415                    pj_ansi_snprintf(acc_id, sizeof(acc_id), "%s #%d",  
     3416                                     tmp_buf, j); 
     3417                    shut_acc_ids[shut_acc_cnt++] = j; 
     3418                    if (!shutdown_transport) { 
     3419                        shutdown_transport = 
     3420                                    next_acc->cfg.ip_change_cfg.shutdown_tp;                         
     3421                    } 
     3422                } 
     3423            } 
     3424        } 
     3425 
     3426        if (shutdown_transport) { 
     3427            unsigned j; 
     3428            /* Shutdown the transport. */            
     3429            PJ_LOG(3, (THIS_FILE, "Shutdown transport %s used by account %s " 
     3430                       "triggered by IP change", transport->obj_name, acc_id)); 
     3431 
     3432            for (j = 0; j < shut_acc_cnt; ++j) { 
     3433                pjsua_acc *tmp_acc = &pjsua_var.acc[shut_acc_ids[j]]; 
     3434                tmp_acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP; 
     3435                acc_done[shut_acc_ids[j]] = PJ_TRUE; 
     3436            } 
     3437 
     3438            status = pjsip_transport_shutdown2(transport, PJ_TRUE); 
     3439 
     3440            /* Report progress to each acc which uses the same transport. */ 
     3441            for (j = 0; j < shut_acc_cnt; ++j) { 
     3442                pjsua_acc *tmp_acc = &pjsua_var.acc[shut_acc_ids[j]]; 
     3443 
     3444                if (pjsua_var.ua_cfg.cb.on_ip_change_progress) { 
     3445                    pjsua_ip_change_op_info info; 
     3446 
     3447                    pj_bzero(&info, sizeof(info)); 
     3448                    info.acc_shutdown_tp.acc_id = tmp_acc->index; 
     3449 
     3450                    pjsua_var.ua_cfg.cb.on_ip_change_progress( 
     3451                                                         tmp_acc->ip_change_op, 
     3452                                                         status, 
     3453                                                         &info); 
     3454                } 
     3455 
     3456            } 
     3457        } else { 
     3458            acc_done[i] = PJ_TRUE; 
     3459            if (acc->cfg.allow_contact_rewrite) { 
     3460                status = pjsua_acc_update_contact_on_ip_change(acc); 
     3461            } else { 
     3462                status = pjsua_acc_handle_call_on_ip_change(acc); 
     3463            } 
     3464        } 
     3465    } 
     3466    return status; 
     3467} 
     3468 
     3469 
     3470static pj_status_t restart_listener(pjsua_transport_id id,  
     3471                                    unsigned restart_lis_delay) 
     3472{ 
     3473    pj_sockaddr bind_addr; 
     3474    pjsua_transport_info tp_info; 
     3475    pj_status_t status;     
     3476 
     3477    pjsua_transport_get_info(id, &tp_info);         
     3478    pj_sockaddr_init(pjsip_transport_type_get_af(tp_info.type), 
     3479                     &bind_addr, 
     3480                     NULL, 
     3481                     pj_sockaddr_get_port(&tp_info.local_addr)); 
     3482     
     3483    switch (tp_info.type) { 
     3484    case PJSIP_TRANSPORT_UDP: 
     3485    case PJSIP_TRANSPORT_UDP6: 
     3486        status = pjsip_udp_transport_restart2( 
     3487                                       pjsua_var.tpdata[id].data.tp, 
     3488                                       PJSIP_UDP_TRANSPORT_DESTROY_SOCKET, 
     3489                                       PJ_INVALID_SOCKET, 
     3490                                       &bind_addr, 
     3491                                       NULL); 
     3492        break; 
     3493 
     3494#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0 
     3495    case PJSIP_TRANSPORT_TLS: 
     3496    case PJSIP_TRANSPORT_TLS6: 
     3497        status = pjsip_tls_transport_restart( 
     3498                                        pjsua_var.tpdata[id].data.factory, 
     3499                                        &bind_addr, 
     3500                                        NULL); 
     3501        break; 
     3502#endif 
     3503    case PJSIP_TRANSPORT_TCP: 
     3504    case PJSIP_TRANSPORT_TCP6: 
     3505        status = pjsip_tcp_transport_restart( 
     3506                                        pjsua_var.tpdata[id].data.factory, 
     3507                                        &bind_addr, 
     3508                                        NULL); 
     3509        break; 
     3510 
     3511    default: 
     3512        status = PJ_EINVAL; 
     3513    } 
     3514    if (status != PJ_SUCCESS && (restart_lis_delay > 0)) { 
     3515        /* Try restarting again, with delay. */ 
     3516        pjsua_schedule_timer2(&restart_listener_cb,  
     3517                              (void*)(pj_size_t)id,  
     3518                              restart_lis_delay); 
     3519    } else { 
     3520        int i = 0; 
     3521        pj_bool_t all_done = PJ_TRUE; 
     3522 
     3523        pjsua_var.tpdata[id].is_restarting = PJ_FALSE;   
     3524        if (pjsua_var.ua_cfg.cb.on_ip_change_progress) { 
     3525            pjsua_ip_change_op_info info; 
     3526 
     3527            pj_bzero(&info, sizeof(info)); 
     3528            info.lis_restart.transport_id = id; 
     3529            pjsua_var.ua_cfg.cb.on_ip_change_progress( 
     3530                                                PJSUA_IP_CHANGE_OP_RESTART_LIS,  
     3531                                                status,  
     3532                                                &info); 
     3533        } 
     3534 
     3535        /* Move forward if all listener has been restarted. */ 
     3536        for (; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) { 
     3537            if (pjsua_var.tpdata[i].data.ptr != NULL &&  
     3538                pjsua_var.tpdata[i].is_restarting)  
     3539            { 
     3540                all_done = PJ_FALSE; 
     3541                break; 
     3542            } 
     3543        } 
     3544        if (all_done) 
     3545            status = handle_ip_change_on_acc(); 
     3546    } 
     3547    return status; 
     3548} 
     3549 
     3550 
     3551static void restart_listener_cb(void *user_data) 
     3552{ 
     3553    pjsua_transport_id transport_id = (pjsua_transport_id)(pj_size_t)user_data; 
     3554    restart_listener(transport_id, 0); 
     3555} 
     3556 
     3557 
     3558PJ_DEF(pj_status_t) pjsua_handle_ip_change(const pjsua_ip_change_param *param) 
     3559{ 
     3560    pj_status_t status = PJ_SUCCESS; 
     3561    int i = 0; 
     3562 
     3563    PJ_ASSERT_RETURN(param, PJ_EINVAL); 
     3564 
     3565    PJ_LOG(3, (THIS_FILE, "Start handling IP address change")); 
     3566     
     3567    if (param->restart_listener) { 
     3568        /* Restart listener/transport, handle_ip_change_on_acc() will 
     3569         * be called after listener restart is completed successfully. 
     3570         */ 
     3571        for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) { 
     3572            if (pjsua_var.tpdata[i].data.ptr != NULL) { 
     3573                pjsua_var.tpdata[i].is_restarting = PJ_TRUE; 
     3574            } 
     3575        } 
     3576        for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) { 
     3577            if (pjsua_var.tpdata[i].data.ptr != NULL) {          
     3578                status = restart_listener(i, param->restart_lis_delay); 
     3579            } 
     3580        } 
     3581    } else { 
     3582        status = handle_ip_change_on_acc(); 
     3583    } 
     3584 
     3585    return status; 
     3586} 
Note: See TracChangeset for help on using the changeset viewer.