[svn-commits] oej: branch oej/pinepacketrequest r217406 - /team/oej/pinepacketrequest/chann...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Wed Sep 9 06:58:27 CDT 2009
Author: oej
Date: Wed Sep 9 06:58:24 2009
New Revision: 217406
URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=217406
Log:
- Preparse a few common headers that are request time upon time upon time again. We can afford having pointers to them in the packet
- Make sure we have cseq as value both for incoming and outbound requests
- Move some failure detection code to *BEFORE* we allocate a PVT to reject unparsable packets early and in one place in the code instead of two different places
Modified:
team/oej/pinepacketrequest/channels/chan_sip.c
Modified: team/oej/pinepacketrequest/channels/chan_sip.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/oej/pinepacketrequest/channels/chan_sip.c?view=diff&rev=217406&r1=217405&r2=217406
==============================================================================
--- team/oej/pinepacketrequest/channels/chan_sip.c (original)
+++ team/oej/pinepacketrequest/channels/chan_sip.c Wed Sep 9 06:58:24 2009
@@ -1,5 +1,6 @@
/* TESTING
- With TCP
+ - Optimize and remove get_header(from,to,cseq,callid) to use req-> pointers
*/
/*
@@ -1368,6 +1369,11 @@
/* XXX Do we need to unref socket.ser when the request goes away? */
struct sip_socket socket; /*!< The socket used for this request */
AST_LIST_ENTRY(sip_message) next;
+ /*------ To simplify parsing and avoid a lot of get_header() */
+ const char *callid;
+ const char *from;
+ const char *to;
+ const char *cseq;
/* ------------------------ Fields Used only for inbound messages (read from a socket) */
/* Outbound messages only */
int retrans; /*!< Retransmission number */
@@ -2931,11 +2937,15 @@
for (;;) {
struct ast_str *str_save;
+ struct ast_str *str_save_parsedata;
str_save = req.data;
+ str_save_parsedata = req.parsedata;
memset(&req, 0, sizeof(req));
req.data = str_save;
+ req.parsedata = str_save_parsedata;
ast_str_reset(req.data);
+ ast_str_reset(req.parsedata);
memset(buf, 0, sizeof(buf));
@@ -2967,6 +2977,7 @@
req.len = req.data->used;
}
parse_request(&req);
+
/* In order to know how much to read, we need the content-length header */
if (sscanf(get_header(&req, "Content-Length"), "%30d", &cl)) {
while (cl > 0) {
@@ -3271,7 +3282,7 @@
ast_free(msg->data);
}
if (msg->parsedata) {
- ast_free(msg->data);
+ ast_free(msg->parsedata);
}
}
@@ -7338,20 +7349,12 @@
char totag[128];
char fromtag[128];
struct find_call_cb_arg arg;
- const char *callid = get_header(req, "Call-ID");
- const char *from = get_header(req, "From");
- const char *to = get_header(req, "To");
- const char *cseq = get_header(req, "Cseq");
+ const char *from = req->from;
struct sip_pvt *sip_pvt_ptr;
- /* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
- /* get_header always returns non-NULL so we must use ast_strlen_zero() */
- if (ast_strlen_zero(callid) || ast_strlen_zero(to) ||
- ast_strlen_zero(from) || ast_strlen_zero(cseq))
- return NULL; /* Invalid packet */
arg.method = req->method;
- arg.callid = callid;
+ arg.callid = req->callid;
arg.fromtag = fromtag;
arg.totag = totag;
arg.tag = ""; /* make sure tag is never NULL */
@@ -7369,16 +7372,16 @@
tag = (req->method == SIP_RESPONSE) ? totag : fromtag;
- ast_debug(5, "= Looking for Call ID: %s (Checking %s) --From tag %s --To-tag %s \n", callid, req->method==SIP_RESPONSE ? "To" : "From", fromtag, totag);
+ ast_debug(5, "= Looking for Call ID: %s (Checking %s) --From tag %s --To-tag %s \n", req->callid, req->method==SIP_RESPONSE ? "To" : "From", fromtag, totag);
/* All messages must always have From: tag */
if (ast_strlen_zero(fromtag)) {
- ast_debug(5, "%s request has no from tag, dropping callid: %s from: %s\n", sip_methods[req->method].text , callid, from );
+ ast_debug(5, "%s request has no from tag, dropping callid: %s from: %s\n", sip_methods[req->method].text , req->callid, from );
return NULL;
}
/* reject requests that must always have a To: tag */
if (ast_strlen_zero(totag) && (req->method == SIP_ACK || req->method == SIP_BYE || req->method == SIP_INFO )) {
- ast_debug(5, "%s must have a to tag. dropping callid: %s from: %s\n", sip_methods[req->method].text , callid, from );
+ ast_debug(5, "%s must have a to tag. dropping callid: %s from: %s\n", sip_methods[req->method].text , req->callid, from );
return NULL;
}
}
@@ -7386,7 +7389,7 @@
restartsearch:
if (!sip_cfg.pedanticsipchecking) {
struct sip_pvt tmp_dialog = {
- .callid = callid,
+ .callid = req->callid,
};
sip_pvt_ptr = ao2_t_find(dialogs, &tmp_dialog, OBJ_POINTER, "ao2_find in dialogs");
if (sip_pvt_ptr) { /* well, if we don't find it-- what IS in there? */
@@ -7413,14 +7416,14 @@
if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG) {
if (intended_method == SIP_REFER) {
/* We do support REFER, but not outside of a dialog yet */
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "603 Declined (no dialog)", 603);
+ transmit_response_using_temp(req->callid, sin, 1, intended_method, req, "603 Declined (no dialog)", 603);
} else if (intended_method == SIP_NOTIFY) {
/* We do not support out-of-dialog NOTIFY either,
like voicemail notification, so cancel that early */
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "489 Bad event", 489);
+ transmit_response_using_temp(req->callid, sin, 1, intended_method, req, "489 Bad event", 489);
} else {
/* Ok, time to create a new SIP dialog object, a pvt */
- if ((p = sip_alloc(callid, sin, 1, intended_method, req))) {
+ if ((p = sip_alloc(req->callid, sin, 1, intended_method, req))) {
/* Ok, we've created a dialog, let's go and process it */
sip_pvt_lock(p);
} else {
@@ -7432,24 +7435,24 @@
Sorry, we apologize for the inconvienience
*/
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "500 Server internal error", 500);
+ transmit_response_using_temp(req->callid, sin, 1, intended_method, req, "500 Server internal error", 500);
ast_debug(4, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n");
}
}
return p; /* can be NULL */
} else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
/* A method we do not support, let's take it on the volley */
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "501 Method Not Implemented", 501);
+ transmit_response_using_temp(req->callid, sin, 1, intended_method, req, "501 Method Not Implemented", 501);
ast_debug(2, "Got a request with unsupported SIP method.\n");
} else if (intended_method != SIP_RESPONSE && intended_method != SIP_ACK) {
/* This is a request outside of a dialog that we don't know about */
- transmit_response_using_temp(callid, sin, 1, intended_method, req, "481 Call leg/transaction does not exist", 481);
- ast_debug(2, "That's odd... Got a request in unknown dialog. Callid %s\n", callid ? callid : "<unknown>");
+ transmit_response_using_temp(req->callid, sin, 1, intended_method, req, "481 Call leg/transaction does not exist", 481);
+ ast_debug(2, "That's odd... Got a request in unknown dialog. Callid %s\n", req->callid ? req->callid : "<unknown>");
}
/* We do not respond to responses for dialogs that we don't know about, we just drop
the session quickly */
if (intended_method == SIP_RESPONSE)
- ast_debug(2, "That's odd... Got a response on a call we dont know about. Callid %s\n", callid ? callid : "<unknown>");
+ ast_debug(2, "That's odd... Got a response on a call we dont know about. Callid %s\n", req->callid ? req->callid : "<unknown>");
return NULL;
}
@@ -9373,6 +9376,7 @@
add_header(resp, "To", ot);
copy_header(resp, req, "Call-ID");
copy_header(resp, req, "CSeq");
+ resp->seqno = req->seqno;
if (!ast_strlen_zero(global_useragent))
add_header(resp, "Server", global_useragent);
add_header(resp, "Allow", ALLOWED_METHODS);
@@ -9431,6 +9435,7 @@
p->ocseq++;
seqno = p->ocseq;
}
+ req->seqno = seqno;
/* A CANCEL must have the same branch as the INVITE that it is canceling.
* Similarly, if we need to re-send an INVITE with auth credentials, then we
@@ -22161,35 +22166,17 @@
/* Called with p->lock held, as well as p->owner->lock if appropriate, keeping things
relatively static */
const char *cmd;
- const char *cseq;
+ int seqno = req->seqno;
const char *useragent;
- int seqno;
int len;
int respid;
int res = 0;
int debug = sip_debug_test_pvt(p);
const char *e;
- int error = 0;
/* Get Method and Cseq */
- cseq = get_header(req, "Cseq");
cmd = REQ_OFFSET_TO_STR(req, header[0]);
- /* Must have Cseq */
- if (ast_strlen_zero(cmd) || ast_strlen_zero(cseq)) {
- ast_log(LOG_ERROR, "Missing Cseq. Dropping this SIP message, it's incomplete.\n");
- error = 1;
- }
- if (!error && sscanf(cseq, "%30d%n", &seqno, &len) != 1) {
- ast_log(LOG_ERROR, "No seqno in '%s'. Dropping incomplete message.\n", cmd);
- error = 1;
- }
- if (error) {
- if (!p->initreq.headers) { /* New call */
- pvt_set_needdestroy(p, "no headers");
- }
- return -1;
- }
/* Get the command XXX */
cmd = REQ_OFFSET_TO_STR(req, rlPart1);
@@ -22219,15 +22206,17 @@
ast_log(LOG_WARNING, "Invalid SIP response code: '%d'\n", respid);
return 0;
}
- if (p->ocseq && (p->ocseq < seqno)) {
+ req->response_code = respid;
+
+ if (p->ocseq && (p->ocseq < req->seqno)) {
if (option_debug)
- ast_log(LOG_DEBUG, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq);
+ ast_log(LOG_DEBUG, "Ignoring out of order response %d (expecting %d)\n", req->seqno, p->ocseq);
return -1;
} else {
if ((respid == 200) || ((respid >= 300) && (respid <= 399))) {
extract_uri(p, req);
}
- handle_response(p, respid, e + len, req, seqno);
+ handle_response(p, respid, e + len, req, req->seqno);
}
return 0;
}
@@ -22239,31 +22228,31 @@
p->method = req->method; /* Find out which SIP method they are using */
ast_debug(4, "**** Received %s (%d) - Command in SIP %s\n", sip_methods[p->method].text, sip_methods[p->method].id, cmd);
- if (p->icseq && (p->icseq > seqno) ) {
- if (p->pendinginvite && seqno == p->pendinginvite && (req->method == SIP_ACK || req->method == SIP_CANCEL)) {
+ if (p->icseq && (p->icseq > req->seqno) ) {
+ if (p->pendinginvite && req->seqno == p->pendinginvite && (req->method == SIP_ACK || req->method == SIP_CANCEL)) {
ast_debug(2, "Got CANCEL or ACK on INVITE with transactions in between.\n");
} else {
- ast_debug(1, "Ignoring too old SIP packet packet %d (expecting >= %d)\n", seqno, p->icseq);
+ ast_debug(1, "Ignoring too old SIP packet packet %d (expecting >= %d)\n", req->seqno, p->icseq);
if (req->method != SIP_ACK)
transmit_response(p, 503, "503 Server error", req); /* We must respond according to RFC 3261 sec 12.2 */
return -1;
}
} else if (p->icseq &&
- p->icseq == seqno &&
+ p->icseq == req->seqno &&
req->method != SIP_ACK &&
(p->method != SIP_CANCEL || p->alreadygone)) {
/* ignore means "don't do anything with it" but still have to
respond appropriately. We do this if we receive a repeat of
the last sequence number */
req->ignore = 1;
- ast_debug(3, "Ignoring SIP message because of retransmit (%s Seqno %d, ours %d)\n", sip_methods[p->method].text, p->icseq, seqno);
+ ast_debug(3, "Ignoring SIP message because of retransmit (%s Seqno %d, ours %d)\n", sip_methods[p->method].text, p->icseq, req->seqno);
}
- if (seqno >= p->icseq)
+ if (req->seqno >= p->icseq)
/* Next should follow monotonically (but not necessarily
incrementally -- thanks again to the genius authors of SIP --
increasing */
- p->icseq = seqno;
+ p->icseq = req->seqno;
/* Find their tag if we haven't got it */
if (ast_strlen_zero(p->theirtag)) {
@@ -22524,6 +22513,9 @@
int recount = 0;
int nounlock = 0;
int lockretry;
+ int parseerror = FALSE;
+ int len;
+ const char *cmd;
if (sip_debug_test_addr(sin)) /* Set the debug flag early on packet level */
req->debug = 1;
@@ -22541,15 +22533,40 @@
return 1;
}
req->method = find_sip_method(REQ_OFFSET_TO_STR(req, rlPart1));
-
- if (req->debug)
- ast_verbose("--- (%d headers %d lines)%s ---\n", req->headers, req->lines, (req->headers + req->lines == 0) ? " Nat keepalive" : "");
-
- if (req->headers < 2) { /* Must have at least two headers */
+ req->callid = get_header(req, "Call-ID");
+ req->from = get_header(req, "From");
+ req->to = get_header(req, "To");
+ req->cseq = get_header(req, "Cseq");
+
+ /* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
+ /* get_header always returns non-NULL so we must use ast_strlen_zero() */
+ if (ast_strlen_zero(req->callid) || ast_strlen_zero(req->to) ||
+ ast_strlen_zero(req->from) || ast_strlen_zero(req->cseq)) {
+ parseerror = TRUE;
+ }
+ if (!parseerror && req->headers < 2) { /* Must have at least two headers */
+ parseerror = TRUE;
+ }
+
+ /* Must have Cseq and first line */
+ cmd = REQ_OFFSET_TO_STR(req, header[0]);
+ if (!parseerror && (ast_strlen_zero(cmd) || ast_strlen_zero(req->cseq))) {
+ ast_log(LOG_ERROR, "Missing Cseq. Dropping this SIP message, it's incomplete.\n");
+ parseerror = TRUE;
+ }
+ if (!parseerror && sscanf(req->cseq, "%30d%n", &req->seqno, &len) != 1) {
+ ast_log(LOG_ERROR, "No seqno in '%s'. Dropping incomplete message.\n", cmd);
+ parseerror = 1;
+ }
+
+ if (parseerror) {
ast_str_reset(req->data); /* nulling this out is NOT a good idea here. */
ast_str_reset(req->parsedata); /* nulling this out is NOT a good idea here. */
return 1;
}
+
+ if (req->debug)
+ ast_verbose("--- (%d headers %d lines)%s ---\n", req->headers, req->lines, (req->headers + req->lines == 0) ? " Nat keepalive" : "");
/* Process request, with netlock held, and with usual deadlock avoidance */
for (lockretry = 10; lockretry > 0; lockretry--) {
More information about the svn-commits
mailing list