Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:52 2007

Asterisk developer's documentation :: Codename Pineapple


sip3_parse.c File Reference


Detailed Description

Various SIP parsing functions Version 3 of chan_sip.

Author:
Mark Spencer <markster@digium.com>

Olle E. Johansson <oej@edvina.net> (all the chan_sip3 changes)

See Also:

Definition in file sip3_parse.c.

#include "asterisk.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <regex.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/udptl.h"
#include "asterisk/acl.h"
#include "asterisk/manager.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/musiconhold.h"
#include "asterisk/features.h"
#include "asterisk/causes.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/astobj.h"
#include "asterisk/linkedlists.h"
#include "asterisk/stringfields.h"
#include "asterisk/monitor.h"
#include "asterisk/compiler.h"
#include "sip3.h"
#include "sip3funcs.h"

Include dependency graph for sip3_parse.c:

Go to the source code of this file.

Functions

const char * __get_header (struct sip_request *req, const char *name, int *start)
int copy_all_header (struct sip_request *req, struct sip_request *orig, const char *field)
 Copy all headers from one request to another.
int copy_header (struct sip_request *req, struct sip_request *orig, const char *field)
 Copy one header field from one request to another.
void copy_request (struct sip_request *dst, const struct sip_request *src)
 copy SIP request (mostly used to save request for responses)
int copy_via_headers (struct sip_dialog *p, struct sip_request *req, struct sip_request *orig, const char *field)
 Copy SIP VIA Headers from the request to the response.
int determine_firstline_parts (struct sip_request *req)
 Parse first line of incoming SIP request.
void extract_uri (struct sip_dialog *p, struct sip_request *req)
 Check Contact: URI of SIP message.
const char * find_alias (const char *name, const char *_default)
 Find compressed SIP alias Structure for conversion between compressed SIP and "normal" SIP.
static const char * find_closing_quote (const char *start, const char *lim)
 Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search. start must be past the first quote.
int find_sip_method (const char *msg)
 find_sip_method: Find SIP method from header
char * generate_random_string (char *buf, size_t size)
 Generate 32 byte random string for callid's etc.
int get_destination (struct sip_dialog *p, struct sip_request *oreq)
 Find out who the call is for We use the INVITE request uri to find out Runs a dialplan lookup.
const char * get_header (struct sip_request *req, const char *name)
 Get header from SIP request.
char * get_in_brackets (char *tmp)
 Pick out text in brackets from character string.
int get_rdnis (struct sip_dialog *p, struct sip_request *oreq)
 Get referring dnis.
const char * gettag (const char *header, char *tagbuf, int tagbufsize)
 Get tag from packet.
GNURK int lws2sws (char *msgbuf, int len)
 Parse multiline SIP headers into one header This is enabled if pedanticsipchecking is enabled.
int method_match (enum sipmethod id, const char *name)
 returns true if 'name' (with optional trailing whitespace) matches the sip method 'id'. Strictly speaking, SIP methods are case SENSITIVE, but we do a case-insensitive comparison to be more tolerant. following Jon Postel's rule: Be gentle in what you accept, strict with what you send
void parse_moved_contact (struct sip_dialog *p, struct sip_request *req)
 Parse 302 Moved temporalily response.
GNURK void parse_request (struct sip_request *req)
 Parse a SIP message.
unsigned int parse_sip_options (struct sip_dialog *pvt, const char *supported)
 Parse supported header in incoming packet.
char * sip_method2txt (int method)
 return text string for sip method
int sip_method_needrtp (int method)
 Check whether method needs RTP.
char * sip_option2text (int option)
 Return text representation of SIP option.
int sip_option_lookup (const char *optionlabel)
 Check if sip option is known to us, avoid x- options (non-standard).
void sip_options_print (int options, int fd)
 Print options to cli.
static void sip_set_redirstr (struct sip_dialog *p, char *reason)
 Translate referring cause.

Variables

const struct cfsip_methods sip_methods []
static const struct cfsip_options sip_options []
 List of well-known SIP options. If we get this in a require, we should check the list and answer accordingly.


Function Documentation

const char* __get_header struct sip_request req,
const char *  name,
int *  start
 

Definition at line 587 of file sip3_parse.c.

References ast_log(), ast_test_flag, sip_request::header, sip_request::headers, len, LOG_ERROR, parse_request(), SIP_PKT_CONNECTED, and SIP_PKT_PARSED.

00588 {
00589    int pass;
00590 
00591    if (!ast_test_flag(req, SIP_PKT_PARSED)) {
00592       /* Ok, so this req is not parse by parse_request yet. */
00593       /* Parsing it before we have finished re-transmit may be bad. */
00594       if (!ast_test_flag(req, SIP_PKT_CONNECTED))
00595          parse_request(req);
00596       else {
00597          ast_log(LOG_ERROR, "Can't get header %s from request before parsing. Hang in for a jumpy ride!\n", name);
00598          return "";
00599       }
00600          
00601    }
00602    /*
00603     * Technically you can place arbitrary whitespace both before and after the ':' in
00604     * a header, although RFC3261 clearly says you shouldn't before, and place just
00605     * one afterwards.  If you shouldn't do it, what absolute idiot decided it was 
00606     * a good idea to say you can do it, and if you can do it, why in the hell would.
00607     * you say you shouldn't.
00608     */
00609    for (pass = 0; name && pass < 2;pass++) {
00610       int x, len = strlen(name);
00611       for (x=*start; x<req->headers; x++) {
00612          if (!strncasecmp(req->header[x], name, len)) {
00613             char *r = req->header[x] + len;  /* skip name */
00614             r = ast_skip_blanks(r);
00615 
00616             if (*r == ':') {
00617                *start = x+1;
00618                return ast_skip_blanks(r+1);
00619             }
00620          }
00621       }
00622       if (pass == 0) /* Try aliases */
00623          name = find_alias(name, NULL);
00624    }
00625 
00626    /* Don't return NULL, so get_header is always a valid pointer */
00627    return "";
00628 }

int copy_all_header struct sip_request req,
struct sip_request orig,
const char *  field
 

Copy all headers from one request to another.

Definition at line 649 of file sip3_parse.c.

References __get_header(), add_header(), and ast_strlen_zero().

00650 {
00651    int start = 0;
00652    int copied = 0;
00653    int res;
00654 
00655    for (;;) {
00656       const char *tmp = __get_header(orig, field, &start);
00657 
00658       if (ast_strlen_zero(tmp))
00659          break;
00660       /* Add what we're responding to */
00661       res = add_header(req, field, tmp);
00662       if (res != -1)
00663          copied++;
00664       else
00665          return -1;
00666       
00667    }
00668    return copied ? 0 : -1;
00669 }

int copy_header struct sip_request req,
struct sip_request orig,
const char *  field
 

Copy one header field from one request to another.

Definition at line 638 of file sip3_parse.c.

References add_header(), ast_log(), ast_strlen_zero(), get_header(), and LOG_NOTICE.

00639 {
00640    const char *tmp = get_header(orig, field);
00641 
00642    if (!ast_strlen_zero(tmp)) /* Add what we're responding to */
00643       return add_header(req, field, tmp);
00644    ast_log(LOG_NOTICE, "No field '%s' present to copy\n", field);
00645    return -1;
00646 }

void copy_request struct sip_request dst,
const struct sip_request src
 

copy SIP request (mostly used to save request for responses)

Definition at line 238 of file sip3_parse.c.

References ast_calloc, ast_log(), free, LOG_DEBUG, offset, and option_debug.

00239 {
00240    long offset;
00241    int x;
00242 
00243    offset = ((void *)dst) - ((void *)src);
00244    /* First copy stuff */
00245    memcpy(dst, src, sizeof(*dst));
00246    
00247    /* Now, fix data part */
00248    if (dst->data)
00249       free(dst->data);
00250    dst->data = ast_calloc(1, src->data_size);
00251    dst->data_size = src->data_size;
00252    memcpy(dst->data, src->data, src->data_size);
00253 
00254    /* Now fix pointer arithmetic */
00255    for (x=0; x < src->headers; x++)
00256       dst->header[x] += offset;
00257    for (x=0; x < src->lines; x++)
00258       dst->line[x] += offset;
00259 
00260    if (option_debug > 3)
00261       ast_log(LOG_DEBUG, "==== Copied request... \n");
00262 }

int copy_via_headers struct sip_dialog p,
struct sip_request req,
struct sip_request orig,
const char *  field
 

Copy SIP VIA Headers from the request to the response.

Note:
If the client indicates that it wishes to know the port we received from, it adds ;rport without an argument to the topmost via header. We need to add the port number (from our point of view) to that parameter. We always add ;received=<ip address>=""> to the topmost via header. Received: RFC 3261, rport RFC 3581

Definition at line 677 of file sip3_parse.c.

References __get_header(), add_header(), ast_inet_ntoa(), ast_strlen_zero(), ast_test_flag, sip_dialog::flags, sip_dialog::recv, SIP_NAT, SIP_NAT_ALWAYS, and SIP_NAT_RFC3581.

00678 {
00679    int copied = 0;
00680    int start = 0;
00681 
00682    for (;;) {
00683       char new[256];
00684       const char *oh = __get_header(orig, field, &start);
00685 
00686       if (ast_strlen_zero(oh))
00687          break;
00688 
00689       if (!copied) { /* Only check for empty rport in topmost via header */
00690          char leftmost[256], *others, *rport;
00691 
00692          /* Only work on leftmost value */
00693          ast_copy_string(leftmost, oh, sizeof(leftmost));
00694          others = strchr(leftmost, ',');
00695          if (others)
00696             *others++ = '\0';
00697 
00698          /* Find ;rport;  (empty request) */
00699          rport = strstr(leftmost, ";rport");
00700          if (rport && *(rport+6) == '=') 
00701             rport = NULL;     /* We already have a parameter to rport */
00702 
00703          if (rport && ( (ast_test_flag(&p->flags[0], SIP_NAT) == SIP_NAT_ALWAYS) ||
00704             (ast_test_flag(&p->flags[0], SIP_NAT) == SIP_NAT_RFC3581) ) ) {
00705             /* We need to add received port - rport */
00706             char *end;
00707 
00708             rport = strstr(leftmost, ";rport");
00709 
00710             if (rport) {
00711                end = strchr(rport + 1, ';');
00712                if (end)
00713                   memmove(rport, end, strlen(end) + 1);
00714                else
00715                   *rport = '\0';
00716             }
00717 
00718             /* Add rport to first VIA header if requested */
00719             /* Whoo hoo!  Now we can indicate port address translation too!  Just
00720                another RFC (RFC3581). I'll leave the original comments in for
00721                posterity.  */
00722             snprintf(new, sizeof(new), "%s;received=%s;rport=%d%s%s",
00723                leftmost, ast_inet_ntoa(p->recv.sin_addr),
00724                ntohs(p->recv.sin_port),
00725                others ? "," : "", others ? others : "");
00726                         } else {
00727                                 /* We should *always* add a received to the topmost via */
00728             snprintf(new, sizeof(new), "%s;received=%s%s%s",
00729                leftmost, ast_inet_ntoa(p->recv.sin_addr),
00730                others ? "," : "", others ? others : "");
00731 
00732          }
00733          oh = new;   /* the header to copy */
00734       }  /* else add the following via headers untouched */
00735       add_header(req, field, oh);
00736       copied++;
00737    }
00738    if (!copied) {
00739       ast_log(LOG_NOTICE, "No header field '%s' present to copy\n", field);
00740       return -1;
00741    }
00742    return 0;
00743 }

int determine_firstline_parts struct sip_request req  ) 
 

Parse first line of incoming SIP request.

Definition at line 865 of file sip3_parse.c.

References ast_log(), sip_request::header, LOG_WARNING, sip_request::rlPart1, and sip_request::rlPart2.

00866 {
00867    char *e = ast_skip_blanks(req->header[0]);   /* there shouldn't be any */
00868 
00869    if (!*e)
00870       return -1;
00871    req->rlPart1 = e; /* method or protocol */
00872    e = ast_skip_nonblanks(e);
00873    if (*e)
00874       *e++ = '\0';
00875    /* Get URI or status code */
00876    e = ast_skip_blanks(e);
00877    if ( !*e )
00878       return -1;
00879    ast_trim_blanks(e);
00880 
00881    if (!strcasecmp(req->rlPart1, "SIP/2.0") ) { /* We have a response */
00882       if (strlen(e) < 3)   /* status code is 3 digits */
00883          return -1;
00884       req->rlPart2 = e;
00885    } else { /* We have a request */
00886       if ( *e == '<' ) { /* XXX the spec says it must not be in <> ! */
00887          ast_log(LOG_WARNING, "bogus uri in <> %s\n", e);
00888          e++;
00889          if (!*e)
00890             return -1; 
00891       }
00892       req->rlPart2 = e; /* URI */
00893       e = ast_skip_nonblanks(e);
00894       if (*e)
00895          *e++ = '\0';
00896       e = ast_skip_blanks(e);
00897       if (strcasecmp(e, "SIP/2.0") ) {
00898          ast_log(LOG_WARNING, "Bad request protocol %s\n", e);
00899          return -1;
00900       }
00901    }
00902    return 1;
00903 }

void extract_uri struct sip_dialog p,
struct sip_request req
 

Check Contact: URI of SIP message.

Definition at line 906 of file sip3_parse.c.

References ast_string_field_set, ast_strlen_zero(), get_header(), get_in_brackets(), and strsep().

00907 {
00908    char stripped[256];
00909    char *c;
00910 
00911    ast_copy_string(stripped, get_header(req, "Contact"), sizeof(stripped));
00912    c = get_in_brackets(stripped);
00913    c = strsep(&c, ";"); /* trim ; and beyond */
00914    if (!ast_strlen_zero(c))
00915       ast_string_field_set(p, uri, c);
00916 }

const char* find_alias const char *  name,
const char *  _default
 

Find compressed SIP alias Structure for conversion between compressed SIP and "normal" SIP.

Definition at line 320 of file sip3_parse.c.

References aliases.

00321 {
00322    /*! \brief Structure for conversion between compressed SIP and "normal" SIP */
00323    static const struct cfalias {
00324       char * const fullname;
00325       char * const shortname;
00326    } aliases[] = {
00327       { "Content-Type",  "c" },
00328       { "Content-Encoding",    "e" },
00329       { "From",       "f" },
00330       { "Call-ID",       "i" },
00331       { "Contact",       "m" },
00332       { "Content-Length",   "l" },
00333       { "Subject",       "s" },
00334       { "To",         "t" },
00335       { "Supported",     "k" },
00336       { "Refer-To",      "r" },
00337       { "Referred-By",   "b" },
00338       { "Allow-Events",  "u" },
00339       { "Event",      "o" },
00340       { "Via",     "v" },
00341       { "Accept-Contact",      "a" },
00342       { "Reject-Contact",      "j" },
00343       { "Request-Disposition", "d" },
00344       { "Session-Expires",     "x" },
00345       { "Identity",            "y" },
00346       { "Identity-Info",       "n" },
00347    };
00348    int x;
00349 
00350    for (x=0; x<sizeof(aliases) / sizeof(aliases[0]); x++) 
00351       if (!strcasecmp(aliases[x].fullname, name))
00352          return aliases[x].shortname;
00353 
00354    return _default;
00355 }

static const char* find_closing_quote const char *  start,
const char *  lim
[static]
 

Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search. start must be past the first quote.

Definition at line 749 of file sip3_parse.c.

References s.

00750 {
00751         char last_char = '\0';
00752         const char *s;
00753         for (s = start; *s && s != lim; last_char = *s++) {
00754                 if (*s == '"' && last_char != '\\')
00755                         break;
00756         }
00757         return s;
00758 }

int find_sip_method const char *  msg  ) 
 

find_sip_method: Find SIP method from header

Definition at line 163 of file sip3_parse.c.

References ast_strlen_zero(), method_match(), and sip_methods.

00164 {
00165    int i, res = 0;
00166    
00167    if (ast_strlen_zero(msg))
00168       return 0;
00169    for (i = 1; i < (sizeof(sip_methods) / sizeof(sip_methods[0])) && !res; i++) {
00170       if (method_match(i, msg))
00171          res = sip_methods[i].id;
00172    }
00173    return res;
00174 }

char* generate_random_string char *  buf,
size_t  size
 

Generate 32 byte random string for callid's etc.

Definition at line 852 of file sip3_parse.c.

References ast_random().

00853 {
00854    long val[4];
00855    int x;
00856 
00857    for (x=0; x<4; x++)
00858       val[x] = ast_random();
00859    snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
00860 
00861    return buf;
00862 }

int get_destination struct sip_dialog p,
struct sip_request oreq
 

Find out who the call is for We use the INVITE request uri to find out Runs a dialplan lookup.

Definition at line 448 of file sip3_parse.c.

References sip_globals::allow_external_domains, ast_log(), AST_MAX_EXTENSION, ast_string_field_set, ast_strlen_zero(), ast_uri_decode(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_RDLOCK, ASTOBJ_UNLOCK, check_sip_domain(), context, domains_configured(), FALSE, sip_request::from, get_header(), get_in_brackets(), global, sip_dialog::initreq, LOG_DEBUG, LOG_WARNING, sip_request::method, option_debug, REG_MAGICMARKER, sip_dialog::registry, regl, sip_request::rlPart2, SIP_INVITE, sip_method2txt(), SIP_REFER, strsep(), and TRUE.

00449 {
00450    char tmp[256] = "", *uri, *a;
00451    char tmpf[256] = "", *from;
00452    struct sip_request *req;
00453    char *colon;
00454    int localdomain = TRUE;
00455    
00456    req = oreq;
00457    if (!req)
00458       req = p->initreq;
00459 
00460    /* Find the request URI */
00461    if (req->rlPart2)
00462       ast_copy_string(tmp, req->rlPart2, sizeof(tmp));
00463    
00464    ast_uri_decode(tmp);
00465 
00466    uri = get_in_brackets(tmp);
00467 
00468    if (strncmp(uri, "sip:", 4)) {
00469       ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", uri);
00470       return -1;
00471    }
00472    uri += 4;
00473 
00474    /* Now find the From: caller ID and name */
00475    ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf));
00476    if (!ast_strlen_zero(tmpf)) {
00477       ast_uri_decode(tmpf);
00478       from = get_in_brackets(tmpf);
00479    } else {
00480       from = NULL;
00481    }
00482    
00483    if (!ast_strlen_zero(from)) {
00484       if (strncmp(from, "sip:", 4)) {
00485          ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", from);
00486          return -1;
00487       }
00488       from += 4;
00489       if ((a = strchr(from, '@')))
00490          *a++ = '\0';
00491       else
00492          a = from;   /* just a domain */
00493       from = strsep(&from, ";"); /* Remove userinfo options */
00494       a = strsep(&a, ";");    /* Remove URI options */
00495       ast_string_field_set(p, fromdomain, a);
00496    }
00497 
00498    /* Skip any options and find the domain */
00499 
00500    /* Get the target domain */
00501    if ((a = strchr(uri, '@'))) {
00502       *a++ = '\0';
00503    } else { /* No username part */
00504       a = uri;
00505       uri = "s";  /* Set extension to "s" */
00506    }
00507    colon = strchr(a, ':'); /* Remove :port */
00508    if (colon)
00509       *colon = '\0';
00510 
00511    uri = strsep(&uri, ";");   /* Remove userinfo options */
00512    a = strsep(&a, ";");    /* Remove URI options */
00513 
00514    ast_string_field_set(p, domain, a);
00515 
00516    if (domains_configured()) {
00517       char domain_context[AST_MAX_EXTENSION];
00518 
00519       domain_context[0] = '\0';
00520       if (!check_sip_domain(p->domain, domain_context, sizeof(domain_context))) {
00521          localdomain = FALSE;
00522          if (!global.allow_external_domains && (req->method == SIP_INVITE || req->method == SIP_REFER)) {
00523             if (option_debug)
00524                ast_log(LOG_DEBUG, "Got SIP %s to non-local domain '%s'; refusing request.\n", sip_method2txt(req->method), p->domain);
00525             return -2;
00526          }
00527       }
00528       /* If we have a domain context defined, overwrite the original context */
00529       if (!ast_strlen_zero(domain_context))
00530          ast_string_field_set(p, context, domain_context);
00531    }
00532 
00533    /* If the URI starts with our magic marker and has a corresponding
00534       entry in the registry, then replace the URI with the extension
00535       we want to use */
00536    /* We don't have to check this at all if we have no registry entries... */
00537    if (localdomain && req->method == SIP_INVITE) {
00538       if (option_debug)
00539          ast_log(LOG_DEBUG, "Checking %s for magic registry marker \n", uri);
00540       /* Check if the incoming URI is a registry entry */
00541       /* Need a function in ASTOBJ to check if there are objects
00542          in the container at all here to avoid this check 
00543          when we have no registry entries */
00544       if (!strncmp(uri, REG_MAGICMARKER, strlen(REG_MAGICMARKER))) {
00545          int found = FALSE;
00546 
00547          if (option_debug)
00548             ast_log(LOG_DEBUG, "Checking for %s in registry\n", uri);
00549          /* Traverse the registry to find something */
00550          ASTOBJ_CONTAINER_TRAVERSE(&regl, !found, do {
00551             ASTOBJ_RDLOCK(iterator);
00552             if (!strcmp(uri, iterator->contact)) {
00553                found = TRUE;
00554                /* Use the extension of this registry item for the incoming call */
00555                uri = (char *) iterator->extension;
00556                p->registry = iterator;
00557             }
00558             ASTOBJ_UNLOCK(iterator);
00559          } while(0));
00560       }
00561    }
00562 
00563 
00564    if (sip_debug_test_pvt(p))
00565       ast_verbose("Looking for %s in %s (domain %s)\n", uri, p->context, p->domain);
00566 
00567    /* Check the dialplan for the username part of the request URI,
00568       the domain will be stored in the SIPDOMAIN variable
00569       Return 0 if we have a matching extension */
00570    if (ast_exists_extension(NULL, p->context, uri, 1, from) ||
00571       !strcmp(uri, ast_pickup_ext())) {
00572       if (!oreq)
00573          ast_string_field_set(p, exten, uri);
00574       return 0;
00575    }
00576 
00577    /* Return 1 for pickup extension or overlap dialling support (if we support it) */
00578    if((ast_test_flag(&global.flags[1], SIP_PAGE2_ALLOWOVERLAP) && 
00579        ast_canmatch_extension(NULL, p->context, uri, 1, from)) ||
00580        !strncmp(uri, ast_pickup_ext(), strlen(uri))) {
00581       return 1;
00582    }
00583    
00584    return -1;
00585 }

const char* get_header struct sip_request req,
const char *  name
 

Get header from SIP request.

Definition at line 631 of file sip3_parse.c.

References __get_header().

00632 {
00633    int start = 0;
00634    return __get_header(req, name, &start);
00635 }

char* get_in_brackets char *  tmp  ) 
 

Pick out text in brackets from character string.

Returns:
pointer to terminated stripped string
Parameters:
tmp input string that will be modified Examples:
"foo" <bar> valid input, returns bar foo returns the whole string < "foo ... > returns the string between brackets < "foo... bogus (missing closing bracket), returns the whole string XXX maybe should still skip the opening bracket

Definition at line 771 of file sip3_parse.c.

References ast_log(), find_closing_quote(), LOG_WARNING, and parse().

00772 {
00773    const char *parse = tmp;
00774    char *first_bracket;
00775 
00776    /*
00777     * Skip any quoted text until we find the part in brackets.
00778          * On any error give up and return the full string.
00779          */
00780         while ( (first_bracket = strchr(parse, '<')) ) {
00781                 char *first_quote = strchr(parse, '"');
00782 
00783       if (!first_quote || first_quote > first_bracket)
00784          break; /* no need to look at quoted part */
00785       /* the bracket is within quotes, so ignore it */
00786       parse = find_closing_quote(first_quote + 1, NULL);
00787       if (!*parse) { /* not found, return full string ? */
00788          /* XXX or be robust and return in-bracket part ? */
00789          ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
00790          break;
00791       }
00792       parse++;
00793    }
00794    if (first_bracket) {
00795       char *second_bracket = strchr(first_bracket + 1, '>');
00796       if (second_bracket) {
00797          *second_bracket = '\0';
00798          tmp = first_bracket + 1;
00799       } else {
00800          ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
00801       }
00802    }
00803    return tmp;
00804 }

int get_rdnis struct sip_dialog p,
struct sip_request oreq
 

Get referring dnis.

Definition at line 390 of file sip3_parse.c.

References ast_log(), ast_string_field_set, ast_strip_quoted(), ast_strlen_zero(), ast_verbose(), exten, get_header(), get_in_brackets(), sip_dialog::initreq, LOG_WARNING, sip_dialog::owner, pbx_builtin_setvar_helper(), sip_debug_test_pvt(), sip_set_redirstr(), strcasestr(), and strsep().

00391 {
00392    char tmp[256], *exten, *rexten, *rdomain;
00393    char *params, *reason = NULL;
00394    struct sip_request *req;
00395    
00396    req = oreq ? oreq : p->initreq;
00397 
00398    ast_copy_string(tmp, get_header(req, "Diversion"), sizeof(tmp));
00399    if (ast_strlen_zero(tmp))
00400       return 0;
00401 
00402    exten = get_in_brackets(tmp);
00403    if (strncmp(exten, "sip:", 4)) {
00404       ast_log(LOG_WARNING, "Huh?  Not an RDNIS SIP header (%s)?\n", exten);
00405       return -1;
00406    }
00407    exten += 4;
00408 
00409    /* Get diversion-reason param if present */
00410    if ((params = strchr(tmp, ';'))) {
00411       *params = '\0';   /* Cut off parameters  */
00412       params++;
00413       while (*params == ';' || *params == ' ')
00414          params++;
00415       /* Check if we have a reason parameter */
00416       if ((reason = strcasestr(params, "reason="))) {
00417          reason+=7;
00418          /* Remove enclosing double-quotes */
00419          if (*reason == '"') 
00420             ast_strip_quoted(reason, "\"", "\"");
00421          if (!ast_strlen_zero(reason)) {
00422             sip_set_redirstr(p, reason);
00423             if (p->owner) {
00424                pbx_builtin_setvar_helper(p->owner, "__PRIREDIRECTREASON", p->redircause);
00425                pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason);
00426             }
00427          }
00428       }
00429    }
00430 
00431    rdomain = exten;
00432    rexten = strsep(&rdomain, "@");  /* trim anything after @ */
00433    if (p->owner) 
00434       pbx_builtin_setvar_helper(p->owner, "__SIPRDNISDOMAIN", rdomain);
00435 
00436    if (sip_debug_test_pvt(p))
00437       ast_verbose("RDNIS for this call is is %s (reason %s)\n", exten, reason ? reason : "");
00438 
00439    ast_string_field_set(p, rdnis, rexten);
00440 
00441    return 0;
00442 }

const char* gettag const char *  header,
char *  tagbuf,
int  tagbufsize
 

Get tag from packet.

Returns:
Returns the pointer to the provided tag buffer, or NULL if the tag was not found.

Definition at line 200 of file sip3_parse.c.

References strcasestr(), and strsep().

00201 {
00202    const char *thetag;
00203 
00204    if (!tagbuf)
00205       return NULL;
00206    tagbuf[0] = '\0';    /* reset the buffer */
00207    thetag = strcasestr(header, ";tag=");
00208    if (thetag) {
00209       thetag += 5;
00210       ast_copy_string(tagbuf, thetag, tagbufsize);
00211       return strsep(&tagbuf, ";");
00212    }
00213    return NULL;
00214 }

GNURK int lws2sws char *  msgbuf,
int  len
 

Parse multiline SIP headers into one header This is enabled if pedanticsipchecking is enabled.

sip3_parse.c

Definition at line 807 of file sip3_parse.c.

00808 {
00809    int h = 0, t = 0; 
00810    int lws = 0; 
00811 
00812    for (; h < len;) { 
00813       /* Eliminate all CRs */ 
00814       if (msgbuf[h] == '\r') { 
00815          h++; 
00816          continue; 
00817       } 
00818       /* Check for end-of-line */ 
00819       if (msgbuf[h] == '\n') { 
00820          /* Check for end-of-message */ 
00821          if (h + 1 == len) 
00822             break; 
00823          /* Check for a continuation line */ 
00824          if (msgbuf[h + 1] == ' ' || msgbuf[h + 1] == '\t') { 
00825             /* Merge continuation line */ 
00826             h++; 
00827             continue; 
00828          } 
00829          /* Propagate LF and start new line */ 
00830          msgbuf[t++] = msgbuf[h++]; 
00831          lws = 0;
00832          continue; 
00833       } 
00834       if (msgbuf[h] == ' ' || msgbuf[h] == '\t') { 
00835          if (lws) { 
00836             h++; 
00837             continue; 
00838          } 
00839          msgbuf[t++] = msgbuf[h++]; 
00840          lws = 1; 
00841          continue; 
00842       } 
00843       msgbuf[t++] = msgbuf[h++]; 
00844       if (lws) 
00845          lws = 0; 
00846    } 
00847    msgbuf[t] = '\0'; 
00848    return t; 
00849 }

int method_match enum sipmethod  id,
const char *  name
 

returns true if 'name' (with optional trailing whitespace) matches the sip method 'id'. Strictly speaking, SIP methods are case SENSITIVE, but we do a case-insensitive comparison to be more tolerant. following Jon Postel's rule: Be gentle in what you accept, strict with what you send

Definition at line 152 of file sip3_parse.c.

References len, sip_methods, and cfsip_options::text.

00153 {
00154    int len = strlen(sip_methods[id].text);
00155    int l_name = name ? strlen(name) : 0;
00156 
00157    /* true if the string is long enough, and ends with whitespace, and matches */
00158    return (l_name >= len && name[len] < 33 &&
00159       !strncasecmp(sip_methods[id].text, name, len));
00160 }

void parse_moved_contact struct sip_dialog p,
struct sip_request req
 

Parse 302 Moved temporalily response.

Definition at line 919 of file sip3_parse.c.

References ast_log(), ast_string_field_build, ast_string_field_set, ast_test_flag, sip_dialog::flags, get_header(), get_in_brackets(), LOG_DEBUG, option_debug, sip_dialog::owner, pbx_builtin_setvar_helper(), s, SIP_PROMISCREDIR, and strsep().

00920 {
00921    char tmp[256];
00922    char *s, *e;
00923    char *domain;
00924 
00925    ast_copy_string(tmp, get_header(req, "Contact"), sizeof(tmp));
00926    s = get_in_brackets(tmp);
00927    s = strsep(&s, ";"); /* strip ; and beyond */
00928    if (ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) {
00929       if (!strncasecmp(s, "sip:", 4))
00930          s += 4;
00931       e = strchr(s, '/');
00932       if (e)
00933          *e = '\0';
00934       if (option_debug)
00935          ast_log(LOG_DEBUG, "Found promiscuous redirection to 'SIP/%s'\n", s);
00936       if (p->owner)
00937          ast_string_field_build(p->owner, call_forward, "SIP/%s", s);
00938    } else {
00939       e = strchr(tmp, '@');
00940       if (e) {
00941          *e++ = '\0';
00942          domain = e;
00943       } else {
00944          /* No username part */
00945          domain = tmp;
00946       }
00947       e = strchr(tmp, '/');
00948       if (e)
00949          *e = '\0';
00950       if (!strncasecmp(s, "sip:", 4))
00951          s += 4;
00952       if (option_debug > 1)
00953          ast_log(LOG_DEBUG, "Received 302 Redirect to extension '%s' (domain %s)\n", s, domain);
00954       if (p->owner) {
00955          pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain);
00956          ast_string_field_set(p->owner, call_forward, s);
00957       }
00958    }
00959 }

GNURK void parse_request struct sip_request req  ) 
 

Parse a SIP message.

Note:
this function is used both on incoming and outgoing packets

Definition at line 964 of file sip3_parse.c.

References ast_log(), ast_strlen_zero(), sip_request::data, sip_request::header, sip_request::headers, sip_request::line, LOG_DEBUG, option_debug, sip_request::seqno, SIP_MAX_HEADERS, SIP_MAX_LINES, and sipdebug.

00965 {
00966    char *c = req->data, **dst = req->header;
00967    int i = 0, lim = SIP_MAX_HEADERS - 1;
00968    int seqno = 0;
00969 
00970    req->header[0] = c;
00971    req->headers = -1;   /* mark that we are working on the header */
00972    for (; *c; c++) {
00973       if (*c == '\r')      /* remove \r */
00974          *c = '\0';
00975       else if (*c == '\n') { /* end of this line */
00976          *c = '\0';
00977          if (sipdebug && option_debug > 3)
00978             ast_log(LOG_DEBUG, "%7s %2d [%3d]: %s\n",
00979                req->headers < 0 ? "Header" : "Body",
00980                i, (int)strlen(dst[i]), dst[i]);
00981          if (ast_strlen_zero(dst[i]) && req->headers < 0) {
00982             req->headers = i; /* record number of header lines */
00983             dst = req->line;  /* start working on the body */
00984             i = 0;
00985             lim = SIP_MAX_LINES - 1;
00986          } else { /* move to next line, check for overflows */
00987             if (i++ >= lim)
00988                break;
00989          }
00990          dst[i] = c + 1; /* record start of next line */
00991       }
00992         }
00993    /* update count of header or body lines */
00994    if (req->headers >= 0)  /* we are in the body */
00995       req->lines = i;
00996    else {         /* no body */
00997       req->headers = i;
00998       req->lines = 0;
00999       req->line[0] = "";
01000    }
01001 
01002    if (*c)
01003       ast_log(LOG_WARNING, "Too many lines, skipping <%s>\n", c);
01004    /* Split up the first line parts */
01005    determine_firstline_parts(req);
01006    /* Determine the seqno of this request once and for all */
01007 
01008    ast_set_flag(req, SIP_PKT_PARSED);
01009 
01010    req->callid = get_header(req, "Call-ID");
01011    req->from = get_header(req, "From");
01012    req->to = get_header(req, "To");
01013    req->via = get_header(req, "Via");  /* Get the first via header only */
01014    req->cseqheader = get_header(req, "CSeq");  
01015    /* Seqno can be zero, but anyway... */
01016    if (!req->seqno && sscanf(req->cseqheader, "%d ", &seqno) != 1)
01017       req->seqno = seqno;
01018 }

unsigned int parse_sip_options struct sip_dialog pvt,
const char *  supported
 

Parse supported header in incoming packet.

Definition at line 266 of file sip3_parse.c.

References ast_log(), ast_strdupa, ast_strlen_zero(), FALSE, cfsip_options::id, LOG_DEBUG, option_debug, sip_option_lookup(), sip_options, and sipdebug.

00267 {
00268    char *next, *sep;
00269    char *temp;
00270    unsigned int profile = 0;
00271    int i, found;
00272 
00273    if (ast_strlen_zero(supported))
00274       return 0;
00275    temp = ast_strdupa(supported);
00276 
00277    if (option_debug > 2 && sipdebug)
00278       ast_log(LOG_DEBUG, "Begin: parsing SIP \"Supported: %s\"\n", supported);
00279 
00280    for (next = temp; next; next = sep) {
00281       found = FALSE;
00282       if ( (sep = strchr(next, ',')) != NULL)
00283          *sep++ = '\0';
00284       next = ast_skip_blanks(next);
00285       if (option_debug > 2 && sipdebug)
00286          ast_log(LOG_DEBUG, "Got SIP option: -%s-\n", next);
00287       i = sip_option_lookup(next);
00288       if (i > 0)
00289          profile |= sip_options[i].id;
00290    }
00291 
00292    if (pvt)
00293       pvt->sipoptions = profile;
00294    return profile;
00295 }

char* sip_method2txt int  method  ) 
 

return text string for sip method

Definition at line 177 of file sip3_parse.c.

References ast_log(), LOG_DEBUG, option_debug, and sip_methods.

Referenced by __sip_autodestruct(), __sip_destroy(), __sip_pretend_ack(), __sip_semi_ack(), append_send_history(), build_reply_digest(), do_proxy_auth(), get_destination(), handle_request(), handle_request_subscribe(), handle_response(), init_req(), reqprep(), retrans_pkt(), sip_alloc(), sip_scheddestroy(), transmit_final_response(), and transmit_register().

00178 {
00179    int max = sizeof(sip_methods) / sizeof(sip_methods[0]);
00180 
00181    if (method > max || method < 0) {
00182       if (option_debug > 3)
00183          ast_log(LOG_DEBUG, "Unknown SIP method %d given to this function. Strange... \n", method);
00184       return "<unknown>";
00185    }
00186    return sip_methods[method].text;
00187 }

int sip_method_needrtp int  method  ) 
 

Check whether method needs RTP.

Definition at line 190 of file sip3_parse.c.

References cfsip_methods::need_rtp, and sip_methods.

Referenced by sip_alloc().

00191 {
00192    return sip_methods[method].need_rtp;
00193 }

char* sip_option2text int  option  ) 
 

Return text representation of SIP option.

Definition at line 298 of file sip3_parse.c.

References sip_options, and cfsip_options::text.

00299 {
00300    return sip_options[option].text;
00301 }

int sip_option_lookup const char *  optionlabel  ) 
 

Check if sip option is known to us, avoid x- options (non-standard).

Definition at line 217 of file sip3_parse.c.

References ast_log(), LOG_DEBUG, option_debug, sip_options, sipdebug, and cfsip_options::text.

Referenced by parse_sip_options().

00218 {
00219    int i;
00220 
00221    for (i=0; i < (sizeof(sip_options) / sizeof(sip_options[0])); i++) {
00222       if (!strcasecmp(optionlabel, sip_options[i].text)) {
00223          if (option_debug > 2 && sipdebug)
00224             ast_log(LOG_DEBUG, "Matched SIP option: %s\n", optionlabel);
00225          return i;
00226       }
00227    }
00228    if (option_debug > 2) {
00229       if (!strncasecmp(optionlabel, "x-", 2))
00230          ast_log(LOG_DEBUG, "Found private SIP option, not supported: %s\n", optionlabel);
00231       else
00232          ast_log(LOG_DEBUG, "Found no match for SIP option: %s (Please file bug report!)\n", optionlabel);
00233    }
00234    return -1;
00235 }

void sip_options_print int  options,
int  fd
 

Print options to cli.

Definition at line 304 of file sip3_parse.c.

References ast_cli(), sip_options, and cfsip_options::text.

Referenced by _sip_show_device(), and sip_show_channel().

00305 {
00306    int x;
00307    int lastoption = -1;
00308    
00309    for (x=0 ; (x < (sizeof(sip_options) / sizeof(sip_options[0]))); x++) {
00310       if (sip_options[x].id != lastoption) {
00311          if (options & sip_options[x].id)
00312             ast_cli(fd, "%s ", sip_options[x].text);
00313          lastoption = x;
00314       }
00315    }
00316 }

static void sip_set_redirstr struct sip_dialog p,
char *  reason
[static]
 

Translate referring cause.

Definition at line 359 of file sip3_parse.c.

References ast_string_field_set.

00359                                                                  {
00360 
00361    if (strcmp(reason, "unknown")==0) {
00362       ast_string_field_set(p, redircause, "UNKNOWN");
00363    } else if (strcmp(reason, "user-busy")==0) {
00364       ast_string_field_set(p, redircause, "BUSY");
00365    } else if (strcmp(reason, "no-answer")==0) {
00366       ast_string_field_set(p, redircause, "NOANSWER");
00367    } else if (strcmp(reason, "unavailable")==0) {
00368       ast_string_field_set(p, redircause, "UNREACHABLE");
00369    } else if (strcmp(reason, "unconditional")==0) {
00370       ast_string_field_set(p, redircause, "UNCONDITIONAL");
00371    } else if (strcmp(reason, "time-of-day")==0) {
00372       ast_string_field_set(p, redircause, "UNKNOWN");
00373    } else if (strcmp(reason, "do-not-disturb")==0) {
00374       ast_string_field_set(p, redircause, "UNKNOWN");
00375    } else if (strcmp(reason, "deflection")==0) {
00376       ast_string_field_set(p, redircause, "UNKNOWN");
00377    } else if (strcmp(reason, "follow-me")==0) {
00378       ast_string_field_set(p, redircause, "UNKNOWN");
00379    } else if (strcmp(reason, "out-of-service")==0) {
00380       ast_string_field_set(p, redircause, "UNREACHABLE");
00381    } else if (strcmp(reason, "away")==0) {
00382       ast_string_field_set(p, redircause, "UNREACHABLE");
00383    } else {
00384       ast_string_field_set(p, redircause, "UNKNOWN");
00385    }
00386 }


Variable Documentation

const struct cfsip_methods sip_methods[]
 

XXX Note that sip_methods[i].id == i must hold or the code breaks

Definition at line 86 of file sip3_parse.c.

const struct cfsip_options sip_options[] [static]
 

List of well-known SIP options. If we get this in a require, we should check the list and answer accordingly.

Definition at line 107 of file sip3_parse.c.


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen