/* Handler when response is received. */ static pj_bool_t mod_test_on_rx_response(pjsip_rx_data *rdata) { if (pjsip_rdata_get_tsx(rdata) == NULL) { report_completion(rdata->msg_info.msg->line.status.code); } return PJ_TRUE; }
static void send_response(struct ast_sip_session *session, int code, struct pjsip_rx_data *rdata) { pjsip_tx_data *tdata; if (pjsip_dlg_create_response(session->inv_session->dlg, rdata, code, NULL, &tdata) == PJ_SUCCESS) { struct pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); pjsip_dlg_send_response(session->inv_session->dlg, tsx, tdata); } }
static pj_status_t send_options_response(pjsip_rx_data *rdata, int code) { pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata); pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata); pjsip_tx_data *tdata; const pjsip_hdr *hdr; pj_status_t status; /* Make the response object */ status = ast_sip_create_response(rdata, code, NULL, &tdata); if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to create response (%d)\n", status); return status; } /* Add appropriate headers */ if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } /* * XXX TODO: pjsip doesn't care a lot about either of these headers - * while it provides specific methods to create them, they are defined * to be the standard string header creation. We never did add them * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here. */ ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING); ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE); if (dlg && trans) { status = pjsip_dlg_send_response(dlg, trans, tdata); } else { struct ast_sip_endpoint *endpoint; endpoint = ast_pjsip_rdata_get_endpoint(rdata); status = ast_sip_send_stateful_response(rdata, tdata, endpoint); ao2_cleanup(endpoint); } if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send response (%d)\n", status); } return status; }
static int options_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata) { pjsip_tx_data *tdata; pj_status_t status; const pjsip_hdr *hdr; pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); status = pjsip_dlg_create_response(session->inv_session->dlg, rdata, 200, NULL,&tdata); if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to create response (%d)\n", status); return status; } /* Add appropriate headers */ if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } /* * XXX TODO: pjsip doesn't care a lot about either of these headers - * while it provides specific methods to create them, they are defined * to be the standard string header creation. We never did add them * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here. */ ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING); ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE); status = pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata); if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send response (%d)\n", status); } return status; }
static pj_bool_t outbound_auth(pjsip_rx_data *rdata) { RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); pjsip_transaction *tsx; pjsip_dialog *dlg; struct outbound_auth_cb_data *cb_data; pjsip_tx_data *tdata; if (rdata->msg_info.msg->line.status.code != 401 && rdata->msg_info.msg->line.status.code != 407) { /* Doesn't pertain to us. Move on */ return PJ_FALSE; } tsx = pjsip_rdata_get_tsx(rdata); dlg = pjsip_rdata_get_dlg(rdata); if (!dlg || !tsx) { return PJ_FALSE; } endpoint = ast_sip_dialog_get_endpoint(dlg); if (!endpoint) { return PJ_FALSE; } if (ast_sip_create_request_with_auth(&endpoint->outbound_auths, rdata, tsx, &tdata)) { return PJ_FALSE; } cb_data = dlg->mod_data[outbound_auth_mod.id]; if (cb_data) { cb_data->cb(dlg, tdata, cb_data->user_data); return PJ_TRUE; } pjsip_dlg_send_request(dlg, tdata, -1, NULL); return PJ_TRUE; }
/* * Create PRACK request for the incoming reliable provisional response. */ PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv, pjsip_rx_data *rdata, pjsip_tx_data **p_tdata) { dlg_data *dd; uac_state_t *uac_state = NULL; const pj_str_t *to_tag = &rdata->msg_info.to->tag; pjsip_transaction *tsx; pjsip_msg *msg; pjsip_generic_string_hdr *rseq_hdr; pjsip_generic_string_hdr *rack_hdr; unsigned rseq; pj_str_t rack; char rack_buf[80]; pjsip_tx_data *tdata; pj_status_t status; *p_tdata = NULL; dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED); tsx = pjsip_rdata_get_tsx(rdata); msg = rdata->msg_info.msg; /* Check our assumptions */ pj_assert( tsx->role == PJSIP_ROLE_UAC && tsx->method.id == PJSIP_INVITE_METHOD && msg->line.status.code > 100 && msg->line.status.code < 200); /* Get the RSeq header */ rseq_hdr = (pjsip_generic_string_hdr*) pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL); if (rseq_hdr == NULL) { PJ_LOG(4,(dd->inv->dlg->obj_name, "Ignoring 100rel response with no RSeq header")); return PJSIP_EMISSINGHDR; } rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue); /* Find UAC state for the specified call leg */ uac_state = dd->uac_state_list; while (uac_state) { if (pj_stricmp(&uac_state->tag, to_tag)==0) break; uac_state = uac_state->next; } /* Create new UAC state if we don't have one */ if (uac_state == NULL) { uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool, uac_state_t); uac_state->cseq = rdata->msg_info.cseq->cseq; uac_state->rseq = rseq - 1; pj_strdup(dd->inv->dlg->pool, &uac_state->tag, to_tag); uac_state->next = dd->uac_state_list; dd->uac_state_list = uac_state; } /* If this is from new INVITE transaction, reset UAC state. */ if (rdata->msg_info.cseq->cseq != uac_state->cseq) { uac_state->cseq = rdata->msg_info.cseq->cseq; uac_state->rseq = rseq - 1; } /* Ignore provisional response retransmission */ if (rseq <= uac_state->rseq) { /* This should have been handled before */ return PJ_EIGNORED; /* Ignore provisional response with out-of-order RSeq */ } else if (rseq != uac_state->rseq + 1) { PJ_LOG(4,(dd->inv->dlg->obj_name, "Ignoring 100rel response because RSeq jump " "(expecting %u, got %u)", uac_state->rseq+1, rseq)); return PJ_EIGNORED; } /* Update our RSeq */ uac_state->rseq = rseq; /* Create PRACK */ status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method, -1, &tdata); if (status != PJ_SUCCESS) return status; /* If this response is a forked response from a different call-leg, * update the req URI (https://trac.pjsip.org/repos/ticket/1364) */ if (pj_stricmp(&uac_state->tag, &dd->inv->dlg->remote.info->tag)) { const pjsip_contact_hdr *mhdr; mhdr = (const pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); if (!mhdr || !mhdr->uri) { PJ_LOG(4,(dd->inv->dlg->obj_name, "Ignoring 100rel response with no or " "invalid Contact header")); pjsip_tx_data_dec_ref(tdata); return PJ_EIGNORED; } tdata->msg->line.req.uri = (pjsip_uri*) pjsip_uri_clone(tdata->pool, mhdr->uri); } /* Create RAck header */ rack.ptr = rack_buf; rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf), "%u %u %.*s", rseq, rdata->msg_info.cseq->cseq, (int)tsx->method.name.slen, tsx->method.name.ptr); if (rack.slen < 1 || rack.slen >= (int)sizeof(rack_buf)) { return PJ_ETOOSMALL; } rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr); /* Done */ *p_tdata = tdata; return PJ_SUCCESS; }
/* * Handler to receive incoming MESSAGE */ static pj_bool_t im_on_rx_request(pjsip_rx_data *rdata) { pj_str_t from, to; pjsip_accept_hdr *accept_hdr; pjsip_msg *msg; msg = rdata->msg_info.msg; /* Only want to handle MESSAGE requests. */ if (pjsip_method_cmp(&msg->line.req.method, &pjsip_message_method) != 0) { return PJ_FALSE; } /* Should not have any transaction attached to rdata. */ PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata)==NULL, PJ_FALSE); /* Should not have any dialog attached to rdata. */ PJ_ASSERT_RETURN(pjsip_rdata_get_dlg(rdata)==NULL, PJ_FALSE); /* Check if we can accept the message. */ if (!pjsua_im_accept_pager(rdata, &accept_hdr)) { pjsip_hdr hdr_list; pj_list_init(&hdr_list); pj_list_push_back(&hdr_list, accept_hdr); pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, PJSIP_SC_NOT_ACCEPTABLE_HERE, NULL, &hdr_list, NULL); return PJ_TRUE; } /* Respond with 200 first, so that remote doesn't retransmit in case * the UI takes too long to process the message. */ pjsip_endpt_respond( pjsua_var.endpt, NULL, rdata, 200, NULL, NULL, NULL, NULL); /* For the source URI, we use Contact header if present, since * Contact header contains the port number information. If this is * not available, then use From header. */ from.ptr = (char*)pj_pool_alloc(rdata->tp_info.pool, PJSIP_MAX_URL_SIZE); from.slen = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->msg_info.from->uri, from.ptr, PJSIP_MAX_URL_SIZE); if (from.slen < 1) from = pj_str("<--URI is too long-->"); /* Build the To text. */ to.ptr = (char*) pj_pool_alloc(rdata->tp_info.pool, PJSIP_MAX_URL_SIZE); to.slen = pjsip_uri_print( PJSIP_URI_IN_FROMTO_HDR, rdata->msg_info.to->uri, to.ptr, PJSIP_MAX_URL_SIZE); if (to.slen < 1) to = pj_str("<--URI is too long-->"); /* Process pager. */ pjsua_im_process_pager(-1, &from, &to, rdata); /* Done. */ return PJ_TRUE; }
static int msg_send(void *data) { RAII_VAR(struct msg_data *, mdata, data, ao2_cleanup); const struct ast_sip_body body = { .type = "text", .subtype = "plain", .body_text = ast_msg_get_body(mdata->msg) }; pjsip_tx_data *tdata; RAII_VAR(char *, uri, NULL, ast_free); RAII_VAR(struct ast_sip_endpoint *, endpoint, get_outbound_endpoint( mdata->to, &uri), ao2_cleanup); if (!endpoint) { ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not find endpoint '%s' and " "no default outbound endpoint configured\n", mdata->to); return -1; } if (ast_sip_create_request("MESSAGE", NULL, endpoint, uri, NULL, &tdata)) { ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not create request\n"); return -1; } update_to(tdata, mdata->to); update_from(tdata, mdata->from); if (ast_sip_add_body(tdata, &body)) { pjsip_tx_data_dec_ref(tdata); ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not add body to request\n"); return -1; } vars_to_headers(mdata->msg, tdata); ast_debug(1, "Sending message to '%s' (via endpoint %s) from '%s'\n", mdata->to, ast_sorcery_object_get_id(endpoint), mdata->from); if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) { ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not send request\n"); return -1; } return PJ_SUCCESS; } static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *from) { struct msg_data *mdata; if (ast_strlen_zero(to)) { ast_log(LOG_ERROR, "SIP MESSAGE - a 'To' URI must be specified\n"); return -1; } if (!(mdata = msg_data_create(msg, to, from)) || ast_sip_push_task(message_serializer, msg_send, mdata)) { ao2_ref(mdata, -1); return -1; } return 0; } static const struct ast_msg_tech msg_tech = { .name = "pjsip", .msg_send = sip_msg_send, }; static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code code, pjsip_dialog *dlg, pjsip_transaction *tsx) { pjsip_tx_data *tdata; pj_status_t status; status = ast_sip_create_response(rdata, code, NULL, &tdata); if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to create response (%d)\n", status); return status; } if (dlg && tsx) { status = pjsip_dlg_send_response(dlg, tsx, tdata); } else { struct ast_sip_endpoint *endpoint; endpoint = ast_pjsip_rdata_get_endpoint(rdata); status = ast_sip_send_stateful_response(rdata, tdata, endpoint); ao2_cleanup(endpoint); } if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send response (%d)\n", status); } return status; } static pj_bool_t module_on_rx_request(pjsip_rx_data *rdata) { enum pjsip_status_code code; struct ast_msg *msg; /* if not a MESSAGE, don't handle */ if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_message_method)) { return PJ_FALSE; } code = check_content_type(rdata); if (code != PJSIP_SC_OK) { send_response(rdata, code, NULL, NULL); return PJ_TRUE; } msg = ast_msg_alloc(); if (!msg) { send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL); return PJ_TRUE; } code = rx_data_to_ast_msg(rdata, msg); if (code != PJSIP_SC_OK) { send_response(rdata, code, NULL, NULL); ast_msg_destroy(msg); return PJ_TRUE; } if (!ast_msg_has_destination(msg)) { ast_debug(1, "MESSAGE request received, but no handler wanted it\n"); send_response(rdata, PJSIP_SC_NOT_FOUND, NULL, NULL); ast_msg_destroy(msg); return PJ_TRUE; } /* Send it to the messaging core. * * If we are unable to send a response, the most likely reason is that we * are handling a retransmission of an incoming MESSAGE and were unable to * create a transaction due to a duplicate key. If we are unable to send * a response, we should not queue the message to the dialplan */ if (!send_response(rdata, PJSIP_SC_ACCEPTED, NULL, NULL)) { ast_msg_queue(msg); } return PJ_TRUE; } static int incoming_in_dialog_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata) { char buf[MAX_BODY_SIZE]; enum pjsip_status_code code; struct ast_frame f; pjsip_dialog *dlg = session->inv_session->dlg; pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); if (!session->channel) { send_response(rdata, PJSIP_SC_NOT_FOUND, dlg, tsx); return 0; } if ((code = check_content_type(rdata)) != PJSIP_SC_OK) { send_response(rdata, code, dlg, tsx); return 0; } if (print_body(rdata, buf, sizeof(buf)-1) < 1) { /* invalid body size */ send_response(rdata, PJSIP_SC_REQUEST_ENTITY_TOO_LARGE, dlg, tsx); return 0; } ast_debug(3, "Received in dialog SIP message\n"); memset(&f, 0, sizeof(f)); f.frametype = AST_FRAME_TEXT; f.subclass.integer = 0; f.offset = 0; f.data.ptr = buf; f.datalen = strlen(buf) + 1; ast_queue_frame(session->channel, &f); send_response(rdata, PJSIP_SC_ACCEPTED, dlg, tsx); return 0; }
/* This is called when request is received. * We need to check for incoming SUBSCRIBE request. */ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata) { int acc_id; pjsua_acc *acc; pj_str_t contact; pjsip_method *req_method = &rdata->msg_info.msg->line.req.method; pjsua_srv_pres *uapres; pjsip_evsub *sub; pjsip_evsub_user pres_cb; pjsip_dialog *dlg; pjsip_status_code st_code; pj_str_t reason; pjsip_expires_hdr *expires_hdr; pjsua_msg_data msg_data; pj_status_t status; if (pjsip_method_cmp(req_method, pjsip_get_subscribe_method()) != 0) return PJ_FALSE; /* Incoming SUBSCRIBE: */ PJSUA_LOCK(); /* Find which account for the incoming request. */ acc_id = pjsua_acc_find_for_incoming(rdata); acc = &pjsua_var.acc[acc_id]; PJ_LOG(4,(THIS_FILE, "Creating server subscription, using account %d", acc_id)); /* Create suitable Contact header */ if (acc->contact.slen) { contact = acc->contact; } else { status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact, acc_id, rdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); PJSUA_UNLOCK(); pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 400, NULL, NULL, NULL); return PJ_TRUE; } } /* Create UAS dialog: */ status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create UAS dialog for subscription", status); PJSUA_UNLOCK(); pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 400, NULL, NULL, NULL); return PJ_TRUE; } /* Set credentials and preference. */ pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->cred_cnt, acc->cred); pjsip_auth_clt_set_prefs(&dlg->auth_sess, &acc->cfg.auth_pref); /* Init callback: */ pj_bzero(&pres_cb, sizeof(pres_cb)); pres_cb.on_evsub_state = &pres_evsub_on_srv_state; /* Create server presence subscription: */ status = pjsip_pres_create_uas( dlg, &pres_cb, rdata, &sub); if (status != PJ_SUCCESS) { int code = PJSIP_ERRNO_TO_SIP_STATUS(status); pjsip_tx_data *tdata; pjsua_perror(THIS_FILE, "Unable to create server subscription", status); if (code==599 || code > 699 || code < 300) { code = 400; } status = pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata); if (status == PJ_SUCCESS) { status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); } PJSUA_UNLOCK(); return PJ_TRUE; } /* If account is locked to specific transport, then lock dialog * to this transport too. */ if (acc->cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); pjsip_dlg_set_transport(dlg, &tp_sel); } /* Attach our data to the subscription: */ uapres = PJ_POOL_ALLOC_T(dlg->pool, pjsua_srv_pres); uapres->sub = sub; uapres->remote = (char*) pj_pool_alloc(dlg->pool, PJSIP_MAX_URL_SIZE); uapres->acc_id = acc_id; uapres->dlg = dlg; status = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->remote.info->uri, uapres->remote, PJSIP_MAX_URL_SIZE); if (status < 1) pj_ansi_strcpy(uapres->remote, "<-- url is too long-->"); else uapres->remote[status] = '\0'; pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, uapres); /* Add server subscription to the list: */ pj_list_push_back(&pjsua_var.acc[acc_id].pres_srv_list, uapres); /* Capture the value of Expires header. */ expires_hdr = (pjsip_expires_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); if (expires_hdr) uapres->expires = expires_hdr->ivalue; else uapres->expires = -1; st_code = (pjsip_status_code)200; reason = pj_str("OK"); pjsua_msg_data_init(&msg_data); /* Notify application callback, if any */ if (pjsua_var.ua_cfg.cb.on_incoming_subscribe) { pjsua_buddy_id buddy_id; buddy_id = pjsua_find_buddy(rdata->msg_info.from->uri); (*pjsua_var.ua_cfg.cb.on_incoming_subscribe)(acc_id, uapres, buddy_id, &dlg->remote.info_str, rdata, &st_code, &reason, &msg_data); } /* Handle rejection case */ if (st_code >= 300) { pjsip_tx_data *tdata; /* Create response */ status = pjsip_dlg_create_response(dlg, rdata, st_code, &reason, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error creating response", status); pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_FALSE; } /* Add header list, if any */ pjsua_process_msg_data(tdata, &msg_data); /* Send the response */ status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error sending response", status); /* This is not fatal */ } /* Terminate presence subscription */ pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_TRUE; } /* Create and send 2xx response to the SUBSCRIBE request: */ status = pjsip_pres_accept(sub, rdata, st_code, &msg_data.hdr_list); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to accept presence subscription", status); pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_FALSE; } /* If code is 200, send NOTIFY now */ if (st_code == 200) { pjsua_pres_notify(acc_id, uapres, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, PJ_TRUE, &msg_data); } /* Done: */ PJSUA_UNLOCK(); return PJ_TRUE; }
static int msg_send(void *data) { RAII_VAR(struct msg_data *, mdata, data, ao2_cleanup); const struct ast_sip_body body = { .type = "text", .subtype = "plain", .body_text = ast_msg_get_body(mdata->msg) }; pjsip_tx_data *tdata; RAII_VAR(char *, uri, NULL, ast_free); RAII_VAR(struct ast_sip_endpoint *, endpoint, get_outbound_endpoint( mdata->to, &uri), ao2_cleanup); if (!endpoint) { ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not find endpoint and " "no default outbound endpoint configured\n"); return -1; } if (ast_sip_create_request("MESSAGE", NULL, endpoint, uri, NULL, &tdata)) { ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not create request\n"); return -1; } update_to(tdata, mdata->to); update_from(tdata, mdata->from); if (ast_sip_add_body(tdata, &body)) { pjsip_tx_data_dec_ref(tdata); ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not add body to request\n"); return -1; } vars_to_headers(mdata->msg, tdata); if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) { ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not send request\n"); return -1; } return PJ_SUCCESS; } static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *from) { struct msg_data *mdata; if (ast_strlen_zero(to)) { ast_log(LOG_ERROR, "SIP MESSAGE - a 'To' URI must be specified\n"); return -1; } if (!(mdata = msg_data_create(msg, to, from)) || ast_sip_push_task(NULL, msg_send, mdata)) { ao2_ref(mdata, -1); return -1; } return 0; } static const struct ast_msg_tech msg_tech = { .name = "pjsip", .msg_send = sip_msg_send, }; static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code code, pjsip_dialog *dlg, pjsip_transaction *tsx) { pjsip_tx_data *tdata; pj_status_t status; pjsip_response_addr res_addr; status = ast_sip_create_response(rdata, code, NULL, &tdata); if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to create response (%d)\n", status); return status; } if (dlg && tsx) { status = pjsip_dlg_send_response(dlg, tsx, tdata); } else { /* Get where to send request. */ status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr); if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to get response address (%d)\n", status); return status; } status = ast_sip_send_response(&res_addr, tdata, ast_pjsip_rdata_get_endpoint(rdata)); } if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send response (%d)\n", status); } return status; } static pj_bool_t module_on_rx_request(pjsip_rx_data *rdata) { enum pjsip_status_code code; struct ast_msg *msg; /* if not a MESSAGE, don't handle */ if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_message_method)) { return PJ_FALSE; } msg = ast_msg_alloc(); if (!msg) { send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL); return PJ_TRUE; } if ((code = check_content_type(rdata)) != PJSIP_SC_OK) { send_response(rdata, code, NULL, NULL); return PJ_TRUE; } if ((code = rx_data_to_ast_msg(rdata, msg)) == PJSIP_SC_OK) { /* send it to the dialplan */ ast_msg_queue(msg); code = PJSIP_SC_ACCEPTED; } send_response(rdata, code, NULL, NULL); return PJ_TRUE; } static int incoming_in_dialog_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata) { char buf[MAX_BODY_SIZE]; enum pjsip_status_code code; struct ast_frame f; pjsip_dialog *dlg = session->inv_session->dlg; pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata); if ((code = check_content_type(rdata)) != PJSIP_SC_OK) { send_response(rdata, code, dlg, tsx); return 0; } if (print_body(rdata, buf, sizeof(buf)-1) < 1) { /* invalid body size */ return 0; } ast_debug(3, "Received in dialog SIP message\n"); memset(&f, 0, sizeof(f)); f.frametype = AST_FRAME_TEXT; f.subclass.integer = 0; f.offset = 0; f.data.ptr = buf; f.datalen = strlen(buf) + 1; ast_queue_frame(session->channel, &f); send_response(rdata, PJSIP_SC_ACCEPTED, dlg, tsx); return 0; }
static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata) { const pj_str_t call_user = { "2", 1 }; pjsip_uri *uri; pjsip_sip_uri *sip_uri; struct call *call; pjsip_dialog *dlg; pjmedia_sdp_session *sdp; pjsip_tx_data *tdata; pj_bool_t has_initial = PJ_FALSE; pj_status_t status; uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri); /* Only want to receive SIP/SIPS scheme */ if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) return PJ_FALSE; sip_uri = (pjsip_sip_uri*) uri; /* Only want to handle INVITE requests. */ if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { return PJ_FALSE; } /* Check for matching user part. Incoming requests will be handled * call-statefully if: * - user part is "2", or * - user part is not "0" nor "1" and method is INVITE. */ if (pj_strcmp(&sip_uri->user, &call_user) == 0 || sip_uri->user.slen != 1 || (*sip_uri->user.ptr != '0' && *sip_uri->user.ptr != '1')) { /* Match */ } else { return PJ_FALSE; } /* Verify that we can handle the request. */ if (app.real_sdp) { unsigned options = 0; status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, app.sip_endpt, &tdata); if (status != PJ_SUCCESS) { /* * No we can't handle the incoming INVITE request. */ if (tdata) { pjsip_response_addr res_addr; pjsip_get_response_addr(tdata->pool, rdata, &res_addr); pjsip_endpt_send_response(app.sip_endpt, &res_addr, tdata, NULL, NULL); } else { /* Respond with 500 (Internal Server Error) */ pjsip_endpt_respond_stateless(app.sip_endpt, rdata, 500, NULL, NULL, NULL); } return PJ_TRUE; } } /* Create UAS dialog */ status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, &app.local_contact, &dlg); if (status != PJ_SUCCESS) { const pj_str_t reason = pj_str("Unable to create dialog"); pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 500, &reason, NULL, NULL); return PJ_TRUE; } /* Alloc call structure. */ call = pj_pool_zalloc(dlg->pool, sizeof(struct call)); /* Create SDP from PJMEDIA */ if (app.real_sdp) { status = pjmedia_endpt_create_sdp(app.med_endpt, rdata->tp_info.pool, app.skinfo_cnt, app.skinfo, &sdp); } else { sdp = app.dummy_sdp; } /* Create UAS invite session */ status = pjsip_inv_create_uas( dlg, rdata, sdp, 0, &call->inv); if (status != PJ_SUCCESS) { pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata); pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); return PJ_TRUE; } /* Send 100/Trying if needed */ if (app.server.send_trying) { status = send_response(call->inv, rdata, 100, &has_initial); if (status != PJ_SUCCESS) return PJ_TRUE; } /* Send 180/Ringing if needed */ if (app.server.send_ringing) { status = send_response(call->inv, rdata, 180, &has_initial); if (status != PJ_SUCCESS) return PJ_TRUE; } /* Simulate call processing delay */ if (app.server.delay) { pj_time_val delay; call->ans_timer.id = 1; call->ans_timer.user_data = call; call->ans_timer.cb = &answer_timer_cb; delay.sec = 0; delay.msec = app.server.delay; pj_time_val_normalize(&delay); pjsip_endpt_schedule_timer(app.sip_endpt, &call->ans_timer, &delay); } else { /* Send the 200 response immediately . */ status = send_response(call->inv, rdata, 200, &has_initial); PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return PJ_TRUE); } /* Done */ app.server.cur_state.call_cnt++; return PJ_TRUE; }