Ignore:
Timestamp:
Apr 1, 2007 10:58:47 PM (17 years ago)
Author:
bennylp
Message:

Ticket #204: Implement SIP proxy functionalities (including some samples)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/pjproject-0.5-stable/pjsip/src/pjsip/sip_util_proxy.c

    r974 r1121  
    1818 */ 
    1919#include <pjsip/sip_util.h> 
     20#include <pjsip/sip_endpoint.h> 
    2021#include <pjsip/sip_errno.h> 
     22#include <pjsip/sip_msg.h> 
    2123#include <pj/assert.h> 
    22  
    23 PJ_DEF(pj_status_t) pjsip_endpt_create_request_fwd(  pjsip_endpoint *endpt, 
    24                                                      pjsip_rx_data *rdata,  
    25                                                      const pjsip_uri *uri, 
    26                                                      const pj_str_t *branch, 
    27                                                      unsigned options, 
    28                                                      pjsip_tx_data **tdata) 
    29 { 
    30     PJ_UNUSED_ARG(endpt); 
    31     PJ_UNUSED_ARG(rdata); 
    32     PJ_UNUSED_ARG(uri); 
    33     PJ_UNUSED_ARG(branch); 
     24#include <pj/ctype.h> 
     25#include <pj/except.h> 
     26#include <pj/pool.h> 
     27#include <pj/string.h> 
     28#include <pjlib-util/md5.h> 
     29 
     30 
     31/** 
     32 * Clone the incoming SIP request or response message. A forwarding proxy 
     33 * typically would need to clone the incoming SIP message before processing 
     34 * the message. 
     35 * 
     36 * Once a transmit data is created, the reference counter is initialized to 1. 
     37 * 
     38 * @param endpt     The endpoint instance. 
     39 * @param rdata     The incoming SIP message. 
     40 * @param p_tdata   Pointer to receive the transmit data containing 
     41 *                  the duplicated message. 
     42 * 
     43 * @return          PJ_SUCCESS on success. 
     44 */ 
     45PJ_DEF(pj_status_t) pjsip_endpt_clone_msg( pjsip_endpoint *endpt, 
     46                                           const pjsip_rx_data *rdata, 
     47                                           pjsip_tx_data **p_tdata) 
     48{ 
     49    pjsip_tx_data *tdata; 
     50    pj_status_t status; 
     51 
     52    status = pjsip_endpt_create_tdata(endpt, &tdata); 
     53    if (status != PJ_SUCCESS) 
     54        return status; 
     55 
     56    tdata->msg = pjsip_msg_clone(tdata->pool, rdata->msg_info.msg); 
     57 
     58    pjsip_tx_data_add_ref(tdata); 
     59     
     60    *p_tdata = tdata; 
     61 
     62    return PJ_SUCCESS; 
     63} 
     64 
     65 
     66/* 
     67 * Create new request message to be forwarded upstream to new destination URI  
     68 * in uri.  
     69 */ 
     70PJ_DEF(pj_status_t) pjsip_endpt_create_request_fwd(pjsip_endpoint *endpt, 
     71                                                   pjsip_rx_data *rdata,  
     72                                                   const pjsip_uri *uri, 
     73                                                   const pj_str_t *branch, 
     74                                                   unsigned options, 
     75                                                   pjsip_tx_data **p_tdata) 
     76{ 
     77    pjsip_tx_data *tdata; 
     78    pj_status_t status; 
     79    PJ_USE_EXCEPTION; 
     80 
     81 
     82    PJ_ASSERT_RETURN(endpt && rdata && p_tdata, PJ_EINVAL); 
     83    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,  
     84                     PJSIP_ENOTREQUESTMSG); 
     85 
    3486    PJ_UNUSED_ARG(options); 
    35     PJ_UNUSED_ARG(tdata); 
    36  
    37     pj_assert(!"Not implemented yet"); 
    38     return PJ_EBUG; 
     87 
     88 
     89    /* Request forwarding rule in RFC 3261 section 16.6: 
     90     * 
     91     * For each target, the proxy forwards the request following these 
     92     * steps: 
     93     *  
     94     * 1.  Make a copy of the received request 
     95     * 2.  Update the Request-URI 
     96     * 3.  Update the Max-Forwards header field 
     97     * 4.  Optionally add a Record-route header field value 
     98     * 5.  Optionally add additional header fields 
     99     * 6.  Postprocess routing information 
     100     * 7.  Determine the next-hop address, port, and transport 
     101     * 8.  Add a Via header field value 
     102     * 9.  Add a Content-Length header field if necessary 
     103     * 10. Forward the new request 
     104     * 
     105     * Of these steps, we only do step 1-3, since the later will be 
     106     * done by application. 
     107     */ 
     108 
     109    status = pjsip_endpt_create_tdata(endpt, &tdata); 
     110    if (status != PJ_SUCCESS) 
     111        return status; 
     112 
     113    /* Always increment ref counter to 1 */ 
     114    pjsip_tx_data_add_ref(tdata); 
     115 
     116    /* Duplicate the request */ 
     117    PJ_TRY { 
     118        pjsip_msg *dst; 
     119        const pjsip_msg *src = rdata->msg_info.msg; 
     120        const pjsip_hdr *hsrc; 
     121 
     122        /* Create the request */ 
     123        tdata->msg = dst = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG); 
     124 
     125        /* Duplicate request method */ 
     126        pjsip_method_copy(tdata->pool, &tdata->msg->line.req.method, 
     127                          &src->line.req.method); 
     128 
     129        /* Set request URI */ 
     130        if (uri) { 
     131            dst->line.req.uri = pjsip_uri_clone(tdata->pool, uri); 
     132        } else { 
     133            dst->line.req.uri = pjsip_uri_clone(tdata->pool, src->line.req.uri); 
     134        } 
     135 
     136        /* Clone ALL headers */ 
     137        hsrc = src->hdr.next; 
     138        while (hsrc != &src->hdr) { 
     139 
     140            pjsip_hdr *hdst; 
     141 
     142            /* If this is the top-most Via header, insert our own before 
     143             * cloning the header. 
     144             */ 
     145            if (hsrc == (pjsip_hdr*)rdata->msg_info.via) { 
     146                pjsip_via_hdr *hvia; 
     147                hvia = pjsip_via_hdr_create(tdata->pool); 
     148                if (branch) 
     149                    pj_strdup(tdata->pool, &hvia->branch_param, branch); 
     150                else { 
     151                    pj_str_t new_branch = pjsip_calculate_branch_id(rdata); 
     152                    pj_strdup(tdata->pool, &hvia->branch_param, &new_branch); 
     153                } 
     154                pjsip_msg_add_hdr(dst, (pjsip_hdr*)hvia); 
     155 
     156            } 
     157            /* Skip Content-Type and Content-Length as these would be  
     158             * generated when the the message is printed. 
     159             */ 
     160            else if (hsrc->type == PJSIP_H_CONTENT_LENGTH || 
     161                     hsrc->type == PJSIP_H_CONTENT_TYPE) { 
     162 
     163                hsrc = hsrc->next; 
     164                continue; 
     165 
     166            } 
     167#if 0 
     168            /* If this is the top-most Route header and it indicates loose 
     169             * route, remove the header. 
     170             */ 
     171            else if (hsrc == (pjsip_hdr*)rdata->msg_info.route) { 
     172 
     173                const pjsip_route_hdr *hroute = (const pjsip_route_hdr*) hsrc; 
     174                const pjsip_sip_uri *sip_uri; 
     175 
     176                if (!PJSIP_URI_SCHEME_IS_SIP(hroute->name_addr.uri) && 
     177                    !PJSIP_URI_SCHEME_IS_SIPS(hroute->name_addr.uri)) 
     178                { 
     179                    /* This is a bad request! */ 
     180                    status = PJSIP_EINVALIDHDR; 
     181                    goto on_error; 
     182                } 
     183 
     184                sip_uri = (pjsip_sip_uri*) hroute->name_addr.uri; 
     185 
     186                if (sip_uri->lr_param) { 
     187                    /* Yes lr param is present, skip this Route header */ 
     188                    hsrc = hsrc->next; 
     189                    continue; 
     190                } 
     191            } 
     192#endif 
     193 
     194            /* Clone the header */ 
     195            hdst = pjsip_hdr_clone(tdata->pool, hsrc); 
     196 
     197            /* If this is Max-Forward header, decrement the value */ 
     198            if (hdst->type == PJSIP_H_MAX_FORWARDS) { 
     199                pjsip_max_fwd_hdr *hmaxfwd = (pjsip_max_fwd_hdr*)hdst; 
     200                --hmaxfwd->ivalue; 
     201            } 
     202 
     203            /* Append header to new request */ 
     204            pjsip_msg_add_hdr(dst, hdst); 
     205 
     206 
     207            hsrc = hsrc->next; 
     208        } 
     209 
     210        /* 16.6.3: 
     211         * If the copy does not contain a Max-Forwards header field, the 
     212         * proxy MUST add one with a field value, which SHOULD be 70. 
     213         */ 
     214        if (rdata->msg_info.max_fwd == NULL) { 
     215            pjsip_max_fwd_hdr *hmaxfwd =  
     216                pjsip_max_fwd_hdr_create(tdata->pool, 70); 
     217            pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hmaxfwd); 
     218        } 
     219 
     220        /* Clone request body */ 
     221        if (src->body) { 
     222            dst->body = pjsip_msg_body_clone(tdata->pool, src->body); 
     223        } 
     224 
     225    } 
     226    PJ_CATCH_ANY { 
     227        status = PJ_ENOMEM; 
     228        goto on_error; 
     229    } 
     230    PJ_END 
     231 
     232 
     233    /* Done */ 
     234    *p_tdata = tdata; 
     235    return PJ_SUCCESS; 
     236 
     237on_error: 
     238    pjsip_tx_data_dec_ref(tdata); 
     239    return status; 
    39240} 
    40241 
     
    43244                                                     pjsip_rx_data *rdata,  
    44245                                                     unsigned options, 
    45                                                      pjsip_tx_data **tdata) 
    46 { 
    47     PJ_UNUSED_ARG(endpt); 
    48     PJ_UNUSED_ARG(rdata); 
     246                                                     pjsip_tx_data **p_tdata) 
     247{ 
     248    pjsip_tx_data *tdata; 
     249    pj_status_t status; 
     250    PJ_USE_EXCEPTION; 
     251 
    49252    PJ_UNUSED_ARG(options); 
    50     PJ_UNUSED_ARG(tdata); 
    51  
    52     pj_assert(!"Not implemented yet"); 
    53     return PJ_EBUG; 
     253 
     254    status = pjsip_endpt_create_tdata(endpt, &tdata); 
     255    if (status != PJ_SUCCESS) 
     256        return status; 
     257 
     258    pjsip_tx_data_add_ref(tdata); 
     259 
     260    PJ_TRY { 
     261        pjsip_msg *dst; 
     262        const pjsip_msg *src = rdata->msg_info.msg; 
     263        const pjsip_hdr *hsrc; 
     264 
     265        /* Create the request */ 
     266        tdata->msg = dst = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG); 
     267 
     268        /* Clone the status line */ 
     269        dst->line.status.code = src->line.status.code; 
     270        pj_strdup(tdata->pool, &dst->line.status.reason,  
     271                  &src->line.status.reason); 
     272 
     273        /* Duplicate all headers */ 
     274        hsrc = src->hdr.next; 
     275        while (hsrc != &src->hdr) { 
     276             
     277            /* Skip Content-Type and Content-Length as these would be  
     278             * generated when the the message is printed. 
     279             */ 
     280            if (hsrc->type == PJSIP_H_CONTENT_LENGTH || 
     281                hsrc->type == PJSIP_H_CONTENT_TYPE) { 
     282 
     283                hsrc = hsrc->next; 
     284                continue; 
     285 
     286            } 
     287            /* Remove the first Via header */ 
     288            else if (hsrc == (pjsip_hdr*) rdata->msg_info.via) { 
     289 
     290                hsrc = hsrc->next; 
     291                continue; 
     292            } 
     293 
     294            pjsip_msg_add_hdr(dst, pjsip_hdr_clone(tdata->pool, hsrc)); 
     295 
     296            hsrc = hsrc->next; 
     297        } 
     298 
     299        /* Clone message body */ 
     300        if (src->body) 
     301            dst->body = pjsip_msg_body_clone(tdata->pool, src->body); 
     302 
     303 
     304    } 
     305    PJ_CATCH_ANY { 
     306        status = PJ_ENOMEM; 
     307        goto on_error; 
     308    } 
     309    PJ_END; 
     310 
     311    *p_tdata = tdata; 
     312    return PJ_SUCCESS; 
     313 
     314on_error: 
     315    pjsip_tx_data_dec_ref(tdata); 
     316    return status; 
     317} 
     318 
     319 
     320static void digest2str(const unsigned char digest[], char *output) 
     321{ 
     322    int i; 
     323    for (i = 0; i<16; ++i) { 
     324        pj_val_to_hex_digit(digest[i], output); 
     325        output += 2; 
     326    } 
    54327} 
    55328 
     
    57330PJ_DEF(pj_str_t) pjsip_calculate_branch_id( pjsip_rx_data *rdata ) 
    58331{ 
    59     pj_str_t empty_str = { NULL, 0 }; 
    60  
    61     PJ_UNUSED_ARG(rdata); 
    62     pj_assert(!"Not implemented yet"); 
    63     return empty_str; 
    64 } 
    65  
    66  
     332    pj_md5_context ctx; 
     333    pj_uint8_t digest[16]; 
     334    pj_str_t branch; 
     335 
     336    /* Create branch ID for new request by calculating MD5 hash 
     337     * of the branch parameter in top-most Via header. 
     338     */ 
     339    pj_md5_init(&ctx); 
     340    pj_md5_update(&ctx, (pj_uint8_t*)rdata->msg_info.via->branch_param.ptr, 
     341                  rdata->msg_info.via->branch_param.slen); 
     342    pj_md5_final(&ctx, digest); 
     343 
     344    branch.ptr = pj_pool_alloc(rdata->tp_info.pool,  
     345                               32 + PJSIP_RFC3261_BRANCH_LEN); 
     346    pj_memcpy(branch.ptr, PJSIP_RFC3261_BRANCH_ID, PJSIP_RFC3261_BRANCH_LEN); 
     347 
     348    digest2str(digest, branch.ptr+PJSIP_RFC3261_BRANCH_LEN); 
     349 
     350    branch.slen = 32 + PJSIP_RFC3261_BRANCH_LEN; 
     351 
     352    return branch; 
     353} 
     354 
     355 
Note: See TracChangeset for help on using the changeset viewer.