Ignore:
Timestamp:
Apr 14, 2010 6:57:35 AM (13 years ago)
Author:
nanang
Message:

Ticket #1056:

  • Added functions to set/unset transport state notification callback on specific transport.
  • Updated transaction to immediately terminate the transactions when their transport gets disconnected.
  • Minor update: renamed function pjsip_tpmgr_set/get_status_cb() to pjsip_tpmgr_set/get_state_cb().
File:
1 edited

Legend:

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

    r3119 r3138  
    3434#include <pj/assert.h> 
    3535#include <pj/lock.h> 
     36#include <pj/list.h> 
    3637 
    3738 
     
    9192    pj_status_t    (*on_tx_msg)(pjsip_endpoint*, pjsip_tx_data*); 
    9293    pjsip_tp_state_callback tp_state_cb; 
    93     void *tp_state_user_data; 
    9494}; 
     95 
     96 
     97/* Transport state listener list type */ 
     98typedef struct tp_state_listener 
     99{ 
     100    PJ_DECL_LIST_MEMBER(struct tp_state_listener); 
     101 
     102    pjsip_tp_state_callback  cb; 
     103    void *user_data; 
     104} tp_state_listener; 
     105 
     106 
     107/* 
     108 * Transport data. 
     109 */ 
     110typedef struct transport_data 
     111{ 
     112    /* Transport listeners */ 
     113    tp_state_listener       st_listeners; 
     114    tp_state_listener       st_listeners_empty; 
     115} transport_data; 
    95116 
    96117 
     
    179200}; 
    180201 
     202static void tp_state_callback(pjsip_transport *tp, 
     203                              pjsip_transport_state state, 
     204                              const pjsip_transport_state_info *info); 
     205 
     206 
    181207struct transport_names_t *get_tpname(pjsip_transport_type_e type) 
    182208{ 
     
    10921118#endif 
    10931119 
     1120    /* Set transport state callback */ 
     1121    status = pjsip_tpmgr_set_state_cb(mgr, &tp_state_callback); 
     1122    if (status != PJ_SUCCESS) 
     1123        return status; 
     1124 
    10941125    PJ_LOG(5, (THIS_FILE, "Transport manager created.")); 
    10951126 
     
    17381769} 
    17391770 
    1740 PJ_DEF(pj_status_t) pjsip_tpmgr_set_status_cb(pjsip_tpmgr *mgr, 
    1741                                               pjsip_tp_state_callback cb) 
     1771/** 
     1772 * Set callback of global transport state notification. 
     1773 */ 
     1774PJ_DEF(pj_status_t) pjsip_tpmgr_set_state_cb(pjsip_tpmgr *mgr, 
     1775                                             pjsip_tp_state_callback cb) 
    17421776{ 
    17431777    PJ_ASSERT_RETURN(mgr, PJ_EINVAL); 
     
    17481782} 
    17491783 
    1750 PJ_DEF(pjsip_tp_state_callback) pjsip_tpmgr_get_status_cb( 
    1751                                               const pjsip_tpmgr *mgr) 
     1784/** 
     1785 * Get callback of global transport state notification. 
     1786 */ 
     1787PJ_DEF(pjsip_tp_state_callback) pjsip_tpmgr_get_state_cb( 
     1788                                             const pjsip_tpmgr *mgr) 
    17521789{ 
    17531790    PJ_ASSERT_RETURN(mgr, NULL); 
     
    17551792    return mgr->tp_state_cb; 
    17561793} 
     1794 
     1795 
     1796/** 
     1797 * Allocate and init transport data. 
     1798 */ 
     1799static void init_tp_data(pjsip_transport *tp) 
     1800{ 
     1801    transport_data *tp_data; 
     1802 
     1803    pj_assert(tp && !tp->data); 
     1804 
     1805    tp_data = PJ_POOL_ZALLOC_T(tp->pool, transport_data); 
     1806    pj_list_init(&tp_data->st_listeners); 
     1807    pj_list_init(&tp_data->st_listeners_empty); 
     1808    tp->data = tp_data; 
     1809} 
     1810 
     1811 
     1812static void tp_state_callback(pjsip_transport *tp, 
     1813                              pjsip_transport_state state, 
     1814                              const pjsip_transport_state_info *info) 
     1815{ 
     1816    transport_data *tp_data; 
     1817 
     1818    pj_lock_acquire(tp->lock); 
     1819 
     1820    tp_data = (transport_data*)tp->data; 
     1821 
     1822    /* Notify the transport state listeners, if any. */ 
     1823    if (!tp_data || pj_list_empty(&tp_data->st_listeners)) { 
     1824        goto on_return; 
     1825    } else { 
     1826        pjsip_transport_state_info st_info; 
     1827        tp_state_listener *st_listener = tp_data->st_listeners.next; 
     1828 
     1829        /* As we need to put the user data into the transport state info, 
     1830         * let's use a copy of transport state info. 
     1831         */ 
     1832        pj_memcpy(&st_info, info, sizeof(st_info)); 
     1833        while (st_listener != &tp_data->st_listeners) { 
     1834            st_info.user_data = st_listener->user_data; 
     1835            (*st_listener->cb)(tp, state, &st_info); 
     1836 
     1837            st_listener = st_listener->next; 
     1838        } 
     1839    } 
     1840 
     1841on_return: 
     1842    pj_lock_release(tp->lock); 
     1843} 
     1844 
     1845 
     1846/** 
     1847 * Add a listener to the specified transport for transport state notification. 
     1848 */ 
     1849PJ_DEF(pj_status_t) pjsip_transport_add_state_listener ( 
     1850                                            pjsip_transport *tp, 
     1851                                            pjsip_tp_state_callback cb, 
     1852                                            void *user_data, 
     1853                                            pjsip_tp_state_listener_key **key) 
     1854{ 
     1855    transport_data *tp_data; 
     1856    tp_state_listener *entry; 
     1857 
     1858    PJ_ASSERT_RETURN(tp && cb && key, PJ_EINVAL); 
     1859 
     1860    pj_lock_acquire(tp->lock); 
     1861 
     1862    /* Init transport data, if it hasn't */ 
     1863    if (!tp->data) 
     1864        init_tp_data(tp); 
     1865 
     1866    tp_data = (transport_data*)tp->data; 
     1867 
     1868    /* Init the new listener entry. Use available empty slot, if any, 
     1869     * otherwise allocate it using the transport pool. 
     1870     */ 
     1871    if (!pj_list_empty(&tp_data->st_listeners_empty)) { 
     1872        entry = tp_data->st_listeners_empty.next; 
     1873        pj_list_erase(entry); 
     1874    } else { 
     1875        entry = PJ_POOL_ZALLOC_T(tp->pool, tp_state_listener); 
     1876    } 
     1877    entry->cb = cb; 
     1878    entry->user_data = user_data; 
     1879 
     1880    /* Add the new listener entry to the listeners list */ 
     1881    pj_list_push_back(&tp_data->st_listeners, entry); 
     1882 
     1883    *key = entry; 
     1884 
     1885    pj_lock_release(tp->lock); 
     1886 
     1887    return PJ_SUCCESS; 
     1888} 
     1889 
     1890/** 
     1891 * Remove a listener from the specified transport for transport state  
     1892 * notification. 
     1893 */ 
     1894PJ_DEF(pj_status_t) pjsip_transport_remove_state_listener ( 
     1895                                    pjsip_transport *tp, 
     1896                                    pjsip_tp_state_listener_key *key, 
     1897                                    const void *user_data) 
     1898{ 
     1899    transport_data *tp_data; 
     1900    tp_state_listener *entry; 
     1901 
     1902    PJ_ASSERT_RETURN(tp && key, PJ_EINVAL); 
     1903 
     1904    pj_lock_acquire(tp->lock); 
     1905 
     1906    tp_data = (transport_data*)tp->data; 
     1907 
     1908    /* Transport data is NULL or no registered listener? */ 
     1909    if (!tp_data || pj_list_empty(&tp_data->st_listeners)) { 
     1910        pj_lock_release(tp->lock); 
     1911        return PJ_ENOTFOUND; 
     1912    } 
     1913 
     1914    entry = (tp_state_listener*)key; 
     1915 
     1916    /* Validate the user data */ 
     1917    if (entry->user_data != user_data) { 
     1918        pj_assert(!"Invalid transport state listener key"); 
     1919        pj_lock_release(tp->lock); 
     1920        return PJ_EBUG; 
     1921    } 
     1922 
     1923    /* Reset the entry and move it to the empty list */ 
     1924    entry->cb = NULL; 
     1925    entry->user_data = NULL; 
     1926    pj_list_erase(entry); 
     1927    pj_list_push_back(&tp_data->st_listeners_empty, entry); 
     1928 
     1929    pj_lock_release(tp->lock); 
     1930 
     1931    return PJ_SUCCESS; 
     1932} 
Note: See TracChangeset for help on using the changeset viewer.