diff options
Diffstat (limited to 'res')
155 files changed, 2980 insertions, 2303 deletions
diff --git a/res/Makefile b/res/Makefile index e56a14880..ecaa03d3c 100644 --- a/res/Makefile +++ b/res/Makefile @@ -1,6 +1,6 @@ # # Asterisk -- An open source telephony toolkit. -# +# # Makefile for resource modules # # Copyright (C) 1999-2006, Digium, Inc. diff --git a/res/ael/ael.flex b/res/ael/ael.flex index b064646d9..82a5f9e17 100644 --- a/res/ael/ael.flex +++ b/res/ael/ael.flex @@ -275,11 +275,11 @@ includes { STORE_POS; return KW_INCLUDES;} [ ]+ { my_col += yyleng; } [\t]+ { my_col += (yyleng*8)-(my_col%8); } -({KEYWORD}?[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]]|{HIBIT}|(\\.)|(\$\{)|(\$\[)) { - /* boy did I open a can of worms when I changed the lexical token "word". +({KEYWORD}?[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]]|{HIBIT}|(\\.)|(\$\{)|(\$\[)) { + /* boy did I open a can of worms when I changed the lexical token "word". all the above keywords can be used as a beginning to a "word".- - before, a "word" would match a longer sequence than the above - keywords, and all would be well. But now "word" is a single char + before, a "word" would match a longer sequence than the above + keywords, and all would be well. But now "word" is a single char and feeds into a statemachine sort of sequence from there on. So... I added the {KEYWORD}? to the beginning of the word match sequence */ @@ -350,7 +350,7 @@ includes { STORE_POS; return KW_INCLUDES;} } } -<curlystate>{NOPARENS}[\(\[\{] { +<curlystate>{NOPARENS}[\(\[\{] { char c = yytext[yyleng-1]; if (c == '{') parencount2++; @@ -358,7 +358,7 @@ includes { STORE_POS; return KW_INCLUDES;} yymore(); } -<curlystate>{NOPARENS}[\]\)] { +<curlystate>{NOPARENS}[\]\)] { char c = yytext[yyleng-1]; if ( pbcpop2(c)) { /* error */ STORE_LOC; @@ -393,7 +393,7 @@ includes { STORE_POS; return KW_INCLUDES;} } } -<brackstate>{NOPARENS}[\(\[\{] { +<brackstate>{NOPARENS}[\(\[\{] { char c = yytext[yyleng-1]; if (c == '[') parencount3++; @@ -401,7 +401,7 @@ includes { STORE_POS; return KW_INCLUDES;} yymore(); } -<brackstate>{NOPARENS}[\}\)] { +<brackstate>{NOPARENS}[\}\)] { char c = yytext[yyleng-1]; if ( pbcpop3(c)) { /* error */ STORE_LOC; @@ -586,7 +586,7 @@ includes { STORE_POS; return KW_INCLUDES;} glob_t globbuf; /* the current globbuf */ int globbuf_pos = -1; /* where we are in the current globbuf */ globbuf.gl_offs = 0; /* initialize it to silence gcc */ - + p1 = strchr(yytext,'"'); p2 = strrchr(yytext,'"'); if ( include_stack_index >= MAX_INCLUDE_DEPTH ) { @@ -631,8 +631,8 @@ includes { STORE_POS; return KW_INCLUDES;} yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner ); include_stack[include_stack_index-1].globbuf_pos++; setup_filestack(fnamebuf, sizeof(fnamebuf), &include_stack[include_stack_index-1].globbuf, include_stack[include_stack_index-1].globbuf_pos, yyscanner, 0); - /* finish this */ - + /* finish this */ + } else { if (include_stack[include_stack_index].fname) { free(include_stack[include_stack_index].fname); @@ -647,7 +647,7 @@ includes { STORE_POS; return KW_INCLUDES;} } else { globfree(&include_stack[include_stack_index].globbuf); include_stack[include_stack_index].globbuf_pos = -1; - + yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner ); yy_switch_to_buffer(include_stack[include_stack_index].bufstate, yyscanner ); my_lineno = include_stack[include_stack_index].lineno; @@ -817,7 +817,7 @@ struct pval *ael2_parse(char *filename, int *errors) buffer = (char*)malloc(stats.st_size+2); if (fread(buffer, 1, stats.st_size, fin) != stats.st_size) { ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno)); - } + } buffer[stats.st_size]=0; fclose(fin); @@ -889,7 +889,7 @@ static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf, buffer = (char*)malloc(stats.st_size+1); if (fread(buffer, 1, stats.st_size, in1) != stats.st_size) { ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno)); - } + } buffer[stats.st_size] = 0; ast_debug(1, " --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size); fclose(in1); diff --git a/res/ael/ael.tab.c b/res/ael/ael.tab.c index 414914101..802e78f9d 100644 --- a/res/ael/ael.tab.c +++ b/res/ael/ael.tab.c @@ -1,19 +1,19 @@ /* A Bison parser, made by GNU Bison 2.5. */ /* Bison implementation for Yacc-like parsers in C - + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. - + This program 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 3 of the License, or (at your option) any later version. - + This program 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, see <http://www.gnu.org/licenses/>. */ @@ -26,7 +26,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -119,7 +119,7 @@ static void set_dads(pval *dad, pval *child_list); void reset_parencount(yyscan_t yyscanner); void reset_semicount(yyscan_t yyscanner); void reset_argcount(yyscan_t yyscanner ); - + #define YYLEX_PARAM ((struct parse_io *)parseio)->scanner #define YYERROR_VERBOSE 1 @@ -2896,7 +2896,7 @@ yyreduce: free((yyvsp[(1) - (2)].str)); free((yyvsp[(2) - (2)].str)); prev_word = (yyval.str); - } + } } break; @@ -4001,9 +4001,7 @@ static pval *nword(char *string, YYLTYPE *pos) static void set_dads(struct pval *dad, struct pval *child_list) { struct pval *t; - + for(t=child_list;t;t=t->next) /* simple stuff */ t->dad = dad; } - - diff --git a/res/ael/ael.tab.h b/res/ael/ael.tab.h index 93fc23d0c..1647649a8 100644 --- a/res/ael/ael.tab.h +++ b/res/ael/ael.tab.h @@ -1,19 +1,19 @@ /* A Bison parser, made by GNU Bison 2.5. */ /* Bison interface for Yacc-like parsers in C - + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. - + This program 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 3 of the License, or (at your option) any later version. - + This program 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, see <http://www.gnu.org/licenses/>. */ @@ -26,7 +26,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -118,6 +118,3 @@ typedef struct YYLTYPE # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif - - - diff --git a/res/ael/ael.y b/res/ael/ael.y index 458863a02..da13c66bc 100644 --- a/res/ael/ael.y +++ b/res/ael/ael.y @@ -42,7 +42,7 @@ static void set_dads(pval *dad, pval *child_list); void reset_parencount(yyscan_t yyscanner); void reset_semicount(yyscan_t yyscanner); void reset_argcount(yyscan_t yyscanner ); - + #define YYLEX_PARAM ((struct parse_io *)parseio)->scanner #define YYERROR_VERBOSE 1 @@ -210,7 +210,7 @@ context : opt_abstract KW_CONTEXT context_name LC elements RC { $$->u1.str = $3; $$->u2.statements = $5; set_dads($$,$5); - $$->u3.abstract = $1;} + $$->u3.abstract = $1;} ; /* optional "abstract" keyword XXX there is no regression test for this */ @@ -421,7 +421,7 @@ word3_list : word { $$ = $1;} free($1); free($2); prev_word = $$; - } + } } | word word word { if (asprintf(&($$), "%s%s%s", $1, $2, $3) < 0) { @@ -544,7 +544,7 @@ statement : LC statements RC { opt_else : KW_ELSE statement { $$ = $2; } | { $$ = NULL ; } - + target : goto_word { $$ = nword($1, &@1); } | goto_word BAR goto_word { $$ = nword($1, &@1); @@ -883,8 +883,7 @@ static pval *nword(char *string, YYLTYPE *pos) static void set_dads(struct pval *dad, struct pval *child_list) { struct pval *t; - + for(t=child_list;t;t=t->next) /* simple stuff */ t->dad = dad; } - diff --git a/res/ael/ael_lex.c b/res/ael/ael_lex.c index 10f669382..a716a1757 100644 --- a/res/ael/ael_lex.c +++ b/res/ael/ael_lex.c @@ -37,7 +37,7 @@ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. + * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 @@ -54,7 +54,7 @@ typedef uint32_t flex_uint32_t; typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; +typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; @@ -187,7 +187,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE; #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) - + /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ @@ -249,7 +249,7 @@ struct yy_buffer_state int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ - + /* Whether to try to fill the input buffer when we reach the * end of it. */ @@ -1033,9 +1033,9 @@ static int yy_init_globals (yyscan_t yyscanner ); /* This must go here because YYSTYPE and YYLTYPE are included * from bison output in section 1.*/ # define yylval yyg->yylval_r - + # define yylloc yyg->yylloc_r - + int ael_yylex_init (yyscan_t* scanner); int ael_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); @@ -1074,9 +1074,9 @@ YYSTYPE * ael_yyget_lval (yyscan_t yyscanner ); void ael_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); YYLTYPE *ael_yyget_lloc (yyscan_t yyscanner ); - + void ael_yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); - + /* Macros after this point can all be overridden by user definitions in * section 1. */ @@ -1090,7 +1090,7 @@ extern int ael_yywrap (yyscan_t yyscanner ); #endif static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); - + #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); #endif @@ -1568,11 +1568,11 @@ YY_RULE_SETUP case 51: YY_RULE_SETUP #line 272 "ael.flex" -{ - /* boy did I open a can of worms when I changed the lexical token "word". +{ + /* boy did I open a can of worms when I changed the lexical token "word". all the above keywords can be used as a beginning to a "word".- - before, a "word" would match a longer sequence than the above - keywords, and all would be well. But now "word" is a single char + before, a "word" would match a longer sequence than the above + keywords, and all would be well. But now "word" is a single char and feeds into a statemachine sort of sequence from there on. So... I added the {KEYWORD}? to the beginning of the word match sequence */ @@ -1674,7 +1674,7 @@ case 59: /* rule 59 can match eol */ YY_RULE_SETUP #line 347 "ael.flex" -{ +{ char c = yytext[yyleng-1]; if (c == '{') parencount2++; @@ -1686,7 +1686,7 @@ case 60: /* rule 60 can match eol */ YY_RULE_SETUP #line 355 "ael.flex" -{ +{ char c = yytext[yyleng-1]; if ( pbcpop2(c)) { /* error */ STORE_LOC; @@ -1728,7 +1728,7 @@ case 62: /* rule 62 can match eol */ YY_RULE_SETUP #line 390 "ael.flex" -{ +{ char c = yytext[yyleng-1]; if (c == '[') parencount3++; @@ -1740,7 +1740,7 @@ case 63: /* rule 63 can match eol */ YY_RULE_SETUP #line 398 "ael.flex" -{ +{ char c = yytext[yyleng-1]; if ( pbcpop3(c)) { /* error */ STORE_LOC; @@ -1967,7 +1967,7 @@ YY_RULE_SETUP glob_t globbuf; /* the current globbuf */ int globbuf_pos = -1; /* where we are in the current globbuf */ globbuf.gl_offs = 0; /* initialize it to silence gcc */ - + p1 = strchr(yytext,'"'); p2 = strrchr(yytext,'"'); if ( include_stack_index >= MAX_INCLUDE_DEPTH ) { @@ -2020,8 +2020,8 @@ case YY_STATE_EOF(brackstate): ael_yy_delete_buffer(YY_CURRENT_BUFFER,yyscanner ); include_stack[include_stack_index-1].globbuf_pos++; setup_filestack(fnamebuf, sizeof(fnamebuf), &include_stack[include_stack_index-1].globbuf, include_stack[include_stack_index-1].globbuf_pos, yyscanner, 0); - /* finish this */ - + /* finish this */ + } else { if (include_stack[include_stack_index].fname) { free(include_stack[include_stack_index].fname); @@ -2036,7 +2036,7 @@ case YY_STATE_EOF(brackstate): } else { globfree(&include_stack[include_stack_index].globbuf); include_stack[include_stack_index].globbuf_pos = -1; - + ael_yy_delete_buffer(YY_CURRENT_BUFFER,yyscanner ); ael_yy_switch_to_buffer(include_stack[include_stack_index].bufstate,yyscanner ); my_lineno = include_stack[include_stack_index].lineno; @@ -2574,7 +2574,7 @@ static void ael_yy_load_buffer_state (yyscan_t yyscanner) YY_BUFFER_STATE ael_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) { YY_BUFFER_STATE b; - + b = (YY_BUFFER_STATE) ael_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in ael_yy_create_buffer()" ); @@ -2618,7 +2618,7 @@ static void ael_yy_load_buffer_state (yyscan_t yyscanner) #ifndef __cplusplus extern int isatty (int ); #endif /* __cplusplus */ - + /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a ael_yyrestart() or at EOF. @@ -2644,7 +2644,7 @@ extern int isatty (int ); } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; - + errno = oerrno; } @@ -2750,9 +2750,9 @@ static void ael_yyensure_buffer_stack (yyscan_t yyscanner) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in ael_yyensure_buffer_stack()" ); - + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - + yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; @@ -2781,12 +2781,12 @@ static void ael_yyensure_buffer_stack (yyscan_t yyscanner) * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. + * @return the newly allocated buffer state object. */ YY_BUFFER_STATE ael_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; - + if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) @@ -2822,7 +2822,7 @@ YY_BUFFER_STATE ael_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yys */ YY_BUFFER_STATE ael_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) { - + return ael_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); } @@ -2839,7 +2839,7 @@ YY_BUFFER_STATE ael_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , char *buf; yy_size_t n; int i; - + /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) ael_yyalloc(n ,yyscanner ); @@ -2907,10 +2907,10 @@ YY_EXTRA_TYPE ael_yyget_extra (yyscan_t yyscanner) int ael_yyget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - + if (! YY_CURRENT_BUFFER) return 0; - + return yylineno; } @@ -2920,10 +2920,10 @@ int ael_yyget_lineno (yyscan_t yyscanner) int ael_yyget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - + if (! YY_CURRENT_BUFFER) return 0; - + return yycolumn; } @@ -2984,8 +2984,8 @@ void ael_yyset_lineno (int line_number , yyscan_t yyscanner) /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "ael_yyset_lineno called with no buffer" , yyscanner); - + yy_fatal_error( "ael_yyset_lineno called with no buffer" , yyscanner); + yylineno = line_number; } @@ -2999,8 +2999,8 @@ void ael_yyset_column (int column_no , yyscan_t yyscanner) /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "ael_yyset_column called with no buffer" , yyscanner); - + yy_fatal_error( "ael_yyset_column called with no buffer" , yyscanner); + yycolumn = column_no; } @@ -3053,13 +3053,13 @@ YYLTYPE *ael_yyget_lloc (yyscan_t yyscanner) struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylloc; } - + void ael_yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylloc = yylloc_param; } - + /* User-visible API */ /* ael_yylex_init is special because it creates the scanner itself, so it is @@ -3107,20 +3107,20 @@ int ael_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals errno = EINVAL; return 1; } - + *ptr_yy_globals = (yyscan_t) ael_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); - + if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } - + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - + ael_yyset_extra (yy_user_defined, *ptr_yy_globals); - + return yy_init_globals ( *ptr_yy_globals ); } @@ -3390,7 +3390,7 @@ struct pval *ael2_parse(char *filename, int *errors) buffer = (char*)malloc(stats.st_size+2); if (fread(buffer, 1, stats.st_size, fin) != stats.st_size) { ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno)); - } + } buffer[stats.st_size]=0; fclose(fin); @@ -3462,7 +3462,7 @@ static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf, buffer = (char*)malloc(stats.st_size+1); if (fread(buffer, 1, stats.st_size, in1) != stats.st_size) { ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno)); - } + } buffer[stats.st_size] = 0; ast_debug(1, " --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size); fclose(in1); @@ -3492,4 +3492,3 @@ static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf, } } } - diff --git a/res/ael/pval.c b/res/ael/pval.c index b0a04fe2f..f927077a8 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -20,7 +20,7 @@ /*! \file * * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2. - * + * */ /*** MODULEINFO @@ -116,16 +116,16 @@ static void print_pval(FILE *fin, pval *item, int depth) { int i; pval *lp; - + for (i=0; i<depth; i++) { fprintf(fin, "\t"); /* depth == indentation */ } - + switch ( item->type ) { case PV_WORD: fprintf(fin,"%s;\n", item->u1.str); /* usually, words are encapsulated in something else */ break; - + case PV_MACRO: fprintf(fin,"macro %s(", item->u1.str); for (lp=item->u2.arglist; lp; lp=lp->next) { @@ -140,7 +140,7 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,"};\n\n"); break; - + case PV_CONTEXT: if ( item->u3.abstract ) fprintf(fin,"abstract context %s {\n", item->u1.str); @@ -152,7 +152,7 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,"};\n\n"); break; - + case PV_MACRO_CALL: fprintf(fin,"&%s(", item->u1.str); for (lp=item->u2.arglist; lp; lp=lp->next) { @@ -162,7 +162,7 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,");\n"); break; - + case PV_APPLICATION_CALL: fprintf(fin,"%s(", item->u1.str); for (lp=item->u2.arglist; lp; lp=lp->next) { @@ -172,22 +172,22 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,");\n"); break; - + case PV_CASE: fprintf(fin,"case %s:\n", item->u1.str); print_pval_list(fin,item->u2.statements, depth+1); break; - + case PV_PATTERN: fprintf(fin,"pattern %s:\n", item->u1.str); print_pval_list(fin,item->u2.statements, depth+1); break; - + case PV_DEFAULT: fprintf(fin,"default:\n"); print_pval_list(fin,item->u2.statements, depth+1); break; - + case PV_CATCH: fprintf(fin,"catch %s {\n", item->u1.str); print_pval_list(fin,item->u2.statements, depth+1); @@ -196,7 +196,7 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,"};\n"); break; - + case PV_SWITCHES: fprintf(fin,"switches {\n"); print_pval_list(fin,item->u1.list,depth+1); @@ -205,7 +205,7 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,"};\n"); break; - + case PV_ESWITCHES: fprintf(fin,"eswitches {\n"); print_pval_list(fin,item->u1.list,depth+1); @@ -214,7 +214,7 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,"};\n"); break; - + case PV_INCLUDES: fprintf(fin,"includes {\n"); for (lp=item->u1.list; lp; lp=lp->next) { @@ -223,7 +223,7 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,"%s", lp->u1.str); /* usually, words are encapsulated in something else */ if (lp->u2.arglist) - fprintf(fin,"|%s|%s|%s|%s", + fprintf(fin,"|%s|%s|%s|%s", lp->u2.arglist->u1.str, lp->u2.arglist->next->u1.str, lp->u2.arglist->next->next->u1.str, @@ -231,13 +231,13 @@ static void print_pval(FILE *fin, pval *item, int depth) ); fprintf(fin,";\n"); /* usually, words are encapsulated in something else */ } - + for (i=0; i<depth; i++) { fprintf(fin,"\t"); /* depth == indentation */ } fprintf(fin,"};\n"); break; - + case PV_STATEMENTBLOCK: fprintf(fin,"{\n"); print_pval_list(fin,item->u1.list, depth+1); @@ -246,15 +246,15 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,"}\n"); break; - + case PV_VARDEC: fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val); break; - + case PV_LOCALVARDEC: fprintf(fin,"local %s=%s;\n", item->u1.str, item->u2.val); break; - + case PV_GOTO: fprintf(fin,"goto %s", item->u1.list->u1.str); if ( item->u1.list->next ) @@ -263,42 +263,42 @@ static void print_pval(FILE *fin, pval *item, int depth) fprintf(fin,",%s", item->u1.list->next->next->u1.str); fprintf(fin,"\n"); break; - + case PV_LABEL: fprintf(fin,"%s:\n", item->u1.str); break; - + case PV_FOR: fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc); print_pval_list(fin,item->u4.for_statements,depth+1); break; - + case PV_WHILE: fprintf(fin,"while (%s)\n", item->u1.str); print_pval_list(fin,item->u2.statements,depth+1); break; - + case PV_BREAK: fprintf(fin,"break;\n"); break; - + case PV_RETURN: fprintf(fin,"return;\n"); break; - + case PV_CONTINUE: fprintf(fin,"continue;\n"); break; - + case PV_RANDOM: case PV_IFTIME: case PV_IF: if ( item->type == PV_IFTIME ) { - - fprintf(fin,"ifTime ( %s|%s|%s|%s )\n", - item->u1.list->u1.str, - item->u1.list->next->u1.str, - item->u1.list->next->next->u1.str, + + fprintf(fin,"ifTime ( %s|%s|%s|%s )\n", + item->u1.list->u1.str, + item->u1.list->next->u1.str, + item->u1.list->next->next->u1.str, item->u1.list->next->next->next->u1.str ); } else if ( item->type == PV_RANDOM ) { @@ -334,7 +334,7 @@ static void print_pval(FILE *fin, pval *item, int depth) print_pval_list(fin,item->u3.else_statements, depth); } break; - + case PV_SWITCH: fprintf(fin,"switch( %s ) {\n", item->u1.str); print_pval_list(fin,item->u2.statements,depth+1); @@ -343,22 +343,22 @@ static void print_pval(FILE *fin, pval *item, int depth) } fprintf(fin,"}\n"); break; - + case PV_EXTENSION: if ( item->u4.regexten ) fprintf(fin, "regexten "); if ( item->u3.hints ) fprintf(fin,"hints(%s) ", item->u3.hints); - + fprintf(fin,"%s => ", item->u1.str); print_pval_list(fin,item->u2.statements,depth+1); fprintf(fin,"\n"); break; - + case PV_IGNOREPAT: fprintf(fin,"ignorepat => %s;\n", item->u1.str); break; - + case PV_GLOBALS: fprintf(fin,"globals {\n"); print_pval_list(fin,item->u1.statements,depth+1); @@ -373,7 +373,7 @@ static void print_pval(FILE *fin, pval *item, int depth) static void print_pval_list(FILE *fin, pval *item, int depth) { pval *i; - + for (i=item; i; i=i->next) { print_pval(fin, i, depth); } @@ -401,12 +401,12 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f but you may not need it */ { pval *lp; - + switch ( item->type ) { case PV_WORD: /* fields: item->u1.str == string associated with this (word). */ break; - + case PV_MACRO: /* fields: item->u1.str == name of macro item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user @@ -416,11 +416,11 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f item->u3.macro_statements == pval list of statements in macro body. */ for (lp=item->u2.arglist; lp; lp=lp->next) { - + } traverse_pval_item_template(item->u3.macro_statements,depth+1); break; - + case PV_CONTEXT: /* fields: item->u1.str == name of context item->u2.statements == pval list of statements in context body @@ -428,7 +428,7 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f */ traverse_pval_item_template(item->u2.statements,depth+1); break; - + case PV_MACRO_CALL: /* fields: item->u1.str == name of macro to call item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user @@ -438,7 +438,7 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f for (lp=item->u2.arglist; lp; lp=lp->next) { } break; - + case PV_APPLICATION_CALL: /* fields: item->u1.str == name of application to call item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user @@ -448,47 +448,47 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f for (lp=item->u2.arglist; lp; lp=lp->next) { } break; - + case PV_CASE: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case */ traverse_pval_item_template(item->u2.statements,depth+1); break; - + case PV_PATTERN: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case */ traverse_pval_item_template(item->u2.statements,depth+1); break; - + case PV_DEFAULT: - /* fields: + /* fields: item->u2.statements == pval list of statements under the case */ traverse_pval_item_template(item->u2.statements,depth+1); break; - + case PV_CATCH: /* fields: item->u1.str == name of extension to catch item->u2.statements == pval list of statements in context body */ traverse_pval_item_template(item->u2.statements,depth+1); break; - + case PV_SWITCHES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ traverse_pval_item_template(item->u1.list,depth+1); break; - + case PV_ESWITCHES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ traverse_pval_item_template(item->u1.list,depth+1); break; - + case PV_INCLUDES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list item->u2.arglist == pval list of 4 PV_WORD elements for time values @@ -496,37 +496,37 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f traverse_pval_item_template(item->u1.list,depth+1); traverse_pval_item_template(item->u2.arglist,depth+1); break; - + case PV_STATEMENTBLOCK: /* fields: item->u1.list == pval list of statements in block, one per entry in the list */ traverse_pval_item_template(item->u1.list,depth+1); break; - + case PV_LOCALVARDEC: case PV_VARDEC: /* fields: item->u1.str == variable name item->u2.val == variable value to assign */ break; - + case PV_GOTO: /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. item->u1.list->u1.str == where the data on a PV_WORD will always be. */ - + if ( item->u1.list->next ) ; if ( item->u1.list->next && item->u1.list->next->next ) ; - + break; - + case PV_LABEL: /* fields: item->u1.str == label name */ break; - + case PV_FOR: /* fields: item->u1.for_init == a string containing the initalizer item->u2.for_test == a string containing the loop test @@ -536,7 +536,7 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f */ traverse_pval_item_template(item->u4.for_statements,depth+1); break; - + case PV_WHILE: /* fields: item->u1.str == the while conditional, as supplied by user @@ -544,22 +544,22 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f */ traverse_pval_item_template(item->u2.statements,depth+1); break; - + case PV_BREAK: /* fields: none */ break; - + case PV_RETURN: /* fields: none */ break; - + case PV_CONTINUE: /* fields: none */ break; - + case PV_IFTIME: /* fields: item->u1.list == there are 4 linked PV_WORDs here. @@ -572,7 +572,7 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f traverse_pval_item_template(item->u3.else_statements,depth+1); } break; - + case PV_RANDOM: /* fields: item->u1.str == the random number expression, as supplied by user @@ -585,7 +585,7 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f traverse_pval_item_template(item->u3.else_statements,depth+1); } break; - + case PV_IF: /* fields: item->u1.str == the if conditional, as supplied by user @@ -598,16 +598,16 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f traverse_pval_item_template(item->u3.else_statements,depth+1); } break; - + case PV_SWITCH: /* fields: item->u1.str == the switch expression - item->u2.statements == a pval list of statements in the switch, + item->u2.statements == a pval list of statements in the switch, (will be case statements, most likely!) */ traverse_pval_item_template(item->u2.statements,depth+1); break; - + case PV_EXTENSION: /* fields: item->u1.str == the extension name, label, whatever it's called @@ -617,12 +617,12 @@ void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy f */ traverse_pval_item_template(item->u2.statements,depth+1); break; - + case PV_IGNOREPAT: /* fields: item->u1.str == the ignorepat data */ break; - + case PV_GLOBALS: /* fields: item->u1.statements == pval list of statements, usually vardecs */ @@ -635,7 +635,7 @@ void traverse_pval_template(pval *item, int depth) /* depth comes in handy for a but you may not need it */ { pval *i; - + for (i=item; i; i=i->next) { traverse_pval_item_template(i, depth); } @@ -695,16 +695,16 @@ static int extension_matches(pval *here, const char *exten, const char *pattern) { int err1; regex_t preg; - + /* simple case, they match exactly, the pattern and exten name */ if (strcmp(pattern,exten) == 0) return 1; - + if (pattern[0] == '_') { char reg1[2000]; const char *p; char *r = reg1; - + if ( strlen(pattern)*5 >= 2000 ) /* safety valve */ { ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n", pattern); @@ -724,7 +724,7 @@ static int extension_matches(pval *here, const char *exten, const char *pattern) *r++ = 'X'; *r++ = ']'; break; - + case 'Z': *r++ = '['; *r++ = '1'; @@ -733,7 +733,7 @@ static int extension_matches(pval *here, const char *exten, const char *pattern) *r++ = 'Z'; *r++ = ']'; break; - + case 'N': *r++ = '['; *r++ = '2'; @@ -742,7 +742,7 @@ static int extension_matches(pval *here, const char *exten, const char *pattern) *r++ = 'N'; *r++ = ']'; break; - + case '[': while ( *p && *p != ']' ) { *r++ = *p++; @@ -753,7 +753,7 @@ static int extension_matches(pval *here, const char *exten, const char *pattern) here->filename, here->startline, here->endline, pattern); } break; - + case '.': case '!': *r++ = '.'; @@ -766,7 +766,7 @@ static int extension_matches(pval *here, const char *exten, const char *pattern) default: *r++ = *p; break; - + } } *r++ = '$'; /* what if the extension is a pattern ?? */ @@ -782,7 +782,7 @@ static int extension_matches(pval *here, const char *exten, const char *pattern) } err1 = regexec(&preg, exten, 0, 0, 0); regfree(&preg); - + if ( err1 ) { /* ast_log(LOG_NOTICE,"*****************************[%d]Extension %s did not match %s(%s)\n", err1,exten, pattern, reg1); */ @@ -792,8 +792,8 @@ static int extension_matches(pval *here, const char *exten, const char *pattern) exten, pattern); */ return 1; } - - + + } else { if ( strcmp(exten,pattern) == 0 ) { return 1; @@ -855,7 +855,7 @@ static void check_timerange(pval *p) } *e = '\0'; e++; - while (*e && !isdigit(*e)) + while (*e && !isdigit(*e)) e++; if (!*e) { ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n", @@ -906,7 +906,7 @@ static void check_dow(pval *DOW) char *c; /* The following line is coincidence, really! */ int s, e; - + dow = ast_strdupa(DOW->u1.str); /* Check for all days */ @@ -1012,7 +1012,7 @@ static void check_month(pval *MON) mon = ast_strdupa(MON->u1.str); /* Check for all days */ - if (ast_strlen_zero(mon) || !strcmp(mon, "*")) + if (ast_strlen_zero(mon) || !strcmp(mon, "*")) return ; /* Get start and ending days */ c = strchr(mon, '-'); @@ -1043,11 +1043,11 @@ static void check_month(pval *MON) static int check_break(pval *item) { pval *p = item; - + while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ { /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make no sense */ - if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN + if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN || p->type == PV_WHILE || p->type == PV_FOR ) { return 1; } @@ -1056,14 +1056,14 @@ static int check_break(pval *item) ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n", item->filename, item->startline, item->endline); errs++; - + return 0; } static int check_continue(pval *item) { pval *p = item; - + while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ { /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make no sense */ @@ -1075,14 +1075,14 @@ static int check_continue(pval *item) ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n", item->filename, item->startline, item->endline); errs++; - + return 0; } static struct pval *in_macro(pval *item) { struct pval *curr; - curr = item; + curr = item; while( curr ) { if( curr->type == PV_MACRO ) { return curr; @@ -1095,7 +1095,7 @@ static struct pval *in_macro(pval *item) static struct pval *in_context(pval *item) { struct pval *curr; - curr = item; + curr = item; while( curr ) { if( curr->type == PV_MACRO || curr->type == PV_CONTEXT ) { return curr; @@ -1113,11 +1113,11 @@ static void check_label(pval *item) struct pval *curr; struct pval *x; int alright = 0; - + /* A label outside an extension just plain does not make sense! */ - + curr = item; - + while( curr ) { if( curr->type == PV_MACRO || curr->type == PV_EXTENSION ) { alright = 1; @@ -1129,21 +1129,21 @@ static void check_label(pval *item) { ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Label %s is not within an extension or macro!\n", item->filename, item->startline, item->endline, item->u1.str); - errs++; + errs++; } - - + + /* basically, ensure that a label is not repeated in a context. Period. The method: well, for each label, find the first label in the context with the same name. If it's not the current label, then throw an error. */ - + /* printf("==== check_label: ====\n"); */ if( !current_extension ) curr = current_context; else curr = current_extension; - + x = find_first_label_in_current_context((char *)item->u1.str, curr); /* printf("Hey, check_label found with item = %x, and x is %x, and currcont is %x, label name is %s\n", item,x, current_context, (char *)item->u1.str); */ if( x && x != item ) @@ -1160,7 +1160,7 @@ static pval *get_goto_target(pval *item) /* just one item-- the label should be in the current extension */ pval *curr_ext = get_extension_or_contxt(item); /* containing exten, or macro */ pval *curr_cont; - + if (!item->u1.list) { return NULL; } @@ -1174,21 +1174,21 @@ static pval *get_goto_target(pval *item) /* TWO items */ if (item->u1.list->next && !item->u1.list->next->next) { - if (!strstr((item->u1.list)->u1.str,"${") + if (!strstr((item->u1.list)->u1.str,"${") && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ { struct pval *x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, curr_cont); return x; } } - + /* All 3 items! */ if (item->u1.list->next && item->u1.list->next->next) { /* all three */ pval *first = item->u1.list; pval *second = item->u1.list->next; pval *third = item->u1.list->next->next; - - if (!strstr((item->u1.list)->u1.str,"${") + + if (!strstr((item->u1.list)->u1.str,"${") && !strstr(item->u1.list->next->u1.str,"${") && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ { struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); @@ -1196,7 +1196,7 @@ static pval *get_goto_target(pval *item) struct pval *p3; struct pval *that_context = find_context(item->u1.list->u1.str); - + /* the target of the goto could be in an included context!! Fancy that!! */ /* look for includes in the current context */ if (that_context) { @@ -1256,17 +1256,17 @@ static void check_goto(pval *item) else return; } - + /* TWO items */ if (item->u1.list->next && !item->u1.list->next->next) { /* two items */ /* printf("Calling find_label_in_current_context with args %s, %s\n", (char*)((item->u1.list)->u1.str), (char *)item->u1.list->next->u1.str); */ - if (!strstr((item->u1.list)->u1.str,"${") + if (!strstr((item->u1.list)->u1.str,"${") && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ { struct pval *z = get_contxt(item); struct pval *x = 0; - + if (z) x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z); @@ -1279,17 +1279,17 @@ static void check_goto(pval *item) return; } } - + /* All 3 items! */ if (item->u1.list->next && item->u1.list->next->next) { /* all three */ pval *first = item->u1.list; pval *second = item->u1.list->next; pval *third = item->u1.list->next->next; - + /* printf("Calling find_label_in_current_db with args %s, %s, %s\n", (char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); */ - if (!strstr((item->u1.list)->u1.str,"${") + if (!strstr((item->u1.list)->u1.str,"${") && !strstr(item->u1.list->next->u1.str,"${") && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ { struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); @@ -1297,7 +1297,7 @@ static void check_goto(pval *item) struct pval *p3; struct pval *found = 0; struct pval *that_context = find_context(item->u1.list->u1.str); - + /* the target of the goto could be in an included context!! Fancy that!! */ /* look for includes in the current context */ if (that_context) { @@ -1333,7 +1333,7 @@ static void check_goto(pval *item) { ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n", item->filename, item->startline, item->endline); - warns++; + warns++; } } } @@ -1342,7 +1342,7 @@ static void check_goto(pval *item) #ifdef STANDALONE struct pbx_find_info pfiq = {.stacklen = 0 }; extern int localized_pbx_load_module(void); - /* if this is a standalone, we will need to make sure the + /* if this is a standalone, we will need to make sure the localized load of extensions.conf is done */ if (!extensions_dot_conf_loaded) { localized_pbx_load_module(); @@ -1350,9 +1350,9 @@ static void check_goto(pval *item) } pbx_find_extension(NULL, NULL, &pfiq, first->u1.str, second->u1.str, atoi(third->u1.str), - atoi(third->u1.str) ? NULL : third->u1.str, NULL, + atoi(third->u1.str) ? NULL : third->u1.str, NULL, atoi(third->u1.str) ? E_MATCH : E_FINDLABEL); - + if (pfiq.status != STATUS_SUCCESS) { ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: Couldn't find goto target %s|%s|%s, not even in extensions.conf!\n", item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str); @@ -1372,24 +1372,24 @@ static void check_goto(pval *item) { ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n", item->filename, item->startline, item->endline); - warns++; + warns++; } } } } } } - + static void find_pval_goto_item(pval *item, int lev) { struct pval *p4; - + if (lev>100) { ast_log(LOG_ERROR,"find_pval_goto in infinite loop! item_type: %u\n\n", item->type); return; } - + switch ( item->type ) { case PV_MACRO: /* fields: item->u1.str == name of macro @@ -1399,12 +1399,12 @@ static void find_pval_goto_item(pval *item, int lev) item->u3.macro_statements == pval list of statements in macro body. */ - + /* printf("Descending into macro %s at line %d\n", item->u1.str, item->startline); */ find_pval_gotos(item->u3.macro_statements,lev+1); /* if we're just searching for a context, don't bother descending into them */ - + break; - + case PV_CONTEXT: /* fields: item->u1.str == name of context item->u2.statements == pval list of statements in context body @@ -1419,7 +1419,7 @@ static void find_pval_goto_item(pval *item, int lev) /* printf("Descending into Case of %s\n", item->u1.str); */ find_pval_gotos(item->u2.statements,lev+1); break; - + case PV_PATTERN: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case @@ -1427,15 +1427,15 @@ static void find_pval_goto_item(pval *item, int lev) /* printf("Descending into Pattern of %s\n", item->u1.str); */ find_pval_gotos(item->u2.statements,lev+1); break; - + case PV_DEFAULT: - /* fields: + /* fields: item->u2.statements == pval list of statements under the case */ /* printf("Descending into default\n"); */ find_pval_gotos(item->u2.statements,lev+1); break; - + case PV_CATCH: /* fields: item->u1.str == name of extension to catch item->u2.statements == pval list of statements in context body @@ -1443,21 +1443,21 @@ static void find_pval_goto_item(pval *item, int lev) /* printf("Descending into catch of %s\n", item->u1.str); */ find_pval_gotos(item->u2.statements,lev+1); break; - + case PV_STATEMENTBLOCK: /* fields: item->u1.list == pval list of statements in block, one per entry in the list */ /* printf("Descending into statement block\n"); */ find_pval_gotos(item->u1.list,lev+1); break; - + case PV_GOTO: /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. item->u1.list->u1.str == where the data on a PV_WORD will always be. */ check_goto(item); /* THE WHOLE FUNCTION OF THIS ENTIRE ROUTINE!!!! */ break; - + case PV_INCLUDES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ @@ -1473,7 +1473,7 @@ static void find_pval_goto_item(pval *item, int lev) } } break; - + case PV_FOR: /* fields: item->u1.for_init == a string containing the initalizer item->u2.for_test == a string containing the loop test @@ -1484,7 +1484,7 @@ static void find_pval_goto_item(pval *item, int lev) /* printf("Descending into for at line %d\n", item->startline); */ find_pval_gotos(item->u4.for_statements,lev+1); break; - + case PV_WHILE: /* fields: item->u1.str == the while conditional, as supplied by user @@ -1493,7 +1493,7 @@ static void find_pval_goto_item(pval *item, int lev) /* printf("Descending into while at line %d\n", item->startline); */ find_pval_gotos(item->u2.statements,lev+1); break; - + case PV_RANDOM: /* fields: item->u1.str == the random number expression, as supplied by user @@ -1501,7 +1501,7 @@ static void find_pval_goto_item(pval *item, int lev) item->u3.else_statements == a pval list of statements in the else (could be zero) fall thru to PV_IF */ - + case PV_IFTIME: /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list @@ -1524,17 +1524,17 @@ static void find_pval_goto_item(pval *item, int lev) find_pval_gotos(item->u3.else_statements,lev+1); } break; - + case PV_SWITCH: /* fields: item->u1.str == the switch expression - item->u2.statements == a pval list of statements in the switch, + item->u2.statements == a pval list of statements in the switch, (will be case statements, most likely!) */ /* printf("Descending into switch at line %d\n", item->startline); */ find_pval_gotos(item->u3.else_statements,lev+1); break; - + case PV_EXTENSION: /* fields: item->u1.str == the extension name, label, whatever it's called @@ -1555,7 +1555,7 @@ static void find_pval_goto_item(pval *item, int lev) static void find_pval_gotos(pval *item,int lev) { pval *i; - + for (i=item; i; i=i->next) { /* printf("About to call pval_goto_item, itemcount=%d, itemtype=%d\n", item_count, i->type); */ find_pval_goto_item(i, lev); @@ -1568,7 +1568,7 @@ static void find_pval_gotos(pval *item,int lev) static struct pval *match_pval_item(pval *item) { pval *x; - + switch ( item->type ) { case PV_MACRO: /* fields: item->u1.str == name of macro @@ -1580,15 +1580,15 @@ static struct pval *match_pval_item(pval *item) */ /* printf(" matching in MACRO %s, match_context=%s; retoncontmtch=%d; \n", item->u1.str, match_context, return_on_context_match); */ if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) { - + /* printf("MACRO: match context is: %s\n", match_context); */ - + if (return_on_context_match && !strcmp(item->u1.str, match_context)) /* if we're just searching for a context, don't bother descending into them */ { /* printf("Returning on matching macro %s\n", match_context); */ return item; } - - + + if (!return_on_context_match) { /* printf("Descending into matching macro %s/%s\n", match_context, item->u1.str); */ if ((x=match_pval(item->u3.macro_statements))) { @@ -1599,9 +1599,9 @@ static struct pval *match_pval_item(pval *item) } else { /* printf("Skipping context/macro %s\n", item->u1.str); */ } - + break; - + case PV_CONTEXT: /* fields: item->u1.str == name of context item->u2.statements == pval list of statements in context body @@ -1614,7 +1614,7 @@ static struct pval *match_pval_item(pval *item) /* printf("non-CONTEXT: Responded with pval match %x\n", x); */ return item; } - + if (!return_on_context_match ) { /* printf("Descending into matching context %s\n", match_context); */ if ((x=match_pval(item->u2.statements))) /* if we're just searching for a context, don't bother descending into them */ { @@ -1637,7 +1637,7 @@ static struct pval *match_pval_item(pval *item) return x; } break; - + case PV_PATTERN: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case @@ -1648,9 +1648,9 @@ static struct pval *match_pval_item(pval *item) return x; } break; - + case PV_DEFAULT: - /* fields: + /* fields: item->u2.statements == pval list of statements under the case */ /* printf(" matching in DEFAULT\n"); */ @@ -1659,7 +1659,7 @@ static struct pval *match_pval_item(pval *item) return x; } break; - + case PV_CATCH: /* fields: item->u1.str == name of extension to catch item->u2.statements == pval list of statements in context body @@ -1670,7 +1670,7 @@ static struct pval *match_pval_item(pval *item) return x; } break; - + case PV_STATEMENTBLOCK: /* fields: item->u1.list == pval list of statements in block, one per entry in the list */ @@ -1680,19 +1680,19 @@ static struct pval *match_pval_item(pval *item) return x; } break; - + case PV_LABEL: /* fields: item->u1.str == label name */ - /* printf("PV_LABEL %s (cont=%s, exten=%s\n", + /* printf("PV_LABEL %s (cont=%s, exten=%s\n", item->u1.str, current_context->u1.str, (current_extension?current_extension->u1.str:"<macro>"));*/ - + if (count_labels) { if (!strcmp(match_label, item->u1.str)) { label_count++; last_matched_label = item; } - + } else { if (!strcmp(match_label, item->u1.str)) { /* printf("LABEL: Responded with pval match %x\n", x); */ @@ -1700,7 +1700,7 @@ static struct pval *match_pval_item(pval *item) } } break; - + case PV_FOR: /* fields: item->u1.for_init == a string containing the initalizer item->u2.for_test == a string containing the loop test @@ -1714,7 +1714,7 @@ static struct pval *match_pval_item(pval *item) return x; } break; - + case PV_WHILE: /* fields: item->u1.str == the while conditional, as supplied by user @@ -1726,7 +1726,7 @@ static struct pval *match_pval_item(pval *item) return x; } break; - + case PV_RANDOM: /* fields: item->u1.str == the random number expression, as supplied by user @@ -1734,7 +1734,7 @@ static struct pval *match_pval_item(pval *item) item->u3.else_statements == a pval list of statements in the else (could be zero) fall thru to PV_IF */ - + case PV_IFTIME: /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list @@ -1760,11 +1760,11 @@ static struct pval *match_pval_item(pval *item) } } break; - + case PV_SWITCH: /* fields: item->u1.str == the switch expression - item->u2.statements == a pval list of statements in the switch, + item->u2.statements == a pval list of statements in the switch, (will be case statements, most likely!) */ /* printf(" matching in SWITCH\n"); */ @@ -1773,7 +1773,7 @@ static struct pval *match_pval_item(pval *item) return x; } break; - + case PV_EXTENSION: /* fields: item->u1.str == the extension name, label, whatever it's called @@ -1820,7 +1820,7 @@ struct pval *match_pval(pval *item) for (i=item; i; i=i->next) { pval *x; /* printf(" -- match pval: item %d\n", i->type); */ - + if ((x = match_pval_item(i))) { /* printf("match_pval: returning x=%x\n", (int)x); */ return x; /* cut the search short */ @@ -1836,7 +1836,7 @@ int count_labels_in_current_context(char *label) count_labels = 1; return_on_context_match = 0; match_pval(current_context->u2.statements); - + return label_count; } #endif @@ -1846,17 +1846,17 @@ struct pval *find_first_label_in_current_context(char *label, pval *curr_cont) /* printf(" --- Got args %s, %s\n", exten, label); */ struct pval *ret; struct pval *p3; - + count_labels = 0; return_on_context_match = 0; match_context = "*"; match_exten = "*"; match_label = label; - + ret = match_pval(curr_cont); if (ret) return ret; - + /* the target of the goto could be in an included context!! Fancy that!! */ /* look for includes in the current context */ for (p3=curr_cont->u2.statements; p3; p3=p3->next) { @@ -1886,7 +1886,7 @@ struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_ /* printf(" --- Got args %s, %s\n", exten, label); */ struct pval *ret; struct pval *p3; - + count_labels = 0; return_on_context_match = 0; match_context = "*"; @@ -1895,7 +1895,7 @@ struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_ ret = match_pval(curr_cont->u2.statements); if (ret) return ret; - + /* the target of the goto could be in an included context!! Fancy that!! */ /* look for includes in the current context */ for (p3=curr_cont->u2.statements; p3; p3=p3->next) { @@ -1940,7 +1940,7 @@ static struct pval *find_label_in_current_db(const char *context, const char *ex match_context = context; match_exten = exten; match_label = label; - + return match_pval(current_db); } @@ -2002,12 +2002,12 @@ int option_matches_j( struct argdesc *should, pval *is, struct argapp *app) { struct argchoice *ac; char *opcop,*q,*p; - + switch (should->dtype) { case ARGD_OPTIONSET: if ( strstr(is->u1.str,"${") ) return 0; /* no checking anything if there's a var reference in there! */ - + opcop = ast_strdupa(is->u1.str); for (q=opcop;*q;q++) { /* erase the innards of X(innard) type arguments, so we don't get confused later */ @@ -2018,7 +2018,7 @@ int option_matches_j( struct argdesc *should, pval *is, struct argapp *app) q = p+1; } } - + for (ac=app->opts; ac; ac=ac->next) { if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0) /* multichar option, no parens, and a match? */ return 0; @@ -2026,13 +2026,13 @@ int option_matches_j( struct argdesc *should, pval *is, struct argapp *app) for (ac=app->opts; ac; ac=ac->next) { if (strlen(ac->name)==1 || strchr(ac->name,'(')) { char *p = strchr(opcop,ac->name[0]); /* wipe out all matched options in the user-supplied string */ - + if (p && *p == 'j') { ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The j option in the %s application call is not appropriate for AEL!\n", is->filename, is->startline, is->endline, app->name); errs++; } - + if (p) { *p = '+'; if (ac->name[1] == '(') { @@ -2057,14 +2057,14 @@ int option_matches_j( struct argdesc *should, pval *is, struct argapp *app) default: return 0; } - + } int option_matches( struct argdesc *should, pval *is, struct argapp *app) { struct argchoice *ac; char *opcop; - + switch (should->dtype) { case ARGD_STRING: if (is_empty(is->u1.str) && should->type == ARGD_REQUIRED) @@ -2072,21 +2072,21 @@ int option_matches( struct argdesc *should, pval *is, struct argapp *app) if (is->u1.str && strlen(is->u1.str) > 0) /* most will match */ return 1; break; - + case ARGD_INT: if (is_int(is->u1.str)) return 1; else return 0; break; - + case ARGD_FLOAT: if (is_float(is->u1.str)) return 1; else return 0; break; - + case ARGD_ENUM: if( !is->u1.str || strlen(is->u1.str) == 0 ) return 1; /* a null arg in the call will match an enum, I guess! */ @@ -2096,10 +2096,10 @@ int option_matches( struct argdesc *should, pval *is, struct argapp *app) } return 0; break; - + case ARGD_OPTIONSET: opcop = ast_strdupa(is->u1.str); - + for (ac=app->opts; ac; ac=ac->next) { if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0) /* multichar option, no parens, and a match? */ return 1; @@ -2107,7 +2107,7 @@ int option_matches( struct argdesc *should, pval *is, struct argapp *app) for (ac=app->opts; ac; ac=ac->next) { if (strlen(ac->name)==1 || strchr(ac->name,'(')) { char *p = strchr(opcop,ac->name[0]); /* wipe out all matched options in the user-supplied string */ - + if (p) { *p = '+'; if (ac->name[1] == '(') { @@ -2138,7 +2138,7 @@ int check_app_args(pval* appcall, pval *arglist, struct argapp *app) struct argdesc *ad = app->args; pval *pa; int z; - + for (pa = arglist; pa; pa=pa->next) { if (!ad) { ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n", @@ -2150,12 +2150,12 @@ int check_app_args(pval* appcall, pval *arglist, struct argapp *app) do { if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */ break; - + z= option_matches( ad, pa, app); if (!z) { if ( !arglist ) arglist=appcall; - + if (ad->type == ARGD_REQUIRED) { ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); @@ -2172,7 +2172,7 @@ int check_app_args(pval* appcall, pval *arglist, struct argapp *app) /* any app nodes left, that are not optional? */ for ( ; ad; ad=ad->next) { if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) { - if ( !arglist ) + if ( !arglist ) arglist=appcall; ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); @@ -2195,11 +2195,11 @@ void check_switch_expr(pval *item, struct argapp *apps) struct appsetvar *v,*v2; struct argchoice *c; pval *t; - + p = item->u1.str; while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) ) p++; - + buff1 = ast_strdupa(p); while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t')) @@ -2220,7 +2220,7 @@ void check_switch_expr(pval *item, struct argapp *apps) int def= 0; int pat = 0; int f1 = 0; - + /* first of all, does this switch have a default case ? */ for (t=item->u2.statements; t; t=t->next) { if (t->type == PV_DEFAULT) { @@ -2274,7 +2274,7 @@ void check_switch_expr(pval *item, struct argapp *apps) if (f1) break; } - + /* see if it sets the var */ if (!f1) { ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find an application call in this extension that sets the expression (%s) value!\n", @@ -2285,7 +2285,7 @@ void check_switch_expr(pval *item, struct argapp *apps) #else pval *t,*tl=0,*p2; int def= 0; - + /* first of all, does this switch have a default case ? */ for (t=item->u2.statements; t; t=t->next) { if (t->type == PV_DEFAULT) { @@ -2298,7 +2298,7 @@ void check_switch_expr(pval *item, struct argapp *apps) return; /* if no default, warn and insert a default case at the end */ p2 = tl->next = calloc(1, sizeof(struct pval)); - + p2->type = PV_DEFAULT; p2->startline = tl->startline; p2->endline = tl->endline; @@ -2308,7 +2308,7 @@ void check_switch_expr(pval *item, struct argapp *apps) ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n", p2->filename, p2->startline, p2->endline); warns++; - + #endif } @@ -2335,7 +2335,7 @@ static void check_abstract_reference(pval *abstract_context) { pval *i,*j; /* find some context includes that reference this context */ - + /* otherwise, print out a warning */ for (i=current_db; i; i=i->next) { @@ -2370,13 +2370,13 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) char errmsg[4096]; char *strp; - + switch (item->type) { case PV_WORD: /* fields: item->u1.str == string associated with this (word). item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */ break; - + case PV_MACRO: /* fields: item->u1.str == name of macro item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user @@ -2390,13 +2390,13 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) current_extension = 0; check_macro_returns(item); - + for (lp=item->u2.arglist; lp; lp=lp->next) { - + } check_pval(item->u3.macro_statements, apps,in_globals); break; - + case PV_CONTEXT: /* fields: item->u1.str == name of context item->u2.statements == pval list of statements in context body @@ -2411,7 +2411,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) in_abstract_context = 0; check_pval(item->u2.statements, apps,in_globals); break; - + case PV_MACRO_CALL: /* fields: item->u1.str == name of macro to call item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user @@ -2419,7 +2419,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) item->u2.arglist->next == next arg */ #ifdef STANDALONE - /* if this is a standalone, we will need to make sure the + /* if this is a standalone, we will need to make sure the localized load of extensions.conf is done */ if (!extensions_dot_conf_loaded) { localized_pbx_load_module(); @@ -2434,14 +2434,14 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) /* look for the macro in the extensions.conf world */ pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH); - + if (pfiq.status != STATUS_SUCCESS) { char namebuf2[256]; snprintf(namebuf2, 256, "macro-%s", item->u1.str); - + /* look for the macro in the extensions.conf world */ pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH); - + if (pfiq2.status == STATUS_SUCCESS) { ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (macro-%s was found in the extensions.conf stuff, but we are using gosubs!)\n", item->filename, item->startline, item->endline, item->u1.str, item->u1.str); @@ -2456,7 +2456,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n", item->filename, item->startline, item->endline, item->u1.str); warns++; - + #endif #ifdef THIS_IS_1DOT4 char namebuf2[256]; @@ -2464,13 +2464,13 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) /* look for the macro in the extensions.conf world */ pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH); - + if (pfiq.status != STATUS_SUCCESS) { ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s was not found in the AEL, nor the extensions.conf !\n", item->filename, item->startline, item->endline, item->u1.str); warns++; } - + #endif } else if (macro_def->type != PV_MACRO) { @@ -2481,7 +2481,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) /* macro_def is a MACRO, so do the args match in number? */ int hereargs = 0; int thereargs = 0; - + for (lp=item->u2.arglist; lp; lp=lp->next) { hereargs++; } @@ -2495,7 +2495,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) } } break; - + case PV_APPLICATION_CALL: /* fields: item->u1.str == name of application to call item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user @@ -2538,7 +2538,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) free(item->u1.str); item->u1.str = 0; } - + #ifdef AAL_ARGCHECK found = 0; for (app=apps; app; app=app->next) { @@ -2555,7 +2555,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) check_app_args(item, item->u2.arglist, app); #endif break; - + case PV_CASE: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case @@ -2564,44 +2564,44 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) /* find the last statement */ check_pval(item->u2.statements, apps,in_globals); break; - + case PV_PATTERN: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case */ /* Make sure sequence of statements under case is terminated with goto, return, or break */ /* find the last statement */ - + check_pval(item->u2.statements, apps,in_globals); break; - + case PV_DEFAULT: - /* fields: + /* fields: item->u2.statements == pval list of statements under the case */ check_pval(item->u2.statements, apps,in_globals); break; - + case PV_CATCH: /* fields: item->u1.str == name of extension to catch item->u2.statements == pval list of statements in context body */ check_pval(item->u2.statements, apps,in_globals); break; - + case PV_SWITCHES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ check_pval(item->u1.list, apps,in_globals); break; - + case PV_ESWITCHES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ check_pval(item->u1.list, apps,in_globals); break; - + case PV_INCLUDES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ @@ -2617,20 +2617,20 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) check_day(lp->u2.arglist->next->next); check_month(lp->u2.arglist->next->next->next); } - + if (that_context) { find_pval_gotos(that_context->u2.statements,0); - + } } break; - + case PV_STATEMENTBLOCK: /* fields: item->u1.list == pval list of statements in block, one per entry in the list */ check_pval(item->u1.list, apps,in_globals); break; - + case PV_VARDEC: /* fields: item->u1.str == variable name item->u2.val == variable value to assign @@ -2649,7 +2649,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) check_expr2_input(item,item->u2.val); } break; - + case PV_LOCALVARDEC: /* fields: item->u1.str == variable name item->u2.val == variable value to assign @@ -2666,7 +2666,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) } check_expr2_input(item,item->u2.val); break; - + case PV_GOTO: /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. item->u1.list->u1.str == where the data on a PV_WORD will always be. @@ -2674,10 +2674,10 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) /* don't check goto's in abstract contexts */ if ( in_abstract_context ) break; - + check_goto(item); break; - + case PV_LABEL: /* fields: item->u1.str == label name */ @@ -2689,7 +2689,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) check_label(item); break; - + case PV_FOR: /* fields: item->u1.for_init == a string containing the initalizer item->u2.for_test == a string containing the loop test @@ -2721,11 +2721,11 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) } check_expr2_input(item,item->u2.for_test); check_expr2_input(item,item->u3.for_inc); - + ast_expr_clear_extra_error_info(); check_pval(item->u4.for_statements, apps,in_globals); break; - + case PV_WHILE: /* fields: item->u1.str == the while conditional, as supplied by user @@ -2743,24 +2743,24 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) check_expr2_input(item,item->u1.str); check_pval(item->u2.statements, apps,in_globals); break; - + case PV_BREAK: /* fields: none */ check_break(item); break; - + case PV_RETURN: /* fields: none */ break; - + case PV_CONTINUE: /* fields: none */ check_continue(item); break; - + case PV_RANDOM: /* fields: item->u1.str == the random number expression, as supplied by user @@ -2785,7 +2785,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) break; case PV_IFTIME: - /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list + /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list item->u2.statements == a pval list of statements in the if () item->u3.else_statements == a pval list of statements in the else @@ -2803,7 +2803,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) check_pval(item->u3.else_statements, apps,in_globals); } break; - + case PV_IF: /* fields: item->u1.str == the if conditional, as supplied by user @@ -2826,11 +2826,11 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) check_pval(item->u3.else_statements, apps,in_globals); } break; - + case PV_SWITCH: /* fields: item->u1.str == the switch expression - item->u2.statements == a pval list of statements in the switch, + item->u2.statements == a pval list of statements in the switch, (will be case statements, most likely!) */ /* we can check the switch expression, see if it matches any of the app variables... @@ -2838,7 +2838,7 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) check_switch_expr(item, apps); check_pval(item->u2.statements, apps,in_globals); break; - + case PV_EXTENSION: /* fields: item->u1.str == the extension name, label, whatever it's called @@ -2847,15 +2847,15 @@ void check_pval_item(pval *item, struct argapp *apps, int in_globals) item->u4.regexten == an int boolean. non-zero says that regexten was specified */ current_extension = item ; - + check_pval(item->u2.statements, apps,in_globals); break; - + case PV_IGNOREPAT: /* fields: item->u1.str == the ignorepat data */ break; - + case PV_GLOBALS: /* fields: item->u1.statements == pval list of statements, usually vardecs */ @@ -2872,16 +2872,16 @@ void check_pval(pval *item, struct argapp *apps, int in_globals) pval *i; /* checks to do: - 1. Do goto's point to actual labels? + 1. Do goto's point to actual labels? 2. Do macro calls reference a macro? 3. Does the number of macro args match the definition? 4. Is a macro call missing its & at the front? 5. Application calls-- we could check syntax for existing applications, - but I need some some sort of universal description bnf for a general - sort of method for checking arguments, in number, maybe even type, at least. + but I need some sort of universal description bnf for a general + sort of method for checking arguments, in number, maybe even type, at least. Don't want to hand code checks for hundreds of applications. */ - + for (i=item; i; i=i->next) { check_pval_item(i,apps,in_globals); } @@ -2889,7 +2889,7 @@ void check_pval(pval *item, struct argapp *apps, int in_globals) void ael2_semantic_check(pval *item, int *arg_errs, int *arg_warns, int *arg_notes) { - + #ifdef AAL_ARGCHECK int argapp_errs =0; char *rfilename; @@ -2901,7 +2901,7 @@ void ael2_semantic_check(pval *item, int *arg_errs, int *arg_warns, int *arg_not #ifdef AAL_ARGCHECK rfilename = ast_alloca(10 + strlen(ast_config_AST_VAR_DIR)); sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR); - + apps = argdesc_parse(rfilename, &argapp_errs); /* giveth */ #endif current_db = item; @@ -2941,7 +2941,7 @@ struct ael_extension *new_exten(void) void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten) { char *p1, *p2; - + if (!exten->plist) { exten->plist = prio; exten->plist_last = prio; @@ -2951,7 +2951,7 @@ void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael } if( !prio->exten ) prio->exten = exten; /* don't override the switch value */ - /* The following code will cause all priorities within an extension + /* The following code will cause all priorities within an extension to have ${EXTEN} or ${EXTEN: replaced with ~~EXTEN~~, which is set just before the first switch in an exten. The switches will muck up the original ${EXTEN} value, so we save it away @@ -2985,17 +2985,17 @@ void destroy_extensions(struct ael_extension *exten) struct ael_extension *ne, *nen; for (ne=exten; ne; ne=nen) { struct ael_priority *pe, *pen; - + if (ne->name) free(ne->name); - + /* cidmatch fields are allocated with name, and freed when the name field is freed. Don't do a free for this field, unless you LIKE to see a crash! */ if (ne->hints) free(ne->hints); - + for (pe=ne->plist; pe; pe=pen) { pen = pe->next; if (pe->app) @@ -3023,7 +3023,7 @@ void destroy_extensions(struct ael_extension *exten) static int label_inside_case(pval *label) { pval *p = label; - + while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ { if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) { return 1; @@ -3098,11 +3098,11 @@ int find_switch_item(pval *item) case PV_LOCALVARDEC: /* fields: item->u1.str == string associated with this (word). */ break; - + case PV_WORD: /* fields: item->u1.str == string associated with this (word). */ break; - + case PV_MACRO: /* fields: item->u1.str == name of macro item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user @@ -3115,7 +3115,7 @@ int find_switch_item(pval *item) if (contains_switch(item->u3.macro_statements)) return 1; break; - + case PV_CONTEXT: /* fields: item->u1.str == name of context item->u2.statements == pval list of statements in context body @@ -3125,7 +3125,7 @@ int find_switch_item(pval *item) if (contains_switch(item->u2.statements)) return 1; break; - + case PV_MACRO_CALL: /* fields: item->u1.str == name of macro to call item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user @@ -3133,7 +3133,7 @@ int find_switch_item(pval *item) item->u2.arglist->next == next arg */ break; - + case PV_APPLICATION_CALL: /* fields: item->u1.str == name of application to call item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user @@ -3141,7 +3141,7 @@ int find_switch_item(pval *item) item->u2.arglist->next == next arg */ break; - + case PV_CASE: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case @@ -3150,7 +3150,7 @@ int find_switch_item(pval *item) if (contains_switch(item->u2.statements)) return 1; break; - + case PV_PATTERN: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case @@ -3159,16 +3159,16 @@ int find_switch_item(pval *item) if (contains_switch(item->u2.statements)) return 1; break; - + case PV_DEFAULT: - /* fields: + /* fields: item->u2.statements == pval list of statements under the case */ /* had better not see this */ if (contains_switch(item->u2.statements)) return 1; break; - + case PV_CATCH: /* fields: item->u1.str == name of extension to catch item->u2.statements == pval list of statements in context body @@ -3177,47 +3177,47 @@ int find_switch_item(pval *item) if (contains_switch(item->u2.statements)) return 1; break; - + case PV_SWITCHES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ break; - + case PV_ESWITCHES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ break; - + case PV_INCLUDES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list item->u2.arglist == pval list of 4 PV_WORD elements for time values */ break; - + case PV_STATEMENTBLOCK: /* fields: item->u1.list == pval list of statements in block, one per entry in the list */ if (contains_switch(item->u1.list) ) return 1; break; - + case PV_VARDEC: /* fields: item->u1.str == variable name item->u2.val == variable value to assign */ break; - + case PV_GOTO: /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. item->u1.list->u1.str == where the data on a PV_WORD will always be. */ break; - + case PV_LABEL: /* fields: item->u1.str == label name */ break; - + case PV_FOR: /* fields: item->u1.for_init == a string containing the initalizer item->u2.for_test == a string containing the loop test @@ -3228,7 +3228,7 @@ int find_switch_item(pval *item) if (contains_switch(item->u4.for_statements)) return 1; break; - + case PV_WHILE: /* fields: item->u1.str == the while conditional, as supplied by user @@ -3237,22 +3237,22 @@ int find_switch_item(pval *item) if (contains_switch(item->u2.statements)) return 1; break; - + case PV_BREAK: /* fields: none */ break; - + case PV_RETURN: /* fields: none */ break; - + case PV_CONTINUE: /* fields: none */ break; - + case PV_IFTIME: /* fields: item->u1.list == there are 4 linked PV_WORDs here. @@ -3267,7 +3267,7 @@ int find_switch_item(pval *item) return 1; } break; - + case PV_RANDOM: /* fields: item->u1.str == the random number expression, as supplied by user @@ -3282,7 +3282,7 @@ int find_switch_item(pval *item) return 1; } break; - + case PV_IF: /* fields: item->u1.str == the if conditional, as supplied by user @@ -3297,16 +3297,16 @@ int find_switch_item(pval *item) return 1; } break; - + case PV_SWITCH: /* fields: item->u1.str == the switch expression - item->u2.statements == a pval list of statements in the switch, + item->u2.statements == a pval list of statements in the switch, (will be case statements, most likely!) */ return 1; /* JACKPOT */ break; - + case PV_EXTENSION: /* fields: item->u1.str == the extension name, label, whatever it's called @@ -3317,12 +3317,12 @@ int find_switch_item(pval *item) if (contains_switch(item->u2.statements)) return 1; break; - + case PV_IGNOREPAT: /* fields: item->u1.str == the ignorepat data */ break; - + case PV_GLOBALS: /* fields: item->u1.statements == pval list of statements, usually vardecs */ @@ -3334,7 +3334,7 @@ int find_switch_item(pval *item) int contains_switch(pval *item) { pval *i; - + for (i=item; i; i=i->next) { if (find_switch_item(i)) return 1; @@ -3374,7 +3374,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, if (!(new_label = malloc(BUF_SIZE))) { return -1; } - + if ((mother_exten && !mother_exten->checked_switch) || (exten && !exten->checked_switch)) { if (contains_switch(statement)) { /* only run contains_switch if you haven't checked before */ if (mother_exten) { @@ -3460,7 +3460,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, pr->origin = p; linkprio(exten, pr, mother_exten); break; - + case PV_GOTO: pr = new_prio(); pr->type = AEL_APPCALL; @@ -3468,22 +3468,22 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, if( p->u2.goto_target ) { p->u3.goto_target_in_case = label_inside_case(p->u2.goto_target); } - + if (!p->u1.list->next) /* just one */ { pr->app = strdup("Goto"); if (!mother_exten) pr->appargs = strdup(p->u1.list->u1.str); - else { /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */ + else { /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */ snprintf(buf1, BUF_SIZE, "%s,%s", mother_exten->name, p->u1.list->u1.str); pr->appargs = strdup(buf1); } - + } else if (p->u1.list->next && !p->u1.list->next->next) /* two */ { snprintf(buf1, BUF_SIZE, "%s,%s", p->u1.list->u1.str, p->u1.list->next->u1.str); pr->app = strdup("Goto"); pr->appargs = strdup(buf1); } else if (p->u1.list->next && p->u1.list->next->next) { - snprintf(buf1, BUF_SIZE, "%s,%s,%s", p->u1.list->u1.str, + snprintf(buf1, BUF_SIZE, "%s,%s,%s", p->u1.list->u1.str, p->u1.list->next->u1.str, p->u1.list->next->next->u1.str); pr->app = strdup("Goto"); @@ -3518,7 +3518,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, for_loop->type = AEL_CONTROL1; /* simple goto */ for_end->type = AEL_APPCALL; for_init->app = strdup("MSet"); - + strcpy(buf2,p->u1.for_init); remove_spaces_before_equals(buf2); strp = strchr(buf2, '='); @@ -3623,20 +3623,20 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, /* link & load! */ linkprio(exten, for_init, mother_exten); linkprio(exten, for_test, mother_exten); - + /* now, put the body of the for loop here */ exten->loop_break = for_end; exten->loop_continue = for_inc; - + if (gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context)) { /* this will link in all the statements here */ return -1; } - + linkprio(exten, for_inc, mother_exten); linkprio(exten, for_loop, mother_exten); linkprio(exten, for_end, mother_exten); - - + + exten->loop_break = loop_break_save; exten->loop_continue = loop_continue_save; for_loop->origin = p; @@ -3663,19 +3663,19 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, while_end->appargs = strdup(buf1); linkprio(exten, while_test, mother_exten); - + /* now, put the body of the for loop here */ exten->loop_break = while_end; exten->loop_continue = while_test; - + if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the while body statements here */ return -1; } linkprio(exten, while_loop, mother_exten); linkprio(exten, while_end, mother_exten); - - + + exten->loop_break = loop_break_save; exten->loop_continue = loop_continue_save; while_loop->origin = p; @@ -3702,11 +3702,11 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, linkprio(exten, switch_test, mother_exten); linkprio(exten, switch_end, mother_exten); - + exten->loop_break = switch_end; exten->loop_continue = 0; default_exists = 0; - + for (p2=p->u2.statements; p2; p2=p2->next) { /* now, for each case/default put the body of the for loop here */ if (p2->type == PV_CASE) { @@ -3725,12 +3725,12 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, /* the break/continue locations are inherited from parent */ switch_case->loop_break = exten->loop_break; switch_case->loop_continue = exten->loop_continue; - + linkexten(exten,switch_case); snprintf(buf1, BUF_SIZE, "sw_%d_%s", local_control_statement_count, p2->u1.str); switch_case->name = strdup(buf1); snprintf(new_label, BUF_SIZE, "sw_%s_%s_%d", label, p2->u1.str, local_control_statement_count); - + if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the case body statements here */ return -1; } @@ -3869,7 +3869,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, } switch_case->context = this_context; switch_case->is_switch = 1; - + /* new: the default case intros a pattern with ., which covers ALMOST everything. but it doesn't cover a NULL pattern. So, we'll define a null extension to match that goto's the default extension. */ @@ -3903,13 +3903,13 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, linkexten(exten,switch_case); snprintf(buf1, BUF_SIZE, "_sw_%d_.", local_control_statement_count); switch_case->name = strdup(buf1); - + snprintf(new_label, BUF_SIZE, "sw_%s_default_%d", label, local_control_statement_count); - + if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the default: body statements here */ return -1; } - + /* here is where we write code to "fall thru" to the next case... if there is one... */ for (p3=p2->u2.statements; p3; p3=p3->next) { if (!p3->next) @@ -3962,7 +3962,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, /* what could it be??? */ } } - + exten->loop_break = loop_break_save; exten->loop_continue = loop_continue_save; switch_test->origin = p; @@ -4037,13 +4037,13 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, case PV_IFTIME: control_statement_count++; snprintf(new_label, BUF_SIZE, "iftime_%s_%d", label, control_statement_count); - + if_test = new_prio(); if_test->type = AEL_IFTIME_CONTROL; snprintf(buf1, BUF_SIZE, "%s,%s,%s,%s", - p->u1.list->u1.str, - p->u1.list->next->u1.str, - p->u1.list->next->next->u1.str, + p->u1.list->u1.str, + p->u1.list->next->u1.str, + p->u1.list->next->next->u1.str, p->u1.list->next->next->next->u1.str); if_test->app = 0; if_test->appargs = strdup(buf1); @@ -4074,33 +4074,33 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, } else { if_false->goto_true = if_end; } - + /* link & load! */ linkprio(exten, if_test, mother_exten); linkprio(exten, if_false, mother_exten); - + /* now, put the body of the if here */ - + if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the statements here */ return -1; } - + if (p->u3.else_statements) { linkprio(exten, if_skip, mother_exten); if (gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context)) { /* this will link in all the statements here */ return -1; } } - + linkprio(exten, if_end, mother_exten); - + break; case PV_RANDOM: case PV_IF: control_statement_count++; snprintf(new_label, BUF_SIZE, "if_%s_%d", label, control_statement_count); - + if_test = new_prio(); if_end = new_prio(); if_test->type = AEL_IF_CONTROL; @@ -4115,7 +4115,7 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, if_end->app = strdup("NoOp"); if_end->appargs = strdup(buf1); if_test->origin = p; - + if (p->u3.else_statements) { if_skip = new_prio(); if_skip->type = AEL_CONTROL1; /* simple goto */ @@ -4125,25 +4125,25 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, if_skip = 0; if_test->goto_false = if_end;; } - + /* link & load! */ linkprio(exten, if_test, mother_exten); - + /* now, put the body of the if here */ - + if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the statements here */ return -1; } - + if (p->u3.else_statements) { linkprio(exten, if_skip, mother_exten); if (gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context)) { /* this will link in all the statements here */ return -1; } } - + linkprio(exten, if_end, mother_exten); - + break; case PV_STATEMENTBLOCK: @@ -4165,12 +4165,12 @@ static int gen_prios(struct ael_extension *exten, char *label, pval *statement, switch_case->has_switch = exten->has_switch; switch_case->checked_switch = exten->checked_switch; } - + switch_case->context = this_context; linkexten(exten,switch_case); switch_case->name = strdup(p->u1.str); snprintf(new_label, BUF_SIZE, "catch_%s_%d",p->u1.str, control_statement_count); - + if (gen_prios(switch_case, new_label, p->u2.statements, mother_exten,this_context)) { /* this will link in all the catch body statements here */ return -1; } @@ -4204,17 +4204,17 @@ void set_priorities(struct ael_extension *exten) i=2; else i=1; - + for (pr=exten->plist; pr; pr=pr->next) { pr->priority_num = i; - + if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan, but we want them to point to the right priority, which would be the next line after the label; */ i++; } - + exten = exten->next_exten; } while ( exten ); } @@ -4230,16 +4230,16 @@ void add_extensions(struct ael_extension *exten) } do { struct ael_priority *last = 0; - + pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1); if (exten->hints) { - if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, + if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, exten->hints, NULL, ast_free_ptr, registrar, NULL, 0)) { ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n", exten->name); } } - + for (pr=exten->plist; pr; pr=pr->next) { char app[2000]; char appargs[2000]; @@ -4251,7 +4251,7 @@ void add_extensions(struct ael_extension *exten) last = pr; continue; } - + if (pr->app) strcpy(app, pr->app); else @@ -4264,7 +4264,7 @@ void add_extensions(struct ael_extension *exten) case AEL_APPCALL: /* easy case. Everything is all set up */ break; - + case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */ /* simple, unconditional goto. */ strcpy(app,"Goto"); @@ -4275,12 +4275,12 @@ void add_extensions(struct ael_extension *exten) } else snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num); break; - + case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */ strcpy(app,"GotoIf"); snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); break; - + case AEL_IF_CONTROL: strcpy(app,"GotoIf"); if (pr->origin->u3.else_statements ) @@ -4303,7 +4303,7 @@ void add_extensions(struct ael_extension *exten) strcpy(app,"Return"); appargs[0] = 0; break; - + default: break; } @@ -4312,10 +4312,10 @@ void add_extensions(struct ael_extension *exten) } else label = 0; - - if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, + + if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, app, strdup(appargs), ast_free_ptr, registrar, NULL, 0)) { - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, + ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, exten->name); } last = pr; @@ -4333,7 +4333,7 @@ static void attach_exten(struct ael_extension **list, struct ael_extension *newm return; } lptr = *list; - + while( lptr->next_exten ) { lptr = lptr->next_exten; } @@ -4344,20 +4344,20 @@ static void attach_exten(struct ael_extension **list, struct ael_extension *newm static pval *get_extension_or_contxt(pval *p) { while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) { - + p = p->dad; } - + return p; } static pval *get_contxt(pval *p) { while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) { - + p = p->dad; } - + return p; } @@ -4368,9 +4368,9 @@ static void fix_gotos_in_extensions(struct ael_extension *exten) struct ael_priority *p; for(p=e->plist;p;p=p->next) { - + if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) { - + /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */ pval *target = p->origin->u2.goto_target; @@ -4378,24 +4378,24 @@ static void fix_gotos_in_extensions(struct ael_extension *exten) pval *pv2 = p->origin; char buf1[500]; char *apparg_save = p->appargs; - + p->appargs = 0; if (!pv2->u1.list->next) /* just one -- it won't hurt to repeat the extension */ { snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->u1.str); p->appargs = strdup(buf1); - + } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ { snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->next->u1.str); p->appargs = strdup(buf1); } else if (pv2->u1.list->next && pv2->u1.list->next->next) { - snprintf(buf1,sizeof(buf1),"%s,%s,%s", pv2->u1.list->u1.str, + snprintf(buf1,sizeof(buf1),"%s,%s,%s", pv2->u1.list->u1.str, z->name, pv2->u1.list->next->next->u1.str); p->appargs = strdup(buf1); } else printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n"); - + if( apparg_save ) { free(apparg_save); } @@ -4446,12 +4446,12 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo for (p=root; p; p=p->next ) { pval *lp; int argc; - + switch (p->type) { case PV_MACRO: - + context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar); - + exten = new_exten(); exten->context = context; exten->name = strdup("~~s~~"); @@ -4466,7 +4466,7 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo np2->appargs = strdup(buf); linkprio(exten, np2, NULL); } - + /* CONTAINS APPCALLS, CATCH, just like extensions... */ if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) { return -1; @@ -4480,35 +4480,35 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo linkprio(exten, np2, NULL); exten-> return_target = np2; } - + set_priorities(exten); attach_exten(&exten_list, exten); break; - + case PV_GLOBALS: /* already done */ break; - + case PV_CONTEXT: context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar); - + /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */ for (p2=p->u2.statements; p2; p2=p2->next) { pval *p3; char *s3; - + switch (p2->type) { case PV_EXTENSION: exten = new_exten(); exten->name = strdup(p2->u1.str); exten->context = context; - + if( (s3=strchr(exten->name, '/') ) != 0 ) { *s3 = 0; exten->cidmatch = s3+1; } - + if ( p2->u3.hints ) exten->hints = strdup(p2->u3.hints); exten->regexten = p2->u4.regexten; @@ -4537,15 +4537,15 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo set_priorities(exten); attach_exten(&exten_list, exten); break; - + case PV_IGNOREPAT: ast_context_add_ignorepat2(context, p2->u1.str, registrar); break; - + case PV_INCLUDES: for (p3 = p2->u1.list; p3 ;p3=p3->next) { if ( p3->u2.arglist ) { - snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s", + snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s", p3->u1.str, p3->u2.arglist->u1.str, p3->u2.arglist->next->u1.str, @@ -4556,7 +4556,7 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo ast_context_add_include2(context, p3->u1.str, registrar); } break; - + case PV_SWITCHES: for (p3 = p2->u1.list; p3 ;p3=p3->next) { char *c = strchr(p3->u1.str, '/'); @@ -4586,13 +4586,13 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo break; } } - + break; - + default: /* huh? what? */ break; - + } } @@ -4666,7 +4666,7 @@ int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *lo fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */ add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */ destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */ - + return 0; } @@ -4684,7 +4684,7 @@ void destroy_pval_item(pval *item) if (item->filename) free(item->filename); - + switch (item->type) { case PV_WORD: /* fields: item->u1.str == string associated with this (word). */ @@ -4693,7 +4693,7 @@ void destroy_pval_item(pval *item) if ( item->u2.arglist ) destroy_pval(item->u2.arglist); break; - + case PV_MACRO: /* fields: item->u1.str == name of macro item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user @@ -4707,7 +4707,7 @@ void destroy_pval_item(pval *item) free(item->u1.str); destroy_pval(item->u3.macro_statements); break; - + case PV_CONTEXT: /* fields: item->u1.str == name of context item->u2.statements == pval list of statements in context body @@ -4717,7 +4717,7 @@ void destroy_pval_item(pval *item) free(item->u1.str); destroy_pval(item->u2.statements); break; - + case PV_MACRO_CALL: /* fields: item->u1.str == name of macro to call item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user @@ -4728,7 +4728,7 @@ void destroy_pval_item(pval *item) free(item->u1.str); destroy_pval(item->u2.arglist); break; - + case PV_APPLICATION_CALL: /* fields: item->u1.str == name of application to call item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user @@ -4739,7 +4739,7 @@ void destroy_pval_item(pval *item) free(item->u1.str); destroy_pval(item->u2.arglist); break; - + case PV_CASE: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case @@ -4748,7 +4748,7 @@ void destroy_pval_item(pval *item) free(item->u1.str); destroy_pval(item->u2.statements); break; - + case PV_PATTERN: /* fields: item->u1.str == value of case item->u2.statements == pval list of statements under the case @@ -4757,14 +4757,14 @@ void destroy_pval_item(pval *item) free(item->u1.str); destroy_pval(item->u2.statements); break; - + case PV_DEFAULT: - /* fields: + /* fields: item->u2.statements == pval list of statements under the case */ destroy_pval(item->u2.statements); break; - + case PV_CATCH: /* fields: item->u1.str == name of extension to catch item->u2.statements == pval list of statements in context body @@ -4773,32 +4773,32 @@ void destroy_pval_item(pval *item) free(item->u1.str); destroy_pval(item->u2.statements); break; - + case PV_SWITCHES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ destroy_pval(item->u1.list); break; - + case PV_ESWITCHES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list */ destroy_pval(item->u1.list); break; - + case PV_INCLUDES: /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list item->u2.arglist == pval list of 4 PV_WORD elements for time values */ destroy_pval(item->u1.list); break; - + case PV_STATEMENTBLOCK: /* fields: item->u1.list == pval list of statements in block, one per entry in the list */ destroy_pval(item->u1.list); break; - + case PV_LOCALVARDEC: case PV_VARDEC: /* fields: item->u1.str == variable name @@ -4809,22 +4809,22 @@ void destroy_pval_item(pval *item) if (item->u2.val) free(item->u2.val); break; - + case PV_GOTO: /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. item->u1.list->u1.str == where the data on a PV_WORD will always be. */ - + destroy_pval(item->u1.list); break; - + case PV_LABEL: /* fields: item->u1.str == label name */ if (item->u1.str) free(item->u1.str); break; - + case PV_FOR: /* fields: item->u1.for_init == a string containing the initalizer item->u2.for_test == a string containing the loop test @@ -4840,7 +4840,7 @@ void destroy_pval_item(pval *item) free(item->u3.for_inc); destroy_pval(item->u4.for_statements); break; - + case PV_WHILE: /* fields: item->u1.str == the while conditional, as supplied by user @@ -4850,22 +4850,22 @@ void destroy_pval_item(pval *item) free(item->u1.str); destroy_pval(item->u2.statements); break; - + case PV_BREAK: /* fields: none */ break; - + case PV_RETURN: /* fields: none */ break; - + case PV_CONTINUE: /* fields: none */ break; - + case PV_IFTIME: /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list @@ -4879,7 +4879,7 @@ void destroy_pval_item(pval *item) destroy_pval(item->u3.else_statements); } break; - + case PV_RANDOM: /* fields: item->u1.str == the random percentage, as supplied by user @@ -4901,18 +4901,18 @@ void destroy_pval_item(pval *item) destroy_pval(item->u3.else_statements); } break; - + case PV_SWITCH: /* fields: item->u1.str == the switch expression - item->u2.statements == a pval list of statements in the switch, + item->u2.statements == a pval list of statements in the switch, (will be case statements, most likely!) */ if (item->u1.str) free(item->u1.str); destroy_pval(item->u2.statements); break; - + case PV_EXTENSION: /* fields: item->u1.str == the extension name, label, whatever it's called @@ -4926,14 +4926,14 @@ void destroy_pval_item(pval *item) free(item->u3.hints); destroy_pval(item->u2.statements); break; - + case PV_IGNOREPAT: /* fields: item->u1.str == the ignorepat data */ if (item->u1.str) free(item->u1.str); break; - + case PV_GLOBALS: /* fields: item->u1.statements == pval list of statements, usually vardecs */ @@ -4943,13 +4943,13 @@ void destroy_pval_item(pval *item) free(item); } -void destroy_pval(pval *item) +void destroy_pval(pval *item) { pval *i,*nxt; - + for (i=item; i; i=nxt) { nxt = i->next; - + destroy_pval_item(i); } } @@ -5019,14 +5019,14 @@ int ael_is_funcname(char *name) int s,t; t = sizeof(ael_funclist)/sizeof(char*); s = 0; - while ((s < t) && strcasecmp(name, ael_funclist[s])) + while ((s < t) && strcasecmp(name, ael_funclist[s])) s++; if ( s < t ) return 1; else return 0; } -#endif +#endif /* PVAL PI */ @@ -5129,7 +5129,7 @@ void pvalMacroAddStatement( pval *p, pval *statement ) else linku1(p->u3.macro_statements, statement); - + } pval *pvalMacroWalkStatements( pval *p, pval **next_statement ) @@ -5533,35 +5533,35 @@ char* pvalVarDecGetValue( pval *p ) void pvalGotoSetTarget( pval *p, char *context, char *exten, char *label ) { pval *con, *ext, *pri; - + if (!pvalCheckType(p, "pvalGotoSetTarget", PV_GOTO)) return; if (context && strlen(context)) { con = pvalCreateNode(PV_WORD); ext = pvalCreateNode(PV_WORD); pri = pvalCreateNode(PV_WORD); - + con->u1.str = context; ext->u1.str = exten; pri->u1.str = label; - + con->next = ext; ext->next = pri; p->u1.list = con; } else if (exten && strlen(exten)) { ext = pvalCreateNode(PV_WORD); pri = pvalCreateNode(PV_WORD); - + ext->u1.str = exten; pri->u1.str = label; - + ext->next = pri; p->u1.list = ext; } else { pri = pvalCreateNode(PV_WORD); - + pri->u1.str = label; - + p->u1.list = pri; } } @@ -5574,7 +5574,7 @@ void pvalGotoGetTarget( pval *p, char **context, char **exten, char **label ) *context = p->u1.list->u1.str; *exten = p->u1.list->next->u1.str; *label = p->u1.list->next->next->u1.str; - + } else if (p->u1.list && p->u1.list->next ) { *exten = p->u1.list->u1.str; *label = p->u1.list->next->u1.str; @@ -5584,7 +5584,7 @@ void pvalGotoGetTarget( pval *p, char **context, char **exten, char **label ) *label = p->u1.list->u1.str; *context = 0; *exten = 0; - + } else { *context = 0; *exten = 0; @@ -5940,4 +5940,3 @@ pval * linku1(pval *head, pval *tail) } return head; } - diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h index 093e3f4f5..328349b34 100644 --- a/res/ari/ari_model_validators.h +++ b/res/ari/ari_model_validators.h @@ -148,7 +148,7 @@ int ast_ari_validate_list(struct ast_json *json, int (*fn)(struct ast_json *)); /*! @} */ /*! - * \brief Function type for validator functions. Allows for + * \brief Function type for validator functions. Allows for */ typedef int (*ari_validator)(struct ast_json *json); diff --git a/res/ari/config.c b/res/ari/config.c index a080bb713..46d23c61d 100644 --- a/res/ari/config.c +++ b/res/ari/config.c @@ -39,8 +39,8 @@ static struct aco_type general_option = { .type = ACO_GLOBAL, .name = "general", .item_offset = offsetof(struct ast_ari_conf, general), - .category = "^general$", - .category_match = ACO_WHITELIST, + .category = "general", + .category_match = ACO_WHITELIST_EXACT, }; static struct aco_type *general_options[] = ACO_TYPES(&general_option); @@ -156,8 +156,8 @@ static void *user_find(struct ao2_container *tmp_container, const char *cat) static struct aco_type user_option = { .type = ACO_ITEM, .name = "user", - .category_match = ACO_BLACKLIST, - .category = "^general$", + .category_match = ACO_BLACKLIST_EXACT, + .category = "general", .matchfield = "type", .matchvalue = "user", .item_alloc = user_alloc, diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c index a320c2987..9808288e9 100644 --- a/res/ari/resource_bridges.c +++ b/res/ari/resource_bridges.c @@ -24,8 +24,6 @@ */ /*** MODULEINFO - <depend type="module">res_stasis_recording</depend> - <depend type="module">res_stasis_playback</depend> <support_level>core</support_level> ***/ diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index 6b4f26c25..cdf0f8820 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -24,10 +24,6 @@ */ /*** MODULEINFO - <depend type="module">res_stasis_answer</depend> - <depend type="module">res_stasis_playback</depend> - <depend type="module">res_stasis_recording</depend> - <depend type="module">res_stasis_snoop</depend> <support_level>core</support_level> ***/ diff --git a/res/ari/resource_device_states.c b/res/ari/resource_device_states.c index 020d9301f..c442fa51b 100644 --- a/res/ari/resource_device_states.c +++ b/res/ari/resource_device_states.c @@ -24,7 +24,6 @@ */ /*** MODULEINFO - <depend type="module">res_stasis_device_state</depend> <support_level>core</support_level> ***/ diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c index 992c562a7..5a8e89858 100644 --- a/res/ari/resource_events.c +++ b/res/ari/resource_events.c @@ -24,7 +24,6 @@ */ /*** MODULEINFO - <depend type="module">res_http_websocket</depend> <support_level>core</support_level> ***/ @@ -438,7 +437,7 @@ static int event_session_alloc(struct ast_tcptls_session_instance *ser, if (register_handler(app, stasis_app_message_handler, session)) { ast_log(LOG_WARNING, "Stasis registration failed for application: '%s'\n", app); return event_session_allocation_error_handler( - session, ERROR_TYPE_STASIS_REGISTRATION, ser); + session, ERROR_TYPE_STASIS_REGISTRATION, ser); } } diff --git a/res/ari/resource_mailboxes.c b/res/ari/resource_mailboxes.c index 3577e6515..ae0f24978 100644 --- a/res/ari/resource_mailboxes.c +++ b/res/ari/resource_mailboxes.c @@ -24,7 +24,6 @@ */ /*** MODULEINFO - <depend type="module">res_stasis_mailbox</depend> <support_level>core</support_level> ***/ diff --git a/res/ari/resource_playbacks.c b/res/ari/resource_playbacks.c index 57f424c01..fc05a8d03 100644 --- a/res/ari/resource_playbacks.c +++ b/res/ari/resource_playbacks.c @@ -24,7 +24,6 @@ */ /*** MODULEINFO - <depend type="module">res_stasis_playback</depend> <support_level>core</support_level> ***/ diff --git a/res/ari/resource_recordings.c b/res/ari/resource_recordings.c index 39ef65ce3..090f26370 100644 --- a/res/ari/resource_recordings.c +++ b/res/ari/resource_recordings.c @@ -24,7 +24,6 @@ */ /*** MODULEINFO - <depend type="module">res_stasis_recording</depend> <support_level>core</support_level> ***/ diff --git a/res/parking/res_parking.h b/res/parking/res_parking.h index f4ef2ea09..3c34e5c92 100644 --- a/res/parking/res_parking.h +++ b/res/parking/res_parking.h @@ -135,7 +135,7 @@ struct parking_lot_cfg *parking_lot_cfg_create(const char *cat); * \param dynamic non-zero if creating a dynamic parking lot with this. Don't replace existing parking lots. Ever. * * \retval A reference to the new parking lot - * \retval NULL if it was not found and could not be be allocated + * \retval NULL if it was not found and could not be allocated * * \note The parking lot will need to be unreffed if it ever falls out of scope * \note The parking lot will automatically be added to the parking lot container if needed as part of this process diff --git a/res/res_ael_share.c b/res/res_ael_share.c index 3539eb843..28ca2028d 100644 --- a/res/res_ael_share.c +++ b/res/res_ael_share.c @@ -21,7 +21,7 @@ * \brief Shareable AEL code -- mainly between internal and external modules * * \author Steve Murphy <murf@digium.com> - * + * * \ingroup applications */ diff --git a/res/res_agi.c b/res/res_agi.c index 13af48f49..0931c1a07 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -2046,7 +2046,7 @@ static int handle_connection(const char *agiurl, const struct ast_sockaddr addr, FastAGI defaults to port 4573 */ static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds) { - int s = 0, flags; + int s = 0; char *host, *script; int num_addrs = 0, i = 0; struct ast_sockaddr *addrs; @@ -2076,14 +2076,7 @@ static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds) continue; } - if ((flags = fcntl(s, F_GETFL)) < 0) { - ast_log(LOG_WARNING, "fcntl(F_GETFL) failed: %s\n", strerror(errno)); - close(s); - continue; - } - - if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { - ast_log(LOG_WARNING, "fnctl(F_SETFL) failed: %s\n", strerror(errno)); + if (ast_fd_set_flags(s, O_NONBLOCK)) { close(s); continue; } @@ -2249,9 +2242,8 @@ static enum agi_result launch_script(struct ast_channel *chan, char *script, int close(toast[1]); return AGI_RESULT_FAILURE; } - res = fcntl(audio[1], F_GETFL); - if (res > -1) - res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK); + + res = ast_fd_set_flags(audio[1], O_NONBLOCK); if (res < 0) { ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno)); close(fromast[0]); @@ -3823,8 +3815,6 @@ int AST_OPTIONAL_API_NAME(ast_agi_register)(struct ast_module *mod, agi_command AST_RWLIST_WRLOCK(&agi_commands); AST_LIST_INSERT_TAIL(&agi_commands, cmd, list); AST_RWLIST_UNLOCK(&agi_commands); - if (mod != ast_module_info->self) - ast_module_ref(ast_module_info->self); ast_verb(2, "AGI Command '%s' registered\n",fullcmd); return 1; } else { @@ -3833,7 +3823,7 @@ int AST_OPTIONAL_API_NAME(ast_agi_register)(struct ast_module *mod, agi_command } } -int AST_OPTIONAL_API_NAME(ast_agi_unregister)(struct ast_module *mod, agi_command *cmd) +int AST_OPTIONAL_API_NAME(ast_agi_unregister)(agi_command *cmd) { struct agi_command *e; int unregistered = 0; @@ -3845,8 +3835,6 @@ int AST_OPTIONAL_API_NAME(ast_agi_unregister)(struct ast_module *mod, agi_comman AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) { if (cmd == e) { AST_RWLIST_REMOVE_CURRENT(list); - if (mod != ast_module_info->self) - ast_module_unref(ast_module_info->self); #ifdef AST_XML_DOCS if (e->docsrc == AST_XML_DOC) { ast_free((char *) e->summary); @@ -3893,7 +3881,7 @@ int AST_OPTIONAL_API_NAME(ast_agi_register_multiple)(struct ast_module *mod, str to fail is if the command is not registered */ - (void) ast_agi_unregister(mod, cmd + x - 1); + (void) ast_agi_unregister(cmd + x - 1); } return -1; } @@ -3901,7 +3889,7 @@ int AST_OPTIONAL_API_NAME(ast_agi_register_multiple)(struct ast_module *mod, str return 0; } -int AST_OPTIONAL_API_NAME(ast_agi_unregister_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len) +int AST_OPTIONAL_API_NAME(ast_agi_unregister_multiple)(struct agi_command *cmd, unsigned int len) { unsigned int i; int res = 0; @@ -3911,7 +3899,7 @@ int AST_OPTIONAL_API_NAME(ast_agi_unregister_multiple)(struct ast_module *mod, s attempts failed... there is no recourse if any of them do */ - res |= ast_agi_unregister(mod, cmd + i); + res |= ast_agi_unregister(cmd + i); } return res; @@ -4048,14 +4036,19 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch parse_args(buf, &argc, argv); c = find_command(argv, 0); - if (c && (!dead || (dead && c->dead))) { - /* if this command wasn't registered by res_agi, be sure to usecount - the module we are using */ - if (c->mod != ast_module_info->self) - ast_module_ref(c->mod); + if (!c || !ast_module_running_ref(c->mod)) { + ami_res = "Invalid or unknown command"; + resultcode = 510; + + ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res); + + publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res); + + return AGI_RESULT_SUCCESS; + } + + if (!dead || (dead && c->dead)) { res = c->handler(chan, agi, argc, argv); - if (c->mod != ast_module_info->self) - ast_module_unref(c->mod); switch (res) { case RESULT_SHOWUSAGE: ami_res = "Usage"; @@ -4102,21 +4095,15 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch break; } - } else if (c) { + } else { ami_res = "Command Not Permitted on a dead channel or intercept routine"; resultcode = 511; ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res); publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res); - } else { - ami_res = "Invalid or unknown command"; - resultcode = 510; - - ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res); - - publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res); } + ast_module_unref(c->mod); return AGI_RESULT_SUCCESS; } @@ -4668,7 +4655,7 @@ AST_TEST_DEFINE(test_agi_null_docs) } #endif - ast_agi_unregister(ast_module_info->self, &noop_command); + ast_agi_unregister(&noop_command); return res; } #endif @@ -4682,7 +4669,7 @@ static int unload_module(void) STASIS_MESSAGE_TYPE_CLEANUP(agi_async_end_type); ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi)); - ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands)); + ast_agi_unregister_multiple(commands, ARRAY_LEN(commands)); ast_unregister_application(eapp); ast_unregister_application(deadapp); ast_manager_unregister("AGI"); @@ -4715,9 +4702,6 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } - /* For Optional API. */ - ast_module_shutdown_ref(AST_MODULE_SELF); - return AST_MODULE_LOAD_SUCCESS; } @@ -4726,4 +4710,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_speech", ); diff --git a/res/res_ari.c b/res/res_ari.c index 9104eded3..354201bf3 100644 --- a/res/res_ari.c +++ b/res/res_ari.c @@ -196,7 +196,6 @@ int ast_ari_add_handler(struct stasis_rest_handlers *handler) ao2_cleanup(root_handler); ao2_ref(new_handler, +1); root_handler = new_handler; - ast_module_ref(ast_module_info->self); return 0; } @@ -222,7 +221,6 @@ int ast_ari_remove_handler(struct stasis_rest_handlers *handler) memcpy(new_handler, root_handler, sizeof(*new_handler)); for (i = 0, j = 0; i < root_handler->num_children; ++i) { if (root_handler->children[i] == handler) { - ast_module_unref(ast_module_info->self); continue; } new_handler->children[j++] = root_handler->children[i]; @@ -1197,6 +1195,7 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .load = load_module, .unload = unload_module, .reload = reload_module, - .nonoptreq = "res_http_websocket", + .optional_modules = "res_http_websocket", + .requires = "http,res_stasis", .load_pri = AST_MODPRI_APP_DEPEND, ); diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c index cf700c464..fd8a448ce 100644 --- a/res/res_ari_applications.c +++ b/res/res_ari_applications.c @@ -493,7 +493,6 @@ static struct stasis_rest_handlers applications = { static int unload_module(void) { ast_ari_remove_handler(&applications); - stasis_app_unref(); return 0; } @@ -501,10 +500,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&applications); if (res) { unload_module(); @@ -518,5 +514,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Sta .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis", ); diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c index eb0617b4c..e143a7f6a 100644 --- a/res/res_ari_asterisk.c +++ b/res/res_ari_asterisk.c @@ -1214,7 +1214,6 @@ static struct stasis_rest_handlers asterisk = { static int unload_module(void) { ast_ari_remove_handler(&asterisk); - stasis_app_unref(); return 0; } @@ -1222,10 +1221,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&asterisk); if (res) { unload_module(); @@ -1239,5 +1235,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Ast .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis", ); diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c index 35fd3bd7f..7ef0f684a 100644 --- a/res/res_ari_bridges.c +++ b/res/res_ari_bridges.c @@ -35,6 +35,8 @@ <depend type="module">res_ari</depend> <depend type="module">res_ari_model</depend> <depend type="module">res_stasis</depend> + <depend type="module">res_stasis_recording</depend> + <depend type="module">res_stasis_playback</depend> <support_level>core</support_level> ***/ @@ -1554,7 +1556,6 @@ static struct stasis_rest_handlers bridges = { static int unload_module(void) { ast_ari_remove_handler(&bridges); - stasis_app_unref(); return 0; } @@ -1562,10 +1563,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&bridges); if (res) { unload_module(); @@ -1579,5 +1577,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Bri .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis,res_stasis_recording,res_stasis_playback", ); diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c index f6befcc90..dae146c43 100644 --- a/res/res_ari_channels.c +++ b/res/res_ari_channels.c @@ -35,6 +35,10 @@ <depend type="module">res_ari</depend> <depend type="module">res_ari_model</depend> <depend type="module">res_stasis</depend> + <depend type="module">res_stasis_answer</depend> + <depend type="module">res_stasis_playback</depend> + <depend type="module">res_stasis_recording</depend> + <depend type="module">res_stasis_snoop</depend> <support_level>core</support_level> ***/ @@ -2844,7 +2848,6 @@ static struct stasis_rest_handlers channels = { static int unload_module(void) { ast_ari_remove_handler(&channels); - stasis_app_unref(); return 0; } @@ -2852,10 +2855,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&channels); if (res) { unload_module(); @@ -2869,5 +2869,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Cha .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis,res_stasis_answer,res_stasis_playback,res_stasis_recording,res_stasis_snoop", ); diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c index f39393562..12962b68a 100644 --- a/res/res_ari_device_states.c +++ b/res/res_ari_device_states.c @@ -35,6 +35,7 @@ <depend type="module">res_ari</depend> <depend type="module">res_ari_model</depend> <depend type="module">res_stasis</depend> + <depend type="module">res_stasis_device_state</depend> <support_level>core</support_level> ***/ @@ -324,7 +325,6 @@ static struct stasis_rest_handlers deviceStates = { static int unload_module(void) { ast_ari_remove_handler(&deviceStates); - stasis_app_unref(); return 0; } @@ -332,10 +332,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&deviceStates); if (res) { unload_module(); @@ -349,5 +346,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Dev .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis,res_stasis_device_state", ); diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c index d1242c0fb..947da71e2 100644 --- a/res/res_ari_endpoints.c +++ b/res/res_ari_endpoints.c @@ -448,7 +448,6 @@ static struct stasis_rest_handlers endpoints = { static int unload_module(void) { ast_ari_remove_handler(&endpoints); - stasis_app_unref(); return 0; } @@ -456,10 +455,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&endpoints); if (res) { unload_module(); @@ -473,5 +469,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - End .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis", ); diff --git a/res/res_ari_events.c b/res/res_ari_events.c index f916d0e4e..c8f28f97b 100644 --- a/res/res_ari_events.c +++ b/res/res_ari_events.c @@ -35,6 +35,7 @@ <depend type="module">res_ari</depend> <depend type="module">res_ari_model</depend> <depend type="module">res_stasis</depend> + <depend type="module">res_http_websocket</depend> <support_level>core</support_level> ***/ @@ -423,7 +424,6 @@ static int unload_module(void) ao2_cleanup(events.ws_server); events.ws_server = NULL; ast_ari_websocket_events_event_websocket_dtor(); - stasis_app_unref(); return 0; } @@ -431,35 +431,29 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); + struct ast_websocket_protocol *protocol; - /* This is scoped to not conflict with CHECK_ARI_MODULE_LOADED */ - { - struct ast_websocket_protocol *protocol; - - if (ast_ari_websocket_events_event_websocket_init() == -1) { - return AST_MODULE_LOAD_DECLINE; - } + if (ast_ari_websocket_events_event_websocket_init() == -1) { + return AST_MODULE_LOAD_DECLINE; + } - events.ws_server = ast_websocket_server_create(); - if (!events.ws_server) { - ast_ari_websocket_events_event_websocket_dtor(); - return AST_MODULE_LOAD_DECLINE; - } + events.ws_server = ast_websocket_server_create(); + if (!events.ws_server) { + ast_ari_websocket_events_event_websocket_dtor(); + return AST_MODULE_LOAD_DECLINE; + } - protocol = ast_websocket_sub_protocol_alloc("ari"); - if (!protocol) { - ao2_ref(events.ws_server, -1); - events.ws_server = NULL; - ast_ari_websocket_events_event_websocket_dtor(); - return AST_MODULE_LOAD_DECLINE; - } - protocol->session_attempted = ast_ari_events_event_websocket_ws_attempted_cb; - protocol->session_established = ast_ari_events_event_websocket_ws_established_cb; - res |= ast_websocket_server_add_protocol2(events.ws_server, protocol); + protocol = ast_websocket_sub_protocol_alloc("ari"); + if (!protocol) { + ao2_ref(events.ws_server, -1); + events.ws_server = NULL; + ast_ari_websocket_events_event_websocket_dtor(); + return AST_MODULE_LOAD_DECLINE; } + protocol->session_attempted = ast_ari_events_event_websocket_ws_attempted_cb; + protocol->session_established = ast_ari_events_event_websocket_ws_established_cb; + res |= ast_websocket_server_add_protocol2(events.ws_server, protocol); - stasis_app_ref(); res |= ast_ari_add_handler(&events); if (res) { unload_module(); @@ -473,5 +467,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Web .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis,res_http_websocket", ); diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c index 1f6d2cc81..e25a7bc3d 100644 --- a/res/res_ari_mailboxes.c +++ b/res/res_ari_mailboxes.c @@ -35,6 +35,7 @@ <depend type="module">res_ari</depend> <depend type="module">res_ari_model</depend> <depend type="module">res_stasis</depend> + <depend type="module">res_stasis_mailbox</depend> <support_level>core</support_level> ***/ @@ -330,7 +331,6 @@ static struct stasis_rest_handlers mailboxes = { static int unload_module(void) { ast_ari_remove_handler(&mailboxes); - stasis_app_unref(); return 0; } @@ -338,10 +338,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&mailboxes); if (res) { unload_module(); @@ -355,5 +352,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Mai .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis,res_stasis_mailbox", ); diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c index 40099cfb4..5fbfcf165 100644 --- a/res/res_ari_playbacks.c +++ b/res/res_ari_playbacks.c @@ -35,6 +35,7 @@ <depend type="module">res_ari</depend> <depend type="module">res_ari_model</depend> <depend type="module">res_stasis</depend> + <depend type="module">res_stasis_playback</depend> <support_level>core</support_level> ***/ @@ -282,7 +283,6 @@ static struct stasis_rest_handlers playbacks = { static int unload_module(void) { ast_ari_remove_handler(&playbacks); - stasis_app_unref(); return 0; } @@ -290,10 +290,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&playbacks); if (res) { unload_module(); @@ -307,5 +304,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Pla .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis,res_stasis_playback", ); diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c index fe3d343ee..6487f3e15 100644 --- a/res/res_ari_recordings.c +++ b/res/res_ari_recordings.c @@ -35,6 +35,7 @@ <depend type="module">res_ari</depend> <depend type="module">res_ari_model</depend> <depend type="module">res_stasis</depend> + <depend type="module">res_stasis_recording</depend> <support_level>core</support_level> ***/ @@ -866,7 +867,6 @@ static struct stasis_rest_handlers recordings = { static int unload_module(void) { ast_ari_remove_handler(&recordings); - stasis_app_unref(); return 0; } @@ -874,10 +874,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&recordings); if (res) { unload_module(); @@ -891,5 +888,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Rec .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis,res_stasis_recording", ); diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c index 8d5928a50..b9c9bdfac 100644 --- a/res/res_ari_sounds.c +++ b/res/res_ari_sounds.c @@ -212,7 +212,6 @@ static struct stasis_rest_handlers sounds = { static int unload_module(void) { ast_ari_remove_handler(&sounds); - stasis_app_unref(); return 0; } @@ -220,10 +219,7 @@ static int load_module(void) { int res = 0; - CHECK_ARI_MODULE_LOADED(); - - stasis_app_ref(); res |= ast_ari_add_handler(&sounds); if (res) { unload_module(); @@ -237,5 +233,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Sou .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_ari,res_stasis", + .requires = "res_ari,res_ari_model,res_stasis", ); diff --git a/res/res_calendar.c b/res/res_calendar.c index 3369f38ce..c46307f95 100644 --- a/res/res_calendar.c +++ b/res/res_calendar.c @@ -18,7 +18,7 @@ /*! \file * \brief Calendaring API - * + * * \todo Support responding to a meeting invite * \todo Support writing attendees */ @@ -27,7 +27,7 @@ * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page calendar.conf calendar.conf * \verbinclude calendar.conf.sample */ @@ -1890,8 +1890,8 @@ static int unload_module(void) * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c index 248c80e65..425a1e3d8 100644 --- a/res/res_calendar_caldav.c +++ b/res/res_calendar_caldav.c @@ -21,6 +21,7 @@ */ /*** MODULEINFO + <depend>res_calendar</depend> <depend>neon</depend> <depend>ical</depend> <depend>libxml2</depend> @@ -320,7 +321,7 @@ static struct ast_str *caldav_get_events_between(struct caldav_pvt *pvt, time_t return response; } -static time_t icalfloat_to_timet(icaltimetype time) +static time_t icalfloat_to_timet(icaltimetype time) { struct ast_tm tm = {0,}; struct timeval tv; @@ -752,4 +753,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk CalDAV Calen .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, + .requires = "res_calendar", ); diff --git a/res/res_calendar_ews.c b/res/res_calendar_ews.c index cf0ddc240..c12fb012e 100644 --- a/res/res_calendar_ews.c +++ b/res/res_calendar_ews.c @@ -21,6 +21,7 @@ */ /*** MODULEINFO + <depend>res_calendar</depend> <depend>neon29</depend> <support_level>extended</support_level> ***/ @@ -940,4 +941,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk MS Exchange .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, + .requires = "res_calendar", ); diff --git a/res/res_calendar_exchange.c b/res/res_calendar_exchange.c index 99dc5e6ec..21c1c1a84 100644 --- a/res/res_calendar_exchange.c +++ b/res/res_calendar_exchange.c @@ -21,6 +21,7 @@ */ /*** MODULEINFO + <depend>res_calendar</depend> <depend>neon</depend> <depend>ical</depend> <depend>iksemel</depend> @@ -743,4 +744,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk MS Exchange .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, + .requires = "res_calendar", ); diff --git a/res/res_calendar_icalendar.c b/res/res_calendar_icalendar.c index 58876c187..4f78f9a3a 100644 --- a/res/res_calendar_icalendar.c +++ b/res/res_calendar_icalendar.c @@ -21,6 +21,7 @@ */ /*** MODULEINFO + <depend>res_calendar</depend> <depend>neon</depend> <depend>ical</depend> <support_level>extended</support_level> @@ -159,7 +160,7 @@ static icalcomponent *fetch_icalendar(struct icalendar_pvt *pvt) return comp; } -static time_t icalfloat_to_timet(icaltimetype time) +static time_t icalfloat_to_timet(icaltimetype time) { struct ast_tm tm = {0,}; struct timeval tv; @@ -541,4 +542,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk iCalendar .i .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, + .requires = "res_calendar", ); diff --git a/res/res_chan_stats.c b/res/res_chan_stats.c index 061d0867e..dbc79f03e 100644 --- a/res/res_chan_stats.c +++ b/res/res_chan_stats.c @@ -182,5 +182,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Example of how to use St .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, - .nonoptreq = "res_statsd" + .requires = "res_statsd" ); diff --git a/res/res_clialiases.c b/res/res_clialiases.c index 1a2fc6939..eaf9b9fec 100644 --- a/res/res_clialiases.c +++ b/res/res_clialiases.c @@ -21,7 +21,7 @@ * \brief CLI Aliases * * \author\verbatim Joshua Colp <jcolp@digium.com> \endverbatim - * + * * This module provides the capability to create aliases to other * CLI commands. */ @@ -30,7 +30,7 @@ * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page cli_aliases.conf cli_aliases.conf * \verbinclude cli_aliases.conf.sample */ @@ -103,7 +103,7 @@ static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_ struct cli_alias tmp = { .cli_entry.command = e->command, }; - char *generator; + char *generator = NULL; const char *line; /* Try to find the alias based on the CLI entry */ @@ -118,14 +118,10 @@ static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_ case CLI_GENERATE: line = a->line; line += (strlen(alias->alias)); - if (!strncasecmp(alias->alias, alias->real_cmd, strlen(alias->alias))) { - generator = NULL; - } else if (!ast_strlen_zero(a->word)) { + if (strncasecmp(alias->alias, alias->real_cmd, strlen(alias->alias))) { struct ast_str *real_cmd = ast_str_alloca(strlen(alias->real_cmd) + strlen(line) + 1); ast_str_append(&real_cmd, 0, "%s%s", alias->real_cmd, line); generator = ast_cli_generator(ast_str_buffer(real_cmd), a->word, a->n); - } else { - generator = ast_cli_generator(alias->real_cmd, a->word, a->n); } ao2_ref(alias, -1); return generator; @@ -280,8 +276,8 @@ static int unload_module(void) * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) diff --git a/res/res_config_curl.c b/res/res_config_curl.c index 06a6aef89..03ff80c2e 100644 --- a/res/res_config_curl.c +++ b/res/res_config_curl.c @@ -23,7 +23,7 @@ * \author Tilghman Lesher <res_config_curl_v1@the-tilghman.com> * * Depends on the CURL library - http://curl.haxx.se/ - * + * */ /*** MODULEINFO @@ -637,20 +637,6 @@ static int unload_module(void) static int load_module(void) { - if (!ast_module_check("res_curl.so")) { - if (ast_load_resource("res_curl.so") != AST_MODULE_LOAD_SUCCESS) { - ast_log(LOG_ERROR, "Cannot load res_curl, so res_config_curl cannot be loaded\n"); - return AST_MODULE_LOAD_DECLINE; - } - } - - if (!ast_module_check("func_curl.so")) { - if (ast_load_resource("func_curl.so") != AST_MODULE_LOAD_SUCCESS) { - ast_log(LOG_ERROR, "Cannot load func_curl, so res_config_curl cannot be loaded\n"); - return AST_MODULE_LOAD_DECLINE; - } - } - reload_module(); ast_config_engine_register(&curl_engine); @@ -664,4 +650,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime Curl configu .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, + .requires = "extconfig,res_curl,func_curl", ); diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c index 8f24a8dc3..d73f42b11 100644 --- a/res/res_config_ldap.c +++ b/res/res_config_ldap.c @@ -35,7 +35,7 @@ * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page res_ldap.conf res_ldap.conf * \verbinclude res_ldap.conf.sample */ @@ -90,7 +90,7 @@ struct category_and_metric { int var_metric; /*!< For organizing variables (particularly includes and switch statments) within a context */ }; -/*! \brief Table configuration +/*! \brief Table configuration */ struct ldap_table_config { char *table_name; /*!< table name */ @@ -101,7 +101,7 @@ struct ldap_table_config { /* TODO: Make proxies work */ }; -/*! \brief Should be locked before using it +/*! \brief Should be locked before using it */ static AST_LIST_HEAD_NOLOCK_STATIC(table_configs, ldap_table_config); static struct ldap_table_config *base_table_config; @@ -132,7 +132,7 @@ static struct ldap_table_config *table_config_new(const char *table_name) /*! \brief Find a table_config * - * Should be locked before using it + * Should be locked before using it * * \note This function assumes ldap_lock to be locked. */ @@ -178,7 +178,7 @@ static int semicolon_count_str(const char *somestr) } /* \brief Count semicolons in variables - * + * * takes a linked list of \a ast_variable variables, finds the one with the name variable_value * and returns the number of semicolons in the value for that \a ast_variable */ @@ -271,7 +271,7 @@ static const char *convert_attribute_name_to_ldap(struct ldap_table_config *tabl return attribute_name; } -/*! \brief Convert ldap attribute name to variable name +/*! \brief Convert ldap attribute name to variable name * * \note Should be locked before using it */ @@ -299,7 +299,7 @@ static const char *convert_attribute_name_from_ldap(struct ldap_table_config *ta return attribute_name; } -/*! \brief Get variables from ldap entry attributes +/*! \brief Get variables from ldap entry attributes * \note Should be locked before using it * \return a linked list of ast_variable variables. */ @@ -309,8 +309,10 @@ static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config BerElement *ber = NULL; struct ast_variable *var = NULL; struct ast_variable *prev = NULL; +#if 0 int is_delimited = 0; int i = 0; +#endif char *ldap_attribute_name; struct berval *value; int pos = 0; @@ -338,6 +340,7 @@ static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config ast_debug(2, "md5: %s\n", valptr); } if (valptr) { +#if 0 /* ok, so looping through all delimited values except the last one (not, last character is not delimited...) */ if (is_delimited) { i = 0; @@ -358,6 +361,7 @@ static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config i++; } } +#endif /* for the last delimited value or if the value is not delimited: */ if (prev) { prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name); @@ -382,7 +386,7 @@ static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config /*! \brief Get variables from ldap entry attributes - Should be locked before using it * * The results are freed outside this function so is the \a vars array. - * + * * \return \a vars - an array of ast_variable variables terminated with a null. */ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_config *table_config, @@ -405,7 +409,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf */ ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg); - for (tot_count = 0; ldap_entry; tot_count++) { + for (tot_count = 0; ldap_entry; tot_count++) { struct ast_variable *tmp = realtime_ldap_entry_to_var(table_config, ldap_entry); tot_count += semicolon_count_var(tmp); ldap_entry = ldap_next_entry(ldapConn, ldap_entry); @@ -544,11 +548,11 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf } /*!< while (ldap_attribute_name) */ ber_free(ber, 0); if (static_table_config == table_config) { - if (option_debug > 2) { + if (DEBUG_ATLEAST(3)) { const struct ast_variable *tmpdebug = variable_named(var, "variable_name"); const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value"); if (tmpdebug && tmpdebug2) { - ast_debug(3, "Added to vars - %s = %s\n", tmpdebug->value, tmpdebug2->value); + ast_log(LOG_DEBUG, "Added to vars - %s = %s\n", tmpdebug->value, tmpdebug2->value); } } vars[entry_index++] = var; @@ -580,7 +584,7 @@ static int is_ldap_connect_error(int err) /*! \brief Get LDAP entry by dn and return attributes as variables * - * Should be locked before using it + * Should be locked before using it * * This is used for setting the default values of an object * i.e., with accountBaseDN @@ -702,7 +706,7 @@ static char *cleaned_basedn(struct ast_channel *channel, const char *basedn) return cbasedn; } -/*! \brief Replace \<search\> by \<by\> in string. +/*! \brief Replace \<search\> by \<by\> in string. * \note No check is done on string allocated size ! */ static int replace_string_in_string(char *string, const char *search, const char *by) @@ -727,7 +731,7 @@ static int replace_string_in_string(char *string, const char *search, const char return replaced; } -/*! \brief Append a name=value filter string. The filter string can grow. +/*! \brief Append a name=value filter string. The filter string can grow. */ static void append_var_and_value_to_filter(struct ast_str **filter, struct ldap_table_config *table_config, @@ -795,7 +799,7 @@ static struct ast_str *create_lookup_filter(struct ldap_table_config *config, co return filter; } -/*! \brief LDAP base function +/*! \brief LDAP base function * \return a null terminated array of ast_variable (one per entry) or NULL if no entry is found or if an error occured * caller should free the returned array and ast_variables * \param entries_count_ptr is a pointer to found entries count (can be NULL) @@ -819,7 +823,7 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p ast_log(LOG_ERROR, "No table_name specified.\n"); ast_free(clean_basedn); return NULL; - } + } if (!field) { ast_log(LOG_ERROR, "Realtime retrieval requires at least 1 parameter" @@ -876,7 +880,7 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result)); ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter)); } else { - /* this is where we create the variables from the search result + /* this is where we create the variables from the search result * freeing this \a vars outside this function */ if (ldap_count_entries(ldapConn, ldap_result_msg) > 0) { /* is this a static var or some other? they are handled different for delimited values */ @@ -898,7 +902,7 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p if (strcasecmp(tmp->name, "accountBaseDN") == 0) { /* Get the variable to compare with for the defaults */ struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value); - + while (base_var) { struct ast_variable *next = base_var->next; struct ast_variable *test_var = *p; @@ -1101,7 +1105,7 @@ static int compare_categories(const void *a, const void *b) return 1; } else if (as->metric == bs->metric && strcmp(as->name, bs->name) != 0) { return strcmp(as->name, bs->name); - } + } /* if the metric and the category name is the same, we check the variable metric */ if (as->var_metric < bs->var_metric) { return -1; @@ -1115,7 +1119,7 @@ static int compare_categories(const void *a, const void *b) /*! \brief See Asterisk Realtime Documentation * * This is for Static Realtime - * + * * load the configuration stuff for the .conf files * called on a reload */ @@ -1614,14 +1618,14 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct /* Ready to update */ ast_debug(3, "Modifying %zu matched entries\n", entry_count); - if (option_debug > 2) { + if (DEBUG_ATLEAST(3)) { size_t i; for (i = 0; modifications[i]; i++) { if (modifications[i]->mod_op != LDAP_MOD_DELETE) { - ast_debug(3, "%s => %s\n", modifications[i]->mod_type, - modifications[i]->mod_values[0]); + ast_log(LOG_DEBUG, "%s => %s\n", modifications[i]->mod_type, + modifications[i]->mod_values[0]); } else { - ast_debug(3, "deleting %s\n", modifications[i]->mod_type); + ast_log(LOG_DEBUG, "deleting %s\n", modifications[i]->mod_type); } } } @@ -1701,8 +1705,8 @@ static struct ast_config_engine ldap_engine = { * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. * * \todo Don't error or warn on a default install. If the config is @@ -1770,7 +1774,7 @@ static int reload(void) ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n"); ast_mutex_unlock(&ldap_lock); return 0; - } + } if (!ldap_reconnect()) { ast_log(LOG_WARNING, "Couldn't establish connection to your directory server. Check debug.\n"); @@ -1857,7 +1861,7 @@ static int parse_config(void) if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) { ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN); ast_copy_string(base_distinguished_name, RES_CONFIG_LDAP_DEFAULT_BASEDN, sizeof(base_distinguished_name)); - } else + } else ast_copy_string(base_distinguished_name, s, sizeof(base_distinguished_name)); if (!(s = ast_variable_retrieve(config, "_general", "version")) && !(s = ast_variable_retrieve(config, "_general", "protocol"))) { @@ -1873,7 +1877,7 @@ static int parse_config(void) int is_general = (strcasecmp(category_name, "_general") == 0); int is_config = (strcasecmp(category_name, "config") == 0); /*!< using the [config] context for Static RealTime */ struct ast_variable *var = ast_variable_browse(config, category_name); - + if (var) { struct ldap_table_config *table_config = table_config_for_table_name(category_name); @@ -1974,7 +1978,7 @@ static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_c if (!ldapConn) return CLI_FAILURE; - if (!ast_strlen_zero(url)) + if (!ast_strlen_zero(url)) snprintf(status, sizeof(status), "Connected to '%s', baseDN %s", url, base_distinguished_name); if (!ast_strlen_zero(user)) @@ -1995,4 +1999,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "LDAP realtime interfa .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DRIVER, + .requires = "extconfig", ); diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index 114708325..be920d673 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -30,6 +30,7 @@ /*** MODULEINFO <depend>res_odbc</depend> + <depend>generic_odbc</depend> <support_level>core</support_level> ***/ @@ -143,7 +144,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data) ENCODE_CHUNK(encodebuf, newval); ast_string_field_set(cps, encoding[x], encodebuf); newval = cps->encoding[x]; - } + } SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); } @@ -243,7 +244,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl for (x = 0; x < colcount; x++) { colsize = 0; collen = sizeof(coltitle); - res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, + res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, &datatype, &colsize, &decimaldigits, &nullable); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql)); @@ -313,7 +314,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl * \param ap list containing one or more field/operator/value set. * * Select database and preform query on table, prepare the sql statement - * Sub-in the values to the prepared statement and execute it. + * Sub-in the values to the prepared statement and execute it. * Execute this prepared query against several ODBC connected databases. * Return results as an ast_config variable. * @@ -414,7 +415,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char * for (x=0;x<colcount;x++) { colsize = 0; collen = sizeof(coltitle); - res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, + res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, &datatype, &colsize, &decimaldigits, &nullable); if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql)); @@ -1013,7 +1014,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c return NULL; } continue; - } + } if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) { cur_cat = ast_category_new_dynamic(q.category); if (!cur_cat) { @@ -1237,4 +1238,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime ODBC configu .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, + .requires = "extconfig,res_odbc", ); diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c index e436e2ff8..c8660fb3a 100644 --- a/res/res_config_pgsql.c +++ b/res/res_config_pgsql.c @@ -1215,7 +1215,8 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap struct columns *column; struct tables *table; char *elm; - int type, size, res = 0; + int type, res = 0; + unsigned int size; /* * Ignore database from the extconfig.conf since it was @@ -1231,7 +1232,7 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap while ((elm = va_arg(ap, char *))) { type = va_arg(ap, require_type); - size = va_arg(ap, int); + size = va_arg(ap, unsigned int); AST_LIST_TRAVERSE(&table->columns, column, list) { if (strcmp(column->name, elm) == 0) { /* Char can hold anything, as long as it is large enough */ @@ -1288,14 +1289,14 @@ static int require_pgsql(const char *database, const char *tablename, va_list ap res = -1; } else { struct ast_str *sql = ast_str_create(100); - char fieldtype[15]; + char fieldtype[10]; PGresult *result; if (requirements == RQ_CREATECHAR || type == RQ_CHAR) { /* Size is minimum length; make it at least 50% greater, * just to be sure, because PostgreSQL doesn't support * resizing columns. */ - snprintf(fieldtype, sizeof(fieldtype), "CHAR(%hhu)", + snprintf(fieldtype, sizeof(fieldtype), "CHAR(%u)", size < 15 ? size * 2 : (size * 3 / 2 > 255) ? 255 : size * 3 / 2); } else if (type == RQ_INTEGER1 || type == RQ_UINTEGER1 || type == RQ_INTEGER2) { @@ -1527,16 +1528,16 @@ static int parse_config(int is_reload) ast_config_destroy(config); - if (option_debug) { + if (DEBUG_ATLEAST(1)) { if (!ast_strlen_zero(dbhost)) { - ast_debug(1, "PostgreSQL RealTime Host: %s\n", dbhost); - ast_debug(1, "PostgreSQL RealTime Port: %i\n", dbport); + ast_log(LOG_DEBUG, "PostgreSQL RealTime Host: %s\n", dbhost); + ast_log(LOG_DEBUG, "PostgreSQL RealTime Port: %i\n", dbport); } else { - ast_debug(1, "PostgreSQL RealTime Socket: %s\n", dbsock); + ast_log(LOG_DEBUG, "PostgreSQL RealTime Socket: %s\n", dbsock); } - ast_debug(1, "PostgreSQL RealTime User: %s\n", dbuser); - ast_debug(1, "PostgreSQL RealTime Password: %s\n", dbpass); - ast_debug(1, "PostgreSQL RealTime DBName: %s\n", dbname); + ast_log(LOG_DEBUG, "PostgreSQL RealTime User: %s\n", dbuser); + ast_log(LOG_DEBUG, "PostgreSQL RealTime Password: %s\n", dbpass); + ast_log(LOG_DEBUG, "PostgreSQL RealTime DBName: %s\n", dbname); } if (!pgsql_reconnect(NULL)) { @@ -1719,4 +1720,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PostgreSQL RealTime C .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DRIVER, + .requires = "extconfig", ); diff --git a/res/res_config_sqlite.c b/res/res_config_sqlite.c index 0f9113188..323d2249b 100644 --- a/res/res_config_sqlite.c +++ b/res/res_config_sqlite.c @@ -27,7 +27,7 @@ * res_config_sqlite is a module for the Asterisk Open Source PBX to * support SQLite 2 databases. It can be used to fetch configuration * from a database (static configuration files and/or using the Asterisk - * RealTime Architecture - ARA). It can also be used to log CDR entries. + * RealTime Architecture - ARA). It can also be used to log CDR entries. * Note that Asterisk already comes with a module named cdr_sqlite. * There are two reasons for including it in res_config_sqlite: * the first is that rewriting it was a training to learn how to write a @@ -75,14 +75,14 @@ * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page res_config_sqlite.conf res_config_sqlite.conf * \verbinclude res_config_sqlite.conf.sample */ /*** MODULEINFO <depend>sqlite</depend> - <support_level>extended</support_level> + <support_level>deprecated</support_level> ***/ #include "asterisk.h" @@ -430,7 +430,7 @@ static int realtime_destroy_handler(const char *database, const char *table, * \brief Asterisk callback function for the CLI status command. * * \param e CLI command - * \param cmd + * \param cmd * \param a CLI argument list * \return RESULT_SUCCESS */ @@ -1656,8 +1656,8 @@ static int unload_module(void) * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) @@ -1772,9 +1772,16 @@ static int load_module(void) return AST_MODULE_LOAD_SUCCESS; } +/* + * This module should require "cdr" to enforce startup/shutdown ordering but it + * loads at REALTIME_DRIVER priority which would cause "cdr" to load too early. + * + * ast_cdr_register / ast_cdr_unregister is safe for use while "cdr" is not running. + */ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime SQLite configuration", - .support_level = AST_MODULE_SUPPORT_EXTENDED, + .support_level = AST_MODULE_SUPPORT_DEPRECATED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DRIVER, + .requires = "extconfig", ); diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c index bbf6db211..854034f38 100644 --- a/res/res_config_sqlite3.c +++ b/res/res_config_sqlite3.c @@ -33,7 +33,7 @@ * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page res_config_sqlite3.conf res_config_sqlite3.conf * \verbinclude res_config_sqlite3.conf.sample */ @@ -1180,7 +1180,7 @@ static int realtime_sqlite3_require(const char *database, const char *table, va_ struct realtime_sqlite3_db *db; /* SQLite3 columns are dynamically typed, with type affinity. Built-in functions will - * return the results as char * anyway. The only field that that cannot contain text + * return the results as char * anyway. The only field that cannot contain text * data is an INTEGER PRIMARY KEY, which must be a 64-bit signed integer. So, for * the purposes here we really only care whether the column exists and not what its * type or length is. */ @@ -1361,8 +1361,8 @@ static void discover_sqlite3_caps(void) * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) @@ -1393,4 +1393,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SQLite 3 realtime con .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_REALTIME_DRIVER, + .requires = "extconfig", ); diff --git a/res/res_convert.c b/res/res_convert.c index 705e8922d..10a5ed33e 100644 --- a/res/res_convert.c +++ b/res/res_convert.c @@ -18,13 +18,13 @@ */ /*! \file - * + * * \brief file format conversion CLI command using Asterisk formats and translators * * \author redice li <redice_li@yahoo.com> * \author Russell Bryant <russell@digium.com> * - */ + */ /*** MODULEINFO <support_level>core</support_level> @@ -41,7 +41,7 @@ static int split_ext(char *filename, char **name, char **ext) { *name = *ext = filename; - + if ((*ext = strrchr(filename, '.'))) { **ext = '\0'; (*ext)++; @@ -53,8 +53,8 @@ static int split_ext(char *filename, char **name, char **ext) return 0; } -/*! - * \brief Convert a file from one format to another +/*! + * \brief Convert a file from one format to another * \param e CLI entry * \param cmd command number * \param a list of cli arguments @@ -85,10 +85,10 @@ static char *handle_cli_file_convert(struct ast_cli_entry *e, int cmd, struct as case CLI_GENERATE: return NULL; } - + if (a->argc != 4 || ast_strlen_zero(a->argv[2]) || ast_strlen_zero(a->argv[3])) { ret = CLI_SHOWUSAGE; - goto fail_out; + goto fail_out; } file_in = ast_strdupa(a->argv[2]); @@ -102,7 +102,7 @@ static char *handle_cli_file_convert(struct ast_cli_entry *e, int cmd, struct as ast_cli(a->fd, "Unable to open input file: %s\n", a->argv[2]); goto fail_out; } - + if (split_ext(file_out, &name_out, &ext_out)) { ast_cli(a->fd, "'%s' is an invalid filename!\n", a->argv[3]); goto fail_out; @@ -113,7 +113,7 @@ static char *handle_cli_file_convert(struct ast_cli_entry *e, int cmd, struct as } start = ast_tvnow(); - + while ((f = ast_readframe(fs_in))) { if (ast_writestream(fs_out, f)) { ast_frfree(f); @@ -134,7 +134,7 @@ fail_out: ast_filedelete(name_out, ext_out); } - if (fs_in) + if (fs_in) ast_closestream(fs_in); return ret; diff --git a/res/res_corosync.c b/res/res_corosync.c index 0d91b1860..50dd510e0 100644 --- a/res/res_corosync.c +++ b/res/res_corosync.c @@ -1203,4 +1203,3 @@ static int unload_module(void) } AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Corosync"); - diff --git a/res/res_crypto.c b/res/res_crypto.c index 8f97ce9f8..4f8f2cb6e 100644 --- a/res/res_crypto.c +++ b/res/res_crypto.c @@ -651,8 +651,6 @@ static int load_module(void) crypto_load(-1, -1); } - /* This prevents dlclose from ever running, but allows CLI cleanup at shutdown. */ - ast_module_shutdown_ref(ast_module_info->self); return AST_MODULE_LOAD_SUCCESS; } @@ -663,7 +661,6 @@ static int unload_module(void) return 0; } -/* needs usecount semantics defined */ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Cryptographic Digital Signatures", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, diff --git a/res/res_curl.c b/res/res_curl.c index 5c4363295..3dc7c2f03 100644 --- a/res/res_curl.c +++ b/res/res_curl.c @@ -23,14 +23,14 @@ * \author Tilghman Lesher <res_curl_v1@the-tilghman.com> * * Depends on the CURL library - http://curl.haxx.se/ - * + * */ /*! \li \ref res_curl.c uses the configuration file \ref res_curl.conf * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page res_curl.conf res_curl.conf * \verbinclude res_curl.conf.sample */ @@ -46,46 +46,16 @@ #include "asterisk/module.h" -static const char *dependents[] = { - "func_curl.so", - "res_config_curl.so", - "res_http_media_cache.so", -}; - static int unload_module(void) { - int res = 0; - size_t i; - - /* If the dependent modules are still in memory, forbid unload */ - for (i = 0; i < ARRAY_LEN(dependents); i++) { - if (ast_module_check(dependents[i])) { - ast_log(LOG_ERROR, "%s (dependent module) is still loaded. Cannot unload res_curl.so\n", dependents[i]); - res = -1; - } - } - - if (res) - return -1; - curl_global_cleanup(); - return res; + return 0; } -/*! - * \brief Load the module - * - * Module loading including tests for configuration or dependencies. - * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, - * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return - * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. - */ static int load_module(void) { - int res = 0; + int res = AST_MODULE_LOAD_SUCCESS; if (curl_global_init(CURL_GLOBAL_ALL)) { ast_log(LOG_ERROR, "Unable to initialize the cURL library. Cannot load res_curl.so\n"); diff --git a/res/res_endpoint_stats.c b/res/res_endpoint_stats.c index 1e3f104c2..7ce44f958 100644 --- a/res/res_endpoint_stats.c +++ b/res/res_endpoint_stats.c @@ -151,5 +151,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Endpoint statistics", .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, - .nonoptreq = "res_statsd" + .requires = "res_statsd" ); diff --git a/res/res_fax.c b/res/res_fax.c index 4a1c0846f..315f0003b 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -363,7 +363,7 @@ 'gateway' and state is 'Uninitialized'.</para> </parameter> <parameter name="FileName" required="false"> - <para>Filename of the image being sent/recieved for this FAX session. This field is not + <para>Filename of the image being sent/received for this FAX session. This field is not included if Operation isn't 'send' or 'receive'.</para> </parameter> <parameter name="PagesTransmitted" required="false"> @@ -375,7 +375,7 @@ Operation is not 'send' or 'receive'. Will be 0 for 'send'.</para> </parameter> <parameter name="TotalBadLines" required="false"> - <para>Total number of bad lines sent/recieved during this session. This field is not + <para>Total number of bad lines sent/received during this session. This field is not included if Operation is not 'send' or 'received'.</para> </parameter> </syntax> @@ -978,7 +978,6 @@ int ast_fax_tech_register(struct ast_fax_tech *tech) AST_RWLIST_WRLOCK(&faxmodules); AST_RWLIST_INSERT_TAIL(&faxmodules, fax, list); AST_RWLIST_UNLOCK(&faxmodules); - ast_module_ref(ast_module_info->self); ast_verb(3, "Registered handler for '%s' (%s)\n", fax->tech->type, fax->tech->description); @@ -998,7 +997,6 @@ void ast_fax_tech_unregister(struct ast_fax_tech *tech) continue; } AST_RWLIST_REMOVE_CURRENT(list); - ast_module_unref(ast_module_info->self); ast_free(fax); ast_verb(4, "Unregistered FAX module type '%s'\n", tech->type); break; @@ -1161,8 +1159,10 @@ static struct ast_fax_session *fax_session_reserve(struct ast_fax_session_detail if ((faxmod->tech->caps & details->caps) != details->caps) { continue; } + if (!ast_module_running_ref(faxmod->tech->module)) { + continue; + } ast_debug(4, "Reserving a FAX session from '%s'.\n", faxmod->tech->description); - ast_module_ref(faxmod->tech->module); s->tech = faxmod->tech; break; } @@ -1279,8 +1279,10 @@ static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *d if ((faxmod->tech->caps & details->caps) != details->caps) { continue; } + if (!ast_module_running_ref(faxmod->tech->module)) { + continue; + } ast_debug(4, "Requesting a new FAX session from '%s'.\n", faxmod->tech->description); - ast_module_ref(faxmod->tech->module); if (reserved) { /* Balance module ref from reserved session */ ast_module_unref(reserved->tech->module); diff --git a/res/res_fax_spandsp.c b/res/res_fax_spandsp.c index 540a9021b..045dbc708 100644 --- a/res/res_fax_spandsp.c +++ b/res/res_fax_spandsp.c @@ -859,7 +859,7 @@ static int spandsp_fax_gateway_start(struct ast_fax_session *s) t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal); t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr); t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig); - t38_set_data_rate_management_method(p->t38_core_state, + t38_set_data_rate_management_method(p->t38_core_state, (t38_param->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF)? 1 : 2); t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE); @@ -868,7 +868,7 @@ static int spandsp_fax_gateway_start(struct ast_fax_session *s) t38_gateway_set_supported_modems(&p->t38_gw_state, spandsp_modems(s->details)); - /* engage udptl nat on other side of T38 line + /* engage udptl nat on other side of T38 line * (Asterisk changes media ports thus we send a few packets to reinitialize * pinholes in NATs and FWs */ @@ -1266,4 +1266,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 F .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, + .enhances = "res_fax", ); diff --git a/res/res_format_attr_opus.c b/res/res_format_attr_opus.c index 1367f9578..cf30cf5cf 100644 --- a/res/res_format_attr_opus.c +++ b/res/res_format_attr_opus.c @@ -115,7 +115,7 @@ static void sdp_fmtp_get(const char *attributes, const char *name, int *attr) /* Skip any preceeding blanks as some implementations separate attributes using spaces too */ kvp = ast_skip_blanks(kvp); - /* If we are at at the requested attribute get its value and return */ + /* If we are at the requested attribute get its value and return */ if (!strncmp(kvp, name, strlen(name)) && kvp[strlen(name)] == '=') { if (sscanf(kvp, "%*[^=]=%30d", &val) == 1) { *attr = val; diff --git a/res/res_format_attr_silk.c b/res/res_format_attr_silk.c index d2f9b3544..e2c9ca1f9 100644 --- a/res/res_format_attr_silk.c +++ b/res/res_format_attr_silk.c @@ -109,7 +109,7 @@ static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int return; } - if ((attr->maxbitrate > 5000) && (attr->maxbitrate < 40000)) { + if ((attr->maxbitrate > 5000) && (attr->maxbitrate < 40000)) { ast_str_append(str, 0, "a=fmtp:%u maxaveragebitrate=%u\r\n", payload, attr->maxbitrate); } diff --git a/res/res_hep.c b/res/res_hep.c index 25b4d13b1..4e548e274 100644 --- a/res/res_hep.c +++ b/res/res_hep.c @@ -258,8 +258,8 @@ static struct aco_type global_option = { .type = ACO_GLOBAL, .name = "general", .item_offset = offsetof(struct module_config, general), - .category_match = ACO_WHITELIST, - .category = "^general$", + .category_match = ACO_WHITELIST_EXACT, + .category = "general", }; struct aco_type *global_options[] = ACO_TYPES(&global_option); @@ -421,7 +421,7 @@ int hepv3_is_loaded(void) { RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup); - return (config != NULL) ? 1 : 0; + return config && config->general->enabled; } struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len) diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c index 6283efc76..be2f6eab0 100644 --- a/res/res_hep_pjsip.c +++ b/res/res_hep_pjsip.c @@ -232,10 +232,8 @@ static pjsip_module logging_module = { static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - - if (!ast_module_check("res_hep.so") || !hepv3_is_loaded()) { - ast_log(AST_LOG_WARNING, "res_hep is not loaded or running; declining module load\n"); + if (!hepv3_is_loaded()) { + ast_log(AST_LOG_WARNING, "res_hep is disabled; declining module load\n"); return AST_MODULE_LOAD_DECLINE; } @@ -253,4 +251,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "PJSIP HEPv3 Logger", .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, + .requires = "res_hep,res_pjsip", ); diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c index afad0c845..c3abbc164 100644 --- a/res/res_hep_rtcp.c +++ b/res/res_hep_rtcp.c @@ -157,8 +157,8 @@ static void rtp_topic_handler(void *data, struct stasis_subscription *sub, struc static int load_module(void) { - if (!ast_module_check("res_hep.so") || !hepv3_is_loaded()) { - ast_log(AST_LOG_WARNING, "res_hep is not loaded or running; declining module load\n"); + if (!hepv3_is_loaded()) { + ast_log(AST_LOG_WARNING, "res_hep is disabled; declining module load\n"); return AST_MODULE_LOAD_DECLINE; } @@ -184,4 +184,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RTCP HEPv3 Logger", .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, + .requires = "res_hep", ); diff --git a/res/res_http_media_cache.c b/res/res_http_media_cache.c index 918686e8a..eba7ecc61 100644 --- a/res/res_http_media_cache.c +++ b/res/res_http_media_cache.c @@ -441,4 +441,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "HTTP Media Cache Backend .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, + .requires = "res_curl", ); diff --git a/res/res_http_post.c b/res/res_http_post.c index 9f5b1837a..bf404ced6 100644 --- a/res/res_http_post.c +++ b/res/res_http_post.c @@ -17,7 +17,7 @@ */ /*! - * \file + * \file * \brief HTTP POST upload support for Asterisk HTTP server * * \author Terry Wilson <twilson@digium.com @@ -36,7 +36,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <gmime/gmime.h> -#if defined (__OpenBSD__) || defined(__FreeBSD__) || defined(__Darwin__) +#if defined (__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__Darwin__) #include <libgen.h> #endif @@ -55,7 +55,7 @@ #ifdef GMIME_TYPE_CONTENT_TYPE #define AST_GMIME_VER_24 #endif -#if GMIME_MAJOR_VERSION >= 3 +#if defined(GMIME_MAJOR_VERSION) && (GMIME_MAJOR_VERSION >= 3) #define AST_GMIME_VER_30 #endif @@ -111,7 +111,7 @@ static GMimeMessage *parse_message(FILE *f) parser = g_mime_parser_new_with_stream(stream); g_mime_parser_set_respect_content_length(parser, 1); - + g_object_unref(stream); message = g_mime_parser_construct_message(parser @@ -513,4 +513,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "HTTP POST support", .load = load_module, .unload = unload_module, .reload = reload, + .requires = "http", ); diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index c1f9a29d6..9a32bf37c 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -131,24 +131,18 @@ struct ast_websocket_server { struct ao2_container *protocols; /*!< Container for registered protocols */ }; -static void websocket_server_internal_dtor(void *obj) +static void websocket_server_dtor(void *obj) { struct ast_websocket_server *server = obj; ao2_cleanup(server->protocols); server->protocols = NULL; } -static void websocket_server_dtor(void *obj) -{ - websocket_server_internal_dtor(obj); - ast_module_unref(ast_module_info->self); -} - -static struct ast_websocket_server *websocket_server_create_impl(void (*dtor)(void *)) +static struct ast_websocket_server *websocket_server_create_impl(void) { RAII_VAR(struct ast_websocket_server *, server, NULL, ao2_cleanup); - server = ao2_alloc(sizeof(*server), dtor); + server = ao2_alloc(sizeof(*server), websocket_server_dtor); if (!server) { return NULL; } @@ -164,13 +158,12 @@ static struct ast_websocket_server *websocket_server_create_impl(void (*dtor)(vo static struct ast_websocket_server *websocket_server_internal_create(void) { - return websocket_server_create_impl(websocket_server_internal_dtor); + return websocket_server_create_impl(); } struct ast_websocket_server *AST_OPTIONAL_API_NAME(ast_websocket_server_create)(void) { - ast_module_ref(ast_module_info->self); - return websocket_server_create_impl(websocket_server_dtor); + return websocket_server_create_impl(); } /*! \brief Destructor function for sessions */ @@ -291,6 +284,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_server_remove_protocol)(struct ast_webso /*! \brief Close function for websocket session */ int AST_OPTIONAL_API_NAME(ast_websocket_close)(struct ast_websocket *session, uint16_t reason) { + enum ast_websocket_opcode opcode = AST_WEBSOCKET_OPCODE_CLOSE; char frame[4] = { 0, }; /* The header is 2 bytes and the reason code takes up another 2 bytes */ int res; @@ -298,7 +292,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_close)(struct ast_websocket *session, ui return 0; } - frame[0] = AST_WEBSOCKET_OPCODE_CLOSE | 0x80; + frame[0] = opcode | 0x80; frame[1] = 2; /* The reason code is always 2 bytes */ /* If no reason has been specified assume 1000 which is normal closure */ @@ -494,13 +488,20 @@ const char * AST_OPTIONAL_API_NAME(ast_websocket_session_id)(struct ast_websocke * Note during the header parsing stage we try to read in small chunks just what we need, this * is buffered data anyways, no expensive syscall required most of the time ... */ -static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len, enum ast_websocket_opcode *opcode) +static inline int ws_safe_read(struct ast_websocket *session, char *buf, size_t len, enum ast_websocket_opcode *opcode) { ssize_t rlen; int xlen = len; char *rbuf = buf; int sanity = 10; + ast_assert(len > 0); + + if (!len) { + errno = EINVAL; + return -1; + } + ao2_lock(session); if (!session->stream) { ao2_unlock(session); @@ -614,9 +615,12 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha return -1; } - if (ws_safe_read(session, *payload, *payload_len, opcode)) { - return -1; + if (*payload_len) { + if (ws_safe_read(session, *payload, *payload_len, opcode)) { + return -1; + } } + /* If a mask is present unmask the payload */ if (mask_present) { unsigned int pos; @@ -672,18 +676,27 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha session->payload_len = 0; } } else if (*opcode == AST_WEBSOCKET_OPCODE_CLOSE) { + session->closing = 1; + /* Make the payload available so the user can look at the reason code if they so desire */ - if ((*payload_len) && (new_payload = ast_realloc(session->payload, *payload_len))) { - if (ws_safe_read(session, &buf[frame_size], (*payload_len), opcode)) { - return -1; - } - session->payload = new_payload; - memcpy(session->payload, &buf[frame_size], *payload_len); - *payload = session->payload; - frame_size += (*payload_len); + if (!*payload_len) { + return 0; } - session->closing = 1; + if (!(new_payload = ast_realloc(session->payload, *payload_len))) { + ast_log(LOG_WARNING, "Failed allocation: %p, %"PRIu64"\n", + session->payload, *payload_len); + *payload_len = 0; + return -1; + } + + session->payload = new_payload; + if (ws_safe_read(session, &buf[frame_size], *payload_len, opcode)) { + return -1; + } + memcpy(session->payload, &buf[frame_size], *payload_len); + *payload = session->payload; + frame_size += *payload_len; } else { ast_log(LOG_WARNING, "WebSocket unknown opcode %u\n", *opcode); /* We received an opcode that we don't understand, the RFC states that 1003 is for a type of data that can't be accepted... opcodes @@ -951,17 +964,11 @@ static struct ast_http_uri websocketuri = { /*! \brief Simple echo implementation which echoes received text and binary frames */ static void websocket_echo_callback(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers) { - int flags, res; + int res; ast_debug(1, "Entering WebSocket echo loop\n"); - if ((flags = fcntl(ast_websocket_fd(session), F_GETFL)) == -1) { - goto end; - } - - flags |= O_NONBLOCK; - - if (fcntl(ast_websocket_fd(session), F_SETFL, flags) == -1) { + if (ast_fd_set_flags(ast_websocket_fd(session), O_NONBLOCK)) { goto end; } @@ -1002,11 +1009,7 @@ static int websocket_add_protocol_internal(const char *name, ast_websocket_callb int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol)(const char *name, ast_websocket_callback callback) { - int res = websocket_add_protocol_internal(name, callback); - if (res == 0) { - ast_module_ref(ast_module_info->self); - } - return res; + return websocket_add_protocol_internal(name, callback); } int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol2)(struct ast_websocket_protocol *protocol) @@ -1021,7 +1024,6 @@ int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol2)(struct ast_websocket_prot return -1; } - ast_module_ref(ast_module_info->self); return 0; } @@ -1036,11 +1038,7 @@ static int websocket_remove_protocol_internal(const char *name, ast_websocket_ca int AST_OPTIONAL_API_NAME(ast_websocket_remove_protocol)(const char *name, ast_websocket_callback callback) { - int res = websocket_remove_protocol_internal(name, callback); - if (res == 0) { - ast_module_unref(ast_module_info->self); - } - return res; + return websocket_remove_protocol_internal(name, callback); } /*! \brief Parse the given uri into a path and remote address. @@ -1462,9 +1460,6 @@ static int load_module(void) ast_http_uri_link(&websocketuri); websocket_add_protocol_internal("echo", websocket_echo_callback); - /* For Optional API. */ - ast_module_shutdown_ref(AST_MODULE_SELF); - return 0; } @@ -1483,4 +1478,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "http", ); diff --git a/res/res_limit.c b/res/res_limit.c index a308c4121..d55244b9d 100644 --- a/res/res_limit.c +++ b/res/res_limit.c @@ -2,7 +2,7 @@ * Asterisk -- An open source telephony toolkit. * * Resource limits - * + * * Copyright (c) 2006 Tilghman Lesher. All rights reserved. * * Tilghman Lesher <res_limit_200607@the-tilghman.com> @@ -213,4 +213,3 @@ static int load_module(void) } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Resource limits"); - diff --git a/res/res_monitor.c b/res/res_monitor.c index 3ac6e455f..efedab7c3 100644 --- a/res/res_monitor.c +++ b/res/res_monitor.c @@ -25,9 +25,10 @@ /*** MODULEINFO <use type="module">func_periodic_hook</use> - <support_level>core</support_level> + <support_level>deprecated</support_level> + <replacement>app_mixmonitor</replacement> ***/ - + #include "asterisk.h" #include <sys/stat.h> @@ -271,9 +272,9 @@ AST_MUTEX_DEFINE_STATIC(monitorlock); static unsigned long seq = 0; -/*! - * \brief Change state of monitored channel - * \param chan +/*! + * \brief Change state of monitored channel + * \param chan * \param state monitor state * \retval 0 on success. * \retval -1 on failure. @@ -372,7 +373,7 @@ int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const cha } else { monitor->format = ast_strdup("wav"); } - + /* open files */ if (stream_action & X_REC_IN) { if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) @@ -446,13 +447,13 @@ static const char *get_soxmix_format(const char *format) res = "ul"; if (!strcasecmp(format,"alaw")) res = "al"; - + return res; } -/*! - * \brief Stop monitoring channel - * \param chan +/*! + * \brief Stop monitoring channel + * \param chan * \param need_lock * Stop the recording, close any open streams, mix in/out channels if required * \return Always 0 @@ -512,7 +513,7 @@ int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_l #endif format = get_soxmix_format(format); delfiles = 1; - } + } execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS"); if (ast_strlen_zero(execute_args)) { execute_args = ""; @@ -578,8 +579,8 @@ static int unpause_monitor_exec(struct ast_channel *chan, const char *data) return ast_monitor_unpause(chan); } -/*! - * \brief Change monitored filename of channel +/*! + * \brief Change monitored filename of channel * \param chan * \param fname_base new filename * \param need_lock @@ -624,7 +625,7 @@ int AST_OPTIONAL_API_NAME(ast_monitor_change_fname)(struct ast_channel *chan, co * and we aren't interfering with the recording itself. */ ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, ast_channel_monitor(chan)->filename_base); - + if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 || (fd[1] = open(ast_channel_monitor(chan)->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) { if (fd[0] < 0) { @@ -708,7 +709,7 @@ static int start_monitor_exec(struct ast_channel *chan, const char *data) AST_APP_ARG(fname_base); AST_APP_ARG(options); ); - + /* Parse arguments. */ if (ast_strlen_zero(data)) { ast_log(LOG_ERROR, "Monitor requires an argument\n"); @@ -985,9 +986,6 @@ static int load_module(void) ast_manager_register_xml("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action); ast_manager_register_xml("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action); - /* For Optional API. */ - ast_module_shutdown_ref(AST_MODULE_SELF); - return AST_MODULE_LOAD_SUCCESS; } @@ -1009,8 +1007,9 @@ static int unload_module(void) /* usecount semantics need to be defined */ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Call Monitoring Resource", - .support_level = AST_MODULE_SUPPORT_CORE, + .support_level = AST_MODULE_SUPPORT_DEPRECATED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .optional_modules = "func_periodic_hook", ); diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index e4bb7a2d9..55b14c934 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -19,7 +19,7 @@ /*! \file * * \brief Routines implementing music on hold - * + * * \author Mark Spencer <markster@digium.com> */ @@ -27,7 +27,7 @@ * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page musiconhold.conf musiconhold.conf * \verbinclude musiconhold.conf.sample */ @@ -314,7 +314,7 @@ static void moh_files_release(struct ast_channel *chan, void *data) state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator"); } -static int ast_moh_files_next(struct ast_channel *chan) +static int ast_moh_files_next(struct ast_channel *chan) { struct moh_files_state *state = ast_channel_music_state(chan); int tries; @@ -333,6 +333,7 @@ static int ast_moh_files_next(struct ast_channel *chan) } } else { state->announcement = 0; + state->samples = 0; } if (!state->class->total_files) { @@ -560,7 +561,7 @@ static int spawn_mp3(struct mohclass *class) DIR *dir = NULL; struct dirent *de; - + if (!strcasecmp(class->dir, "nodir")) { files = 1; } else { @@ -578,19 +579,19 @@ static int spawn_mp3(struct mohclass *class) argv[argc++] = "--mono"; argv[argc++] = "-r"; argv[argc++] = "8000"; - + if (!ast_test_flag(class, MOH_SINGLE)) { argv[argc++] = "-b"; argv[argc++] = "2048"; } - + argv[argc++] = "-f"; - + if (ast_test_flag(class, MOH_QUIET)) argv[argc++] = "4096"; else argv[argc++] = "8192"; - + /* Look for extra arguments and add them to the list */ ast_copy_string(xargs, class->args, sizeof(xargs)); argptr = xargs; @@ -614,9 +615,9 @@ static int spawn_mp3(struct mohclass *class) files++; } else if (dir) { while ((de = readdir(dir)) && (files < MAX_MP3S)) { - if ((strlen(de->d_name) > 3) && - ((ast_test_flag(class, MOH_CUSTOM) && - (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || + if ((strlen(de->d_name) > 3) && + ((ast_test_flag(class, MOH_CUSTOM) && + (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) || !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { ast_copy_string(fns[files], de->d_name, sizeof(fns[files])); @@ -629,7 +630,7 @@ static int spawn_mp3(struct mohclass *class) if (dir) { closedir(dir); } - if (pipe(fds)) { + if (pipe(fds)) { ast_log(LOG_WARNING, "Pipe failed\n"); return -1; } @@ -885,7 +886,7 @@ static int start_moh_exec(struct ast_channel *chan, const char *data) AST_STANDARD_APP_ARGS(args, parse); class = S_OR(args.class, NULL); - if (ast_moh_start(chan, class, NULL)) + if (ast_moh_start(chan, class, NULL)) ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan)); return 0; @@ -922,7 +923,6 @@ static struct mohclass *_get_mohbyname(const char *name, int warn, int flags, co static struct mohdata *mohalloc(struct mohclass *cl) { struct mohdata *moh; - long flags; if (!(moh = ast_calloc(1, sizeof(*moh)))) return NULL; @@ -934,10 +934,8 @@ static struct mohdata *mohalloc(struct mohclass *cl) } /* Make entirely non-blocking */ - flags = fcntl(moh->pipe[0], F_GETFL); - fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); - flags = fcntl(moh->pipe[1], F_GETFL); - fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(moh->pipe[0], O_NONBLOCK); + ast_fd_set_flags(moh->pipe[1], O_NONBLOCK); moh->f.frametype = AST_FRAME_VOICE; moh->f.subclass.format = cl->format; @@ -948,7 +946,7 @@ static struct mohdata *mohalloc(struct mohclass *cl) ao2_lock(cl); AST_LIST_INSERT_HEAD(&cl->members, moh, list); ao2_unlock(cl); - + return moh; } @@ -959,9 +957,9 @@ static void moh_release(struct ast_channel *chan, void *data) struct ast_format *oldwfmt; ao2_lock(class); - AST_LIST_REMOVE(&moh->parent->members, moh, list); + AST_LIST_REMOVE(&moh->parent->members, moh, list); ao2_unlock(class); - + close(moh->pipe[0]); close(moh->pipe[1]); @@ -1331,8 +1329,8 @@ static int _moh_register(struct mohclass *moh, int reload, int unref, const char } return -1; } - } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || - !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || + } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || + !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { if (init_app_class(moh)) { if (unref) { @@ -1651,7 +1649,7 @@ static void moh_class_destructor(void *obj) stime = time(NULL) + 2; killpid(class->pid, class->kill_delay, class->kill_method); - while ((ast_wait_for_input(class->srcfd, 100) > 0) && + while ((ast_wait_for_input(class->srcfd, 100) > 0) && (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { tbytes = tbytes + bytes; } @@ -1836,7 +1834,7 @@ static int load_moh_classes(int reload) ast_config_destroy(cfg); - ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, + ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes"); return numclasses; @@ -1937,6 +1935,9 @@ static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struc ast_cli(a->fd, "Class: %s\n", class->name); ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); + if (ast_test_flag(class, MOH_ANNOUNCEMENT)) { + ast_cli(a->fd, "\tAnnouncement: %s\n", S_OR(class->announcement, "<none>")); + } if (ast_test_flag(class, MOH_CUSTOM)) { ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); ast_cli(a->fd, "\tKill Escalation Delay: %zu ms\n", class->kill_delay / 1000); @@ -1980,8 +1981,8 @@ static int moh_class_cmp(void *obj, void *arg, int flags) * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) diff --git a/res/res_mwi_external.c b/res/res_mwi_external.c index d79799196..82c74b990 100644 --- a/res/res_mwi_external.c +++ b/res/res_mwi_external.c @@ -81,16 +81,6 @@ struct ast_mwi_mailbox_object { static struct ast_sorcery *mwi_sorcery; -void ast_mwi_external_ref(void) -{ - ast_module_ref(ast_module_info->self); -} - -void ast_mwi_external_unref(void) -{ - ast_module_unref(ast_module_info->self); -} - /*! * \internal * \brief Post an update event to the MWI counts. diff --git a/res/res_mwi_external_ami.c b/res/res_mwi_external_ami.c index 80d47d782..e4d5054e2 100644 --- a/res/res_mwi_external_ami.c +++ b/res/res_mwi_external_ami.c @@ -342,8 +342,6 @@ static int unload_module(void) ast_manager_unregister("MWIDelete"); ast_manager_unregister("MWIUpdate"); - /* Must be done last */ - ast_mwi_external_unref(); return 0; } @@ -351,9 +349,6 @@ static int load_module(void) { int res; - /* Must be done first */ - ast_mwi_external_ref(); - res = 0; res |= ast_manager_register_xml("MWIGet", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, mwi_mailbox_get); res |= ast_manager_register_xml("MWIDelete", EVENT_FLAG_CALL, mwi_mailbox_delete); @@ -370,5 +365,6 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "AMI support for external .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, + .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5, + .requires = "res_mwi_external", ); - diff --git a/res/res_odbc.c b/res/res_odbc.c index 24f63a92e..3ee8cba74 100644 --- a/res/res_odbc.c +++ b/res/res_odbc.c @@ -22,7 +22,7 @@ /*! \file * * \brief ODBC resource manager - * + * * \author Mark Spencer <markster@digium.com> * \author Anthony Minessale II <anthmct@yahoo.com> * \author Tilghman Lesher <tilghman@digium.com> @@ -34,7 +34,7 @@ * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page res_odbc.conf res_odbc.conf * \verbinclude res_odbc.conf.sample */ @@ -42,7 +42,6 @@ /*** MODULEINFO <depend>generic_odbc</depend> <depend>res_odbc_transaction</depend> - <depend>ltdl</depend> <support_level>core</support_level> ***/ @@ -1001,16 +1000,6 @@ static int unload_module(void) return -1; } -/*! - * \brief Load the module - * - * Module loading including tests for configuration or dependencies. - * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, - * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return - * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. - */ static int load_module(void) { if (!(class_container = ao2_container_alloc(1, null_hash_fn, ao2_match_by_addr))) @@ -1018,8 +1007,7 @@ static int load_module(void) if (load_odbc_config() == -1) return AST_MODULE_LOAD_DECLINE; ast_cli_register_multiple(cli_odbc, ARRAY_LEN(cli_odbc)); - ast_log(LOG_NOTICE, "res_odbc loaded.\n"); - return 0; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "ODBC resource", diff --git a/res/res_parking.c b/res/res_parking.c index 2dbe6f7d5..5d1b30c23 100644 --- a/res/res_parking.c +++ b/res/res_parking.c @@ -289,8 +289,8 @@ static struct aco_type global_option = { .type = ACO_GLOBAL, .name = "globals", .item_offset = offsetof(struct parking_config, global), - .category_match = ACO_WHITELIST, - .category = "^general$", + .category_match = ACO_WHITELIST_EXACT, + .category = "general", }; struct aco_type *global_options[] = ACO_TYPES(&global_option); @@ -298,8 +298,8 @@ struct aco_type *global_options[] = ACO_TYPES(&global_option); static struct aco_type parking_lot_type = { .type = ACO_ITEM, .name = "parking_lot", - .category_match = ACO_BLACKLIST, - .category = "^(general)$", + .category_match = ACO_BLACKLIST_EXACT, + .category = "general", .item_alloc = parking_lot_cfg_alloc, .item_find = named_item_find, .item_offset = offsetof(struct parking_config, parking_lots), diff --git a/res/res_phoneprov.c b/res/res_phoneprov.c index 92eec318f..70e133328 100644 --- a/res/res_phoneprov.c +++ b/res/res_phoneprov.c @@ -33,7 +33,7 @@ * \addtogroup configuration_file Configuration Files */ -/*! +/*! * \page phoneprov.conf phoneprov.conf * \verbinclude phoneprov.conf.sample */ @@ -1498,6 +1498,7 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "http", ); /**** Public API for register/unregister, set defaults, and add extension. ****/ diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 6137898a3..ebd71b99b 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -280,16 +280,6 @@ void ast_pjproject_log_intercept_end(void) ast_mutex_unlock(&pjproject_log_intercept_lock); } -void ast_pjproject_ref(void) -{ - ast_module_ref(ast_module_info->self); -} - -void ast_pjproject_unref(void) -{ - ast_module_unref(ast_module_info->self); -} - static char *handle_pjproject_show_buildopts(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { int i; @@ -469,6 +459,18 @@ static struct ast_cli_entry pjproject_cli[] = { AST_CLI_DEFINE(handle_pjproject_show_log_level, "Show the maximum active pjproject logging level"), }; +void ast_pjproject_caching_pool_init(pj_caching_pool *cp, + const pj_pool_factory_policy *policy, pj_size_t max_capacity) +{ + /* Passing a max_capacity of zero disables caching pools */ + pj_caching_pool_init(cp, policy, ast_option_pjproject_cache_pools ? max_capacity : 0); +} + +void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp) +{ + pj_caching_pool_destroy(cp); +} + static int load_module(void) { ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n"); diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 21e43f073..935a5598e 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -66,7 +66,7 @@ It contains the core SIP related options only, endpoints are <emphasis>NOT</emphasis> dialable entries of their own. Communication with another SIP device is accomplished via Addresses of Record (AoRs) which have one or more - contacts assicated with them. Endpoints <emphasis>NOT</emphasis> configured to + contacts associated with them. Endpoints <emphasis>NOT</emphasis> configured to use a <literal>transport</literal> will default to first transport found in <filename>pjsip.conf</filename> that matches its type. </para> @@ -269,45 +269,71 @@ <configOption name="ice_support" default="no"> <synopsis>Enable the ICE mechanism to help traverse NAT</synopsis> </configOption> - <configOption name="identify_by" default="username,ip"> - <synopsis>Way(s) for Endpoint to be identified</synopsis> - <description><para> - Endpoints and aors can be identified in multiple ways. Currently, the supported - options are <literal>username</literal>, which matches the endpoint or aor id based on - the username and domain in the From header (or To header for aors), - <literal>auth_username</literal>, which matches the endpoint or aor id based on the - username and realm in the Authentication header, and <literal>ip</literal> which matches - an endpoint based on the source IP address. In the <literal>username</literal> and - <literal>auth_username</literal> cases, if an exact match on both username and - domain/realm fails, the match will be retried with just the username. + <configOption name="identify_by"> + <synopsis>Way(s) for the endpoint to be identified</synopsis> + <description> + <para>Endpoints and AORs can be identified in multiple ways. This + option is a comma separated list of methods the endpoint can be + identified. </para> <note><para> - Identification by auth_username has some security considerations because an - Authentication header is not present on the first message of a dialog when - digest authentication is used. The client can't generate it until the server - sends the challenge in a 401 response. Since Asterisk normally sends a security - event when an incoming request can't be matched to an endpoint, using auth_username - requires that the security event be deferred until a request is received with - the Authentication header and only generated if the username doesn't result in a - match. This may result in a delay before an attack is recognized. You can control - how many unmatched requests are received from a single ip address before a security - event is generated using the unidentified_request parameters in the "global" - configuration object. + This option controls both how an endpoint is matched for incoming + traffic and also how an AOR is determined if a registration + occurs. You must list at least one method that also matches for + AORs or the registration will fail. </para></note> - <note><para>Endpoints can also be identified by IP address; however, that method - of identification is not configured but simply allowed by this configuration option. - See the documentation for the <literal>identify</literal> configuration section for - more details on that method of endpoint identification.</para></note> - <note><para> - This option controls both how an endpoint is matched for incoming traffic and also how - an AoR is determined if a registration occurs. If <literal>ip</literal> is set alone - then incoming registration will not find an AoR and the registration attempt will fail. - If you want to allow incoming registrations to succeed you must set a second identify - method such as <literal>username</literal> in this case.</para></note> <enumlist> - <enum name="username" /> - <enum name="auth_username" /> - <enum name="ip" /> + <enum name="username"> + <para>Matches the endpoint or AOR ID based on the username + and domain in the From header (or To header for AORs). If + an exact match on both username and domain/realm fails, the + match is retried with just the username. + </para> + </enum> + <enum name="auth_username"> + <para>Matches the endpoint or AOR ID based on the username + and realm in the Authentication header. If an exact match + on both username and domain/realm fails, the match is + retried with just the username. + </para> + <note><para>This method of identification has some security + considerations because an Authentication header is not + present on the first message of a dialog when digest + authentication is used. The client can't generate it until + the server sends the challenge in a 401 response. Since + Asterisk normally sends a security event when an incoming + request can't be matched to an endpoint, using this method + requires that the security event be deferred until a request + is received with the Authentication header and only + generated if the username doesn't result in a match. This + may result in a delay before an attack is recognized. You + can control how many unmatched requests are received from + a single ip address before a security event is generated + using the <literal>unidentified_request</literal> + parameters in the "global" configuration object. + </para></note> + </enum> + <enum name="ip"> + <para>Matches the endpoint based on the source IP address. + </para> + <para>This method of identification is not configured here + but simply allowed by this configuration option. See the + documentation for the <literal>identify</literal> + configuration section for more details on this method of + endpoint identification. + </para> + </enum> + <enum name="header"> + <para>Matches the endpoint based on a configured SIP header + value. + </para> + <para>This method of identification is not configured here + but simply allowed by this configuration option. See the + documentation for the <literal>identify</literal> + configuration section for more details on this method of + endpoint identification. + </para> + </enum> </enumlist> </description> </configOption> @@ -423,7 +449,7 @@ <configOption name="timers_min_se" default="90"> <synopsis>Minimum session timers expiration period</synopsis> <description><para> - Minimium session timer expiration period. Time in seconds. + Minimum session timer expiration period. Time in seconds. </para></description> </configOption> <configOption name="timers" default="yes"> @@ -441,7 +467,7 @@ <configOption name="timers_sess_expires" default="1800"> <synopsis>Maximum session timer expiration period</synopsis> <description><para> - Maximium session timer expiration period. Time in seconds. + Maximum session timer expiration period. Time in seconds. </para></description> </configOption> <configOption name="transport"> @@ -483,7 +509,7 @@ <synopsis>Must be of type 'endpoint'.</synopsis> </configOption> <configOption name="use_ptime" default="no"> - <synopsis>Use Endpoint's requested packetisation interval</synopsis> + <synopsis>Use Endpoint's requested packetization interval</synopsis> </configOption> <configOption name="use_avpf" default="no"> <synopsis>Determines whether res_pjsip will use and enforce usage of AVPF for this @@ -621,7 +647,7 @@ Forward error correction should be used. </para></enum> <enum name="redundancy"><para> - Redundacy error correction should be used. + Redundancy error correction should be used. </para></enum> </enumlist> </description> @@ -1085,7 +1111,7 @@ <description><para>Only used when auth_type is <literal>md5</literal>.</para></description> </configOption> <configOption name="password"> - <synopsis>PlainText password used for authentication.</synopsis> + <synopsis>Plain text password used for authentication.</synopsis> <description><para>Only used when auth_type is <literal>userpass</literal>.</para></description> </configOption> <configOption name="realm"> @@ -1212,6 +1238,8 @@ <para>This option is equivalent to setting 'default'</para> </enum> <enum name="tlsv1" /> + <enum name="tlsv1_1" /> + <enum name="tlsv1_2" /> <enum name="sslv2" /> <enum name="sslv3" /> <enum name="sslv23" /> @@ -1288,7 +1316,7 @@ </description> </configOption> <configOption name="symmetric_transport" default="no"> - <synopsis>Use the same transport for outgoing reqests as incoming ones.</synopsis> + <synopsis>Use the same transport for outgoing requests as incoming ones.</synopsis> <description> <para>When a request from a dynamic contact comes in on a transport with this option set to 'yes', @@ -1333,7 +1361,7 @@ <configOption name="qualify_timeout" default="3.0"> <synopsis>Timeout for qualify</synopsis> <description><para> - If the contact doesn't repond to the OPTIONS request before the timeout, + If the contact doesn't respond to the OPTIONS request before the timeout, the contact is marked unavailable. If <literal>0</literal> no timeout. Time in fractional seconds. </para></description> @@ -1417,8 +1445,8 @@ <literal>endpoint</literal> for calls. </para><para> This can be used as another way of grouping a list of contacts to dial - rather than specifing them each directly when dialing via the dialplan. - This must be used in conjuction with the <literal>PJSIP_DIAL_CONTACTS</literal>. + rather than specifying them each directly when dialing via the dialplan. + This must be used in conjunction with the <literal>PJSIP_DIAL_CONTACTS</literal>. </para><para> Registrations: For Asterisk to match an inbound registration to an endpoint, the AoR object name must match the user portion of the SIP URI in the "To:" @@ -1458,7 +1486,7 @@ <configOption name="maximum_expiration" default="7200"> <synopsis>Maximum time to keep an AoR</synopsis> <description><para> - Maximium time to keep a peer with explicit expiration. Time in seconds. + Maximum time to keep a peer with explicit expiration. Time in seconds. </para></description> </configOption> <configOption name="max_contacts" default="0"> @@ -1532,7 +1560,7 @@ <configOption name="qualify_timeout" default="3.0"> <synopsis>Timeout for qualify</synopsis> <description><para> - If the contact doesn't repond to the OPTIONS request before the timeout, + If the contact doesn't respond to the OPTIONS request before the timeout, the contact is marked unavailable. If <literal>0</literal> no timeout. Time in fractional seconds. </para></description> @@ -1631,7 +1659,7 @@ <configOption name="disable_multi_domain" default="no"> <synopsis>Disable Multi Domain support</synopsis> <description><para> - If disabled it can improve realtime performace by reducing number of database requsts. + If disabled it can improve realtime performance by reducing the number of database requests. </para></description> </configOption> <configOption name="max_initial_qualify_time" default="0"> @@ -1676,7 +1704,7 @@ <synopsis>Enable/Disable SIP debug logging. Valid options include yes|no or a host address</synopsis> </configOption> - <configOption name="endpoint_identifier_order" default="ip,username,anonymous"> + <configOption name="endpoint_identifier_order"> <synopsis>The order by which endpoint identifiers are processed and checked. Identifier names are usually derived from and can be found in the endpoint identifier module itself (res_pjsip_endpoint_identifier_*). @@ -1757,7 +1785,7 @@ in the user field of a SIP URI then the field is truncated at the first semicolon. This effectively makes the semicolon a non-usable character for PJSIP endpoint names, extensions, - and AORs. This can be useful for improving compatability with + and AORs. This can be useful for improving compatibility with an ITSP that likes to use user options for whatever reason. </para> <example title="Sample SIP URI"> @@ -1804,9 +1832,15 @@ <parameter name="Endpoint"> <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_endpoint_identifier_ip']/configFile[@name='pjsip.conf']/configObject[@name='identify']/configOption[@name='endpoint']/synopsis/node())"/></para> </parameter> + <parameter name="SrvLookups"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_endpoint_identifier_ip']/configFile[@name='pjsip.conf']/configObject[@name='identify']/configOption[@name='srv_lookups']/synopsis/node())"/></para> + </parameter> <parameter name="Match"> <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_endpoint_identifier_ip']/configFile[@name='pjsip.conf']/configObject[@name='identify']/configOption[@name='match']/synopsis/node())"/></para> </parameter> + <parameter name="MatchHeader"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip_endpoint_identifier_ip']/configFile[@name='pjsip.conf']/configObject[@name='identify']/configOption[@name='match_header']/synopsis/node())"/></para> + </parameter> <parameter name="EndpointName"> <para>The name of the endpoint associated with this information.</para> </parameter> @@ -2267,6 +2301,151 @@ </syntax> </managerEventInstance> </managerEvent> + <managerEvent language="en_US" name="AorList"> + <managerEventInstance class="EVENT_FLAG_COMMAND"> + <synopsis>Provide details about an Address of Record (AoR) section.</synopsis> + <syntax> + <parameter name="ObjectType"> + <para>The object's type. This will always be 'aor'.</para> + </parameter> + <parameter name="ObjectName"> + <para>The name of this object.</para> + </parameter> + <parameter name="MinimumExpiration"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='minimum_expiration']/synopsis/node())"/></para> + </parameter> + <parameter name="MaximumExpiration"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='maximum_expiration']/synopsis/node())"/></para> + </parameter> + <parameter name="DefaultExpiration"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='default_expiration']/synopsis/node())"/></para> + </parameter> + <parameter name="QualifyFrequency"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='qualify_frequency']/synopsis/node())"/></para> + </parameter> + <parameter name="AuthenticateQualify"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='authenticate_qualify']/synopsis/node())"/></para> + </parameter> + <parameter name="MaxContacts"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='max_contacts']/synopsis/node())"/></para> + </parameter> + <parameter name="RemoveExisting"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_existing']/synopsis/node())"/></para> + </parameter> + <parameter name="Mailboxes"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='mailboxes']/synopsis/node())"/></para> + </parameter> + <parameter name="OutboundProxy"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='outbound_proxy']/synopsis/node())"/></para> + </parameter> + <parameter name="SupportPath"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='support_path']/synopsis/node())"/></para> + </parameter> + </syntax> + </managerEventInstance> + </managerEvent> + <managerEvent language="en_US" name="AuthList"> + <managerEventInstance class="EVENT_FLAG_COMMAND"> + <synopsis>Provide details about an Address of Record (Auth) section.</synopsis> + <syntax> + <parameter name="ObjectType"> + <para>The object's type. This will always be 'auth'.</para> + </parameter> + <parameter name="ObjectName"> + <para>The name of this object.</para> + </parameter> + <parameter name="Username"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='username']/synopsis/node())"/></para> + </parameter> + <parameter name="Md5Cred"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='md5_cred']/synopsis/node())"/></para> + </parameter> + <parameter name="Realm"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='realm']/synopsis/node())"/></para> + </parameter> + <parameter name="AuthType"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='auth_type']/synopsis/node())"/></para> + </parameter> + <parameter name="Password"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='password']/synopsis/node())"/></para> + </parameter> + <parameter name="NonceLifetime"> + <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='auth']/configOption[@name='nonce_lifetime']/synopsis/node())"/></para> + </parameter> + </syntax> + </managerEventInstance> + </managerEvent> + <managerEvent language="en_US" name="ContactList"> + <managerEventInstance class="EVENT_FLAG_COMMAND"> + <synopsis>Provide details about a contact section.</synopsis> + <syntax> + <parameter name="ObjectType"> + <para>The object's type. This will always be 'contact'.</para> + </parameter> + <parameter name="ObjectName"> + <para>The name of this object.</para> + </parameter> + <parameter name="ViaAddr"> + <para>IP address of the last Via header in REGISTER request. + Will only appear in the event if available.</para> + </parameter> + <parameter name="ViaPort"> + <para>Port number of the last Via header in REGISTER request. + Will only appear in the event if available.</para> + </parameter> + <parameter name="QualifyTimeout"> + <para>The elapsed time in decimal seconds after which an OPTIONS + message is sent before the contact is considered unavailable.</para> + </parameter> + <parameter name="CallId"> + <para>Content of the Call-ID header in REGISTER request. + Will only appear in the event if available.</para> + </parameter> + <parameter name="RegServer"> + <para>Asterisk Server name.</para> + </parameter> + <parameter name="PruneOnBoot"> + <para>If true delete the contact on Asterisk restart/boot.</para> + </parameter> + <parameter name="Path"> + <para>The Path header received on the REGISTER.</para> + </parameter> + <parameter name="Endpoint"> + <para>The name of the endpoint associated with this information.</para> + </parameter> + <parameter name="AuthenticateQualify"> + <para>A boolean indicating whether a qualify should be authenticated.</para> + </parameter> + <parameter name="Uri"> + <para>This contact's URI.</para> + </parameter> + <parameter name="QualifyFrequency"> + <para>The interval in seconds at which the contact will be qualified.</para> + </parameter> + <parameter name="UserAgent"> + <para>Content of the User-Agent header in REGISTER request</para> + </parameter> + <parameter name="ExpirationTime"> + <para>Absolute time that this contact is no longer valid after</para> + </parameter> + <parameter name="OutboundProxy"> + <para>The contact's outbound proxy.</para> + </parameter> + <parameter name="Status"> + <para>This contact's status.</para> + <enumlist> + <enum name="Reachable"/> + <enum name="Unreachable"/> + <enum name="NonQualified"/> + <enum name="Unknown"/> + </enumlist> + </parameter> + <parameter name="RoundtripUsec"> + <para>The round trip time in microseconds.</para> + </parameter> + </syntax> + </managerEventInstance> + </managerEvent> <managerEvent language="en_US" name="ContactStatusDetail"> <managerEventInstance class="EVENT_FLAG_COMMAND"> <synopsis>Provide details about a contact's status.</synopsis> @@ -2282,6 +2461,8 @@ <enumlist> <enum name="Reachable"/> <enum name="Unreachable"/> + <enum name="NonQualified"/> + <enum name="Unknown"/> </enumlist> </parameter> <parameter name="RoundtripUsec"> @@ -2425,6 +2606,87 @@ </managerEvent> </responses> </manager> + <manager name="PJSIPShowAors" language="en_US"> + <synopsis> + Lists PJSIP AORs. + </synopsis> + <syntax /> + <description> + <para> + Provides a listing of all AORs. For each AOR an <literal>AorList</literal> event + is raised that contains relevant attributes and status information. Once all + aors have been listed an <literal>AorListComplete</literal> event is issued. + </para> + </description> + <responses> + <list-elements> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='AorList'])" /> + </list-elements> + <managerEvent language="en_US" name="AorListComplete"> + <managerEventInstance class="EVENT_FLAG_COMMAND"> + <synopsis>Provide final information about an aor list.</synopsis> + <syntax> + <parameter name="EventList"/> + <parameter name="ListItems"/> + </syntax> + </managerEventInstance> + </managerEvent> + </responses> + </manager> + <manager name="PJSIPShowAuths" language="en_US"> + <synopsis> + Lists PJSIP Auths. + </synopsis> + <syntax /> + <description> + <para>Provides a listing of all Auths. For each Auth an <literal>AuthList</literal> event + is raised that contains relevant attributes and status information. Once all + auths have been listed an <literal>AuthListComplete</literal> event is issued. + </para> + </description> + <responses> + <list-elements> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='AuthList'])" /> + </list-elements> + <managerEvent language="en_US" name="AuthListComplete"> + <managerEventInstance class="EVENT_FLAG_COMMAND"> + <synopsis>Provide final information about an auth list.</synopsis> + <syntax> + <parameter name="EventList"/> + <parameter name="ListItems"/> + </syntax> + </managerEventInstance> + </managerEvent> + </responses> + </manager> + <manager name="PJSIPShowContacts" language="en_US"> + <synopsis> + Lists PJSIP Contacts. + </synopsis> + <syntax /> + <description> + <para>Provides a listing of all Contacts. For each Contact a <literal>ContactList</literal> + event is raised that contains relevant attributes and status information. + Once all contacts have been listed a <literal>ContactListComplete</literal> event + is issued. + </para> + </description> + <responses> + <list-elements> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='ContactList'])" /> + </list-elements> + <managerEvent language="en_US" name="ContactListComplete"> + <managerEventInstance class="EVENT_FLAG_COMMAND"> + <synopsis>Provide final information about a contact list.</synopsis> + <syntax> + <parameter name="EventList"/> + <parameter name="ListItems"/> + </syntax> + </managerEventInstance> + </managerEvent> + </responses> + </manager> + ***/ #define MOD_DATA_CONTACT "contact" @@ -2454,7 +2716,7 @@ static pj_sockaddr host_ip_ipv6; /*! Local host address for IPv6 (string form) */ static char host_ip_ipv6_string[PJ_INET6_ADDRSTRLEN]; -static int register_service_noref(void *data) +static int register_service(void *data) { pjsip_module **module = data; if (!ast_pjsip_endpoint) { @@ -2469,23 +2731,12 @@ static int register_service_noref(void *data) return 0; } -int internal_sip_register_service(pjsip_module *module) +int ast_sip_register_service(pjsip_module *module) { - return ast_sip_push_task_synchronous(NULL, register_service_noref, &module); + return ast_sip_push_task_synchronous(NULL, register_service, &module); } -int __ast_sip_register_service(pjsip_module *module, const char *file, int line, const char *func) -{ - int res; - - if (!(res = ast_sip_push_task_synchronous(NULL, register_service_noref, &module))) { - __ast_module_ref(ast_module_info->self, file, line, func); - } - - return res; -} - -static int unregister_service_noref(void *data) +static int unregister_service(void *data) { pjsip_module **module = data; if (!ast_pjsip_endpoint) { @@ -2496,16 +2747,9 @@ static int unregister_service_noref(void *data) return 0; } -int internal_sip_unregister_service(pjsip_module *module) -{ - return ast_sip_push_task_synchronous(NULL, unregister_service_noref, &module); -} - -void __ast_sip_unregister_service(pjsip_module *module, const char *file, int line, const char *func) +void ast_sip_unregister_service(pjsip_module *module) { - if (!ast_sip_push_task_synchronous(NULL, unregister_service_noref, &module)) { - __ast_module_unref(ast_module_info->self, file, line, func); - } + ast_sip_push_task_synchronous(NULL, unregister_service, &module); } static struct ast_sip_authenticator *registered_authenticator; @@ -2518,7 +2762,7 @@ int ast_sip_register_authenticator(struct ast_sip_authenticator *auth) } registered_authenticator = auth; ast_debug(1, "Registered SIP authenticator module %p\n", auth); - ast_module_ref(ast_module_info->self); + return 0; } @@ -2531,7 +2775,6 @@ void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth) } registered_authenticator = NULL; ast_debug(1, "Unregistered SIP authenticator %p\n", auth); - ast_module_unref(ast_module_info->self); } int ast_sip_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata) @@ -2564,7 +2807,7 @@ int ast_sip_register_outbound_authenticator(struct ast_sip_outbound_authenticato } registered_outbound_authenticator = auth; ast_debug(1, "Registered SIP outbound authenticator module %p\n", auth); - ast_module_ref(ast_module_info->self); + return 0; } @@ -2577,7 +2820,6 @@ void ast_sip_unregister_outbound_authenticator(struct ast_sip_outbound_authentic } registered_outbound_authenticator = NULL; ast_debug(1, "Unregistered SIP outbound authenticator %p\n", auth); - ast_module_unref(ast_module_info->self); } int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, @@ -2608,18 +2850,17 @@ int ast_sip_register_endpoint_identifier_with_name(struct ast_sip_endpoint_ident id_list_item = ast_calloc(1, sizeof(*id_list_item)); if (!id_list_item) { - ast_log(LOG_ERROR, "Unabled to add endpoint identifier. Out of memory.\n"); + ast_log(LOG_ERROR, "Unable to add endpoint identifier. Out of memory.\n"); return -1; } id_list_item->identifier = identifier; id_list_item->name = name; - ast_debug(1, "Register endpoint identifier %s (%p)\n", name, identifier); + ast_debug(1, "Register endpoint identifier %s(%p)\n", name ?: "", identifier); if (ast_strlen_zero(name)) { /* if an identifier has no name then place in front */ AST_RWLIST_INSERT_HEAD(&endpoint_identifiers, id_list_item, list); - ast_module_ref(ast_module_info->self); return 0; } @@ -2629,7 +2870,6 @@ int ast_sip_register_endpoint_identifier_with_name(struct ast_sip_endpoint_ident if (ast_strlen_zero(identifier_order)) { id_list_item->priority = UINT_MAX; AST_RWLIST_INSERT_TAIL(&endpoint_identifiers, id_list_item, list); - ast_module_ref(ast_module_info->self); ast_free(identifier_order); return 0; } @@ -2637,7 +2877,8 @@ int ast_sip_register_endpoint_identifier_with_name(struct ast_sip_endpoint_ident id_list_item->priority = 0; while ((current = strchr(current, ','))) { ++id_list_item->priority; - if (!strncmp(prev, name, current - prev)) { + if (!strncmp(prev, name, current - prev) + && strlen(name) == current - prev) { break; } prev = ++current; @@ -2656,7 +2897,6 @@ int ast_sip_register_endpoint_identifier_with_name(struct ast_sip_endpoint_ident /* if not in the endpoint_identifier_order list then consider it less in priority and add it to the end */ AST_RWLIST_INSERT_TAIL(&endpoint_identifiers, id_list_item, list); - ast_module_ref(ast_module_info->self); ast_free(identifier_order); return 0; } @@ -2674,7 +2914,6 @@ int ast_sip_register_endpoint_identifier_with_name(struct ast_sip_endpoint_ident } AST_RWLIST_TRAVERSE_SAFE_END; - ast_module_ref(ast_module_info->self); ast_free(identifier_order); return 0; } @@ -2693,7 +2932,6 @@ void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier * AST_RWLIST_REMOVE_CURRENT(list); ast_free(iter); ast_debug(1, "Unregistered endpoint identifier %p\n", identifier); - ast_module_unref(ast_module_info->self); break; } } @@ -2836,23 +3074,17 @@ static struct ast_cli_entry cli_commands[] = { AST_RWLIST_HEAD_STATIC(endpoint_formatters, ast_sip_endpoint_formatter); -void internal_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) +void ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) { SCOPED_LOCK(lock, &endpoint_formatters, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); AST_RWLIST_INSERT_TAIL(&endpoint_formatters, obj, next); } -int ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) -{ - internal_sip_register_endpoint_formatter(obj); - ast_module_ref(ast_module_info->self); - return 0; -} - -int internal_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) +void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) { struct ast_sip_endpoint_formatter *i; SCOPED_LOCK(lock, &endpoint_formatters, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + AST_RWLIST_TRAVERSE_SAFE_BEGIN(&endpoint_formatters, i, next) { if (i == obj) { AST_RWLIST_REMOVE_CURRENT(next); @@ -2860,14 +3092,6 @@ int internal_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter } } AST_RWLIST_TRAVERSE_SAFE_END; - return i == obj ? 0 : -1; -} - -void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj) -{ - if (!internal_sip_unregister_endpoint_formatter(obj)) { - ast_module_unref(ast_module_info->self); - } } int ast_sip_format_endpoint_ami(struct ast_sip_endpoint *endpoint, @@ -2894,6 +3118,45 @@ pjsip_endpoint *ast_sip_get_pjsip_endpoint(void) return ast_pjsip_endpoint; } +int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, + pjsip_rx_data *rdata) +{ + pj_str_t host_name; + int result = 1; + + /* Determine if the contact cannot survive a restart/boot. */ + if (uri->port == rdata->pkt_info.src_port + && !pj_strcmp(&uri->host, + pj_cstr(&host_name, rdata->pkt_info.src_name)) + /* We have already checked if the URI scheme is sip: or sips: */ + && PJSIP_TRANSPORT_IS_RELIABLE(rdata->tp_info.transport)) { + pj_str_t type_name; + + /* Determine the transport parameter value */ + if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) { + /* WSS is special, as it needs to be ws. */ + pj_cstr(&type_name, "ws"); + } else { + pj_cstr(&type_name, rdata->tp_info.transport->type_name); + } + + if (!pj_stricmp(&uri->transport_param, &type_name) + && (endpoint->nat.rewrite_contact + /* Websockets are always rewritten */ + || !pj_stricmp(&uri->transport_param, + pj_cstr(&type_name, "ws")))) { + /* + * The contact was rewritten to the reliable transport's + * source address. Disconnecting the transport for any + * reason invalidates the contact. + */ + result = 0; + } + } + + return result; +} + int ast_sip_get_transport_name(const struct ast_sip_endpoint *endpoint, pjsip_sip_uri *sip_uri, char *buf, size_t buf_len) { @@ -3087,8 +3350,6 @@ void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t { pjsip_sip_uri *sip_uri; int i = 0; - pjsip_param *param; - static const pj_str_t STR_USER = { "user", 4 }; static const pj_str_t STR_PHONE = { "phone", 5 }; if (!endpoint || !endpoint->usereqphone || (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) { @@ -3116,15 +3377,7 @@ void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t return; } - if (pjsip_param_find(&sip_uri->other_param, &STR_USER)) { - /* Don't add it if it's already there */ - return; - } - - param = PJ_POOL_ALLOC_T(pool, pjsip_param); - param->name = STR_USER; - param->value = STR_PHONE; - pj_list_insert_before(&sip_uri->other_param, param); + sip_uri->user_param = STR_PHONE; } pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, @@ -3276,7 +3529,7 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, ast_assert(status != NULL); contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); - if (ast_sip_set_tpselector_from_ep_or_uri(endpoint, pjsip_uri_get_uri(contact_hdr->uri), + if (!contact_hdr || ast_sip_set_tpselector_from_ep_or_uri(endpoint, pjsip_uri_get_uri(contact_hdr->uri), &selector)) { return NULL; } @@ -3554,7 +3807,7 @@ int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, AST_RWLIST_HEAD_STATIC(supplements, ast_sip_supplement); -void internal_sip_register_supplement(struct ast_sip_supplement *supplement) +void ast_sip_register_supplement(struct ast_sip_supplement *supplement) { struct ast_sip_supplement *iter; int inserted = 0; @@ -3574,39 +3827,18 @@ void internal_sip_register_supplement(struct ast_sip_supplement *supplement) } } -int __ast_sip_register_supplement(struct ast_sip_supplement *supplement, - const char *file, int line, const char *func) -{ - internal_sip_register_supplement(supplement); - __ast_module_ref(ast_module_info->self, file, line, func); - - return 0; -} - -int internal_sip_unregister_supplement(struct ast_sip_supplement *supplement) +void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement) { struct ast_sip_supplement *iter; SCOPED_LOCK(lock, &supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); - int res = -1; AST_RWLIST_TRAVERSE_SAFE_BEGIN(&supplements, iter, next) { if (supplement == iter) { AST_RWLIST_REMOVE_CURRENT(next); - res = 0; break; } } AST_RWLIST_TRAVERSE_SAFE_END; - - return res; -} - -void __ast_sip_unregister_supplement(struct ast_sip_supplement *supplement, - const char *file, int line, const char *func) -{ - if (!internal_sip_unregister_supplement(supplement)) { - __ast_module_unref(ast_module_info->self, file, line, func); - } } static int send_in_dialog_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg) @@ -3941,7 +4173,8 @@ int ast_sip_failover_request(pjsip_tx_data *tdata) { pjsip_via_hdr *via; - if (!tdata->dest_info.addr.count || (tdata->dest_info.cur_addr == tdata->dest_info.addr.count - 1)) { + if (!tdata || !tdata->dest_info.addr.count + || (tdata->dest_info.cur_addr == tdata->dest_info.addr.count - 1)) { /* No more addresses to try */ return 0; } @@ -4489,9 +4722,15 @@ static void supplement_outgoing_response(pjsip_tx_data *tdata, struct ast_sip_en int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint) { + pj_status_t status; + supplement_outgoing_response(tdata, sip_endpoint); + status = pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), res_addr, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } - return pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), res_addr, tdata, NULL, NULL); + return status == PJ_SUCCESS ? 0 : -1; } int ast_sip_send_stateful_response(pjsip_rx_data *rdata, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint) @@ -4733,10 +4972,11 @@ static int unload_pjsip(void *data) ast_res_pjsip_cleanup_options_handling(); ast_res_pjsip_cleanup_message_filter(); ast_sip_destroy_distributor(); + ast_sip_destroy_transport_management(); ast_res_pjsip_destroy_configuration(); ast_sip_destroy_system(); ast_sip_destroy_global_headers(); - internal_sip_unregister_service(&supplement_module); + ast_sip_unregister_service(&supplement_module); ast_sip_destroy_transport_events(); } @@ -4758,7 +4998,7 @@ static int unload_pjsip(void *data) ast_pjsip_endpoint = NULL; if (caching_pool.lock) { - pj_caching_pool_destroy(&caching_pool); + ast_pjproject_caching_pool_destroy(&caching_pool); } pj_shutdown(); @@ -4775,7 +5015,7 @@ static int load_pjsip(void) * example code from PJLIB. This can be adjusted * if necessary. */ - pj_caching_pool_init(&caching_pool, NULL, 1024 * 1024); + ast_pjproject_caching_pool_init(&caching_pool, NULL, 1024 * 1024); if (pjsip_endpt_create(&caching_pool.factory, "SIP", &ast_pjsip_endpoint) != PJ_SUCCESS) { ast_log(LOG_ERROR, "Failed to create PJSIP endpoint structure. Aborting load\n"); goto error; @@ -4836,8 +5076,6 @@ static int load_module(void) { struct ast_threadpool_options options; - CHECK_PJPROJECT_MODULE_LOADED(); - /* pjproject and config_system need to be initialized before all else */ if (pj_init() != PJ_SUCCESS) { return AST_MODULE_LOAD_DECLINE; @@ -4898,12 +5136,17 @@ static int load_module(void) ast_sip_initialize_resolver(); ast_sip_initialize_dns(); + if (ast_sip_initialize_transport_management()) { + ast_log(LOG_ERROR, "Failed to initialize SIP transport management. Aborting load\n"); + goto error; + } + if (ast_sip_initialize_distributor()) { ast_log(LOG_ERROR, "Failed to register distributor module. Aborting load\n"); goto error; } - if (internal_sip_register_service(&supplement_module)) { + if (ast_sip_register_service(&supplement_module)) { ast_log(LOG_ERROR, "Failed to initialize supplement hooks. Aborting load\n"); goto error; } @@ -4920,8 +5163,6 @@ static int load_module(void) AST_TEST_REGISTER(xml_sanitization_end_null); AST_TEST_REGISTER(xml_sanitization_exceeds_buffer); - ast_pjproject_ref(); - return AST_MODULE_LOAD_SUCCESS; error: @@ -4963,8 +5204,6 @@ static int unload_module(void) serializer_pool_shutdown(); ast_threadpool_shutdown(sip_threadpool); - ast_pjproject_unref(); - return 0; } @@ -4974,4 +5213,6 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5, + .requires = "dnsmgr,res_pjproject", + .optional_modules = "res_statsd", ); diff --git a/res/res_pjsip/config_auth.c b/res/res_pjsip/config_auth.c index 9160e6709..b1bf9c422 100644 --- a/res/res_pjsip/config_auth.c +++ b/res/res_pjsip/config_auth.c @@ -195,6 +195,67 @@ static struct ast_sip_endpoint_formatter endpoint_auth_formatter = { .format_ami = format_ami_endpoint_auth }; +static struct ao2_container *cli_get_auths(void) +{ + struct ao2_container *auths; + + auths = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "auth", + AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + + return auths; +} + +static int format_ami_authlist_handler(void *obj, void *arg, int flags) +{ + struct ast_sip_auth *auth = obj; + struct ast_sip_ami *ami = arg; + struct ast_str *buf; + + buf = ast_sip_create_ami_event("AuthList", ami); + if (!buf) { + return CMP_STOP; + } + + sip_auth_to_ami(auth, &buf); + + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + ami->count++; + + ast_free(buf); + + return 0; +} + +static int ami_show_auths(struct mansession *s, const struct message *m) +{ + struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), }; + struct ao2_container *auths; + + auths = cli_get_auths(); + if (!auths) { + astman_send_error(s, m, "Could not get Auths\n"); + return 0; + } + + if (!ao2_container_count(auths)) { + astman_send_error(s, m, "No Auths found\n"); + ao2_ref(auths, -1); + return 0; + } + + astman_send_listack(s, m, "A listing of Auths follows, presented as AuthList events", + "start"); + + ao2_callback(auths, OBJ_NODATA, format_ami_authlist_handler, &ami); + + astman_send_list_complete_start(s, m, "AuthListComplete", ami.count); + astman_send_list_complete_end(s); + + ao2_ref(auths, -1); + + return 0; +} + static struct ao2_container *cli_get_container(const char *regex) { RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup); @@ -313,7 +374,7 @@ int ast_sip_initialize_sorcery_auth(void) ast_sorcery_object_field_register_custom(sorcery, SIP_SORCERY_AUTH_TYPE, "auth_type", "userpass", auth_type_handler, auth_type_to_str, NULL, 0, 0); - internal_sip_register_endpoint_formatter(&endpoint_auth_formatter); + ast_sip_register_endpoint_formatter(&endpoint_auth_formatter); cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); if (!cli_formatter) { @@ -331,6 +392,10 @@ int ast_sip_initialize_sorcery_auth(void) ast_sip_register_cli_formatter(cli_formatter); ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); + if (ast_manager_register_xml("PJSIPShowAuths", EVENT_FLAG_SYSTEM, ami_show_auths)) { + return -1; + } + return 0; } @@ -338,7 +403,9 @@ int ast_sip_destroy_sorcery_auth(void) { ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sip_unregister_cli_formatter(cli_formatter); - internal_sip_unregister_endpoint_formatter(&endpoint_auth_formatter); + ast_sip_unregister_endpoint_formatter(&endpoint_auth_formatter); + + ast_manager_unregister("PJSIPShowAuths"); return 0; } diff --git a/res/res_pjsip/config_domain_aliases.c b/res/res_pjsip/config_domain_aliases.c index 8feff0571..79ea8dd0e 100644 --- a/res/res_pjsip/config_domain_aliases.c +++ b/res/res_pjsip/config_domain_aliases.c @@ -34,8 +34,9 @@ static void domain_alias_destroy(void *obj) static void *domain_alias_alloc(const char *name) { - struct ast_sip_domain_alias *alias = ast_sorcery_generic_alloc(sizeof(*alias), domain_alias_destroy); + struct ast_sip_domain_alias *alias; + alias = ast_sorcery_generic_alloc(sizeof(*alias), domain_alias_destroy); if (!alias) { return NULL; } @@ -48,6 +49,23 @@ static void *domain_alias_alloc(const char *name) return alias; } +/*! \brief Apply handler for domain_alias type */ +static int domain_alias_apply(const struct ast_sorcery *sorcery, void *obj) +{ + struct ast_sip_domain_alias *alias = obj; + + if (ast_strlen_zero(alias->domain)) { + /* + * What is the point of defining an alias and not saying + * what is being aliased? + */ + ast_log(LOG_ERROR, "%s '%s' missing required domain being aliased.\n", + SIP_SORCERY_DOMAIN_ALIAS_TYPE, ast_sorcery_object_get_id(alias)); + return -1; + } + return 0; +} + /*! \brief Initialize sorcery with domain alias support */ int ast_sip_initialize_sorcery_domain_alias(void) { @@ -55,7 +73,8 @@ int ast_sip_initialize_sorcery_domain_alias(void) ast_sorcery_apply_default(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, "config", "pjsip.conf,criteria=type=domain_alias"); - if (ast_sorcery_object_register(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, domain_alias_alloc, NULL, NULL)) { + if (ast_sorcery_object_register(sorcery, SIP_SORCERY_DOMAIN_ALIAS_TYPE, + domain_alias_alloc, NULL, domain_alias_apply)) { return -1; } diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 2f29456ab..15c03769b 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -30,6 +30,7 @@ #include "asterisk/acl.h" #include "asterisk/utils.h" #include "include/res_pjsip_private.h" +/* We're only using a #define from http_websocket.h, no OPTIONAL_API symbols are used. */ #include "asterisk/http_websocket.h" #define MAX_POINTER_STRING 33 @@ -618,6 +619,8 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) &temp_state->state->factory); } } else if (transport->type == AST_TRANSPORT_TLS) { + static int option = 1; + if (transport->async_operations > 1 && ast_compare_versions(pj_get_version(), "2.5.0") < 0) { ast_log(LOG_ERROR, "Transport: %s: When protocol=tls and pjproject version < 2.5.0, async_operations can't be > 1\n", ast_sorcery_object_get_id(obj)); @@ -627,6 +630,13 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) temp_state->state->tls.password = pj_str((char*)transport->password); set_qos(transport, &temp_state->state->tls.qos_params); + /* sockopt_params.options is copied to each newly connected socket */ + temp_state->state->tls.sockopt_params.options[0].level = pj_SOL_TCP(); + temp_state->state->tls.sockopt_params.options[0].optname = pj_TCP_NODELAY(); + temp_state->state->tls.sockopt_params.options[0].optval = &option; + temp_state->state->tls.sockopt_params.options[0].optlen = sizeof(option); + temp_state->state->tls.sockopt_params.cnt = 1; + for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->factory && perm_state->state->factory->destroy) { @@ -917,6 +927,12 @@ static int transport_tls_method_handler(const struct aco_option *opt, struct ast state->tls.method = PJSIP_SSL_UNSPECIFIED_METHOD; } else if (!strcasecmp(var->value, "tlsv1")) { state->tls.method = PJSIP_TLSV1_METHOD; +#ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO + } else if (!strcasecmp(var->value, "tlsv1_1")) { + state->tls.method = PJSIP_TLSV1_1_METHOD; + } else if (!strcasecmp(var->value, "tlsv1_2")) { + state->tls.method = PJSIP_TLSV1_2_METHOD; +#endif } else if (!strcasecmp(var->value, "sslv2")) { state->tls.method = PJSIP_SSLV2_METHOD; } else if (!strcasecmp(var->value, "sslv3")) { @@ -933,6 +949,10 @@ static int transport_tls_method_handler(const struct aco_option *opt, struct ast static const char *tls_method_map[] = { [PJSIP_SSL_UNSPECIFIED_METHOD] = "unspecified", [PJSIP_TLSV1_METHOD] = "tlsv1", +#ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO + [PJSIP_TLSV1_1_METHOD] = "tlsv1_1", + [PJSIP_TLSV1_2_METHOD] = "tlsv1_2", +#endif [PJSIP_SSLV2_METHOD] = "sslv2", [PJSIP_SSLV3_METHOD] = "sslv3", [PJSIP_SSLV23_METHOD] = "sslv23", @@ -1416,7 +1436,7 @@ int ast_sip_initialize_sorcery_transport(void) ast_sorcery_object_field_register(sorcery, "transport", "allow_reload", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_transport, allow_reload)); ast_sorcery_object_field_register(sorcery, "transport", "symmetric_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_transport, symmetric_transport)); - internal_sip_register_endpoint_formatter(&endpoint_transport_formatter); + ast_sip_register_endpoint_formatter(&endpoint_transport_formatter); cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); if (!cli_formatter) { @@ -1446,7 +1466,7 @@ int ast_sip_destroy_sorcery_transport(void) ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sip_unregister_cli_formatter(cli_formatter); - internal_sip_unregister_endpoint_formatter(&endpoint_transport_formatter); + ast_sip_unregister_endpoint_formatter(&endpoint_transport_formatter); ao2_ref(transport_states, -1); transport_states = NULL; diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index 5ce3c6faf..71947f840 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -314,58 +314,10 @@ int sip_cli_print_global(struct ast_sip_cli_context *context); */ int sip_cli_print_system(struct ast_sip_cli_context *context); -/*! - * \internal - * \brief Used by res_pjsip.so to register a service without adding a self reference - */ -int internal_sip_register_service(pjsip_module *module); - -/*! - * \internal - * \brief Used by res_pjsip.so to unregister a service without removing a self reference - */ -int internal_sip_unregister_service(pjsip_module *module); - -/*! - * \internal - * \brief Used by res_pjsip.so to register a supplement without adding a self reference - */ -void internal_sip_register_supplement(struct ast_sip_supplement *supplement); - -/*! - * \internal - * \brief Used by res_pjsip.so to unregister a supplement without removing a self reference - */ -int internal_sip_unregister_supplement(struct ast_sip_supplement *supplement); - -/*! - * \internal - * \brief Used by res_pjsip.so to register an endpoint formatter without adding a self reference - */ -void internal_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj); - -/*! - * \internal - * \brief Used by res_pjsip.so to unregister a endpoint formatter without removing a self reference - */ -int internal_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj); - struct ast_sip_session_supplement; /*! * \internal - * \brief Used by res_pjsip.so to register a session supplement without adding a self reference - */ -void internal_sip_session_register_supplement(struct ast_sip_session_supplement *supplement); - -/*! - * \internal - * \brief Used by res_pjsip.so to unregister a session supplement without removing a self reference - */ -int internal_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement); - -/*! - * \internal * \brief Finds or creates contact_status for a contact */ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact); @@ -395,4 +347,46 @@ int ast_sip_initialize_scheduler(void); */ int ast_sip_destroy_scheduler(void); +/*! + * \internal + * \brief Determines if a uri will still be valid after an asterisk restart + * \since 13.20.0 + * + * \param uri uri to test + * \param endpoint The associated endpoint + * \param rdata The rdata to get transport information from + * + * \retval 1 Yes, 0 No + */ +int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, + pjsip_rx_data *rdata); + +/*! + * \internal + * \brief Initialize the transport management module + * \since 13.20.0 + * + * The transport management module is responsible for 3 things... + * 1. It automatically destroys any reliable transport that does not + * receive a valid request within system/timer_b milliseconds of the + * connection being opened. (Attack mitigation) + * 2. Since it increments the reliable transport's reference count + * for that period of time, it also prevents issues if the transport + * disconnects while we're still trying to process a response. + * (Attack mitigation) + * 3. If enabled by global/keep_alive_interval, it sends '\r\n' + * keepalives on reliable transports at the interval specified. + * + * \retval -1 Failure + * \retval 0 Success + */ +int ast_sip_initialize_transport_management(void); + +/*! + * \internal + * \brief Destruct the transport management module. + * \since 13.20.0 + */ +void ast_sip_destroy_transport_management(void); + #endif /* RES_PJSIP_PRIVATE_H_ */ diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 299fdb722..22da80577 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -17,8 +17,8 @@ */ #include "asterisk.h" -#include "pjsip.h" -#include "pjlib.h" +#include <pjsip.h> +#include <pjlib.h> #include "asterisk/res_pjsip.h" #include "asterisk/logger.h" @@ -1179,6 +1179,67 @@ static int cli_aor_print_body(void *obj, void *arg, int flags) return 0; } +static struct ao2_container *cli_get_aors(void) +{ + struct ao2_container *aors; + + aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor", + AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + + return aors; +} + +static int format_ami_aorlist_handler(void *obj, void *arg, int flags) +{ + struct ast_sip_aor *aor = obj; + struct ast_sip_ami *ami = arg; + struct ast_str *buf; + + buf = ast_sip_create_ami_event("AorList", ami); + if (!buf) { + return -1; + } + + sip_aor_to_ami(aor, &buf); + + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + ami->count++; + + ast_free(buf); + + return 0; +} + +static int ami_show_aors(struct mansession *s, const struct message *m) +{ + struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), }; + struct ao2_container *aors; + + aors = cli_get_aors(); + if (!aors) { + astman_send_error(s, m, "Could not get AORs\n"); + return 0; + } + + if (!ao2_container_count(aors)) { + astman_send_error(s, m, "No AORs found\n"); + ao2_ref(aors, -1); + return 0; + } + + astman_send_listack(s, m, "A listing of AORs follows, presented as AorList events", + "start"); + + ao2_callback(aors, OBJ_NODATA, format_ami_aorlist_handler, &ami); + + astman_send_list_complete_start(s, m, "AorListComplete", ami.count); + astman_send_list_complete_end(s); + + ao2_ref(aors, -1); + + return 0; +} + static struct ast_cli_entry cli_commands[] = { AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Aors", .command = "pjsip list aors", @@ -1285,7 +1346,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path)); - internal_sip_register_endpoint_formatter(&endpoint_aor_formatter); + ast_sip_register_endpoint_formatter(&endpoint_aor_formatter); contact_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); if (!contact_formatter) { @@ -1317,6 +1378,10 @@ int ast_sip_initialize_sorcery_location(void) ast_sip_register_cli_formatter(aor_formatter); ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); + if (ast_manager_register_xml("PJSIPShowAors", EVENT_FLAG_SYSTEM, ami_show_aors)) { + return -1; + } + /* * Reset StatsD gauges in case we didn't shut down cleanly. * Note that this must done here, as contacts will create the contact_status @@ -1335,9 +1400,9 @@ int ast_sip_destroy_sorcery_location(void) ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sip_unregister_cli_formatter(contact_formatter); ast_sip_unregister_cli_formatter(aor_formatter); + ast_manager_unregister("PJSIPShowAors"); - internal_sip_unregister_endpoint_formatter(&endpoint_aor_formatter); + ast_sip_unregister_endpoint_formatter(&endpoint_aor_formatter); return 0; } - diff --git a/res/res_pjsip/pjsip_cli.c b/res/res_pjsip/pjsip_cli.c index 56ec191ed..4544a1717 100644 --- a/res/res_pjsip/pjsip_cli.c +++ b/res/res_pjsip/pjsip_cli.c @@ -82,31 +82,22 @@ int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags) return 0; } -static char *complete_show_sorcery_object(struct ao2_container *container, +static void complete_show_sorcery_object(struct ao2_container *container, struct ast_sip_cli_formatter_entry *formatter_entry, - const char *word, int state) + const char *word) { - char *result = NULL; - int wordlen = strlen(word); - int which = 0; - - struct ao2_iterator i = ao2_iterator_init(container, 0); + size_t wordlen = strlen(word); void *object; + struct ao2_iterator i = ao2_iterator_init(container, 0); while ((object = ao2_t_iterator_next(&i, "iterate thru endpoints table"))) { const char *id = formatter_entry->get_id(object); - if (!strncasecmp(word, id, wordlen) - && ++which > state) { - result = ast_strdup(id); + if (!strncasecmp(word, id, wordlen)) { + ast_cli_completion_add(ast_strdup(id)); } ao2_t_ref(object, -1, "toss iterator endpoint ptr before break"); - if (result) { - break; - } } ao2_iterator_destroy(&i); - - return result; } static void dump_str_and_free(int fd, struct ast_str *buf) @@ -211,7 +202,8 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_ if (cmd == CLI_GENERATE) { ast_free(context.output_buffer); - return complete_show_sorcery_object(container, formatter_entry, a->word, a->n); + complete_show_sorcery_object(container, formatter_entry, a->word); + return NULL; } if (is_container) { diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index e63e158c4..3094f248e 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1,8 +1,19 @@ /* - * sip_cli_commands.c + * Asterisk -- An open source telephony toolkit. * - * Created on: Jan 25, 2013 - * Author: mjordan + * Copyright (C) 2013, Digium, Inc. + * + * Matt Jordan <mjordan@digium.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. */ #include "asterisk.h" @@ -561,12 +572,68 @@ static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **b return ast_sip_auths_to_str(&endpoint->outbound_auths, buf); } +/*! + * \internal + * \brief Convert identify_by method to string. + * + * \param method Method value to convert to string + * + * \return String representation. + */ +static const char *sip_endpoint_identifier_type2str(enum ast_sip_endpoint_identifier_type method) +{ + const char *str = "<unknown>"; + + switch (method) { + case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME: + str = "username"; + break; + case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME: + str = "auth_username"; + break; + case AST_SIP_ENDPOINT_IDENTIFY_BY_IP: + str = "ip"; + break; + case AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER: + str = "header"; + break; + } + return str; +} + +/*! + * \internal + * \brief Convert string to an endpoint identifier token. + * + * \param str String to convert + * + * \retval enum ast_sip_endpoint_identifier_type token value on success. + * \retval -1 on failure. + */ +static int sip_endpoint_identifier_str2type(const char *str) +{ + int method; + + if (!strcasecmp(str, "username")) { + method = AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME; + } else if (!strcasecmp(str, "auth_username")) { + method = AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME; + } else if (!strcasecmp(str, "ip")) { + method = AST_SIP_ENDPOINT_IDENTIFY_BY_IP; + } else if (!strcasecmp(str, "header")) { + method = AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER; + } else { + method = -1; + } + return method; +} + static int ident_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; char *idents = ast_strdupa(var->value); char *val; - enum ast_sip_endpoint_identifier_type method; + int method; /* * If there's already something in the vector when we get here, @@ -582,13 +649,8 @@ static int ident_handler(const struct aco_option *opt, struct ast_variable *var, continue; } - if (!strcasecmp(val, "username")) { - method = AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME; - } else if (!strcasecmp(val, "auth_username")) { - method = AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME; - } else if (!strcasecmp(val, "ip")) { - method = AST_SIP_ENDPOINT_IDENTIFY_BY_IP; - } else { + method = sip_endpoint_identifier_str2type(val); + if (method == -1) { ast_log(LOG_ERROR, "Unrecognized identification method %s specified for endpoint %s\n", val, ast_sorcery_object_get_id(endpoint)); AST_VECTOR_RESET(&endpoint->ident_method_order, AST_VECTOR_ELEM_CLEANUP_NOOP); @@ -611,34 +673,41 @@ static int ident_to_str(const void *obj, const intptr_t *args, char **buf) { const struct ast_sip_endpoint *endpoint = obj; int methods; - char *method; - int i; - int j = 0; + int idx; + int buf_used = 0; + int buf_size = MAX_OBJECT_FIELD; methods = AST_VECTOR_SIZE(&endpoint->ident_method_order); if (!methods) { return 0; } - if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) { + *buf = ast_malloc(buf_size); + if (!*buf) { return -1; } - for (i = 0; i < methods; i++) { - switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) { - case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME : - method = "username"; - break; - case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME : - method = "auth_username"; - break; - case AST_SIP_ENDPOINT_IDENTIFY_BY_IP : - method = "ip"; - break; - default: + for (idx = 0; idx < methods; ++idx) { + enum ast_sip_endpoint_identifier_type method; + const char *method_str; + + method = AST_VECTOR_GET(&endpoint->ident_method_order, idx); + method_str = sip_endpoint_identifier_type2str(method); + + /* Should never have an "<unknown>" method string */ + ast_assert(strcmp(method_str, "<unknown>")); + if (!strcmp(method_str, "<unknown>")) { continue; } - j = sprintf(*buf + j, "%s%s", method, i < methods - 1 ? "," : ""); + + buf_used += snprintf(*buf + buf_used, buf_size - buf_used, "%s%s", + method_str, idx < methods - 1 ? "," : ""); + if (buf_size <= buf_used) { + /* Need more room than available, truncating. */ + *(*buf + (buf_size - 1)) = '\0'; + ast_log(LOG_WARNING, "Truncated identify_by string: %s\n", *buf); + break; + } } return 0; @@ -1592,7 +1661,7 @@ static int ami_show_endpoint(struct mansession *s, const struct message *m) return 0; } - astman_send_listack(s, m, "Following are Events for each object associated with the the Endpoint", + astman_send_listack(s, m, "Following are Events for each object associated with the Endpoint", "start"); /* the endpoint detail needs to always come first so apply as such */ @@ -2124,6 +2193,7 @@ static void info_configuration_destroy(struct ast_sip_endpoint_info_configuratio static void media_configuration_destroy(struct ast_sip_endpoint_media_configuration *media) { + ast_rtp_dtls_cfg_free(&media->rtp.dtls_cfg); ast_string_field_free_memory(&media->rtp); ast_string_field_free_memory(media); } diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index b4828d89f..33d4bced2 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -854,7 +854,9 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) case AST_SIP_AUTHENTICATION_CHALLENGE: /* Send the 401 we created for them */ ast_sip_report_auth_challenge_sent(endpoint, rdata, tdata); - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } return PJ_TRUE; case AST_SIP_AUTHENTICATION_SUCCESS: /* See note in endpoint_lookup about not holding an unnecessary write lock */ @@ -867,7 +869,9 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) case AST_SIP_AUTHENTICATION_FAILED: log_failed_request(rdata, "Failed to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } return PJ_TRUE; case AST_SIP_AUTHENTICATION_ERROR: log_failed_request(rdata, "Error to authenticate", 0, 0); @@ -1243,15 +1247,15 @@ int ast_sip_initialize_distributor(void) return -1; } - if (internal_sip_register_service(&distributor_mod)) { + if (ast_sip_register_service(&distributor_mod)) { ast_sip_destroy_distributor(); return -1; } - if (internal_sip_register_service(&endpoint_mod)) { + if (ast_sip_register_service(&endpoint_mod)) { ast_sip_destroy_distributor(); return -1; } - if (internal_sip_register_service(&auth_mod)) { + if (ast_sip_register_service(&auth_mod)) { ast_sip_destroy_distributor(); return -1; } @@ -1282,9 +1286,9 @@ void ast_sip_destroy_distributor(void) ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_sip_unregister_cli_formatter(unid_formatter); - internal_sip_unregister_service(&auth_mod); - internal_sip_unregister_service(&endpoint_mod); - internal_sip_unregister_service(&distributor_mod); + ast_sip_unregister_service(&auth_mod); + ast_sip_unregister_service(&endpoint_mod); + ast_sip_unregister_service(&distributor_mod); ao2_global_obj_release(artificial_auth); ao2_cleanup(artificial_endpoint); diff --git a/res/res_pjsip/pjsip_global_headers.c b/res/res_pjsip/pjsip_global_headers.c index 501f5f523..52075ae5c 100644 --- a/res/res_pjsip/pjsip_global_headers.c +++ b/res/res_pjsip/pjsip_global_headers.c @@ -55,7 +55,7 @@ struct header { static struct header *alloc_header(const char *name, const char *value) { struct header *alloc; - + alloc = ast_calloc_with_stringfields(1, struct header, 32); if (!alloc) { @@ -139,7 +139,7 @@ static int add_header(struct header_list *headers, const char *name, const char } AST_RWLIST_WRLOCK(headers); - if (replace) { + if (replace) { remove_header(headers, name); } if (to_add) { @@ -165,7 +165,7 @@ void ast_sip_initialize_global_headers(void) AST_RWLIST_HEAD_INIT(&request_headers); AST_RWLIST_HEAD_INIT(&response_headers); - internal_sip_register_service(&global_header_mod); + ast_sip_register_service(&global_header_mod); } static void destroy_headers(struct header_list *headers) @@ -183,5 +183,5 @@ void ast_sip_destroy_global_headers(void) destroy_headers(&request_headers); destroy_headers(&response_headers); - internal_sip_unregister_service(&global_header_mod); + ast_sip_unregister_service(&global_header_mod); } diff --git a/res/res_pjsip/pjsip_message_filter.c b/res/res_pjsip/pjsip_message_filter.c index 085d9787e..f948c4449 100644 --- a/res/res_pjsip/pjsip_message_filter.c +++ b/res/res_pjsip/pjsip_message_filter.c @@ -429,15 +429,27 @@ static pj_bool_t on_rx_process_uris(pjsip_rx_data *rdata) return PJ_TRUE; } - while ((contact = - (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, - contact ? contact->next : NULL))) { + + contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr( + rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); + + if (!contact && pjsip_method_creates_dialog(&rdata->msg_info.msg->line.req.method)) { + /* A contact header is required for dialog creating methods */ + static const pj_str_t missing_contact = { "Missing Contact header", 22 }; + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, + &missing_contact, NULL, NULL); + return PJ_TRUE; + } + + while (contact) { if (!contact->star && !is_sip_uri(contact->uri)) { print_uri_debug(URI_TYPE_CONTACT, rdata, (pjsip_hdr *)contact); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL); return PJ_TRUE; } + contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr( + rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next); } return PJ_FALSE; @@ -505,24 +517,24 @@ static pj_bool_t filter_on_rx_message(pjsip_rx_data *rdata) void ast_res_pjsip_cleanup_message_filter(void) { - internal_sip_unregister_service(&filter_module_tsx); - internal_sip_unregister_service(&filter_module_transport); - internal_sip_unregister_supplement(&filter_supplement); - internal_sip_session_unregister_supplement(&filter_session_supplement); + ast_sip_unregister_service(&filter_module_tsx); + ast_sip_unregister_service(&filter_module_transport); + ast_sip_unregister_supplement(&filter_supplement); + ast_sip_session_unregister_supplement(&filter_session_supplement); } int ast_res_pjsip_init_message_filter(void) { - internal_sip_session_register_supplement(&filter_session_supplement); - internal_sip_register_supplement(&filter_supplement); + ast_sip_session_register_supplement(&filter_session_supplement); + ast_sip_register_supplement(&filter_supplement); - if (internal_sip_register_service(&filter_module_transport)) { + if (ast_sip_register_service(&filter_module_transport)) { ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n"); ast_res_pjsip_cleanup_message_filter(); return -1; } - if (internal_sip_register_service(&filter_module_tsx)) { + if (ast_sip_register_service(&filter_module_tsx)) { ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n"); ast_res_pjsip_cleanup_message_filter(); return -1; diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 662166c89..4ae1f31d1 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -41,7 +41,7 @@ static const char *status_map [] = { [UNAVAILABLE] = "Unreachable", [AVAILABLE] = "Reachable", [UNKNOWN] = "Unknown", - [CREATED] = "Created", + [CREATED] = "NonQualified", [REMOVED] = "Removed", }; @@ -49,7 +49,7 @@ static const char *short_status_map [] = { [UNAVAILABLE] = "Unavail", [AVAILABLE] = "Avail", [UNKNOWN] = "Unknown", - [CREATED] = "Created", + [CREATED] = "NonQual", [REMOVED] = "Removed", }; @@ -205,24 +205,12 @@ static void update_contact_status(const struct ast_sip_contact *contact, return; } - if (is_contact_refresh - && status->status == CREATED) { - /* - * The contact status hasn't been updated since creation - * and we don't want to re-send a created status. - */ - if (contact->qualify_frequency - || status->rtt_start.tv_sec > 0) { - /* Ignore, the status will change soon. */ - return; - } - - /* - * Convert to a regular contact status update - * because the status may never change. - */ - is_contact_refresh = 0; - value = UNKNOWN; + /* + * If the current status is CREATED, and it's a refresh or the given value is + * also CREATED then there is nothing to update as nothing needs to change. + */ + if (status->status == CREATED && (is_contact_refresh || status->status == value)) { + return; } update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, @@ -595,7 +583,7 @@ static void qualify_and_schedule(struct ast_sip_contact *contact) schedule_qualify(contact, contact->qualify_frequency * 1000); } else { - update_contact_status(contact, UNKNOWN, 0); + update_contact_status(contact, CREATED, 0); } } @@ -941,6 +929,91 @@ static int ami_contact_cb(void *obj, void *arg, int flags) return 0; } +static struct ao2_container *get_all_contacts(void) +{ + struct ao2_container *contacts; + + contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", + AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + + return contacts; +} + +static int sip_contact_to_ami(const struct ast_sip_contact *contact, + struct ast_str **buf) +{ + return ast_sip_sorcery_object_to_ami(contact, buf); +} + +static int format_ami_contactlist_handler(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + struct ast_sip_ami *ami = arg; + struct ast_str *buf; + struct ast_sip_contact_status *status; + + buf = ast_sip_create_ami_event("ContactList", ami); + + if (!buf) { + return CMP_STOP; + } + + if (sip_contact_to_ami(contact, &buf)) { + ast_free(buf); + return CMP_STOP; + } + + /* Add extra info */ + status = ast_sorcery_retrieve_by_id( + ast_sip_get_sorcery(), CONTACT_STATUS, + ast_sorcery_object_get_id(contact)); + ast_str_append(&buf, 0, "Status: %s\r\n", + ast_sip_get_contact_status_label(status ? status->status : UNKNOWN)); + if (!status || status->status == UNKNOWN) { + ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n"); + } else { + ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt); + } + + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + + ami->count++; + + ast_free(buf); + + return 0; +} + +static int ami_show_contacts(struct mansession *s, const struct message *m) +{ + struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), }; + struct ao2_container *contacts; + + contacts = get_all_contacts(); + if (!contacts) { + astman_send_error(s, m, "Could not get Contacts\n"); + return 0; + } + + if (!ao2_container_count(contacts)) { + astman_send_error(s, m, "No Contacts found\n"); + ao2_ref(contacts, -1); + return 0; + } + + astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events", + "start"); + + ao2_callback(contacts, OBJ_NODATA, format_ami_contactlist_handler, &ami); + + astman_send_list_complete_start(s, m, "ContactListComplete", ami.count); + astman_send_list_complete_end(s); + + ao2_ref(contacts, -1); + + return 0; +} + static int ami_sip_qualify(struct mansession *s, const struct message *m) { const char *endpoint_name = astman_get_header(m, "Endpoint"); @@ -1127,7 +1200,7 @@ static void qualify_and_schedule_contact(struct ast_sip_contact *contact) if (contact->qualify_frequency) { schedule_qualify(contact, initial_interval); } else { - update_contact_status(contact, UNKNOWN, 0); + update_contact_status(contact, CREATED, 0); } } @@ -1147,7 +1220,24 @@ static int qualify_and_schedule_cb_with_aor(void *obj, void *arg, int flags) static int qualify_and_schedule_cb_without_aor(void *obj, void *arg, int flags) { - qualify_and_schedule_contact((struct ast_sip_contact *) obj); + /* + * These are really dynamic contacts. We need to retrieve the aor associated + * with the contact since it's possible some of the aor's fields were updated + * since last load. + */ + struct ast_sip_contact *contact = obj; + struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(contact->aor); + + if (aor) { + qualify_and_schedule_cb_with_aor(obj, aor, flags); + ao2_ref(aor, -1); + } else { + ast_log(LOG_WARNING, "Unable to locate AOR for contact '%s'. Keeping old " + "associated settings: frequency=%d, timeout=%f, authenticate=%s\n", + contact->uri, contact->qualify_frequency, contact->qualify_timeout, + contact->authenticate_qualify ? "yes" : "no"); + qualify_and_schedule_contact(contact); + } return 0; } @@ -1175,32 +1265,21 @@ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) return 0; } -/*! - * \internal - * \brief Unschedule all existing contacts - */ -static int unschedule_all_cb(void *obj, void *arg, int flags) -{ - struct sched_data *data = obj; - - AST_SCHED_DEL_UNREF(sched, data->id, ao2_ref(data, -1)); - - return CMP_MATCH; -} - static void qualify_and_schedule_all(void) { - struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", ""); struct ao2_container *aors; struct ao2_container *contacts; - if (!var) { - return; - } - aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), - "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); + /* + * It's possible that the AOR had some of it's fields updated prior to a + * reload. For instance qualifying could have been turned on or off by + * setting the qualify_frequency. Due to this we have to iterate through + * all contacts (static and dynamic), and not just ones where the frequency + * is greater than zero, updating any contact fields with the AOR's values. + */ - ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); + aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "aor", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); if (aors) { ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); @@ -1208,14 +1287,11 @@ static void qualify_and_schedule_all(void) } contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), - "contact", AST_RETRIEVE_FLAG_MULTIPLE, var); + "contact", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); if (contacts) { ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_without_aor, NULL); ao2_ref(contacts, -1); } - - ast_variables_destroy(var); - } int ast_sip_format_contact_ami(void *obj, void *arg, int flags) @@ -1268,7 +1344,7 @@ int ast_sip_format_contact_ami(void *obj, void *arg, int flags) astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); ami->count++; - + ast_free(buf); ao2_cleanup(status); return 0; @@ -1486,8 +1562,9 @@ int ast_res_pjsip_init_options_handling(int reload) return -1; } - internal_sip_register_endpoint_formatter(&contact_status_formatter); + ast_sip_register_endpoint_formatter(&contact_status_formatter); ast_manager_register_xml("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify); + ast_manager_register_xml("PJSIPShowContacts", EVENT_FLAG_SYSTEM, ami_show_contacts); ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options)); update_all_unqualified_endpoints(); @@ -1500,7 +1577,8 @@ void ast_res_pjsip_cleanup_options_handling(void) { ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options)); ast_manager_unregister("PJSIPQualify"); - internal_sip_unregister_endpoint_formatter(&contact_status_formatter); + ast_manager_unregister("PJSIPShowContacts"); + ast_sip_unregister_endpoint_formatter(&contact_status_formatter); ast_sorcery_observer_remove(ast_sip_get_sorcery(), "aor", &observer_callbacks_options); pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module); diff --git a/res/res_pjsip/pjsip_session.c b/res/res_pjsip/pjsip_session.c index 4f3e3be55..f3f3a4d87 100644 --- a/res/res_pjsip/pjsip_session.c +++ b/res/res_pjsip/pjsip_session.c @@ -32,7 +32,7 @@ AST_RWLIST_HEAD_STATIC(session_supplements, ast_sip_session_supplement); -void internal_sip_session_register_supplement(struct ast_sip_session_supplement *supplement) +void ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement) { struct ast_sip_session_supplement *iter; int inserted = 0; @@ -56,39 +56,18 @@ void internal_sip_session_register_supplement(struct ast_sip_session_supplement } } -int __ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement, - const char *file, int line, const char *func) -{ - internal_sip_session_register_supplement(supplement); - __ast_module_ref(AST_MODULE_SELF, file, line, func); - - return 0; -} - -int internal_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement) +void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement) { struct ast_sip_session_supplement *iter; - int res = -1; SCOPED_LOCK(lock, &session_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&session_supplements, iter, next) { if (supplement == iter) { AST_RWLIST_REMOVE_CURRENT(next); - res = 0; break; } } AST_RWLIST_TRAVERSE_SAFE_END; - - return res; -} - -void __ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement, - const char *file, int line, const char *func) -{ - if (!internal_sip_session_unregister_supplement(supplement)) { - __ast_module_unref(AST_MODULE_SELF, file, line, func); - } } static struct ast_sip_session_supplement *supplement_dup(const struct ast_sip_session_supplement *src) @@ -120,4 +99,3 @@ int ast_sip_session_add_supplements(struct ast_sip_session *session) return 0; } - diff --git a/res/res_pjsip/pjsip_transport_events.c b/res/res_pjsip/pjsip_transport_events.c index 0f57303ba..c701b8411 100644 --- a/res/res_pjsip/pjsip_transport_events.c +++ b/res/res_pjsip/pjsip_transport_events.c @@ -135,7 +135,7 @@ static void transport_state_callback(pjsip_transport *transport, break; } monitored->transport = transport; - if (AST_VECTOR_INIT(&monitored->monitors, 2)) { + if (AST_VECTOR_INIT(&monitored->monitors, 5)) { ao2_ref(monitored, -1); break; } @@ -166,6 +166,8 @@ static void transport_state_callback(pjsip_transport *transport, struct transport_monitor_notifier *notifier; notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); + ast_debug(3, "running callback %p(%p) for transport %s\n", + notifier->cb, notifier->data, transport->obj_name); notifier->cb(notifier->data); } ao2_ref(monitored, -1); @@ -195,43 +197,66 @@ static void transport_state_callback(pjsip_transport *transport, } } -static int transport_monitor_unregister_all(void *obj, void *arg, int flags) +struct callback_data { + ast_transport_monitor_shutdown_cb cb; + void *data; + ast_transport_monitor_data_matcher matches; +}; + +static int transport_monitor_unregister_cb(void *obj, void *arg, int flags) { struct transport_monitor *monitored = obj; - ast_transport_monitor_shutdown_cb cb = arg; + struct callback_data *cb_data = arg; int idx; for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { struct transport_monitor_notifier *notifier; notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); - if (notifier->cb == cb) { + if (notifier->cb == cb_data->cb && (!cb_data->data + || cb_data->matches(cb_data->data, notifier->data))) { ao2_cleanup(notifier->data); AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx); - break; + ast_debug(3, "Unregistered monitor %p(%p) from transport %s\n", + notifier->cb, notifier->data, monitored->transport->obj_name); } } return 0; } -void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb) +static int ptr_matcher(void *a, void *b) +{ + return a == b; +} + +void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, + void *data, ast_transport_monitor_data_matcher matches) { struct ao2_container *transports; + struct callback_data cb_data = { + .cb = cb, + .data = data, + .matches = matches ?: ptr_matcher, + }; + + ast_assert(cb != NULL); transports = ao2_global_obj_ref(active_transports); if (!transports) { return; } - ao2_callback(transports, OBJ_MULTIPLE | OBJ_NODATA, transport_monitor_unregister_all, - cb); + ao2_callback(transports, OBJ_MULTIPLE | OBJ_NODATA, transport_monitor_unregister_cb, &cb_data); ao2_ref(transports, -1); } -void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb) +void ast_sip_transport_monitor_unregister(pjsip_transport *transport, + ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches) { struct ao2_container *transports; struct transport_monitor *monitored; + ast_assert(transport != NULL && cb != NULL); + transports = ao2_global_obj_ref(active_transports); if (!transports) { return; @@ -240,18 +265,13 @@ void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transp ao2_lock(transports); monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (monitored) { - int idx; + struct callback_data cb_data = { + .cb = cb, + .data = data, + .matches = matches ?: ptr_matcher, + }; - for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { - struct transport_monitor_notifier *notifier; - - notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); - if (notifier->cb == cb) { - ao2_cleanup(notifier->data); - AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx); - break; - } - } + transport_monitor_unregister_cb(monitored, &cb_data, 0); ao2_ref(monitored, -1); } ao2_unlock(transports); @@ -265,6 +285,8 @@ enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transpor struct transport_monitor *monitored; enum ast_transport_monitor_reg res = AST_TRANSPORT_MONITOR_REG_NOT_FOUND; + ast_assert(transport != NULL && cb != NULL); + transports = ao2_global_obj_ref(active_transports); if (!transports) { return res; @@ -273,31 +295,22 @@ enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transpor ao2_lock(transports); monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (monitored) { - int idx; struct transport_monitor_notifier new_monitor; - /* Check if the callback monitor already exists */ - for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) { - struct transport_monitor_notifier *notifier; - - notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); - if (notifier->cb == cb) { - /* The monitor is already in the vector replace with new ao2_data. */ - ao2_replace(notifier->data, ao2_data); - res = AST_TRANSPORT_MONITOR_REG_REPLACED; - goto register_done; - } - } - /* Add new monitor to vector */ new_monitor.cb = cb; new_monitor.data = ao2_bump(ao2_data); if (AST_VECTOR_APPEND(&monitored->monitors, new_monitor)) { ao2_cleanup(ao2_data); res = AST_TRANSPORT_MONITOR_REG_FAILED; + ast_debug(3, "Register monitor %p(%p) to transport %s FAILED\n", + cb, ao2_data, transport->obj_name); + } else { + res = AST_TRANSPORT_MONITOR_REG_SUCCESS; + ast_debug(3, "Registered monitor %p(%p) to transport %s\n", + cb, ao2_data, transport->obj_name); } -register_done: ao2_ref(monitored, -1); } ao2_unlock(transports); diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip/pjsip_transport_management.c index eb92eb7a5..efda37d7c 100644 --- a/res/res_pjsip_transport_management.c +++ b/res/res_pjsip/pjsip_transport_management.c @@ -16,12 +16,6 @@ * at the top of the source tree. */ -/*** MODULEINFO - <depend>pjproject</depend> - <depend>res_pjsip</depend> - <support_level>core</support_level> - ***/ - #include "asterisk.h" #include <signal.h> @@ -32,6 +26,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/module.h" #include "asterisk/astobj2.h" +#include "include/res_pjsip_private.h" /*! \brief Number of buckets for monitored transports */ #define TRANSPORTS_BUCKETS 127 @@ -319,12 +314,10 @@ static pjsip_module idle_monitor_module = { .on_rx_request = idle_monitor_on_rx_request, }; -static int load_module(void) +int ast_sip_initialize_transport_management(void) { struct ao2_container *transports; - CHECK_PJSIP_MODULE_LOADED(); - transports = ao2_container_alloc(TRANSPORTS_BUCKETS, monitored_transport_hash_fn, monitored_transport_cmp_fn); if (!transports) { @@ -356,11 +349,10 @@ static int load_module(void) ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &keepalive_global_observer); ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); - ast_module_shutdown_ref(ast_module_info->self); return AST_MODULE_LOAD_SUCCESS; } -static int unload_module(void) +void ast_sip_destroy_transport_management(void) { if (keepalive_interval) { keepalive_interval = 0; @@ -381,20 +373,4 @@ static int unload_module(void) sched = NULL; ao2_global_obj_release(monitored_transports); - - return 0; -} - -static int reload_module(void) -{ - ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); - return 0; } - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Reliable Transport Management", - .support_level = AST_MODULE_SUPPORT_CORE, - .load = load_module, - .reload = reload_module, - .unload = unload_module, - .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4, -); diff --git a/res/res_pjsip/security_events.c b/res/res_pjsip/security_events.c index ea3810bfd..b31445b0c 100644 --- a/res/res_pjsip/security_events.c +++ b/res/res_pjsip/security_events.c @@ -186,7 +186,7 @@ void ast_sip_report_auth_success(struct ast_sip_endpoint *endpoint, pjsip_rx_dat .transport = transport, }, .common.session_id = call_id, - .using_password = auth ? (uint32_t *)1 : (uint32_t *)0, + .using_password = auth ? 1 : 0, }; security_event_populate(rdata, call_id, sizeof(call_id), &local, &remote); diff --git a/res/res_pjsip_acl.c b/res/res_pjsip_acl.c index 5c10e5779..8caf70344 100644 --- a/res/res_pjsip_acl.c +++ b/res/res_pjsip_acl.c @@ -282,8 +282,6 @@ static void *acl_alloc(const char *name) static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - ast_sorcery_apply_config(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE); ast_sorcery_apply_default(ast_sip_get_sorcery(), SIP_SORCERY_ACL_TYPE, "config", "pjsip.conf,criteria=type=acl"); @@ -321,4 +319,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP ACL Resource", .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_authenticator_digest.c b/res/res_pjsip_authenticator_digest.c index ef57e3754..518ef73bb 100644 --- a/res/res_pjsip_authenticator_digest.c +++ b/res/res_pjsip_authenticator_digest.c @@ -524,8 +524,6 @@ static int reload_module(void) static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - if (build_entity_id()) { return AST_MODULE_LOAD_DECLINE; } @@ -554,4 +552,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP authentication .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c index 64191a750..f15a66c05 100644 --- a/res/res_pjsip_caller_id.c +++ b/res/res_pjsip_caller_id.c @@ -19,7 +19,6 @@ /*** MODULEINFO <depend>pjproject</depend> <depend>res_pjsip</depend> - <depend>res_pjsip_session</depend> <support_level>core</support_level> ***/ @@ -747,8 +746,6 @@ static struct ast_sip_session_supplement caller_id_supplement = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - ast_sip_session_register_supplement(&caller_id_supplement); return AST_MODULE_LOAD_SUCCESS; } @@ -764,4 +761,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Caller ID Suppo .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c index 7c386e3b2..a13995fac 100644 --- a/res/res_pjsip_dialog_info_body_generator.c +++ b/res/res_pjsip_dialog_info_body_generator.c @@ -20,7 +20,6 @@ <depend>pjproject</depend> <depend>res_pjsip</depend> <depend>res_pjsip_pubsub</depend> - <depend>res_pjsip_exten_state</depend> <support_level>core</support_level> ***/ @@ -199,8 +198,6 @@ static struct ast_sip_pubsub_body_generator dialog_info_body_generator = { static int load_module(void) { - CHECK_PJSIP_PUBSUB_MODULE_LOADED(); - if (ast_sip_pubsub_register_body_generator(&dialog_info_body_generator)) { return AST_MODULE_LOAD_DECLINE; } @@ -219,4 +216,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjsip,res_pjsip_pubsub", ); diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c index efb5489f8..e82140b72 100644 --- a/res/res_pjsip_diversion.c +++ b/res/res_pjsip_diversion.c @@ -19,7 +19,6 @@ /*** MODULEINFO <depend>pjproject</depend> <depend>res_pjsip</depend> - <depend>res_pjsip_session</depend> <support_level>core</support_level> ***/ @@ -412,8 +411,6 @@ static struct ast_sip_session_supplement diversion_supplement = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - ast_sip_session_register_supplement(&diversion_supplement); return AST_MODULE_LOAD_SUCCESS; } @@ -429,4 +426,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Add Diversion H .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_dlg_options.c b/res/res_pjsip_dlg_options.c index e2ed29a2c..93e3f228e 100644 --- a/res/res_pjsip_dlg_options.c +++ b/res/res_pjsip_dlg_options.c @@ -19,7 +19,6 @@ /*** MODULEINFO <depend>pjproject</depend> <depend>res_pjsip</depend> - <depend>res_pjsip_session</depend> <support_level>core</support_level> ***/ @@ -84,11 +83,8 @@ static struct ast_sip_session_supplement dlg_options_supplement = { static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); + ast_sip_session_register_supplement(&dlg_options_supplement); - if (ast_sip_session_register_supplement(&dlg_options_supplement)) { - return AST_MODULE_LOAD_DECLINE; - } return AST_MODULE_LOAD_SUCCESS; } @@ -99,7 +95,9 @@ static int unload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP OPTIONS in dialog handler", + .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_dtmf_info.c b/res/res_pjsip_dtmf_info.c index e534f3e27..983498def 100644 --- a/res/res_pjsip_dtmf_info.c +++ b/res/res_pjsip_dtmf_info.c @@ -19,7 +19,6 @@ /*** MODULEINFO <depend>pjproject</depend> <depend>res_pjsip</depend> - <depend>res_pjsip_session</depend> <support_level>core</support_level> ***/ @@ -161,8 +160,6 @@ static struct ast_sip_session_supplement dtmf_info_supplement = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - ast_sip_session_register_supplement(&dtmf_info_supplement); return AST_MODULE_LOAD_SUCCESS; } @@ -178,4 +175,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP DTMF INFO Suppo .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_empty_info.c b/res/res_pjsip_empty_info.c index 774f9de7e..74e5729a5 100644 --- a/res/res_pjsip_empty_info.c +++ b/res/res_pjsip_empty_info.c @@ -19,7 +19,6 @@ /*** MODULEINFO <depend>pjproject</depend> <depend>res_pjsip</depend> - <depend>res_pjsip_session</depend> <support_level>core</support_level> ***/ @@ -67,8 +66,6 @@ static struct ast_sip_session_supplement empty_info_supplement = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - ast_sip_session_register_supplement(&empty_info_supplement); return AST_MODULE_LOAD_SUCCESS; } @@ -84,4 +81,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Empty INFO Supp .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_endpoint_identifier_anonymous.c b/res/res_pjsip_endpoint_identifier_anonymous.c index b47aefa94..63fc40562 100644 --- a/res/res_pjsip_endpoint_identifier_anonymous.c +++ b/res/res_pjsip_endpoint_identifier_anonymous.c @@ -47,10 +47,11 @@ static int find_transport_state_in_use(void *obj, void *arg, int flags) struct ast_sip_transport_state *transport_state = obj; pjsip_rx_data *rdata = arg; - if (transport_state && ((transport_state->transport == rdata->tp_info.transport) || - (transport_state->factory && !pj_strcmp(&transport_state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) && - transport_state->factory->addr_name.port == rdata->tp_info.transport->local_name.port))) { - return CMP_MATCH | CMP_STOP; + if (transport_state->transport == rdata->tp_info.transport + || (transport_state->factory + && !pj_strcmp(&transport_state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) + && transport_state->factory->addr_name.port == rdata->tp_info.transport->local_name.port)) { + return CMP_MATCH; } return 0; @@ -62,28 +63,33 @@ static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata) { char domain_name[DOMAIN_NAME_LEN + 1]; struct ast_sip_endpoint *endpoint; - RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); - RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup); - RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup); - RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); if (get_endpoint_details(rdata, domain_name, sizeof(domain_name))) { return NULL; } if (!ast_sip_get_disable_multi_domain()) { + struct ast_sip_domain_alias *alias; + struct ao2_container *transport_states; + struct ast_sip_transport_state *transport_state = NULL; + struct ast_sip_transport *transport = NULL; char id[sizeof("anonymous@") + DOMAIN_NAME_LEN]; /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "anonymous@%s", domain_name); - if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); + if (endpoint) { goto done; } /* See if an alias exists for the domain provided */ - if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { + alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", + domain_name); + if (alias) { snprintf(id, sizeof(id), "anonymous@%s", alias->domain); - if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { + ao2_ref(alias, -1); + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); + if (endpoint) { goto done; } } @@ -94,9 +100,13 @@ static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata) && (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id)) && !ast_strlen_zero(transport->domain)) { snprintf(id, sizeof(id), "anonymous@%s", transport->domain); - if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { - goto done; - } + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); + } + ao2_cleanup(transport); + ao2_cleanup(transport_state); + ao2_cleanup(transport_states); + if (endpoint) { + goto done; } } @@ -116,8 +126,6 @@ static struct ast_sip_endpoint_identifier anonymous_identifier = { static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - ast_sip_register_endpoint_identifier_with_name(&anonymous_identifier, "anonymous"); return AST_MODULE_LOAD_SUCCESS; } @@ -132,4 +140,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "PJSIP Anonymous endpoint .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index 8b92cef27..555d65331 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -43,41 +43,50 @@ <para>This module provides alternatives to matching inbound requests to a configured endpoint. At least one of the matching mechanisms must be provided, or the object configuration will be invalid.</para> - <para>If multiple criteria are provided, an inbound request will - be matched if it matches <emphasis>any</emphasis> of the criteria.</para> <para>The matching mechanisms are provided by the following configuration options:</para> <enumlist> <enum name="match"><para>Match by source IP address.</para></enum> <enum name="match_header"><para>Match by SIP header.</para></enum> </enumlist> + <note><para>If multiple matching criteria are provided then an inbound + request will be matched to the endpoint if it matches + <emphasis>any</emphasis> of the criteria.</para></note> </description> <configOption name="endpoint"> - <synopsis>Name of Endpoint</synopsis> + <synopsis>Name of endpoint identified</synopsis> </configOption> <configOption name="match"> <synopsis>IP addresses or networks to match against.</synopsis> - <description><para> - The value is a comma-delimited list of IP addresses. IP addresses may - have a subnet mask appended. The subnet mask may be written in either - CIDR or dot-decimal notation. Separate the IP address and subnet - mask with a slash ('/'). - </para></description> + <description> + <para>The value is a comma-delimited list of IP addresses or + hostnames. IP addresses may have a subnet mask appended. The + subnet mask may be written in either CIDR or dotted-decimal + notation. Separate the IP address and subnet mask with a slash + ('/'). + </para> + </description> </configOption> <configOption name="srv_lookups" default="yes"> <synopsis>Perform SRV lookups for provided hostnames.</synopsis> - <description><para>When enabled, <replaceable>srv_lookups</replaceable> will - perform SRV lookups for _sip._udp, _sip._tcp, and _sips._tcp of the given - hostnames to determine additional addresses that traffic may originate from. - </para></description> + <description> + <para>When enabled, <replaceable>srv_lookups</replaceable> will + perform SRV lookups for _sip._udp, _sip._tcp, and _sips._tcp of + the given hostnames to determine additional addresses that traffic + may originate from. + </para> + </description> </configOption> <configOption name="match_header"> <synopsis>Header/value pair to match against.</synopsis> - <description><para>A SIP header who value is used to match against. SIP - requests containing the header, along with the specified value, will be - mapped to the specified endpoint. The header must be specified with a - <literal>:</literal>, as in <literal>match_header = SIPHeader: value</literal>. - </para></description> + <description> + <para>A SIP header whose value is used to match against. SIP + requests containing the header, along with the specified value, + will be mapped to the specified endpoint. The header must be + specified with a <literal>:</literal>, as in + <literal>match_header = SIPHeader: value</literal>. + </para> + </description> </configOption> <configOption name="type"> <synopsis>Must be of type 'identify'.</synopsis> @@ -105,7 +114,7 @@ struct ip_identify_match { struct ast_ha *matches; /*! \brief Perform SRV resolution of hostnames */ unsigned int srv_lookups; - /*! \brief Hosts to be resolved after applying configuration */ + /*! \brief Hosts to be resolved when applying configuration */ struct ao2_container *hosts; }; @@ -150,8 +159,8 @@ static int header_identify_match_check(void *obj, void *arg, int flags) c_header = ast_strdupa(identify->match_header); c_value = strchr(c_header, ':'); if (!c_value) { - ast_log(LOG_WARNING, "Identify '%s' has invalid header_match: No ':' separator found!\n", - ast_sorcery_object_get_id(identify)); + /* This should not be possible. The object cannot be created if so. */ + ast_assert(0); return 0; } *c_value = '\0'; @@ -161,21 +170,23 @@ static int header_identify_match_check(void *obj, void *arg, int flags) pj_header_name = pj_str(c_header); header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &pj_header_name, NULL); if (!header) { - ast_debug(3, "SIP message does not contain header '%s'\n", c_header); + ast_debug(3, "Identify '%s': SIP message does not have header '%s'\n", + ast_sorcery_object_get_id(identify), + c_header); return 0; } pj_header_value = pj_str(c_value); if (pj_strcmp(&pj_header_value, &header->hvalue)) { - ast_debug(3, "SIP message contains header '%s' but value '%.*s' does not match value '%s' for endpoint '%s'\n", + ast_debug(3, "Identify '%s': SIP message has header '%s' but value '%.*s' does not match '%s'\n", + ast_sorcery_object_get_id(identify), c_header, (int) pj_strlen(&header->hvalue), pj_strbuf(&header->hvalue), - c_value, - identify->endpoint_name); + c_value); return 0; } - return CMP_MATCH | CMP_STOP; + return CMP_MATCH; } /*! \brief Comparator function for matching an object by IP address */ @@ -190,7 +201,7 @@ static int ip_identify_match_check(void *obj, void *arg, int flags) ast_debug(3, "Source address %s matches identify '%s'\n", ast_sockaddr_stringify(addr), ast_sorcery_object_get_id(identify)); - return CMP_MATCH | CMP_STOP; + return CMP_MATCH; } else { ast_debug(3, "Source address %s does not match identify '%s'\n", ast_sockaddr_stringify(addr), @@ -199,55 +210,62 @@ static int ip_identify_match_check(void *obj, void *arg, int flags) } } -static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata) +static struct ast_sip_endpoint *common_identify(ao2_callback_fn *identify_match_cb, void *arg) { - struct ast_sockaddr addr = { { 0, } }; RAII_VAR(struct ao2_container *, candidates, NULL, ao2_cleanup); - RAII_VAR(struct ip_identify_match *, match, NULL, ao2_cleanup); + struct ip_identify_match *match; struct ast_sip_endpoint *endpoint; /* If no possibilities exist return early to save some time */ - if (!(candidates = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) || - !ao2_container_count(candidates)) { + candidates = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify", + AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + if (!candidates || !ao2_container_count(candidates)) { ast_debug(3, "No identify sections to match against\n"); return NULL; } - ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID); - ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port); - - match = ao2_callback(candidates, 0, ip_identify_match_check, &addr); + match = ao2_callback(candidates, 0, identify_match_cb, arg); if (!match) { - ast_debug(3, "Identify checks by IP address failed to find match: '%s' did not match any identify section rules\n", - ast_sockaddr_stringify(&addr)); - match = ao2_callback(candidates, 0, header_identify_match_check, rdata); - if (!match) { - return NULL; - } + return NULL; } - endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", match->endpoint_name); - + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", + match->endpoint_name); if (endpoint) { - if (!(endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_IP)) { - ast_debug(3, "Endpoint '%s' found for '%s' but 'ip' method not supported'\n", match->endpoint_name, - ast_sockaddr_stringify(&addr)); - ao2_cleanup(endpoint); - return NULL; - } - ast_debug(3, "Retrieved endpoint %s\n", ast_sorcery_object_get_id(endpoint)); + ast_debug(3, "Identify '%s' SIP message matched to endpoint %s\n", + ast_sorcery_object_get_id(match), match->endpoint_name); } else { - ast_log(LOG_WARNING, "Identify section '%s' points to endpoint '%s' but endpoint could not be looked up\n", - ast_sorcery_object_get_id(match), match->endpoint_name); + ast_log(LOG_WARNING, "Identify '%s' points to endpoint '%s' but endpoint could not be found\n", + ast_sorcery_object_get_id(match), match->endpoint_name); } + ao2_ref(match, -1); return endpoint; } +static struct ast_sip_endpoint *ip_identify(pjsip_rx_data *rdata) +{ + struct ast_sockaddr addr = { { 0, } }; + + ast_sockaddr_parse(&addr, rdata->pkt_info.src_name, PARSE_PORT_FORBID); + ast_sockaddr_set_port(&addr, rdata->pkt_info.src_port); + + return common_identify(ip_identify_match_check, &addr); +} + static struct ast_sip_endpoint_identifier ip_identifier = { .identify_endpoint = ip_identify, }; +static struct ast_sip_endpoint *header_identify(pjsip_rx_data *rdata) +{ + return common_identify(header_identify_match_check, rdata); +} + +static struct ast_sip_endpoint_identifier header_identifier = { + .identify_endpoint = header_identify, +}; + /*! \brief Helper function which performs a host lookup and adds result to identify match */ static int ip_identify_match_host_lookup(struct ip_identify_match *identify, const char *host) { @@ -261,7 +279,7 @@ static int ip_identify_match_host_lookup(struct ip_identify_match *identify, con } for (i = 0; i < num_addrs; ++i) { - /* Check if the address is already in the list, if so don't bother adding it again */ + /* Check if the address is already in the list, if so don't add it again */ if (identify->matches && (ast_apply_ha(identify->matches, &addrs[i]) != AST_SENSE_ALLOW)) { continue; } @@ -283,14 +301,13 @@ static int ip_identify_match_host_lookup(struct ip_identify_match *identify, con } /*! \brief Helper function which performs an SRV lookup and then resolves the hostname */ -static int ip_identify_match_srv_lookup(struct ip_identify_match *identify, const char *prefix, const char *host) +static int ip_identify_match_srv_lookup(struct ip_identify_match *identify, const char *prefix, const char *host, int results) { char service[NI_MAXHOST]; struct srv_context *context = NULL; int srv_ret; const char *srvhost; unsigned short srvport; - int results = 0; snprintf(service, sizeof(service), "%s.%s", prefix, host); @@ -372,10 +389,33 @@ static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj) char *current_string; struct ao2_iterator i; + /* Validate the identify object configuration */ + if (ast_strlen_zero(identify->endpoint_name)) { + ast_log(LOG_ERROR, "Identify '%s' missing required endpoint name.\n", + ast_sorcery_object_get_id(identify)); + return -1; + } + if (ast_strlen_zero(identify->match_header) /* No header to match */ + /* and no static IP addresses with a mask */ + && !identify->matches + /* and no addresses to resolve */ + && (!identify->hosts || !ao2_container_count(identify->hosts))) { + ast_log(LOG_ERROR, "Identify '%s' is not configured to match anything.\n", + ast_sorcery_object_get_id(identify)); + return -1; + } + if (!ast_strlen_zero(identify->match_header) + && !strchr(identify->match_header, ':')) { + ast_log(LOG_ERROR, "Identify '%s' missing ':' separator in match_header '%s'.\n", + ast_sorcery_object_get_id(identify), identify->match_header); + return -1; + } + if (!identify->hosts) { return 0; } + /* Resolve the match addresses now */ i = ao2_iterator_init(identify->hosts, 0); while ((current_string = ao2_iterator_next(&i))) { struct ast_sockaddr address; @@ -383,26 +423,29 @@ static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj) /* If the provided string is not an IP address perform SRV resolution on it */ if (identify->srv_lookups && !ast_sockaddr_parse(&address, current_string, 0)) { - results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string); + results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string, + results); if (results != -1) { - results += ip_identify_match_srv_lookup(identify, "_sip._tcp", current_string); + results = ip_identify_match_srv_lookup(identify, "_sip._tcp", + current_string, results); } if (results != -1) { - results += ip_identify_match_srv_lookup(identify, "_sips._tcp", current_string); + results = ip_identify_match_srv_lookup(identify, "_sips._tcp", + current_string, results); } } - /* If SRV falls fall back to a normal lookup on the host itself */ + /* If SRV fails fall back to a normal lookup on the host itself */ if (!results) { results = ip_identify_match_host_lookup(identify, current_string); } if (results == 0) { - ast_log(LOG_ERROR, "Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address\n", - current_string, ast_sorcery_object_get_id(obj)); + ast_log(LOG_WARNING, "Identify '%s' provided address '%s' did not resolve to any address\n", + ast_sorcery_object_get_id(identify), current_string); } else if (results == -1) { - ast_log(LOG_ERROR, "An error occurred when adding resolution results of '%s' on '%s'\n", - current_string, ast_sorcery_object_get_id(obj)); + ast_log(LOG_ERROR, "Identify '%s' failed when adding resolution results of '%s'\n", + ast_sorcery_object_get_id(identify), current_string); ao2_ref(current_string, -1); ao2_iterator_destroy(&i); return -1; @@ -457,47 +500,54 @@ static int sip_identify_to_ami(const struct ip_identify_match *identify, return ast_sip_sorcery_object_to_ami(identify, buf); } -static int find_identify_by_endpoint(void *obj, void *arg, int flags) +static int send_identify_ami_event(void *obj, void *arg, void *data, int flags) { struct ip_identify_match *identify = obj; const char *endpoint_name = arg; + struct ast_sip_ami *ami = data; + struct ast_str *buf; + + /* Build AMI event */ + buf = ast_sip_create_ami_event("IdentifyDetail", ami); + if (!buf) { + return CMP_STOP; + } + if (sip_identify_to_ami(identify, &buf)) { + ast_free(buf); + return CMP_STOP; + } + ast_str_append(&buf, 0, "EndpointName: %s\r\n", endpoint_name); + + /* Send AMI event */ + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + ++ami->count; - return strcmp(identify->endpoint_name, endpoint_name) ? 0 : CMP_MATCH; + ast_free(buf); + return 0; } static int format_ami_endpoint_identify(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami) { - RAII_VAR(struct ao2_container *, identifies, NULL, ao2_cleanup); - RAII_VAR(struct ip_identify_match *, identify, NULL, ao2_cleanup); - RAII_VAR(struct ast_str *, buf, NULL, ast_free); + struct ao2_container *identifies; + struct ast_variable fields = { + .name = "endpoint", + .value = ast_sorcery_object_get_id(endpoint), + }; identifies = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "identify", - AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + AST_RETRIEVE_FLAG_MULTIPLE, &fields); if (!identifies) { return -1; } - identify = ao2_callback(identifies, 0, find_identify_by_endpoint, - (void *) ast_sorcery_object_get_id(endpoint)); - if (!identify) { - return 1; - } - - if (!(buf = ast_sip_create_ami_event("IdentifyDetail", ami))) { - return -1; - } - - if (sip_identify_to_ami(identify, &buf)) { - return -1; - } - - ast_str_append(&buf, 0, "EndpointName: %s\r\n", - ast_sorcery_object_get_id(endpoint)); - - astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); - ami->count++; + /* Build and send any found identify object's AMI IdentifyDetail event. */ + ao2_callback_data(identifies, OBJ_MULTIPLE | OBJ_NODATA, + send_identify_ami_event, + (void *) ast_sorcery_object_get_id(endpoint), + ami); + ao2_ref(identifies, -1); return 0; } @@ -667,8 +717,6 @@ static struct ast_sip_cli_formatter_entry *cli_formatter; static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_endpoint_identifier_ip"); ast_sorcery_apply_default(ast_sip_get_sorcery(), "identify", "config", "pjsip.conf,criteria=type=identify"); @@ -684,6 +732,7 @@ static int load_module(void) ast_sorcery_load_object(ast_sip_get_sorcery(), "identify"); ast_sip_register_endpoint_identifier_with_name(&ip_identifier, "ip"); + ast_sip_register_endpoint_identifier_with_name(&header_identifier, "header"); ast_sip_register_endpoint_formatter(&endpoint_identify_formatter); cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL); @@ -728,4 +777,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP IP endpoint ide .reload = reload_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_endpoint_identifier_user.c b/res/res_pjsip_endpoint_identifier_user.c index ff97a62e4..46e82db17 100644 --- a/res/res_pjsip_endpoint_identifier_user.c +++ b/res/res_pjsip_endpoint_identifier_user.c @@ -65,10 +65,11 @@ static int find_transport_state_in_use(void *obj, void *arg, int flags) struct ast_sip_transport_state *transport_state = obj; pjsip_rx_data *rdata = arg; - if (transport_state && ((transport_state->transport == rdata->tp_info.transport) || - (transport_state->factory && !pj_strcmp(&transport_state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) && - transport_state->factory->addr_name.port == rdata->tp_info.transport->local_name.port))) { - return CMP_MATCH | CMP_STOP; + if (transport_state->transport == rdata->tp_info.transport + || (transport_state->factory + && !pj_strcmp(&transport_state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host) + && transport_state->factory->addr_name.port == rdata->tp_info.transport->local_name.port)) { + return CMP_MATCH; } return 0; @@ -81,36 +82,46 @@ static struct ast_sip_endpoint *find_endpoint(pjsip_rx_data *rdata, char *endpoi char *domain_name) { struct ast_sip_endpoint *endpoint; - RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); - RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup); - RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup); - RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); if (!ast_sip_get_disable_multi_domain()) { + struct ast_sip_domain_alias *alias; + struct ao2_container *transport_states; + struct ast_sip_transport_state *transport_state = NULL; + struct ast_sip_transport *transport = NULL; char id[DOMAIN_NAME_LEN + USERNAME_LEN + sizeof("@")]; /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "%s@%s", endpoint_name, domain_name); - if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); + if (endpoint) { return endpoint; } /* See if an alias exists for the domain provided */ - if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { + alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", + domain_name); + if (alias) { snprintf(id, sizeof(id), "%s@%s", endpoint_name, alias->domain); - if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { + ao2_ref(alias, -1); + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); + if (endpoint) { return endpoint; } } + /* See if the transport this came in on has a provided domain */ if ((transport_states = ast_sip_get_transport_states()) && (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata)) && (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id)) && !ast_strlen_zero(transport->domain)) { - snprintf(id, sizeof(id), "anonymous@%s", transport->domain); - if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { - return endpoint; - } + snprintf(id, sizeof(id), "%s@%s", endpoint_name, transport->domain); + endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); + } + ao2_cleanup(transport); + ao2_cleanup(transport_state); + ao2_cleanup(transport_states); + if (endpoint) { + return endpoint; } } @@ -195,8 +206,6 @@ static struct ast_sip_endpoint_identifier auth_username_identifier = { static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - ast_sip_register_endpoint_identifier_with_name(&username_identifier, "username"); ast_sip_register_endpoint_identifier_with_name(&auth_username_identifier, "auth_username"); return AST_MODULE_LOAD_SUCCESS; @@ -214,4 +223,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP username endpoi .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 3e756134c..47ec8b461 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -959,13 +959,6 @@ static int unload_module(void) static int load_module(void) { - CHECK_PJSIP_PUBSUB_MODULE_LOADED(); - - if (!ast_module_check("res_pjsip_outbound_publish.so")) { - ast_log(LOG_WARNING, "This module requires the 'res_pjsip_outbound_publish.so' module to be loaded\n"); - return AST_MODULE_LOAD_DECLINE; - } - publishers = ao2_container_alloc(PUBLISHER_BUCKETS, exten_state_publisher_hash, exten_state_publisher_cmp); if (!publishers) { @@ -1015,4 +1008,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5, + .requires = "res_pjsip,res_pjsip_pubsub,res_pjsip_outbound_publish", ); diff --git a/res/res_pjsip_header_funcs.c b/res/res_pjsip_header_funcs.c index 648f1c860..6c0f9151d 100644 --- a/res/res_pjsip_header_funcs.c +++ b/res/res_pjsip_header_funcs.c @@ -146,18 +146,11 @@ struct hdr_list_entry { pjsip_hdr *hdr; AST_LIST_ENTRY(hdr_list_entry) nextptr; }; -AST_LIST_HEAD(hdr_list, hdr_list_entry); - -/*! \brief Destructor for hdr_list */ -static void hdr_list_destroy(void *obj) -{ - AST_LIST_HEAD_DESTROY((struct hdr_list *) obj); -} +AST_LIST_HEAD_NOLOCK(hdr_list, hdr_list_entry); /*! \brief Datastore for saving headers */ static const struct ast_datastore_info header_datastore = { .type = "header_datastore", - .destroy = hdr_list_destroy, }; /*! \brief Data structure used for ast_sip_push_task_synchronous */ @@ -215,7 +208,7 @@ static int incoming_request(struct ast_sip_session *session, pjsip_rx_data * rda ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n"); return 0; } - AST_LIST_HEAD_INIT((struct hdr_list *) datastore->data); + AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data); } insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg); @@ -340,7 +333,7 @@ static int add_header(void *obj) ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n"); return -1; } - AST_LIST_HEAD_INIT((struct hdr_list *) datastore->data); + AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data); } ast_debug(1, "Adding header %s with value %s\n", data->header_name, @@ -486,15 +479,15 @@ static int func_read_header(struct ast_channel *chan, const char *function, char header_data.buf = buf; header_data.len = len; - if (stricmp(args.action, "read") == 0) { + if (!strcasecmp(args.action, "read")) { return ast_sip_push_task_synchronous(channel->session->serializer, read_header, &header_data); - } else if (stricmp(args.action, "remove") == 0) { + } else if (!strcasecmp(args.action, "remove")) { return ast_sip_push_task_synchronous(channel->session->serializer, remove_header, &header_data); } else { ast_log(AST_LOG_ERROR, - "Unknown action \'%s\' is not valid, Must be \'read\' or \'remove\'.\n", + "Unknown action '%s' is not valid, must be 'read' or 'remove'.\n", args.action); return -1; } @@ -545,18 +538,18 @@ static int func_write_header(struct ast_channel *chan, const char *cmd, char *da header_data.buf = NULL; header_data.len = 0; - if (stricmp(args.action, "add") == 0) { + if (!strcasecmp(args.action, "add")) { return ast_sip_push_task_synchronous(channel->session->serializer, add_header, &header_data); - } else if (stricmp(args.action, "update") == 0) { + } else if (!strcasecmp(args.action, "update")) { return ast_sip_push_task_synchronous(channel->session->serializer, update_header, &header_data); - } else if (stricmp(args.action, "remove") == 0) { + } else if (!strcasecmp(args.action, "remove")) { return ast_sip_push_task_synchronous(channel->session->serializer, remove_header, &header_data); } else { ast_log(AST_LOG_ERROR, - "Unknown action \'%s\' is not valid, Must be \'add\', \'update\', or \'remove\'.\n", + "Unknown action '%s' is not valid, must be 'add', 'update', or 'remove'.\n", args.action); return -1; } @@ -609,8 +602,6 @@ static struct ast_sip_session_supplement header_funcs_supplement = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - ast_sip_session_register_supplement(&header_funcs_supplement); ast_custom_function_register(&pjsip_header_function); @@ -629,4 +620,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Header Function .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c index ed374d605..ab035a296 100644 --- a/res/res_pjsip_history.c +++ b/res/res_pjsip_history.c @@ -42,6 +42,7 @@ #include "asterisk/netsock2.h" #include "asterisk/vector.h" #include "asterisk/lock.h" +#include "asterisk/res_pjproject.h" #define HISTORY_INITIAL_SIZE 256 @@ -1280,7 +1281,7 @@ static char *pjsip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli } entry = ao2_bump(AST_VECTOR_GET(vec, 0)); if (vec == &vector_history) { - ast_mutex_lock(&history_lock); + ast_mutex_unlock(&history_lock); } } @@ -1364,14 +1365,12 @@ static struct ast_cli_entry cli_pjsip[] = { static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - log_level = ast_logger_register_level("PJSIP_HISTORY"); if (log_level < 0) { ast_log(LOG_WARNING, "Unable to register history log level\n"); } - pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0); + ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0); AST_VECTOR_INIT(&vector_history, HISTORY_INITIAL_SIZE); @@ -1389,7 +1388,7 @@ static int unload_module(void) ast_sip_push_task_synchronous(NULL, clear_history_entries, NULL); AST_VECTOR_FREE(&vector_history); - pj_caching_pool_destroy(&cachingpool); + ast_pjproject_caching_pool_destroy(&cachingpool); if (log_level != -1) { ast_logger_unregister_level("PJSIP_HISTORY"); @@ -1403,4 +1402,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP History", .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_logger.c b/res/res_pjsip_logger.c index d29a6e213..49ad6faec 100644 --- a/res/res_pjsip_logger.c +++ b/res/res_pjsip_logger.c @@ -231,8 +231,6 @@ static const struct ast_sorcery_observer global_observer = { static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - if (ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer)) { ast_log(LOG_WARNING, "Unable to add global observer\n"); return AST_MODULE_LOAD_DECLINE; @@ -262,4 +260,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Packet Logger", .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c index b6e7a64c3..cbaed83fb 100644 --- a/res/res_pjsip_messaging.c +++ b/res/res_pjsip_messaging.c @@ -19,7 +19,6 @@ /*** MODULEINFO <depend>pjproject</depend> <depend>res_pjsip</depend> - <depend>res_pjsip_session</depend> <support_level>core</support_level> ***/ @@ -806,8 +805,6 @@ static pjsip_module messaging_module = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - if (ast_sip_register_service(&messaging_module) != PJ_SUCCESS) { return AST_MODULE_LOAD_DECLINE; } @@ -850,4 +847,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Messaging Suppo .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index 5423038e6..4cd892c05 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -650,11 +650,11 @@ static void send_mwi_notify(struct mwi_subscription *sub) .body_type = AST_SIP_MESSAGE_ACCUMULATOR, .body_data = &counter, }; - const char *resource = ast_sip_subscription_get_resource_name(sub->sip_sub); ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter); if (sub->is_solicited) { + const char *resource = ast_sip_subscription_get_resource_name(sub->sip_sub); struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sub->sip_sub); struct ast_sip_aor *aor = find_aor_for_resource(endpoint, resource); pjsip_dialog *dlg = ast_sip_subscription_get_dialog(sub->sip_sub); @@ -1339,8 +1339,6 @@ static int reload(void) static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - if (ast_sip_register_subscription_handler(&mwi_handler)) { return AST_MODULE_LOAD_DECLINE; } @@ -1397,4 +1395,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP MWI resource", .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5, + .requires = "res_pjsip,res_pjsip_pubsub", ); diff --git a/res/res_pjsip_mwi_body_generator.c b/res/res_pjsip_mwi_body_generator.c index e8279101c..29b2ed027 100644 --- a/res/res_pjsip_mwi_body_generator.c +++ b/res/res_pjsip_mwi_body_generator.c @@ -97,8 +97,6 @@ static struct ast_sip_pubsub_body_generator mwi_generator = { static int load_module(void) { - CHECK_PJSIP_PUBSUB_MODULE_LOADED(); - if (ast_sip_pubsub_register_body_generator(&mwi_generator)) { return AST_MODULE_LOAD_DECLINE; } @@ -116,4 +114,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP MWI resource", .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjsip,res_pjsip_pubsub", ); diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c index e1d56e6af..1d42805d8 100644 --- a/res/res_pjsip_nat.c +++ b/res/res_pjsip_nat.c @@ -357,18 +357,12 @@ static int unload_module(void) static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - if (ast_sip_register_service(&nat_module)) { ast_log(LOG_ERROR, "Could not register NAT module for incoming and outgoing requests\n"); return AST_MODULE_LOAD_DECLINE; } - if (ast_sip_session_register_supplement(&nat_supplement)) { - ast_log(LOG_ERROR, "Could not register NAT session supplement for incoming and outgoing INVITE requests\n"); - unload_module(); - return AST_MODULE_LOAD_DECLINE; - } + ast_sip_session_register_supplement(&nat_supplement); return AST_MODULE_LOAD_SUCCESS; } @@ -378,4 +372,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP NAT Support", .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_notify.c b/res/res_pjsip_notify.c index 8de88c7e8..253cf9ac8 100644 --- a/res/res_pjsip_notify.c +++ b/res/res_pjsip_notify.c @@ -82,7 +82,7 @@ order; any other header is treated as part of the SIP request.</para> </description> - <configOption name="^.*$"> + <configOption name=""> <synopsis>A key/value pair to add to a NOTIFY request.</synopsis> <description> <para>If the key is <literal>Content</literal>, @@ -234,8 +234,8 @@ static void *notify_cfg_alloc(void) static struct aco_type notify_option = { .type = ACO_ITEM, .name = "notify", - .category_match = ACO_BLACKLIST, - .category = "^general$", + .category_match = ACO_BLACKLIST_EXACT, + .category = "general", .item_offset = offsetof(struct notify_cfg, notify_options), .item_alloc = notify_option_alloc, .item_find = notify_option_find @@ -987,13 +987,11 @@ static int manager_notify(struct mansession *s, const struct message *m) static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - if (aco_info_init(¬ify_cfg)) { return AST_MODULE_LOAD_DECLINE; } - aco_option_register_custom(¬ify_cfg, "^.*$", ACO_REGEX, notify_options, + aco_option_register_custom(¬ify_cfg, "", ACO_PREFIX, notify_options, "", notify_option_handler, 0); if (aco_process_config(¬ify_cfg, 0)) { @@ -1032,4 +1030,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "CLI/AMI PJSIP NOTIFY .reload = reload_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_one_touch_record_info.c b/res/res_pjsip_one_touch_record_info.c index ec5f9be3e..50f2a3832 100644 --- a/res/res_pjsip_one_touch_record_info.c +++ b/res/res_pjsip_one_touch_record_info.c @@ -19,7 +19,6 @@ /*** MODULEINFO <depend>pjproject</depend> <depend>res_pjsip</depend> - <depend>res_pjsip_session</depend> <support_level>core</support_level> ***/ @@ -108,12 +107,7 @@ static struct ast_sip_session_supplement info_supplement = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - - if (ast_sip_session_register_supplement(&info_supplement)) { - ast_log(LOG_ERROR, "Unable to register One Touch Recording supplement\n"); - return AST_MODULE_LOAD_DECLINE; - } + ast_sip_session_register_supplement(&info_supplement); return AST_MODULE_LOAD_SUCCESS; } @@ -129,4 +123,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP INFO One Touch .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_outbound_authenticator_digest.c b/res/res_pjsip_outbound_authenticator_digest.c index 7e2d71129..063b4d3eb 100644 --- a/res/res_pjsip_outbound_authenticator_digest.c +++ b/res/res_pjsip_outbound_authenticator_digest.c @@ -205,8 +205,6 @@ static struct ast_sip_outbound_authenticator digest_authenticator = { static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - if (ast_sip_register_outbound_authenticator(&digest_authenticator)) { return AST_MODULE_LOAD_DECLINE; } @@ -224,4 +222,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP authentication .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index f1f49d510..75e74a26f 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -345,7 +345,6 @@ AST_RWLIST_HEAD_STATIC(publisher_handlers, ast_sip_event_publisher_handler); static void sub_add_handler(struct ast_sip_event_publisher_handler *handler) { AST_RWLIST_INSERT_TAIL(&publisher_handlers, handler, next); - ast_module_ref(ast_module_info->self); } static struct ast_sip_event_publisher_handler *find_publisher_handler_for_event_name(const char *event_name) @@ -643,7 +642,6 @@ void ast_sip_unregister_event_publisher_handler(struct ast_sip_event_publisher_h AST_RWLIST_TRAVERSE_SAFE_BEGIN(&publisher_handlers, iter, next) { if (handler == iter) { AST_RWLIST_REMOVE_CURRENT(next); - ast_module_unref(ast_module_info->self); break; } } @@ -1643,8 +1641,6 @@ static int unload_module(void) static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */ ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size); @@ -1697,8 +1693,10 @@ static int reload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Publish Support", + .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .reload = reload_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjproject,res_pjsip", ); diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index d9afcd284..d0f754604 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -850,6 +850,14 @@ static void registration_transport_shutdown_cb(void *obj) } } +static int monitor_matcher(void *a, void *b) +{ + char *ma = a; + char *mb = b; + + return strcmp(ma, mb) == 0; +} + static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name) { char *monitor; @@ -950,7 +958,8 @@ static int handle_registration_response(void *data) ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri); update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED); ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport, - registration_transport_shutdown_cb); + registration_transport_shutdown_cb, response->client_state->registration_name, + monitor_matcher); } } else if (response->client_state->destroy) { /* We need to deal with the pending destruction instead. */ @@ -2149,7 +2158,7 @@ static int unload_module(void) ao2_global_obj_release(current_states); - ast_sip_transport_monitor_unregister_all(registration_transport_shutdown_cb); + ast_sip_transport_monitor_unregister_all(registration_transport_shutdown_cb, NULL, NULL); /* Wait for registration serializers to get destroyed. */ ast_debug(2, "Waiting for registration transactions to complete for unload.\n"); @@ -2177,8 +2186,6 @@ static int load_module(void) { struct ao2_container *new_states; - CHECK_PJSIP_MODULE_LOADED(); - shutdown_group = ast_serializer_shutdown_group_alloc(); if (!shutdown_group) { return AST_MODULE_LOAD_DECLINE; @@ -2289,4 +2296,6 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Regist .reload = reload_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip", + .optional_modules = "res_statsd", ); diff --git a/res/res_pjsip_path.c b/res/res_pjsip_path.c index e170a750d..3c545f9d2 100644 --- a/res/res_pjsip_path.c +++ b/res/res_pjsip_path.c @@ -238,16 +238,8 @@ static struct ast_sip_session_supplement path_session_supplement = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - - if (ast_sip_register_supplement(&path_supplement)) { - return AST_MODULE_LOAD_DECLINE; - } - - if (ast_sip_session_register_supplement(&path_session_supplement)) { - ast_sip_unregister_supplement(&path_supplement); - return AST_MODULE_LOAD_DECLINE; - } + ast_sip_register_supplement(&path_supplement); + ast_sip_session_register_supplement(&path_session_supplement); return AST_MODULE_LOAD_SUCCESS; } @@ -264,4 +256,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Path Header Sup .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_phoneprov_provider.c b/res/res_pjsip_phoneprov_provider.c index eef3a082f..acb1e68b5 100644 --- a/res/res_pjsip_phoneprov_provider.c +++ b/res/res_pjsip_phoneprov_provider.c @@ -367,8 +367,6 @@ static int load_users(void) static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - sorcery = ast_sip_get_sorcery(); ast_sorcery_apply_config(sorcery, "res_pjsip_phoneprov_provider"); @@ -413,8 +411,10 @@ static int reload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Phoneprov Provider", + .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .reload = reload_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_phoneprov", ); diff --git a/res/res_pjsip_pidf_body_generator.c b/res/res_pjsip_pidf_body_generator.c index 29c9e6be2..8bc062e08 100644 --- a/res/res_pjsip_pidf_body_generator.c +++ b/res/res_pjsip_pidf_body_generator.c @@ -116,8 +116,6 @@ static struct ast_sip_pubsub_body_generator pidf_body_generator = { static int load_module(void) { - CHECK_PJSIP_PUBSUB_MODULE_LOADED(); - if (ast_sip_pubsub_register_body_generator(&pidf_body_generator)) { return AST_MODULE_LOAD_DECLINE; } @@ -135,4 +133,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjsip,res_pjsip_pubsub", ); diff --git a/res/res_pjsip_pidf_digium_body_supplement.c b/res/res_pjsip_pidf_digium_body_supplement.c index 93e4982e2..832f42302 100644 --- a/res/res_pjsip_pidf_digium_body_supplement.c +++ b/res/res_pjsip_pidf_digium_body_supplement.c @@ -95,8 +95,6 @@ static struct ast_sip_pubsub_body_supplement pidf_supplement = { static int load_module(void) { - CHECK_PJSIP_PUBSUB_MODULE_LOADED(); - if (ast_sip_pubsub_register_body_supplement(&pidf_supplement)) { return AST_MODULE_LOAD_DECLINE; } @@ -114,4 +112,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP PIDF Digium pre .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjsip,res_pjsip_pubsub", ); diff --git a/res/res_pjsip_pidf_eyebeam_body_supplement.c b/res/res_pjsip_pidf_eyebeam_body_supplement.c index 40470840c..15446bc52 100644 --- a/res/res_pjsip_pidf_eyebeam_body_supplement.c +++ b/res/res_pjsip_pidf_eyebeam_body_supplement.c @@ -92,8 +92,6 @@ static struct ast_sip_pubsub_body_supplement pidf_supplement = { static int load_module(void) { - CHECK_PJSIP_PUBSUB_MODULE_LOADED(); - if (ast_sip_pubsub_register_body_supplement(&pidf_supplement)) { return AST_MODULE_LOAD_DECLINE; } @@ -111,4 +109,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP PIDF Eyebeam su .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjsip,res_pjsip_pubsub", ); diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c index 72e1e4d7e..220ba0bc5 100644 --- a/res/res_pjsip_publish_asterisk.c +++ b/res/res_pjsip_publish_asterisk.c @@ -855,8 +855,6 @@ static int regex_filter_handler(const struct aco_option *opt, struct ast_variabl static int load_module(void) { - CHECK_PJSIP_PUBSUB_MODULE_LOADED(); - if (ast_eid_is_empty(&ast_eid_default)) { ast_log(LOG_ERROR, "Entity ID is not set.\n"); return AST_MODULE_LOAD_DECLINE; @@ -929,8 +927,10 @@ static int unload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Asterisk Event PUBLISH Support", + .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .reload = reload_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5, + .requires = "res_pjsip,res_pjsip_outbound_publish,res_pjsip_pubsub", ); diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 59418e4a9..69c256dab 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -127,6 +127,11 @@ <configOption name="contact_uri"> <synopsis>The Contact URI of the dialog for the subscription</synopsis> </configOption> + <configOption name="prune_on_boot"> + <synopsis>If set, indicates that the contact used a reliable transport + and therefore the subscription must be deleted after an asterisk restart. + </synopsis> + </configOption> </configObject> <configObject name="resource_list"> <synopsis>Resource list configuration parameters.</synopsis> @@ -382,6 +387,8 @@ struct subscription_persistence { struct timeval expires; /*! Contact URI */ char contact_uri[PJSIP_MAX_URL_SIZE]; + /*! Prune subscription on restart */ + int prune_on_boot; }; /*! @@ -446,6 +453,10 @@ struct sip_subscription_tree { * capable of restarting the timer. */ struct ast_sip_sched_task *expiration_task; + /*! The transport the subscription was received on. + * Only used for reliable transports. + */ + pjsip_transport *transport; }; /*! @@ -525,7 +536,7 @@ static void pubsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_s pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body); static void pubsub_on_client_refresh(pjsip_evsub *sub); static void pubsub_on_server_timeout(pjsip_evsub *sub); - + static pjsip_evsub_user pubsub_cb = { .on_evsub_state = pubsub_on_evsub_state, .on_rx_refresh = pubsub_on_rx_refresh, @@ -549,6 +560,17 @@ static void *publication_resource_alloc(const char *name) return ast_sorcery_generic_alloc(sizeof(struct ast_sip_publication_resource), publication_resource_destroy); } +static void sub_tree_transport_cb(void *data) { + struct sip_subscription_tree *sub_tree = data; + + ast_debug(3, "Transport destroyed. Removing subscription '%s->%s' prune on restart: %d\n", + sub_tree->persistence->endpoint, sub_tree->root->resource, + sub_tree->persistence->prune_on_boot); + + sub_tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS; + pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE); +} + /*! \brief Destructor for subscription persistence */ static void subscription_persistence_destroy(void *obj) { @@ -599,8 +621,9 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr return; } - ast_debug(3, "Updating persistence for '%s->%s'\n", sub_tree->persistence->endpoint, - sub_tree->root->resource); + ast_debug(3, "Updating persistence for '%s->%s' prune on restart: %s\n", + sub_tree->persistence->endpoint, sub_tree->root->resource, + sub_tree->persistence->prune_on_boot ? "yes" : "no"); dlg = sub_tree->dlg; sub_tree->persistence->cseq = dlg->local.cseq; @@ -613,8 +636,34 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES; sub_tree->persistence->expires = ast_tvadd(ast_tvnow(), ast_samp2tv(expires, 1)); - pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri, - sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri)); + if (contact_hdr) { + if (contact_hdr) { + if (type == SUBSCRIPTION_PERSISTENCE_CREATED) { + sub_tree->persistence->prune_on_boot = + !ast_sip_will_uri_survive_restart( + (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri), + sub_tree->endpoint, rdata); + + if (sub_tree->persistence->prune_on_boot) { + ast_debug(3, "adding transport monitor on %s for '%s->%s' prune on restart: %d\n", + rdata->tp_info.transport->obj_name, + sub_tree->persistence->endpoint, sub_tree->root->resource, + sub_tree->persistence->prune_on_boot); + sub_tree->transport = rdata->tp_info.transport; + ast_sip_transport_monitor_register(rdata->tp_info.transport, + sub_tree_transport_cb, sub_tree); + /* + * FYI: ast_sip_transport_monitor_register holds a reference to the sub_tree + */ + } + } + } + + pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri, + sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri)); + } else { + ast_log(LOG_WARNING, "Contact not updated due to missing contact header\n"); + } /* When receiving a packet on an streaming transport, it's possible to receive more than one SIP * message at a time into the rdata->pkt_info.packet buffer. However, the rdata->msg_info.msg_buf @@ -652,6 +701,15 @@ static void subscription_persistence_remove(struct sip_subscription_tree *sub_tr return; } + if (sub_tree->persistence->prune_on_boot && sub_tree->transport) { + ast_debug(3, "Unregistering transport monitor on %s '%s->%s'\n", + sub_tree->transport->obj_name, + sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown", + sub_tree->root ? sub_tree->root->resource : "Unknown"); + ast_sip_transport_monitor_unregister(sub_tree->transport, + sub_tree_transport_cb, sub_tree, NULL); + } + ast_sorcery_delete(ast_sip_get_sorcery(), sub_tree->persistence); ao2_ref(sub_tree->persistence, -1); sub_tree->persistence = NULL; @@ -728,10 +786,11 @@ static struct ast_sip_pubsub_body_generator *subscription_get_generator_from_rda char accept[AST_SIP_MAX_ACCEPT][64]; size_t num_accept_headers = 0; - while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next))) { + while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) && + (num_accept_headers < AST_SIP_MAX_ACCEPT)) { int i; - for (i = 0; i < accept_header->count; ++i) { + for (i = 0; i < accept_header->count && num_accept_headers < AST_SIP_MAX_ACCEPT; ++i) { if (!exceptional_accept(&accept_header->values[i])) { ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers])); ++num_accept_headers; @@ -895,7 +954,7 @@ static int have_visited(const char *resource, struct resources *visited) * This iterates through the items on a resource list and creates tree nodes for each one. The * tree nodes created are children of the supplied parent node. If an item in the resource * list is itself a list, then this function is called recursively to provide children for - * the the new node. + * the new node. * * If an item in a resource list is not a list, then the supplied subscription handler is * called into as if a new SUBSCRIBE for the list item were presented. The handler's response @@ -1560,6 +1619,14 @@ static int subscription_persistence_recreate(void *obj, void *arg, int flags) pjsip_rx_data rdata; struct persistence_recreate_data recreate_data; + /* If this subscription used a reliable transport it can't be reestablished so remove it */ + if (persistence->prune_on_boot) { + ast_debug(3, "Deleting subscription marked as 'prune' from persistent store '%s' %s\n", + persistence->endpoint, persistence->tag); + ast_sorcery_delete(ast_sip_get_sorcery(), persistence); + return 0; + } + /* If this subscription has already expired remove it */ if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) { ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n", @@ -2579,8 +2646,6 @@ int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler) publish_add_handler(handler); - ast_module_ref(ast_module_info->self); - return 0; } @@ -2593,7 +2658,6 @@ void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler) if (handler == iter) { AST_RWLIST_REMOVE_CURRENT(next); ao2_cleanup(handler->publications); - ast_module_unref(ast_module_info->self); break; } } @@ -2607,7 +2671,6 @@ static void sub_add_handler(struct ast_sip_subscription_handler *handler) { AST_RWLIST_WRLOCK(&subscription_handlers); AST_RWLIST_INSERT_TAIL(&subscription_handlers, handler, next); - ast_module_ref(ast_module_info->self); AST_RWLIST_UNLOCK(&subscription_handlers); } @@ -2666,7 +2729,6 @@ void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscription_handlers, iter, next) { if (handler == iter) { AST_RWLIST_REMOVE_CURRENT(next); - ast_module_unref(ast_module_info->self); break; } } @@ -5374,8 +5436,6 @@ static int load_module(void) static const pj_str_t str_PUBLISH = { "PUBLISH", 7 }; struct ast_sorcery *sorcery; - CHECK_PJSIP_MODULE_LOADED(); - sorcery = ast_sip_get_sorcery(); if (!(sched = ast_sched_context_create())) { @@ -5419,6 +5479,8 @@ static int load_module(void) persistence_expires_str2struct, persistence_expires_struct2str, NULL, 0, 0); ast_sorcery_object_field_register(sorcery, "subscription_persistence", "contact_uri", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct subscription_persistence, contact_uri)); + ast_sorcery_object_field_register(sorcery, "subscription_persistence", "prune_on_boot", "0", OPT_UINT_T, 0, + FLDSET(struct subscription_persistence, prune_on_boot)); if (apply_list_configuration(sorcery)) { ast_sched_context_destroy(sched); @@ -5495,6 +5557,8 @@ static int unload_module(void) AST_TEST_UNREGISTER(loop); AST_TEST_UNREGISTER(bad_event); + ast_sip_transport_monitor_unregister_all(sub_tree_transport_cb, NULL, NULL); + ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND); @@ -5514,4 +5578,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 62f8b67de..7d892f653 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -468,10 +468,20 @@ static struct refer_attended *refer_attended_alloc(struct ast_sip_session *trans return attended; } -static int defer_termination_cancel(void *data) +static int session_end_if_deferred_task(void *data) { struct ast_sip_session *session = data; + ast_sip_session_end_if_deferred(session); + ao2_ref(session, -1); + return 0; +} + +static int defer_termination_cancel_task(void *data) +{ + struct ast_sip_session *session = data; + + ast_sip_session_end_if_deferred(session); ast_sip_session_defer_termination_cancel(session); ao2_ref(session, -1); return 0; @@ -513,6 +523,7 @@ static int refer_attended_task(void *data) { struct refer_attended *attended = data; int response; + int (*task_cb)(void *data); if (attended->transferer_second->channel) { ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n", @@ -543,13 +554,18 @@ static int refer_attended_task(void *data) } } - ast_sip_session_end_if_deferred(attended->transferer); - if (response != 200) { - if (!ast_sip_push_task(attended->transferer->serializer, - defer_termination_cancel, attended->transferer)) { - /* Gave the ref to the pushed task. */ - attended->transferer = NULL; - } + if (response == 200) { + task_cb = session_end_if_deferred_task; + } else { + task_cb = defer_termination_cancel_task; + } + if (!ast_sip_push_task(attended->transferer->serializer, + task_cb, attended->transferer)) { + /* Gave the ref to the pushed task. */ + attended->transferer = NULL; + } else { + /* Do this anyway even though it is the wrong serializer. */ + ast_sip_session_end_if_deferred(attended->transferer); } ao2_ref(attended, -1); @@ -1202,8 +1218,6 @@ static int load_module(void) { const pj_str_t str_norefersub = { "norefersub", 10 }; - CHECK_PJSIP_SESSION_MODULE_LOADED(); - pjsip_replaces_init_module(ast_sip_get_pjsip_endpoint()); pjsip_xfer_init_module(ast_sip_get_pjsip_endpoint()); pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_SUPPORTED, NULL, 1, &str_norefersub); @@ -1229,4 +1243,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Blind and Atten .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session,res_pjsip_pubsub", ); diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index f0da6dee2..bdee91fb3 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -25,6 +25,7 @@ #include "asterisk.h" +#include <signal.h> #include <pjsip.h> #include <pjsip_ua.h> @@ -327,6 +328,15 @@ struct contact_transport_monitor { char aor_name[0]; }; +static int contact_transport_monitor_matcher(void *a, void *b) +{ + struct contact_transport_monitor *ma = a; + struct contact_transport_monitor *mb = b; + + return strcmp(ma->aor_name, mb->aor_name) == 0 + && strcmp(ma->contact_name, mb->contact_name) == 0; +} + static void register_contact_transport_shutdown_cb(void *data) { struct contact_transport_monitor *monitor = data; @@ -578,8 +588,7 @@ static void register_aor_core(pjsip_rx_data *rdata, contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details); if (!contact) { - int prune_on_boot = 0; - pj_str_t host_name; + int prune_on_boot; /* If they are actually trying to delete a contact that does not exist... be forgiving */ if (!expiration) { @@ -588,35 +597,7 @@ static void register_aor_core(pjsip_rx_data *rdata, continue; } - /* Determine if the contact cannot survive a restart/boot. */ - if (details.uri->port == rdata->pkt_info.src_port - && !pj_strcmp(&details.uri->host, - pj_cstr(&host_name, rdata->pkt_info.src_name)) - /* We have already checked if the URI scheme is sip: or sips: */ - && PJSIP_TRANSPORT_IS_RELIABLE(rdata->tp_info.transport)) { - pj_str_t type_name; - - /* Determine the transport parameter value */ - if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) { - /* WSS is special, as it needs to be ws. */ - pj_cstr(&type_name, "ws"); - } else { - pj_cstr(&type_name, rdata->tp_info.transport->type_name); - } - - if (!pj_stricmp(&details.uri->transport_param, &type_name) - && (endpoint->nat.rewrite_contact - /* Websockets are always rewritten */ - || !pj_stricmp(&details.uri->transport_param, - pj_cstr(&type_name, "ws")))) { - /* - * The contact was rewritten to the reliable transport's - * source address. Disconnecting the transport for any - * reason invalidates the contact. - */ - prune_on_boot = 1; - } - } + prune_on_boot = !ast_sip_will_uri_survive_restart(details.uri, endpoint, rdata); contact = ast_sip_location_create_contact(aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), @@ -703,6 +684,21 @@ static void register_aor_core(pjsip_rx_data *rdata, contact_update->user_agent); ao2_cleanup(contact_update); } else { + if (contact->prune_on_boot) { + struct contact_transport_monitor *monitor; + const char *contact_name = + ast_sorcery_object_get_id(contact); + + monitor = ast_alloca(sizeof(*monitor) + 2 + strlen(aor_name) + + strlen(contact_name)); + strcpy(monitor->aor_name, aor_name);/* Safe */ + monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1; + strcpy(monitor->contact_name, contact_name);/* Safe */ + + ast_sip_transport_monitor_unregister(rdata->tp_info.transport, + register_contact_transport_shutdown_cb, monitor, contact_transport_monitor_matcher); + } + /* We want to report the user agent that was actually in the removed contact */ ast_sip_location_delete_contact(contact); ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name); @@ -1091,18 +1087,114 @@ static pjsip_module registrar_module = { .on_rx_request = registrar_on_rx_request, }; +/*! \brief Thread keeping things alive */ +static pthread_t check_thread = AST_PTHREADT_NULL; + +/*! \brief The global interval at which to check for contact expiration */ +static unsigned int check_interval; + +/*! \brief Callback function which deletes a contact */ +static int expire_contact(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + struct ast_named_lock *lock; + + lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", contact->aor); + if (!lock) { + return 0; + } + + /* + * We need to check the expiration again with the aor lock held + * in case another thread is attempting to renew the contact. + */ + ao2_lock(lock); + if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) { + if (contact->prune_on_boot) { + struct contact_transport_monitor *monitor; + const char *contact_name = ast_sorcery_object_get_id(contact); + + monitor = ast_alloca(sizeof(*monitor) + 2 + strlen(contact->aor) + + strlen(contact_name)); + strcpy(monitor->aor_name, contact->aor);/* Safe */ + monitor->contact_name = monitor->aor_name + strlen(contact->aor) + 1; + strcpy(monitor->contact_name, contact_name);/* Safe */ + + ast_sip_transport_monitor_unregister_all(register_contact_transport_shutdown_cb, + monitor, contact_transport_monitor_matcher); + } + ast_sip_location_delete_contact(contact); + } + ao2_unlock(lock); + ast_named_lock_put(lock); + + return 0; +} + +static void *check_expiration_thread(void *data) +{ + struct ao2_container *contacts; + struct ast_variable *var; + char *time = alloca(64); + + while (check_interval) { + sleep(check_interval); + + sprintf(time, "%ld", ast_tvnow().tv_sec); + var = ast_variable_new("expiration_time <=", time, ""); + + ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval); + + contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", + AST_RETRIEVE_FLAG_MULTIPLE, var); + + ast_variables_destroy(var); + if (contacts) { + ast_debug(3, "Expiring %d contacts\n", ao2_container_count(contacts)); + ao2_callback(contacts, OBJ_NODATA, expire_contact, NULL); + ao2_ref(contacts, -1); + } + } + + return NULL; +} + +static void expiration_global_loaded(const char *object_type) +{ + check_interval = ast_sip_get_contact_expiration_check_interval(); + + /* Observer calls are serialized so this is safe without it's own lock */ + if (check_interval) { + if (check_thread == AST_PTHREADT_NULL) { + if (ast_pthread_create_background(&check_thread, NULL, check_expiration_thread, NULL)) { + ast_log(LOG_ERROR, "Could not create thread for checking contact expiration.\n"); + return; + } + ast_debug(3, "Interval = %d, starting thread\n", check_interval); + } + } else { + if (check_thread != AST_PTHREADT_NULL) { + pthread_kill(check_thread, SIGURG); + pthread_join(check_thread, NULL); + check_thread = AST_PTHREADT_NULL; + ast_debug(3, "Interval = 0, shutting thread down\n"); + } + } +} + +/*! \brief Observer which is used to update our interval when the global setting changes */ +static struct ast_sorcery_observer expiration_global_observer = { + .loaded = expiration_global_loaded, +}; + static int load_module(void) { const pj_str_t STR_REGISTER = { "REGISTER", 8 }; - CHECK_PJPROJECT_MODULE_LOADED(); - ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname); /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */ ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size); - CHECK_PJSIP_MODULE_LOADED(); - if (ast_sip_register_service(®istrar_module)) { return AST_MODULE_LOAD_DECLINE; } @@ -1117,15 +1209,28 @@ static int load_module(void) ast_manager_register_xml(AMI_SHOW_REGISTRATION_CONTACT_STATUSES, EVENT_FLAG_SYSTEM, ami_show_registration_contact_statuses); + ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &expiration_global_observer); + ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); + return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { + if (check_thread != AST_PTHREADT_NULL) { + check_interval = 0; + pthread_kill(check_thread, SIGURG); + pthread_join(check_thread, NULL); + + check_thread = AST_PTHREADT_NULL; + } + + ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &expiration_global_observer); + ast_manager_unregister(AMI_SHOW_REGISTRATIONS); ast_manager_unregister(AMI_SHOW_REGISTRATION_CONTACT_STATUSES); ast_sip_unregister_service(®istrar_module); - ast_sip_transport_monitor_unregister_all(register_contact_transport_shutdown_cb); + ast_sip_transport_monitor_unregister_all(register_contact_transport_shutdown_cb, NULL, NULL); return 0; } @@ -1134,4 +1239,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Registrar Suppo .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 3, + .requires = "res_pjproject,res_pjsip", ); diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c deleted file mode 100644 index fe4a60da8..000000000 --- a/res/res_pjsip_registrar_expire.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2013, Digium, Inc. - * - * Joshua Colp <jcolp@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*** MODULEINFO - <depend>pjproject</depend> - <depend>res_pjsip</depend> - <support_level>core</support_level> - ***/ - -#include "asterisk.h" - -#include <pjsip.h> -#include <sys/time.h> -#include <signal.h> - -#include "asterisk/res_pjsip.h" -#include "asterisk/module.h" -#include "asterisk/named_locks.h" - -/*! \brief Thread keeping things alive */ -static pthread_t check_thread = AST_PTHREADT_NULL; - -/*! \brief The global interval at which to check for contact expiration */ -static unsigned int check_interval; - -/*! \brief Callback function which deletes a contact */ -static int expire_contact(void *obj, void *arg, int flags) -{ - struct ast_sip_contact *contact = obj; - struct ast_named_lock *lock; - - lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", contact->aor); - if (!lock) { - return 0; - } - - /* - * We need to check the expiration again with the aor lock held - * in case another thread is attempting to renew the contact. - */ - ao2_lock(lock); - if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) { - ast_sip_location_delete_contact(contact); - } - ao2_unlock(lock); - ast_named_lock_put(lock); - - return 0; -} - -static void *check_expiration_thread(void *data) -{ - struct ao2_container *contacts; - struct ast_variable *var; - char *time = alloca(64); - - while (check_interval) { - sleep(check_interval); - - sprintf(time, "%ld", ast_tvnow().tv_sec); - var = ast_variable_new("expiration_time <=", time, ""); - - ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval); - - contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", - AST_RETRIEVE_FLAG_MULTIPLE, var); - - ast_variables_destroy(var); - if (contacts) { - ast_debug(3, "Expiring %d contacts\n", ao2_container_count(contacts)); - ao2_callback(contacts, OBJ_NODATA, expire_contact, NULL); - ao2_ref(contacts, -1); - } - } - - return NULL; -} - -static void expiration_global_loaded(const char *object_type) -{ - check_interval = ast_sip_get_contact_expiration_check_interval(); - - /* Observer calls are serialized so this is safe without it's own lock */ - if (check_interval) { - if (check_thread == AST_PTHREADT_NULL) { - if (ast_pthread_create_background(&check_thread, NULL, check_expiration_thread, NULL)) { - ast_log(LOG_ERROR, "Could not create thread for checking contact expiration.\n"); - return; - } - ast_debug(3, "Interval = %d, starting thread\n", check_interval); - } - } else { - if (check_thread != AST_PTHREADT_NULL) { - pthread_kill(check_thread, SIGURG); - pthread_join(check_thread, NULL); - check_thread = AST_PTHREADT_NULL; - ast_debug(3, "Interval = 0, shutting thread down\n"); - } - } -} - -/*! \brief Observer which is used to update our interval when the global setting changes */ -static struct ast_sorcery_observer expiration_global_observer = { - .loaded = expiration_global_loaded, -}; - -static int unload_module(void) -{ - if (check_thread != AST_PTHREADT_NULL) { - check_interval = 0; - pthread_kill(check_thread, SIGURG); - pthread_join(check_thread, NULL); - - check_thread = AST_PTHREADT_NULL; - } - - ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &expiration_global_observer); - - return 0; -} - - -static int load_module(void) -{ - CHECK_PJSIP_MODULE_LOADED(); - - ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &expiration_global_observer); - ast_sorcery_reload_object(ast_sip_get_sorcery(), "global"); - - return AST_MODULE_LOAD_SUCCESS; -} - -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Contact Auto-Expiration", - .support_level = AST_MODULE_SUPPORT_CORE, - .load = load_module, - .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND, -); diff --git a/res/res_pjsip_rfc3326.c b/res/res_pjsip_rfc3326.c index d49a170d3..76b0d08b0 100644 --- a/res/res_pjsip_rfc3326.c +++ b/res/res_pjsip_rfc3326.c @@ -19,7 +19,6 @@ /*** MODULEINFO <depend>pjproject</depend> <depend>res_pjsip</depend> - <depend>res_pjsip_session</depend> <support_level>core</support_level> ***/ @@ -36,32 +35,35 @@ static void rfc3326_use_reason_header(struct ast_sip_session *session, struct pjsip_rx_data *rdata) { - const pj_str_t str_reason = { "Reason", 6 }; - pjsip_generic_string_hdr *header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_reason, NULL); - char buf[20], *cause, *text; + static const pj_str_t str_reason = { "Reason", 6 }; + pjsip_generic_string_hdr *header; + char buf[20]; + char *cause; + char *text; int code; - if (!header) { - return; - } + header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_reason, NULL); + for (; header; + header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_reason, header->next)) { + ast_copy_pj_str(buf, &header->hvalue, sizeof(buf)); + cause = ast_skip_blanks(buf); - ast_copy_pj_str(buf, &header->hvalue, sizeof(buf)); - cause = ast_skip_blanks(buf); + if (strncasecmp(cause, "Q.850", 5) || !(cause = strstr(cause, "cause="))) { + continue; + } - if (strncasecmp(cause, "Q.850", 5) || !(cause = strstr(cause, "cause="))) { - return; - } + /* If text is present get rid of it */ + if ((text = strstr(cause, ";"))) { + *text = '\0'; + } - /* If text is present get rid of it */ - if ((text = strstr(cause, ";"))) { - *text = '\0'; - } + if (sscanf(cause, "cause=%30d", &code) != 1) { + continue; + } - if (sscanf(cause, "cause=%30d", &code) != 1) { - return; + ast_channel_hangupcause_set(session->channel, code & 0x7f); + break; } - - ast_channel_hangupcause_set(session->channel, code & 0x7f); } static int rfc3326_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata) @@ -92,12 +94,12 @@ static void rfc3326_add_reason_header(struct ast_sip_session *session, struct pj { char buf[20]; - snprintf(buf, sizeof(buf), "Q.850;cause=%i", ast_channel_hangupcause(session->channel) & 0x7f); - ast_sip_add_header(tdata, "Reason", buf); - if (ast_channel_hangupcause(session->channel) == AST_CAUSE_ANSWERED_ELSEWHERE) { ast_sip_add_header(tdata, "Reason", "SIP;cause=200;text=\"Call completed elsewhere\""); } + + snprintf(buf, sizeof(buf), "Q.850;cause=%i", ast_channel_hangupcause(session->channel) & 0x7f); + ast_sip_add_header(tdata, "Reason", buf); } static void rfc3326_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata) @@ -139,8 +141,6 @@ static struct ast_sip_session_supplement rfc3326_supplement = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - ast_sip_session_register_supplement(&rfc3326_supplement); return AST_MODULE_LOAD_SUCCESS; } @@ -156,4 +156,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP RFC3326 Support .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a87758267..9f0cdd300 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -219,10 +219,13 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me (session->endpoint->media.tos_audio || session->endpoint->media.cos_audio)) { ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_audio, session->endpoint->media.cos_audio, "SIP RTP Audio"); - } else if (session_media->type == AST_MEDIA_TYPE_VIDEO && - (session->endpoint->media.tos_video || session->endpoint->media.cos_video)) { - ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_video, - session->endpoint->media.cos_video, "SIP RTP Video"); + } else if (session_media->type == AST_MEDIA_TYPE_VIDEO) { + ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RETRANS_RECV, session->endpoint->media.webrtc); + ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RETRANS_SEND, session->endpoint->media.webrtc); + if (session->endpoint->media.tos_video || session->endpoint->media.cos_video) { + ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_video, + session->endpoint->media.cos_video, "SIP RTP Video"); + } } ast_rtp_instance_set_last_rx(session_media->rtp, time(NULL)); @@ -627,7 +630,7 @@ static void process_ice_attributes(struct ast_sip_session *session, struct ast_s /* Find all of the candidates */ for (attr_i = 0; attr_i < remote_stream->attr_count; ++attr_i) { - char foundation[32], transport[32], address[PJ_INET6_ADDRSTRLEN + 1], cand_type[6], relay_address[PJ_INET6_ADDRSTRLEN + 1] = ""; + char foundation[33], transport[32], address[PJ_INET6_ADDRSTRLEN + 1], cand_type[6], relay_address[PJ_INET6_ADDRSTRLEN + 1] = ""; unsigned int port, relay_port = 0; struct ast_rtp_engine_ice_candidate candidate = { 0, }; @@ -640,7 +643,7 @@ static void process_ice_attributes(struct ast_sip_session *session, struct ast_s ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value)); - if (sscanf(attr_value, "%31s %30u %31s %30u %46s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport, + if (sscanf(attr_value, "%32s %30u %31s %30u %46s %30u typ %5s %*s %23s %*s %30u", foundation, &candidate.id, transport, (unsigned *)&candidate.priority, address, &port, cand_type, relay_address, &relay_port) < 7) { /* Candidate did not parse properly */ continue; @@ -1253,7 +1256,8 @@ static int add_crypto_to_stream(struct ast_sip_session *session, /* If this is an answer we need to use our current state, if it's an offer we need to use * the configured value. */ - if (pjmedia_sdp_neg_get_state(session->inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) { + if (session->inv_session->neg + && pjmedia_sdp_neg_get_state(session->inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) { setup = dtls->get_setup(session_media->rtp); } else { setup = session->endpoint->media.rtp.dtls_cfg.default_setup; @@ -1927,8 +1931,6 @@ static int unload_module(void) */ static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - if (ast_check_ipv6()) { ast_sockaddr_parse(&address_rtp, "::", 0); } else { @@ -1969,4 +1971,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP SDP RTP/AVP str .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_send_to_voicemail.c b/res/res_pjsip_send_to_voicemail.c index 1cd28ceac..d68960275 100644 --- a/res/res_pjsip_send_to_voicemail.c +++ b/res/res_pjsip_send_to_voicemail.c @@ -215,12 +215,7 @@ static struct ast_sip_session_supplement refer_supplement = { static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - - if (ast_sip_session_register_supplement(&refer_supplement)) { - ast_log(LOG_ERROR, "Unable to register Send to Voicemail supplement\n"); - return AST_MODULE_LOAD_DECLINE; - } + ast_sip_session_register_supplement(&refer_supplement); return AST_MODULE_LOAD_SUCCESS; } @@ -236,4 +231,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP REFER Send to V .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_pjsip_session", ); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 781d3e4eb..f25201731 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -124,7 +124,7 @@ int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *han } AST_LIST_INSERT_TAIL(&handler_list->list, handler, next); ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type); - ast_module_ref(ast_module_info->self); + return 0; } @@ -141,7 +141,7 @@ int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *han return -1; } ast_debug(1, "Registered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type); - ast_module_ref(ast_module_info->self); + return 0; } @@ -156,7 +156,6 @@ static int remove_handler(void *obj, void *arg, void *data, int flags) if (!strcmp(iter->id, handler->id)) { AST_LIST_REMOVE_CURRENT(next); ast_debug(1, "Unregistered SDP stream handler '%s' for stream type '%s'\n", handler->id, stream_type); - ast_module_unref(ast_module_info->self); } } AST_LIST_TRAVERSE_SAFE_END; @@ -456,6 +455,12 @@ struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_ses return NULL; } session_media->bundle_group = 0; + + /* Some WebRTC clients can't handle an offer to bundle media streams. Instead they expect them to + * already be bundled. Every client handles this scenario though so if WebRTC is enabled just go + * ahead and treat the streams as having already been bundled. + */ + session_media->bundled = session->endpoint->media.webrtc; } else { session_media->bundle_group = -1; } @@ -871,15 +876,30 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_ struct ast_stream_topology *topology; unsigned int changed = 0; - /* This situation can legitimately happen when an SDP is received in a - * 183 Session Progress message. In that case, everything's been done - * by the time this function is called and there are no more pending - * streams. - */ if (!session->pending_media_state->topology) { - ast_debug(1, "Pending topology was NULL for channel '%s'\n", - session->channel ? ast_channel_name(session->channel) : "unknown"); - return 0; + if (session->active_media_state->topology) { + /* + * This happens when we have negotiated media after receiving a 183, + * and we're now receiving a 200 with a new SDP. In this case, there + * is active_media_state, but the pending_media_state has been reset. + */ + struct ast_sip_session_media_state *active_media_state_clone; + + active_media_state_clone = + ast_sip_session_media_state_clone(session->active_media_state); + if (!active_media_state_clone) { + ast_log(LOG_WARNING, "Unable to clone active media state for channel '%s'\n", + session->channel ? ast_channel_name(session->channel) : "unknown"); + return -1; + } + + ast_sip_session_media_state_free(session->pending_media_state); + session->pending_media_state = active_media_state_clone; + } else { + ast_log(LOG_WARNING, "No pending or active media state for channel '%s'\n", + session->channel ? ast_channel_name(session->channel) : "unknown"); + return -1; + } } /* If we're handling negotiated streams, then we should already have set @@ -1067,7 +1087,7 @@ enum delayed_method { /*! * \internal - * \brief Convert delayed method enum value to to a string. + * \brief Convert delayed method enum value to a string. * \since 13.3.0 * * \param method Delayed method enum value to convert to a string. @@ -1860,7 +1880,9 @@ static pj_bool_t session_reinvite_on_rx_request(pjsip_rx_data *rdata) /* Otherwise this is a new re-invite, so reject it */ if (pjsip_dlg_create_response(dlg, rdata, 491, NULL, &tdata) == PJ_SUCCESS) { - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } } return PJ_TRUE; @@ -2241,7 +2263,7 @@ static int sip_session_suspend_task(void *data) suspender->suspended = 1; ast_cond_signal(&suspender->cond_suspended); - /* Wait for the the serializer suspension to be completed. */ + /* Wait for the serializer suspension to be completed. */ while (!suspender->complete) { ast_cond_wait(&suspender->cond_complete, ao2_object_get_lockaddr(suspender)); } @@ -2818,6 +2840,12 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s ast_copy_pj_str(domain, &sip_ruri->host, size); pbx_builtin_setvar_helper(session->channel, "SIPDOMAIN", domain); + /* + * Save off the INVITE Request-URI in case it is + * needed: CHANNEL(pjsip,request_uri) + */ + session->request_uri = pjsip_uri_clone(session->inv_session->pool, ruri); + return SIP_GET_DEST_EXTEN_FOUND; } @@ -2844,7 +2872,9 @@ static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct a if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) { if (tdata) { - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } } else { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); } @@ -3303,6 +3333,12 @@ static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_d struct ast_sip_session_supplement *supplement; struct pjsip_status_line status = tdata->msg->line.status; pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); + + if (!cseq) { + ast_log(LOG_ERROR, "Cannot send response due to missing sequence header"); + return; + } + ast_debug(3, "Method is %.*s, Response is %d %.*s\n", (int) pj_strlen(&cseq->method.name), pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason)); @@ -3408,9 +3444,13 @@ static void handle_incoming_before_media(pjsip_inv_session *inv, static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) { - struct ast_sip_session *session = inv->mod_data[session_module.id]; + struct ast_sip_session *session; pjsip_event_id_e type; + if (ast_shutdown_final()) { + return; + } + if (e) { print_debug_details(inv, NULL, e); type = e->type; @@ -3418,6 +3458,7 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) type = PJSIP_EVENT_UNKNOWN; } + session = inv->mod_data[session_module.id]; if (!session) { return; } @@ -3519,13 +3560,7 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans struct ast_sip_session *session; pjsip_tx_data *tdata; - /* - * A race condition exists at shutdown where the res_pjsip_session can be - * unloaded but this callback may still get called afterwards. In this case - * the id may end up being -1 which is useless to us. To work around this - * we store the current value and check/use it. - */ - if (id < 0) { + if (ast_shutdown_final()) { return; } @@ -3872,10 +3907,15 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru if (!session->pending_media_state->topology || !ast_stream_topology_get_count(session->pending_media_state->topology)) { /* We've encountered a situation where we have been told to create a local SDP but noone has given us any indication - * of what kind of stream topology they would like. As a fallback we use the topology from the configured endpoint. + * of what kind of stream topology they would like. We try to not alter the current state of the SDP negotiation + * by using what is currently negotiated. If this is unavailable we fall back to what is configured on the endpoint. */ ast_stream_topology_free(session->pending_media_state->topology); - session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology); + if (session->active_media_state->topology) { + session->pending_media_state->topology = ast_stream_topology_clone(session->active_media_state->topology); + } else { + session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology); + } if (!session->pending_media_state->topology) { return NULL; } @@ -3969,9 +4009,14 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru static void session_inv_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer) { - struct ast_sip_session *session = inv->mod_data[session_module.id]; + struct ast_sip_session *session; pjmedia_sdp_session *answer; + if (ast_shutdown_final()) { + return; + } + + session = inv->mod_data[session_module.id]; if (handle_incoming_sdp(session, offer)) { return; } @@ -3990,9 +4035,14 @@ static void session_inv_on_create_offer(pjsip_inv_session *inv, pjmedia_sdp_sess static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status) { - struct ast_sip_session *session = inv->mod_data[session_module.id]; + struct ast_sip_session *session; const pjmedia_sdp_session *local, *remote; + if (ast_shutdown_final()) { + return; + } + + session = inv->mod_data[session_module.id]; if (!session || !session->channel) { /* * If we don't have a session or channel then we really @@ -4015,10 +4065,15 @@ static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t stat static pjsip_redirect_op session_inv_on_redirected(pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e) { - struct ast_sip_session *session = inv->mod_data[session_module.id]; + struct ast_sip_session *session; const pjsip_sip_uri *uri; - if (!session->channel) { + if (ast_shutdown_final()) { + return PJSIP_REDIRECT_STOP; + } + + session = inv->mod_data[session_module.id]; + if (!session || !session->channel) { return PJSIP_REDIRECT_STOP; } @@ -4133,8 +4188,6 @@ static int load_module(void) { pjsip_endpoint *endpt; - CHECK_PJSIP_MODULE_LOADED(); - if (!ast_sip_get_sorcery() || !ast_sip_get_pjsip_endpoint()) { return AST_MODULE_LOAD_DECLINE; } @@ -4179,4 +4232,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_sips_contact.c b/res/res_pjsip_sips_contact.c index 7579be6f3..7c0ff4360 100644 --- a/res/res_pjsip_sips_contact.c +++ b/res/res_pjsip_sips_contact.c @@ -90,8 +90,6 @@ static int unload_module(void) static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - if (ast_sip_register_service(&sips_contact_module)) { return AST_MODULE_LOAD_DECLINE; } @@ -104,4 +102,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "UAC SIPS Contact supp .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip", ); diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 8f1905f6e..333295fe6 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -1023,18 +1023,13 @@ static int unload_module(void) */ static int load_module(void) { - CHECK_PJSIP_SESSION_MODULE_LOADED(); - if (ast_check_ipv6()) { ast_sockaddr_parse(&address, "::", 0); } else { ast_sockaddr_parse(&address, "0.0.0.0", 0); } - if (ast_sip_session_register_supplement(&t38_supplement)) { - ast_log(LOG_ERROR, "Unable to register T.38 session supplement\n"); - goto end; - } + ast_sip_session_register_supplement(&t38_supplement); if (ast_sip_session_register_sdp_handler(&image_sdp_handler, "image")) { ast_log(LOG_ERROR, "Unable to register SDP handler for image stream type\n"); @@ -1053,4 +1048,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP T.38 UDPTL Supp .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, + .requires = "res_pjsip,res_pjsip_session,udptl", ); diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index 3ce90390c..974b15087 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -471,8 +471,6 @@ static struct ast_sip_session_supplement websocket_supplement = { static int load_module(void) { - CHECK_PJSIP_MODULE_LOADED(); - /* * We only need one transport type name (ws) defined. Firefox * and Chrome do not support anything other than secure websockets @@ -490,10 +488,7 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } - if (ast_sip_session_register_supplement(&websocket_supplement)) { - ast_sip_unregister_service(&websocket_module); - return AST_MODULE_LOAD_DECLINE; - } + ast_sip_session_register_supplement(&websocket_supplement); if (ast_websocket_add_protocol("sip", websocket_cb)) { ast_sip_session_unregister_supplement(&websocket_supplement); @@ -518,4 +513,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP WebSocket Trans .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, + .requires = "res_pjsip,res_http_websocket", ); diff --git a/res/res_pjsip_xpidf_body_generator.c b/res/res_pjsip_xpidf_body_generator.c index 41f6224d1..7395fd9b7 100644 --- a/res/res_pjsip_xpidf_body_generator.c +++ b/res/res_pjsip_xpidf_body_generator.c @@ -20,7 +20,6 @@ <depend>pjproject</depend> <depend>res_pjsip</depend> <depend>res_pjsip_pubsub</depend> - <depend>res_pjsip_exten_state</depend> <support_level>core</support_level> ***/ @@ -149,8 +148,6 @@ static void unregister_all(void) static int load_module(void) { - CHECK_PJSIP_PUBSUB_MODULE_LOADED(); - if (ast_sip_pubsub_register_body_generator(&xpidf_body_generator)) { goto fail; } @@ -177,4 +174,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Extension State .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjsip,res_pjsip_pubsub", ); diff --git a/res/res_pktccops.c b/res/res_pktccops.c index e8d266cda..9beabfb3d 100644 --- a/res/res_pktccops.c +++ b/res/res_pktccops.c @@ -19,10 +19,10 @@ /*!\file * * \brief PacketCable COPS - * + * * \author Attila Domjan <attila.domjan.hu@gmail.com> * - * \note + * \note * This module is an add-on to chan_mgcp. It adds support for the * PacketCable MGCP variation called NCS. Res_pktccops implements COPS * (RFC 2748), a protocol used to manage dynamic bandwith allocation in @@ -94,7 +94,7 @@ struct pktcobj { unsigned char cnum; unsigned char ctype; char *contents; - struct pktcobj *next; + struct pktcobj *next; }; struct copsmsg { @@ -134,7 +134,7 @@ struct cops_cmts { char name[80]; char host[80]; char port[80]; - uint16_t t1; + uint16_t t1; uint16_t t7; uint16_t t8; uint32_t keepalive; @@ -184,7 +184,7 @@ static uint16_t cops_constructgatespec(struct gatespec *gs, char *res) if (res == NULL) { return 0; } - + *res = (char) gs->direction; *(res + 1) = (char) gs->protocolid; *(res + 2) = (char) gs->flags; @@ -224,7 +224,7 @@ static uint16_t cops_construct_gate (int cmd, char *p, uint16_t trid, { struct gatespec gs; int offset = 0; - + ast_debug(3, "CMD: %d\n", cmd); /* Transaction Identifier 8 octets */ @@ -244,7 +244,7 @@ static uint16_t cops_construct_gate (int cmd, char *p, uint16_t trid, *(p + offset++) = 1; /* stype */ *((uint32_t *) (p + offset)) = htonl(mtahost); offset += 4; - + if (cmd == GATE_INFO || cmd == GATE_SET_HAVE_GATEID || cmd == GATE_DEL) { /* Gate ID 8 Octets */ *(p + offset++) = 0; @@ -256,7 +256,7 @@ static uint16_t cops_construct_gate (int cmd, char *p, uint16_t trid, if (cmd == GATE_INFO || cmd == GATE_DEL) { return offset; } - + } /* Activity Count 8 octets */ @@ -390,7 +390,7 @@ static int cops_sendmsg (int sfd, struct copsmsg * sendmsg) char *buf; int bufpos; struct pktcobj *pobject; - + if (sfd < 0) { return -1; } @@ -433,7 +433,7 @@ static int cops_sendmsg (int sfd, struct copsmsg * sendmsg) pobject = pobject->next; } } - + errno = 0; #ifdef HAVE_MSG_NOSIGNAL #define SENDFLAGS MSG_NOSIGNAL | MSG_DONTWAIT @@ -479,15 +479,15 @@ struct cops_gate * AST_OPTIONAL_API_NAME(ast_pktccops_gate_alloc)(int cmd, ast_debug(3, "------- gate modify gateid 0x%x ssip: 0x%x\n", gate->gateid, ssip); /* TODO implement it */ ast_log(LOG_WARNING, "Modify GateID not implemented\n"); - } - + } + if ((gate = cops_gate_cmd(cmd, NULL, cops_trid++, mta, actcount, bitrate, psize, ssip, ssport, gate))) { ast_debug(3, "COPS: Allocating gate for mta: 0x%x\n", mta); gate->got_dq_gi = got_dq_gi; gate->gate_remove = gate_remove; return(gate); } else { - ast_debug(3, "COPS: Couldn't allocate gate for mta: 0x%x\n", mta); + ast_debug(3, "COPS: Couldn't allocate gate for mta: 0x%x\n", mta); return NULL; } } @@ -550,7 +550,7 @@ static struct cops_gate *cops_gate_cmd(int cmd, struct cops_cmts *cmts, gate->trid = trid; } } - + gate->in_transaction = time(NULL); if (!(gateset = ast_malloc(sizeof(struct copsmsg)))) { @@ -561,7 +561,7 @@ static struct cops_gate *cops_gate_cmd(int cmd, struct cops_cmts *cmts, gateset->verflag = 0x10; gateset->opcode = 2; /* Decision */ gateset->clienttype = 0x8008; /* =PacketCable */ - + /* Handle object */ gateset->object = ast_malloc(sizeof(struct pktcobj)); if (!gateset->object) { @@ -627,7 +627,7 @@ static struct cops_gate *cops_gate_cmd(int cmd, struct cops_cmts *cmts, return NULL; } gateset->object->next->next->next->next = NULL; - + gateset->length = COPS_HEADER_SIZE + gateset->object->length + gateset->object->next->length + gateset->object->next->next->length + gateset->object->next->next->next->length; if ((cmd == GATE_INFO || cmd == GATE_SET_HAVE_GATEID || cmd == GATE_DEL) && gate) { @@ -648,7 +648,7 @@ static struct cops_gate *cops_gate_cmd(int cmd, struct cops_cmts *cmts, static int cops_connect(char *host, char *port) { - int s, sfd = -1, flags; + int s, sfd = -1; struct addrinfo hints; struct addrinfo *rp; struct addrinfo *result; @@ -658,7 +658,7 @@ static int cops_connect(char *host, char *port) memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; + hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = 0; @@ -674,8 +674,7 @@ static int cops_connect(char *host, char *port) if (sfd == -1) { ast_log(LOG_WARNING, "Failed socket\n"); } - flags = fcntl(sfd, F_GETFL); - fcntl(sfd, F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(sfd, O_NONBLOCK); #ifdef HAVE_SO_NOSIGPIPE setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, &trueval, sizeof(trueval)); #endif @@ -825,7 +824,7 @@ static void *do_pktccops(void *data) ast_debug(3, " S-Num S-type: 0x%.4x len: %i\n", (unsigned)snst, sobjlen); if (snst == 0x0101 ) { recvtrid = ntohs(*((uint16_t *) (sobjp + 4))); - scommand = ntohs(*((uint16_t *) (sobjp + 6))); + scommand = ntohs(*((uint16_t *) (sobjp + 6))); ast_debug(3, " Transaction Identifier command: %i trid %i\n", scommand, recvtrid); } else if (snst == 0x0201) { subscrid = ntohl(*((uint32_t *) (sobjp + 4))); @@ -871,7 +870,7 @@ static void *do_pktccops(void *data) gate->gate_open = NULL; } break; - } + } } } AST_LIST_TRAVERSE_SAFE_END; @@ -942,7 +941,7 @@ static void *do_pktccops(void *data) cmts->state = 2; cmts->katimer = time(NULL); } - } + } if (len <= 0) { ast_debug(3, "COPS: lost connection to %s\n", cmts->name); close(cmts->sfd); @@ -952,7 +951,7 @@ static void *do_pktccops(void *data) cops_freemsg(recmsg); } } - AST_LIST_UNLOCK(&cmts_list); + AST_LIST_UNLOCK(&cmts_list); } if (pktcreload) { ast_debug(3, "Reloading pktccops...\n"); @@ -1057,7 +1056,7 @@ static int load_pktccops_config(void) } else { ast_log(LOG_WARNING, "Unkown option %s in general section of res_ptkccops.conf\n", v->name); } - } + } } else { /* Defaults */ host = NULL; @@ -1069,7 +1068,7 @@ static int load_pktccops_config(void) for (v = ast_variable_browse(config, cat); v; v = v->next) { if (!strcasecmp(v->name, "host")) { - host = v->value; + host = v->value; } else if (!strcasecmp(v->name, "port")) { port = v->value; } else if (!strcasecmp(v->name, "t1")) { @@ -1153,11 +1152,11 @@ static char *pktccops_show_cmtses(struct ast_cli_entry *e, int cmd, struct ast_c struct cops_cmts *cmts; char statedesc[16]; int katimer; - + switch(cmd) { case CLI_INIT: e->command = "pktccops show cmtses"; - e->usage = + e->usage = "Usage: pktccops show cmtses\n" " List PacketCable COPS CMTSes.\n"; @@ -1193,7 +1192,7 @@ static char *pktccops_show_gates(struct ast_cli_entry *e, int cmd, struct ast_cl switch(cmd) { case CLI_INIT: e->command = "pktccops show gates"; - e->usage = + e->usage = "Usage: pktccops show gates\n" " List PacketCable COPS GATEs.\n"; @@ -1224,8 +1223,8 @@ static char *pktccops_show_gates(struct ast_cli_entry *e, int cmd, struct ast_cl } else { ast_copy_string(state_desc, "N/A", sizeof(state_desc)); } - - ast_cli(a->fd, "%-16s 0x%.8x 0x%08x %-10s %10i %10i %u\n", (gate->cmts) ? gate->cmts->name : "null" , gate->gateid, gate->mta, + + ast_cli(a->fd, "%-16s 0x%.8x 0x%08x %-10s %10i %10i %u\n", (gate->cmts) ? gate->cmts->name : "null" , gate->gateid, gate->mta, state_desc, (int) (time(NULL) - gate->allocated), (gate->checked) ? (int) (time(NULL) - gate->checked) : 0, (unsigned int) gate->in_transaction); } AST_LIST_UNLOCK(&cmts_list); @@ -1242,7 +1241,7 @@ static char *pktccops_show_pools(struct ast_cli_entry *e, int cmd, struct ast_cl switch(cmd) { case CLI_INIT: e->command = "pktccops show pools"; - e->usage = + e->usage = "Usage: pktccops show pools\n" " List PacketCable COPS ip pools of MTAs.\n"; @@ -1275,7 +1274,7 @@ static char *pktccops_gatedel(struct ast_cli_entry *e, int cmd, struct ast_cli_a switch (cmd) { case CLI_INIT: e->command = "pktccops gatedel"; - e->usage = + e->usage = "Usage: pktccops gatedel <cmts> <gateid>\n" " Send Gate-Del to cmts.\n"; return NULL; @@ -1295,13 +1294,13 @@ static char *pktccops_gatedel(struct ast_cli_entry *e, int cmd, struct ast_cli_a } } AST_LIST_UNLOCK(&cmts_list); - + if (!found) return CLI_SHOWUSAGE; trid = cops_trid++; if (!sscanf(a->argv[3], "%x", &gateid)) { - ast_cli(a->fd, "bad gate specification (%s)\n", a->argv[3]); + ast_cli(a->fd, "bad gate specification (%s)\n", a->argv[3]); return CLI_SHOWUSAGE; } @@ -1313,7 +1312,7 @@ static char *pktccops_gatedel(struct ast_cli_entry *e, int cmd, struct ast_cli_a break; } } - + if (!found) { ast_cli(a->fd, "gate not found: %s\n", a->argv[3]); return CLI_SHOWUSAGE; @@ -1335,7 +1334,7 @@ static char *pktccops_gateset(struct ast_cli_entry *e, int cmd, struct ast_cli_a switch (cmd) { case CLI_INIT: e->command = "pktccops gateset"; - e->usage = + e->usage = "Usage: pktccops gateset <cmts> <mta> <acctcount> <bitrate> <packet size> <switch ip> <switch port>\n" " Send Gate-Set to cmts.\n"; return NULL; @@ -1386,7 +1385,7 @@ static char *pktccops_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_arg switch (cmd) { case CLI_INIT: e->command = "pktccops set debug {on|off}"; - e->usage = + e->usage = "Usage: pktccops set debug {on|off}\n" " Turn on/off debuging\n"; return NULL; @@ -1473,9 +1472,6 @@ static int load_module(void) ast_cli_register_multiple(cli_pktccops, sizeof(cli_pktccops) / sizeof(struct ast_cli_entry)); restart_pktc_thread(); - /* For Optional API. */ - ast_module_shutdown_ref(AST_MODULE_SELF); - return 0; } @@ -1518,4 +1514,3 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PktcCOPS manager .unload = unload_module, .reload = reload_module, ); - diff --git a/res/res_realtime.c b/res/res_realtime.c index 9e487a83f..9a8e6482c 100644 --- a/res/res_realtime.c +++ b/res/res_realtime.c @@ -23,7 +23,7 @@ * * \author Anthony Minessale <anthmct@yahoo.com> * \author Mark Spencer <markster@digium.com> - * + * * \ingroup applications */ @@ -42,7 +42,7 @@ #include "asterisk/cli.h" -static char *cli_realtime_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +static char *cli_realtime_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { #define CRL_HEADER_FORMAT "%30s %-30s\n" struct ast_variable *var = NULL, *orig_var = NULL; @@ -60,7 +60,7 @@ static char *cli_realtime_load(struct ast_cli_entry *e, int cmd, struct ast_cli_ } - if (a->argc < 5) + if (a->argc < 5) return CLI_SHOWUSAGE; var = ast_load_realtime_all(a->argv[2], a->argv[3], a->argv[4], SENTINEL); @@ -98,7 +98,7 @@ static char *cli_realtime_update(struct ast_cli_entry *e, int cmd, struct ast_cl return NULL; } - if (a->argc < 7) + if (a->argc < 7) return CLI_SHOWUSAGE; res = ast_update_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], SENTINEL); @@ -133,7 +133,7 @@ static char *cli_realtime_update2(struct ast_cli_entry *e, int cmd, struct ast_c return NULL; } - if (a->argc < 7) + if (a->argc < 7) return CLI_SHOWUSAGE; if (a->argc == 7) { diff --git a/res/res_resolver_unbound.c b/res/res_resolver_unbound.c index 3c7805010..25f61509a 100644 --- a/res/res_resolver_unbound.c +++ b/res/res_resolver_unbound.c @@ -142,8 +142,8 @@ static struct aco_type global_option = { .type = ACO_GLOBAL, .name = "general", .item_offset = offsetof(struct unbound_config, global), - .category_match = ACO_WHITELIST, - .category = "^general$", + .category_match = ACO_WHITELIST_EXACT, + .category = "general", }; static struct aco_type *global_options[] = ACO_TYPES(&global_option); diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 273061124..d0e482405 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -71,6 +71,9 @@ #include "asterisk/smoother.h" #include "asterisk/uuid.h" #include "asterisk/test.h" +#ifdef HAVE_PJPROJECT +#include "asterisk/res_pjproject.h" +#endif #define MAX_TIMESTAMP_SKEW 640 @@ -140,7 +143,14 @@ enum strict_rtp_state { STRICT_RTP_CLOSED, /*! Drop all RTP packets not coming from source that was learned */ }; -#define STRICT_RTP_LEARN_TIMEOUT 1500 /*!< milliseconds */ +/*! + * \brief Strict RTP learning timeout time in milliseconds + * + * \note Set to 5 seconds to allow reinvite chains for direct media + * to settle before media actually starts to arrive. There may be a + * reinvite collision involved on the other leg. + */ +#define STRICT_RTP_LEARN_TIMEOUT 5000 #define DEFAULT_STRICT_RTP -1 /*!< Enabled */ #define DEFAULT_ICESUPPORT 1 @@ -249,6 +259,8 @@ struct rtp_learning_info { struct timeval received; /*!< The time of the first received packet */ int max_seq; /*!< The highest sequence number received */ int packets; /*!< The number of remaining packets before the source is accepted */ + /*! Type of media stream carried by the RTP instance */ + enum ast_media_type stream_type; }; #ifdef HAVE_OPENSSL_SRTP @@ -1027,6 +1039,15 @@ static void ast_rtp_ice_set_role(struct ast_rtp_instance *instance, enum ast_rtp } rtp->role = role; + + if (!rtp->ice->real_ice->is_nominating && !rtp->ice->real_ice->is_complete) { + pj_thread_register_check(); + + pj_ice_sess_change_role(rtp->ice->real_ice, role == AST_RTP_ICE_ROLE_CONTROLLED ? + PJ_ICE_SESS_ROLE_CONTROLLED : PJ_ICE_SESS_ROLE_CONTROLLING); + } else { + ast_debug(3, "Not setting ICE role because state is %s\n", rtp->ice->real_ice->is_nominating ? "nominating" : "complete" ); + } } /*! \pre instance is locked */ @@ -3041,8 +3062,7 @@ static int create_new_socket(const char *type, int af) } ast_log(LOG_WARNING, "Unable to allocate %s socket: %s\n", type, strerror(errno)); } else { - long flags = fcntl(sock, F_GETFL); - fcntl(sock, F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(sock, O_NONBLOCK); #ifdef SO_NO_CHECK if (nochecksums) { setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums)); @@ -3089,18 +3109,30 @@ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t info->received = ast_tvnow(); } - /* - * Protect against packet floods by checking that we - * received the packet sequence in at least the minimum - * allowed time. - */ - if (ast_tvzero(info->received)) { - info->received = ast_tvnow(); - } else if (!info->packets && (ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration )) { - /* Packet flood; reset */ - info->packets = learning_min_sequential - 1; - info->received = ast_tvnow(); + switch (info->stream_type) { + case AST_MEDIA_TYPE_UNKNOWN: + case AST_MEDIA_TYPE_AUDIO: + /* + * Protect against packet floods by checking that we + * received the packet sequence in at least the minimum + * allowed time. + */ + if (ast_tvzero(info->received)) { + info->received = ast_tvnow(); + } else if (!info->packets + && ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration) { + /* Packet flood; reset */ + info->packets = learning_min_sequential - 1; + info->received = ast_tvnow(); + } + break; + case AST_MEDIA_TYPE_VIDEO: + case AST_MEDIA_TYPE_IMAGE: + case AST_MEDIA_TYPE_TEXT: + case AST_MEDIA_TYPE_END: + break; } + info->max_seq = seq; return info->packets; @@ -3461,6 +3493,7 @@ static int rtp_allocate_transport(struct ast_rtp_instance *instance, struct ast_ static void rtp_deallocate_transport(struct ast_rtp_instance *instance, struct ast_rtp *rtp) { + int saved_rtp_s = rtp->s; #ifdef HAVE_PJPROJECT struct timeval wait = ast_tvadd(ast_tvnow(), ast_samp2tv(TURN_STATE_WAIT_TIME, 1000)); struct timespec ts = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000, }; @@ -3478,7 +3511,9 @@ static void rtp_deallocate_transport(struct ast_rtp_instance *instance, struct a /* Destroy RTCP if it was being used */ if (rtp->rtcp && rtp->rtcp->s > -1) { - close(rtp->rtcp->s); + if (saved_rtp_s != rtp->rtcp->s) { + close(rtp->rtcp->s); + } rtp->rtcp->s = -1; } @@ -4530,11 +4565,9 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr format = frame->subclass.format; if (ast_format_cmp(rtp->lasttxformat, format) == AST_FORMAT_CMP_NOT_EQUAL) { /* Oh dear, if the format changed we will have to set up a new smoother */ - if (option_debug > 0) { - ast_debug(1, "Ooh, format changed from %s to %s\n", - ast_format_get_name(rtp->lasttxformat), - ast_format_get_name(frame->subclass.format)); - } + ast_debug(1, "Ooh, format changed from %s to %s\n", + ast_format_get_name(rtp->lasttxformat), + ast_format_get_name(frame->subclass.format)); ao2_replace(rtp->lasttxformat, format); if (rtp->smoother) { ast_smoother_free(rtp->smoother); @@ -5163,7 +5196,6 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c unsigned int first_word; /*! True if we have seen an acceptable SSRC to learn the remote RTCP address */ unsigned int ssrc_seen; - int report_counter = 0; struct ast_rtp_rtcp_report_block *report_block; struct ast_frame *f = &ast_null_frame; @@ -5407,7 +5439,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c } return &ast_null_frame; } - rtcp_report->report_block[report_counter] = report_block; + rtcp_report->report_block[0] = report_block; report_block->source_ssrc = ntohl(rtcpheader[i]); report_block->lost_count.packets = ntohl(rtcpheader[i + 1]) & 0x00ffffff; report_block->lost_count.fraction = ((ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24); @@ -5444,7 +5476,6 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c ast_verbose(" DLSR: %4.4f (sec)\n",(double)report_block->dlsr / 65536.0); ast_verbose(" RTT: %4.4f(sec)\n", rtp->rtcp->rtt); } - report_counter++; } /* If and when we handle more than one report block, this should occur outside * this loop. @@ -5469,9 +5500,9 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c /* There's always a single report block stored, here */ struct ast_rtp_rtcp_report *rtcp_report2; report_block = transport_rtp->f.data.ptr + transport_rtp->f.datalen + sizeof(struct ast_rtp_rtcp_report_block *); - memcpy(report_block, rtcp_report->report_block[report_counter-1], sizeof(struct ast_rtp_rtcp_report_block)); + memcpy(report_block, rtcp_report->report_block[0], sizeof(struct ast_rtp_rtcp_report_block)); rtcp_report2 = (struct ast_rtp_rtcp_report *)transport_rtp->f.data.ptr; - rtcp_report2->report_block[report_counter-1] = report_block; + rtcp_report2->report_block[0] = report_block; transport_rtp->f.datalen += sizeof(struct ast_rtp_rtcp_report_block); } transport_rtp->f.offset = AST_FRIENDLY_OFFSET; @@ -5711,7 +5742,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, ast_sockaddr_stringify(&remote_address), strerror(errno)); } else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) { - if (option_debug || rtpdebug) { + if (rtpdebug || DEBUG_ATLEAST(1)) { ast_log(LOG_WARNING, "RTP NAT: Can't write RTP to private " "address %s, waiting for other end to " @@ -5947,6 +5978,15 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc * source and we should switch to it. */ if (!ast_sockaddr_cmp(&rtp->rtp_source_learn.proposed_address, &addr)) { + if (rtp->rtp_source_learn.stream_type == AST_MEDIA_TYPE_UNKNOWN) { + struct ast_rtp_codecs *codecs; + + codecs = ast_rtp_instance_get_codecs(instance); + rtp->rtp_source_learn.stream_type = + ast_rtp_codecs_get_stream_type(codecs); + ast_verb(4, "%p -- Strict RTP qualifying stream type: %s\n", + rtp, ast_codec_media_type2str(rtp->rtp_source_learn.stream_type)); + } if (!rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) { /* Accept the new RTP stream */ ast_verb(4, "%p -- Strict RTP switching source address to %s\n", @@ -6075,13 +6115,14 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc if (ext) { hdrlen += (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2; hdrlen += 4; - if (option_debug) { + if (DEBUG_ATLEAST(1)) { unsigned int profile; profile = (ntohl(rtpheader[3]) & 0xffff0000) >> 16; - if (profile == 0x505a) - ast_debug(1, "Found Zfone extension in RTP stream - zrtp - not supported.\n"); - else - ast_debug(1, "Found unknown RTP Extensions %x\n", profile); + if (profile == 0x505a) { + ast_log(LOG_DEBUG, "Found Zfone extension in RTP stream - zrtp - not supported.\n"); + } else { + ast_log(LOG_DEBUG, "Found unknown RTP Extensions %x\n", profile); + } } } @@ -7337,7 +7378,7 @@ static void rtp_terminate_pjproject(void) pj_thread_destroy(timer_thread); } - pj_caching_pool_destroy(&cachingpool); + ast_pjproject_caching_pool_destroy(&cachingpool); pj_shutdown(); } #endif @@ -7362,7 +7403,7 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } - pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0); + ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0); pool = pj_pool_create(&cachingpool.factory, "timer", 512, 512, NULL); diff --git a/res/res_rtp_multicast.c b/res/res_rtp_multicast.c index 72c53211b..24ab9a591 100644 --- a/res/res_rtp_multicast.c +++ b/res/res_rtp_multicast.c @@ -94,7 +94,7 @@ struct multicast_rtp { unsigned int ssrc; /*! Sequence number, used when creating/sending the RTP packet */ uint16_t seqno; - unsigned int lastts; + unsigned int lastts; struct timeval txcore; struct ast_smoother *smoother; }; diff --git a/res/res_sdp_translator_pjmedia.c b/res/res_sdp_translator_pjmedia.c index 772be272c..676e740bc 100644 --- a/res/res_sdp_translator_pjmedia.c +++ b/res/res_sdp_translator_pjmedia.c @@ -17,6 +17,11 @@ */ #include "asterisk.h" + +#include <pjlib.h> +#include <pjmedia.h> + +#include "asterisk/res_pjproject.h" #include "asterisk/sdp_translator.h" #include "asterisk/sdp_options.h" #include "asterisk/vector.h" @@ -27,10 +32,6 @@ #include "asterisk/module.h" #include "asterisk/sdp.h" -#ifdef HAVE_PJPROJECT -#include <pjlib.h> -#include <pjmedia.h> -#endif /*** MODULEINFO <depend>pjproject</depend> @@ -573,7 +574,7 @@ static int load_module(void) if (ast_sdp_register_translator(&pjmedia_translator)) { return AST_MODULE_LOAD_DECLINE; } - pj_caching_pool_init(&sdp_caching_pool, NULL, 1024 * 1024); + ast_pjproject_caching_pool_init(&sdp_caching_pool, NULL, 1024 * 1024); AST_TEST_REGISTER(pjmedia_to_sdp_test); AST_TEST_REGISTER(sdp_to_pjmedia_test); @@ -583,7 +584,7 @@ static int load_module(void) static int unload_module(void) { ast_sdp_unregister_translator(&pjmedia_translator); - pj_caching_pool_destroy(&sdp_caching_pool); + ast_pjproject_caching_pool_destroy(&sdp_caching_pool); AST_TEST_UNREGISTER(pjmedia_to_sdp_test); AST_TEST_UNREGISTER(sdp_to_pjmedia_test); return 0; @@ -600,4 +601,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJMEDIA SDP Translato .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, + .requires = "res_pjproject", ); diff --git a/res/res_smdi.c b/res/res_smdi.c index 0edabb83c..1d4826a6a 100644 --- a/res/res_smdi.c +++ b/res/res_smdi.c @@ -249,7 +249,7 @@ static void smdi_interface_destroy(void *obj) ast_module_unref(ast_module_info->self); } -/*! +/*! * \internal * \brief Push an SMDI message to the back of an interface's message queue. * \param iface a pointer to the interface to use. @@ -324,10 +324,10 @@ static inline int lock_msg_q(struct ast_smdi_interface *iface, enum smdi_message switch (type) { case SMDI_MWI: return ast_mutex_lock(&iface->mwi_q_lock); - case SMDI_MD: + case SMDI_MD: return ast_mutex_lock(&iface->md_q_lock); } - + return -1; } @@ -375,7 +375,7 @@ static void purge_old_messages(struct ast_smdi_interface *iface, enum smdi_messa struct timeval now = ast_tvnow(); long elapsed = 0; void *msg; - + lock_msg_q(iface, type); msg = unlink_from_msg_q(iface, type); unlock_msg_q(iface, type); @@ -389,7 +389,7 @@ static void purge_old_messages(struct ast_smdi_interface *iface, enum smdi_messa ao2_ref(msg, -1); ast_log(LOG_NOTICE, "Purged expired message from %s SMDI %s message queue. " "Message was %ld milliseconds too old.\n", - iface->name, (type == SMDI_MD) ? "MD" : "MWI", + iface->name, (type == SMDI_MD) ? "MD" : "MWI", elapsed - iface->msg_expiry); lock_msg_q(iface, type); @@ -473,7 +473,7 @@ static void *smdi_msg_find(struct ast_smdi_interface *iface, return msg; } -static void *smdi_message_wait(struct ast_smdi_interface *iface, int timeout, +static void *smdi_message_wait(struct ast_smdi_interface *iface, int timeout, enum smdi_message_type type, const char *search_key, struct ast_flags options) { struct timeval start; @@ -572,7 +572,7 @@ struct ast_smdi_interface * AST_OPTIONAL_API_NAME(ast_smdi_interface_find)(const return iface; } -/*! +/*! * \internal * \brief Read an SMDI message. * @@ -586,9 +586,8 @@ static void *smdi_read(void *iface_p) struct ast_smdi_interface *iface = iface_p; struct ast_smdi_md_message *md_msg; struct ast_smdi_mwi_message *mwi_msg; - char c = '\0'; char *cp = NULL; - int i; + int i, c; int start = 0; /* read an smdi message */ @@ -616,7 +615,14 @@ static void *smdi_read(void *iface_p) /* read the message desk number */ for (i = 0; i < sizeof(md_msg->mesg_desk_num) - 1; i++) { - md_msg->mesg_desk_num[i] = fgetc(iface->file); + c = fgetc(iface->file); + if (c == EOF) { + ast_log(LOG_ERROR, "Unexpected EOF while reading MD message\n"); + ao2_ref(md_msg, -1); + ao2_ref(iface, -1); + return NULL; + } + md_msg->mesg_desk_num[i] = (char) c; ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_num[i]); } @@ -626,7 +632,14 @@ static void *smdi_read(void *iface_p) /* read the message desk terminal number */ for (i = 0; i < sizeof(md_msg->mesg_desk_term) - 1; i++) { - md_msg->mesg_desk_term[i] = fgetc(iface->file); + c = fgetc(iface->file); + if (c == EOF) { + ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n"); + ao2_ref(md_msg, -1); + ao2_ref(iface, -1); + return NULL; + } + md_msg->mesg_desk_term[i] = (char) c; ast_debug(1, "Read a '%c'\n", md_msg->mesg_desk_term[i]); } @@ -635,7 +648,14 @@ static void *smdi_read(void *iface_p) ast_debug(1, "The message desk terminal is '%s'\n", md_msg->mesg_desk_term); /* read the message type */ - md_msg->type = fgetc(iface->file); + c = fgetc(iface->file); + if (c == EOF) { + ast_log(LOG_ERROR, "Unexpected EOF while reading SMDI message\n"); + ao2_ref(md_msg, -1); + ao2_ref(iface, -1); + return NULL; + } + md_msg->type = (char) c; ast_debug(1, "Message type is '%c'\n", md_msg->type); @@ -717,7 +737,7 @@ static void *smdi_read(void *iface_p) /* discard the 'I' (from 'MWI') */ fgetc(iface->file); - + /* read the forwarding station number (may be blank) */ cp = &mwi_msg->fwd_st[0]; for (i = 0; i < sizeof(mwi_msg->fwd_st) - 1; i++) { @@ -740,8 +760,16 @@ static void *smdi_read(void *iface_p) ast_copy_string(mwi_msg->name, mwi_msg->fwd_st, sizeof(mwi_msg->name)); /* read the mwi failure cause */ - for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) - mwi_msg->cause[i] = fgetc(iface->file); + for (i = 0; i < sizeof(mwi_msg->cause) - 1; i++) { + c = fgetc(iface->file); + if (c == EOF) { + ast_log(LOG_ERROR, "Unexpected EOF while reading MWI message\n"); + ao2_ref(mwi_msg, -1); + ao2_ref(iface, -1); + return NULL; + } + mwi_msg->cause[i] = (char) c; + } mwi_msg->cause[sizeof(mwi_msg->cause) - 1] = '\0'; @@ -941,7 +969,7 @@ static int smdi_load(int reload) tcflag_t paritybit = PARENB; /* even parity checking */ tcflag_t charsize = CS7; /* seven bit characters */ int stopbits = 0; /* One stop bit */ - + int msdstrip = 0; /* strip zero digits */ long msg_expiry = SMDI_MSG_EXPIRY_TIME; @@ -1024,7 +1052,7 @@ static int smdi_load(int reload) continue; } } - + if (!(iface = alloc_smdi_interface())) continue; @@ -1052,19 +1080,19 @@ static int smdi_load(int reload) ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno)); continue; } - + /* set the stop bits */ if (stopbits) iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB; /* set two stop bits */ else iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB; /* set one stop bit */ - + /* set the parity */ iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit; - + /* set the character size */ iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize; - + /* commit the desired attributes */ if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) { ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno)); @@ -1130,7 +1158,7 @@ static int smdi_load(int reload) if (ao2_container_count(new_ifaces)) { res = 1; } - + return res; } @@ -1301,7 +1329,7 @@ static int smdi_msg_read(struct ast_channel *chan, const char *cmd, char *data, ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &smdi_msg_datastore_info, args.id); ast_channel_unlock(chan); - + if (!datastore) { ast_log(LOG_WARNING, "No SMDI message found for message ID '%s'\n", args.id); goto return_error; @@ -1351,8 +1379,8 @@ static int _unload_module(int fromload); * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) @@ -1406,9 +1434,6 @@ static int _unload_module(int fromload) smdi_loaded = 0; - /* For Optional API. */ - ast_module_shutdown_ref(AST_MODULE_SELF); - return 0; } diff --git a/res/res_snmp.c b/res/res_snmp.c index f9f064e55..c758bee85 100644 --- a/res/res_snmp.c +++ b/res/res_snmp.c @@ -107,8 +107,8 @@ static int load_config(void) * Module loading including tests for configuration or dependencies. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails - * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the - * configuration file or other non-critical problem return + * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the + * configuration file or other non-critical problem return * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS. */ static int load_module(void) diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index 8b93b57ba..87823be0d 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -334,14 +334,14 @@ static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, voi const char *family_prefix = data; size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */ char family[family_len + 1]; - char tree[prefix_len + sizeof("%")]; + char tree[prefix_len + 1]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); struct ast_db_entry *entry; - snprintf(tree, sizeof(tree), "%.*s%%", (int) prefix_len, prefix); + snprintf(tree, sizeof(tree), "%.*s", (int) prefix_len, prefix); snprintf(family, sizeof(family), "%s/%s", family_prefix, type); - if (!(entries = ast_db_gettree(family, tree))) { + if (!(entries = ast_db_gettree_by_prefix(family, tree))) { return; } diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index a858cbcef..101034009 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -95,7 +95,7 @@ static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data return (ast_store_realtime_fields(config->family, fields) <= 0) ? -1 : 0; } -/*! \brief Internal helper function which returns a filtered objectset. +/*! \brief Internal helper function which returns a filtered objectset. * * The following are filtered out of the objectset: * \li The id field. This is returned to the caller in an out parameter. @@ -176,6 +176,7 @@ static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, if (!id || !(object = ast_sorcery_alloc(sorcery, type, id->value)) || ast_sorcery_objectset_apply(sorcery, object, objectset)) { + ao2_cleanup(object); return NULL; } @@ -233,7 +234,9 @@ static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type); - if (id && (object = ast_sorcery_alloc(sorcery, type, id->value)) && !ast_sorcery_objectset_apply(sorcery, object, objectset)) { + if (id + && (object = ast_sorcery_alloc(sorcery, type, id->value)) + && !ast_sorcery_objectset_apply(sorcery, object, objectset)) { ao2_link(objects, object); } diff --git a/res/res_speech.c b/res/res_speech.c index d6c532971..31ad61acb 100644 --- a/res/res_speech.c +++ b/res/res_speech.c @@ -363,5 +363,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND, + .load_pri = AST_MODPRI_APP_DEPEND - 1, ); diff --git a/res/res_srtp.c b/res/res_srtp.c index 295c332e2..cda1291fa 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -41,7 +41,6 @@ #if HAVE_SRTP_VERSION > 1 # include <srtp2/srtp.h> -# include <srtp2/crypto_types.h> # include "srtp/srtp_compat.h" # include <openssl/rand.h> #else @@ -198,7 +197,7 @@ static struct ast_srtp *res_srtp_new(void) ast_free(srtp); return NULL; } - + srtp->warned = 1; return srtp; @@ -482,7 +481,7 @@ static int ast_srtp_protect(struct ast_srtp *srtp, void **buf, int *len, int rtc if ((*len + SRTP_MAX_TRAILER_LEN) > sizeof(srtp->buf)) { return -1; } - + localbuf = rtcp ? srtp->rtcpbuf : srtp->buf; memcpy(localbuf, *buf, *len); diff --git a/res/res_stasis.c b/res/res_stasis.c index f99dcee37..dcd74141f 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -498,7 +498,8 @@ static void moh_after_bridge_cb(struct ast_channel *chan, void *data) /*! Request a bridge MOH channel */ static struct ast_channel *prepare_bridge_moh_channel(void) { - RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup); + struct ast_channel *chan; + struct ast_format_cap *cap; cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!cap) { @@ -507,7 +508,10 @@ static struct ast_channel *prepare_bridge_moh_channel(void) ast_format_cap_append(cap, ast_format_slin, 0); - return ast_request("Announcer", cap, NULL, NULL, "ARI_MOH", NULL); + chan = ast_request("Announcer", cap, NULL, NULL, "ARI_MOH", NULL); + ao2_ref(cap, -1); + + return chan; } /*! Provides the moh channel with a thread so it can actually play its music */ @@ -599,23 +603,27 @@ static struct ast_channel *bridge_moh_create(struct ast_bridge *bridge) struct ast_channel *stasis_app_bridge_moh_channel(struct ast_bridge *bridge) { - RAII_VAR(struct stasis_app_bridge_channel_wrapper *, moh_wrapper, NULL, ao2_cleanup); + struct ast_channel *chan; + struct stasis_app_bridge_channel_wrapper *moh_wrapper; - { - SCOPED_AO2LOCK(lock, app_bridges_moh); + ao2_lock(app_bridges_moh); + moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (!moh_wrapper) { + chan = bridge_moh_create(bridge); + } + ao2_unlock(app_bridges_moh); - moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_NOLOCK); - if (!moh_wrapper) { - return bridge_moh_create(bridge); - } + if (moh_wrapper) { + chan = ast_channel_get_by_name(moh_wrapper->channel_id); + ao2_ref(moh_wrapper, -1); } - return ast_channel_get_by_name(moh_wrapper->channel_id); + return chan; } int stasis_app_bridge_moh_stop(struct ast_bridge *bridge) { - RAII_VAR(struct stasis_app_bridge_channel_wrapper *, moh_wrapper, NULL, ao2_cleanup); + struct stasis_app_bridge_channel_wrapper *moh_wrapper; struct ast_channel *chan; moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_SEARCH_KEY | OBJ_UNLINK); @@ -624,6 +632,7 @@ int stasis_app_bridge_moh_stop(struct ast_bridge *bridge) } chan = ast_channel_get_by_name(moh_wrapper->channel_id); + ao2_ref(moh_wrapper, -1); if (!chan) { return -1; } @@ -862,25 +871,30 @@ static const struct ast_datastore_info replace_channel_store_info = { static struct replace_channel_store *get_replace_channel_store(struct ast_channel *chan, int no_create) { struct ast_datastore *datastore; + struct replace_channel_store *ret; - SCOPED_CHANNELLOCK(lock, chan); + ast_channel_lock(chan); datastore = ast_channel_datastore_find(chan, &replace_channel_store_info, NULL); - if (!datastore) { - if (no_create) { - return NULL; - } - + if (!datastore && !no_create) { datastore = ast_datastore_alloc(&replace_channel_store_info, NULL); - if (!datastore) { - return NULL; + if (datastore) { + ast_channel_datastore_add(chan, datastore); } - ast_channel_datastore_add(chan, datastore); + } + + if (!datastore) { + ast_channel_unlock(chan); + return NULL; } if (!datastore->data) { datastore->data = ast_calloc(1, sizeof(struct replace_channel_store)); } - return datastore->data; + + ret = datastore->data; + ast_channel_unlock(chan); + + return ret; } int app_set_replace_channel_snapshot(struct ast_channel *chan, struct ast_channel_snapshot *replace_snapshot) @@ -959,9 +973,9 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app int argc, char *argv[], struct ast_channel_snapshot *snapshot, struct ast_channel_snapshot *replace_channel_snapshot) { - RAII_VAR(struct ast_json *, json_blob, NULL, ast_json_unref); + struct ast_json *json_blob; struct ast_json *json_args; - RAII_VAR(struct start_message_blob *, payload, NULL, ao2_cleanup); + struct start_message_blob *payload; struct stasis_message *msg; int i; @@ -986,8 +1000,11 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app "args"); if (!json_blob) { ast_log(LOG_ERROR, "Error packing JSON for StasisStart message\n"); + ao2_ref(payload, -1); return -1; } + payload->blob = json_blob; + /* Append arguments to args array */ json_args = ast_json_object_get(json_blob, "args"); @@ -997,13 +1014,14 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app ast_json_string_create(argv[i])); if (r != 0) { ast_log(LOG_ERROR, "Error appending to StasisStart message\n"); + ao2_ref(payload, -1); return -1; } } - payload->blob = ast_json_ref(json_blob); msg = stasis_message_create(start_message_type(), payload); + ao2_ref(payload, -1); if (!msg) { ast_log(LOG_ERROR, "Error sending StasisStart message\n"); return -1; @@ -1020,9 +1038,9 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app static int send_start_msg(struct stasis_app *app, struct ast_channel *chan, int argc, char *argv[]) { - RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup); - RAII_VAR(struct ast_channel_snapshot *, replace_channel_snapshot, - NULL, ao2_cleanup); + int ret = -1; + struct ast_channel_snapshot *snapshot; + struct ast_channel_snapshot *replace_channel_snapshot; ast_assert(chan != NULL); @@ -1032,10 +1050,13 @@ static int send_start_msg(struct stasis_app *app, struct ast_channel *chan, ast_channel_lock(chan); snapshot = ast_channel_snapshot_create(chan); ast_channel_unlock(chan); - if (!snapshot) { - return -1; + if (snapshot) { + ret = send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot); + ao2_ref(snapshot, -1); } - return send_start_msg_snapshots(chan, app, argc, argv, snapshot, replace_channel_snapshot); + ao2_cleanup(replace_channel_snapshot); + + return ret; } static void remove_masquerade_store(struct ast_channel *chan); @@ -1281,8 +1302,6 @@ static void remove_stasis_end_published(struct ast_channel *chan) int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, char *argv[]) { - SCOPED_MODULE_USE(ast_module_info->self); - RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup); RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink); struct ast_bridge *bridge = NULL; @@ -1478,7 +1497,7 @@ int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc, int stasis_app_send(const char *app_name, struct ast_json *message) { - RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup); + struct stasis_app *app; if (!apps_registry) { return -1; @@ -1494,6 +1513,8 @@ int stasis_app_send(const char *app_name, struct ast_json *message) return -1; } app_send(app, message); + ao2_ref(app, -1); + return 0; } @@ -1528,7 +1549,7 @@ static int append_name(void *obj, void *arg, int flags) struct ao2_container *stasis_app_get_all(void) { - RAII_VAR(struct ao2_container *, apps, NULL, ao2_cleanup); + struct ao2_container *apps; if (!apps_registry) { return NULL; @@ -1541,12 +1562,12 @@ struct ao2_container *stasis_app_get_all(void) ao2_callback(apps_registry, OBJ_NODATA, append_name, apps); - return ao2_bump(apps); + return apps; } static int __stasis_app_register(const char *app_name, stasis_app_cb handler, void *data, int all_events) { - RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup); + struct stasis_app *app; if (!apps_registry) { return -1; @@ -1558,24 +1579,25 @@ static int __stasis_app_register(const char *app_name, stasis_app_cb handler, vo app_update(app, handler, data); } else { app = app_create(app_name, handler, data, all_events ? STASIS_APP_SUBSCRIBE_ALL : STASIS_APP_SUBSCRIBE_MANUAL); - if (app) { - if (all_events) { - struct stasis_app_event_source *source; - SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); + if (!app) { + ao2_unlock(apps_registry); + return -1; + } - AST_LIST_TRAVERSE(&event_sources, source, next) { - if (!source->subscribe) { - continue; - } + if (all_events) { + struct stasis_app_event_source *source; - source->subscribe(app, NULL); + AST_RWLIST_RDLOCK(&event_sources); + AST_LIST_TRAVERSE(&event_sources, source, next) { + if (!source->subscribe) { + continue; } + + source->subscribe(app, NULL); } - ao2_link_flags(apps_registry, app, OBJ_NOLOCK); - } else { - ao2_unlock(apps_registry); - return -1; + AST_RWLIST_UNLOCK(&event_sources); } + ao2_link_flags(apps_registry, app, OBJ_NOLOCK); } /* We lazily clean up the apps_registry, because it's good enough to @@ -1583,6 +1605,7 @@ static int __stasis_app_register(const char *app_name, stasis_app_cb handler, vo */ cleanup(); ao2_unlock(apps_registry); + ao2_ref(app, -1); return 0; } @@ -1598,7 +1621,7 @@ int stasis_app_register_all(const char *app_name, stasis_app_cb handler, void *d void stasis_app_unregister(const char *app_name) { - RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup); + struct stasis_app *app; if (!app_name) { return; @@ -1621,33 +1644,30 @@ void stasis_app_unregister(const char *app_name) * and clean up, just in case */ cleanup(); + + ao2_ref(app, -1); } void stasis_app_register_event_source(struct stasis_app_event_source *obj) { - SCOPED_LOCK(lock, &event_sources, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + AST_RWLIST_WRLOCK(&event_sources); AST_LIST_INSERT_TAIL(&event_sources, obj, next); - /* only need to bump the module ref on non-core sources because the - core ones are [un]registered by this module. */ - if (!stasis_app_is_core_event_source(obj)) { - ast_module_ref(ast_module_info->self); - } + AST_RWLIST_UNLOCK(&event_sources); } void stasis_app_unregister_event_source(struct stasis_app_event_source *obj) { struct stasis_app_event_source *source; - SCOPED_LOCK(lock, &event_sources, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK); + + AST_RWLIST_WRLOCK(&event_sources); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&event_sources, source, next) { if (source == obj) { AST_RWLIST_REMOVE_CURRENT(next); - if (!stasis_app_is_core_event_source(obj)) { - ast_module_unref(ast_module_info->self); - } break; } } AST_RWLIST_TRAVERSE_SAFE_END; + AST_RWLIST_UNLOCK(&event_sources); } /*! @@ -1666,12 +1686,15 @@ static struct ast_json *app_event_sources_to_json( const struct stasis_app *app, struct ast_json *json) { struct stasis_app_event_source *source; - SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); + + AST_RWLIST_RDLOCK(&event_sources); AST_LIST_TRAVERSE(&event_sources, source, next) { if (source->to_json) { source->to_json(app, json); } } + AST_RWLIST_UNLOCK(&event_sources); + return json; } @@ -1686,9 +1709,12 @@ static struct ast_json *stasis_app_object_to_json(struct stasis_app *app) struct ast_json *stasis_app_to_json(const char *app_name) { - RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup); + struct stasis_app *app = find_app_by_name(app_name); + struct ast_json *json = stasis_app_object_to_json(app); - return stasis_app_object_to_json(app); + ao2_cleanup(app); + + return json; } /*! @@ -1705,13 +1731,16 @@ struct ast_json *stasis_app_to_json(const char *app_name) static struct stasis_app_event_source *app_event_source_find(const char *uri) { struct stasis_app_event_source *source; - SCOPED_LOCK(lock, &event_sources, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); + + AST_RWLIST_RDLOCK(&event_sources); AST_LIST_TRAVERSE(&event_sources, source, next) { if (ast_begins_with(uri, source->scheme)) { - return source; + break; } } - return NULL; + AST_RWLIST_UNLOCK(&event_sources); + + return source; } /*! @@ -1746,25 +1775,32 @@ static enum stasis_app_subscribe_res app_handle_subscriptions( int event_sources_count, struct ast_json **json, app_subscription_handler handler) { - RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup); + struct stasis_app *app = find_app_by_name(app_name); int i; + ast_assert(handler != NULL); + if (!app) { return STASIS_ASR_APP_NOT_FOUND; } for (i = 0; i < event_sources_count; ++i) { const char *uri = event_source_uris[i]; - enum stasis_app_subscribe_res res = STASIS_ASR_INTERNAL_ERROR; struct stasis_app_event_source *event_source; + enum stasis_app_subscribe_res res; - if (!(event_source = app_event_source_find(uri))) { + event_source = app_event_source_find(uri); + if (!event_source) { ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri); + ao2_ref(app, -1); + return STASIS_ASR_EVENT_SOURCE_BAD_SCHEME; } - if (handler && - ((res = handler(app, uri, event_source)))) { + res = handler(app, uri, event_source); + if (res != STASIS_ASR_OK) { + ao2_ref(app, -1); + return res; } } @@ -1774,13 +1810,15 @@ static enum stasis_app_subscribe_res app_handle_subscriptions( *json = stasis_app_object_to_json(app); } + ao2_ref(app, -1); + return STASIS_ASR_OK; } enum stasis_app_subscribe_res stasis_app_subscribe_channel(const char *app_name, struct ast_channel *chan) { - RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup); + struct stasis_app *app = find_app_by_name(app_name); int res; if (!app) { @@ -1790,6 +1828,8 @@ enum stasis_app_subscribe_res stasis_app_subscribe_channel(const char *app_name, ast_debug(3, "%s: Subscribing to %s\n", app_name, ast_channel_uniqueid(chan)); res = app_subscribe_channel(app, chan); + ao2_ref(app, -1); + if (res != 0) { ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n", app_name, ast_channel_uniqueid(chan)); @@ -1892,12 +1932,10 @@ enum stasis_app_user_event_res stasis_app_user_event(const char *app_name, struct ast_json *json_variables) { RAII_VAR(struct stasis_app *, app, find_app_by_name(app_name), ao2_cleanup); - RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); - RAII_VAR(struct ast_multi_object_blob *, multi, NULL, ao2_cleanup); - RAII_VAR(void *, obj, NULL, ao2_cleanup); - RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); + struct ast_json *blob = NULL; + struct ast_multi_object_blob *multi; + struct stasis_message *message; enum stasis_app_user_event_res res = STASIS_APP_USER_INTERNAL_ERROR; - struct ast_json *json_value; int have_channel = 0; int i; @@ -1910,23 +1948,29 @@ enum stasis_app_user_event_res stasis_app_user_event(const char *app_name, return res; } - blob = json_variables; - if (!blob) { - blob = ast_json_pack("{}"); + if (json_variables) { + struct ast_json *json_value = ast_json_string_create(event_name); + + if (json_value && !ast_json_object_set(json_variables, "eventname", json_value)) { + blob = ast_json_ref(json_variables); + } } else { - ast_json_ref(blob); - } - json_value = ast_json_string_create(event_name); - if (!json_value) { - ast_log(LOG_ERROR, "unable to create json string\n"); - return res; + blob = ast_json_pack("{s: s}", "eventname", event_name); } - if (ast_json_object_set(blob, "eventname", json_value)) { - ast_log(LOG_ERROR, "unable to set eventname to blob\n"); + + if (!blob) { + ast_log(LOG_ERROR, "Failed to initialize blob\n"); + return res; } multi = ast_multi_object_blob_create(blob); + ast_json_unref(blob); + if (!multi) { + ast_log(LOG_ERROR, "Failed to initialize multi\n"); + + return res; + } for (i = 0; i < sources_count; ++i) { const char *uri = source_uris[i]; @@ -1945,16 +1989,22 @@ enum stasis_app_user_event_res stasis_app_user_event(const char *app_name, snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL); } else { ast_log(LOG_WARNING, "Invalid scheme: %s\n", uri); + ao2_ref(multi, -1); + return STASIS_APP_USER_EVENT_SOURCE_BAD_SCHEME; } if (!snapshot) { ast_log(LOG_ERROR, "Unable to get snapshot for %s\n", uri); + ao2_ref(multi, -1); + return STASIS_APP_USER_EVENT_SOURCE_NOT_FOUND; } ast_multi_object_blob_add(multi, type, snapshot); } message = stasis_message_create(ast_multi_user_event_type(), multi); + ao2_ref(multi, -1); + if (!message) { ast_log(LOG_ERROR, "Unable to create stasis user event message\n"); return res; @@ -1971,20 +2021,11 @@ enum stasis_app_user_event_res stasis_app_user_event(const char *app_name, if (have_channel) { stasis_publish(ast_manager_get_topic(), message); } + ao2_ref(message, -1); return STASIS_APP_USER_OK; } -void stasis_app_ref(void) -{ - ast_module_ref(ast_module_info->self); -} - -void stasis_app_unref(void) -{ - ast_module_unref(ast_module_info->self); -} - static int unload_module(void) { stasis_app_unregister_event_sources(); @@ -1992,6 +2033,9 @@ static int unload_module(void) messaging_cleanup(); cleanup(); + + stasis_app_control_shutdown(); + ao2_cleanup(apps_registry); apps_registry = NULL; @@ -2007,8 +2051,6 @@ static int unload_module(void) ao2_cleanup(app_bridges_playback); app_bridges_playback = NULL; - stasis_app_control_shutdown(); - STASIS_MESSAGE_TYPE_CLEANUP(end_message_type); STASIS_MESSAGE_TYPE_CLEANUP(start_message_type); @@ -2036,9 +2078,14 @@ static int channel_sanitizer(const struct ast_channel *chan) /* \brief Sanitization callback for channel unique IDs */ static int channel_id_sanitizer(const char *id) { - RAII_VAR(struct ast_channel_snapshot *, snapshot, ast_channel_snapshot_get_latest(id), ao2_cleanup); + struct ast_channel_snapshot *snapshot; + int ret; + + snapshot = ast_channel_snapshot_get_latest(id); + ret = channel_snapshot_sanitizer(snapshot); + ao2_cleanup(snapshot); - return channel_snapshot_sanitizer(snapshot); + return ret; } /* \brief Sanitization callbacks for communication to Stasis applications */ @@ -2155,8 +2202,8 @@ static int load_module(void) return AST_MODULE_LOAD_SUCCESS; } -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application support", - .load_pri = AST_MODPRI_APP_DEPEND, +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis application support", + .load_pri = AST_MODPRI_APP_DEPEND - 1, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, diff --git a/res/res_stasis_answer.c b/res/res_stasis_answer.c index 407a63135..6ec50c81b 100644 --- a/res/res_stasis_answer.c +++ b/res/res_stasis_answer.c @@ -73,5 +73,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis applicatio .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_stasis" + .requires = "res_stasis", ); diff --git a/res/res_stasis_device_state.c b/res/res_stasis_device_state.c index 6527af4a6..be09b15ad 100644 --- a/res/res_stasis_device_state.c +++ b/res/res_stasis_device_state.c @@ -482,5 +482,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis applicatio .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_stasis" + .requires = "res_stasis", ); diff --git a/res/res_stasis_mailbox.c b/res/res_stasis_mailbox.c index 5ed061de2..3f6bede8f 100644 --- a/res/res_stasis_mailbox.c +++ b/res/res_stasis_mailbox.c @@ -143,17 +143,11 @@ enum stasis_mailbox_result stasis_app_mailbox_delete( static int load_module(void) { - /* Must be done first */ - ast_mwi_external_ref(); - return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { - /* Must be done last */ - ast_mwi_external_unref(); - return 0; } @@ -161,5 +155,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis applicatio .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_stasis,res_mwi_external" + .requires = "res_stasis,res_mwi_external" ); diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index ca0446b89..5b8256fc4 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -759,5 +759,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis applicatio .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_stasis,res_stasis_recording" + .requires = "res_stasis,res_stasis_recording" ); diff --git a/res/res_stasis_recording.c b/res/res_stasis_recording.c index 56984cb40..17213aa24 100644 --- a/res/res_stasis_recording.c +++ b/res/res_stasis_recording.c @@ -655,6 +655,6 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_stasis", + .requires = "res_stasis", .load_pri = AST_MODPRI_APP_DEPEND ); diff --git a/res/res_stasis_snoop.c b/res/res_stasis_snoop.c index f797a9b94..b234de111 100644 --- a/res/res_stasis_snoop.c +++ b/res/res_stasis_snoop.c @@ -445,5 +445,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis applicatio .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .nonoptreq = "res_stasis" + .requires = "res_stasis", ); diff --git a/res/res_statsd.c b/res/res_statsd.c index aee0bcd5a..3e0815218 100644 --- a/res/res_statsd.c +++ b/res/res_statsd.c @@ -231,8 +231,8 @@ static struct aco_type global_option = { .type = ACO_GLOBAL, .name = "global", .item_offset = offsetof(struct conf, global), - .category = "^general$", - .category_match = ACO_WHITELIST + .category = "general", + .category_match = ACO_WHITELIST_EXACT, }; static struct aco_type *global_options[] = ACO_TYPES(&global_option); @@ -353,9 +353,6 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } - /* For Optional API. */ - ast_module_shutdown_ref(AST_MODULE_SELF); - return AST_MODULE_LOAD_SUCCESS; } @@ -381,13 +378,13 @@ static int reload_module(void) } } -/* The priority of this module is set to be as low as possible, since it could - * be used by any other sort of module. +/* The priority of this module is set just after realtime, since it loads + * configuration and could be used by any other sort of module. */ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Statsd client support", .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload_module, - .load_pri = 0, + .load_pri = AST_MODPRI_REALTIME_DRIVER + 5, ); diff --git a/res/res_timing_dahdi.c b/res/res_timing_dahdi.c index af2087599..c49f057ac 100644 --- a/res/res_timing_dahdi.c +++ b/res/res_timing_dahdi.c @@ -16,11 +16,11 @@ * at the top of the source tree. */ -/*! +/*! * \file * \author Russell Bryant <russell@digium.com> * - * \brief DAHDI timing interface + * \brief DAHDI timing interface */ /*** MODULEINFO @@ -154,7 +154,7 @@ static enum ast_timer_event dahdi_timer_get_event(void *data) return AST_TIMING_EVENT_CONTINUOUS; case DAHDI_EVENT_TIMER_EXPIRED: default: - return AST_TIMING_EVENT_EXPIRED; + return AST_TIMING_EVENT_EXPIRED; } } @@ -176,7 +176,7 @@ static int dahdi_test_timer(void) { int fd; int x = 160; - + fd = open("/dev/dahdi/timer", O_RDWR); if (fd < 0) { diff --git a/res/res_timing_pthread.c b/res/res_timing_pthread.c index 09952f929..bcc9eb0e8 100644 --- a/res/res_timing_pthread.c +++ b/res/res_timing_pthread.c @@ -130,11 +130,9 @@ static void *pthread_timer_open(void) } for (i = 0; i < ARRAY_LEN(timer->pipe); ++i) { - int flags = fcntl(timer->pipe[i], F_GETFL); - flags |= O_NONBLOCK; - fcntl(timer->pipe[i], F_SETFL, flags); + ast_fd_set_flags(timer->pipe[i], O_NONBLOCK); } - + ao2_lock(pthread_timers); if (!ao2_container_count(pthread_timers)) { ast_mutex_lock(&timing_thread.lock); diff --git a/res/res_xmpp.c b/res/res_xmpp.c index f683557a5..b72581fa5 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -820,8 +820,8 @@ static struct aco_type global_option = { .type = ACO_GLOBAL, .name = "global", .item_offset = offsetof(struct xmpp_config, global), - .category_match = ACO_WHITELIST, - .category = "^general$", + .category_match = ACO_WHITELIST_EXACT, + .category = "general", }; struct aco_type *global_options[] = ACO_TYPES(&global_option); @@ -829,8 +829,8 @@ struct aco_type *global_options[] = ACO_TYPES(&global_option); static struct aco_type client_option = { .type = ACO_ITEM, .name = "client", - .category_match = ACO_BLACKLIST, - .category = "^(general)$", + .category_match = ACO_BLACKLIST_EXACT, + .category = "general", .item_alloc = ast_xmpp_client_config_alloc, .item_find = xmpp_config_find, .item_prelink = xmpp_config_prelink, diff --git a/res/snmp/agent.c b/res/snmp/agent.c index b8fcb07f6..2a0eb7552 100644 --- a/res/snmp/agent.c +++ b/res/snmp/agent.c @@ -555,7 +555,7 @@ static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_ ast_variables_destroy(channel_types); if (next == NULL || tech == NULL) return NULL; - + switch (vp->magic) { case ASTCHANTYPEINDEX: long_ret = name[*length - 1]; diff --git a/res/stasis/app.c b/res/stasis/app.c index a1ef5c0b6..18ac7d6ed 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -112,20 +112,19 @@ static void forwards_unsubscribe(struct app_forwards *forwards) static struct app_forwards *forwards_create(struct stasis_app *app, const char *id) { - RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup); + struct app_forwards *forwards; if (!app || ast_strlen_zero(id)) { return NULL; } - forwards = ao2_alloc(sizeof(*forwards) + strlen(id) + 1, forwards_dtor); + forwards = ao2_t_alloc(sizeof(*forwards) + strlen(id) + 1, forwards_dtor, id); if (!forwards) { return NULL; } - strcpy(forwards->id, id); + strcpy(forwards->id, id); /* SAFE */ - ao2_ref(forwards, +1); return forwards; } @@ -335,7 +334,7 @@ static void sub_default_handler(void *data, struct stasis_subscription *sub, struct stasis_message *message) { struct stasis_app *app = data; - RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); + struct ast_json *json; if (stasis_subscription_final_message(sub, message)) { ao2_cleanup(app); @@ -352,6 +351,7 @@ static void sub_default_handler(void *data, struct stasis_subscription *sub, } app_send(app, json); + ast_json_unref(json); } /*! \brief Typedef for callbacks that get called on channel snapshot updates */ @@ -554,11 +554,12 @@ static void sub_channel_update_handler(void *data, stasis_message_timestamp(message); for (i = 0; i < ARRAY_LEN(channel_monitors); ++i) { - RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref); + struct ast_json *msg; msg = channel_monitors[i](old_snapshot, new_snapshot, tv); if (msg) { app_send(app, msg); + ast_json_unref(msg); } } @@ -586,7 +587,7 @@ static struct ast_json *simple_endpoint_event( static int message_received_handler(const char *endpoint_id, struct ast_json *json_msg, void *pvt) { - RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup); + struct ast_endpoint_snapshot *snapshot; struct ast_json *json_endpoint; struct ast_json *message; struct stasis_app *app = pvt; @@ -610,6 +611,7 @@ static int message_received_handler(const char *endpoint_id, struct ast_json *js } json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer()); + ao2_ref(snapshot, -1); if (!json_endpoint) { return -1; } @@ -631,7 +633,6 @@ static void sub_endpoint_update_handler(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct stasis_app *app = data; struct stasis_cache_update *update; struct ast_endpoint_snapshot *new_snapshot; @@ -648,6 +649,8 @@ static void sub_endpoint_update_handler(void *data, old_snapshot = stasis_message_data(update->old_snapshot); if (new_snapshot) { + struct ast_json *json; + tv = stasis_message_timestamp(update->new_snapshot); json = simple_endpoint_event("EndpointStateChange", new_snapshot, tv); @@ -656,6 +659,7 @@ static void sub_endpoint_update_handler(void *data, } app_send(app, json); + ast_json_unref(json); } if (!new_snapshot && old_snapshot) { @@ -683,7 +687,7 @@ static void sub_bridge_update_handler(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); + struct ast_json *json = NULL; struct stasis_app *app = data; struct stasis_cache_update *update; struct ast_bridge_snapshot *new_snapshot; @@ -717,6 +721,7 @@ static void sub_bridge_update_handler(void *data, if (json) { app_send(app, json); + ast_json_unref(json); } if (!new_snapshot && old_snapshot) { @@ -1019,7 +1024,7 @@ void app_send(struct stasis_app *app, struct ast_json *message) { stasis_app_cb handler; char eid[20]; - RAII_VAR(void *, data, NULL, ao2_cleanup); + void *data; if (ast_json_object_set(message, "asterisk_id", ast_json_string_create( ast_eid_to_str(eid, sizeof(eid), &ast_eid_default)))) { @@ -1028,37 +1033,36 @@ void app_send(struct stasis_app *app, struct ast_json *message) } /* Copy off mutable state with lock held */ - { - SCOPED_AO2LOCK(lock, app); - handler = app->handler; - if (app->data) { - ao2_ref(app->data, +1); - data = app->data; - } - /* Name is immutable; no need to copy */ - } - - if (!handler) { + ao2_lock(app); + handler = app->handler; + data = ao2_bump(app->data); + ao2_unlock(app); + /* Name is immutable; no need to copy */ + + if (handler) { + handler(data, app->name, message); + } else { ast_verb(3, "Inactive Stasis app '%s' missed message\n", app->name); - return; } - - handler(data, app->name, message); + ao2_cleanup(data); } void app_deactivate(struct stasis_app *app) { - SCOPED_AO2LOCK(lock, app); + ao2_lock(app); + ast_verb(1, "Deactivating Stasis app '%s'\n", app->name); app->handler = NULL; ao2_cleanup(app->data); app->data = NULL; + + ao2_unlock(app); } void app_shutdown(struct stasis_app *app) { - SCOPED_AO2LOCK(lock, app); + ao2_lock(app); ast_assert(app_is_finished(app)); @@ -1068,27 +1072,37 @@ void app_shutdown(struct stasis_app *app) app->bridge_router = NULL; stasis_message_router_unsubscribe(app->endpoint_router); app->endpoint_router = NULL; + + ao2_unlock(app); } int app_is_active(struct stasis_app *app) { - SCOPED_AO2LOCK(lock, app); - return app->handler != NULL; + int ret; + + ao2_lock(app); + ret = app->handler != NULL; + ao2_unlock(app); + + return ret; } int app_is_finished(struct stasis_app *app) { - SCOPED_AO2LOCK(lock, app); + int ret; + + ao2_lock(app); + ret = app->handler == NULL && ao2_container_count(app->forwards) == 0; + ao2_unlock(app); - return app->handler == NULL && ao2_container_count(app->forwards) == 0; + return ret; } void app_update(struct stasis_app *app, stasis_app_cb handler, void *data) { - SCOPED_AO2LOCK(lock, app); - + ao2_lock(app); if (app->handler && app->data) { - RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref); + struct ast_json *msg; ast_verb(1, "Replacing Stasis app '%s'\n", app->name); @@ -1097,17 +1111,15 @@ void app_update(struct stasis_app *app, stasis_app_cb handler, void *data) "application", app->name); if (msg) { app_send(app, msg); + ast_json_unref(msg); } } else { ast_verb(1, "Activating Stasis app '%s'\n", app->name); } app->handler = handler; - ao2_cleanup(app->data); - if (data) { - ao2_ref(data, +1); - } - app->data = data; + ao2_replace(app->data, data); + ao2_unlock(app); } const char *stasis_app_name(const struct stasis_app *app) @@ -1184,68 +1196,72 @@ void stasis_app_to_cli(const struct stasis_app *app, struct ast_cli_args *a) struct ast_json *app_to_json(const struct stasis_app *app) { - RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); + struct ast_json *json; struct ast_json *channels; struct ast_json *bridges; struct ast_json *endpoints; struct ao2_iterator i; - void *obj; + struct app_forwards *forwards; json = ast_json_pack("{s: s, s: [], s: [], s: []}", "name", app->name, "channel_ids", "bridge_ids", "endpoint_ids"); + if (!json) { + return NULL; + } channels = ast_json_object_get(json, "channel_ids"); bridges = ast_json_object_get(json, "bridge_ids"); endpoints = ast_json_object_get(json, "endpoint_ids"); i = ao2_iterator_init(app->forwards, 0); - while ((obj = ao2_iterator_next(&i))) { - RAII_VAR(struct app_forwards *, forwards, obj, ao2_cleanup); - RAII_VAR(struct ast_json *, id, NULL, ast_json_unref); - int append_res = -1; - - id = ast_json_string_create(forwards->id); + while ((forwards = ao2_iterator_next(&i))) { + struct ast_json *array = NULL; + int append_res; switch (forwards->forward_type) { case FORWARD_CHANNEL: - append_res = ast_json_array_append(channels, - ast_json_ref(id)); + array = channels; break; case FORWARD_BRIDGE: - append_res = ast_json_array_append(bridges, - ast_json_ref(id)); + array = bridges; break; case FORWARD_ENDPOINT: - append_res = ast_json_array_append(endpoints, - ast_json_ref(id)); + array = endpoints; break; } + /* If forward_type value is unexpected this will safely return an error. */ + append_res = ast_json_array_append(array, ast_json_string_create(forwards->id)); + ao2_ref(forwards, -1); + if (append_res != 0) { ast_log(LOG_ERROR, "Error building response\n"); ao2_iterator_destroy(&i); + ast_json_unref(json); + return NULL; } } ao2_iterator_destroy(&i); - return ast_json_ref(json); + return json; } int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan) { struct app_forwards *forwards; - SCOPED_AO2LOCK(lock, app->forwards); - int res; if (!app) { return -1; } + ao2_lock(app->forwards); /* If subscribed to all, don't subscribe again */ forwards = ao2_find(app->forwards, CHANNEL_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (forwards) { + ao2_unlock(app->forwards); ao2_ref(forwards, -1); + return 0; } @@ -1253,16 +1269,21 @@ int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan) chan ? ast_channel_uniqueid(chan) : CHANNEL_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { + int res; + /* Forwards not found, create one */ forwards = forwards_create_channel(app, chan); if (!forwards) { + ao2_unlock(app->forwards); + return -1; } - res = ao2_link_flags(app->forwards, forwards, - OBJ_NOLOCK); + res = ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); if (!res) { + ao2_unlock(app->forwards); ao2_ref(forwards, -1); + return -1; } } @@ -1273,7 +1294,9 @@ int app_subscribe_channel(struct stasis_app *app, struct ast_channel *chan) forwards->interested, app->name); + ao2_unlock(app->forwards); ao2_ref(forwards, -1); + return 0; } @@ -1284,8 +1307,7 @@ static int subscribe_channel(struct stasis_app *app, void *obj) static int unsubscribe(struct stasis_app *app, const char *kind, const char *id, int terminate) { - RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup); - SCOPED_AO2LOCK(lock, app->forwards); + struct app_forwards *forwards; if (!id) { if (!strcmp(kind, "bridge")) { @@ -1300,8 +1322,10 @@ static int unsubscribe(struct stasis_app *app, const char *kind, const char *id, } } + ao2_lock(app->forwards); forwards = ao2_find(app->forwards, id, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { + ao2_unlock(app->forwards); ast_debug(3, "App '%s' not subscribed to %s '%s'\n", app->name, kind, id); return -1; } @@ -1320,6 +1344,8 @@ static int unsubscribe(struct stasis_app *app, const char *kind, const char *id, messaging_app_unsubscribe_endpoint(app->name, id); } } + ao2_unlock(app->forwards); + ao2_ref(forwards, -1); return 0; } @@ -1344,12 +1370,14 @@ int app_unsubscribe_channel_id(struct stasis_app *app, const char *channel_id) int app_is_subscribed_channel_id(struct stasis_app *app, const char *channel_id) { - RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup); + struct app_forwards *forwards; if (ast_strlen_zero(channel_id)) { channel_id = CHANNEL_ALL; } forwards = ao2_find(app->forwards, channel_id, OBJ_SEARCH_KEY); + ao2_cleanup(forwards); + return forwards != NULL; } @@ -1369,28 +1397,42 @@ struct stasis_app_event_source channel_event_source = { int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge) { struct app_forwards *forwards; - SCOPED_AO2LOCK(lock, app->forwards); if (!app) { return -1; } + ao2_lock(app->forwards); /* If subscribed to all, don't subscribe again */ forwards = ao2_find(app->forwards, BRIDGE_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (forwards) { + ao2_unlock(app->forwards); ao2_ref(forwards, -1); + return 0; } - forwards = ao2_find(app->forwards, bridge ? bridge->uniqueid : BRIDGE_ALL, + forwards = ao2_find(app->forwards, + bridge ? bridge->uniqueid : BRIDGE_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { + int res; + /* Forwards not found, create one */ forwards = forwards_create_bridge(app, bridge); if (!forwards) { + ao2_unlock(app->forwards); + + return -1; + } + + res = ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); + if (!res) { + ao2_unlock(app->forwards); + ao2_ref(forwards, -1); + return -1; } - ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); } ++forwards->interested; @@ -1399,7 +1441,9 @@ int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge) forwards->interested, app->name); + ao2_unlock(app->forwards); ao2_ref(forwards, -1); + return 0; } @@ -1429,25 +1473,15 @@ int app_unsubscribe_bridge_id(struct stasis_app *app, const char *bridge_id) int app_is_subscribed_bridge_id(struct stasis_app *app, const char *bridge_id) { struct app_forwards *forwards; - SCOPED_AO2LOCK(lock, app->forwards); - - forwards = ao2_find(app->forwards, BRIDGE_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); - if (forwards) { - ao2_ref(forwards, -1); - return 1; - } if (ast_strlen_zero(bridge_id)) { bridge_id = BRIDGE_ALL; } - forwards = ao2_find(app->forwards, bridge_id, OBJ_SEARCH_KEY | OBJ_NOLOCK); - if (forwards) { - ao2_ref(forwards, -1); - return 1; - } + forwards = ao2_find(app->forwards, bridge_id, OBJ_SEARCH_KEY); + ao2_cleanup(forwards); - return 0; + return forwards != NULL; } static void *bridge_find(const struct stasis_app *app, const char *id) @@ -1466,16 +1500,18 @@ struct stasis_app_event_source bridge_event_source = { int app_subscribe_endpoint(struct stasis_app *app, struct ast_endpoint *endpoint) { struct app_forwards *forwards; - SCOPED_AO2LOCK(lock, app->forwards); if (!app) { return -1; } + ao2_lock(app->forwards); /* If subscribed to all, don't subscribe again */ forwards = ao2_find(app->forwards, ENDPOINT_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (forwards) { + ao2_unlock(app->forwards); ao2_ref(forwards, -1); + return 0; } @@ -1483,12 +1519,23 @@ int app_subscribe_endpoint(struct stasis_app *app, struct ast_endpoint *endpoint endpoint ? ast_endpoint_get_id(endpoint) : ENDPOINT_ALL, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!forwards) { + int res; + /* Forwards not found, create one */ forwards = forwards_create_endpoint(app, endpoint); if (!forwards) { + ao2_unlock(app->forwards); + + return -1; + } + + res = ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); + if (!res) { + ao2_unlock(app->forwards); + ao2_ref(forwards, -1); + return -1; } - ao2_link_flags(app->forwards, forwards, OBJ_NOLOCK); /* Subscribe for messages */ messaging_app_subscribe_endpoint(app->name, endpoint, &message_received_handler, app); @@ -1500,7 +1547,9 @@ int app_subscribe_endpoint(struct stasis_app *app, struct ast_endpoint *endpoint forwards->interested, app->name); + ao2_unlock(app->forwards); ao2_ref(forwards, -1); + return 0; } @@ -1520,12 +1569,14 @@ int app_unsubscribe_endpoint_id(struct stasis_app *app, const char *endpoint_id) int app_is_subscribed_endpoint_id(struct stasis_app *app, const char *endpoint_id) { - RAII_VAR(struct app_forwards *, forwards, NULL, ao2_cleanup); + struct app_forwards *forwards; if (ast_strlen_zero(endpoint_id)) { endpoint_id = ENDPOINT_ALL; } forwards = ao2_find(app->forwards, endpoint_id, OBJ_SEARCH_KEY); + ao2_cleanup(forwards); + return forwards != NULL; } @@ -1549,18 +1600,9 @@ void stasis_app_register_event_sources(void) stasis_app_register_event_source(&endpoint_event_source); } -int stasis_app_is_core_event_source(struct stasis_app_event_source *obj) -{ - return obj == &endpoint_event_source || - obj == &bridge_event_source || - obj == &channel_event_source; -} - void stasis_app_unregister_event_sources(void) { stasis_app_unregister_event_source(&endpoint_event_source); stasis_app_unregister_event_source(&bridge_event_source); stasis_app_unregister_event_source(&channel_event_source); } - - diff --git a/res/stasis/command.c b/res/stasis/command.c index 05ebd7b1d..83a1a4c23 100644 --- a/res/stasis/command.c +++ b/res/stasis/command.c @@ -76,21 +76,26 @@ struct stasis_app_command *command_create( void command_complete(struct stasis_app_command *command, int retval) { - SCOPED_MUTEX(lock, &command->lock); - + ast_mutex_lock(&command->lock); command->is_done = 1; command->retval = retval; ast_cond_signal(&command->condition); + ast_mutex_unlock(&command->lock); } int command_join(struct stasis_app_command *command) { - SCOPED_MUTEX(lock, &command->lock); + int ret; + + ast_mutex_lock(&command->lock); while (!command->is_done) { ast_cond_wait(&command->condition, &command->lock); } - return command->retval; + ret = command->retval; + ast_mutex_unlock(&command->lock); + + return ret; } void command_invoke(struct stasis_app_command *command, diff --git a/res/stasis/control.c b/res/stasis/control.c index dc005a1e5..b4fd69fb3 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -148,8 +148,9 @@ static void app_control_register_rule( struct stasis_app_control *control, struct app_control_rules *list, struct stasis_app_control_rule *obj) { - SCOPED_AO2LOCK(lock, control->command_queue); + ao2_lock(control->command_queue); AST_LIST_INSERT_TAIL(list, obj, next); + ao2_unlock(control->command_queue); } static void app_control_unregister_rule( @@ -157,7 +158,8 @@ static void app_control_unregister_rule( struct app_control_rules *list, struct stasis_app_control_rule *obj) { struct stasis_app_control_rule *rule; - SCOPED_AO2LOCK(lock, control->command_queue); + + ao2_lock(control->command_queue); AST_RWLIST_TRAVERSE_SAFE_BEGIN(list, rule, next) { if (rule == obj) { AST_RWLIST_REMOVE_CURRENT(next); @@ -165,6 +167,7 @@ static void app_control_unregister_rule( } } AST_RWLIST_TRAVERSE_SAFE_END; + ao2_unlock(control->command_queue); } /*! @@ -508,9 +511,10 @@ static int app_control_mute(struct stasis_app_control *control, struct ast_channel *chan, void *data) { struct stasis_app_control_mute_data *mute_data = data; - SCOPED_CHANNELLOCK(lockvar, chan); + ast_channel_lock(chan); ast_channel_suppress(control->channel, mute_data->direction, mute_data->frametype); + ast_channel_unlock(chan); return 0; } @@ -535,9 +539,10 @@ static int app_control_unmute(struct stasis_app_control *control, struct ast_channel *chan, void *data) { struct stasis_app_control_mute_data *mute_data = data; - SCOPED_CHANNELLOCK(lockvar, chan); + ast_channel_lock(chan); ast_channel_unsuppress(control->channel, mute_data->direction, mute_data->frametype); + ast_channel_unlock(chan); return 0; } @@ -746,7 +751,7 @@ void stasis_app_control_silence_stop(struct stasis_app_control *control) struct ast_channel_snapshot *stasis_app_control_get_snapshot( const struct stasis_app_control *control) { - RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct stasis_message *msg; struct ast_channel_snapshot *snapshot; msg = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(), @@ -759,6 +764,8 @@ struct ast_channel_snapshot *stasis_app_control_get_snapshot( ast_assert(snapshot != NULL); ao2_ref(snapshot, +1); + ao2_ref(msg, -1); + return snapshot; } @@ -767,7 +774,8 @@ static int app_send_command_on_condition(struct stasis_app_control *control, command_data_destructor_fn data_destructor, app_command_can_exec_cb can_exec_fn) { - RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup); + int ret; + struct stasis_app_command *command; if (control == NULL || control->is_done) { /* If exec_command_on_condition fails, it calls the data_destructor. @@ -787,7 +795,10 @@ static int app_send_command_on_condition(struct stasis_app_control *control, return -1; } - return command_join(command); + ret = command_join(command); + ao2_ref(command, -1); + + return ret; } int stasis_app_send_command(struct stasis_app_control *control, @@ -800,7 +811,7 @@ int stasis_app_send_command_async(struct stasis_app_control *control, stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor) { - RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup); + struct stasis_app_command *command; if (control == NULL || control->is_done) { /* If exec_command fails, it calls the data_destructor. In order to @@ -818,18 +829,24 @@ int stasis_app_send_command_async(struct stasis_app_control *control, if (!command) { return -1; } + ao2_ref(command, -1); return 0; } struct ast_bridge *stasis_app_get_bridge(struct stasis_app_control *control) { + struct ast_bridge *ret; + if (!control) { return NULL; - } else { - SCOPED_AO2LOCK(lock, control); - return control->bridge; } + + ao2_lock(control); + ret = control->bridge; + ao2_unlock(control); + + return ret; } /*! @@ -858,7 +875,7 @@ AST_MUTEX_DEFINE_STATIC(dial_bridge_lock); * they are finished with it. * * \retval NULL Unable to find/create the dial bridge - * \retval non-NULL A reference to teh dial bridge + * \retval non-NULL A reference to the dial bridge */ static struct ast_bridge *get_dial_bridge(void) { @@ -970,16 +987,16 @@ static int depart_channel(struct stasis_app_control *control, struct ast_channel static int bridge_channel_depart(struct stasis_app_control *control, struct ast_channel *chan, void *data) { - struct ast_bridge_channel *bridge_channel = data; + struct ast_bridge_channel *bridge_channel; - { - SCOPED_CHANNELLOCK(lock, chan); + ast_channel_lock(chan); + bridge_channel = ast_channel_internal_bridge_channel(chan); + ast_channel_unlock(chan); - if (bridge_channel != ast_channel_internal_bridge_channel(chan)) { - ast_debug(3, "%s: Channel is no longer in departable state\n", - ast_channel_uniqueid(chan)); - return -1; - } + if (bridge_channel != data) { + ast_debug(3, "%s: Channel is no longer in departable state\n", + ast_channel_uniqueid(chan)); + return -1; } ast_debug(3, "%s: Channel departing bridge\n", @@ -994,9 +1011,9 @@ static void internal_bridge_after_cb(struct ast_channel *chan, void *data, enum ast_bridge_after_cb_reason reason) { struct stasis_app_control *control = data; - SCOPED_AO2LOCK(lock, control); struct ast_bridge_channel *bridge_channel; + ao2_lock(control); ast_debug(3, "%s, %s: %s\n", ast_channel_uniqueid(chan), control->bridge ? control->bridge->uniqueid : "unknown", ast_bridge_after_cb_reason_string(reason)); @@ -1042,6 +1059,7 @@ static void internal_bridge_after_cb(struct ast_channel *chan, void *data, ast_softhangup_nolock(chan, hangup_flag); ast_channel_unlock(chan); } + ao2_unlock(control); } static void bridge_after_cb(struct ast_channel *chan, void *data) @@ -1544,7 +1562,9 @@ void stasis_app_control_shutdown(void) { ast_mutex_lock(&dial_bridge_lock); shutting_down = 1; - ao2_cleanup(dial_bridge); - dial_bridge = NULL; + if (dial_bridge) { + ast_bridge_destroy(dial_bridge, 0); + dial_bridge = NULL; + } ast_mutex_unlock(&dial_bridge_lock); } diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c index 7ce675cb9..d78e59cac 100644 --- a/res/stasis/stasis_bridge.c +++ b/res/stasis/stasis_bridge.c @@ -250,7 +250,7 @@ static int bridge_stasis_moving(struct ast_bridge_channel *bridge_channel, void { if (src->v_table == &bridge_stasis_v_table && dst->v_table != &bridge_stasis_v_table) { - RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup); + struct stasis_app_control *control; struct ast_channel *chan; chan = bridge_channel->chan; @@ -263,6 +263,7 @@ static int bridge_stasis_moving(struct ast_bridge_channel *bridge_channel, void stasis_app_channel_set_stasis_end_published(chan); app_send_end_msg(control_app(control), chan); + ao2_ref(control, -1); } return -1; diff --git a/res/stasis_recording/stored.c b/res/stasis_recording/stored.c index 9df5d75dc..909524e8f 100644 --- a/res/stasis_recording/stored.c +++ b/res/stasis_recording/stored.c @@ -123,18 +123,9 @@ static int split_path(const char *path, char **dir, char **file) return -1; } -#if defined(__AST_DEBUG_MALLOC) *dir = ast_strdup(real_dir); /* Dupe so we can ast_free() */ -#else - /* - * ast_std_free() and ast_free() are the same thing at this time - * so we don't need to dupe. - */ - *dir = real_dir; - real_dir = NULL; -#endif /* defined(__AST_DEBUG_MALLOC) */ *file = ast_strdup(file_portion); - return 0; + return (*dir && *file) ? 0 : -1; } struct match_recording_data { @@ -330,6 +321,7 @@ struct stasis_app_stored_recording *stasis_app_stored_recording_find_by_name( RAII_VAR(char *, file_with_ext, NULL, ast_free); int res; struct stat file_stat; + int prefix_len = strlen(ast_config_AST_RECORDING_DIR); errno = 0; @@ -350,18 +342,28 @@ struct stasis_app_stored_recording *stasis_app_stored_recording_find_by_name( ast_string_field_build(recording, file, "%s/%s", dir, file); if (!ast_begins_with(dir, ast_config_AST_RECORDING_DIR)) { - /* Attempt to escape the recording directory */ - ast_log(LOG_WARNING, "Attempt to access invalid recording %s\n", - name); - errno = EACCES; - return NULL; + /* It's possible that one or more component of the recording path is + * a symbolic link, this would prevent dir from ever matching. */ + char *real_basedir = realpath(ast_config_AST_RECORDING_DIR, NULL); + + if (!real_basedir || !ast_begins_with(dir, real_basedir)) { + /* Attempt to escape the recording directory */ + ast_log(LOG_WARNING, "Attempt to access invalid recording directory %s\n", + dir); + ast_std_free(real_basedir); + errno = EACCES; + + return NULL; + } + + prefix_len = strlen(real_basedir); + ast_std_free(real_basedir); } /* The actual name of the recording is file with the config dir * prefix removed. */ - ast_string_field_set(recording, name, - recording->file + strlen(ast_config_AST_RECORDING_DIR) + 1); + ast_string_field_set(recording, name, recording->file + prefix_len + 1); file_with_ext = find_recording(dir, file); if (!file_with_ext) { |