Changeset 1123


Ignore:
Timestamp:
Apr 2, 2007 11:23:09 AM (13 years ago)
Author:
bennylp
Message:

More work on stateful proxy sample

Location:
pjproject/branches/pjproject-0.5-stable/pjsip-apps/src/samples
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/pjproject-0.5-stable/pjsip-apps/src/samples/proxy.h

    r1121 r1123  
    5454    puts("Options:\n" 
    5555         "\n" 
    56          " -p, --port N    Set local listener port to N\n" 
    57          " -R, --rr        Perform record routing\n" 
    58          " -h, --help      Show this help screen\n" 
     56         " --port N       Set local listener port to N\n" 
     57         " --rr           Perform record routing\n" 
     58         " --log-level N  Set log level to N (default: 4)\n" 
     59         " --help         Show this help screen\n" 
    5960         ); 
    6061} 
     
    6465{ 
    6566    struct pj_getopt_option long_opt[] = { 
    66         { "port",1, 0, 'p'}, 
    67         { "rr",  1, 0, 'R'}, 
    68         { "help",1, 0, 'h'}, 
     67        { "port",       1, 0, 'p'}, 
     68        { "rr",         0, 0, 'R'}, 
     69        { "log-level",  1, 0, 'L'}, 
     70        { "help",       0, 0, 'h'}, 
    6971    }; 
    7072    int c; 
     
    7274 
    7375    pj_optind = 0; 
    74     while((c=pj_getopt_long(argc, argv, "pRh", long_opt, &opt_ind))!=-1) { 
     76    while((c=pj_getopt_long(argc, argv, "", long_opt, &opt_ind))!=-1) { 
    7577        switch (c) { 
    7678        case 'p': 
     
    8486            break; 
    8587 
     88        case 'L': 
     89            pj_log_set_level(atoi(pj_optarg)); 
     90            break; 
     91 
    8692        case 'h': 
    8793            usage(); 
     
    8995 
    9096        default: 
    91             puts("Unknown option ignored"); 
    92             break; 
     97            puts("Unknown option. Run with --help for help."); 
     98            return -1; 
    9399        } 
    94100    } 
     
    96102    return PJ_SUCCESS; 
    97103} 
     104 
     105 
     106/***************************************************************************** 
     107 * This is a very simple PJSIP module, whose sole purpose is to display 
     108 * incoming and outgoing messages to log. This module will have priority 
     109 * higher than transport layer, which means: 
     110 * 
     111 *  - incoming messages will come to this module first before reaching 
     112 *    transaction layer. 
     113 * 
     114 *  - outgoing messages will come to this module last, after the message 
     115 *    has been 'printed' to contiguous buffer by transport layer and 
     116 *    appropriate transport instance has been decided for this message. 
     117 * 
     118 */ 
     119 
     120/* Notification on incoming messages */ 
     121static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) 
     122{ 
     123    PJ_LOG(5,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n" 
     124                         "%.*s\n" 
     125                         "--end msg--", 
     126                         rdata->msg_info.len, 
     127                         pjsip_rx_data_get_info(rdata), 
     128                         rdata->tp_info.transport->type_name, 
     129                         rdata->pkt_info.src_name, 
     130                         rdata->pkt_info.src_port, 
     131                         (int)rdata->msg_info.len, 
     132                         rdata->msg_info.msg_buf)); 
     133     
     134    /* Always return false, otherwise messages will not get processed! */ 
     135    return PJ_FALSE; 
     136} 
     137 
     138/* Notification on outgoing messages */ 
     139static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) 
     140{ 
     141     
     142    /* Important note: 
     143     *  tp_info field is only valid after outgoing messages has passed 
     144     *  transport layer. So don't try to access tp_info when the module 
     145     *  has lower priority than transport layer. 
     146     */ 
     147 
     148    PJ_LOG(5,(THIS_FILE, "TX %d bytes %s to %s %s:%d:\n" 
     149                         "%.*s\n" 
     150                         "--end msg--", 
     151                         (tdata->buf.cur - tdata->buf.start), 
     152                         pjsip_tx_data_get_info(tdata), 
     153                         tdata->tp_info.transport->type_name, 
     154                         tdata->tp_info.dst_name, 
     155                         tdata->tp_info.dst_port, 
     156                         (int)(tdata->buf.cur - tdata->buf.start), 
     157                         tdata->buf.start)); 
     158 
     159    /* Always return success, otherwise message will not get sent! */ 
     160    return PJ_SUCCESS; 
     161} 
     162 
     163/* The module instance. */ 
     164static pjsip_module mod_msg_logger =  
     165{ 
     166    NULL, NULL,                         /* prev, next.          */ 
     167    { "mod-msg-logger", 14 },           /* Name.                */ 
     168    -1,                                 /* Id                   */ 
     169    PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority            */ 
     170    NULL,                               /* load()               */ 
     171    NULL,                               /* start()              */ 
     172    NULL,                               /* stop()               */ 
     173    NULL,                               /* unload()             */ 
     174    &logging_on_rx_msg,                 /* on_rx_request()      */ 
     175    &logging_on_rx_msg,                 /* on_rx_response()     */ 
     176    &logging_on_tx_msg,                 /* on_tx_request.       */ 
     177    &logging_on_tx_msg,                 /* on_tx_response()     */ 
     178    NULL,                               /* on_tsx_state()       */ 
     179 
     180}; 
    98181 
    99182 
     
    142225    global.pool = pj_pool_create(&global.cp.factory, "proxyapp",  
    143226                                 4000, 4000, NULL); 
     227 
     228    /* Register the logger module */ 
     229    pjsip_endpt_register_module(global.endpt, &mod_msg_logger); 
    144230 
    145231    return PJ_SUCCESS; 
     
    413499 
    414500    /* We're not interested to receive request destined to us, so 
    415      * respond with 404/Not Found. 
    416      */ 
    417     pjsip_endpt_respond_stateless(global.endpt, rdata, 
    418                                   PJSIP_SC_NOT_FOUND, NULL, 
    419                                   NULL, NULL); 
     501     * respond with 404/Not Found (only if request is not ACK!). 
     502     */ 
     503    if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) { 
     504        pjsip_endpt_respond_stateless(global.endpt, rdata, 
     505                                      PJSIP_SC_NOT_FOUND, NULL, 
     506                                      NULL, NULL); 
     507    } 
    420508 
    421509    /* Delete the request since we're not forwarding it */ 
  • pjproject/branches/pjproject-0.5-stable/pjsip-apps/src/samples/stateful_proxy.c

    r1121 r1123  
    2424 
    2525 
    26 /* Callback to be called to handle incoming requests. */ 
    27 static pj_bool_t on_rx_request( pjsip_rx_data *rdata ); 
    28  
    29 /* Callback to be called to handle incoming response. */ 
    30 static pj_bool_t on_rx_response( pjsip_rx_data *rdata ); 
    31  
    32  
    33 /* This is the data that is attached to the UAC transaction */ 
    34 struct tsx_data 
    35 { 
    36     pjsip_transaction   *uas_tsx; 
    37     pj_timer_entry       timer; 
    38 }; 
    39  
     26/* 
     27 * mod_stateful_proxy is the module to receive SIP request and 
     28 * response message that is outside any transaction context. 
     29 */ 
     30static pj_bool_t proxy_on_rx_request(pjsip_rx_data *rdata ); 
     31static pj_bool_t proxy_on_rx_response(pjsip_rx_data *rdata ); 
    4032 
    4133static pjsip_module mod_stateful_proxy = 
    4234{ 
    43     NULL, NULL,                 /* prev, next.          */ 
     35    NULL, NULL,                         /* prev, next.          */ 
    4436    { "mod-stateful-proxy", 18 },       /* Name.                */ 
    45     -1,                         /* Id                   */ 
    46     PJSIP_MOD_PRIORITY_APPLICATION, /* Priority         */ 
     37    -1,                                 /* Id                   */ 
     38    PJSIP_MOD_PRIORITY_UA_PROXY_LAYER,  /* Priority             */ 
    4739    NULL,                               /* load()               */ 
    4840    NULL,                               /* start()              */ 
    4941    NULL,                               /* stop()               */ 
    5042    NULL,                               /* unload()             */ 
    51     &on_rx_request,                     /* on_rx_request()      */ 
    52     &on_rx_response,            /* on_rx_response()     */ 
     43    &proxy_on_rx_request,               /* on_rx_request()      */ 
     44    &proxy_on_rx_response,              /* on_rx_response()     */ 
    5345    NULL,                               /* on_tx_request.       */ 
    5446    NULL,                               /* on_tx_response()     */ 
     
    5749 
    5850 
     51/* 
     52 * mod_tu (tu=Transaction User) is the module to receive notification 
     53 * from transaction when the transaction state has changed. 
     54 */ 
     55static void tu_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event); 
     56 
     57static pjsip_module mod_tu = 
     58{ 
     59    NULL, NULL,                         /* prev, next.          */ 
     60    { "mod-transaction-user", 20 },     /* Name.                */ 
     61    -1,                                 /* Id                   */ 
     62    PJSIP_MOD_PRIORITY_APPLICATION,     /* Priority             */ 
     63    NULL,                               /* load()               */ 
     64    NULL,                               /* start()              */ 
     65    NULL,                               /* stop()               */ 
     66    NULL,                               /* unload()             */ 
     67    NULL,                               /* on_rx_request()      */ 
     68    NULL,                               /* on_rx_response()     */ 
     69    NULL,                               /* on_tx_request.       */ 
     70    NULL,                               /* on_tx_response()     */ 
     71    &tu_on_tsx_state,                   /* on_tsx_state()       */ 
     72}; 
     73 
     74 
     75/* This is the data that is attached to the UAC transaction */ 
     76struct uac_data 
     77{ 
     78    pjsip_transaction   *uas_tsx; 
     79    pj_timer_entry       timer; 
     80}; 
     81 
     82 
     83/* This is the data that is attached to the UAS transaction */ 
     84struct uas_data 
     85{ 
     86    pjsip_transaction   *uac_tsx; 
     87}; 
     88 
     89 
     90 
    5991static pj_status_t init_stateful_proxy(void) 
    6092{ 
    6193    pj_status_t status; 
    6294 
    63     /* Register our module to receive incoming requests. */ 
    6495    status = pjsip_endpt_register_module( global.endpt, &mod_stateful_proxy); 
    6596    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    6697 
     98    status = pjsip_endpt_register_module( global.endpt, &mod_tu); 
     99    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
     100 
    67101    return PJ_SUCCESS; 
    68102} 
    69103 
    70104 
    71 /* Callback to be called to handle incoming requests. */ 
    72 static pj_bool_t on_rx_request( pjsip_rx_data *rdata ) 
     105/* Callback to be called to handle new incoming requests. */ 
     106static pj_bool_t proxy_on_rx_request( pjsip_rx_data *rdata ) 
    73107{ 
    74108    pjsip_transaction *uas_tsx, *uac_tsx; 
    75     struct tsx_data *tsx_data; 
     109    struct uac_data *uac_data; 
     110    struct uas_data *uas_data; 
    76111    pjsip_tx_data *tdata; 
    77112    pj_status_t status; 
    78113 
    79     /* Verify incoming request */ 
    80     status = proxy_verify_request(rdata); 
    81     if (status != PJ_SUCCESS) { 
    82         app_perror("RX invalid request", status); 
    83         return PJ_TRUE; 
    84     } 
    85  
    86     /* 
    87      * Request looks sane, next clone the request to create transmit data. 
    88      */ 
    89     status = pjsip_endpt_create_request_fwd(global.endpt, rdata, NULL, 
    90                                             NULL, 0, &tdata); 
    91     if (status != PJ_SUCCESS) { 
    92         pjsip_endpt_respond_stateless(global.endpt, rdata, 
    93                                       PJSIP_SC_INTERNAL_SERVER_ERROR, NULL,  
    94                                       NULL, NULL); 
    95         return PJ_TRUE; 
    96     } 
    97  
    98  
    99     /* Process routing */ 
    100     status = proxy_process_routing(tdata); 
    101     if (status != PJ_SUCCESS) { 
    102         app_perror("Error processing route", status); 
    103         return PJ_TRUE; 
    104     } 
    105  
    106     /* Calculate target */ 
    107     status = proxy_calculate_target(rdata, tdata); 
    108     if (status != PJ_SUCCESS) { 
    109         app_perror("Error calculating target", status); 
    110         return PJ_TRUE; 
    111     } 
    112  
    113     /* Everything is set to forward the request. */ 
    114  
    115     /* If this is an ACK request, forward statelessly */ 
    116     if (tdata->msg->line.req.method.id == PJSIP_ACK_METHOD) { 
    117         status = pjsip_endpt_send_request_stateless(global.endpt, tdata,  
    118                                                     NULL, NULL); 
    119         if (status != PJ_SUCCESS) { 
    120             app_perror("Error forwarding request", status); 
    121             return PJ_TRUE; 
    122         } 
    123  
    124         return PJ_TRUE; 
    125     } 
    126  
    127     /* Create UAC transaction for forwarding the request */ 
    128     status = pjsip_tsx_create_uac(&mod_stateful_proxy, tdata, &uac_tsx); 
    129     if (status != PJ_SUCCESS) { 
    130         pjsip_tx_data_dec_ref(tdata); 
    131         pjsip_endpt_respond_stateless(global.endpt, rdata,  
    132                                       PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, 
    133                                       NULL, NULL); 
    134         return PJ_TRUE; 
    135     } 
    136  
    137     /* Create UAS transaction to handle incoming request */ 
    138     status = pjsip_tsx_create_uas(&mod_stateful_proxy, rdata, &uas_tsx); 
    139     if (status != PJ_SUCCESS) { 
    140         pjsip_tx_data_dec_ref(tdata); 
    141         pjsip_endpt_respond_stateless(global.endpt, rdata,  
    142                                       PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, 
    143                                       NULL, NULL); 
    144         pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); 
    145         return PJ_TRUE; 
    146     } 
    147  
    148     /* Feed the request to the UAS transaction to drive it's state  
    149      * out of NULL state.  
    150      */ 
    151     pjsip_tsx_recv_msg(uas_tsx, rdata); 
    152  
    153     /* Attach a data to the UAC transaction, to be used to find the 
    154      * UAS transaction when we receive response in the UAC side. 
    155      */ 
    156     tsx_data = pj_pool_alloc(uac_tsx->pool, sizeof(struct tsx_data)); 
    157     tsx_data->uas_tsx = uas_tsx; 
    158      
    159     uac_tsx->mod_data[mod_stateful_proxy.id] = (void*)tsx_data; 
    160  
    161     /* Everything is setup, forward the request */ 
    162     status = pjsip_tsx_send_msg(uac_tsx, tdata); 
    163     if (status != PJ_SUCCESS) { 
    164         pjsip_tx_data *err_res; 
    165  
    166         /* Fail to send request, for some reason */ 
    167  
    168         /* Destroy UAC transaction */ 
    169         pjsip_tx_data_dec_ref(tdata); 
    170         pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); 
    171  
    172         /* Send 500/Internal Server Error to UAS transaction */ 
    173         status = pjsip_endpt_create_response(global.endpt, rdata, 
    174                                              PJSIP_SC_INTERNAL_SERVER_ERROR, 
    175                                              NULL, &err_res); 
    176         if (status == PJ_SUCCESS) 
     114    if (rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD) { 
     115 
     116        /* Verify incoming request */ 
     117        status = proxy_verify_request(rdata); 
     118        if (status != PJ_SUCCESS) { 
     119            app_perror("RX invalid request", status); 
     120            return PJ_TRUE; 
     121        } 
     122 
     123        /* 
     124         * Request looks sane, next clone the request to create transmit data. 
     125         */ 
     126        status = pjsip_endpt_create_request_fwd(global.endpt, rdata, NULL, 
     127                                                NULL, 0, &tdata); 
     128        if (status != PJ_SUCCESS) { 
     129            pjsip_endpt_respond_stateless(global.endpt, rdata, 
     130                                          PJSIP_SC_INTERNAL_SERVER_ERROR,  
     131                                          NULL, NULL, NULL); 
     132            return PJ_TRUE; 
     133        } 
     134 
     135 
     136        /* Process routing */ 
     137        status = proxy_process_routing(tdata); 
     138        if (status != PJ_SUCCESS) { 
     139            app_perror("Error processing route", status); 
     140            return PJ_TRUE; 
     141        } 
     142 
     143        /* Calculate target */ 
     144        status = proxy_calculate_target(rdata, tdata); 
     145        if (status != PJ_SUCCESS) { 
     146            app_perror("Error calculating target", status); 
     147            return PJ_TRUE; 
     148        } 
     149 
     150        /* Everything is set to forward the request. */ 
     151 
     152        /* If this is an ACK request, forward statelessly. 
     153         * This happens if the proxy records route and this ACK 
     154         * is sent for 2xx response. An ACK that is sent for non-2xx 
     155         * final response will be absorbed by transaction layer, and 
     156         * it will not be received by on_rx_request() callback. 
     157         */ 
     158        if (tdata->msg->line.req.method.id == PJSIP_ACK_METHOD) { 
     159            status = pjsip_endpt_send_request_stateless(global.endpt, tdata,  
     160                                                        NULL, NULL); 
     161            if (status != PJ_SUCCESS) { 
     162                app_perror("Error forwarding request", status); 
     163                return PJ_TRUE; 
     164            } 
     165 
     166            return PJ_TRUE; 
     167        } 
     168 
     169        /* Create UAC transaction for forwarding the request.  
     170         * Set our module as the transaction user to receive further 
     171         * events from this transaction. 
     172         */ 
     173        status = pjsip_tsx_create_uac(&mod_tu, tdata, &uac_tsx); 
     174        if (status != PJ_SUCCESS) { 
     175            pjsip_tx_data_dec_ref(tdata); 
     176            pjsip_endpt_respond_stateless(global.endpt, rdata,  
     177                                          PJSIP_SC_INTERNAL_SERVER_ERROR,  
     178                                          NULL, NULL, NULL); 
     179            return PJ_TRUE; 
     180        } 
     181 
     182        /* Create UAS transaction to handle incoming request */ 
     183        status = pjsip_tsx_create_uas(&mod_tu, rdata, &uas_tsx); 
     184        if (status != PJ_SUCCESS) { 
     185            pjsip_tx_data_dec_ref(tdata); 
     186            pjsip_endpt_respond_stateless(global.endpt, rdata,  
     187                                          PJSIP_SC_INTERNAL_SERVER_ERROR,  
     188                                          NULL, NULL, NULL); 
     189            pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); 
     190            return PJ_TRUE; 
     191        } 
     192 
     193        /* Feed the request to the UAS transaction to drive it's state  
     194         * out of NULL state.  
     195         */ 
     196        pjsip_tsx_recv_msg(uas_tsx, rdata); 
     197 
     198        /* Attach a data to the UAC transaction, to be used to find the 
     199         * UAS transaction when we receive response in the UAC side. 
     200         */ 
     201        uac_data = (struct uac_data*) 
     202                   pj_pool_alloc(uac_tsx->pool, sizeof(struct uac_data)); 
     203        uac_data->uas_tsx = uas_tsx; 
     204        uac_tsx->mod_data[mod_tu.id] = (void*)uac_data; 
     205 
     206        /* Attach data to the UAS transaction, to find the UAC transaction 
     207         * when cancelling INVITE request. 
     208         */ 
     209        uas_data = (struct uas_data*) 
     210                    pj_pool_alloc(uas_tsx->pool, sizeof(struct uas_data)); 
     211        uas_data->uac_tsx = uac_tsx; 
     212        uas_tsx->mod_data[mod_tu.id] = (void*)uas_data; 
     213 
     214        /* Everything is setup, forward the request */ 
     215        status = pjsip_tsx_send_msg(uac_tsx, tdata); 
     216        if (status != PJ_SUCCESS) { 
     217            pjsip_tx_data *err_res; 
     218 
     219            /* Fail to send request, for some reason */ 
     220 
     221            /* Destroy transmit data */ 
     222            pjsip_tx_data_dec_ref(tdata); 
     223 
     224            /* I think UAC transaction should have been destroyed when 
     225             * it fails to send request, so no need to destroy it. 
     226            pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); 
     227             */ 
     228 
     229            /* Send 500/Internal Server Error to UAS transaction */ 
     230            pjsip_endpt_create_response(global.endpt, rdata, 
     231                                        500, NULL, &err_res); 
    177232            pjsip_tsx_send_msg(uas_tsx, err_res); 
    178         else 
    179             pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); 
    180  
    181         return PJ_TRUE; 
     233 
     234            return PJ_TRUE; 
     235        } 
     236 
     237        /* Send 100/Trying if this is an INVITE */ 
     238        if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) { 
     239            pjsip_tx_data *res100; 
     240 
     241            pjsip_endpt_create_response(global.endpt, rdata, 100, NULL,  
     242                                        &res100); 
     243            pjsip_tsx_send_msg(uas_tsx, res100); 
     244        } 
     245 
     246    } else { 
     247        /* This is CANCEL request */ 
     248        pjsip_transaction *invite_uas; 
     249        struct uas_data *uas_data; 
     250        pj_str_t key; 
     251         
     252        /* Find the UAS INVITE transaction */ 
     253        pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_UAS_ROLE, 
     254                             &pjsip_invite_method, rdata); 
     255        invite_uas = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE); 
     256        if (!invite_uas) { 
     257            /* Invite transaction not found, respond CANCEL with 481 */ 
     258            pjsip_endpt_respond_stateless(global.endpt, rdata, 481, NULL, 
     259                                          NULL, NULL); 
     260            return PJ_TRUE; 
     261        } 
     262 
     263        /* Respond 200 OK to CANCEL */ 
     264        pjsip_endpt_respond(global.endpt, NULL, rdata, 200, NULL, NULL, 
     265                            NULL, NULL); 
     266 
     267        /* Send CANCEL to cancel the UAC transaction. 
     268         * The UAS INVITE transaction will get final response when 
     269         * we receive final response from the UAC INVITE transaction. 
     270         */ 
     271        uas_data = (struct uas_data*) invite_uas->mod_data[mod_tu.id]; 
     272        if (uas_data->uac_tsx) { 
     273            pjsip_tx_data *cancel; 
     274 
     275            pj_mutex_lock(uas_data->uac_tsx->mutex); 
     276 
     277            pjsip_endpt_create_cancel(global.endpt, uas_data->uac_tsx->last_tx, 
     278                                      &cancel); 
     279            pjsip_endpt_send_request(global.endpt, cancel, -1, NULL, NULL); 
     280 
     281            pj_mutex_unlock(uas_data->uac_tsx->mutex); 
     282        } 
     283 
     284        /* Unlock UAS tsx because it is locked in find_tsx() */ 
     285        pj_mutex_unlock(invite_uas->mutex); 
    182286    } 
    183287 
     
    186290 
    187291 
    188 /* Callback to be called to handle incoming response. */ 
    189 static pj_bool_t on_rx_response( pjsip_rx_data *rdata ) 
    190 { 
    191     pjsip_transaction *uac_tsx; 
     292/* Callback to be called to handle incoming response outside 
     293 * any transactions. This happens for example when 2xx/OK 
     294 * for INVITE is received and transaction will be destroyed 
     295 * immediately, so we need to forward the subsequent 2xx/OK 
     296 * retransmission statelessly. 
     297 */ 
     298static pj_bool_t proxy_on_rx_response( pjsip_rx_data *rdata ) 
     299{ 
    192300    pjsip_tx_data *tdata; 
    193301    pjsip_response_addr res_addr; 
     
    213321    pj_bzero(&res_addr, sizeof(res_addr)); 
    214322    res_addr.dst_host.type = PJSIP_TRANSPORT_UDP; 
    215     res_addr.dst_host.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP); 
     323    res_addr.dst_host.flag =  
     324        pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP); 
    216325 
    217326    /* Destination address is Via's received param */ 
     
    222331    } 
    223332 
    224     /* Destination port is the rpot */ 
     333    /* Destination port is the rport */ 
    225334    if (hvia->rport_param != 0 && hvia->rport_param != -1) 
    226335        res_addr.dst_host.addr.port = hvia->rport_param; 
     
    233342    } 
    234343 
    235     uac_tsx = pjsip_rdata_get_tsx(rdata); 
    236  
    237     if (!uac_tsx) { 
    238         /* UAC transaction not found (it may have been destroyed). 
    239          * Forward response statelessly. 
    240          */ 
    241         status = pjsip_endpt_send_response(global.endpt, &res_addr, tdata, 
    242                                            NULL, NULL); 
    243         if (status != PJ_SUCCESS) { 
    244             app_perror("Error forwarding response", status); 
    245             return PJ_TRUE; 
    246         } 
    247     } else { 
    248         struct tsx_data *tsx_data; 
    249  
    250         tsx_data = (struct tsx_data*) uac_tsx->mod_data[mod_stateful_proxy.id]; 
     344    /* Forward response */ 
     345    status = pjsip_endpt_send_response(global.endpt, &res_addr, tdata, 
     346                                       NULL, NULL); 
     347    if (status != PJ_SUCCESS) { 
     348        app_perror("Error forwarding response", status); 
     349        return PJ_TRUE; 
     350    } 
     351 
     352    return PJ_TRUE; 
     353} 
     354 
     355 
     356/* Callback to be called to handle transaction state changed. */ 
     357static void tu_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event) 
     358{ 
     359    struct uac_data *uac_data; 
     360    pj_status_t status; 
     361 
     362    if (tsx->role == PJSIP_ROLE_UAS) { 
     363        if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { 
     364            struct uas_data *uas_data; 
     365 
     366            uas_data = (struct uas_data*) tsx->mod_data[mod_tu.id]; 
     367            if (uas_data->uac_tsx) { 
     368                uac_data = (struct uac_data*) 
     369                           uas_data->uac_tsx->mod_data[mod_tu.id]; 
     370                uac_data->uas_tsx = NULL; 
     371            } 
     372                        
     373        } 
     374        return; 
     375    } 
     376 
     377    /* Get the data that we attached to the UAC transaction previously */ 
     378    uac_data = (struct uac_data*) tsx->mod_data[mod_tu.id]; 
     379 
     380 
     381    /* Handle incoming response */ 
     382    if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { 
     383 
     384        pjsip_rx_data *rdata; 
     385        pjsip_response_addr res_addr; 
     386        pjsip_via_hdr *hvia; 
     387        pjsip_tx_data *tdata; 
     388 
     389        rdata = event->body.tsx_state.src.rdata; 
     390 
     391        /* Do not forward 100 response for INVITE (we already responded 
     392         * INVITE with 100) 
     393         */ 
     394        if (tsx->method.id == PJSIP_INVITE_METHOD &&  
     395            rdata->msg_info.msg->line.status.code == 100) 
     396        { 
     397            return; 
     398        } 
     399 
     400        /* Create response to be forwarded upstream  
     401         * (Via will be stripped here)  
     402         */ 
     403        status = pjsip_endpt_create_response_fwd(global.endpt, rdata, 0,  
     404                                                 &tdata); 
     405        if (status != PJ_SUCCESS) { 
     406            app_perror("Error creating response", status); 
     407            return; 
     408        } 
     409 
     410        /* Get topmost Via header of the new response */ 
     411        hvia = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA,  
     412                                                   NULL); 
     413        if (hvia == NULL) { 
     414            /* Invalid response! Just drop it */ 
     415            pjsip_tx_data_dec_ref(tdata); 
     416            return; 
     417        } 
     418 
     419        /* Calculate the address to forward the response */ 
     420        pj_bzero(&res_addr, sizeof(res_addr)); 
     421        res_addr.dst_host.type = PJSIP_TRANSPORT_UDP; 
     422        res_addr.dst_host.flag =  
     423            pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP); 
     424 
     425        /* Destination address is Via's received param */ 
     426        res_addr.dst_host.addr.host = hvia->recvd_param; 
     427        if (res_addr.dst_host.addr.host.slen == 0) { 
     428            /* Someone has messed up our Via header! */ 
     429            res_addr.dst_host.addr.host = hvia->sent_by.host; 
     430        } 
     431 
     432        /* Destination port is the rport */ 
     433        if (hvia->rport_param != 0 && hvia->rport_param != -1) 
     434            res_addr.dst_host.addr.port = hvia->rport_param; 
     435 
     436        if (res_addr.dst_host.addr.port == 0) { 
     437            /* Ugh, original sender didn't put rport! 
     438             * At best, can only send the response to the port in Via. 
     439             */ 
     440            res_addr.dst_host.addr.port = hvia->sent_by.port; 
     441        } 
    251442 
    252443        /* Forward response with the UAS transaction */ 
    253         pjsip_tsx_send_msg(tsx_data->uas_tsx, tdata); 
    254  
    255         /* Special case for pjsip: 
    256          * if response is 2xx for INVITE transaction, terminate the UAS 
    257          * transaction (otherwise it will retransmit the response). 
    258          */ 
    259         if (tsx_data->uas_tsx->method.id == PJSIP_INVITE_METHOD && 
    260             rdata->msg_info.msg->line.status.code/100 == 2) 
    261         { 
    262             pjsip_tsx_terminate(tsx_data->uas_tsx, 
    263                                 rdata->msg_info.msg->line.status.code); 
    264             tsx_data->uas_tsx = NULL; 
    265         } 
    266     } 
    267  
    268     return PJ_TRUE; 
     444        pjsip_tsx_send_msg(uac_data->uas_tsx, tdata); 
     445 
     446    } 
     447 
     448    /* If UAC transaction is terminated, terminate the UAS as well. 
     449     * This could happen because of: 
     450     *  - timeout on the UAC side 
     451     *  - receipt of 2xx response to INVITE 
     452     */ 
     453    if (tsx->state == PJSIP_TSX_STATE_TERMINATED && uac_data->uas_tsx) { 
     454 
     455        pjsip_transaction *uas_tsx; 
     456        struct uas_data *uas_data; 
     457 
     458        uas_tsx = uac_data->uas_tsx; 
     459        uas_data = (struct uas_data*) uas_tsx->mod_data[mod_tu.id]; 
     460        uas_data->uac_tsx = NULL; 
     461 
     462        if (event->body.tsx_state.type == PJSIP_EVENT_TIMER) { 
     463 
     464            /* Send 408/Timeout if this is an INVITE transaction, since 
     465             * we must have sent provisional response before. For non 
     466             * INVITE transaction, just destroy it. 
     467             */ 
     468            if (tsx->method.id == PJSIP_INVITE_METHOD) { 
     469 
     470                pjsip_tx_data *tdata = uas_tsx->last_tx; 
     471 
     472                tdata->msg->line.status.code = PJSIP_SC_REQUEST_TIMEOUT; 
     473                tdata->msg->line.status.reason = pj_str("Request timed out"); 
     474                tdata->msg->body = NULL; 
     475 
     476                pjsip_tx_data_add_ref(tdata); 
     477                pjsip_tx_data_invalidate_msg(tdata); 
     478 
     479                pjsip_tsx_send_msg(uas_tsx, tdata); 
     480 
     481            } else { 
     482                /* For non-INVITE, just destroy the UAS transaction */ 
     483                pjsip_tsx_terminate(uas_tsx, PJSIP_SC_REQUEST_TIMEOUT); 
     484            } 
     485 
     486        } else if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) { 
     487 
     488            if (uas_tsx->state < PJSIP_TSX_STATE_TERMINATED) { 
     489                pjsip_msg *msg; 
     490                int code; 
     491 
     492                msg = event->body.tsx_state.src.rdata->msg_info.msg; 
     493                code = msg->line.status.code; 
     494 
     495                uac_data->uas_tsx = NULL; 
     496                pjsip_tsx_terminate(uas_tsx, code); 
     497            } 
     498        } 
     499    } 
    269500} 
    270501 
     
    280511    global.record_route = 0; 
    281512 
     513    pj_log_set_level(4); 
     514 
    282515    status = init_options(argc, argv); 
    283516    if (status != PJ_SUCCESS) 
    284517        return 1; 
    285  
    286     pj_log_set_level(4); 
    287518 
    288519    status = init_stack(); 
  • pjproject/branches/pjproject-0.5-stable/pjsip-apps/src/samples/stateless_proxy.c

    r1121 r1123  
    3535    static pjsip_module mod_stateless_proxy = 
    3636    { 
    37         NULL, NULL,                     /* prev, next.          */ 
    38         { "mod-stateless-proxy", 19 },  /* Name.                */ 
    39         -1,                             /* Id                   */ 
    40         PJSIP_MOD_PRIORITY_APPLICATION, /* Priority             */ 
    41         NULL,                           /* load()               */ 
    42         NULL,                           /* start()              */ 
    43         NULL,                           /* stop()               */ 
    44         NULL,                           /* unload()             */ 
    45         &on_rx_request,                 /* on_rx_request()      */ 
    46         &on_rx_response,                /* on_rx_response()     */ 
    47         NULL,                           /* on_tx_request.       */ 
    48         NULL,                           /* on_tx_response()     */ 
    49         NULL,                           /* on_tsx_state()       */ 
     37        NULL, NULL,                         /* prev, next.      */ 
     38        { "mod-stateless-proxy", 19 },      /* Name.            */ 
     39        -1,                                 /* Id               */ 
     40        PJSIP_MOD_PRIORITY_UA_PROXY_LAYER, /* Priority         */ 
     41        NULL,                               /* load()           */ 
     42        NULL,                               /* start()          */ 
     43        NULL,                               /* stop()           */ 
     44        NULL,                               /* unload()         */ 
     45        &on_rx_request,                     /* on_rx_request()  */ 
     46        &on_rx_response,                    /* on_rx_response() */ 
     47        NULL,                               /* on_tx_request.   */ 
     48        NULL,                               /* on_tx_response() */ 
     49        NULL,                               /* on_tsx_state()   */ 
    5050    }; 
    5151 
     
    179179 
    180180    global.port = 5060; 
     181    pj_log_set_level(4); 
    181182 
    182183    status = init_options(argc, argv); 
    183184    if (status != PJ_SUCCESS) 
    184185        return 1; 
    185  
    186     pj_log_set_level(4); 
    187186 
    188187    status = init_stack(); 
Note: See TracChangeset for help on using the changeset viewer.