Ignore:
Timestamp:
Oct 4, 2007 9:50:36 AM (16 years ago)
Author:
bennylp
Message:

Ticket #95: Keep-alive mechanism for TCP and TLS transports

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c

    r1405 r1473  
    4242#define POOL_TP_INC     4002 
    4343 
    44  
    4544struct tcp_listener; 
    4645struct tcp_transport; 
     
    113112    pj_bool_t                has_pending_connect; 
    114113 
     114    /* Keep-alive timer. */ 
     115    pj_timer_entry           ka_timer; 
     116    pj_time_val              last_activity; 
     117    pjsip_tx_data_op_key     ka_op_key; 
     118    pj_str_t                 ka_pkt; 
    115119 
    116120    /* TCP transport can only have  one rdata! 
     
    477481                                pj_status_t status); 
    478482 
     483/* TCP keep-alive timer callback */ 
     484static void tcp_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e); 
    479485 
    480486/* 
     
    492498    pj_ioqueue_t *ioqueue; 
    493499    pj_ioqueue_callback tcp_callback; 
     500    const pj_str_t ka_pkt = PJSIP_TCP_KEEP_ALIVE_DATA; 
    494501    pj_status_t status; 
    495502     
     
    569576 
    570577    tcp->is_registered = PJ_TRUE; 
     578 
     579    /* Initialize keep-alive timer */ 
     580    tcp->ka_timer.user_data = (void*)tcp; 
     581    tcp->ka_timer.cb = &tcp_keep_alive_timer; 
     582    pj_ioqueue_op_key_init(&tcp->ka_op_key.key, sizeof(pj_ioqueue_op_key_t)); 
     583    pj_strdup(tcp->base.pool, &tcp->ka_pkt, &ka_pkt); 
    571584 
    572585    /* Done setting up basic transport. */ 
     
    967980                    PJ_LOG(3,(tcp->base.obj_name, "New transport cancelled")); 
    968981                    tcp_destroy(&tcp->base, status); 
     982                } else { 
     983                    /* Start keep-alive timer */ 
     984                    if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) { 
     985                        pj_time_val delay = {PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0}; 
     986                        pjsip_endpt_schedule_timer(listener->endpt,  
     987                                                   &tcp->ka_timer,  
     988                                                   &delay); 
     989                        tcp->ka_timer.id = PJ_TRUE; 
     990                        pj_gettimeofday(&tcp->last_activity); 
     991                    } 
    969992                } 
    970993            } 
     
    10061029    pjsip_tx_data_op_key *tdata_op_key = (pjsip_tx_data_op_key*)op_key; 
    10071030 
     1031    /* Note that op_key may be the op_key from keep-alive, thus 
     1032     * it will not have tdata etc. 
     1033     */ 
     1034 
    10081035    tdata_op_key->tdata = NULL; 
    10091036 
     
    10261053         */ 
    10271054        tdata_op_key->callback(&tcp->base, tdata_op_key->token, bytes_sent); 
     1055 
     1056        /* Mark last activity time */ 
     1057        pj_gettimeofday(&tcp->last_activity); 
    10281058    } 
    10291059} 
     
    11281158/*  
    11291159 * This callback is called by transport manager to shutdown transport. 
    1130  * This normally is only used by UDP transport. 
    11311160 */ 
    11321161static pj_status_t tcp_shutdown(pjsip_transport *transport) 
    11331162{ 
    1134  
    1135     PJ_UNUSED_ARG(transport); 
    1136  
    1137     /* Nothing to do for TCP */ 
     1163    struct tcp_transport *tcp = (struct tcp_transport*)transport; 
     1164     
     1165    /* Stop keep-alive timer. */ 
     1166    if (tcp->ka_timer.id) { 
     1167        pjsip_endpt_cancel_timer(tcp->listener->endpt, &tcp->ka_timer); 
     1168        tcp->ka_timer.id = PJ_FALSE; 
     1169    } 
     1170 
    11381171    return PJ_SUCCESS; 
    11391172} 
     
    11751208        if (bytes_read > 0) { 
    11761209            pj_size_t size_eaten; 
     1210 
     1211            /* Mark this as an activity */ 
     1212            pj_gettimeofday(&tcp->last_activity); 
    11771213 
    11781214            /* Init pkt_info part. */ 
     
    13651401    /* Flush all pending send operations */ 
    13661402    tcp_flush_pending_tx(tcp); 
    1367 } 
     1403 
     1404    /* Start keep-alive timer */ 
     1405    if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) { 
     1406        pj_time_val delay = { PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0 }; 
     1407        pjsip_endpt_schedule_timer(tcp->listener->endpt, &tcp->ka_timer,  
     1408                                   &delay); 
     1409        tcp->ka_timer.id = PJ_TRUE; 
     1410        pj_gettimeofday(&tcp->last_activity); 
     1411    } 
     1412} 
     1413 
     1414/* Transport keep-alive timer callback */ 
     1415static void tcp_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e) 
     1416{ 
     1417    struct tcp_transport *tcp = (struct tcp_transport*) e->user_data; 
     1418    pj_time_val delay; 
     1419    pj_time_val now; 
     1420    pj_ssize_t size; 
     1421    pj_status_t status; 
     1422 
     1423    PJ_UNUSED_ARG(th); 
     1424 
     1425    tcp->ka_timer.id = PJ_TRUE; 
     1426 
     1427    pj_gettimeofday(&now); 
     1428    PJ_TIME_VAL_SUB(now, tcp->last_activity); 
     1429 
     1430    if (now.sec > 0 && now.sec < PJSIP_TCP_KEEP_ALIVE_INTERVAL) { 
     1431        /* There has been activity, so don't send keep-alive */ 
     1432        delay.sec = PJSIP_TCP_KEEP_ALIVE_INTERVAL - now.sec; 
     1433        delay.msec = 0; 
     1434 
     1435        pjsip_endpt_schedule_timer(tcp->listener->endpt, &tcp->ka_timer,  
     1436                                   &delay); 
     1437        tcp->ka_timer.id = PJ_TRUE; 
     1438        return; 
     1439    } 
     1440 
     1441    PJ_LOG(5,(tcp->base.obj_name, "Sending %d byte(s) keep-alive to %.*s:%d",  
     1442              (int)tcp->ka_pkt.slen, (int)tcp->base.remote_name.host.slen, 
     1443              tcp->base.remote_name.host.ptr, 
     1444              tcp->base.remote_name.port)); 
     1445 
     1446    /* Send the data */ 
     1447    size = tcp->ka_pkt.slen; 
     1448    status = pj_ioqueue_send(tcp->key, &tcp->ka_op_key.key, 
     1449                             tcp->ka_pkt.ptr, &size, 0); 
     1450 
     1451    if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
     1452        tcp_perror(tcp->base.obj_name,  
     1453                   "Error sending keep-alive packet", status); 
     1454        pjsip_transport_shutdown(&tcp->base); 
     1455        return; 
     1456    } 
     1457 
     1458    /* Register next keep-alive */ 
     1459    delay.sec = PJSIP_TCP_KEEP_ALIVE_INTERVAL; 
     1460    delay.msec = 0; 
     1461 
     1462    pjsip_endpt_schedule_timer(tcp->listener->endpt, &tcp->ka_timer,  
     1463                               &delay); 
     1464    tcp->ka_timer.id = PJ_TRUE; 
     1465} 
     1466 
    13681467 
    13691468#endif  /* PJ_HAS_TCP */ 
Note: See TracChangeset for help on using the changeset viewer.