Beispiel #1
0
void trans_timer::fire()
{
    trans_bucket* bucket = get_trans_bucket(bucket_id);
    if(bucket){
	bucket->lock();
	if(bucket->exist(t)){
	    DBG("Transaction timer expired: type=%s, trans=%p, eta=%i, t=%i\n",
		timer_name(type),t,expires,wheeltimer::instance()->wall_clock);

	    trans_timer* tt = t->get_timer(this->type & 0xFFFF);
	    if(tt != this) {
		// timer has been reset while very close to firing!!!
		// 1. it is not yet deleted in the wheeltimer
		// 2. we have already set a new one
		// -> anyway, don't fire the old one !!!
                bucket->unlock();
		return;
	    }

	    // timer_expired unlocks the bucket
	    trans_layer::instance()->timer_expired(this,bucket,t);
	}
	else {
	    WARN("Ignoring expired timer (%p/%s): transaction"
		 " %p does not exist anymore\n",this,timer_name(type),t);
	    bucket->unlock();
	}
    }
    else {
	ERROR("Invalid bucket id\n");
    }
}
void trans_timer_cb(timer* t, unsigned int bucket_id, sip_trans* tr)
{
    trans_bucket* bucket = get_trans_bucket(bucket_id);
    if(bucket){
	bucket->lock();
	if(bucket->exist(tr)){
	    DBG("Transaction timer expired: type=0x%x, trans=%p\n",t->type,tr);
	    trans_layer::instance()->timer_expired(t,bucket,tr);
	}
	else {
	    WARN("Transaction %p does not exist anymore\n",tr);
	    WARN("Timer type=0x%x will be deleted without further processing\n",t->type);
	}
	bucket->unlock();
    }
    else {
	ERROR("Invalid bucket id\n");
    }
}
void trans_timer_cb(timer* t, unsigned int bucket_id, sip_trans* tr)
{
    trans_bucket* bucket = get_trans_bucket(bucket_id);
    if(bucket){
	bucket->lock();
	if(bucket->exist(tr)){
	    DBG("Transaction timer expired: type=%c, trans=%p, eta=%i, t=%i\n",
		_timer_name_lookup[t->type],tr,t->expires,wheeltimer::instance()->wall_clock);
	    trans_layer::instance()->timer_expired(t,bucket,tr);
	}
	else {
	    WARN("Transaction %p does not exist anymore\n",tr);
	    WARN("Timer type=%c will be deleted without further processing\n",_timer_name_lookup[t->type]);
	}
	bucket->unlock();
    }
    else {
	ERROR("Invalid bucket id\n");
    }
}
void trans_layer::received_msg(sip_msg* msg)
{
#define DROP_MSG \
          delete msg;\
          return

    int err = parse_sip_msg(msg);
    DBG("parse_sip_msg returned %i\n",err);

    if(err){
	DBG("Message was: \"%.*s\"\n",msg->len,msg->buf);
	DBG("dropping message\n");
	DROP_MSG;
    }
    
    assert(msg->callid && get_cseq(msg));
    if(!msg->callid || !get_cseq(msg)){
	
	DBG("Call-ID or CSeq header missing: dropping message\n");
	DROP_MSG;
    }

    unsigned int  h = hash(msg->callid->value, get_cseq(msg)->num_str);
    trans_bucket* bucket = get_trans_bucket(h);
    sip_trans* t = NULL;

    bucket->lock();

    switch(msg->type){
    case SIP_REQUEST: 
	
	if((t = bucket->match_request(msg)) != NULL){
	    if(msg->u.request->method != t->msg->u.request->method){
		
		// ACK matched INVITE transaction
		DBG("ACK matched INVITE transaction\n");
		
		err = update_uas_request(bucket,t,msg);
		if(err<0){
		    DBG("trans_layer::update_uas_trans() failed!\n");
		    // Anyway, there is nothing we can do...
		}
		else if(err == TS_TERMINATED){
		
		    // do not touch the transaction anymore:
		    // it could have been deleted !!!
		       
		    // should we forward the ACK to SEMS-App upstream? Yes
		}
	    }
	    else {
		DBG("Found retransmission\n");
		retransmit(t);
	    }
	}
	else {

	    string t_id;
	    sip_trans* t = NULL;
	    if(msg->u.request->method != sip_request::ACK){
		
		// New transaction
		t = bucket->add_trans(msg, TT_UAS);

		t_id = int2hex(h).substr(5,string::npos) 
		    + ":" + long2hex((unsigned long)t);
	    }

	    bucket->unlock();
	    
	    //  let's pass the request to
	    //  the UA. 
	    assert(ua);
	    ua->handle_sip_request(t_id.c_str(),msg);

	    if(!t){
		DROP_MSG;
	    }
	    //Else:
	    // forget the msg: it will be
	    // owned by the new transaction
	    return;
	}
	break;
    
    case SIP_REPLY:

	if((t = bucket->match_reply(msg)) != NULL){

	    // Reply matched UAC transaction
	    
	    DBG("Reply matched an existing transaction\n");
	    if(update_uac_trans(bucket,t,msg) < 0){
		ERROR("update_uac_trans() failed, so what happens now???\n");
		break;
	    }
	    // do not touch the transaction anymore:
	    // it could have been deleted !!!
	}
	else {
	    DBG("Reply did NOT match any existing transaction...\n");
	    DBG("reply code = %i\n",msg->u.reply->code);
	    if( (msg->u.reply->code >= 200) &&
	        (msg->u.reply->code <  300) ) {
		
		bucket->unlock();
		
		// pass to UA
		assert(ua);
		ua->handle_sip_reply(msg);
		
		DROP_MSG;
	    }
	}
	break;

    default:
	ERROR("Got unknown message type: Bug?\n");
	break;
    }

    // unlock_drop:
    bucket->unlock();
    DROP_MSG;
}
int trans_layer::cancel(trans_bucket* bucket, sip_trans* t)
{
    bucket->lock();
    if(!bucket->exist(t)){
	DBG("No transaction to cancel: wrong key or finally replied\n");
	bucket->unlock();
	return 0;
    }

    sip_msg* req = t->msg;
    
    // RFC 3261 says: SHOULD NOT be sent for other request
    // than INVITE.
    if(req->u.request->method != sip_request::INVITE){
	bucket->unlock();
	ERROR("Trying to cancel a non-INVITE request (we SHOULD NOT do that)\n");
	return -1;
    }
    
    switch(t->state){
    case TS_CALLING:
	// do not send a request:
	// just remove the transaction
	bucket->remove_trans(t);
	bucket->unlock();
	return 0;

    case TS_COMPLETED:
	// final reply has been sent:
	// do nothing!!!
	bucket->unlock();
	return 0;
	
    case TS_PROCEEDING:
	// continue with CANCEL request
	break;
    }

    cstring cancel_str("CANCEL");

    int request_len = request_line_len(cancel_str,
				       req->u.request->ruri_str);

    char branch_buf[BRANCH_BUF_LEN];
    compute_branch(branch_buf,req->callid->value,get_cseq(req)->num_str);
    cstring branch(branch_buf,BRANCH_BUF_LEN);
    
    string via(transport->get_local_ip());
    if(transport->get_local_port() != 5060)
	via += ":" + int2str(transport->get_local_port());

    request_len += copy_hdr_len(req->via1);

    request_len += copy_hdr_len(req->to)
	+ copy_hdr_len(req->from)
	+ copy_hdr_len(req->callid)
	+ cseq_len(get_cseq(req)->num_str,cancel_str)
	+ copy_hdrs_len(req->route)
	+ copy_hdrs_len(req->contacts);

    request_len += 2/* CRLF end-of-headers*/;

    // Allocate new message
    sip_msg* p_msg = new sip_msg();
    p_msg->buf = new char[request_len];
    p_msg->len = request_len;

    // generate it
    char* c = p_msg->buf;
    request_line_wr(&c,cancel_str,
		    req->u.request->ruri_str);

    copy_hdr_wr(&c,req->via1);
    copy_hdr_wr(&c,req->to);
    copy_hdr_wr(&c,req->from);
    copy_hdr_wr(&c,req->callid);
    cseq_wr(&c,get_cseq(req)->num_str,cancel_str);
    copy_hdrs_wr(&c,req->route);
    copy_hdrs_wr(&c,req->contacts);

    *c++ = CR;
    *c++ = LF;

    // and parse it
    if(parse_sip_msg(p_msg)){
	ERROR("Parser failed on generated request\n");
	ERROR("Message was: <%.*s>\n",p_msg->len,p_msg->buf);
	delete p_msg;
	return MALFORMED_SIP_MSG;
    }

    memcpy(&p_msg->remote_ip,&req->remote_ip,sizeof(sockaddr_storage));

    DBG("Sending to %s:%i <%.*s>\n",
	get_addr_str(((sockaddr_in*)&p_msg->remote_ip)->sin_addr).c_str(),
	ntohs(((sockaddr_in*)&p_msg->remote_ip)->sin_port),
	p_msg->len,p_msg->buf);

    int send_err = transport->send(&p_msg->remote_ip,p_msg->buf,p_msg->len);
    if(send_err < 0){
	ERROR("Error from transport layer\n");
	delete p_msg;
    }
    else {
	trans_bucket* n_bucket = get_trans_bucket(p_msg->callid->value,
						  get_cseq(p_msg)->num_str);

	if(bucket != n_bucket)
	    n_bucket->lock();

	sip_trans* t = n_bucket->add_trans(p_msg,TT_UAC);
	    
	// if transport == UDP
	t->reset_timer(STIMER_E,E_TIMER,bucket->get_id());
	// for any transport type
	t->reset_timer(STIMER_F,F_TIMER,bucket->get_id());

	if(bucket != n_bucket)
	    n_bucket->unlock();
    }
    
    bucket->unlock();
    return send_err;
}
int trans_layer::send_request(sip_msg* msg, char* tid, unsigned int& tid_len)
{
    // Request-URI
    // To
    // From
    // Call-ID
    // CSeq
    // Max-Forwards
    // Via
    // Contact
    // Supported / Require
    // Content-Length / Content-Type
    
    assert(transport);

    tid_len = 0;

    if(set_next_hop(msg->route,msg->u.request->ruri_str,
		    &msg->remote_ip) < 0){
	// TODO: error handling
	DBG("set_next_hop failed\n");
	//delete msg;
	return -1;
    }

    // assume that msg->route headers are not in msg->hdrs
    msg->hdrs.insert(msg->hdrs.begin(),msg->route.begin(),msg->route.end());

    int request_len = request_line_len(msg->u.request->method_str,
				       msg->u.request->ruri_str);

    char branch_buf[BRANCH_BUF_LEN];
    compute_branch(branch_buf,msg->callid->value,msg->cseq->value);
    cstring branch(branch_buf,BRANCH_BUF_LEN);
    
    string via(transport->get_local_ip());
    if(transport->get_local_port() != 5060)
	via += ":" + int2str(transport->get_local_port());

    request_len += via_len(stl2cstr(via),branch);

    request_len += copy_hdrs_len(msg->hdrs);

    string content_len = int2str(msg->body.len);

    request_len += content_length_len(stl2cstr(content_len));
    request_len += 2/* CRLF end-of-headers*/;

    if(msg->body.len){
	request_len += msg->body.len;
    }

    // Allocate new message
    sip_msg* p_msg = new sip_msg();
    p_msg->buf = new char[request_len];
    p_msg->len = request_len;

    // generate it
    char* c = p_msg->buf;
    request_line_wr(&c,msg->u.request->method_str,
		    msg->u.request->ruri_str);

    via_wr(&c,stl2cstr(via),branch);
    copy_hdrs_wr(&c,msg->hdrs);

    content_length_wr(&c,stl2cstr(content_len));

    *c++ = CR;
    *c++ = LF;

    if(msg->body.len){
	memcpy(c,msg->body.s,msg->body.len);

	// Not needed by now as the message is finished
	//c += body.len;
    }

    // and parse it
    if(parse_sip_msg(p_msg)){
	ERROR("Parser failed on generated request\n");
	ERROR("Message was: <%.*s>\n",p_msg->len,p_msg->buf);
	delete p_msg;
	return MALFORMED_SIP_MSG;
    }

    memcpy(&p_msg->remote_ip,&msg->remote_ip,sizeof(sockaddr_storage));

    DBG("Sending to %s:%i <%.*s>\n",
	get_addr_str(((sockaddr_in*)&p_msg->remote_ip)->sin_addr).c_str(),
	ntohs(((sockaddr_in*)&p_msg->remote_ip)->sin_port),
	p_msg->len,p_msg->buf);

    trans_bucket* bucket = get_trans_bucket(p_msg->callid->value,
					    get_cseq(p_msg)->num_str);
    bucket->lock();

    int send_err = transport->send(&p_msg->remote_ip,p_msg->buf,p_msg->len);
    if(send_err < 0){
	ERROR("Error from transport layer\n");
	delete p_msg;
    }
    else {

	sip_trans* t = bucket->add_trans(p_msg,TT_UAC);
	if(p_msg->u.request->method == sip_request::INVITE){
	    
	    // if transport == UDP
	    t->reset_timer(STIMER_A,A_TIMER,bucket->get_id());
	    // for any transport type
	    t->reset_timer(STIMER_B,B_TIMER,bucket->get_id());
	}
	else {
	    
	    // if transport == UDP
	    t->reset_timer(STIMER_E,E_TIMER,bucket->get_id());
	    // for any transport type
	    t->reset_timer(STIMER_F,F_TIMER,bucket->get_id());

	}

	string t_id = int2hex(bucket->get_id()).substr(5,string::npos) 
	    + ":" + long2hex((unsigned long)t);
	memcpy(tid,t_id.c_str(),t_id.length());
	tid_len = t_id.length();
    }

    bucket->unlock();
    
    return send_err;
}