📄 evsub.c
字号:
return; } /* Only interested in final response */ if (tsx->state != PJSIP_TSX_STATE_COMPLETED && tsx->state != PJSIP_TSX_STATE_TERMINATED) { return; } /* Clear pending subscription */ if (tsx == sub->pending_sub) sub->pending_sub = NULL; /* Handle authentication. */ if (tsx->status_code==401 || tsx->status_code==407) { pjsip_tx_data *tdata; pj_status_t status; if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { /* Previously failed transaction has terminated */ return; } status = pjsip_auth_clt_reinit_req(&sub->dlg->auth_sess, event->body.tsx_state.src.rdata, tsx->last_tx, &tdata); if (status == PJ_SUCCESS) status = pjsip_dlg_send_request(sub->dlg, tdata, -1, NULL); if (status != PJ_SUCCESS) { /* Authentication failed! */ set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event); return; } return; } if (tsx->status_code/100 == 2) { /* Successfull SUBSCRIBE request! * This could be: * - response to initial SUBSCRIBE request * - response to subsequent refresh * - response to unsubscription */ if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { /* Ignore; this transaction has been processed before */ return; } /* Update UAC refresh time, if response contains Expires header, * only when we're not unsubscribing. */ if (sub->expires->ivalue != 0) { pjsip_msg *msg; pjsip_expires_hdr *expires; msg = event->body.tsx_state.src.rdata->msg_info.msg; expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL); if (expires) { sub->expires->ivalue = expires->ivalue; } } /* Update time */ update_expires(sub, sub->expires->ivalue); /* Start UAC refresh timer, only when we're not unsubscribing */ if (sub->expires->ivalue != 0) { unsigned timeout = (sub->expires->ivalue > TIME_UAC_REFRESH) ? sub->expires->ivalue - TIME_UAC_REFRESH : sub->expires->ivalue; PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds", timeout)); set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout); } else { /* Otherwise set timer to terminate client subscription when * NOTIFY to end subscription is not received. */ set_timer(sub, TIMER_TYPE_UAC_TERMINATE, TIME_UAC_TERMINATE); } /* Set state, if necessary */ pj_assert(sub->state != PJSIP_EVSUB_STATE_NULL); if (sub->state == PJSIP_EVSUB_STATE_SENT) { set_state(sub, PJSIP_EVSUB_STATE_ACCEPTED, NULL, event); } } else { /* Failed SUBSCRIBE request! * * The RFC 3265 says that if outgoing SUBSCRIBE fails with status * other than 481, the subscription is still considered valid for * the duration of the last Expires. * * Since we send refresh about 5 seconds (TIME_UAC_REFRESH) before * expiration, theoritically the expiration is still valid for the * next 5 seconds even when we receive non-481 failed response. * * Ah, what the heck! * * Just terminate now! * */ if (sub->state == PJSIP_EVSUB_STATE_TERMINATED) { /* Ignore, has been handled before */ return; } /* Ignore 490 (Request Updated) status. * This happens when application sends SUBSCRIBE/REFER while * another one is still in progress. */ if (tsx->status_code == PJSIP_SC_REQUEST_UPDATED) { return; } /* Kill any timer. */ set_timer(sub, TIMER_TYPE_NONE, 0); /* Set state to TERMINATED */ set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event); } } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) { /* Incoming NOTIFY. * This can be the result of: * - Initial subscription response * - UAS updating the resource info. * - Unsubscription response. */ int st_code = 200; pj_str_t *st_text = NULL; pjsip_hdr res_hdr; pjsip_msg_body *body = NULL; pjsip_rx_data *rdata; pjsip_msg *msg; pjsip_sub_state_hdr *sub_state; pjsip_evsub_state new_state; pj_str_t *new_state_str; pjsip_tx_data *tdata; pj_status_t status; int next_refresh; /* Only want to handle initial NOTIFY receive event. */ if (tsx->state != PJSIP_TSX_STATE_TRYING) return; rdata = event->body.tsx_state.src.rdata; msg = rdata->msg_info.msg; pj_list_init(&res_hdr); /* Get subscription state header. */ sub_state = pjsip_msg_find_hdr_by_name(msg, &STR_SUB_STATE, NULL); if (sub_state == NULL) { pjsip_warning_hdr *warn_hdr; pj_str_t warn_text = { "Missing Subscription-State header", 33}; /* Bad request! Add warning header. */ st_code = PJSIP_SC_BAD_REQUEST; warn_hdr = pjsip_warning_hdr_create(rdata->tp_info.pool, 399, pjsip_endpt_name(sub->endpt), &warn_text); pj_list_push_back(&res_hdr, warn_hdr); } /* Call application registered callback to handle incoming NOTIFY, * if any. */ if (st_code==200 && sub->user.on_rx_notify && sub->call_cb) { (*sub->user.on_rx_notify)(sub, rdata, &st_code, &st_text, &res_hdr, &body); /* Application MUST specify final response! */ PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; }); /* Must be a valid status code */ PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; }); } /* If non-2xx should be returned, then send the response. * No need to update server subscription state. */ if (st_code >= 300) { status = create_response(sub, rdata, st_code, st_text, &res_hdr, body, &tdata); if (status == PJ_SUCCESS) { status = pjsip_dlg_send_response(sub->dlg, tsx, tdata); } /* Start timer to terminate subscription, just in case server * is not able to generate NOTIFY to our response. */ if (status == PJ_SUCCESS) { unsigned timeout = TIME_UAC_WAIT_NOTIFY; set_timer(sub, TIMER_TYPE_UAC_WAIT_NOTIFY, timeout); } else { set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); } return; } /* Update expiration from the value of expires param in * Subscription-State header, but ONLY when subscription state * is "active" or "pending", AND the header contains expires param. */ if (sub->expires->ivalue != 0 && sub_state->expires_param >= 0 && (pj_stricmp(&sub_state->sub_state, &STR_ACTIVE)==0 || pj_stricmp(&sub_state->sub_state, &STR_PENDING)==0)) { next_refresh = sub_state->expires_param; } else { next_refresh = sub->expires->ivalue; } /* Update time */ update_expires(sub, next_refresh); /* Start UAC refresh timer, only when we're not unsubscribing */ if (sub->expires->ivalue != 0) { unsigned timeout = (next_refresh > TIME_UAC_REFRESH) ? next_refresh - TIME_UAC_REFRESH : next_refresh; PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds", timeout)); set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout); } /* Find out the state */ get_hdr_state(sub_state, &new_state, &new_state_str); /* Send response. */ status = create_response(sub, rdata, st_code, st_text, &res_hdr, body, &tdata); if (status == PJ_SUCCESS) status = pjsip_dlg_send_response(sub->dlg, tsx, tdata); /* Set the state */ if (status == PJ_SUCCESS) { set_state(sub, new_state, new_state_str, event); } else { set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event); } } else { /* * Unexpected method! */ PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s", (int)tsx->method.name.slen, tsx->method.name.ptr)); }}/* * Transaction event processing by UAS, after subscription is accepted. */static void on_tsx_state_uas( pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event){ if (pjsip_method_cmp(&tsx->method, &sub->method) == 0 || pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0) { /* * Incoming request (e.g. SUBSCRIBE or REFER) to refresh subsciption. * */ pjsip_rx_data *rdata; pjsip_event_hdr *event_hdr; pjsip_expires_hdr *expires; pjsip_msg *msg; pjsip_tx_data *tdata; int st_code = 200; pj_str_t *st_text = NULL; pjsip_hdr res_hdr; pjsip_msg_body *body = NULL; pjsip_evsub_state old_state; pj_str_t old_state_str; pj_status_t status; /* Only wants to handle the first event when the request is * received. */ if (tsx->state != PJSIP_TSX_STATE_TRYING) return; rdata = event->body.tsx_state.src.rdata; msg = rdata->msg_info.msg; /* Set expiration time based on client request (in Expires header), * or package default expiration time. */ event_hdr = pjsip_msg_find_hdr_by_name(msg, &STR_EVENT, NULL); expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL); if (event_hdr && expires) { struct evpkg *evpkg; evpkg = find_pkg(&event_hdr->event_type); if (evpkg) { if (expires->ivalue < (pj_int32_t)evpkg->pkg_expires) sub->expires->ivalue = expires->ivalue; else sub->expires->ivalue = evpkg->pkg_expires; } } /* Update time (before calling on_rx_refresh, since application * will send NOTIFY. */ update_expires(sub, sub->expires->ivalue); /* Save old state. * If application respond with non-2xx, revert to old state. */ old_state = sub->state; old_state_str = sub->state_str; if (sub->expires->ivalue == 0) { sub->state = PJSIP_EVSUB_STATE_TERMINATED; sub->state_str = evsub_state_names[sub->state]; } else if (sub->state == PJSIP_EVSUB_STATE_NULL) { sub->state = PJSIP_EVSUB_STATE_ACCEPTED; sub->state_str = evsub_state_names[sub->state]; } /* Call application's on_rx_refresh, just in case it wants to send * response other than 200 (OK) */ pj_list_init(&res_hdr); if (sub->user.on_rx_refresh && sub->call_cb) { (*sub->user.on_rx_refresh)(sub, rdata, &st_code, &st_text, &res_hdr, &body); } /* Application MUST specify final response! */ PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; }); /* Must be a valid status code */ PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; }); /* Create and send response */ status = create_response(sub, rdata, st_code, st_text, &res_hdr, body, &tdata); if (status == PJ_SUCCESS) { /* Add expires header: */ pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->expires)); /* Send */ status = pjsip_dlg_send_response(sub->dlg, tsx, tdata); } /* Update state or revert state */ if (st_code/100==2) { if (sub->expires->ivalue == 0) { set_state(sub, sub->state, NULL, event); } else if (sub->state == PJSIP_EVSUB_STATE_NULL) { set_state(sub, sub->state, NULL, event); } /* Set UAS timeout timer, when state is not terminated. */ if (sub->state != PJSIP_EVSUB_STATE_TERMINATED) { PJ_LOG(5,(sub->obj_name, "UAS timeout in %d seconds", sub->expires->ivalue)); set_timer(sub, TIMER_TYPE_UAS_TIMEOUT, sub->expires->ivalue); } } else { sub->state = old_state; sub->state_str = old_state_str; } } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method)==0) { /* Handle authentication */ if (tsx->state == PJSIP_TSX_STATE_COMPLETED && (tsx->status_code==401 || tsx->status_code==407)) { pjsip_rx_data *rdata = event->body.tsx_state.src.rdata; pjsip_tx_data *tdata; pj_status_t status; status = pjsip_auth_clt_reinit_req( &sub->dlg->auth_sess, rdata, tsx->last_tx, &tdata); if (status == PJ_SUCCESS) status = pjsip_dlg_send_request( sub->dlg, tdata, -1, NULL ); if (status != PJ_SUCCESS) { /* Can't authenticate. Terminate session (?) */ set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); return; } } /* * Terminate event usage if we receive 481, 408, and 7 class * responses. */ if (sub->state != PJSIP_EVSUB_STATE_TERMINATED && (tsx->status_code==481 || tsx->status_code==408 || tsx->status_code/100 == 7)) { set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event); return; } } else { /* * Unexpected method! */ PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s", (int)tsx->method.name.slen, tsx->method.name.ptr)); }}/* * Notification when transaction state has changed! */static void mod_evsub_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event){ pjsip_evsub *sub = pjsip_tsx_get_evsub(tsx); if (sub == NULL) { sub = on_new_transaction(tsx, event); if (sub == NULL) return; } /* Call on_tsx_state callback, if any. */ if (sub->user.on_tsx_state && sub->call_cb) (*sub->user.on_tsx_state)(sub, tsx, event); /* Process the event: */ if (sub->role == PJSIP_ROLE_UAC) { on_tsx_state_uac(sub, tsx, event); } else { on_tsx_state_uas(sub, tsx, event); } /* Check transaction TERMINATE event */ if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { --sub->pending_tsx; if (sub->state == PJSIP_EVSUB_STATE_TERMINATED && sub->pending_tsx == 0) { evsub_destroy(sub); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -