Exemplo n.º 1
0
void worker_loop(int id) {
	dmq_worker_t* worker = &workers[id];
	dmq_job_t* current_job;
	peer_reponse_t peer_response;
	int ret_value;
	for(;;) {
		LM_DBG("dmq_worker [%d %d] getting lock\n", id, my_pid());
		lock_get(&worker->lock);
		LM_DBG("dmq_worker [%d %d] lock acquired\n", id, my_pid());
		/* multiple lock_release calls might be performed, so remove from queue until empty */
		do {
			/* fill the response with 0's */
			memset(&peer_response, 0, sizeof(peer_response));
			current_job = job_queue_pop(worker->queue);
			/* job_queue_pop might return NULL if queue is empty */
			if(current_job) {
				ret_value = current_job->f(current_job->msg, &peer_response);
				if(ret_value < 0) {
					LM_ERR("running job failed\n");
					continue;
				}
				/* add the body to the reply */
				if(peer_response.body.s) {
					if(set_reply_body(current_job->msg, &peer_response.body, &peer_response.content_type) < 0) {
						LM_ERR("error adding lumps\n");
						continue;
					}
				}
				/* send the reply */
				if(slb.freply(current_job->msg, peer_response.resp_code, &peer_response.reason) < 0)
				{
					LM_ERR("error sending reply\n");
				}
				
				/* if body given, free the lumps and free the body */
				if(peer_response.body.s) {
					del_nonshm_lump_rpl(&current_job->msg->reply_lump);
					pkg_free(peer_response.body.s);
				}
				LM_DBG("sent reply\n");
				shm_free(current_job->msg);
				shm_free(current_job);
				worker->jobs_processed++;
			}
		} while(job_queue_size(worker->queue) > 0);
	}
}
Exemplo n.º 2
0
inline static void free_faked_req(struct sip_msg *faked_req, struct cell *t)
{
	if (faked_req->new_uri.s) {
		pkg_free(faked_req->new_uri.s);
		faked_req->new_uri.s = 0;
	}
	if (faked_req->dst_uri.s) {
		pkg_free(faked_req->dst_uri.s);
		faked_req->dst_uri.s = 0;
	}
	if (faked_req->path_vec.s) {
		pkg_free(faked_req->path_vec.s);
		faked_req->path_vec.s = 0;
	}

	/* SDP in not cloned into SHM, so if we have one, it means the SDP
	 * was parsed in the fake environment, so we have to free it */
	if (faked_req->sdp)
		free_sdp(&(faked_req->sdp));

	if (faked_req->multi) {
		free_multi_body(faked_req->multi);
		faked_req->multi = 0;
	}

	if (faked_req->msg_cb) {
		msg_callback_process(faked_req, MSG_DESTROY, NULL);
	}

	/* free all types of lump that were added in failure handlers */
	del_notflaged_lumps( &(faked_req->add_rm), LUMPFLAG_SHMEM );
	del_notflaged_lumps( &(faked_req->body_lumps), LUMPFLAG_SHMEM );
	del_nonshm_lump_rpl( &(faked_req->reply_lump) );

	clean_msg_clone( faked_req, t->uas.request, t->uas.end_request);
}
Exemplo n.º 3
0
void async_cdp_callback(int is_timeout, void *param, AAAMessage *maa, long elapsed_msecs) {
    int i, j;
    int rc = -1, experimental_rc = -1;
    saved_transaction_t* data = (saved_transaction_t*) param;
    struct cell *t = 0;
    int result = CSCF_RETURN_TRUE;
    int sip_number_auth_items;
    struct auth_data_item_list *adi_list = 0;
    AAA_AVP *auth_data;
    auth_data = 0;
    int item_number;
    str authenticate = {0, 0}, authorization2 = {0, 0}, ck = {0, 0}, ik = {0, 0}, ip = {0, 0}, ha1 = {0, 0};
    str line_identifier = {0, 0};
    str response_auth = {0, 0}, digest_realm = {0, 0};
    auth_vector *av = 0, **avlist = 0;
    HASHHEX ha1_hex;
    HASHHEX result_hex;
    str etsi_nonce = {0, 0};
    str private_identity, public_identity;
    str algorithm;

    if (is_timeout) {
    	update_stat(stat_mar_timeouts, 1);
        LM_ERR("Transaction timeout - did not get MAA\n");
        result = CSCF_RETURN_ERROR;
        goto error;
    }
    if (!maa) {
        LM_ERR("Error sending message via CDP\n");
        result = CSCF_RETURN_ERROR;
        goto error;
    }

    update_stat(mar_replies_received, 1);
    update_stat(mar_replies_response_time, elapsed_msecs);

    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
        LM_ERR("t_continue: transaction not found\n");
        result = CSCF_RETURN_ERROR;
        goto error;
    }

    /* get the private_identity */
    private_identity = get_private_identity(t->uas.request, data->realm, data->is_proxy_auth);
    if (!private_identity.len) {
        LM_ERR("No private identity specified (Authorization: username)\n");
        stateful_request_reply_async(t, t->uas.request, 403, MSG_403_NO_PRIVATE);
        result = CSCF_RETURN_FALSE;
        goto error;
    }
    /* get the public_identity */
    public_identity = get_public_identity(t->uas.request);
    if (!public_identity.len) {
        LM_ERR("No public identity specified (To:)\n");
        stateful_request_reply_async(t, t->uas.request, 403, MSG_403_NO_PUBLIC);
        result = CSCF_RETURN_FALSE;
        goto error;
    }

    //get each individual element from the MAA
    cxdx_get_result_code(maa, &rc);
    cxdx_get_experimental_result_code(maa, &experimental_rc);
    cxdx_get_sip_number_auth_items(maa, &sip_number_auth_items);

    //now assign the auth_data_item elements
    //there can be many of these in the MAA
    struct auth_data_item *adi;
    int adi_len;
    char *p;
    while ((cxdx_get_auth_data_item_answer(maa, &auth_data, &item_number,
            &algorithm, &authenticate, &authorization2,
            &ck, &ik,
            &ip,
            &ha1, &response_auth, &digest_realm,
            &line_identifier))) {

        //create an auth_data_item for each entry in the MAA
        adi_len = sizeof (struct auth_data_item) +authenticate.len + authorization2.len + ck.len + ik.len + ip.len + ha1.len + line_identifier.len + response_auth.len + digest_realm.len + algorithm.len;
        adi = (struct auth_data_item*) shm_malloc(adi_len);
        if (!adi) {
            LM_CRIT("Out of memory!\n");
            result = CSCF_RETURN_ERROR;
            goto done;
        }

        memset(adi, 0, adi_len);

        //put all elements in the auth_data_item entry
        p = (char*) (adi + 1);

        adi->authenticate.s = p;
        adi->authenticate.len = authenticate.len;
        memcpy(p, authenticate.s, authenticate.len);
        p += authenticate.len;

        adi->authorization.s = p;
        adi->authorization.len = authorization2.len;
        memcpy(p, authorization2.s, authorization2.len);
        p += authorization2.len;

        adi->auth_scheme.s = p;
        adi->auth_scheme.len = algorithm.len;
        memcpy(p, algorithm.s, algorithm.len);
        p += algorithm.len;

        adi->ck.s = p;
        adi->ck.len = ck.len;
        memcpy(p, ck.s, ck.len);
        p += ck.len;

        adi->ik.s = p;
        adi->ik.len = ik.len;
        memcpy(p, ik.s, ik.len);
        p += ik.len;

        adi->ip.s = p;
        adi->ip.len = ip.len;
        memcpy(p, ip.s, ip.len);
        p += ip.len;

        adi->ha1.s = p;
        adi->ha1.len = ha1.len;
        memcpy(p, ha1.s, ha1.len);
        p += ha1.len;

        adi->line_identifier.s = p;
        adi->line_identifier.len = line_identifier.len;
        memcpy(p, line_identifier.s, line_identifier.len);
        p += line_identifier.len;

        adi->response_auth.s = p;
        adi->response_auth.len = response_auth.len;
        memcpy(p, response_auth.s, response_auth.len);
        p += response_auth.len;

        adi->digest_realm.s = p;
        adi->digest_realm.len = digest_realm.len;
        memcpy(p, digest_realm.s, digest_realm.len);
        p += digest_realm.len;

        if (p != (((char*) adi) + adi_len)) {
            LM_CRIT("buffer overflow\n");
            shm_free(adi);
            adi = 0;
            result = CSCF_RETURN_ERROR;
            goto done;
        }
        auth_data->code = -auth_data->code;
        adi->item_number = item_number;

        int len = sizeof (struct auth_data_item_list);
        adi_list = (struct auth_data_item_list*) shm_malloc(len);
        memset(adi_list, 0, len);

        if (adi_list->first == 0) {
            adi_list->first = adi_list->last = adi;
        } else {
            adi_list->last->next = adi;
            adi->previous = adi_list->last;
            adi_list->last = adi;
        }
    }

    if (!(rc) && !(experimental_rc)) {
        stateful_request_reply_async(t, t->uas.request, 480, MSG_480_DIAMETER_MISSING_AVP);
        result = CSCF_RETURN_FALSE;
        goto done;
    }

    switch (rc) {
        case -1:
            switch (experimental_rc) {
                case RC_IMS_DIAMETER_ERROR_USER_UNKNOWN:
                    stateful_request_reply_async(t, t->uas.request, 403, MSG_403_USER_UNKNOWN);
                    result = CSCF_RETURN_FALSE;
                    break;
                case RC_IMS_DIAMETER_ERROR_IDENTITIES_DONT_MATCH:
                    stateful_request_reply_async(t, t->uas.request, 403, MSG_403_IDENTITIES_DONT_MATCH);
                    result = CSCF_RETURN_FALSE;
                    break;
                case RC_IMS_DIAMETER_ERROR_AUTH_SCHEME_NOT_SUPPORTED:
                    stateful_request_reply_async(t, t->uas.request, 403, MSG_403_AUTH_SCHEME_UNSOPPORTED);
                    result = CSCF_RETURN_FALSE;
                    break;

                default:
                    stateful_request_reply_async(t, t->uas.request, 403, MSG_403_UNKOWN_EXPERIMENTAL_RC);
                    result = CSCF_RETURN_FALSE;
            }
            break;

        case AAA_UNABLE_TO_COMPLY:
            stateful_request_reply_async(t, t->uas.request, 403, MSG_403_UNABLE_TO_COMPLY);
            result = CSCF_RETURN_FALSE;
            break;

        case AAA_SUCCESS:
            goto success;
            break;

        default:
            stateful_request_reply_async(t, t->uas.request, 403, MSG_403_UNKOWN_RC);
            result = CSCF_RETURN_FALSE;
    }

    goto done;

success:

    if (!sip_number_auth_items) {
        stateful_request_reply_async(t, t->uas.request, 403, MSG_403_NO_AUTH_DATA);
        result = CSCF_RETURN_FALSE;
        goto done;
    }

    avlist = shm_malloc(sizeof (auth_vector *) * sip_number_auth_items);
    if (!avlist) {
        stateful_request_reply_async(t, t->uas.request, 403, MSG_480_HSS_ERROR);
        result = CSCF_RETURN_FALSE;
        goto done;
    }

    sip_number_auth_items = 0;

    struct auth_data_item *tmp;
    tmp = adi_list->first;

    while (tmp) {

        if (tmp->ip.len)
            av = new_auth_vector(tmp->item_number, tmp->auth_scheme, empty_s,
                tmp->ip, empty_s, empty_s);
        else if (tmp->line_identifier.len)
            av = new_auth_vector(tmp->item_number, tmp->auth_scheme, empty_s,
                line_identifier, empty_s, empty_s);
        else if (tmp->ha1.len) {
            if (tmp->response_auth.len) //HSS check
            {
                memset(ha1_hex, 0, HASHHEXLEN + 1);
                memcpy(ha1_hex, tmp->ha1.s,
                        tmp->ha1.len > HASHHEXLEN ? 32 : tmp->ha1.len);

                etsi_nonce.len = tmp->authenticate.len / 2;
                etsi_nonce.s = pkg_malloc(etsi_nonce.len);
                if (!etsi_nonce.s) {
                    LM_ERR("error allocating %d bytes\n", etsi_nonce.len);
                    goto done;
                }
                etsi_nonce.len = base16_to_bin(tmp->authenticate.s,
                        tmp->authenticate.len, etsi_nonce.s);

                calc_response(ha1_hex, &etsi_nonce, &empty_s, &empty_s,
                        &empty_s, 0, &(t->uas.request->first_line.u.request.method),
                        &scscf_name_str, 0, result_hex);
                pkg_free(etsi_nonce.s);

                if (!tmp->response_auth.len == 32
                        || strncasecmp(tmp->response_auth.s, result_hex, 32)) {
                    LM_ERR("The HSS' Response-Auth is different from what we compute locally!\n"
                            " BUT! If you sent an MAR with auth scheme unknown (HSS-Selected Authentication), this is normal.\n"
                            "HA1=\t|%s|\nNonce=\t|%.*s|\nMethod=\t|%.*s|\nuri=\t|%.*s|\nxresHSS=\t|%.*s|\nxresSCSCF=\t|%s|\n",
                            ha1_hex,
                            tmp->authenticate.len, tmp->authenticate.s,
                            t->uas.request->first_line.u.request.method.len, t->uas.request->first_line.u.request.method.s,
                            scscf_name_str.len, scscf_name_str.s,
                            tmp->response_auth.len, tmp->response_auth.s,
                            result_hex);
                    //stateful_register_reply(msg,514,MSG_514_HSS_AUTH_FAILURE);
                    //goto done;
                }
            }
            av = new_auth_vector(tmp->item_number, tmp->auth_scheme,
                    tmp->authenticate, tmp->ha1, empty_s, empty_s);
        } else
            av = new_auth_vector(tmp->item_number, tmp->auth_scheme,
                tmp->authenticate, tmp->authorization, tmp->ck, tmp->ik);

        if (sip_number_auth_items == 0)
            avlist[sip_number_auth_items++] = av;
        else {
            i = sip_number_auth_items;
            while (i > 0 && avlist[i - 1]->item_number > av->item_number)
                i--;
            for (j = sip_number_auth_items; j > i; j--)
                avlist[j] = avlist[j - 1];
            avlist[i] = av;
            sip_number_auth_items++;
        }

        //TODO need to confirm that removing this has done no problems
        //tmp->auth_data->code = -tmp->auth_data->code;

	LM_DBG("Added new auth-vector.\n");

        tmp = tmp->next;
    }

    //MAA returns a whole list of av! Which should we use?
    //right now we take the first and put the rest in the AV queue
    //then we use the first one and then add it to the queue as sent!

    for (i = 1; i < sip_number_auth_items; i++)
        if (!add_auth_vector(private_identity, public_identity, avlist[i]))
            free_auth_vector(avlist[i]);

    if (!pack_challenge(t->uas.request, data->realm, avlist[0], data->is_proxy_auth)) {
        stateful_request_reply_async(t, t->uas.request, 500, MSG_500_PACK_AV);
        result = CSCF_RETURN_FALSE;
        goto done;
    }

    if (data->is_proxy_auth)
        stateful_request_reply_async(t, t->uas.request, 407, MSG_407_CHALLENGE);
    else
        stateful_request_reply_async(t, t->uas.request, 401, MSG_401_CHALLENGE);

done:
    if (avlist) {
        start_reg_await_timer(avlist[0]); //start the timer to remove stale or unused Auth Vectors

        //now we add it to the queue as sent as we have already sent the challenge and used it and set the status to SENT
        if (!add_auth_vector(private_identity, public_identity, avlist[0]))
            free_auth_vector(avlist[0]);
    }

    //free memory
    if (maa) cdpb.AAAFreeMessage(&maa);
    if (avlist) {
        shm_free(avlist);
        avlist = 0;
    }

    if (adi_list) {
        struct auth_data_item *tmp1 = adi_list->first;
        while (tmp1) {
            struct auth_data_item *tmp2 = tmp1->next;
            shm_free(tmp1);
            tmp1 = tmp2;
        }
        shm_free(adi_list);
        adi_list = 0;
    }

    LM_DBG("DBG:UAR Async CDP callback: ... Done resuming transaction\n");
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);

    //make sure we delete any private lumps we created
    create_return_code(result);
    if (t) {
        del_nonshm_lump_rpl(&t->uas.request->reply_lump);
        tmb.unref_cell(t);
    }
    tmb.t_continue(data->tindex, data->tlabel, data->act);
    free_saved_transaction_data(data);
    return;

error:
    //don't need to set result code as by default it is ERROR!

    if (t) {
        del_nonshm_lump_rpl(&t->uas.request->reply_lump);
        tmb.unref_cell(t);
    }
    tmb.t_continue(data->tindex, data->tlabel, data->act);
    free_saved_transaction_data(data);
}
Exemplo n.º 4
0
/* Continues the SIP request processing previously saved by
 * t_suspend(). The script does not continue from the same
 * point, but a separate route block is executed instead.
 *
 * Return value:
 * 	0  - success
 * 	<0 - failure
 */
int t_continue(unsigned int hash_index, unsigned int label,
		struct action *route)
{
	struct cell	*t;
	struct sip_msg	faked_req;
	struct cancel_info cancel_data;
	int	branch;
	struct ua_client *uac =NULL;
	int	ret;
	int cb_type;
	int msg_status;
	int last_uac_status;
	int reply_status;
	int do_put_on_wait;
	struct hdr_field *hdr, *prev = 0, *tmp = 0;

	if (t_lookup_ident(&t, hash_index, label) < 0) {
		LM_ERR("transaction not found\n");
		return -1;
	}

	if (!(t->flags & T_ASYNC_SUSPENDED)) {
		LM_WARN("transaction is not suspended [%u:%u]\n", hash_index, label);
		return -2;
	}

	if (t->flags & T_CANCELED) {
		t->flags &= ~T_ASYNC_SUSPENDED;
		/* The transaction has already been canceled,
		 * needless to continue */
		UNREF(t); /* t_unref would kill the transaction */
		/* reset T as we have no working T anymore */
		set_t(T_UNDEFINED, T_BR_UNDEFINED);
		return 1;
	}

	/* The transaction has to be locked to protect it
	 * form calling t_continue() multiple times simultaneously */
	LOCK_ASYNC_CONTINUE(t);

	t->flags |= T_ASYNC_CONTINUE;   /* we can now know anywhere in kamailio
					 * that we are executing post a suspend */

	/* which route block type were we in when we were suspended */
	cb_type =  FAILURE_CB_TYPE;;
	switch (t->async_backup.backup_route) {
		case REQUEST_ROUTE:
			cb_type = FAILURE_CB_TYPE;
			break;
		case FAILURE_ROUTE:
			cb_type = FAILURE_CB_TYPE;
			break;
		case TM_ONREPLY_ROUTE:
			cb_type = ONREPLY_CB_TYPE;
			break;
		case BRANCH_ROUTE:
			cb_type = FAILURE_CB_TYPE;
			break;
	}

	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
		branch = t->async_backup.blind_uac;	/* get the branch of the blind UAC setup 
			* during suspend */
		if (branch >= 0) {
			stop_rb_timers(&t->uac[branch].request);
 
			if (t->uac[branch].last_received != 0) {
				/* Either t_continue() has already been
				* called or the branch has already timed out.
				* Needless to continue. */
				t->flags &= ~T_ASYNC_SUSPENDED;
				UNLOCK_ASYNC_CONTINUE(t);
				UNREF(t); /* t_unref would kill the transaction */
				return 1;
			}

			/* Set last_received to something >= 200,
			 * the actual value does not matter, the branch
			 * will never be picked up for response forwarding.
			 * If last_received is lower than 200,
			 * then the branch may tried to be cancelled later,
			 * for example when t_reply() is called from
			 * a failure route => deadlock, because both
			 * of them need the reply lock to be held. */
			t->uac[branch].last_received=500;
			uac = &t->uac[branch];
		}
		/* else
			Not a huge problem, fr timer will fire, but CANCEL
			will not be sent. last_received will be set to 408. */

		/* We should not reset kr here to 0 as it's quite possible before continuing the dev. has correctly set the
		 * kr by, for example, sending a transactional reply in code - resetting here will cause a dirty log message
		 * "WARNING: script writer didn't release transaction" to appear in log files. TODO: maybe we need to add 
		 * a special kr for async?
		 * reset_kr();
		 */

		/* fake the request and the environment, like in failure_route */
		if (!fake_req(&faked_req, t->uas.request, 0 /* extra flags */, uac)) {
			LM_ERR("building fake_req failed\n");
			ret = -1;
			goto kill_trans;
		}
		faked_env( t, &faked_req, 1);

		/* execute the pre/post -script callbacks based on original route block */
		if (exec_pre_script_cb(&faked_req, cb_type)>0) {
			if (run_top_route(route, &faked_req, 0)<0)
				LM_ERR("failure inside run_top_route\n");
			exec_post_script_cb(&faked_req, cb_type);
		}

		/* TODO: save_msg_lumps should clone the lumps to shm mem */

		/* restore original environment and free the fake msg */
		faked_env( t, 0, 1);
		free_faked_req(&faked_req, t);

		/* update the flags */
		t->uas.request->flags = faked_req.flags;

		if (t->uas.status < 200) {
			/* No final reply has been sent yet.
			* Check whether or not there is any pending branch.
			*/
			for (	branch = 0;
				branch < t->nr_of_outgoings;
				branch++
			) {
				if (t->uac[branch].last_received < 200)
					break;
			}

			if (branch == t->nr_of_outgoings) {
			/* There is not any open branch so there is
			* no chance that a final response will be received. */
				ret = 0;
				goto kill_trans;
			}
		}

	} else {
		branch = t->async_backup.backup_branch;

		init_cancel_info(&cancel_data);

		LM_DBG("continuing from a suspended reply"
				" - resetting the suspend branch flag\n");

		if (t->uac[branch].reply) {
		t->uac[branch].reply->msg_flags &= ~FL_RPL_SUSPENDED;
                } else {
			LM_WARN("no reply in t_continue for branch. not much we can do\n");
			return 0;
		}
                
		if (t->uas.request) t->uas.request->msg_flags&= ~FL_RPL_SUSPENDED;

		faked_env( t, t->uac[branch].reply, 1);

		if (exec_pre_script_cb(t->uac[branch].reply, cb_type)>0) {
			if (run_top_route(route, t->uac[branch].reply, 0)<0){
				LOG(L_ERR, "ERROR: t_continue_reply: Error in run_top_route\n");
			}
			exec_post_script_cb(t->uac[branch].reply, cb_type);
		}

		LM_DBG("restoring previous environment");
		faked_env( t, 0, 1);

		/*lock transaction replies - will be unlocked when reply is relayed*/
		LOCK_REPLIES( t );
		if ( is_local(t) ) {
			LM_DBG("t is local - sending reply with status code: [%d]\n",
					t->uac[branch].reply->first_line.u.reply.statuscode);
			reply_status = local_reply( t, t->uac[branch].reply, branch,
					t->uac[branch].reply->first_line.u.reply.statuscode,
					&cancel_data );
			if (reply_status == RPS_COMPLETED) {
				/* no more UAC FR/RETR (if I received a 2xx, there may
				* be still pending branches ...
				*/
				cleanup_uac_timers( t );
				if (is_invite(t)) cancel_uacs(t, &cancel_data, F_CANCEL_B_KILL);
				/* There is no need to call set_final_timer because we know
				* that the transaction is local */
				put_on_wait(t);
			}else if (unlikely(cancel_data.cancel_bitmap)){
				/* cancel everything, even non-INVITEs (e.g in case of 6xx), use
				* cancel_b_method for canceling unreplied branches */
				cancel_uacs(t, &cancel_data, cfg_get(tm,tm_cfg, cancel_b_flags));
			}

		} else {
			LM_DBG("t is not local - relaying reply with status code: [%d]\n",
					t->uac[branch].reply->first_line.u.reply.statuscode);
			do_put_on_wait = 0;
			if(t->uac[branch].reply->first_line.u.reply.statuscode>=200){
				do_put_on_wait = 1;
			}
			reply_status=relay_reply( t, t->uac[branch].reply, branch,
					t->uac[branch].reply->first_line.u.reply.statuscode,
					&cancel_data, do_put_on_wait );
			if (reply_status == RPS_COMPLETED) {
				/* no more UAC FR/RETR (if I received a 2xx, there may
				be still pending branches ...
				*/
				cleanup_uac_timers( t );
				/* 2xx is a special case: we can have a COMPLETED request
				* with branches still open => we have to cancel them */
				if (is_invite(t) && cancel_data.cancel_bitmap) 
					cancel_uacs( t, &cancel_data,  F_CANCEL_B_KILL);
				/* FR for negative INVITES, WAIT anything else */
				/* Call to set_final_timer is embedded in relay_reply to avoid
				* race conditions when reply is sent out and an ACK to stop
				* retransmissions comes before retransmission timer is set.*/
			}else if (unlikely(cancel_data.cancel_bitmap)){
				/* cancel everything, even non-INVITEs (e.g in case of 6xx), use
				* cancel_b_method for canceling unreplied branches */
				cancel_uacs(t, &cancel_data, cfg_get(tm,tm_cfg, cancel_b_flags));
			}

		}
		t->uac[branch].request.flags|=F_RB_REPLIED;

		if (reply_status==RPS_ERROR){
			goto done;
		}

		/* update FR/RETR timers on provisional replies */

		msg_status=t->uac[branch].reply->REPLY_STATUS;
		last_uac_status=t->uac[branch].last_received;

		if (is_invite(t) && msg_status<200 &&
			( cfg_get(tm, tm_cfg, restart_fr_on_each_reply) ||
			( (last_uac_status<msg_status) &&
			((msg_status>=180) || (last_uac_status==0)) )
		) ) { /* provisional now */
			restart_rb_fr(& t->uac[branch].request, t->fr_inv_timeout);
			t->uac[branch].request.flags|=F_RB_FR_INV; /* mark fr_inv */
		}
            
	}

done:
	UNLOCK_ASYNC_CONTINUE(t);

	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
		/* unref the transaction */
		t_unref(t->uas.request);
	} else {
		tm_ctx_set_branch_index(T_BR_UNDEFINED);        
		/* unref the transaction */
		t_unref(t->uac[branch].reply);
		LOG(L_DBG,"DEBUG: t_continue_reply: Freeing earlier cloned reply\n");

		/* free lumps that were added during reply processing */
		del_nonshm_lump( &(t->uac[branch].reply->add_rm) );
		del_nonshm_lump( &(t->uac[branch].reply->body_lumps) );
		del_nonshm_lump_rpl( &(t->uac[branch].reply->reply_lump) );

		/* free header's parsed structures that were added */
		for( hdr=t->uac[branch].reply->headers ; hdr ; hdr=hdr->next ) {
			if ( hdr->parsed && hdr_allocs_parse(hdr) &&
				(hdr->parsed<(void*)t->uac[branch].reply ||
				hdr->parsed>=(void*)t->uac[branch].end_reply)) {
				clean_hdr_field(hdr);
				hdr->parsed = 0;
			}
		}

		/* now go through hdr_fields themselves and remove the pkg allocated space */
		hdr = t->uac[branch].reply->headers;
		while (hdr) {
			if ( hdr && ((void*)hdr<(void*)t->uac[branch].reply ||
				(void*)hdr>=(void*)t->uac[branch].end_reply)) {
				//this header needs to be freed and removed form the list.
				if (!prev) {
					t->uac[branch].reply->headers = hdr->next;
				} else {
					prev->next = hdr->next;
				}
				tmp = hdr;
				hdr = hdr->next;
				pkg_free(tmp);
			} else {
				prev = hdr;
				hdr = hdr->next;
			}
		}
		sip_msg_free(t->uac[branch].reply);
		t->uac[branch].reply = 0;
	}

	/*This transaction is no longer suspended so unsetting the SUSPEND flag*/
	t->flags &= ~T_ASYNC_SUSPENDED;


	return 0;

kill_trans:
	t->flags &= ~T_ASYNC_SUSPENDED;
	/* The script has hopefully set the error code. If not,
	 * let us reply with a default error. */
	if ((kill_transaction_unsafe(t,
		tm_error ? tm_error : E_UNSPEC)) <=0
	) {
		LOG(L_ERR, "ERROR: t_continue: "
			"reply generation failed\n");
		/* The transaction must be explicitely released,
		 * no more timer is running */
		UNLOCK_ASYNC_CONTINUE(t);
		t_release_transaction(t);
	} else {
		UNLOCK_ASYNC_CONTINUE(t);
	}

	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
		t_unref(t->uas.request);
	} else {
		/* unref the transaction */
		t_unref(t->uac[branch].reply);
	}
	return ret;
}
Exemplo n.º 5
0
void async_cdp_callback(int is_timeout, void *param, AAAMessage *saa, long elapsed_msecs) {
    struct cell *t = 0;
    int rc = -1, experimental_rc = -1;
    int result = CSCF_RETURN_TRUE;
    saved_transaction_t* data = 0;

    str xml_data = {0, 0}, ccf1 = {0, 0}, ccf2 = {0, 0}, ecf1 = {0, 0}, ecf2 = {0, 0};
    ims_subscription* s = 0;
    rerrno = R_FINE;

    if (!param) {
        LM_DBG("No transaction data this must have been called from usrloc cb impu deleted - just log result code and then exit");
        cxdx_get_result_code(saa, &rc);
        cxdx_get_experimental_result_code(saa, &experimental_rc);

        if (saa) cdpb.AAAFreeMessage(&saa);

        if (!rc && !experimental_rc) {
            LM_ERR("bad SAA result code\n");
            return;
        }
        switch (rc) {
            case -1:
                LM_DBG("Received Diameter error\n");
                return;

            case AAA_UNABLE_TO_COMPLY:
                LM_DBG("Unable to comply\n");
                return;

            case AAA_SUCCESS:
                LM_DBG("received AAA success\n");
                return;

            default:
                LM_ERR("Unknown error\n");
                return;
        }

    } else {
        LM_DBG("There is transaction data this must have been called from save or assign server unreg");
        data = (saved_transaction_t*) param;
        if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
            LM_ERR("t_continue: transaction not found\n");
            rerrno = R_SAR_FAILED;
            goto error_no_send;
        }

	set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
	set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
	set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
	set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
	set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
	set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);

        get_act_time();

        if (is_timeout) {
        	update_stat(stat_sar_timeouts, 1);
            LM_ERR("Transaction timeout - did not get SAA\n");
            rerrno = R_SAR_FAILED;
            goto error;
        }
        if (!saa) {
            LM_ERR("Error sending message via CDP\n");
            rerrno = R_SAR_FAILED;
            goto error;
        }

        update_stat(sar_replies_received, 1);
        update_stat(sar_replies_response_time, elapsed_msecs);

        /* check and see that all the required headers are available and can be parsed */
        if (parse_message_for_register(t->uas.request) < 0) {
            LM_ERR("Unable to parse register message correctly\n");
            rerrno = R_SAR_FAILED;
            goto error;
        }

        cxdx_get_result_code(saa, &rc);
        cxdx_get_experimental_result_code(saa, &experimental_rc);
        cxdx_get_charging_info(saa, &ccf1, &ccf2, &ecf1, &ecf2);

        if (!rc && !experimental_rc) {
            LM_ERR("bad SAA result code\n");
            rerrno = R_SAR_FAILED;
            goto error;
        }

        switch (rc) {
            case -1:
                LM_DBG("Received Diameter error\n");
                rerrno = R_SAR_FAILED;
                goto error;

            case AAA_UNABLE_TO_COMPLY:
                LM_DBG("Unable to comply\n");
                rerrno = R_SAR_FAILED;
                goto error;

            case AAA_SUCCESS:
                LM_DBG("received AAA success for SAR - SAA\n");
                break;

            default:
                LM_ERR("Unknown error\n");
                rerrno = R_SAR_FAILED;
                goto error;
        }
        //success
        //if this is from a save (not a server assign unreg) and expires is zero we don't update usrloc as this is a dereg and usrloc was updated previously
        if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER && data->expires == 0) {
            LM_DBG("no need to update usrloc - already done for de-reg\n");
            result = CSCF_RETURN_TRUE;
            goto success;
        }

        xml_data = cxdx_get_user_data(saa);
        /*If there is XML user data we must be able to parse it*/
        if (xml_data.s && xml_data.len > 0) {
            LM_DBG("Parsing user data string from SAA\n");
            s = parse_user_data(xml_data);
            if (!s) {
                LM_ERR("Unable to parse user data XML string\n");
                rerrno = R_SAR_FAILED;
                goto error;
            }
            LM_DBG("Successfully parse user data XML setting ref to 1 (we are referencing it)\n");
            s->ref_count = 1; //no need to lock as nobody else will be referencing this piece of memory just yet
        } else {
            if (data->require_user_data) {
                LM_ERR("We require User data for this assignment/register and none was supplied\n");
                rerrno = R_SAR_FAILED;
                result = CSCF_RETURN_FALSE;
                goto done;
            }
        }

        if (data->sar_assignment_type == AVP_IMS_SAR_REGISTRATION || data->sar_assignment_type == AVP_IMS_SAR_RE_REGISTRATION) {
            if (build_p_associated_uri(s) != 0) {
                LM_ERR("Unable to build p_associated_uri\n");
                rerrno = R_SAR_FAILED;
                goto error;
            }
        }

        //here we update the contacts and also build the new contact header for the 200 OK reply
        if (update_contacts(t->uas.request, data->domain, &data->public_identity, data->sar_assignment_type, &s, &ccf1, &ccf2, &ecf1, &ecf2, &data->contact_header) <= 0) {
            LM_ERR("Error processing REGISTER\n");
            rerrno = R_SAR_FAILED;
            goto error;
        }
        
        if (data->contact_header) {
            LM_DBG("Updated contacts: %.*s\n", data->contact_header->data_len, data->contact_header->buf);
        } else {
            LM_DBG("Updated unreg contact\n");
        }
        
    }

success:
    update_stat(accepted_registrations, 1);

done:
    if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER)
        reg_send_reply_transactional(t->uas.request, data->contact_header, t);
    LM_DBG("DBG:SAR Async CDP callback: ... Done resuming transaction\n");

    create_return_code(result);

    //release our reference on subscription (s)
    if (s) 
        ul.unref_subscription(s);
    
    //free memory
    if (saa) cdpb.AAAFreeMessage(&saa);
    if (t) {
        del_nonshm_lump_rpl(&t->uas.request->reply_lump);
        tmb.unref_cell(t);
    }
    //free path vector pkg memory
    reset_path_vector(t->uas.request);

    tmb.t_continue(data->tindex, data->tlabel, data->act);
    free_saved_transaction_data(data);
    return;

error:
    create_return_code(-2);
    if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER)
        reg_send_reply_transactional(t->uas.request, data->contact_header, t);
		
error_no_send: //if we don't have the transaction then we can't send a transaction response
    update_stat(rejected_registrations, 1);
    //free memory
    if (saa) cdpb.AAAFreeMessage(&saa);
    if (t) {
        del_nonshm_lump_rpl(&t->uas.request->reply_lump);
        tmb.unref_cell(t);
    }
    tmb.t_continue(data->tindex, data->tlabel, data->act);
    free_saved_transaction_data(data);
    return;
}