[svn-commits] oej: branch oej/darjeeling-prack-1.8 r369599 - /team/oej/darjeeling-prack-1.8...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Jul 4 03:08:43 CDT 2012


Author: oej
Date: Wed Jul  4 03:08:41 2012
New Revision: 369599

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=369599
Log:
Adding a patch for Pavel Troller

Added:
    team/oej/darjeeling-prack-1.8/patches/
    team/oej/darjeeling-prack-1.8/patches/darjeeling-prack-1.8.diff   (with props)

Added: team/oej/darjeeling-prack-1.8/patches/darjeeling-prack-1.8.diff
URL: http://svnview.digium.com/svn/asterisk/team/oej/darjeeling-prack-1.8/patches/darjeeling-prack-1.8.diff?view=auto&rev=369599
==============================================================================
--- team/oej/darjeeling-prack-1.8/patches/darjeeling-prack-1.8.diff (added)
+++ team/oej/darjeeling-prack-1.8/patches/darjeeling-prack-1.8.diff Wed Jul  4 03:08:41 2012
@@ -1,0 +1,1102 @@
+Index: channels/chan_sip.c
+===================================================================
+--- channels/chan_sip.c	(.../branches/1.8)	(revision 369561)
++++ channels/chan_sip.c	(.../team/oej/darjeeling-prack-1.8)	(revision 369561)
+@@ -1242,10 +1242,10 @@
+ static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
+ static int retrans_pkt(const void *data);
+ static int transmit_response_using_temp(ast_string_field callid, struct ast_sockaddr *addr, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg);
+-static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req);
+ static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req);
+ static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req);
+ static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid);
++static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req);
+ static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported);
+ static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
+ static int transmit_provisional_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, int with_sdp);
+@@ -1266,6 +1266,7 @@
+ static int transmit_cc_notify(struct ast_cc_agent *agent, struct sip_pvt *subscription, enum sip_cc_notify_state state);
+ static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader);
+ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, uint32_t seqno);
++static void add_required_respheader(struct sip_request *req);
+ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, uint32_t seqno);
+ static void copy_request(struct sip_request *dst, const struct sip_request *src);
+ static void receive_message(struct sip_pvt *p, struct sip_request *req);
+@@ -3785,6 +3786,9 @@
+ 		if (sscanf(ast_str_buffer(pkt->data), "SIP/2.0 %30u", &respid) == 1) {
+ 			pkt->response_code = respid;
+ 		}
++		if (ast_test_flag(&p->flags[2], SIP_PAGE3_100REL) && respid > 100 && respid < 200) {
++			pkt->rseqno = p->rseq;
++		}
+ 	}
+ 	pkt->timer_t1 = p->timer_t1;	/* Set SIP timer T1 */
+ 	pkt->retransid = -1;
+@@ -3966,7 +3970,7 @@
+ 
+ /*! \brief Acknowledges receipt of a packet and stops retransmission
+  * called with p locked*/
+-int __sip_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod)
++int __sip_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod, int rseqno)
+ {
+ 	struct sip_pkt *cur, *prev = NULL;
+ 	const char *msg = "Not Found";	/* used only for debugging */
+@@ -3985,6 +3989,10 @@
+ 		if (cur->seqno != seqno || cur->is_resp != resp) {
+ 			continue;
+ 		}
++		/* With PRACK we can have a situation with multiple unPRACKed responses */
++		if (rseqno && cur->rseqno != rseqno) {
++			continue;
++		}
+ 		if (cur->is_resp || cur->method == sipmethod) {
+ 			res = TRUE;
+ 			msg = "Found";
+@@ -3996,6 +4004,7 @@
+ 				if (sipdebug)
+ 					ast_debug(4, "** SIP TIMER: Cancelling retransmit of packet (reply received) Retransid #%d\n", cur->retransid);
+ 			}
++
+ 			/* This odd section is designed to thwart a
+ 			 * race condition in the packet scheduler. There are
+ 			 * two conditions under which deleting the packet from the
+@@ -4026,8 +4035,8 @@
+ 			break;
+ 		}
+ 	}
+-	ast_debug(1, "Stopping retransmission on '%s' of %s %u: Match %s\n",
+-		p->callid, resp ? "Response" : "Request", seqno, msg);
++	ast_debug(1, "Stopping retransmission on '%s' of %s %u: Match %s Rseq %d\n",
++		p->callid, resp ? "Response" : "Request", seqno, msg, rseqno);
+ 	return res;
+ }
+ 
+@@ -4045,7 +4054,7 @@
+ 		}
+ 		cur = p->packets;
+ 		method = (cur->method) ? cur->method : find_sip_method(cur->data->str);
+-		__sip_ack(p, cur->seqno, cur->is_resp, method);
++		__sip_ack(p, cur->seqno, cur->is_resp, method, cur->rseqno);
+ 	}
+ }
+ 
+@@ -4158,11 +4167,63 @@
+ 		with_sdp ? send_provisional_keepalive_with_sdp : send_provisional_keepalive, dialog_ref(pvt, "Increment refcount to pass dialog pointer to sched callback"));
+ }
+ 
++/*! \brief Adds a Required header 
++
++	Needs to be called before attachment (i.e. SDP) is added
++*/
++static void add_required_respheader(struct sip_request *req)
++{
++	if (req->reqsipoptions) {
++		char buf[SIPBUFSIZE] = "";
++		int i;
++
++		ast_debug(2, "=!=!=!=!= Plenty of required options for this message \n");
++
++		for (i = 0; i < ARRAY_LEN(sip_options); i++) {
++			if (req->reqsipoptions & sip_options[i].id) {
++				if (buf[0] != '\0') {
++					strncat(buf, ", ", sizeof(buf));
++				}
++				strncat(buf, sip_options[i].text, sizeof(buf));
++				ast_debug(3, "Found required response SIP option: %s\n", sip_options[i].text);
++			}
++		}
++		add_header(req, "Require", buf);
++	} else {
++		ast_debug(2, "=!=!=!=!= No required options for this message \n");
++	}
++
++}
++
++/*! \brief Active PRACK if supported by config and by other end */
++static void add_prack_respheader(struct sip_pvt *p, struct sip_request *req, int reliable)
++{
++	/* If method is INVITE and it contains Supported: 100 rel and we have enabled PRACK */
++	if (ast_test_flag(&p->flags[2], SIP_PAGE3_100REL)) {
++		/* Check if the invite has 100 REL supported here */
++		if (reliable == XMIT_PRACK) {
++			char buf[SIPBUFSIZE/2];
++			if (p->rseq == 0) {
++				p->rseq = 41; /* Starting level. Hi Douglas */
++			}
++			snprintf(buf, sizeof(buf), "%d", ++(p->rseq));
++			add_header(req, "Rseq", buf);
++			req->rseqno = p->rseq;
++			req->reqsipoptions |= SIP_OPT_100REL;
++			append_history(p, "PRACK", "PRACK Required: Our Rseq %d", p->rseq);
++			ast_debug(2, "=!=!=!=!=!=!=!= PRACK USED HERE. Rseq %d \n", p->rseq);
++		} else {
++			ast_debug(2, "=!=!=!=!=!=!=!= PRACK COULD BE USED HERE. Exactly HERE\n");
++		}
++	}
++}
++
+ /*! \brief Transmit response on SIP request*/
+ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, uint32_t seqno)
+ {
+ 	int res;
+ 
++
+ 	finalize_content(req);
+ 	add_blank(req);
+ 	if (sip_debug_test_pvt(p)) {
+@@ -6225,21 +6286,6 @@
+ 	return 0;
+ }
+ 
+-static int reinvite_timeout(const void *data)
+-{
+-	struct sip_pvt *dialog = (struct sip_pvt *) data;
+-	struct ast_channel *owner = sip_pvt_lock_full(dialog);
+-	check_pendings(dialog);
+-	dialog->reinviteid = -1;
+-	if (owner) {
+-		ast_channel_unlock(owner);
+-		ast_channel_unref(owner);
+-	}
+-	ao2_unlock(dialog);
+-	dialog_unref(dialog, "unref for reinvite timeout");
+-	return 0;
+-}
+-
+ /*! \brief  sip_hangup: Hangup SIP call
+  * Part of PBX interface, called from ast_hangup */
+ static int sip_hangup(struct ast_channel *ast)
+@@ -6367,7 +6413,7 @@
+ 				stop_session_timer(p);
+ 			}
+ 
+-			if (!p->pendinginvite) {
++			if (!p->pendinginvite || p->ongoing_reinvite) {
+ 				struct ast_channel *bridge = ast_bridged_channel(oldowner);
+ 				char quality_buf[AST_MAX_USER_FIELD], *quality;
+ 
+@@ -6429,16 +6475,8 @@
+ 				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
+ 				ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);	
+ 				AST_SCHED_DEL_UNREF(sched, p->waitid, dialog_unref(p, "when you delete the waitid sched, you should dec the refcount for the stored dialog ptr"));
+-				if (sip_cancel_destroy(p)) {
++				if (sip_cancel_destroy(p))
+ 					ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
+-				}
+-				/* If we have an ongoing reinvite, there is a chance that we have gotten a provisional
+-				 * response, but something weird has happened and we will never receive a final response.
+-				 * So, just in case, check for pending actions after a bit of time to trigger the pending
+-				 * bye that we are setting above */
+-				if (p->ongoing_reinvite && p->reinviteid < 0) {
+-					p->reinviteid = ast_sched_add(sched, 32 * p->timer_t1, reinvite_timeout, dialog_ref(p, "ref for reinvite_timeout"));
+-				}
+ 			}
+ 		}
+ 	}
+@@ -6485,7 +6523,13 @@
+ 	struct sip_pvt *p = ast->tech_pvt;
+ 
+ 	sip_pvt_lock(p);
+-	if (ast->_state != AST_STATE_UP) {
++	if (ast->_state != AST_STATE_UP && ast_test_flag(&p->flags[2], SIP_PAGE3_INVITE_WAIT_FOR_PRACK)) {
++		ast_set_flag(&p->flags[2], SIP_PAGE3_ANSWER_WAIT_FOR_PRACK);
++		ast_debug(2, "<-<-<--<-<-<-< HOLDING Answer while waiting for PRACK to arrive on channel %s\n", ast->name);
++		sip_pvt_unlock(p);
++		return 0;
++	}
++	if (ast->_state != AST_STATE_UP || ast_test_flag(&p->flags[2], SIP_PAGE3_INVITE_WAIT_FOR_PRACK)) {
+ 		try_suggested_sip_codec(p);	
+ 
+ 		ast_setstate(ast, AST_STATE_UP);
+@@ -7711,7 +7755,6 @@
+ 	p->method = intended_method;
+ 	p->initid = -1;
+ 	p->waitid = -1;
+-	p->reinviteid = -1;
+ 	p->autokillid = -1;
+ 	p->request_queue_sched_id = -1;
+ 	p->provisional_keepalive_sched_id = -1;
+@@ -9871,13 +9914,15 @@
+  *  is supported for this dialog. */
+ static int add_supported_header(struct sip_pvt *pvt, struct sip_request *req)
+ {
+-	int res;
++	char supported[256] = "replaces";
++
+ 	if (st_get_mode(pvt, 0) != SESSION_TIMER_MODE_REFUSE) {
+-		res = add_header(req, "Supported", "replaces, timer");
+-	} else {
+-		res = add_header(req, "Supported", "replaces");
++		strncat(supported, ", timer", sizeof(supported));
++	} 
++	if (ast_test_flag(&pvt->flags[2], SIP_PAGE3_PRACK)) {
++		strncat(supported, ", 100rel", sizeof(supported));
+ 	}
+-	return res;
++	return add_header(req, "Supported", supported);
+ }
+ 
+ /*! \brief Add header to SIP message */
+@@ -10313,6 +10358,7 @@
+ 		snprintf(se_hdr, sizeof(se_hdr), "%d;refresher=%s", p->stimer->st_interval,
+ 			strefresher2str(p->stimer->st_ref));
+ 		add_header(resp, "Session-Expires", se_hdr);
++		resp->reqsipoptions |= SIP_OPT_TIMER;
+ 	}
+ 
+ 	if (msg[0] == '2' && (p->method == SIP_SUBSCRIBE || p->method == SIP_REGISTER)) {
+@@ -10497,8 +10543,10 @@
+ {
+ 	struct sip_request resp;
+ 	uint32_t seqno = 0;
++	int res;
+ 
+-	if (reliable && (sscanf(get_header(req, "CSeq"), "%30u ", &seqno) != 1)) {
++	res = sscanf(get_header(req, "CSeq"), "%30u ", &seqno);
++	if (reliable && res != 1) {
+ 		ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
+ 		return -1;
+ 	}
+@@ -10510,6 +10558,10 @@
+ 		ast_clear_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND);
+ 		add_rpid(&resp, p);
+ 	}
++	if (ast_test_flag(&p->flags[2], SIP_PAGE3_100REL) && strncmp(msg, "100", 3) && !strncmp(msg, "1", 1)) {
++		ast_debug(2, "=!=!=!=!=!= PRACK applied to message \"%s\" \n", msg);
++		reliable = XMIT_PRACK;
++	}
+ 	if (ast_test_flag(&p->flags[0], SIP_OFFER_CC)) {
+ 		add_cc_call_info_to_response(p, &resp);
+ 	}
+@@ -10549,6 +10601,10 @@
+ 			add_header(&resp, "X-Asterisk-HangupCauseCode", buf);
+ 		}
+ 	}
++	if (strncmp(msg, "100", 3)) {
++		add_prack_respheader(p, &resp, reliable);
++		add_required_respheader(&resp);
++	}
+ 	return send_response(p, &resp, reliable, seqno);
+ }
+ 
+@@ -10561,6 +10617,7 @@
+ 	}
+ 	respprep(&resp, p, msg, req);
+ 	add_header(&resp, "SIP-ETag", esc_entry->entity_tag);
++	add_required_respheader(&resp);
+ 
+ 	return send_response(p, &resp, 0, 0);
+ }
+@@ -10648,6 +10705,7 @@
+ 	respprep(&resp, p, msg, req);
+ 	append_date(&resp);
+ 	add_header(&resp, "Unsupported", unsupported);
++	add_required_respheader(&resp);
+ 	return send_response(p, &resp, XMIT_UNRELIABLE, 0);
+ }
+ 
+@@ -10701,6 +10759,7 @@
+ 	struct sip_request resp;
+ 	respprep(&resp, p, msg, req);
+ 	append_date(&resp);
++	add_required_respheader(&resp);
+ 	return send_response(p, &resp, XMIT_UNRELIABLE, 0);
+ }
+ 
+@@ -10710,6 +10769,7 @@
+ 	struct sip_request resp;
+ 	respprep(&resp, p, msg, req);
+ 	add_header(&resp, "Accept", "application/sdp");
++	add_required_respheader(&resp);
+ 	return send_response(p, &resp, reliable, 0);
+ }
+ 
+@@ -10722,6 +10782,7 @@
+ 	snprintf(tmp, sizeof(tmp), "%d", min_expiry);
+ 	respprep(&resp, p, msg, req);
+ 	add_header(&resp, "Min-Expires", tmp);
++	add_required_respheader(&resp);
+ 	return send_response(p, &resp, XMIT_UNRELIABLE, 0);
+ }
+ 
+@@ -11803,6 +11864,16 @@
+ 	if (rpid == TRUE) {
+ 		add_rpid(&resp, p);
+ 	}
++	if (ast_test_flag(&p->flags[2], SIP_PAGE3_100REL) && strncmp(msg, "100", 3) && !strncmp(msg, "1", 1)) {
++		ast_debug(2, "=!=!=!=!=!= PRACK applied to message \"%s\" \n", msg);
++		reliable = XMIT_PRACK;
++	}
++	if (strncmp(msg, "100", 3)) {
++		/* If we send a resposne WITH sdp we are not allowed to respond before the PRACK is received */
++		ast_set_flag(&p->flags[2], SIP_PAGE3_INVITE_WAIT_FOR_PRACK);
++		add_prack_respheader(p, &resp, reliable);
++		add_required_respheader(&resp);
++	}
+ 	if (ast_test_flag(&p->flags[0], SIP_OFFER_CC)) {
+ 		add_cc_call_info_to_response(p, &resp);
+ 	}
+@@ -12212,7 +12283,34 @@
+ }
+ 
+ /*! 
+- * \brief Build REFER/INVITE/OPTIONS/SUBSCRIBE message and transmit it
++ * \brief transmit SIP PRACK as a response to a provisional response with a Rseq and Require: 100rel header 
++ */
++static int transmit_prack(struct sip_pvt *p, int their_rseq)
++{
++	if (their_rseq == p->irseq) {
++		ast_debug(3, "!?!?!?!?!? This is a retransmit of the previous response. %d \n", their_rseq);
++		/* RFC 3262: In particular, a UAC SHOULD NOT retransmit the PRACK request
++   		   	when it receives a retransmission of the provisional response being
++   		   	acknowledged, although doing so does not create a protocol error.*/
++		return -2;	/* Not used by transmit_invite et al */
++	}
++	if (p->irseq > 0 && their_rseq != p->irseq + 1) {
++		ast_debug(3, "!?!?!?!?!? This is a response out of sequence! ignored. %d \n", their_rseq);
++		/* RFC 3262: if the UAC receives another reliable provisional
++   			response to the same request, and its RSeq value is not one higher
++   			than the value of the sequence number, that response MUST NOT be
++   			acknowledged with a PRACK, and MUST NOT be processed further by the
++   			UAC.  An implementation MAY discard the response, or MAY cache the
++   			response in the hopes of receiving the missing responses.
++		*/
++		return -3;
++	}
++	p->irseq = their_rseq;
++	return transmit_invite(p, SIP_PRACK, 0, 1, NULL);
++}
++
++/*! 
++ * \brief Build PRACK/REFER/INVITE/OPTIONS/SUBSCRIBE message and transmit it
+  * \param p sip_pvt structure
+  * \param sipmethod
+  * \param sdp unknown
+@@ -12264,17 +12362,24 @@
+ 		}
+ 		snprintf(buf, sizeof(buf), "%d", p->expiry);
+ 		add_header(&req, "Expires", buf);
++	} else if (sipmethod == SIP_PRACK) {
++		/* Place holder */
++		/* Add headers for PRACK */
++		char buf[SIPBUFSIZE/2];
++		snprintf(buf, sizeof(buf), "%d %d %s", p->irseq, p->lastinvite, "INVITE");
++		add_header(&req, "RAck", buf);
+ 	}
+ 
+ 	/* This new INVITE is part of an attended transfer. Make sure that the
+ 	other end knows and replace the current call with this new call */
+ 	if (p->options && !ast_strlen_zero(p->options->replaces)) {
+ 		add_header(&req, "Replaces", p->options->replaces);
++		/* XXX This needs to be automated since we can have multiple options here */
+ 		add_header(&req, "Require", "replaces");
+ 	}
+ 
+ 	/* Add Session-Timers related headers */
+-	if (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE) {
++	if (sipmethod == SIP_INVITE && st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE) {
+ 		char i2astr[10];
+ 
+ 		if (!p->stimer->st_interval) {
+@@ -17602,6 +17707,7 @@
+ 		ast_cli(fd, "  DirectMedia  : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_DIRECT_MEDIA)));
+ 		ast_cli(fd, "  PromiscRedir : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_PROMISCREDIR)));
+ 		ast_cli(fd, "  User=Phone   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_USEREQPHONE)));
++		ast_cli(fd, "  PRACK support: %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[2], SIP_PAGE3_PRACK)));
+ 		ast_cli(fd, "  Video Support: %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT) || ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS)));
+ 		ast_cli(fd, "  Text Support : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_TEXTSUPPORT)));
+ 		ast_cli(fd, "  Ign SDP ver  : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_IGNORESDPVERSION)));
+@@ -17725,6 +17831,7 @@
+ 
+ 		/* - is enumerated */
+ 		astman_append(s, "SIP-DTMFmode: %s\r\n", dtmfmode2str(ast_test_flag(&peer->flags[0], SIP_DTMF)));
++		astman_append(s, "SIP-PRACK: %s\r\n", ast_test_flag(&peer->flags[2], SIP_PAGE3_PRACK) ? "Y" : "N");
+ 		astman_append(s, "ToHost: %s\r\n", peer->tohost);
+ 		astman_append(s, "Address-IP: %s\r\nAddress-Port: %d\r\n", ast_sockaddr_stringify_addr(&peer->addr), ast_sockaddr_port(&peer->addr));
+ 		astman_append(s, "Default-addr-IP: %s\r\nDefault-addr-port: %d\r\n", ast_sockaddr_stringify_addr(&peer->defaddr), ast_sockaddr_port(&peer->defaddr));
+@@ -18308,6 +18415,7 @@
+  	ast_cli(a->fd, "  Timer B:                %d\n", global_timer_b);
+ 	ast_cli(a->fd, "  No premature media:     %s\n", AST_CLI_YESNO(global_prematuremediafilter));
+ 	ast_cli(a->fd, "  Max forwards:           %d\n", sip_cfg.default_max_forwards);
++	ast_cli(a->fd, "  PRACK support:          %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[2], SIP_PAGE3_PRACK)));
+ 
+ 	ast_cli(a->fd, "\nDefault Settings:\n");
+ 	ast_cli(a->fd, "-----------------\n");
+@@ -18679,10 +18787,14 @@
+ 			ast_cli(a->fd, "  Format:                 %s\n", ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->owner ? cur->owner->nativeformats : 0) );
+ 			ast_cli(a->fd, "  T.38 support            %s\n", AST_CLI_YESNO(cur->udptl != NULL));
+ 			ast_cli(a->fd, "  Video support           %s\n", AST_CLI_YESNO(cur->vrtp != NULL));
++			ast_cli(a->fd, "  PRACK active            %s\n", AST_CLI_YESNO(ast_test_flag(&cur->flags[2], SIP_PAGE3_100REL)));
+ 			ast_cli(a->fd, "  MaxCallBR:              %d kbps\n", cur->maxcallbitrate);
+ 			ast_cli(a->fd, "  Theoretical Address:    %s\n", ast_sockaddr_stringify(&cur->sa));
+ 			ast_cli(a->fd, "  Received Address:       %s\n", ast_sockaddr_stringify(&cur->recv));
+ 			ast_cli(a->fd, "  SIP Transfer mode:      %s\n", transfermode2str(cur->allowtransfer));
++			ast_cli(a->fd, "  SIP PRACK support:      %s\n", ast_test_flag(&cur->flags[2], SIP_PAGE3_100REL) ? "Active" :
++				 (ast_test_flag(&cur->flags[2], SIP_PAGE3_PRACK) ? "Enabled" : "Disabled"));
++
+ 			ast_cli(a->fd, "  Force rport:            %s\n", AST_CLI_YESNO(ast_test_flag(&cur->flags[0], SIP_NAT_FORCE_RPORT)));
+ 			if (ast_sockaddr_isnull(&cur->redirip)) {
+ 				ast_cli(a->fd,
+@@ -19876,9 +19988,8 @@
+ 			   INVITE, but do set an autodestruct just in case we never get it. */
+ 		} else {
+ 			/* We have a pending outbound invite, don't send something
+-			 * new in-transaction, unless it is a pending reinvite, then
+-			 * by the time we are called here, we should probably just hang up. */
+-			if (p->pendinginvite && !p->ongoing_reinvite)
++				new in-transaction */
++			if (p->pendinginvite)
+ 				return;
+ 
+ 			if (p->owner) {
+@@ -19928,6 +20039,48 @@
+ 	return 0;
+ }
+ 
++/*! \brief Handle PRACK responses
++ */
++static void handle_response_prack(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno)
++{
++	ast_debug(2, "---> Got response on PRACK :: %d \n", resp);
++	/* Handle authentication early */
++	if (resp == 401 || resp == 407) {
++		if (p->options) {
++			p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH);
++		}
++		if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, resp, SIP_PRACK, 1)) {
++			ast_log(LOG_NOTICE, "Failed to authenticate on PRACK to '%s'\n", get_header(&p->initreq, "From"));
++		}
++		return;
++	}
++
++	/* THe REALLY important thing is that the PRACK request gets a response. The response itself
++	   is not that important. A 481 means that the call will hang up. No response at all means
++	   that the call will hang up 
++	 */
++	switch(resp) {
++	case 200:	/* 200 OK - all is fine in the kingdom of SIP */
++		break;
++
++	case 408: /* Timeout */
++	case 481: /* Ok, they did not find our call ID. Let's die */
++		if (p->owner) {
++			ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp));
++		}
++		break;
++	case 403: /* Forbidden */
++	case 415: /* Unsupported media type */
++	case 488: /* Not acceptable here */
++	case 606: /* Not Acceptable */
++	default:
++		/* Don't do anything */
++		break;
++	};
++	
++	
++}
++
+ /*!
+  * \brief Handle authentication challenge for SIP UPDATE
+  *
+@@ -20118,19 +20271,12 @@
+  	if (resp >= 300 && (p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA ))
+  		p->invitestate = INV_COMPLETED;
+  	
+-	if ((resp >= 200 && reinvite)) {
+-		p->ongoing_reinvite = 0;
+-		if (p->reinviteid > -1) {
+-			AST_SCHED_DEL_UNREF(sched, p->reinviteid, dialog_unref(p, "unref dialog for reinvite timeout because of a final response"));
+-			/* Since we got a final response to the reinvite, but were relying on the reinvite_timeout
+-			 * function to clean up after the reinvite, we need to make sure and call check_pendings */
+-			check_pendings(p);
+-		}
+-	}
+-
+ 	/* Final response, clear out pending invite */
+ 	if ((resp == 200 || resp >= 300) && p->pendinginvite && seqno == p->pendinginvite) {
+ 		p->pendinginvite = 0;
++		if (reinvite) {
++			p->ongoing_reinvite = 0;
++		}
+ 	}
+ 
+ 	/* If this is a response to our initial INVITE, we need to set what we can use
+@@ -20369,6 +20515,10 @@
+ 
+ 		/* Check for Session-Timers related headers */
+ 		if (st_get_mode(p, 0) != SESSION_TIMER_MODE_REFUSE && p->outgoing_call == TRUE && !reinvite) {
++			/* XXX Code should check in response if there's a "Require: timer"
++				header. If there is, sessions timer is enabled for this dialog
++				If not, only this side (UAC) do session timers.
++			 */
+ 			p_hdrval = (char*)get_header(req, "Session-Expires");
+ 			if (!ast_strlen_zero(p_hdrval)) {
+ 				/* UAS supports Session-Timers */
+@@ -21071,6 +21221,8 @@
+ 	struct ast_channel *owner;
+ 	int sipmethod;
+ 	const char *c = get_header(req, "Cseq");
++	const char *required = get_header(req, "Require");
++
+ 	/* GCC 4.2 complains if I try to cast c as a char * when passing it to ast_skip_nonblanks, so make a copy of it */
+ 	char *c_copy = ast_strdupa(c);
+ 	/* Skip the Cseq and its subsequent spaces */
+@@ -21112,7 +21264,7 @@
+ 				ack_res = __sip_semi_ack(p, seqno, 0, sipmethod);
+ 			}
+ 		} else {
+-			ack_res = __sip_ack(p, seqno, 0, sipmethod);
++			ack_res = __sip_ack(p, seqno, 0, sipmethod, 0);
+ 		}
+ 
+ 		if (ack_res == FALSE) {
+@@ -21138,6 +21290,7 @@
+ 		gettag(req, "To", tag, sizeof(tag));
+ 		ast_string_field_set(p, theirtag, tag);
+ 	}
++
+ 	/* This needs to be configurable on a channel/peer level,
+ 	   not mandatory for all communication. Sadly enough, NAT implementations
+ 	   are not so stable so we can always rely on these headers.
+@@ -21157,7 +21310,44 @@
+ 		pvt_set_needdestroy(p, "received 4XX response to a BYE");
+ 		return;
+ 	}
++	
++	/* If we have a required header in the response, the other side have activated an extension
++	   we said that we do support */
++	if (!ast_strlen_zero(required)) {
++		int activeextensions = parse_required_sip_options(required);
++		if (activeextensions & SIP_OPT_100REL) {
+ 
++			const char *rseq = get_header(req, "RSeq");
++			int their_rseq;
++			int res;
++			ast_debug(3, "!=!=!=!=!=! Response relies on PRACK! Rseq %s\n", rseq);
++
++			/* XXX If the response relies on PRACK, we need to start a PRACK transaction
++			 */
++			sscanf(get_header(req, "RSeq"), "%30u ", &their_rseq);
++			append_history(p, "TxPrack", "Their Rseq %d\n", their_rseq);
++			parse_ok_contact(p, req);
++			build_route(p, req, 1, resp);
++			
++			res = transmit_prack(p, their_rseq);
++			if (res == -2) {
++				/* This response is a retransmit and should be ignored */
++				/* RFC 3262: Once a reliable provisional response is received, retransmissions of
++   				   that response MUST be discarded.  A response is a retransmission when
++   				   its dialog ID, CSeq, and RSeq match the original response.  
++				*/
++				append_history(p, "PrIgnore", "Ignoring this retransmit (PRACK active)\n");
++				return;
++			} else if (res  == -3) {
++				append_history(p, "PrIgnore", "Ignoring this response - out of order (PRACK active)\n");
++				return;
++			}
++		}
++		if (activeextensions & SIP_OPT_TIMER) {
++			ast_debug(3, "!=!=!=!=!=! The other side activated Session timers! \n");
++		}
++	}
++
+ 	if (p->relatedpeer && sipmethod == SIP_OPTIONS) {
+ 		/* We don't really care what the response is, just that it replied back.
+ 		   Well, as long as it's not a 100 response...  since we might
+@@ -21174,6 +21364,9 @@
+ 	} else if (sipmethod == SIP_INFO) {
+ 		/* More good gravy! */
+ 		handle_response_info(p, resp, rest, req, seqno);
++	} else if (sipmethod == SIP_PRACK) {
++		/* More good candy! */
++		handle_response_prack(p, resp, rest, req, seqno);
+ 	} else if (sipmethod == SIP_MESSAGE) {
+ 		/* More good gravy! */
+ 		handle_response_message(p, resp, rest, req, seqno);
+@@ -22321,6 +22514,37 @@
+ 	return 0;
+ }
+ 
++/*! Support for the SIP Prack method
++ */
++static int handle_request_prack(struct sip_pvt *p, struct sip_request *req)
++{
++	const char *rack = get_header(req, "RAck");
++	int rseq, cseq;
++
++	if(sscanf(rack, "%30d %30d", &rseq, &cseq) != 2) {
++		/* we did not get proper rseq/cseq */
++		transmit_response(p, "481 Could not get proper rseq/cseq in Rack", req);
++	}
++	ast_debug(3, "!=!=!=!=!=!= Got PRACK with rseq %d and cseq %d \n", rseq, cseq);
++	if (rseq <= p->rseq) {
++		/* Ack the retransmits */
++		int acked = __sip_ack(p, cseq, 1 /* response */, 0, rseq);
++		ast_debug(2, "!=!=!=!=!=! Tried acking the response - %s \n", acked ? "Sucess" : "Total utterly failure");
++	}
++	append_history(p, "PRACK", "PRACK received Rseq %d", rseq);
++	transmit_response(p, "200 OK", req);
++	if (ast_test_flag(&p->flags[2], SIP_PAGE3_ANSWER_WAIT_FOR_PRACK)) {
++		/* If the response sent reliably contained an SDP, we're not allowed to  answer
++		   until we have a PRACK response 
++		 */
++		ast_debug(2, "-<-<--<-<-<-<- Finally a good time to answer call (PRACK arrived) %s \n", p->owner->name);
++		ast_clear_flag(&p->flags[2], SIP_PAGE3_ANSWER_WAIT_FOR_PRACK);
++		sip_answer(p->owner);
++	}
++	ast_clear_flag(&p->flags[2], SIP_PAGE3_INVITE_WAIT_FOR_PRACK);	/* Clear flag */
++	return 0;
++}
++
+ /*!
+  * \brief Handle incoming INVITE request
+  * \note If the INVITE has a Replaces header, it is part of an
+@@ -22392,6 +22616,24 @@
+ 	p->sipoptions |= required_profile;
+ 	p->reqsipoptions = required_profile;
+ 
++	/* Check if the request supports or require PRACK */
++	if (p->reqsipoptions & SIP_OPT_100REL || p->sipoptions & SIP_OPT_100REL) {
++		if (ast_test_flag(&p->flags[2], SIP_PAGE3_PRACK)) {	/* Is PRACK enabled for this dialog? */
++			ast_set_flag(&p->flags[2], SIP_PAGE3_100REL);	/* Mark PRACK as active for this dialog */
++		} else {
++			/* If PRACK was required but is disabled in configuration, don't play */
++			if (p->reqsipoptions & SIP_OPT_100REL) {
++				transmit_response(p, "420 Bad extension (unsupported)", req);
++			}
++			p->invitestate = INV_COMPLETED;
++			if (!p->lastinvite) {
++				sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
++			}
++			res = -1;
++			goto request_invite_cleanup;
++		}
++	}
++
+ 	/* Check if this is a loop */
+ 	if (ast_test_flag(&p->flags[0], SIP_OUTGOING) && p->owner && (p->invitestate != INV_TERMINATED && p->invitestate != INV_CONFIRMED) && p->owner->_state != AST_STATE_UP) {
+ 		/* This is a call to ourself.  Send ourselves an error code and stop
+@@ -22454,7 +22696,7 @@
+ 			 * transaction. Calling __sip_ack will take care of this by clearing the p->pendinginvite and removing the response
+ 			 * from the previous transaction from the list of outstanding packets.
+ 			 */
+-			__sip_ack(p, p->pendinginvite, 1, 0);
++			__sip_ack(p, p->pendinginvite, 1, 0, 0);
+ 		} else {
+ 			/* We already have a pending invite. Sorry. You are on hold. */
+ 			p->glareinvite = seqno;
+@@ -24550,7 +24792,7 @@
+ 		return 0;
+ 	} else if (auth_result == AUTH_SUCCESSFUL && p->lastinvite) {
+ 		/* We need to stop retransmitting the 401 */
+-		__sip_ack(p, p->lastinvite, 1, 0);
++		__sip_ack(p, p->lastinvite, 1, 0, 0);
+ 	}
+ 
+ 	publish_type = determine_sip_publish_type(req, event, etag, expires_str, &expires_int);
+@@ -25377,12 +25619,15 @@
+ 	case SIP_UPDATE:
+ 		res = handle_request_update(p, req);
+ 		break;
++	case SIP_PRACK:
++		res = handle_request_prack(p, req);
++		break;
+ 	case SIP_ACK:
+ 		/* Make sure we don't ignore this */
+ 		if (seqno == p->pendinginvite) {
+ 			p->invitestate = INV_TERMINATED;
+ 			p->pendinginvite = 0;
+-			acked = __sip_ack(p, seqno, 1 /* response */, 0);
++			acked = __sip_ack(p, seqno, 1 /* response */, 0, 0);
+ 			if (find_sdp(req)) {
+ 				if (process_sdp(p, req, SDP_T38_NONE))
+ 					return -1;
+@@ -25391,7 +25636,7 @@
+ 		} else if (p->glareinvite == seqno) {
+ 			/* handle ack for the 491 pending sent for glareinvite */
+ 			p->glareinvite = 0;
+-			acked = __sip_ack(p, seqno, 1, 0);
++			acked = __sip_ack(p, seqno, 1, 0, 0);
+ 		}
+ 		if (!acked) {
+ 			/* Got an ACK that did not match anything. Ignore
+@@ -27035,6 +27280,9 @@
+ 	} else if (!strcasecmp(v->name, "buggymwi")) {
+ 		ast_set_flag(&mask[1], SIP_PAGE2_BUGGY_MWI);
+ 		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_BUGGY_MWI);
++	} else if (!strcasecmp(v->name, "prack")) {
++		ast_set_flag(&mask[2], SIP_PAGE3_PRACK);
++		ast_set2_flag(&flags[2], ast_true(v->value), SIP_PAGE3_PRACK);
+ 	} else
+ 		res = 0;
+ 
+Index: channels/sip/include/sip.h
+===================================================================
+--- channels/sip/include/sip.h	(.../branches/1.8)	(revision 369561)
++++ channels/sip/include/sip.h	(.../team/oej/darjeeling-prack-1.8)	(revision 369561)
+@@ -155,7 +155,7 @@
+  *  \todo This string should be set dynamically. We only support REFER and SUBSCRIBE if we have
+  *  allowsubscribe and allowrefer on in sip.conf.
+  */
+-#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH"
++#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, PRACK"
+ 
+ /*! \brief Standard SIP unsecure port for UDP and TCP from RFC 3261. DO NOT CHANGE THIS */
+ #define STANDARD_SIP_PORT	5060
+@@ -223,6 +223,7 @@
+ #define DEFAULT_CAPABILITY (AST_FORMAT_ULAW | AST_FORMAT_TESTLAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263);
+ #define DEFAULT_STORE_SIP_CAUSE FALSE      /*!< Don't store HASH(SIP_CAUSE,<channel name>) for channels by default */
+ #endif
++#define DEFAULT_PRACK	FALSE		/*!< Default: Prack is turned off */
+ /*@}*/
+ 
+ /*! \name SIPflags
+@@ -356,10 +357,14 @@
+ 	SIP_PAGE2_Q850_REASON | SIP_PAGE2_HAVEPEERCONTEXT | SIP_PAGE2_USE_SRTP)
+ 
+ 
+-#define SIP_PAGE3_SNOM_AOC               (1 << 0)  /*!< DPG: Allow snom aoc messages */
++#define SIP_PAGE3_SNOM_AOC              (1 << 0)  /*!< DPG: Allow snom aoc messages */
++#define SIP_PAGE3_PRACK               	(1 << 1)  /*!< DPG: Allow snom aoc messages */
++#define SIP_PAGE3_100REL               	(1 << 2)  /*!< D: If PRACK is active for a specific dialog */
++#define SIP_PAGE3_INVITE_WAIT_FOR_PRACK (1 << 3)  /*!< D: Wait for PRACK response before sending 200 OK */
++#define SIP_PAGE3_ANSWER_WAIT_FOR_PRACK	(1 << 4)  /*!< D: Send ANSWER when PRACK is received */
+ 
+ #define SIP_PAGE3_FLAGS_TO_COPY \
+-	(SIP_PAGE3_SNOM_AOC)
++	(SIP_PAGE3_SNOM_AOC | SIP_PAGE3_PRACK)
+ 
+ /*@}*/
+ 
+@@ -403,6 +408,7 @@
+  * where the original response would be sent RELIABLE in an INVITE transaction
+  */
+ enum xmittype {
++	XMIT_PRACK = 3,    /*!< Transmit response the PRACK way: reliably, with re-transmits. */
+ 	XMIT_CRITICAL = 2,    /*!< Transmit critical SIP message reliably, with re-transmits.
+ 	                       *   If it fails, it's critical and will cause a teardown of the session */
+ 	XMIT_RELIABLE = 1,    /*!< Transmit SIP message reliably, with re-transmits */
+@@ -560,7 +566,7 @@
+ 	SIP_NOTIFY,     /*!< Status update, Part of the event package standard, result of a SUBSCRIBE or a REFER */
+ 	SIP_INVITE,     /*!< Set up a session */
+ 	SIP_ACK,        /*!< End of a three-way handshake started with INVITE. */
+-	SIP_PRACK,      /*!< Reliable pre-call signalling. Not supported in Asterisk. */
++	SIP_PRACK,      /*!< Reliable pre-call signalling. */
+ 	SIP_BYE,        /*!< End of a session */
+ 	SIP_REFER,      /*!< Refer to another URI (transfer) */
+ 	SIP_SUBSCRIBE,  /*!< Subscribe for updates (voicemail, session status, device status, presence) */
+@@ -749,6 +755,8 @@
+ 	int headers;            /*!< # of SIP Headers */
+ 	int method;             /*!< Method of this request */
+ 	int lines;              /*!< Body Content */
++	uint32_t rseqno;		/*!< PRACK Rseq */
++	unsigned int reqsipoptions;  /*!< Required SIP options for this answer */
+ 	unsigned int sdp_start; /*!< the line number where the SDP begins */
+ 	unsigned int sdp_count; /*!< the number of lines of SDP */
+ 	char debug;             /*!< print extra debugging if non zero */
+@@ -985,6 +993,8 @@
+ 	uint32_t ocseq;                         /*!< Current outgoing seqno */
+ 	uint32_t icseq;                         /*!< Current incoming seqno */
+ 	uint32_t init_icseq;                    /*!< Initial incoming seqno from first request */
++	uint32_t rseq;                          /*!< Current PRACK rseq on our side*/
++	uint32_t irseq;                         /*!< Current PRACK rseq on their side*/
+ 	ast_group_t callgroup;                  /*!< Call group */
+ 	ast_group_t pickupgroup;                /*!< Pickup group */
+ 	uint32_t lastinvite;                    /*!< Last seqno of invite */
+@@ -1069,7 +1079,6 @@
+ 
+ 	int initid;                         /*!< Auto-congest ID if appropriate (scheduler) */
+ 	int waitid;                         /*!< Wait ID for scheduler after 491 or other delays */
+-	int reinviteid;                     /*!< Reinvite in case of provisional, but no final response */
+ 	int autokillid;                     /*!< Auto-kill ID (scheduler) */
+ 	int t38id;                          /*!< T.38 Response ID */
+ 	struct sip_refer *refer;            /*!< REFER: SIP transfer data structure */
+@@ -1142,6 +1151,7 @@
+ 	int retrans;              /*!< Retransmission number */
+ 	int method;               /*!< SIP method for this packet */
+ 	uint32_t seqno;           /*!< Sequence number */
++	uint32_t rseqno;           /*!< PRACK Sequence number */
+ 	char is_resp;             /*!< 1 if this is a response packet (e.g. 200 OK), 0 if it is a request */
+ 	char is_fatal;            /*!< non-zero if there is a fatal error */
+ 	int response_code;        /*!< If this is a response, the response code */
+@@ -1751,7 +1761,7 @@
+ 	char * const text;  /*!< Text id, as in standard */
+ } sip_options[] = {	/* XXX used in 3 places */
+ 	/* RFC3262: PRACK 100% reliability */
+-	{ SIP_OPT_100REL,	NOT_SUPPORTED,	"100rel" },
++	{ SIP_OPT_100REL,	SUPPORTED,	"100rel" },
+ 	/* RFC3959: SIP Early session support */
+ 	{ SIP_OPT_EARLY_SESSION, NOT_SUPPORTED,	"early-session" },
+ 	/* SIMPLE events:  RFC4662 */
+Index: channels/sip/include/reqresp_parser.h
+===================================================================
+--- channels/sip/include/reqresp_parser.h	(.../branches/1.8)	(revision 369561)
++++ channels/sip/include/reqresp_parser.h	(.../team/oej/darjeeling-prack-1.8)	(revision 369561)
+@@ -145,6 +145,14 @@
+ unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len);
+ 
+ /*!
++ * \brief Parse required header in incoming packet or response
++ *	returns bitmap
++ * 
++ * \param option list
++ */
++unsigned int parse_required_sip_options(const char *options);
++
++/*!
+  * \brief Compare two URIs as described in RFC 3261 Section 19.1.4
+  *
+  * \param input1 First URI
+Index: channels/sip/include/dialog.h
+===================================================================
+--- channels/sip/include/dialog.h	(.../branches/1.8)	(revision 369561)
++++ channels/sip/include/dialog.h	(.../team/oej/darjeeling-prack-1.8)	(revision 369561)
+@@ -67,7 +67,7 @@
+ 
+ /*! \brief Acknowledges receipt of a packet and stops retransmission
+  * called with p locked*/
+-int __sip_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod);
++int __sip_ack(struct sip_pvt *p, uint32_t seqno, int resp, int sipmethod, int rseqno);
+ 
+ /*! \brief Pretend to ack all packets
+  * called with p locked */
+Index: channels/sip/reqresp_parser.c
+===================================================================
+--- channels/sip/reqresp_parser.c	(.../branches/1.8)	(revision 369561)
++++ channels/sip/reqresp_parser.c	(.../team/oej/darjeeling-prack-1.8)	(revision 369561)
+@@ -1516,18 +1516,13 @@
+ }
+ 
+ /*!
+- * \brief Parse supported header in incoming packet
+- *
+- * \details This function parses through the options parameters and
+- * builds a bit field representing all the SIP options in that field. When an
+- * item is found that is not supported, it is copied to the unsupported
+- * out buffer.
+- *
++ * \brief Parse supported or required header in incoming packet
+  * \param option list
+  * \param unsupported out buffer (optional)
+  * \param unsupported out buffer length (optional)
++ * \param response True if this is a required header from a response
+  */
+-unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len)
++static unsigned int _parse_sip_options(const char *options, char *unsupported, size_t unsupported_len)
+ {
+ 	char *next, *sep;
+ 	char *temp;
+@@ -1547,7 +1542,7 @@
+ 
+ 	temp = ast_strdupa(options);
+ 
+-	ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options);
++	ast_debug(3, "Begin: parsing SIP \"Required:\" or \"Supported: %s\"\n", options);
+ 
+ 	for (next = temp; next; next = sep) {
+ 		found = FALSE;
+@@ -1743,6 +1738,35 @@
+ 	return res;
+ }
+ 
++/*!
++ * \brief Parse supported header in incoming packet
++ *
++ * \details This function parses through the options parameters and
++ * builds a bit field representing all the SIP options in that field. When an
++ * item is found that is not supported, it is copied to the unsupported
++ * out buffer.
++ *
++ * \param option list
++ * \param unsupported out buffer (optional)
++ * \param unsupported out buffer length (optional)
++ */
++unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len)
++{
++	return _parse_sip_options(options, unsupported, unsupported_len);
++}
++
++/*!
++ * \brief required header in incoming packet or response
++ *	returns bitmap
++ * 
++ * \param option list
++ */
++unsigned int parse_required_sip_options(const char *options)
++{
++	return _parse_sip_options(options, NULL, 0 );
++}

[... 187 lines stripped ...]



More information about the svn-commits mailing list