Changeset 3196


Ignore:
Timestamp:
Jun 3, 2010 10:41:32 AM (9 years ago)
Author:
nanang
Message:

Re #1089:

  • Added a feature in dialog to store and retrieve remote capabilities dug from the remote messages.
  • Added few APIs in dialog to query and update remote capabilities, also added an API in pjsua_call to query whether a capability is supported by remote.
Location:
pjproject/trunk/pjsip
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/include/pjsip/sip_dialog.h

    r3068 r3196  
    9191 
    9292/** 
     93 * Dialog capability status. 
     94 */ 
     95typedef enum pjsip_dialog_cap_status 
     96{ 
     97    /** Capability is unsupported. */ 
     98    PJSIP_DIALOG_CAP_UNSUPPORTED    = 0, 
     99 
     100    /** Capability is supported */ 
     101    PJSIP_DIALOG_CAP_SUPPORTED      = 1, 
     102 
     103    /**  
     104     *  Unknown capability status. This is usually because we lack the  
     105     *  capability info which is retrieved from capability header specified 
     106     *  in the dialog messages. 
     107     */ 
     108    PJSIP_DIALOG_CAP_UNKNOWN        = 2 
     109} pjsip_dialog_cap_status; 
     110 
     111 
     112/** 
    93113 * This structure describes the dialog structure. Application MUST NOT 
    94114 * try to SET the values here directly, but instead it MUST use the 
     
    128148    pjsip_dlg_party     local;      /**< Local party info.                  */ 
    129149    pjsip_dlg_party     remote;     /**< Remote party info.                 */ 
     150    pjsip_hdr           rem_cap_hdr;/**< List of remote capability header.  */ 
    130151    pjsip_role_e        role;       /**< Initial role.                      */ 
    131152    pj_bool_t           uac_has_2xx;/**< UAC has received 2xx response?     */ 
     
    613634 
    614635/** 
     636 * Check if remote peer have the specified capability as published 
     637 * in the dialog messages from remote peer. 
     638 * 
     639 * Notes: 
     640 * - The capability \a token lookup will apply exact match, but not  
     641 *   case-sensitive, for example: <tt>"text/html"</tt> will not match  
     642 *   <tt>"text / html"</tt> (notice the spaces). 
     643 * 
     644 * @param dlg       The dialog. 
     645 * @param htype     The header type to be checked, which value may be: 
     646 *                  - PJSIP_H_ACCEPT 
     647 *                  - PJSIP_H_ALLOW 
     648 *                  - PJSIP_H_SUPPORTED 
     649 * @param hname     If htype specifies PJSIP_H_OTHER, then the header name 
     650 *                  must be supplied in this argument. Otherwise the value 
     651 *                  must be set to NULL. 
     652 * @param token     The capability token to check. For example, if \a htype 
     653 *                  is PJSIP_H_ALLOW, then \a token specifies the method 
     654 *                  names; if \a htype is PJSIP_H_SUPPORTED, then \a token 
     655 *                  specifies the extension names such as "100rel". 
     656 * 
     657 * @return          PJSIP_DIALOG_CAP_SUPPORTED if the specified capability 
     658 *                  is explicitly supported, see @pjsip_dialog_cap_status 
     659 *                  for more info. 
     660 */ 
     661PJ_DECL(pjsip_dialog_cap_status) pjsip_dlg_remote_has_cap( 
     662                                                    pjsip_dialog *dlg, 
     663                                                    int htype, 
     664                                                    const pj_str_t *hname, 
     665                                                    const pj_str_t *token); 
     666 
     667/** 
     668 * Get the specified capability header from the remote capability headers 
     669 * stored in the dialog. 
     670 * 
     671 * @param dlg       The dialog. 
     672 * @param htype     The header type to be retrieved, which value may be: 
     673 *                  - PJSIP_H_ACCEPT 
     674 *                  - PJSIP_H_ALLOW 
     675 *                  - PJSIP_H_SUPPORTED 
     676 * @param hname     If htype specifies PJSIP_H_OTHER, then the header name 
     677 *                  must be supplied in this argument. Otherwise the value 
     678 *                  must be set to NULL. 
     679 * 
     680 * @return          The appropriate header, or NULL if the header is not 
     681 *                  available. 
     682 */ 
     683PJ_DECL(const pjsip_hdr*) pjsip_dlg_get_remote_cap_hdr(pjsip_dialog *dlg, 
     684                                                       int htype, 
     685                                                       const pj_str_t *hname); 
     686 
     687/** 
     688 * Set remote capability from a SIP header containing array of capability  
     689 * tags/values. 
     690 * 
     691 * @param dlg       The dialog. 
     692 * @param cap_hdr   The SIP header. 
     693 * 
     694 * @return          PJ_SUCCESS when successful, otherwise the appropriate 
     695 *                  error code will be returned. 
     696 */ 
     697PJ_DECL(pj_status_t) pjsip_dlg_set_remote_cap_hdr( 
     698                                    pjsip_dialog *dlg, 
     699                                    const pjsip_generic_array_hdr *cap_hdr); 
     700 
     701/** 
     702 * Remove a remote capability header. 
     703 * 
     704 * @param dlg       The dialog. 
     705 * @param htype     The header type to be removed, which value may be: 
     706 *                  - PJSIP_H_ACCEPT 
     707 *                  - PJSIP_H_ALLOW 
     708 *                  - PJSIP_H_SUPPORTED 
     709 * @param hname     If htype specifies PJSIP_H_OTHER, then the header name 
     710 *                  must be supplied in this argument. Otherwise the value 
     711 *                  must be set to NULL. 
     712 * 
     713 * @return          PJ_SUCCESS when successful, otherwise the appropriate 
     714 *                  error code will be returned. 
     715 */ 
     716PJ_DECL(pj_status_t) pjsip_dlg_remove_remote_cap_hdr(pjsip_dialog *dlg, 
     717                                                     int htype, 
     718                                                     const pj_str_t *hname); 
     719 
     720/** 
     721 * Update remote capabilities from a received message. The header types 
     722 * to be updated from the message will only be \a PJSIP_H_ACCEPT,  
     723 * \a PJSIP_H_ALLOW, and \a PJSIP_H_SUPPORTED. 
     724 * 
     725 * @param dlg       The dialog. 
     726 * @param msg       The received message. 
     727 * @param strict    If this is set to PJ_TRUE, any header types missing 
     728 *                  from the message will cause removal of existing 
     729 *                  header types in the capability list. Otherwise, the  
     730 *                  capability list will not be modified when any header 
     731 *                  type is missing. 
     732 * 
     733 * @return          PJ_SUCCESS when successful, otherwise the appropriate 
     734 *                  error code will be returned. 
     735 */ 
     736PJ_DECL(pj_status_t) pjsip_dlg_update_remote_cap(pjsip_dialog *dlg, 
     737                                                 const pjsip_msg *msg, 
     738                                                 pj_bool_t strict); 
     739 
     740 
     741 
     742/** 
    615743 * @} 
    616744 */ 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r3172 r3196  
    28212821                                         pjsua_call_info *info); 
    28222822 
     2823/** 
     2824 * Check if remote peer support the specified capability. 
     2825 * 
     2826 * @param call_id       Call identification. 
     2827 * @param htype         The header type to be checked, which value may be: 
     2828 *                      - PJSIP_H_ACCEPT 
     2829 *                      - PJSIP_H_ALLOW 
     2830 *                      - PJSIP_H_SUPPORTED 
     2831 * @param hname         If htype specifies PJSIP_H_OTHER, then the header 
     2832 *                      name must be supplied in this argument. Otherwise the  
     2833 *                      value must be set to NULL. 
     2834 * @param token         The capability token to check. For example, if \a  
     2835 *                      htype is PJSIP_H_ALLOW, then \a token specifies the  
     2836 *                      method names; if \a htype is PJSIP_H_SUPPORTED, then 
     2837 *                      \a token specifies the extension names such as 
     2838 *                       "100rel". 
     2839 * 
     2840 * @return              PJSIP_DIALOG_CAP_SUPPORTED if the specified capability 
     2841 *                      is explicitly supported, see @pjsip_dialog_cap_status 
     2842 *                      for more info. 
     2843 */ 
     2844PJ_DECL(pjsip_dialog_cap_status) pjsua_call_remote_has_cap( 
     2845                                                    pjsua_call_id call_id, 
     2846                                                    int htype, 
     2847                                                    const pj_str_t *hname, 
     2848                                                    const pj_str_t *token); 
    28232849 
    28242850/** 
  • pjproject/trunk/pjsip/src/pjsip/sip_dialog.c

    r3190 r3196  
    4747static const pj_str_t HCONTACT = { "Contact", 7 }; 
    4848 
     49 
    4950PJ_DEF(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m) 
    5051{ 
     
    9091 
    9192    pj_list_init(&dlg->inv_hdr); 
     93    pj_list_init(&dlg->rem_cap_hdr); 
    9294 
    9395    status = pj_mutex_create_recursive(pool, dlg->obj_name, &dlg->mutex_); 
     
    523525    dlg->remote.tag_hval = pj_hash_calc(0, dlg->remote.info->tag.ptr,  
    524526                                        dlg->remote.info->tag.slen); 
     527 
     528    /* Update remote capabilities info */ 
     529    pjsip_dlg_update_remote_cap(dlg, rdata->msg_info.msg, PJ_TRUE); 
    525530 
    526531    /* Register this dialog to user agent. */ 
     
    17751780        pjsip_contact_hdr *contact; 
    17761781 
     1782        /* Update remote capability info, when To tags in the dialog remote  
     1783         * info and the incoming response are different, e.g: first response 
     1784         * with To-tag or forking, apply strict update. 
     1785         */ 
     1786        pjsip_dlg_update_remote_cap(dlg, rdata->msg_info.msg, 
     1787                                    pj_strcmp(&dlg->remote.info->tag, 
     1788                                              &rdata->msg_info.to->tag)); 
     1789 
    17771790        /* Update To tag. */ 
    17781791        pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag); 
    17791792        /* No need to update remote's tag_hval since its never used. */ 
    1780  
    17811793 
    17821794        /* RFC 3271 Section 12.1.2: 
     
    18601872        dlg_update_routeset(dlg, rdata); 
    18611873    } 
    1862  
    18631874 
    18641875    /* Pass to dialog usages. */ 
     
    19631974} 
    19641975 
     1976 
     1977/* 
     1978 * Check if the specified capability is supported by remote. 
     1979 */ 
     1980PJ_DEF(pjsip_dialog_cap_status) pjsip_dlg_remote_has_cap( 
     1981                                                    pjsip_dialog *dlg, 
     1982                                                    int htype, 
     1983                                                    const pj_str_t *hname, 
     1984                                                    const pj_str_t *token) 
     1985{ 
     1986    const pjsip_generic_array_hdr *hdr; 
     1987    pjsip_dialog_cap_status cap_status = PJSIP_DIALOG_CAP_UNSUPPORTED; 
     1988    unsigned i; 
     1989 
     1990    PJ_ASSERT_RETURN(dlg && token, PJ_FALSE); 
     1991 
     1992    pjsip_dlg_inc_lock(dlg); 
     1993 
     1994    hdr = (const pjsip_generic_array_hdr*)  
     1995           pjsip_dlg_get_remote_cap_hdr(dlg, htype, hname); 
     1996    if (!hdr) { 
     1997        cap_status = PJSIP_DIALOG_CAP_UNKNOWN; 
     1998    } else { 
     1999        for (i=0; i<hdr->count; ++i) { 
     2000            if (!pj_stricmp(&hdr->values[i], token)) { 
     2001                cap_status = PJSIP_DIALOG_CAP_SUPPORTED; 
     2002                break; 
     2003            } 
     2004        } 
     2005    } 
     2006 
     2007    pjsip_dlg_dec_lock(dlg); 
     2008 
     2009    return cap_status; 
     2010} 
     2011 
     2012 
     2013/* 
     2014 * Update remote capability of ACCEPT, ALLOW, and SUPPORTED from 
     2015 * the received message. 
     2016 */ 
     2017PJ_DEF(pj_status_t) pjsip_dlg_update_remote_cap(pjsip_dialog *dlg, 
     2018                                                const pjsip_msg *msg, 
     2019                                                pj_bool_t strict) 
     2020{ 
     2021    pjsip_hdr_e htypes[] =  
     2022        { PJSIP_H_ACCEPT, PJSIP_H_ALLOW, PJSIP_H_SUPPORTED }; 
     2023    unsigned i; 
     2024 
     2025    PJ_ASSERT_RETURN(dlg && msg, PJ_EINVAL); 
     2026 
     2027    pjsip_dlg_inc_lock(dlg); 
     2028 
     2029    /* Retrieve all specified capability header types */ 
     2030    for (i = 0; i < PJ_ARRAY_SIZE(htypes); ++i) { 
     2031        const pjsip_generic_array_hdr *hdr; 
     2032        pj_status_t status; 
     2033 
     2034        /* Find this capability type in the message */ 
     2035        hdr = (const pjsip_generic_array_hdr*) 
     2036              pjsip_msg_find_hdr(msg, htypes[i], NULL); 
     2037        if (!hdr) { 
     2038            /* Not found. 
     2039             * If strict update is specified, remote this capability type 
     2040             * from the capability list. 
     2041             */ 
     2042            if (strict) 
     2043                pjsip_dlg_remove_remote_cap_hdr(dlg, htypes[i], NULL); 
     2044        } else { 
     2045            /* Found, a capability type may be specified in multiple headers, 
     2046             * so combine all the capability tags/values into a temporary 
     2047             * header. 
     2048             */ 
     2049            pjsip_generic_array_hdr tmp_hdr; 
     2050 
     2051            /* Init temporary header */ 
     2052            pjsip_generic_array_hdr_init(dlg->pool, &tmp_hdr, NULL); 
     2053            pj_memcpy(&tmp_hdr, hdr, sizeof(pjsip_hdr)); 
     2054 
     2055            while (hdr) { 
     2056                unsigned j; 
     2057 
     2058                /* Append the header content to temporary header */ 
     2059                for(j=0; j<hdr->count && 
     2060                         tmp_hdr.count<PJSIP_GENERIC_ARRAY_MAX_COUNT; ++j) 
     2061                { 
     2062                    tmp_hdr.values[tmp_hdr.count++] = hdr->values[j]; 
     2063                } 
     2064 
     2065                /* Get the next header for this capability */ 
     2066                hdr = (const pjsip_generic_array_hdr*) 
     2067                      pjsip_msg_find_hdr(msg, htypes[i], hdr->next); 
     2068            } 
     2069 
     2070            /* Save this capability */ 
     2071            status = pjsip_dlg_set_remote_cap_hdr(dlg, &tmp_hdr); 
     2072            if (status != PJ_SUCCESS) { 
     2073                pjsip_dlg_dec_lock(dlg); 
     2074                return status; 
     2075            } 
     2076        } 
     2077    } 
     2078 
     2079    pjsip_dlg_dec_lock(dlg); 
     2080 
     2081    return PJ_SUCCESS; 
     2082} 
     2083 
     2084 
     2085/* 
     2086 * Get the value of the specified capability header field of remote. 
     2087 */ 
     2088PJ_DEF(const pjsip_hdr*) pjsip_dlg_get_remote_cap_hdr(pjsip_dialog *dlg, 
     2089                                                      int htype, 
     2090                                                      const pj_str_t *hname) 
     2091{ 
     2092    pjsip_hdr *hdr; 
     2093 
     2094    /* Check arguments. */ 
     2095    PJ_ASSERT_RETURN(dlg, NULL); 
     2096    PJ_ASSERT_RETURN((htype != PJSIP_H_OTHER) || (hname && hname->slen), 
     2097                     NULL); 
     2098 
     2099    pjsip_dlg_inc_lock(dlg); 
     2100 
     2101    hdr = dlg->rem_cap_hdr.next; 
     2102    while (hdr != &dlg->rem_cap_hdr) { 
     2103        if ((htype != PJSIP_H_OTHER && htype == hdr->type) || 
     2104            (htype == PJSIP_H_OTHER && pj_stricmp(&hdr->name, hname) == 0)) 
     2105        { 
     2106            pjsip_dlg_dec_lock(dlg); 
     2107            return hdr; 
     2108        } 
     2109        hdr = hdr->next; 
     2110    } 
     2111 
     2112    pjsip_dlg_dec_lock(dlg); 
     2113 
     2114    return NULL; 
     2115} 
     2116 
     2117 
     2118/* 
     2119 * Set remote capability header from a SIP header containing array 
     2120 * of capability tags/values. 
     2121 */ 
     2122PJ_DEF(pj_status_t) pjsip_dlg_set_remote_cap_hdr( 
     2123                                    pjsip_dialog *dlg, 
     2124                                    const pjsip_generic_array_hdr *cap_hdr) 
     2125{ 
     2126    pjsip_generic_array_hdr *hdr; 
     2127 
     2128    /* Check arguments. */ 
     2129    PJ_ASSERT_RETURN(dlg && cap_hdr, PJ_EINVAL); 
     2130 
     2131    pjsip_dlg_inc_lock(dlg); 
     2132 
     2133    /* Find the header. */ 
     2134    hdr = (pjsip_generic_array_hdr*) 
     2135          pjsip_dlg_get_remote_cap_hdr(dlg, cap_hdr->type, &cap_hdr->name); 
     2136 
     2137    /* Quick compare if the capability is up to date */ 
     2138    if (hdr && hdr->count == cap_hdr->count) { 
     2139        unsigned i; 
     2140        pj_bool_t uptodate = PJ_TRUE; 
     2141 
     2142        for (i=0; i<hdr->count; ++i) { 
     2143            if (pj_stricmp(&hdr->values[i], &cap_hdr->values[i])) 
     2144                uptodate = PJ_FALSE; 
     2145        } 
     2146 
     2147        /* Capability is up to date, just return PJ_SUCCESS */ 
     2148        if (uptodate) { 
     2149            pjsip_dlg_dec_lock(dlg); 
     2150            return PJ_SUCCESS; 
     2151        } 
     2152    } 
     2153 
     2154    /* Remove existing capability header if any */ 
     2155    if (hdr) 
     2156        pj_list_erase(hdr); 
     2157 
     2158    /* Add the new capability header */ 
     2159    hdr = (pjsip_generic_array_hdr*) pjsip_hdr_clone(dlg->pool, cap_hdr); 
     2160    hdr->type = cap_hdr->type; 
     2161    pj_strdup(dlg->pool, &hdr->name, &cap_hdr->name); 
     2162    pj_list_push_back(&dlg->rem_cap_hdr, hdr); 
     2163 
     2164    pjsip_dlg_dec_lock(dlg); 
     2165 
     2166    /* Done. */ 
     2167    return PJ_SUCCESS; 
     2168} 
     2169 
     2170/* 
     2171 * Remove a remote capability header. 
     2172 */ 
     2173PJ_DEF(pj_status_t) pjsip_dlg_remove_remote_cap_hdr(pjsip_dialog *dlg, 
     2174                                                    int htype, 
     2175                                                    const pj_str_t *hname) 
     2176{ 
     2177    pjsip_generic_array_hdr *hdr; 
     2178 
     2179    /* Check arguments. */ 
     2180    PJ_ASSERT_RETURN(dlg, PJ_EINVAL); 
     2181    PJ_ASSERT_RETURN((htype != PJSIP_H_OTHER) || (hname && hname->slen), 
     2182                     PJ_EINVAL); 
     2183 
     2184    pjsip_dlg_inc_lock(dlg); 
     2185 
     2186    hdr = (pjsip_generic_array_hdr*) 
     2187          pjsip_dlg_get_remote_cap_hdr(dlg, htype, hname); 
     2188    if (!hdr) { 
     2189        pjsip_dlg_dec_lock(dlg); 
     2190        return PJ_ENOTFOUND; 
     2191    } 
     2192 
     2193    pj_list_erase(hdr); 
     2194 
     2195    pjsip_dlg_dec_lock(dlg); 
     2196 
     2197    return PJ_SUCCESS; 
     2198} 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r3013 r3196  
    13211321 
    13221322    return PJ_SUCCESS; 
     1323} 
     1324 
     1325/* 
     1326 * Check if call remote peer support the specified capability. 
     1327 */ 
     1328PJ_DEF(pjsip_dialog_cap_status) pjsua_call_remote_has_cap( 
     1329                                                    pjsua_call_id call_id, 
     1330                                                    int htype, 
     1331                                                    const pj_str_t *hname, 
     1332                                                    const pj_str_t *token) 
     1333{ 
     1334    pjsua_call *call; 
     1335    pjsip_dialog *dlg; 
     1336    pj_status_t status; 
     1337    pjsip_dialog_cap_status cap_status; 
     1338 
     1339    status = acquire_call("pjsua_call_peer_has_cap()", call_id, &call, &dlg); 
     1340    if (status != PJ_SUCCESS) 
     1341        return PJSIP_DIALOG_CAP_UNKNOWN; 
     1342 
     1343    cap_status = pjsip_dlg_remote_has_cap(dlg, htype, hname, token); 
     1344 
     1345    pjsip_dlg_dec_lock(dlg); 
     1346 
     1347    return cap_status; 
    13231348} 
    13241349 
Note: See TracChangeset for help on using the changeset viewer.