Skip to content
Snippets Groups Projects
chan_sip.c 482 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTUPDATE) &&
    	    (ast_test_flag(&p->flags[0], SIP_REALTIME) || rtcachefriends)) {
    
    		realtime_update_peer(p->name, &p->addr, p->username, rtcachefriends ? p->fullcontact : NULL, expiry);
    
    /*! \brief  realtime_peer: Get peer from realtime storage
    
     * Checks the "sippeers" realtime family from extconfig.conf 
     * \todo Consider adding check of port address when matching here to follow the same
     * 	algorithm as for static peers. Will we break anything by adding that?
    */
    
    static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
    {
    
    	struct sip_peer *peer = NULL;
    
    	struct ast_variable *var;
    	struct ast_variable *tmp;
    
    	char *newpeername = (char *) peername;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* First check on peer name */
    
    		var = ast_load_realtime("sippeers", "name", peername, NULL);
    
    	else if (sin) {	/* Then check on IP address for dynamic peers */
    
    		ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr);
    
    		var = ast_load_realtime("sippeers", "host", iabuf, NULL);	/* First check for fixed IP hosts */
    		if (!var)
    			var = ast_load_realtime("sippeers", "ipaddr", iabuf, NULL);	/* Then check for registred hosts */
    	
    
    	} else
    		return NULL;
    
    	if (!var)
    		return NULL;
    
    
    	for (tmp = var; tmp; tmp = tmp->next) {
    		/* If this is type=user, then skip this object. */
    
    		if (!strcasecmp(tmp->name, "type") &&
    		    !strcasecmp(tmp->value, "user")) {
    
    			ast_variables_destroy(var);
    
    			return NULL;
    
    		} else if (!newpeername && !strcasecmp(tmp->name, "name")) {
    
    	if (!newpeername) {	/* Did not find peer in realtime */
    		ast_log(LOG_WARNING, "Cannot Determine peer name ip=%s\n", iabuf);
    		ast_variables_destroy(var);
    
    	/* Peer found in realtime, now build it in memory */
    
    	peer = build_peer(newpeername, var, !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS));
    
    	if (!peer) {
    		ast_variables_destroy(var);
    
    	if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
    
    		/* Cache peer */
    
    		ast_copy_flags(&peer->flags[1],&global_flags[1], SIP_PAGE2_RTAUTOCLEAR|SIP_PAGE2_RTCACHEFRIENDS);
    		if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR)) {
    
    			if (peer->expire > -1) {
    				ast_sched_del(sched, peer->expire);
    
    			peer->expire = ast_sched_add(sched, (global_rtautoclear) * 1000, expire_register, (void *)peer);
    
    		ASTOBJ_CONTAINER_LINK(&peerl,peer);
    	} else {
    
    		ast_set_flag(&peer->flags[0], SIP_REALTIME);
    
    	ast_variables_destroy(var);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return peer;
    
    /*! \brief Support routine for find_peer */
    
    static int sip_addrcmp(char *name, struct sockaddr_in *sin)
    {
    	/* We know name is the first field, so we can cast */
    
    	struct sip_peer *p = (struct sip_peer *) name;
    
    	return 	!(!inaddrcmp(&p->addr, sin) || 
    
    					(ast_test_flag(&p->flags[0], SIP_INSECURE_PORT) &&
    
    					(p->addr.sin_addr.s_addr == sin->sin_addr.s_addr)));
    }
    
    
    /*! \brief Locate peer by name or ip address 
    
     *	This is used on incoming SIP message to find matching peer on ip
    
    	or outgoing message to find matching peer on name */
    
    static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime)
    
    {
    	struct sip_peer *p = NULL;
    
    
    		p = ASTOBJ_CONTAINER_FIND(&peerl, peer);
    
    		p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp);
    
    	if (!p && realtime) {
    
    		p = realtime_peer(peer, sin);
    
    /*! \brief Remove user object from in-memory storage */
    
    static void sip_destroy_user(struct sip_user *user)
    
    	if (option_debug > 2)
    		ast_log(LOG_DEBUG, "Destroying user object from memory: %s\n", user->name);
    
    	ast_free_ha(user->ha);
    
    	if (user->chanvars) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_variables_destroy(user->chanvars);
    		user->chanvars = NULL;
    
    	if (ast_test_flag(&user->flags[0], SIP_REALTIME))
    
    /*! \brief Load user from realtime storage
    
     * Loads user from "sipusers" category in realtime (extconfig.conf)
     * Users are matched on From: user name (the domain in skipped) */
    
    static struct sip_user *realtime_user(const char *username)
    {
    	struct ast_variable *var;
    	struct ast_variable *tmp;
    
    	struct sip_user *user = NULL;
    
    
    	var = ast_load_realtime("sipusers", "name", username, NULL);
    
    	for (tmp = var; tmp; tmp = tmp->next) {
    
    		if (!strcasecmp(tmp->name, "type") &&
    
    			!strcasecmp(tmp->value, "peer")) {
    
    			ast_variables_destroy(var);
    
    			return NULL;
    
    	user = build_user(username, var, !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS));
    
    	if (!user) {	/* No user found */
    		ast_variables_destroy(var);
    		return NULL;
    	}
    
    
    	if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
    		ast_set_flag(&user->flags[1], SIP_PAGE2_RTCACHEFRIENDS);
    
    		suserobjs++;
    
    		ASTOBJ_CONTAINER_LINK(&userl,user);
    	} else {
    
    		/* Move counter from s to r... */
    		suserobjs--;
    		ruserobjs++;
    
    		ast_set_flag(&user->flags[0], SIP_REALTIME);
    
    	ast_variables_destroy(var);
    
    /*! \brief Locate user by name 
    
     * Locates user by name (From: sip uri user name part) first
     * from in-memory list (static configuration) then from 
     * realtime storage (defined in extconfig.conf) */
    
    static struct sip_user *find_user(const char *name, int realtime)
    
    	struct sip_user *u = ASTOBJ_CONTAINER_FIND(&userl, name);
    	if (!u && realtime)
    
    		u = realtime_user(name);
    
    /*! \brief Create address structure from peer reference */
    
    static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer)
    {
    
    	if ((peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr) &&
    	    (!peer->maxms || ((peer->lastms >= 0)  && (peer->lastms <= peer->maxms)))) {
    
    		r->sa = (peer->addr.sin_addr.s_addr) ? peer->addr : peer->defaddr;
    		r->recv = r->sa;
    
    	ast_copy_flags(&r->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
    	ast_copy_flags(&r->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
    
    	r->capability = peer->capability;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	if (!ast_test_flag(&r->flags[1], SIP_PAGE2_VIDEOSUPPORT) && r->vrtp) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    		ast_rtp_destroy(r->vrtp);
    		r->vrtp = NULL;
    	}
    
    	ast_rtp_setdtmf(r->rtp, ast_test_flag(&r->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
    
    	natflags = ast_test_flag(&r->flags[0], SIP_NAT) & SIP_NAT_ROUTE;
    
    			ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", natflags);
    		ast_rtp_setnat(r->rtp, natflags);
    
    			ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", natflags);
    		ast_rtp_setnat(r->vrtp, natflags);
    
    	ast_string_field_set(r, peername, peer->username);
    	ast_string_field_set(r, authname, peer->username);
    	ast_string_field_set(r, username, peer->username);
    	ast_string_field_set(r, peersecret, peer->secret);
    	ast_string_field_set(r, peermd5secret, peer->md5secret);
    	ast_string_field_set(r, tohost, peer->tohost);
    	ast_string_field_set(r, fullcontact, peer->fullcontact);
    
    	if (!r->initreq.headers && !ast_strlen_zero(peer->fromdomain)) {
    
    		char *tmpcall;
    		char *c;
    		tmpcall = ast_strdupa(r->callid);
    
    		c = strchr(tmpcall, '@');
    		if (c) {
    			*c = '\0';
    			ast_string_field_build(r, callid, "%s@%s", tmpcall, peer->fromdomain);
    
    		ast_inet_ntoa(iabuf, sizeof(iabuf),  r->sa.sin_addr);
    
    		ast_string_field_set(r, tohost, iabuf);
    
    	}
    	if (!ast_strlen_zero(peer->fromdomain))
    
    		ast_string_field_set(r, fromdomain, peer->fromdomain);
    
    	if (!ast_strlen_zero(peer->fromuser))
    
    		ast_string_field_set(r, fromuser, peer->fromuser);
    
    	r->maxtime = peer->maxms;
    	r->callgroup = peer->callgroup;
    	r->pickupgroup = peer->pickupgroup;
    
    	r->allowtransfer = peer->allowtransfer;
    
    	/* Set timer T1 to RTT for this peer (if known by qualify=) */
    
    	/* Minimum is settable or default to 100 ms */
    
    	if (peer->maxms && peer->lastms)
    
    		r->timer_t1 = peer->lastms < global_t1min ? global_t1min : peer->lastms;
    
    	if ((ast_test_flag(&r->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
    	    (ast_test_flag(&r->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
    
    		r->noncodeccapability |= AST_RTP_DTMF;
    	else
    		r->noncodeccapability &= ~AST_RTP_DTMF;
    
    	ast_string_field_set(r, context, peer->context);
    
    	r->rtptimeout = peer->rtptimeout;
    	r->rtpholdtimeout = peer->rtpholdtimeout;
    	r->rtpkeepalive = peer->rtpkeepalive;
    
    		ast_set_flag(&r->flags[0], SIP_CALL_LIMIT);
    
    Olle Johansson's avatar
    Olle Johansson committed
    	r->maxcallbitrate = peer->maxcallbitrate;
    	
    
    /*! \brief create address structure from peer name
    
     *      Or, if peer not found, find it in the global DNS 
     *      returns TRUE (-1) on failure, FALSE on success */
    
    static int create_addr(struct sip_pvt *dialog, const char *opeer)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct hostent *hp;
    
    	struct ast_hostent ahp;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_peer *p;
    	int found=0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *port;
    
    	char host[MAXHOSTNAMELEN], *hostn;
    
    	ast_copy_string(peer, opeer, sizeof(peer));
    
    	dialog->sa.sin_family = AF_INET;
    	dialog->timer_t1 = 500; /* Default SIP retransmission timer T1 (RFC 3261) */
    
    	p = find_peer(peer, NULL, 1);
    
    		if (create_addr_from_peer(dialog, p))
    
    			ASTOBJ_UNREF(p, sip_destroy_peer);
    
    		portno = port ? atoi(port) : DEFAULT_SIP_PORT;
    
    			char service[MAXHOSTNAMELEN];
    
    			int tportno;
    			int ret;
    			snprintf(service, sizeof(service), "_sip._udp.%s", peer);
    			ret = ast_get_srv(NULL, host, sizeof(host), &tportno, service);
    			if (ret > 0) {
    				hostn = host;
    				portno = tportno;
    			}
    		}
    
    		hp = ast_gethostbyname(hostn, &ahp);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (hp) {
    
    			ast_string_field_set(dialog, tohost, peer);
    
    			memcpy(&dialog->sa.sin_addr, hp->h_addr, sizeof(dialog->sa.sin_addr));
    			dialog->sa.sin_port = htons(portno);
    
    			dialog->recv = dialog->sa;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return 0;
    		} else {
    			ast_log(LOG_WARNING, "No such host: %s\n", peer);
    			return -1;
    		}
    
    	} else {
    		ASTOBJ_UNREF(p, sip_destroy_peer);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    
    /*! \brief Scheduled congestion on a call */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int auto_congest(void *nothing)
    {
    	struct sip_pvt *p = nothing;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p->initid = -1;
    	if (p->owner) {
    
    		/* XXX fails on possible deadlock */
    
    		if (!ast_channel_trylock(p->owner)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name);
    
    			ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
    
    			ast_channel_unlock(p->owner);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    /*! \brief Initiate SIP call from PBX 
    
     *      used from the dial() application      */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_call(struct ast_channel *ast, char *dest, int timeout)
    {
    	int res;
    	struct sip_pvt *p;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct varshead *headp;
    	struct ast_var_t *current;
    
    	const char *referer = NULL;   /* SIP refererer */	
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "sip_call called on %s, neither down nor reserved\n", ast->name);
    		return -1;
    	}
    
    	/* Check whether there is vxml_url, distinctive ring variables */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	headp=&ast->varshead;
    	AST_LIST_TRAVERSE(headp,current,entries) {
    
    		/* Check whether there is a VXML_URL variable */
    
    		if (!p->options->vxml_url && !strcasecmp(ast_var_name(current), "VXML_URL")) {
    			p->options->vxml_url = ast_var_value(current);
    
    Olle Johansson's avatar
    Olle Johansson committed
    		} else if (!p->options->uri_options && !strcasecmp(ast_var_name(current), "SIP_URI_OPTIONS")) {
    			p->options->uri_options = ast_var_value(current);
    
    		} else if (!p->options->distinctive_ring && !strcasecmp(ast_var_name(current), "ALERT_INFO")) {
    
    			/* Check whether there is a ALERT_INFO variable */
    
    			p->options->distinctive_ring = ast_var_value(current);
    		} else if (!p->options->addsipheaders && !strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
    
    			/* Check whether there is a variable with a name starting with SIPADDHEADER */
    
    		} else if (!strcasecmp(ast_var_name(current),"SIPTRANSFER")) {
    			/* This is a transfered call */
    			p->options->transfer = 1;
    		} else if (!strcasecmp(ast_var_name(current),"SIPTRANSFER_REFERER")) {
    			/* This is the referer */
    			referer = ast_var_value(current);
    		} else if (!strcasecmp(ast_var_name(current),"SIPTRANSFER_REPLACES")) {
    			/* We're replacing a call. */
    			p->options->replaces = ast_var_value(current);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	res = 0;
    
    	ast_set_flag(&p->flags[0], SIP_OUTGOING);
    
    
    	if (p->options->transfer) {
    		char buf[BUFSIZ/2];
    
    		if (referer) {
    			if (sipdebug && option_debug > 2)
    				ast_log(LOG_DEBUG, "Call for %s transfered by %s\n", p->username, referer);
    			snprintf(buf, sizeof(buf)-1, "-> %s (via %s)", p->cid_name, referer);
    		} else {
    			snprintf(buf, sizeof(buf)-1, "-> %s", p->cid_name);
    		}
    		ast_string_field_set(p, cid_name, buf);
    	} 
    
    	if (option_debug)
    		ast_log(LOG_DEBUG, "Outgoing Call for %s\n", p->username);
    
    	res = update_call_counter(p, INC_CALL_LIMIT);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if ( res != -1 ) {
    
    		p->callingpres = ast->cid.cid_pres;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		p->jointcapability = p->capability;
    
    		transmit_invite(p, SIP_INVITE, 1, 2);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (p->maxtime) {
    			/* Initialize auto-congest time */
    
    			p->initid = ast_sched_add(sched, p->maxtime * 4, auto_congest, p);
    
    		} else {
    			p->initid = ast_sched_add(sched, SIP_TRANS_TIMEOUT, auto_congest, p);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    /*! \brief Destroy registry object
    	Objects created with the register= statement in static configuration */
    
    static void sip_registry_destroy(struct sip_registry *reg)
    {
    	/* Really delete */
    
    	if (option_debug > 2)
    		ast_log(LOG_DEBUG, "Destroying registry entry for %s@%s\n", reg->username, reg->hostname);
    
    
    	if (reg->call) {
    		/* Clear registry before destroying to ensure
    		   we don't get reentered trying to grab the registry lock */
    		reg->call->registry = NULL;
    
    		if (option_debug > 2)
    			ast_log(LOG_DEBUG, "Destroying active SIP dialog for registry %s@%s\n", reg->username, reg->hostname);
    
    		sip_destroy(reg->call);
    	}
    	if (reg->expire > -1)
    		ast_sched_del(sched, reg->expire);
    	if (reg->timeout > -1)
    		ast_sched_del(sched, reg->timeout);
    
    	ast_string_field_free_all(reg);
    
    /*! \brief Execute destruction of SIP dialog structure, release memory */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void __sip_destroy(struct sip_pvt *p, int lockowner)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sip_pvt *cur, *prev = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_pkt *cp;
    
    	if (sip_debug_test_pvt(p) || option_debug > 2)
    		ast_verbose("Really destroying SIP dialog '%s' Method: %s\n", p->callid, sip_methods[p->method].text);
    
    	/* Remove link from peer to subscription of MWI */
    	if (p->relatedpeer && p->relatedpeer->mwipvt)
    
    		p->relatedpeer->mwipvt = NULL;
    
    	if (dumphistory)
    		sip_dump_history(p);
    
    
    	if (p->stateid > -1)
    		ast_extension_state_del(p->stateid, NULL);
    
    	if (p->initid > -1)
    		ast_sched_del(sched, p->initid);
    	if (p->autokillid > -1)
    		ast_sched_del(sched, p->autokillid);
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	if (p->rtp)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_rtp_destroy(p->rtp);
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	if (p->vrtp)
    
    	if (p->refer)
    		free(p->refer);
    
    	if (p->route) {
    		free_old_route(p->route);
    		p->route = NULL;
    	}
    
    		if (p->registry->call == p)
    			p->registry->call = NULL;
    
    		ASTOBJ_UNREF(p->registry, sip_registry_destroy);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Unlink us from the owner if we have one */
    	if (p->owner) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (lockowner)
    
    			ast_channel_lock(p->owner);
    
    		if (option_debug)
    			ast_log(LOG_DEBUG, "Detaching from %s\n", p->owner->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (lockowner)
    
    			ast_channel_unlock(p->owner);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    		struct sip_history *hist;
    		while( (hist = AST_LIST_REMOVE_HEAD(p->history, list)) )
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	for (prev = NULL, cur = iflist; cur; prev = cur, cur = cur->next) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (cur == p) {
    
    			UNLINK(cur, iflist, prev);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			break;
    		}
    	}
    	if (!cur) {
    
    		ast_log(LOG_WARNING, "Trying to destroy \"%s\", not found in dialog list?!?! \n", p->callid);
    		return;
    	} 
    	if (p->initid > -1)
    		ast_sched_del(sched, p->initid);
    
    	while((cp = p->packets)) {
    		p->packets = p->packets->next;
    
    		if (cp->retransid > -1)
    
    			ast_sched_del(sched, cp->retransid);
    		free(cp);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	if (p->chanvars) {
    		ast_variables_destroy(p->chanvars);
    		p->chanvars = NULL;
    	}
    
    	ast_mutex_destroy(&p->lock);
    
    /*! \brief  update_call_counter: Handle call_limit for SIP users 
    
     * Setting a call-limit will cause calls above the limit not to be accepted.
     *
     * Remember that for a type=friend, there's one limit for the user and
     * another for the peer, not a combined call limit.
     * This will cause unexpected behaviour in subscriptions, since a "friend"
     * is *two* devices in Asterisk, not one.
     *
     * Thought: For realtime, we should propably update storage with inuse counter... 
    
     *
     * \return 0 if call is ok (no call limit, below treshold)
     *	-1 on rejection of call
     *		
    
    static int update_call_counter(struct sip_pvt *fup, int event)
    
    	int outgoing = ast_test_flag(&fup->flags[0], SIP_OUTGOING);
    
    	struct sip_user *u = NULL;
    	struct sip_peer *p = NULL;
    
    	if (option_debug > 2)
    		ast_log(LOG_DEBUG, "Updating call counter for %s call\n", outgoing ? "outgoing" : "incoming");
    
    	/* Test if we need to check call limits, in order to avoid 
    	   realtime lookups if we do not need it */
    
    	if (!ast_test_flag(&fup->flags[0], SIP_CALL_LIMIT))
    
    	ast_copy_string(name, fup->username, sizeof(name));
    
    	if (!outgoing)	/* Only check users for incoming calls */
    		u = find_user(name, 1);
    
    
    		if (!p)
    			p = find_peer(fup->peername, NULL, 1);
    
    			ast_copy_string(name, fup->peername, sizeof(name));
    
    			if (option_debug > 1)
    				ast_log(LOG_DEBUG, "%s is not a local user, no call limit\n", name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	switch(event) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* incoming and outgoing affects the inUse counter */
    
    				if (ast_test_flag(&fup->flags[0], SIP_INC_COUNT))
    
    Olle Johansson's avatar
    Olle Johansson committed
    					(*inuse)--;
    
    			} else {
    
    				ast_log(LOG_DEBUG, "Call %s %s '%s' removed from call limit %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *call_limit);
    			}
    
    		case INC_CALL_LIMIT:
    			if (*call_limit > 0 ) {
    				if (*inuse >= *call_limit) {
    					ast_log(LOG_ERROR, "Call %s %s '%s' rejected due to usage limit of %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *call_limit);
    
    						ASTOBJ_UNREF(u, sip_destroy_user);
    
    						ASTOBJ_UNREF(p, sip_destroy_peer);
    
    			ast_set_flag(&fup->flags[0], SIP_INC_COUNT);
    
    				ast_log(LOG_DEBUG, "Call %s %s '%s' is %d out of %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *inuse, *call_limit);
    			}
    
    			break;
    		default:
    
    			ast_log(LOG_ERROR, "update_call_counter(%s, %d) called with no event!\n", name, event);
    
    		ASTOBJ_UNREF(u, sip_destroy_user);
    
    		ASTOBJ_UNREF(p, sip_destroy_peer);
    
    /*! \brief Destroy SIP call structure */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void sip_destroy(struct sip_pvt *p)
    {
    
    	if (option_debug > 2)
    		ast_log(LOG_DEBUG, "Destroying SIP dialog %s\n", p->callid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	__sip_destroy(p, 1);
    
    /*! \brief Convert SIP hangup causes to Asterisk hangup causes */
    
    	/* Possible values taken from causes.h */
    
    
    	switch(cause) {
    
    		case 401:	/* Unauthorized */
    			return AST_CAUSE_CALL_REJECTED;
    
    		case 403:	/* Not found */
    
    			return AST_CAUSE_CALL_REJECTED;
    
    		case 404:	/* Not found */
    
    			return AST_CAUSE_UNALLOCATED;
    
    		case 405:	/* Method not allowed */
    			return AST_CAUSE_INTERWORKING;
    		case 407:	/* Proxy authentication required */
    			return AST_CAUSE_CALL_REJECTED;
    
    		case 408:	/* No reaction */
    
    			return AST_CAUSE_NO_USER_RESPONSE;
    
    		case 409:	/* Conflict */
    			return AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
    		case 410:	/* Gone */
    			return AST_CAUSE_UNALLOCATED;
    		case 411:	/* Length required */
    			return AST_CAUSE_INTERWORKING;
    		case 413:	/* Request entity too large */
    			return AST_CAUSE_INTERWORKING;
    		case 414:	/* Request URI too large */
    			return AST_CAUSE_INTERWORKING;
    		case 415:	/* Unsupported media type */
    			return AST_CAUSE_INTERWORKING;
    		case 420:	/* Bad extension */
    			return AST_CAUSE_NO_ROUTE_DESTINATION;
    
    		case 480:	/* No answer */
    
    			return AST_CAUSE_NO_ANSWER;
    
    		case 481:	/* No answer */
    			return AST_CAUSE_INTERWORKING;
    		case 482:	/* Loop detected */
    			return AST_CAUSE_INTERWORKING;
    
    		case 483:	/* Too many hops */
    
    			return AST_CAUSE_NO_ANSWER;
    
    		case 484:	/* Address incomplete */
    			return AST_CAUSE_INVALID_NUMBER_FORMAT;
    		case 485:	/* Ambigous */
    			return AST_CAUSE_UNALLOCATED;
    
    		case 486:	/* Busy everywhere */
    
    		case 487:	/* Request terminated */
    			return AST_CAUSE_INTERWORKING;
    
    		case 488:	/* No codecs approved */
    			return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
    
    		case 491:	/* Request pending */
    			return AST_CAUSE_INTERWORKING;
    		case 493:	/* Undecipherable */
    			return AST_CAUSE_INTERWORKING;
    
    		case 500:	/* Server internal failure */
    			return AST_CAUSE_FAILURE;
    		case 501:	/* Call rejected */
    			return AST_CAUSE_FACILITY_REJECTED;
    		case 502:	
    			return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
    		case 503:	/* Service unavailable */
    			return AST_CAUSE_CONGESTION;
    
    		case 504:	/* Gateway timeout */
    			return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
    		case 505:	/* SIP version not supported */
    			return AST_CAUSE_INTERWORKING;
    		case 600:	/* Busy everywhere */
    			return AST_CAUSE_USER_BUSY;
    		case 603:	/* Decline */
    			return AST_CAUSE_CALL_REJECTED;
    		case 604:	/* Does not exist anywhere */
    			return AST_CAUSE_UNALLOCATED;
    		case 606:	/* Not acceptable */
    			return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
    
    /*! \brief Convert Asterisk hangup causes to SIP codes 
    
    \verbatim
     Possible values from causes.h
    
            AST_CAUSE_NOTDEFINED    AST_CAUSE_NORMAL        AST_CAUSE_BUSY
            AST_CAUSE_FAILURE       AST_CAUSE_CONGESTION    AST_CAUSE_UNALLOCATED
    
    	In addition to these, a lot of PRI codes is defined in causes.h 
    	...should we take care of them too ?
    	
    	Quote RFC 3398
    
       ISUP Cause value                        SIP response
       ----------------                        ------------
       1  unallocated number                   404 Not Found
       2  no route to network                  404 Not found
       3  no route to destination              404 Not found
       16 normal call clearing                 --- (*)
       17 user busy                            486 Busy here
       18 no user responding                   408 Request Timeout
       19 no answer from the user              480 Temporarily unavailable
       20 subscriber absent                    480 Temporarily unavailable
       21 call rejected                        403 Forbidden (+)
       22 number changed (w/o diagnostic)      410 Gone
       22 number changed (w/ diagnostic)       301 Moved Permanently
       23 redirection to new destination       410 Gone
       26 non-selected user clearing           404 Not Found (=)
       27 destination out of order             502 Bad Gateway
       28 address incomplete                   484 Address incomplete
       29 facility rejected                    501 Not implemented
       31 normal unspecified                   480 Temporarily unavailable
    
    \endverbatim
    
    static const char *hangup_cause2sip(int cause)
    
    		case AST_CAUSE_UNALLOCATED:		/* 1 */
    		case AST_CAUSE_NO_ROUTE_DESTINATION:	/* 3 IAX2: Can't find extension in context */
    		case AST_CAUSE_NO_ROUTE_TRANSIT_NET:	/* 2 */
    			return "404 Not Found";
    
    Olle Johansson's avatar
    Olle Johansson committed
    		case AST_CAUSE_CONGESTION:		/* 34 */
    		case AST_CAUSE_SWITCH_CONGESTION:	/* 42 */
    			return "503 Service Unavailable";
    
    		case AST_CAUSE_NO_USER_RESPONSE:	/* 18 */
    			return "408 Request Timeout";
    		case AST_CAUSE_NO_ANSWER:		/* 19 */
    			return "480 Temporarily unavailable";
    		case AST_CAUSE_CALL_REJECTED:		/* 21 */
    			return "403 Forbidden";
    		case AST_CAUSE_NUMBER_CHANGED:		/* 22 */
    			return "410 Gone";
    		case AST_CAUSE_NORMAL_UNSPECIFIED:	/* 31 */
    			return "480 Temporarily unavailable";
    		case AST_CAUSE_INVALID_NUMBER_FORMAT:
    			return "484 Address incomplete";
    		case AST_CAUSE_USER_BUSY:
    			return "486 Busy here";
    
    		case AST_CAUSE_FAILURE:
    
    Olle Johansson's avatar
    Olle Johansson committed
    			return "500 Server internal failure";
    
    		case AST_CAUSE_FACILITY_REJECTED:	/* 29 */
    			return "501 Not Implemented";
    		case AST_CAUSE_CHAN_NOT_IMPLEMENTED:
    
    			return "503 Service Unavailable";
    
    		/* Used in chan_iax2 */
    		case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
    
    			return "502 Bad Gateway";
    
    		case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL:	/* Can't find codec to connect to host */
    
    			return "488 Not Acceptable Here";
    
    			ast_log(LOG_DEBUG, "AST hangup cause %d (no match found in SIP)\n", cause);
    
     * Part of PBX interface, called from ast_hangup */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_hangup(struct ast_channel *ast)
    {
    
    	int needcancel = FALSE;
    
    	struct ast_flags locflags = {0};
    
    		ast_log(LOG_DEBUG, "Asked to hangup channel that was not connected\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    	}
    
    Olle Johansson's avatar
    Olle Johansson committed
    	if (option_debug && sipdebug)
    
    		ast_log(LOG_DEBUG, "Hangup call %s, SIP callid %s)\n", ast->name, p->callid);
    
    
    Olle Johansson's avatar
    Olle Johansson committed
    	if (option_debug && sipdebug)
    		ast_log(LOG_DEBUG, "update_call_counter(%s) - decrement call limit counter on hangup\n", p->username);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Determine how to disconnect */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (p->owner != ast) {
    
    		ast_log(LOG_WARNING, "Huh?  We aren't the owner? Can't hangup call.\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    	}
    
    	/* If the call is not UP, we need to send CANCEL instead of BYE */
    
    		needcancel = TRUE;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Disconnect */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_dsp_free(p->vad);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p->owner = NULL;
    
    	ast_mutex_lock(&usecnt_lock);
    	usecnt--;
    	ast_mutex_unlock(&usecnt_lock);
    	ast_update_use_count();
    
    
    	ast_set_flag(&locflags, SIP_NEEDDESTROY);	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Start the process if it's not already started */
    
    	if (!ast_test_flag(&p->flags[0], SIP_ALREADYGONE) && !ast_strlen_zero(p->initreq.data)) {
    
    			if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
    
    				/* stop retransmitting an INVITE that has not received a response */
    				__sip_pretend_ack(p);
    
    				/* Send a new request: CANCEL */
    
    Olle Johansson's avatar
    Olle Johansson committed
    				transmit_request_with_auth(p, SIP_CANCEL, p->ocseq, XMIT_RELIABLE, FALSE);
    
    				/* Actually don't destroy us yet, wait for the 487 on our original 
    
    				   INVITE, but do set an autodestruct just in case we never get it. */
    
    				ast_clear_flag(&locflags, SIP_NEEDDESTROY);
    
    				sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				if ( p->initid != -1 ) {
    					/* channel still up - reverse dec of inUse counter
    					   only if the channel is not auto-congested */
    
    Mark Spencer's avatar
    Mark Spencer committed
    				}
    
    				const char *res;
    				if (ast->hangupcause && (res = hangup_cause2sip(ast->hangupcause)))
    
    					transmit_response_reliable(p, res, &p->initreq);
    
    					transmit_response_reliable(p, "603 Declined", &p->initreq);
    
    			if (!p->pendinginvite) {
    				/* Send a hangup */
    
    				transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
    
    				/* Note we will need a BYE when this all settles out
    				   but we can't send one while we have "INVITE" outstanding. */
    
    				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
    				ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);	
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    	ast_copy_flags(&p->flags[0], &locflags, SIP_NEEDDESTROY);	
    
    /*! \brief Try setting codec suggested by the SIP_CODEC channel variable */
    static void try_suggested_sip_codec(struct sip_pvt *p)
    {
    	int fmt;
    	const char *codec;
    
    	codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC");
    	if (!codec) 
    		return;
    
    	fmt = ast_getformatbyname(codec);
    	if (fmt) {
    		ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC) variable\n", codec);
    		if (p->jointcapability & fmt) {
    			p->jointcapability &= fmt;
    			p->capability &= fmt;
    		} else
    			ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because it is not shared by both ends.\n");
    	} else
    		ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized/not configured codec (check allow/disallow in sip.conf): %s\n", codec);
    	return;	
    }
    
    
    /*! \brief  sip_answer: Answer SIP call , send 200 OK on Invite 
     * Part of PBX interface */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_answer(struct ast_channel *ast)
    {
    
    	ast_mutex_lock(&p->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (ast->_state != AST_STATE_UP) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_setstate(ast, AST_STATE_UP);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (option_debug)
    
    			ast_log(LOG_DEBUG, "SIP answering channel: %s\n", ast->name);
    
    		res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
    
    	ast_mutex_unlock(&p->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    /*! \brief Send frame to media channel (rtp) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res = 0;
    
    	switch (frame->frametype) {
    	case AST_FRAME_VOICE:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!(frame->subclass & ast->nativeformats)) {
    			ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
    				frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    				/* If channel is not up, activate early media session */
    
    				if ((ast->_state != AST_STATE_UP) &&
    				    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
    				    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
    
    					transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
    
    					ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);	
    
    				time(&p->lastrtptx);
    
    				res =  ast_rtp_write(p->rtp, frame);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    		break;
    	case AST_FRAME_VIDEO:
    
    				/* Activate video early media */
    
    				if ((ast->_state != AST_STATE_UP) &&
    				    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
    				    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
    
    					transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
    
    					ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);	
    
    				time(&p->lastrtptx);
    
    				res =  ast_rtp_write(p->vrtp, frame);
    			}
    
    		break;
    	case AST_FRAME_IMAGE:
    
    		ast_log(LOG_WARNING, "Can't send %d type frames with SIP write\n", frame->frametype);
    		return 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    
    /*! \brief  sip_fixup: Fix up a channel:  If a channel is consumed, this is called.
    
            Basically update any ->owner links */
    
    static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
    
    	struct sip_pvt *p;
    
    	if (!newchan || !newchan->tech_pvt) {
    		ast_log(LOG_WARNING, "No SIP tech_pvt! Fixup of %s failed.\n", oldchan->name);
    		return -1;
    	}
    	p = newchan->tech_pvt;
    
    	append_history(p, "Masq", "Old channel: %s\n", oldchan->name);