123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- /*
- * $Id$
- *
- * Copyright (C) 2005-2006 iptelorg GmbH
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * History:
- * --------
- * 2005-12-19 select framework (mma)
- * 2006-01-19 multiple nested calls, IS_ALIAS -> NESTED flag renamed (mma)
- * DIVERSION flag checked
- * 2006-02-26 don't free str when changing type STR -> DIVERSION (mma)
- * it can't be freeable sometimes (e.g. xlog's select)
- * 2006-05-30 parse_select (mma)
- * 2006-06-02 shm_parse_select (mma)
- *
- */
- /*!
- * \file
- * \brief SIP-router core ::
- * \ingroup core
- * Module: \ref core
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <ctype.h>
- #include "select.h"
- #include "dprint.h"
- #include "select_core.h"
- #include "mem/mem.h"
- #include "mem/shm_mem.h"
- /*
- * The main parser table list placeholder
- * at startup use core table, modules can
- * add their own via register_select_table call
- */
- static select_table_t *select_list = &select_core_table;
- /* the level of the select call that is beeing evaluated
- * by the child process
- */
- int select_level = 0;
- /* pointer to the SIP uri beeing processed.
- * Nested function calls can pass information to each
- * other using this pointer. Only for performace reasons.
- * (Miklos)
- */
- struct sip_uri *select_uri_p = NULL;
- /** parse a select identifier (internal version)
- * Parse select string into select structure s
- * moves pointer p to the first unused char.
- *
- * The select identifier must be of the form:
- \verbatim
- * [@] <sel_id> [ '.' <sel_id> ...]
- *
- * Where
- * <sel_id> = <id> |
- * <id> '[' <idx> ']'
- * <id> = [a-zA-Z0-9_]+
- * <idx> = <number> | <string>
- * <string> = '"' <ascii> '"' |
- * '\"' <ascii> '\"'
- *
- * Examples:
- * @to.tag
- * @hf_value["contact"]
- * @msg.header["SER-Server-ID"]
- * @eval.pop[-1]
- * contact.uri.params.maddr
- * cfg_get.rtp_proxy.enabled
- \endverbatim
- *
- * @return -1 error
- * p points to the first unconsumed char
- * 0 success
- * p points to the first unconsumed char
- * s points to the select structure
- */
- int w_parse_select(char**p, select_t* sel)
- {
- str name;
- char* select_name;
-
- if (**p=='@') (*p)++;
- select_name=*p;
- sel->n=0;
- while (isalpha((unsigned char)*(*p))) {
- if (sel->n > MAX_SELECT_PARAMS -2) {
- ERR("parse_select: select depth exceeds max\n");
- goto error;
- }
- name.s=(*p);
- while (isalpha((unsigned char)*(*p)) ||
- isdigit((unsigned char)*(*p)) || (*(*p)=='_')) (*p)++;
- name.len=(*p)-name.s;
- sel->params[sel->n].type=SEL_PARAM_STR;
- sel->params[sel->n].v.s=name;
- DBG("parse_select: part %d: %.*s\n", sel->n, sel->params[sel->n].v.s.len, sel->params[sel->n].v.s.s);
- sel->n++;
- if (*(*p)=='[') {
- (*p)++;
- if (*(*p)=='\\') (*p)++;
- if (*(*p)=='"') {
- (*p)++;
- name.s=(*p);
- while ((*(*p)!='\0') && (*(*p)!='"')) (*p)++;
- if (*(*p)!='"') {
- ERR("parse_select: end of string is missing\n");
- goto error;
- }
- name.len=(*p)-name.s;
- if (*((*p)-1)=='\\') name.len--;
- (*p)++;
- if (*(*p)!=']') {
- ERR("parse_select: invalid string index, no closing ]\n");
- goto error;
- };
- (*p)++;
- sel->params[sel->n].type=SEL_PARAM_STR;
- sel->params[sel->n].v.s=name;
- DBG("parse_select: part %d: [\"%.*s\"]\n", sel->n, sel->params[sel->n].v.s.len, sel->params[sel->n].v.s.s);
- } else {
- name.s=(*p);
- if (*(*p)=='-') (*p)++;
- while (isdigit((unsigned char)*(*p))) (*p)++;
- name.len=(*p)-name.s;
- if (*(*p)!=']') {
- ERR("parse_select: invalid index, no closing ]\n");
- goto error;
- };
- (*p)++;
- sel->params[sel->n].type=SEL_PARAM_INT;
- sel->params[sel->n].v.i=atoi(name.s);
- DBG("parse_select: part %d: [%d]\n", sel->n, sel->params[sel->n].v.i);
- }
- sel->n++;
- }
- if (*(*p)!='.') break;
- (*p)++;
- };
- if (sel->n==0) {
- ERR("parse_select: invalid select '%.*s'\n", (int)(*p - select_name), select_name);
- goto error;
- };
- DBG("parse_select: end, total elements: %d, calling resolve_select\n", sel->n);
- if (resolve_select(sel)<0) {
- ERR("parse_select: error while resolve_select '%.*s'\n", (int)(*p - select_name), select_name);
- goto error;
- }
- return 0;
-
- error:
- return -1;
- }
- /** parse a select identifier.
- * Parse select string into select structure s and
- * moves pointer p to the first unused char.
- *
- \verbatim
- * The select identifier must be of the form:
- * [@] <sel_id> [ '.' <sel_id> ...]
- *
- * Where
- * <sel_id> = <id> |
- * <id> '[' <idx> ']'
- * <id> = [a-zA-Z0-9_]+
- * <idx> = <number> | '-' <number> | <string>
- * <string> = '"' <ascii> '"' |
- * '\"' <ascii> '\"'
- *
- * Examples:
- * @to.tag
- * @hf_value["contact"]
- * @msg.header["SER-Server-ID"]
- * @eval.pop[-1]
- * contact.uri.params.maddr
- * cfg_get.rtp_proxy.enabled
- \endverbatim
- *
- * @param p - double string (asciiz) pointer, *p is moved to the first char
- * after the select identifier
- * @param s - the result will be stored here
- * @return < 0 on error, 0 on success
- */
- int parse_select (char** p, select_t** s)
- {
- select_t* sel;
-
- sel=(select_t*)pkg_malloc(sizeof(select_t));
- if (!sel) {
- ERR("parse_select: no free memory\n");
- return -1;
- }
- memset(sel, 0, sizeof(select_t));
- if (w_parse_select(p, sel)<0) {
- pkg_free(sel);
- return -2;
- }
- *s=sel;
- return 0;
- }
- void free_select(select_t *s)
- {
- if (s)
- pkg_free(s);
- }
- void shm_free_select(select_t *s)
- {
- if (s)
- shm_free(s);
- }
- int shm_parse_select (char** p, select_t** s)
- {
- select_t* sel;
-
- sel=(select_t*)shm_malloc(sizeof(select_t));
- if (!sel) {
- ERR("parse_select: no free shared memory\n");
- return -1;
- }
- if (w_parse_select(p, sel)<0) {
- shm_free(sel);
- return -2;
- }
- *s=sel;
- return 0;
- }
- int resolve_select(select_t* s)
- {
- select_f f;
- int nested;
- int param_idx = 0;
- int table_idx = 0;
- select_table_t* t = NULL;
- int accept = 0;
- f = NULL;
- nested = 0;
- memset (s->f, 0, sizeof(s->f));
- while (param_idx<s->n) {
- accept = 0;
- switch (s->params[param_idx].type) {
- case SEL_PARAM_STR:
- DBG("resolve_select: '%.*s'\n", s->params[param_idx].v.s.len, s->params[param_idx].v.s.s);
- break;
- case SEL_PARAM_INT:
- DBG("resolve_select: [%d]\n", s->params[param_idx].v.i);
- break;
- default:
- /* just to avoid the warning */
- break;
- }
- for (t=select_list; t; t=t->next) {
- table_idx = 0;
- if (!t->table) continue;
- while (t->table[table_idx].curr_f || t->table[table_idx].new_f) {
- if (t->table[table_idx].curr_f == f) {
- if ((t->table[table_idx].flags & (NESTED | CONSUME_NEXT_INT | CONSUME_NEXT_STR)) == NESTED) {
- accept = 1;
- } else if (t->table[table_idx].type == s->params[param_idx].type) {
- switch (t->table[table_idx].type) {
- case SEL_PARAM_INT:
- accept = 1;
- break;
- case SEL_PARAM_STR:
- accept = (((t->table[table_idx].name.len == s->params[param_idx].v.s.len) || !t->table[table_idx].name.len)
- && (!t->table[table_idx].name.s || !strncasecmp(t->table[table_idx].name.s, s->params[param_idx].v.s.s, s->params[param_idx].v.s.len)));
- break;
- default:
- break;
- }
- };
- }
- if (accept) goto accepted;
- table_idx++;
- }
- }
- switch (s->params[param_idx].type) {
- case SEL_PARAM_STR:
- LM_ERR("Unable to resolve select '%.*s' at level %d\n", s->params[param_idx].v.s.len, s->params[param_idx].v.s.s, param_idx);
- break;
- case SEL_PARAM_INT:
- LM_ERR("Unable to resolve select [%d] at level %d\n", s->params[param_idx].v.i, param_idx);
- break;
- default:
- BUG ("Unable to resolve select at level %d\n", param_idx);
- break;
- break;
- }
- goto not_found;
- accepted:
- if (t->table[table_idx].flags & DIVERSION) {
- /* if (s->params[param_idx].type == SEL_PARAM_STR) pkg_free(s->params[param_idx].v.s.s); */
- /* don't free it (the mem can leak only once at startup)
- * the parsed string can live inside larger string block
- * e.g. when xlog's select is parsed
- */
- s->params[param_idx].type = SEL_PARAM_DIV;
- s->params[param_idx].v.i = t->table[table_idx].flags & DIVERSION_MASK;
- }
- if (t->table[table_idx].flags & CONSUME_NEXT_STR) {
- if ((param_idx<s->n-1) && (s->params[param_idx+1].type == SEL_PARAM_STR)) {
- param_idx++;
- } else if (!(t->table[table_idx].flags & OPTIONAL)) {
- BUG ("Mandatory STR parameter not found\n");
- goto not_found;
- }
- }
- if (t->table[table_idx].flags & CONSUME_NEXT_INT) {
- if ((param_idx<s->n-1) && (s->params[param_idx+1].type == SEL_PARAM_INT)) {
- param_idx++;
- } else if (!(t->table[table_idx].flags & OPTIONAL)) {
- BUG ("Mandatory INT parameter not found\n");
- goto not_found;
- }
- }
- if (t->table[table_idx].flags & NESTED) {
- if (nested < MAX_NESTED_CALLS-1) { /* need space for final function */
- s->f[nested++] = f;
- s->param_offset[nested] = param_idx;
- } else {
- BUG("MAX_NESTED_CALLS too small to resolve select\n");
- goto not_found;
- }
- } else {
- param_idx++;
- }
- if (t->table[table_idx].flags & FIXUP_CALL) {
- select_level = nested;
- s->param_offset[nested+1] = param_idx;
- if (t->table[table_idx].new_f(NULL, s, NULL)<0) goto not_found;
- }
- f = t->table[table_idx].new_f;
- if (t->table[table_idx].flags & CONSUME_ALL) {
- /* sanity checks */
- if (t->table[table_idx].flags & NESTED)
- WARN("resolve_select: CONSUME_ALL should not be set "
- "together with NESTED flag!\n");
- if ((t->table[table_idx].flags & FIXUP_CALL) == 0)
- WARN("resolve_select: FIXUP_CALL should be defined "
- "if CONSUME_ALL flag is set!\n");
- break;
- }
- }
- if (t==NULL) {
- BUG ("final node not found\n");
- goto not_found;
- }
- if (t->table[table_idx].flags & SEL_PARAM_EXPECTED) {
- BUG ("final node has SEL_PARAM_EXPECTED set (no more parameters available)\n");
- goto not_found;
- }
- if (nested >= MAX_NESTED_CALLS) {
- BUG("MAX_NESTED_CALLS too small, no space for finally resolved function\n");
- goto not_found;
- }
- if ((nested>0) && (s->f[nested-1] == f)) {
- BUG("Topmost nested function equals to final function, won't call it twice\n");
- } else {
- s->f[nested++] = f;
- }
- s->param_offset[nested] = s->n;
- return 0;
- not_found:
- return -1;
- }
- int run_select(str* res, select_t* s, struct sip_msg* msg)
- {
- int ret, orig_level;
- if (res == NULL) {
- BUG("Select unprepared result space\n");
- return -1;
- }
- if (s == 0) {
- BUG("Select structure is NULL\n");
- return -1;
- }
- if (s->f[0] == 0) {
- BUG("Select structure has not been resolved\n");
- return -1;
- }
- DBG("Calling SELECT %p \n", s->f);
- /* reset the uri pointer */
- select_uri_p = NULL;
- /* save and restore the original select_level
- * because of the nested selects */
- orig_level = select_level;
- ret = 0;
- for ( select_level=0;
- (ret == 0) && (select_level<MAX_NESTED_CALLS) && (s->f[select_level] !=0 );
- select_level++
- ) {
- ret = s->f[select_level](res, s, msg);
- }
- select_level = orig_level;
- return ret;
- }
- void print_select(select_t* s)
- {
- int i;
- DBG("select(");
- for(i = 0; i < s->n; i++) {
- if (s->params[i].type == SEL_PARAM_INT) {
- DBG("%d,", s->params[i].v.i);
- } else {
- DBG("%.*s,", s->params[i].v.s.len, s->params[i].v.s.s);
- }
- }
- DBG(")\n");
- }
- int register_select_table(select_row_t* mod_tab)
- {
- select_table_t* t;
- t=(select_table_t*)pkg_malloc(sizeof(select_table_t));
- if (!t) {
- ERR("No memory for new select_table structure\n");
- return -1;
- }
- t->table=mod_tab;
- t->next=select_list;
- select_list=t;
- return 0;
- }
|