Changeset 160


Ignore:
Timestamp:
Feb 8, 2006 10:44:25 PM (18 years ago)
Author:
bennylp
Message:

Finished invite session UAS implementation

Location:
pjproject/trunk/pjsip
Files:
12 edited

Legend:

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

    r141 r160  
    5050 
    5151/** 
     52 * Dialog state. 
     53 */ 
     54enum pjsip_dialog_state 
     55{ 
     56    PJSIP_DIALOG_STATE_NULL, 
     57    PJSIP_DIALOG_STATE_ESTABLISHED, 
     58}; 
     59 
     60/** 
    5261 * This structure describes the dialog structure. 
    5362 */ 
     
    6877 
    6978    /* Dialog's session properties. */ 
    70     pj_bool_t           established;/**< Dialog is established?             */ 
     79    enum pjsip_dialog_state     state;      /**< Dialog state.                      */ 
    7180    pjsip_uri          *target;     /**< Current target.                    */ 
    7281    pjsip_dlg_party     local;      /**< Local party info.                  */ 
  • pjproject/trunk/pjsip/include/pjsip/sip_event.h

    r139 r160  
    125125        { 
    126126            pjsip_tx_data       *tdata; /**< The transmit data buffer.  */ 
    127             pjsip_transaction   *tsx;   /**< The transaction.           */ 
    128127 
    129128        } tx_msg; 
     
    140139        { 
    141140            pjsip_rx_data       *rdata; /**< The receive data buffer.   */ 
    142             pjsip_transaction   *tsx;   /**< The transaction.           */ 
    143141        } rx_msg; 
    144142 
     
    179177 * Init tx msg event. 
    180178 */ 
    181 #define PJSIP_EVENT_INIT_TX_MSG(event,ptsx,ptdata)      \ 
     179#define PJSIP_EVENT_INIT_TX_MSG(event,ptdata)   \ 
    182180        do { \ 
    183181            (event).type = PJSIP_EVENT_TX_MSG;          \ 
    184             (event).body.tx_msg.tsx = ptsx;             \ 
    185182            (event).body.tx_msg.tdata = ptdata;         \ 
    186183        } while (0) 
     
    189186 * Init rx msg event. 
    190187 */ 
    191 #define PJSIP_EVENT_INIT_RX_MSG(event,ptsx,prdata)      \ 
     188#define PJSIP_EVENT_INIT_RX_MSG(event,prdata)   \ 
    192189        do { \ 
    193190            (event).type = PJSIP_EVENT_RX_MSG;          \ 
    194             (event).body.rx_msg.tsx = ptsx;             \ 
    195191            (event).body.rx_msg.rdata = prdata;         \ 
    196192        } while (0) 
  • pjproject/trunk/pjsip/include/pjsip/sip_transaction.h

    r127 r160  
    176176/** 
    177177 * Create, initialize, and register a new transaction as UAS from the 
    178  * specified incoming request in \c rdata. 
     178 * specified incoming request in \c rdata. After calling this function, 
     179 * application MUST call #pjsip_tsx_recv_msg() so that transaction 
     180 * moves from state NULL. 
    179181 * 
    180182 * @param tsx_user  Module to be registered as transaction user of the new 
     
    190192                                           pjsip_transaction **p_tsx ); 
    191193 
     194 
     195/** 
     196 * Call this function to manually feed a message to the transaction. 
     197 * For UAS transaction, application MUST call this function after 
     198 * UAS transaction has been created. 
     199 * 
     200 * This function SHOULD only be called to pass initial request message 
     201 * to UAS transaction. Before this function returns, on_tsx_state() 
     202 * callback of the transaction user will be called. If response message 
     203 * is passed to this function, then on_rx_response() will also be called 
     204 * before on_tsx_state(). 
     205 * 
     206 * @param tsx       The transaction. 
     207 * @param rdata     The message. 
     208 */ 
     209PJ_DECL(void) pjsip_tsx_recv_msg( pjsip_transaction *tsx,  
     210                                  pjsip_rx_data *rdata); 
     211 
    192212/** 
    193213 * Transmit message in tdata with this transaction. It is possible to 
  • pjproject/trunk/pjsip/include/pjsip/sip_types.h

    r127 r160  
    134134typedef struct pjsip_dialog pjsip_dialog; 
    135135 
     136/** 
     137 * Dialog state (sip_dialog.h). 
     138 */ 
     139enum pjsip_dialog_state pjsip_dialog_state; 
    136140 
    137141/** 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c

    r156 r160  
    110110 
    111111/* 
     112 * Set session state. 
     113 */ 
     114void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state, 
     115                   pjsip_event *e) 
     116{ 
     117    inv->state = state; 
     118    if (mod_inv.cb.on_state_changed) 
     119        (*mod_inv.cb.on_state_changed)(inv, e); 
     120 
     121    if (inv->state == PJSIP_INV_STATE_DISCONNECTED) 
     122        pjsip_dlg_dec_session(inv->dlg); 
     123} 
     124 
     125 
     126/* 
    112127 * Send ACK for 2xx response. 
    113128 */ 
     
    146161{ 
    147162    pjsip_method *method; 
     163    pjsip_dialog *dlg; 
     164    pjsip_inv_session *inv; 
    148165 
    149166    /* Only wants to receive request from a dialog. */ 
    150     if (pjsip_rdata_get_dlg(rdata) == NULL) 
     167    dlg = pjsip_rdata_get_dlg(rdata); 
     168    if (dlg == NULL) 
    151169        return PJ_FALSE; 
     170 
     171    inv = dlg->mod_data[mod_inv.mod.id]; 
    152172 
    153173    /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.  
     
    159179    if (method->id == PJSIP_INVITE_METHOD || 
    160180        method->id == PJSIP_CANCEL_METHOD || 
    161         method->id == PJSIP_ACK_METHOD || 
    162181        method->id == PJSIP_BYE_METHOD) 
    163182    { 
    164183        return PJ_TRUE; 
     184    } 
     185 
     186    /* On receipt ACK request, when state is CONNECTING, 
     187     * move state to CONFIRMED. 
     188     */ 
     189    if (method->id == PJSIP_ACK_METHOD && inv && 
     190        inv->state == PJSIP_INV_STATE_CONFIRMED) 
     191    { 
     192        pjsip_event event; 
     193 
     194        PJSIP_EVENT_INIT_RX_MSG(event, rdata); 
     195        inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event); 
    165196    } 
    166197 
     
    703734    inv->pool = dlg->pool; 
    704735    inv->role = PJSIP_ROLE_UAS; 
    705     inv->state = PJSIP_INV_STATE_INCOMING; 
     736    inv->state = PJSIP_INV_STATE_NULL; 
    706737    inv->dlg = dlg; 
    707738    inv->options = options; 
     
    10671098 
    10681099 
    1069 void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state, 
    1070                    pjsip_event *e) 
    1071 { 
    1072     inv->state = state; 
    1073     if (mod_inv.cb.on_state_changed) 
    1074         (*mod_inv.cb.on_state_changed)(inv, e); 
    1075  
    1076     if (inv->state == PJSIP_INV_STATE_DISCONNECTED) 
    1077         pjsip_dlg_dec_session(inv->dlg); 
    1078 } 
    1079  
    1080  
    1081  
    10821100/* 
    10831101 * Respond to incoming CANCEL request. 
     
    11641182    if (inv->state != PJSIP_INV_STATE_DISCONNECTED) 
    11651183        inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     1184} 
     1185 
     1186/* 
     1187 * Respond to BYE request. 
     1188 */ 
     1189static void inv_handle_bye_response( pjsip_inv_session *inv, 
     1190                                     pjsip_transaction *tsx, 
     1191                                     pjsip_rx_data *rdata, 
     1192                                     pjsip_event *e ) 
     1193{ 
     1194    pj_status_t status; 
     1195     
     1196    if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) { 
     1197        inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     1198        return; 
     1199    } 
     1200 
     1201    /* Handle 401/407 challenge. */ 
     1202    if (tsx->status_code == 401 || tsx->status_code == 407) { 
     1203 
     1204        pjsip_tx_data *tdata; 
     1205         
     1206        status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,  
     1207                                            rdata, 
     1208                                            tsx->last_tx, 
     1209                                            &tdata); 
     1210         
     1211        if (status != PJ_SUCCESS) { 
     1212             
     1213            /* Does not have proper credentials.  
     1214             * End the session anyway. 
     1215             */ 
     1216            inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     1217             
     1218        } else { 
     1219            /* Re-send BYE. */ 
     1220            status = pjsip_inv_send_msg(inv, tdata, NULL ); 
     1221        } 
     1222 
     1223    } else { 
     1224 
     1225        /* End the session. */ 
     1226 
     1227        inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     1228    } 
     1229 
    11661230} 
    11671231 
     
    11971261            case PJSIP_TSX_STATE_TRYING: 
    11981262                inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e); 
     1263                break; 
     1264            case PJSIP_TSX_STATE_PROCEEDING: 
     1265                inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e); 
     1266                if (tsx->status_code > 100) 
     1267                    inv_set_state(inv, PJSIP_INV_STATE_EARLY, e); 
    11991268                break; 
    12001269            default: 
     
    14641533 
    14651534        case PJSIP_TSX_STATE_CONFIRMED: 
     1535            if (tsx->status_code/100 == 2) 
     1536                inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e); 
    14661537            break; 
    14671538 
     
    14961567        inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e ); 
    14971568 
    1498     } 
     1569    } else if (tsx->method.id == PJSIP_BYE_METHOD && 
     1570               tsx->role == PJSIP_ROLE_UAC && 
     1571               tsx->state == PJSIP_TSX_STATE_COMPLETED) 
     1572    { 
     1573 
     1574        /* 
     1575         * Outgoing BYE 
     1576         */ 
     1577        inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e); 
     1578 
     1579    } 
     1580 
    14991581} 
    15001582 
     
    15141596        tsx->state == PJSIP_TSX_STATE_COMPLETED) 
    15151597    { 
     1598 
    15161599        /* 
    1517          * Outgoing BYE. 
     1600         * Outgoing BYE 
    15181601         */ 
    1519         pj_status_t status; 
    1520          
    1521         /* Handle 401/407 challenge. */ 
    1522         if (tsx->status_code == 401 || tsx->status_code == 407) { 
    1523  
    1524             pjsip_tx_data *tdata; 
    1525              
    1526             status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,  
    1527                                                 e->body.tsx_state.src.rdata, 
    1528                                                 tsx->last_tx, 
    1529                                                 &tdata); 
    1530              
    1531             if (status != PJ_SUCCESS) { 
    1532                  
    1533                 /* Does not have proper credentials.  
    1534                  * End the session anyway. 
    1535                  */ 
    1536                 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
    1537                  
    1538             } else { 
    1539                 /* Re-send BYE. */ 
    1540                 status = pjsip_inv_send_msg(inv, tdata, NULL ); 
    1541             } 
    1542  
    1543         } else { 
    1544  
    1545             /* End the session. */ 
    1546  
     1602 
     1603        if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) 
     1604            inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e); 
     1605        else 
    15471606            inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
    1548         } 
    15491607 
    15501608    } 
  • pjproject/trunk/pjsip/src/pjsip/sip_dialog.c

    r141 r160  
    7575    dlg->ua = ua; 
    7676    dlg->endpt = endpt; 
     77    dlg->state = PJSIP_DIALOG_STATE_NULL; 
    7778 
    7879    status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex); 
     
    375376    PJ_TODO(DIALOG_APP_TIMER); 
    376377 
     378    /* Feed the first request to the transaction. */ 
     379    pjsip_tsx_recv_msg(tsx, rdata); 
     380 
    377381    /* Done. */ 
    378382    *p_dlg = dlg; 
     
    408412                     PJSIP_ENOTRESPONSEMSG); 
    409413 
     414    /* Status code MUST be 1xx (but not 100), or 2xx */ 
     415    status = rdata->msg_info.msg->line.status.code; 
     416    PJ_ASSERT_RETURN( (status/100==1 && status!=100) || 
     417                      (status/100==2), PJ_EBUG); 
     418 
    410419    /* To tag must present in the response. */ 
    411420    PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen != 0, PJSIP_EMISSINGTAG); 
     
    444453    /* Initial role is UAC. */ 
    445454    dlg->role = PJSIP_ROLE_UAC; 
     455 
     456    /* Dialog state depends on the response. */ 
     457    status = rdata->msg_info.msg->line.status.code/100; 
     458    if (status == 1 || status == 2) 
     459        dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED; 
     460    else { 
     461        pj_assert(!"Invalid status code"); 
     462        dlg->state = PJSIP_DIALOG_STATE_NULL; 
     463    } 
    446464 
    447465    /* Secure? */ 
     
    463481    } 
    464482 
    465     /* Init client authentication session. */ 
     483    /* Clone client authentication session. */ 
    466484    status = pjsip_auth_clt_clone(dlg->pool, &dlg->auth_sess,  
    467485                                  &first_dlg->auth_sess); 
     
    850868} 
    851869 
     870/* Add standard headers for certain types of response */ 
     871static void dlg_beautify_response(pjsip_dialog *dlg, 
     872                                  int st_code, 
     873                                  pjsip_tx_data *tdata) 
     874{ 
     875    pjsip_cseq_hdr *cseq; 
     876    int st_class; 
     877    const pjsip_hdr *c_hdr; 
     878    pjsip_hdr *hdr; 
     879 
     880    cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg); 
     881    pj_assert(cseq != NULL); 
     882 
     883    st_class = st_code / 100; 
     884 
     885    /* Contact, Allow, Supported header. */ 
     886    if (pjsip_method_creates_dialog(&cseq->method)) { 
     887        /* Add Contact header for 1xx, 2xx, 3xx and 485 response. */ 
     888        if (st_class==2 || st_class==3 || (st_class==1 && st_code != 100) || 
     889            st_code==485)  
     890        { 
     891            /* Add contact header only if one is not present. */ 
     892            if (pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL) == 0) { 
     893                hdr = pjsip_hdr_clone(tdata->pool, dlg->local.contact); 
     894                pjsip_msg_add_hdr(tdata->msg, hdr); 
     895            } 
     896        } 
     897 
     898        /* Add Allow header in 2xx and 405 response. */ 
     899        if ((st_class==2 || st_code==405) && 
     900            pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ALLOW, NULL)==NULL)  
     901        { 
     902            c_hdr = pjsip_endpt_get_capability(dlg->endpt, 
     903                                               PJSIP_H_ALLOW, NULL); 
     904            if (c_hdr) { 
     905                hdr = pjsip_hdr_clone(tdata->pool, c_hdr); 
     906                pjsip_msg_add_hdr(tdata->msg, hdr); 
     907            } 
     908        } 
     909 
     910        /* Add Supported header in 2xx response. */ 
     911        if (st_class==2 &&  
     912            pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL)==NULL)  
     913        { 
     914            c_hdr = pjsip_endpt_get_capability(dlg->endpt, 
     915                                               PJSIP_H_SUPPORTED, NULL); 
     916            if (c_hdr) { 
     917                hdr = pjsip_hdr_clone(tdata->pool, c_hdr); 
     918                pjsip_msg_add_hdr(tdata->msg, hdr); 
     919            } 
     920        } 
     921 
     922    } 
     923 
     924    /* Add To tag in all responses except 100 */ 
     925    if (st_code != 100) { 
     926        pjsip_to_hdr *to; 
     927 
     928        to = PJSIP_MSG_TO_HDR(tdata->msg); 
     929        pj_assert(to != NULL); 
     930 
     931        to->tag = dlg->local.info->tag; 
     932    } 
     933} 
     934 
    852935 
    853936/* 
     
    861944{ 
    862945    pj_status_t status; 
    863     pjsip_cseq_hdr *cseq; 
    864946    pjsip_tx_data *tdata; 
    865     int st_class; 
    866  
    867     /* Create generic response. */ 
     947 
     948    /* Create generic response. 
     949     * This will initialize response's Via, To, From, Call-ID, CSeq 
     950     * and Record-Route headers from the request. 
     951     */ 
    868952    status = pjsip_endpt_create_response(dlg->endpt, 
    869953                                         rdata, st_code, st_text, &tdata); 
     
    874958    pj_mutex_lock(dlg->mutex); 
    875959 
    876     /* Special treatment for 2xx response to request that establishes  
    877      * dialog.  
    878      * 
    879      * RFC 3261 Section 12.1.1 
    880      * 
    881      * When a UAS responds to a request with a response that establishes  
    882      * a dialog (such as a 2xx to INVITE): 
    883      * - MUST copy all Record-Route header field values from the request  
    884      *   into the response (including the URIs, URI parameters, and any  
    885      *   Record-Route header field parameters, whether they are known or 
    886      *   unknown to the UAS) and MUST maintain the order of those values. 
    887      * - The Contact header field contains an address where the UAS would 
    888      *   like to be contacted for subsequent requests in the dialog. 
    889      * 
    890      * Also from Table 3, page 119. 
    891      */ 
    892     cseq = PJSIP_MSG_CSEQ_HDR(tdata->msg); 
    893     pj_assert(cseq != NULL); 
    894  
    895     st_class = st_code / 100; 
    896  
    897     if (cseq->cseq == dlg->remote.first_cseq && 
    898         (st_class==1 || st_class==2) && st_code != 100) 
    899     { 
    900         pjsip_hdr *rr, *hdr; 
    901  
    902         /* Duplicate Record-Route header from the request. */ 
    903         rr = (pjsip_hdr*) rdata->msg_info.record_route; 
    904         while (rr) { 
    905             hdr = pjsip_hdr_clone(tdata->pool, rr); 
    906             pjsip_msg_add_hdr(tdata->msg, hdr); 
    907  
    908             rr = rr->next; 
    909             if (rr == &rdata->msg_info.msg->hdr) 
    910                 break; 
    911             rr = pjsip_msg_find_hdr(rdata->msg_info.msg,  
    912                                     PJSIP_H_RECORD_ROUTE, rr); 
    913         } 
    914     } 
    915  
    916     /* Contact header. */ 
    917     if (pjsip_method_creates_dialog(&cseq->method)) { 
    918         /* Add Contact header for 1xx, 2xx, 3xx and 485 response. */ 
    919         if (st_class==2 || st_class==3 || (st_class==1 && st_code != 100) || 
    920             st_code==485)  
    921         { 
    922             /* Add contact header. */ 
    923             pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, dlg->local.contact); 
    924             pjsip_msg_add_hdr(tdata->msg, hdr); 
    925         } 
    926  
    927         /* Add Allow header in 2xx and 405 response. */ 
    928         if (st_class==2 || st_code==405) { 
    929             const pjsip_hdr *c_hdr; 
    930             c_hdr = pjsip_endpt_get_capability(dlg->endpt, 
    931                                                PJSIP_H_ALLOW, NULL); 
    932             if (c_hdr) { 
    933                 pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr); 
    934                 pjsip_msg_add_hdr(tdata->msg, hdr); 
    935             } 
    936         } 
    937  
    938         /* Add Supported header in 2xx response. */ 
    939         if (st_class==2) { 
    940             const pjsip_hdr *c_hdr; 
    941             c_hdr = pjsip_endpt_get_capability(dlg->endpt, 
    942                                                PJSIP_H_SUPPORTED, NULL); 
    943             if (c_hdr) { 
    944                 pjsip_hdr *hdr = pjsip_hdr_clone(tdata->pool, c_hdr); 
    945                 pjsip_msg_add_hdr(tdata->msg, hdr); 
    946             } 
    947         } 
    948  
    949     } 
    950  
    951     /* Add To tag in all responses except 100 */ 
    952     if (st_code != 100 && rdata->msg_info.to->tag.slen == 0) { 
    953         pjsip_to_hdr *to; 
    954  
    955         to = PJSIP_MSG_TO_HDR(tdata->msg); 
    956         pj_assert(to != NULL); 
    957  
    958         to->tag = dlg->local.info->tag; 
    959     } 
     960    dlg_beautify_response(dlg, st_code, tdata); 
    960961 
    961962    /* Unlock the dialog. */ 
     
    981982    PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL); 
    982983 
     984    pj_mutex_lock(dlg->mutex); 
     985 
     986    /* Replace status code and reason */ 
    983987    tdata->msg->line.status.code = st_code; 
    984988    if (st_text) { 
     
    987991        tdata->msg->line.status.reason = *pjsip_get_status_text(st_code); 
    988992    } 
     993 
     994    dlg_beautify_response(dlg, st_code, tdata); 
     995 
     996 
     997    /* Must add reference counter, since tsx_send_msg() will decrement it */ 
     998    pjsip_tx_data_add_ref(tdata); 
     999 
     1000    /* Force to re-print message. */ 
     1001    pjsip_tx_data_invalidate_msg(tdata); 
     1002 
     1003    pj_mutex_unlock(dlg->mutex); 
    9891004 
    9901005    return PJ_SUCCESS; 
     
    10581073{ 
    10591074    pj_status_t status; 
    1060     pjsip_transaction *tsx; 
     1075    pjsip_transaction *tsx = NULL; 
    10611076    unsigned i; 
    10621077 
     
    10651080 
    10661081    /* Check CSeq */ 
    1067     if (rdata->msg_info.cseq->cseq <= dlg->remote.cseq) { 
     1082    if (rdata->msg_info.cseq->cseq <= dlg->remote.cseq && 
     1083        rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD && 
     1084        rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD)  
     1085    { 
    10681086        /* Invalid CSeq. 
    10691087         * Respond statelessly with 500 (Internal Server Error) 
    10701088         */ 
    10711089        pj_mutex_unlock(dlg->mutex); 
     1090        pj_assert(pjsip_rdata_get_tsx(rdata) == NULL); 
    10721091        pjsip_endpt_respond_stateless(dlg->endpt, 
    10731092                                      rdata, 500, NULL, NULL, NULL); 
     
    10791098 
    10801099    /* Create UAS transaction for this request. */ 
    1081     status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx); 
    1082     PJ_ASSERT_ON_FAIL(status==PJ_SUCCESS,{goto on_return;}); 
    1083  
    1084     /* Put this dialog in the transaction data. */ 
    1085     tsx->mod_data[dlg->ua->id] = dlg; 
    1086  
    1087     /* Add transaction count. */ 
    1088     ++dlg->tsx_count; 
     1100    if (pjsip_rdata_get_tsx(rdata) == NULL) { 
     1101        status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx); 
     1102        PJ_ASSERT_ON_FAIL(status==PJ_SUCCESS,{goto on_return;}); 
     1103 
     1104        /* Put this dialog in the transaction data. */ 
     1105        tsx->mod_data[dlg->ua->id] = dlg; 
     1106 
     1107        /* Add transaction count. */ 
     1108        ++dlg->tsx_count; 
     1109    } 
    10891110 
    10901111    /* Report the request to dialog usages. */ 
     
    11011122    } 
    11021123 
    1103     if (i==dlg->usage_cnt) { 
    1104         pjsip_tx_data *tdata; 
    1105  
    1106         PJ_LOG(4,(dlg->obj_name,  
    1107                   "%s is unhandled by dialog usages. " 
    1108                   "Dialog will response with 500 (Internal Server Error)", 
    1109                   pjsip_rx_data_get_info(rdata))); 
    1110         status = pjsip_endpt_create_response(dlg->endpt,  
    1111                                              rdata,  
    1112                                              PJSIP_SC_INTERNAL_SERVER_ERROR,  
    1113                                              NULL, &tdata); 
    1114         if (status == PJ_SUCCESS) 
    1115             status = pjsip_tsx_send_msg(tsx, tdata); 
    1116  
    1117         if (status != PJ_SUCCESS) { 
    1118             char errmsg[PJSIP_ERR_MSG_SIZE]; 
    1119             pj_strerror(status, errmsg, sizeof(errmsg)); 
    1120             PJ_LOG(4,(dlg->obj_name,"Error sending %s: %s", 
    1121                       pjsip_tx_data_get_info(tdata), errmsg)); 
    1122             pjsip_tsx_terminate(tsx, 500); 
    1123         } 
    1124     } 
     1124    /* Feed the first request to the transaction. */ 
     1125    if (tsx) 
     1126        pjsip_tsx_recv_msg(tsx, rdata); 
    11251127 
    11261128on_return: 
     
    11431145    pj_assert(pjsip_rdata_get_dlg(rdata) == dlg); 
    11441146 
    1145     /* Update the remote tag if it is different. */ 
    1146     if (pj_strcmp(&dlg->remote.info->tag, &rdata->msg_info.to->tag) != 0) { 
    1147  
    1148         pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag); 
    1149  
    1150         /* No need to update remote's tag_hval since its never used. */ 
    1151     } 
    1152  
    11531147    /* Keep the response's status code */ 
    11541148    res_code = rdata->msg_info.msg->line.status.code; 
    11551149 
    1156     /* When we receive response that establishes dialog, update the route 
    1157      * set and dialog target. 
    1158      */ 
    1159     if (!dlg->established &&  
     1150    /* When we receive response that establishes dialog, update To tag,  
     1151     * route set and dialog target. 
     1152     */ 
     1153    if (dlg->state == PJSIP_DIALOG_STATE_NULL &&  
    11601154        pjsip_method_creates_dialog(&rdata->msg_info.cseq->method) && 
    11611155        (res_code > 100 && res_code < 300) && 
    11621156        rdata->msg_info.to->tag.slen) 
    11631157    { 
     1158        pjsip_hdr *hdr, *end_hdr; 
     1159        pjsip_contact_hdr *contact; 
     1160 
     1161        /* Update To tag. */ 
     1162        pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag); 
     1163        /* No need to update remote's tag_hval since its never used. */ 
     1164 
     1165 
    11641166        /* RFC 3271 Section 12.1.2: 
    11651167         * The route set MUST be set to the list of URIs in the Record-Route 
     
    11701172         * route set for future requests in this dialog. 
    11711173         */ 
    1172         pjsip_hdr *hdr, *end_hdr; 
    1173         pjsip_contact_hdr *contact; 
    1174  
    11751174        pj_list_init(&dlg->route_set); 
    11761175 
     
    11951194        } 
    11961195 
    1197         dlg->established = 1; 
     1196        dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED; 
    11981197    } 
    11991198 
     
    12521251        --dlg->tsx_count; 
    12531252 
     1253    /* Increment session to prevent usages from destroying dialog. */ 
     1254    ++dlg->sess_count; 
     1255 
    12541256    /* Pass to dialog usages. */ 
    12551257    for (i=0; i<dlg->usage_cnt; ++i) { 
     
    12601262        (*dlg->usage[i]->on_tsx_state)(tsx, e); 
    12611263    } 
     1264 
     1265    /* Decrement temporary session. */ 
     1266    --dlg->sess_count; 
    12621267 
    12631268    if (tsx->state == PJSIP_TSX_STATE_TERMINATED && dlg->tsx_count == 0 &&  
  • pjproject/trunk/pjsip/src/pjsip/sip_transaction.c

    r152 r160  
    171171static int         tsx_send_msg( pjsip_transaction *tsx,  
    172172                                 pjsip_tx_data *tdata); 
    173 static void        tsx_on_rx_msg( pjsip_transaction *tsx, 
    174                                   pjsip_rx_data *rdata ); 
    175173 
    176174 
     
    698696    /* Race condition! 
    699697     * Transaction may gets deleted before we have chance to lock it 
    700      * in tsx_on_rx_msg(). 
     698     * in pjsip_tsx_recv_msg(). 
    701699     */ 
    702700    PJ_TODO(FIX_RACE_CONDITION_HERE); 
    703701 
    704702    /* Pass the message to the transaction. */ 
    705     tsx_on_rx_msg(tsx, rdata ); 
     703    pjsip_tsx_recv_msg(tsx, rdata ); 
    706704 
    707705    return PJ_TRUE; 
     
    746744    /* Race condition! 
    747745     * Transaction may gets deleted before we have chance to lock it 
    748      * in tsx_on_rx_msg(). 
     746     * in pjsip_tsx_recv_msg(). 
    749747     */ 
    750748    PJ_TODO(FIX_RACE_CONDITION_HERE); 
    751749 
    752750    /* Pass the message to the transaction. */ 
    753     tsx_on_rx_msg(tsx, rdata ); 
     751    pjsip_tsx_recv_msg(tsx, rdata ); 
    754752 
    755753    return PJ_TRUE; 
     
    966964        pj_assert(rdata != NULL); 
    967965 
    968         if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG && 
    969             tsx->tsx_user->on_rx_request) 
    970         { 
    971             (*tsx->tsx_user->on_rx_request)(rdata); 
    972  
    973         } else if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG && 
     966        if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG && 
    974967                   tsx->tsx_user->on_rx_response) 
    975968        { 
     
    12401233 
    12411234 
    1242     /* Begin with state TRYING. 
     1235    /* Begin with state NULL. 
    12431236     * Manually set-up the state becase we don't want to call the callback. 
    12441237     */ 
    1245     tsx->state = PJSIP_TSX_STATE_TRYING;  
    1246     tsx->state_handler = &tsx_on_state_trying; 
     1238    tsx->state = PJSIP_TSX_STATE_NULL;  
     1239    tsx->state_handler = &tsx_on_state_null; 
    12471240 
    12481241    /* Get response address. */ 
     
    13281321                             state_str[tsx->state])); 
    13291322 
    1330     PJSIP_EVENT_INIT_TX_MSG(event, tsx, tdata); 
     1323    PJSIP_EVENT_INIT_TX_MSG(event, tdata); 
    13311324 
    13321325    /* Dispatch to transaction. */ 
     
    13501343 * transaction is received. 
    13511344 */ 
    1352 static void tsx_on_rx_msg( pjsip_transaction *tsx, pjsip_rx_data *rdata) 
     1345PJ_DEF(void) pjsip_tsx_recv_msg( pjsip_transaction *tsx,  
     1346                                 pjsip_rx_data *rdata) 
    13531347{ 
    13541348    pjsip_event event; 
     
    13631357 
    13641358    /* Init event. */ 
    1365     PJSIP_EVENT_INIT_RX_MSG(event, tsx, rdata); 
     1359    PJSIP_EVENT_INIT_RX_MSG(event, rdata); 
    13661360 
    13671361    /* Dispatch to transaction. */ 
     
    17171711    if (tsx->role == PJSIP_ROLE_UAS) { 
    17181712 
    1719         /* UAS doesn't have STATE_NULL. 
    1720          * State has moved from NULL after transaction is initialized. 
    1721          */ 
    1722         pj_assert(!"Bug bug bug!!"); 
    1723         return PJ_EBUG; 
     1713        /* Set state to Trying. */ 
     1714        pj_assert(event->type == PJSIP_EVENT_RX_MSG && 
     1715                  event->body.rx_msg.rdata->msg_info.msg->type ==  
     1716                    PJSIP_REQUEST_MSG); 
     1717        tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, PJSIP_EVENT_RX_MSG, 
     1718                       event->body.rx_msg.rdata); 
    17241719 
    17251720    } else { 
  • pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c

    r145 r160  
    475475    pjsip_dialog *dlg; 
    476476 
    477     /* Optimized path: bail out early if request doesn't have To tag */ 
    478     if (rdata->msg_info.to->tag.slen == 0) 
     477    /* Optimized path: bail out early if request is not CANCEL and it doesn't 
     478     * have To tag  
     479     */ 
     480    if (rdata->msg_info.to->tag.slen == 0 &&  
     481        rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD) 
     482    { 
    479483        return PJ_FALSE; 
     484    } 
    480485 
    481486    /* Lock user agent before looking up the dialog hash table. */ 
     
    625630 
    626631    if (rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD) { 
    627         //pj_str_t *to_tag = &rdata->msg_info.to->tag; 
     632         
     633        int st_code = rdata->msg_info.msg->line.status.code; 
     634        pj_str_t *to_tag = &rdata->msg_info.to->tag; 
    628635 
    629636        /* Must hold UA mutex before accessing dialog set. */ 
     
    632639        dlg = dlg_set->dlg_list.next; 
    633640 
    634         /* Forking handling is temporarily disabled. */ 
    635         PJ_TODO(UA_LAYER_HANDLE_FORKING); 
    636  
    637 #if 0 
    638641        while (dlg != (pjsip_dialog*)&dlg_set->dlg_list) { 
    639642 
     
    653656 
    654657        /* If no dialog with matching remote tag is found, this must be 
    655          * a forked response. 
     658         * a forked response. Respond to this ONLY when response is non-100 
     659         * provisional response OR a 2xx response. 
    656660         */ 
    657         if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) { 
     661        if (dlg == (pjsip_dialog*)&dlg_set->dlg_list && 
     662            ((st_code/100==1 && st_code!=100) || st_code/100==2))  
     663        { 
    658664            /* Report to application about forked condition. 
    659665             * Application can either create a dialog or ignore the response. 
     
    678684                return PJ_TRUE; 
    679685            } 
     686 
     687        } else if (dlg == (pjsip_dialog*)&dlg_set->dlg_list) { 
     688 
     689            /* For 100 or non-2xx response which has different To tag, 
     690             * pass the response to the first dialog. 
     691             */ 
     692 
     693            dlg = dlg_set->dlg_list.next; 
     694 
    680695        } 
    681 #endif 
    682696 
    683697        /* Done with the dialog set. */ 
  • pjproject/trunk/pjsip/src/pjsip/sip_util.c

    r156 r160  
    13041304    } 
    13051305 
     1306    /* Feed the request to the transaction. */ 
     1307    pjsip_tsx_recv_msg(tsx, rdata); 
     1308 
    13061309    /* Send the message. */ 
    13071310    status = pjsip_tsx_send_msg(tsx, tdata); 
  • pjproject/trunk/pjsip/src/pjsua/main.c

    r147 r160  
    1919#include "pjsua.h" 
    2020#include "getopt.h" 
    21  
    22  
    23 /* For debugging, disable threading. */ 
    24 //#define NO_WORKER_THREAD 
    25  
    26 #ifdef NO_WORKER_THREAD 
    27 #include <conio.h> 
    28 #endif 
     21#include <stdlib.h> 
     22 
    2923 
    3024#define THIS_FILE       "main.c" 
     
    6963    puts("Console keys:"); 
    7064    puts("  m    Make a call"); 
     65    puts("  a    Answer incoming call"); 
    7166    puts("  h    Hangup current call"); 
    7267    puts("  q    Quit"); 
     
    7570} 
    7671 
     72static pj_bool_t input(const char *title, char *buf, pj_size_t len) 
     73{ 
     74    char *p; 
     75 
     76    printf("%s (empty to cancel): ", title); fflush(stdout); 
     77    fgets(buf, len, stdin); 
     78 
     79    /* Remove trailing newlines. */ 
     80    for (p=buf; ; ++p) { 
     81        if (*p=='\r' || *p=='\n') *p='\0'; 
     82        else if (!*p) break; 
     83    } 
     84 
     85    if (!*buf) 
     86        return PJ_FALSE; 
     87     
     88    return PJ_TRUE; 
     89} 
     90 
    7791static void ui_console_main(void) 
    7892{ 
    79     char keyin[10]; 
    8093    char buf[128]; 
    81     char *p; 
    8294    pjsip_inv_session *inv; 
    8395 
     
    8698    for (;;) { 
    8799 
    88 #ifdef NO_WORKER_THREAD 
    89         pj_time_val timeout = { 0, 10 }; 
    90         pjsip_endpt_handle_events (pjsua.endpt, &timeout); 
    91  
    92         if (kbhit()) 
    93             fgets(keyin, sizeof(keyin), stdin); 
    94 #else 
    95100        ui_help(); 
    96         fgets(keyin, sizeof(keyin), stdin); 
    97 #endif 
    98  
    99         switch (keyin[0]) { 
     101        fgets(buf, sizeof(buf), stdin); 
     102 
     103        switch (buf[0]) { 
    100104 
    101105        case 'm': 
     
    107111 
    108112#if 1 
    109             printf("Enter URL to call: "); fflush(stdout); 
    110             fgets(buf, sizeof(buf), stdin); 
    111  
    112             if (buf[0]=='\r' || buf[0]=='\n') { 
    113                 /* Cancelled. */ 
    114                 puts("<cancelled>"); 
     113            /* Make call! : */ 
     114            if (!input("Enter URL to call", buf, sizeof(buf))) 
     115                continue; 
     116            pjsua_invite(buf, &inv); 
     117 
     118#else 
     119 
     120            pjsua_invite("sip:localhost:5061", &inv); 
     121#endif 
     122            break; 
     123 
     124 
     125        case 'a': 
     126 
     127            if (inv_session == NULL || inv_session->role != PJSIP_ROLE_UAS || 
     128                inv_session->state >= PJSIP_INV_STATE_CONNECTING)  
     129            { 
     130                puts("No pending incoming call"); 
    115131                fflush(stdout); 
    116132                continue; 
    117             } 
    118  
    119             /* Remove trailing newlines. */ 
    120             for (p=buf; ; ++p) { 
    121                 if (*p=='\r' || *p=='\n') *p='\0'; 
    122                 else if (!*p) break; 
    123             } 
    124             /* Make call! : */ 
    125  
    126             pjsua_invite(buf, &inv); 
    127  
    128 #else 
    129  
    130             pjsua_invite("sip:localhost:5061", &inv); 
    131 #endif 
    132             break; 
    133  
     133 
     134            } else { 
     135                pj_status_t status; 
     136                pjsip_tx_data *tdata; 
     137 
     138                if (!input("Answer with code (100-699)", buf, sizeof(buf))) 
     139                    continue; 
     140                 
     141                status = pjsip_inv_answer(inv_session, atoi(buf), NULL, NULL,  
     142                                          &tdata); 
     143                if (status == PJ_SUCCESS) 
     144                    status = pjsip_inv_send_msg(inv_session, tdata, NULL); 
     145 
     146                if (status != PJ_SUCCESS) 
     147                    pjsua_perror("Unable to create/send response", status); 
     148            } 
     149 
     150            break; 
    134151 
    135152        case 'h': 
     
    673690 
    674691 
    675 #ifdef NO_WORKER_THREAD 
    676     pjsua.thread_cnt = 0; 
    677 #endif 
    678  
    679  
    680692    /* Initialize pjsua (to create pool etc). 
    681693     */ 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_core.c

    r147 r160  
    102102static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata) 
    103103{ 
    104     PJ_UNUSED_ARG(rdata); 
    105     PJ_TODO(IMPLEMENT_UAS); 
     104    pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata); 
     105    pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); 
     106    pjsip_msg *msg = rdata->msg_info.msg; 
     107 
     108    /* 
     109     * Handle incoming INVITE outside dialog. 
     110     */ 
     111    if (dlg == NULL && tsx == NULL && 
     112        msg->line.req.method.id == PJSIP_INVITE_METHOD) 
     113    { 
     114        pj_status_t status; 
     115        pjsip_tx_data *response = NULL; 
     116        unsigned options = 0; 
     117 
     118        /* Verify that we can handle the request. */ 
     119        status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, 
     120                                          pjsua.endpt, &response); 
     121        if (status != PJ_SUCCESS) { 
     122 
     123            /* 
     124             * No we can't handle the incoming INVITE request. 
     125             */ 
     126 
     127            if (response) { 
     128                pjsip_response_addr res_addr; 
     129 
     130                pjsip_get_response_addr(response->pool, rdata, &res_addr); 
     131                pjsip_endpt_send_response(pjsua.endpt, &res_addr, response,  
     132                                          NULL, NULL); 
     133 
     134            } else { 
     135 
     136                /* Respond with 500 (Internal Server Error) */ 
     137                pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
     138                                              NULL, NULL); 
     139            } 
     140 
     141        } else { 
     142            /* 
     143             * Yes we can handle the incoming INVITE request. 
     144             */ 
     145            pjsip_inv_session *inv; 
     146            pjmedia_sdp_session *answer; 
     147 
     148            /* Create dummy SDP answer: */ 
     149 
     150 
     151            status = pjmedia_sdp_parse(pjsua.pool, PJSUA_DUMMY_SDP_ANSWER, 
     152                                       pj_native_strlen(PJSUA_DUMMY_SDP_ANSWER), 
     153                                       &answer); 
     154            if (status != PJ_SUCCESS) { 
     155 
     156                pjsip_endpt_respond_stateless(pjsua.endpt, rdata, 500, NULL, 
     157                                              NULL, NULL); 
     158                return PJ_TRUE; 
     159            } 
     160 
     161            /* Create dialog: */ 
     162 
     163            status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, 
     164                                           &pjsua.contact_uri, &dlg); 
     165            if (status != PJ_SUCCESS) 
     166                return PJ_TRUE; 
     167 
     168 
     169            /* Create invite session: */ 
     170 
     171            status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &inv); 
     172            if (status != PJ_SUCCESS) { 
     173 
     174                status = pjsip_dlg_create_response( dlg, rdata, 500, NULL, 
     175                                                    &response); 
     176                if (status == PJ_SUCCESS) 
     177                    status = pjsip_dlg_send_response(dlg,  
     178                                                     pjsip_rdata_get_tsx(rdata), 
     179                                                     response); 
     180                return PJ_TRUE; 
     181 
     182            } 
     183 
     184            /* Answer with 100 (using the dialog, not invite): */ 
     185 
     186            status = pjsip_dlg_create_response(dlg, rdata, 100, NULL, &response); 
     187            if (status == PJ_SUCCESS) 
     188                status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), response); 
     189        } 
     190 
     191        /* This INVITE request has been handled. */ 
     192        return PJ_TRUE; 
     193    } 
     194 
     195     
     196 
    106197    return PJ_FALSE; 
    107198} 
     
    122213{ 
    123214    PJ_UNUSED_ARG(rdata); 
    124     PJ_TODO(IMPLEMENT_UAS); 
    125215    return PJ_FALSE; 
    126216} 
  • pjproject/trunk/pjsip/src/test-pjsip/tsx_uas_test.c

    r127 r160  
    710710                return PJ_TRUE; 
    711711            } 
     712            pjsip_tsx_recv_msg(tsx, rdata); 
    712713 
    713714            save_key(tsx); 
     
    750751                return PJ_TRUE; 
    751752            } 
     753            pjsip_tsx_recv_msg(tsx, rdata); 
    752754 
    753755            save_key(tsx); 
     
    802804            } 
    803805 
     806            pjsip_tsx_recv_msg(tsx, rdata); 
    804807            save_key(tsx); 
    805808 
     
    883886            } 
    884887 
     888            pjsip_tsx_recv_msg(tsx, rdata); 
    885889            save_key(tsx); 
    886890 
     
    967971            } 
    968972 
     973            pjsip_tsx_recv_msg(tsx, rdata); 
    969974            save_key(tsx); 
    970975            send_response(rdata, tsx, TEST9_STATUS_CODE); 
     
    10771082            } 
    10781083 
     1084            pjsip_tsx_recv_msg(tsx, rdata); 
    10791085            save_key(tsx); 
    10801086             
Note: See TracChangeset for help on using the changeset viewer.