diff options
author | Maxim Sobolev <sobomax@FreeBSD.org> | 2005-07-07 20:16:35 +0000 |
---|---|---|
committer | Maxim Sobolev <sobomax@FreeBSD.org> | 2005-07-07 20:16:35 +0000 |
commit | 0fa030f274a2e4f83f08592f507c3f4969d0f643 (patch) | |
tree | 84744a0b420d19c6adeba7ba0b6503a6b50205bc /net/ser/files | |
parent | Update to 0.5.1. (diff) |
Update to 0.9.3.
Notes
Notes:
svn path=/head/; revision=138672
Diffstat (limited to 'net/ser/files')
40 files changed, 3798 insertions, 209 deletions
diff --git a/net/ser/files/patch-Makefile b/net/ser/files/patch-Makefile index 803d2222cbfb..99b6cc4ba0de 100644 --- a/net/ser/files/patch-Makefile +++ b/net/ser/files/patch-Makefile @@ -1,23 +1,27 @@ $FreeBSD$ ---- Makefile.orig Tue Jul 27 02:18:34 2004 -+++ Makefile Tue Jul 27 21:01:36 2004 -@@ -44,10 +44,10 @@ +--- Makefile.orig ++++ Makefile +@@ -45,13 +45,12 @@ + skip_modules?= # if not set on the cmd. line or the env, exclude this modules: - exclude_modules?= cpl cpl-c extcmd \ +-exclude_modules?= cpl ext extcmd \ - postgres snmp \ -+ snmp \ ++exclude_modules?= cpl extcmd \ ++ $(POSTGRESQL) snmp \ im \ - jabber mysql \ -- auth_radius group_radius uri_radius -+ jabber \ -+ group_radius uri_radius ++ jabber $(MYSQL) \ + cpl-c \ +- auth_radius group_radius uri_radius avp_radius \ +- pa ++ group_radius uri_radius avp_radius # always exclude the CVS dir override exclude_modules+= CVS $(skip_modules) -@@ -258,7 +258,7 @@ +@@ -263,7 +262,7 @@ chmod 644 $(cfg-prefix)/$(cfg-dir)ser.cfg.sample if [ -z "${skip_cfg_install}" -a \ ! -f $(cfg-prefix)/$(cfg-dir)ser.cfg ]; then \ @@ -26,7 +30,7 @@ $FreeBSD$ $(cfg-prefix)/$(cfg-dir)ser.cfg; \ fi # $(INSTALL-CFG) etc/ser.cfg $(cfg-prefix)/$(cfg-dir) -@@ -267,10 +267,10 @@ +@@ -272,10 +271,10 @@ $(INSTALL-TOUCH) $(bin-prefix)/$(bin-dir)/ser $(INSTALL-BIN) ser $(bin-prefix)/$(bin-dir) $(INSTALL-TOUCH) $(bin-prefix)/$(bin-dir)/sc @@ -38,4 +42,4 @@ $FreeBSD$ + $(INSTALL-SCRIPT) scripts/ser_mysql.sh $(bin-prefix)/$(bin-dir) $(INSTALL-TOUCH) $(bin-prefix)/$(bin-dir)/gen_ha1 $(INSTALL-BIN) utils/gen_ha1/gen_ha1 $(bin-prefix)/$(bin-dir) - + $(INSTALL-TOUCH) $(bin-prefix)/$(bin-dir)/serunix diff --git a/net/ser/files/patch-Makefile.defs b/net/ser/files/patch-Makefile.defs index 53bca69ecc5e..3e3b9e78cef3 100644 --- a/net/ser/files/patch-Makefile.defs +++ b/net/ser/files/patch-Makefile.defs @@ -3,10 +3,10 @@ $FreeBSD$ --- Makefile.defs.orig +++ Makefile.defs -@@ -133,10 +133,11 @@ +@@ -151,10 +151,11 @@ INSTALL-TOUCH = touch # used to create the file first (good to # make solaris install work) - # INSTALL-CFG = $(INSTALL) -m 644 + INSTALL-CFG = $(INSTALL) -m 644 -INSTALL-BIN = $(INSTALL) -m 755 -INSTALL-MODULES = $(INSTALL) -m 755 -INSTALL-DOC = $(INSTALL) -m 644 @@ -19,22 +19,7 @@ $FreeBSD$ #set some vars from the environment (and not make builtins) CC := $(shell echo "$${CC}") -@@ -285,10 +286,11 @@ - -DPKG_MALLOC \ - -DSHM_MEM -DSHM_MMAP \ - -DDNS_IP_HACK \ -- -DUSE_IPV6 \ -- -DUSE_TCP \ - -DDISABLE_NAGLE \ -- -DF_MALLOC \ -+ -DNO_DEBUG \ -+ -DUSE_IPV6 \ -+ -DUSE_TCP -+ # -DF_MALLOC \ - # -DDBG_QM_MALLOC \ - # -DDBG_QM_MALLOC \ - # -DF_MALLOC \ -@@ -408,8 +410,8 @@ +@@ -444,8 +445,8 @@ found_lock_method=yes endif @@ -45,16 +30,24 @@ $FreeBSD$ # setting CFLAGS ifeq ($(mode), release) #if i386 -@@ -417,7 +419,7 @@ +@@ -453,14 +454,13 @@ # if gcc ifeq ($(CC_NAME), gcc) #common stuff - CFLAGS=-g -O9 -funroll-loops -Wcast-align $(PROFILE) \ + CFLAGS+=-funroll-loops -Wcast-align $(PROFILE) \ - -Wall \ - #if gcc 3.0 + -Wall + #if gcc 3.4+ + ifeq ($(CC_SHORTVER), 3.4) + CPU ?= athlon + CFLAGS+=-minline-all-stringops -malign-double \ +- -falign-loops \ +- -mtune=$(CPU) ++ -falign-loops + else + #if gcc 3.0+ ifeq ($(CC_SHORTVER), 3.0) -@@ -443,7 +445,7 @@ +@@ -486,7 +486,7 @@ else # CC_NAME, gcc ifeq ($(CC_NAME), icc) @@ -63,7 +56,25 @@ $FreeBSD$ -tpp6 -xK #-openmp #optimize for PIII # -prefetch doesn't seem to work #( ty to inline acroos files, unroll loops,prefetch, -@@ -462,7 +464,7 @@ +@@ -504,7 +504,7 @@ + # if gcc + ifeq ($(CC_NAME), gcc) + #common stuff +- CFLAGS=-g -O9 -funroll-loops -Wcast-align $(PROFILE) \ ++ CFLAGS+=-funroll-loops -Wcast-align $(PROFILE) \ + -Wall + #if gcc 3.4 + ifeq ($(CC_SHORTVER), 3.4) +@@ -537,7 +537,7 @@ + + else # CC_NAME, gcc + ifeq ($(CC_NAME), icc) +- CFLAGS=-g -O3 -ipo -ipo_obj -unroll $(PROFILE) \ ++ CFLAGS+=-ipo -ipo_obj -unroll $(PROFILE) \ + -tpp6 -xK #-openmp #optimize for PIII + # -prefetch doesn't seem to work + #( ty to inline acroos files, unroll loops,prefetch, +@@ -555,7 +555,7 @@ #if gcc ifeq ($(CC_NAME), gcc) #common stuff @@ -72,12 +83,63 @@ $FreeBSD$ -Wall\ #-Wcast-align \ #-Wmissing-prototypes -@@ -520,7 +522,7 @@ +@@ -620,7 +620,7 @@ # if gcc ifeq ($(CC_NAME), gcc) #common stuff - CFLAGS=-O9 -funroll-loops -Wcast-align $(PROFILE) \ + CFLAGS+=-funroll-loops -Wcast-align $(PROFILE) \ - -Wall \ - #if gcc 3.0 - ifeq ($(CC_SHORTVER), 3.0) + -Wall + #if gcc 3.4+ + ifeq ($(CC_SHORTVER), 3.4) +@@ -656,7 +656,7 @@ + # if gcc + ifeq ($(CC_NAME), gcc) + #common stuff +- CFLAGS=-O9 -funroll-loops -Wcast-align $(PROFILE) \ ++ CFLAGS+=-funroll-loops -Wcast-align $(PROFILE) \ + -Wall + #if gcc 3.4+ + ifeq ($(CC_SHORTVER), 3.4) +@@ -692,7 +692,7 @@ + # if gcc + ifeq ($(CC_NAME), gcc) + #common stuff +- CFLAGS= -mips2 -O9 -funroll-loops $(PROFILE) \ ++ CFLAGS+= -mips2 -funroll-loops $(PROFILE) \ + -Wall + #if gcc 3.4+ + ifeq ($(CC_SHORTVER), 3.4) +@@ -856,7 +856,7 @@ + # -andrei + else #mode,release + ifeq ($(CC_NAME), gcc) +- CFLAGS=-g -Wcast-align $(PROFILE) ++ CFLAGS+=-Wcast-align $(PROFILE) + ifeq ($(ARCH), sparc64) + CFLAGS+= -mcpu=ultrasparc + endif +@@ -871,12 +871,12 @@ + endif + endif + ifeq ($(CC_NAME), icc) +- CFLAGS=-g $(PROFILE) ++ CFLAGS+=$(PROFILE) + LDFLAGS+=-g -Wl,-E $(PROFILE) + MOD_LDFLAGS=-shared $(LDFLAGS) + endif + ifeq ($(CC_NAME), suncc) +- CFLAGS= -g $(PROFILE) ++ CFLAGS+= $(PROFILE) + LDFLAGS+=-g $(PROFILE) + MOD_LDFLAGS=-G $(LDFLAGS) + endif +@@ -958,7 +958,7 @@ + found_lock_method=yes + LIBS= -pthread -lfl #dlopen is in libc + else +- LIBS= -lfl #dlopen is in libc ++ LIBS= -lfl -L$(LOCALBASE)/lib -lsiplog #dlopen is in libc + endif + YACC=yacc + endif diff --git a/net/ser/files/patch-Makefile.rules b/net/ser/files/patch-Makefile.rules new file mode 100644 index 000000000000..2df91d4f6265 --- /dev/null +++ b/net/ser/files/patch-Makefile.rules @@ -0,0 +1,14 @@ + +$FreeBSD$ + +--- Makefile.rules ++++ Makefile.rules +@@ -18,7 +18,7 @@ + $(CC) $(CFLAGS) $(DEFS) -c $< -o $@ + + %.d: %.c $(ALLDEP) +- @set -e; $(MKDEP) $(DEFS) $< \ ++ @set -e; $(MKDEP) $(CFLAGS) $(DEFS) $< \ + | sed 's#\(\($*D)\)\?$(*F)\)\.o[ :]*#$*.o $@ : #g' > $@; \ + [ -s $@ ] || rm -f $@ + diff --git a/net/ser/files/patch-cfg.lex b/net/ser/files/patch-cfg.lex new file mode 100644 index 000000000000..ddfe015b190b --- /dev/null +++ b/net/ser/files/patch-cfg.lex @@ -0,0 +1,21 @@ + +$FreeBSD$ + +--- cfg.lex 2004/06/29 19:08:42 1.1 ++++ cfg.lex 2004/06/29 19:10:36 +@@ -165,6 +165,7 @@ + FIFO fifo + FIFO_MODE fifo_mode + SERVER_SIGNATURE server_signature ++SERVER_NAME server_name + REPLY_TO_VIA reply_to_via + USER "user"|"uid" + GROUP "group"|"gid" +@@ -332,6 +333,7 @@ + <INITIAL>{FIFO} { count(); yylval.strval=yytext; return FIFO; } + <INITIAL>{FIFO_MODE} { count(); yylval.strval=yytext; return FIFO_MODE; } + <INITIAL>{SERVER_SIGNATURE} { count(); yylval.strval=yytext; return SERVER_SIGNATURE; } ++<INITIAL>{SERVER_NAME} { count(); yylval.strval=yytext; return SERVER_NAME; } + <INITIAL>{REPLY_TO_VIA} { count(); yylval.strval=yytext; return REPLY_TO_VIA; } + <INITIAL>{ADVERTISED_ADDRESS} { count(); yylval.strval=yytext; + return ADVERTISED_ADDRESS; } diff --git a/net/ser/files/patch-cfg.y b/net/ser/files/patch-cfg.y new file mode 100644 index 000000000000..87a917abe8ae --- /dev/null +++ b/net/ser/files/patch-cfg.y @@ -0,0 +1,21 @@ + +$FreeBSD$ + +--- cfg.y.orig ++++ cfg.y +@@ -210,6 +210,7 @@ + %token UNIX_SOCK_CHILDREN + %token UNIX_TX_TIMEOUT + %token SERVER_SIGNATURE ++%token SERVER_NAME + %token REPLY_TO_VIA + %token LOADMODULE + %token MODPARAM +@@ -610,6 +611,7 @@ + | TLS_SEND_TIMEOUT EQUAL error { yyerror("number expected"); } + | SERVER_SIGNATURE EQUAL NUMBER { server_signature=$3; } + | SERVER_SIGNATURE EQUAL error { yyerror("boolean value expected"); } ++ | SERVER_NAME EQUAL STRING { server_name=$3; } + | REPLY_TO_VIA EQUAL NUMBER { reply_to_via=$3; } + | REPLY_TO_VIA EQUAL error { yyerror("boolean value expected"); } + | LISTEN EQUAL id_lst { diff --git a/net/ser/files/patch-config.h b/net/ser/files/patch-config.h new file mode 100644 index 000000000000..1a8259c87b8d --- /dev/null +++ b/net/ser/files/patch-config.h @@ -0,0 +1,23 @@ + +$FreeBSD$ + +--- config.h 2004/06/29 19:14:46 1.1 ++++ config.h 2004/06/29 19:33:41 +@@ -72,12 +72,14 @@ + #define CONTENT_LENGTH "Content-Length: " + #define CONTENT_LENGTH_LEN (sizeof(CONTENT_LENGTH)-1) + +-#define USER_AGENT "User-Agent: Sip EXpress router"\ ++#define UA_NAME "Sip EXpress router "\ + "(" VERSION " (" ARCH "/" OS"))" ++#define UA_NAME_LEN (sizeof(UA_NAME)-1) ++ ++#define USER_AGENT "User-Agent: " + #define USER_AGENT_LEN (sizeof(USER_AGENT)-1) + +-#define SERVER_HDR "Server: Sip EXpress router "\ +- "(" VERSION " (" ARCH "/" OS"))" ++#define SERVER_HDR "Server: " + #define SERVER_HDR_LEN (sizeof(SERVER_HDR)-1) + + #define MAX_WARNING_LEN 256 diff --git a/net/ser/files/patch-fifo_server.c b/net/ser/files/patch-fifo_server.c new file mode 100644 index 000000000000..39b5a3647054 --- /dev/null +++ b/net/ser/files/patch-fifo_server.c @@ -0,0 +1,14 @@ + +$FreeBSD$ + +--- fifo_server.c.orig Sat Nov 1 20:56:58 2003 ++++ fifo_server.c Tue Jun 29 22:33:53 2004 +@@ -642,7 +657,7 @@ + static int print_version_cmd( FILE *stream, char *response_file ) + { + if (response_file) { +- fifo_reply(response_file, "200 ok\n" SERVER_HDR CRLF ); ++ fifo_reply(response_file, "200 ok\n" SERVER_HDR "%s" CRLF, server_name ? server_name : UA_NAME ); + } else { + LOG(L_ERR, "ERROR: no file for %s\n", "print_version_cmd" ); + } diff --git a/net/ser/files/patch-globals.h b/net/ser/files/patch-globals.h new file mode 100644 index 000000000000..0b19a234716a --- /dev/null +++ b/net/ser/files/patch-globals.h @@ -0,0 +1,13 @@ + +$FreeBSD$ + +--- globals.h 2004/06/29 19:08:42 1.1 ++++ globals.h 2004/06/29 19:30:58 +@@ -91,6 +91,7 @@ + /* extern int process_no; */ + extern int sip_warning; + extern int server_signature; ++extern char* server_name; + extern char* user; + extern char* group; + extern char* chroot_dir; diff --git a/net/ser/files/patch-main.c b/net/ser/files/patch-main.c new file mode 100644 index 000000000000..f490905b8b03 --- /dev/null +++ b/net/ser/files/patch-main.c @@ -0,0 +1,16 @@ + +$FreeBSD$ + +--- main.c.orig ++++ main.c +@@ -249,6 +251,10 @@ + be default yes, good for trouble-shooting + */ + int server_signature=1; ++/* ++ * Server's signature if different from default. ++ */ ++char* server_name = 0; + /* should ser try to locate outbound interface on multihomed + * host? by default not -- too expensive + */ diff --git a/net/ser/files/patch-modules::acc::etc::radiusclient.conf b/net/ser/files/patch-modules::acc::etc::radiusclient.conf index 876687437988..3d13a5648be6 100644 --- a/net/ser/files/patch-modules::acc::etc::radiusclient.conf +++ b/net/ser/files/patch-modules::acc::etc::radiusclient.conf @@ -8,7 +8,7 @@ $FreeBSD$ # name of the issue file. it's only display when no username is passed # on the radlogin command line -issue /usr/local/etc/radiusclient/issue -+issue %%LOCALBASE%%/etc/radiusclient/issue ++issue %%LOCALBASE%%/etc/radiusclient-ng/issue # RADIUS settings @@ -36,7 +36,7 @@ $FreeBSD$ # file which specifies mapping between ttyname and NAS-Port attribute -mapfile /usr/local/etc/radiusclient/port-id-map -+mapfile %%LOCALBASE%%/etc/radiusclient/port-id-map ++mapfile %%LOCALBASE%%/etc/radiusclient-ng/port-id-map # default authentication realm to append to all usernames if no # realm was explicitly specified by the user diff --git a/net/ser/files/patch-modules::auth::auth_mod.c b/net/ser/files/patch-modules::auth::auth_mod.c new file mode 100644 index 000000000000..2d08c8f5edff --- /dev/null +++ b/net/ser/files/patch-modules::auth::auth_mod.c @@ -0,0 +1,60 @@ + +$FreeBSD$ + +--- modules/auth/auth_mod.c.orig ++++ modules/auth/auth_mod.c +@@ -84,6 +84,9 @@ + int (*sl_reply)(struct sip_msg* _msg, char* _str1, char* _str2); + + ++struct tm_binds tmb; ++ ++ + /* + * Module parameter variables + */ +@@ -93,6 +96,7 @@ + str secret; + char* sec_rand = 0; + ++int use_tm = 0; + + /* + * Default Remote-Party-ID prefix +@@ -140,6 +144,7 @@ + {"rpid_prefix", STR_PARAM, &rpid_prefix_param }, + {"rpid_suffix", STR_PARAM, &rpid_suffix_param }, + {"realm_prefix", STR_PARAM, &realm_prefix_param}, ++ {"use_tm", INT_PARAM, &use_tm }, + {0, 0, 0} + }; + +@@ -190,13 +195,23 @@ + + static int mod_init(void) + { ++ load_tm_f load_tm; ++ + DBG("auth module - initializing\n"); +- +- sl_reply = find_export("sl_send_reply", 2, 0); + +- if (!sl_reply) { +- LOG(L_ERR, "auth:mod_init(): This module requires sl module\n"); +- return -2; ++ if (use_tm != 0) { ++ load_tm = (load_tm_f)find_export("load_tm", NO_SCRIPT, 0); ++ if (load_tm == NULL || load_tm(&tmb) == -1) { ++ LOG(L_ERR, "Can't import tm\n"); ++ return -1; ++ } ++ } else { ++ sl_reply = find_export("sl_send_reply", 2, 0); ++ ++ if (!sl_reply) { ++ LOG(L_ERR, "auth:mod_init(): This module requires sl module\n"); ++ return -2; ++ } + } + + /* If the parameter was not used */ diff --git a/net/ser/files/patch-modules::auth::auth_mod.h b/net/ser/files/patch-modules::auth::auth_mod.h new file mode 100644 index 000000000000..8d3304af4139 --- /dev/null +++ b/net/ser/files/patch-modules::auth::auth_mod.h @@ -0,0 +1,27 @@ + +$FreeBSD$ + +--- modules/auth/auth_mod.h.orig ++++ modules/auth/auth_mod.h +@@ -36,7 +36,7 @@ + + #include "../../str.h" + #include "../../parser/msg_parser.h" /* struct sip_msg */ +- ++#include "../tm/tm_load.h" + + /* + * Module parameters variables +@@ -46,9 +46,11 @@ + extern str rpid_prefix; /* Remote-Party-ID prefix */ + extern str rpid_suffix; /* Remote-Party-ID suffix */ + extern str realm_prefix; /* strip off auto-generated realm */ +- ++extern int use_tm; + + /* Stateless reply function pointer */ + extern int (*sl_reply)(struct sip_msg* _m, char* _str1, char* _str2); ++ ++extern struct tm_binds tmb; + + #endif /* AUTH_MOD_H */ diff --git a/net/ser/files/patch-modules::auth::common.c b/net/ser/files/patch-modules::auth::common.c new file mode 100644 index 000000000000..d15db240bedc --- /dev/null +++ b/net/ser/files/patch-modules::auth::common.c @@ -0,0 +1,12 @@ + +$FreeBSD$ + +--- modules/auth/common.c.orig ++++ modules/auth/common.c +@@ -95,5 +95,5 @@ + } + } + +- return sl_reply(_m, (char*)(long)_code, _reason); ++ return (use_tm != 0) ? tmb.t_reply(_m, _code, _reason) : sl_reply(_m, (char*)(long)_code, _reason); + } diff --git a/net/ser/files/patch-modules::auth::doc::auth_user.sgml b/net/ser/files/patch-modules::auth::doc::auth_user.sgml new file mode 100644 index 000000000000..c67c487a48e2 --- /dev/null +++ b/net/ser/files/patch-modules::auth::doc::auth_user.sgml @@ -0,0 +1,44 @@ + +$FreeBSD$ + +--- modules/auth/doc/auth_user.sgml ++++ modules/auth/doc/auth_user.sgml +@@ -33,7 +33,10 @@ + must be loaded before this module): + <itemizedlist> + <listitem> +- <para><emphasis>sl</emphasis> -- Stateless replies</para> ++ <para><emphasis>sl</emphasis> -- Stateless replies (if <varname>use_tm</varname> is 0)</para> ++ </listitem> ++ <listitem> ++ <para><emphasis>tm</emphasis> -- Transaction module (if <varname>use_tm</varname> is 1)</para> + </listitem> + </itemizedlist> + </para> +@@ -103,6 +106,26 @@ + <title>rpid_suffix</title> + <programlisting format="linespecific"> + modparam("auth", "rpid_suffix", "@1.2.3.4>") ++</programlisting> ++ </example> ++ </section> ++ <section> ++ <title><varname>use_tm</varname> (integer)</title> ++ <para> ++ If set to 1 then the auth will use <function>t_reply()</function> function from ++ the tm module instead of <function>sl_send_reply()</function> function from the ++ sl module for sending replies. This allows challenge responses to be processes ++ statefully if necessary. When set to 1 script writer need to ensure that transaction ++ exists when <function>www_challenge()</function> or <function>proxy_challenge()</function> ++ is called, usually by calling <function>t_newtran()</function>. ++ </para> ++ <para> ++ Default value is 0. ++ </para> ++ <example> ++ <title>use_tm example</title> ++ <programlisting format="linespecific"> ++modparam("auth", "use_tm", 1) + </programlisting> + </example> + </section> diff --git a/net/ser/files/patch-modules::auth_radius::authrad_mod.c b/net/ser/files/patch-modules::auth_radius::authrad_mod.c index af34b0fc0c66..faf1196f43ea 100644 --- a/net/ser/files/patch-modules::auth_radius::authrad_mod.c +++ b/net/ser/files/patch-modules::auth_radius::authrad_mod.c @@ -1,9 +1,9 @@ $FreeBSD$ ---- modules/auth_radius/authrad_mod.c.orig Mon Jul 19 01:56:23 2004 -+++ modules/auth_radius/authrad_mod.c Tue Jul 27 21:50:52 2004 -@@ -64,7 +64,7 @@ +--- modules/auth_radius/authrad_mod.c.orig ++++ modules/auth_radius/authrad_mod.c +@@ -69,7 +69,7 @@ /* * Module parameter variables */ diff --git a/net/ser/files/patch-modules::check_ua::Makefile b/net/ser/files/patch-modules::check_ua::Makefile new file mode 100644 index 000000000000..c851e5e6168f --- /dev/null +++ b/net/ser/files/patch-modules::check_ua::Makefile @@ -0,0 +1,19 @@ + +$FreeBSD$ + +--- modules/check_ua/Makefile.orig ++++ modules/check_ua/Makefile +@@ -0,0 +1,13 @@ ++# $Id: patch-modules::check_ua::Makefile,v 1.2 2005/04/05 13:10:07 netch Exp $ ++# ++# example module makefile ++# ++# ++# WARNING: do not run this directly, it should be run by the master Makefile ++ ++include ../../Makefile.defs ++auto_gen= ++NAME=check_ua.so ++LIBS= ++ ++include ../../Makefile.modules diff --git a/net/ser/files/patch-modules::check_ua::check_ua.c b/net/ser/files/patch-modules::check_ua::check_ua.c new file mode 100644 index 000000000000..2b70a6d83c8d --- /dev/null +++ b/net/ser/files/patch-modules::check_ua::check_ua.c @@ -0,0 +1,374 @@ + +$FreeBSD$ + +--- /dev/null Sun Jan 9 11:17:56 2005 ++++ modules/check_ua/check_ua.c Sun Jan 9 11:17:26 2005 +@@ -0,0 +1,368 @@ ++/* ++ * $Id: patch-modules::check_ua::check_ua.c,v 1.2 2005/04/05 13:10:07 netch Exp $ ++ * ++ * CHECK_UA module ++ * ++ * ++ * Copyright (C) 2004-2005 Porta Software Ltd. ++ * Copyright (C) Valentin Nechayev <netch@portaone.com> ++ * ++ * This file is part of ser, a free SIP server. ++ * ++ * ser is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * For a license to use the ser software under conditions ++ * other than those described here, or to purchase support for this ++ * software, please contact iptel.org by e-mail at the following addresses: ++ * info@iptel.org ++ * ++ * ser is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++/* History: ++ * -------- ++ * 2004-12-15 initial version (netch) ++ * ++ * 2005-01-09 style(9) and other minor nits (sobomax, netch) ++ */ ++ ++ ++#include <sys/types.h> ++#include <regex.h> ++#include <stdlib.h> ++#include <string.h> ++#include <unistd.h> ++ ++#include "../../db/db.h" ++#include "../../db/db_val.h" ++#include "../../dprint.h" ++#include "../../error.h" ++#include "../../flags.h" ++#include "../../mem/mem.h" ++#include "../../sr_module.h" ++ ++#include "tailq.h" ++ ++MODULE_VERSION ++ ++static int check_ua_init(void); ++static int check_ua_exit(void); ++static int check_ua_f(struct sip_msg *, char *, char *); ++static int child_init(int); ++ ++/* parameters */ ++ ++/* global variables */ ++ ++int check_ua_f(struct sip_msg *, char *, char *); ++ ++static cmd_export_t cmds[]={ ++ {"check_ua", check_ua_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE}, ++ {0, 0, 0, 0, 0} ++}; ++ ++static char *db_url = NULL; ++static char *db_table = NULL; ++static db_con_t *db_handle; ++static int reread_interval = 300; ++ ++static param_export_t params[]={ ++ {"db_url", STR_PARAM, &db_url}, ++ {"db_table", STR_PARAM, &db_table}, ++ {"reread_interval", INT_PARAM, &reread_interval}, ++ {0, 0, 0} ++}; ++ ++struct module_exports exports= { ++ "check_ua", ++ cmds, ++ params, ++ ++ check_ua_init, /* module initialization function */ ++ (response_function) 0, ++ (destroy_function) check_ua_exit, /* module exit function */ ++ 0, ++ child_init /* per-child init function */ ++}; ++ ++typedef struct reglist_entry { ++ TAILQ_ENTRY(reglist_entry) re_link; ++ char *re_regexp; ++ regex_t re_compiled; ++ int re_has_compiled; ++ int re_flag_num; ++} reglist_entry; ++ ++static TAILQ_HEAD(reglist_head_t, reglist_entry) reglist; ++typedef struct reglist_head_t reglist_head_t; ++ ++static time_t last_got; ++ ++static void reglist_entry_free(reglist_entry *); ++static int load_reglist(reglist_head_t *); ++static void check_ua_periodic(void); ++static str *getUserAgent(struct sip_msg *msg); ++ ++static db_func_t db_functions; ++ ++static int ++check_ua_init(void) ++{ ++ ++ LOG(L_INFO,"CHECK_UA - initializing\n"); ++ if (bind_dbmod(db_url, &db_functions) != 0) { ++ LOG(L_ERR, "CHECK_UA: init: bind_dbmod() failed\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++child_init(int child) ++{ ++ ++ TAILQ_INIT(®list); ++ db_handle = db_functions.init(db_url); ++ if (!db_handle) { ++ LOG(L_ERR, "CHECK_UA: cannot connect to database\n"); ++ return -1; ++ } ++ if (load_reglist(®list) < 0) ++ return -1; ++ time(&last_got); ++ srand(time(NULL) + getpid()); ++ return 0; ++} ++ ++static int ++check_ua_exit(void) ++{ ++ ++ reglist_entry *re; ++ LOG(L_INFO, "CHECK_UA - destroing module\n"); ++ ++ /* Free reglist */ ++ while ((re = TAILQ_FIRST(®list)) != NULL) { ++ TAILQ_REMOVE(®list, re, re_link); ++ reglist_entry_free(re); ++ } ++ ++ return 0; ++} ++ ++static int ++load_reglist_sub(reglist_head_t *head) ++{ ++ ++ db_key_t cols[2]; ++ db_res_t *db_res; ++ reglist_entry *re; ++ int i; ++ int ret; ++ ++ ret = -1; ++ if (db_functions.use_table(db_handle, db_table) < 0) { ++ LOG(L_ERR, "check_ua: load_reglist(): can't select table\n"); ++ return -1; ++ } ++ cols[0] = "rexp"; ++ cols[1] = "flag"; ++ if (db_functions.query(db_handle, NULL, NULL, NULL, cols, 0, 2, NULL, &db_res) < 0) { ++ LOG(L_ERR, "check_ua: load_reglist(): query failed\n"); ++ return -1; ++ } ++ /* Iterate result */ ++ for (i = 0; i < RES_ROW_N(db_res); ++i) { ++ db_row_t *row = &RES_ROWS(db_res)[i]; ++ db_val_t *val_regexp; ++ db_val_t *val_flag; ++ char *r; ++ int flags; ++ str t; ++ ++ if (row->n != 2) { ++ LOG(L_ERR, "check_ua: load_reglist(): no required columns\n"); ++ goto cleanup; ++ } ++ val_regexp = &ROW_VALUES(row)[0]; ++ val_flag = &ROW_VALUES(row)[1]; ++ re = pkg_malloc(sizeof(*re)); ++ if (re == NULL) { ++ LOG(L_ERR, "ERROR: check_ua: load_reglist(): no memory\n"); ++ goto cleanup; ++ } ++ memset(re, '\0', sizeof(*re)); ++ /* First is weight, either absolute or accumulated */ ++ re->re_flag_num = VAL_INT(val_flag); ++ if (VAL_TYPE(val_regexp) == DB_STRING) { ++ t.s = (char *)VAL_STRING(val_regexp); ++ t.len = strlen(t.s); ++ } else if (VAL_TYPE(val_regexp) == DB_STR) { ++ t = VAL_STR(val_regexp); ++ } else { ++ LOG(L_ERR, "ERROR: check_ua: load_reglist(): invalid value type\n"); ++ goto cleanup; ++ } ++ re->re_regexp = pkg_malloc(t.len + 1); ++ if (re->re_regexp == NULL) { ++ LOG(L_ERR, "ERROR: check_ua: load_reglist(): no memory\n"); ++ goto cleanup; ++ } ++ memcpy(re->re_regexp, t.s, t.len); ++ re->re_regexp[t.len] = '\0'; ++ flags = REG_EXTENDED; ++ r = re->re_regexp; ++ if (strncmp(r, "\\c", 2) == 0) { ++ r += 2; ++ flags |= REG_ICASE; ++ } ++ if (regcomp(&re->re_compiled, r, flags) != 0) { ++ LOG(L_ERR, "ERROR: check_ua: load_reglist(): regcomp() failed\n"); ++ reglist_entry_free(re); ++ goto cleanup; ++ } ++ re->re_has_compiled = 1; ++ TAILQ_INSERT_TAIL(head, re, re_link); ++ } ++ ret = 0; ++cleanup: ++ db_functions.free_result(db_handle, db_res); ++ return ret; ++} ++ ++static int ++load_reglist(reglist_head_t *head) ++{ ++ reglist_entry *re; ++ int rc; ++ ++ rc = load_reglist_sub(head); ++ if (rc < 0) { ++ /* Free list. This is too hard to add in subfunction. */ ++ while ((re = TAILQ_FIRST(head)) != NULL) { ++ TAILQ_REMOVE(head, re, re_link); ++ reglist_entry_free(re); ++ } ++ } ++ return rc; ++} ++ ++static int ++check_ua_f(struct sip_msg *msg, char *dummy1, char *dummy2) ++{ ++ str *useragent_str; ++ char *ua; ++ reglist_entry *re; ++ time_t now; ++ int rval; ++ ++ time(&now); ++ if (now < last_got || now >= last_got + reread_interval) ++ check_ua_periodic(); ++ ++ /* Note that getUserAgent() always returns valid pointer */ ++ useragent_str = getUserAgent(msg); ++ /* ++ * Make nul-terminated string copy of user-agent. We can't use ++ * that is in parsed header. ++ */ ++ ua = pkg_malloc(useragent_str->len + 1); ++ if (ua == NULL) { ++ LOG(L_ERR, "ERROR: check_ua: no memory\n"); ++ return -1; ++ } ++ memcpy(ua, useragent_str->s, useragent_str->len); ++ ua[useragent_str->len] = '\0'; ++ ++ rval = -1; ++ /* Iterate regexp list and set flags on matching */ ++ TAILQ_FOREACH(re, ®list, re_link) { ++ int rc; ++ ++ rc = regexec(&re->re_compiled, ua, 0, NULL, 0); ++ if (rc == 0) { /* matched */ ++ setflag(msg, re->re_flag_num); ++ rval = 1; ++ } else if (rc != REG_NOMATCH) { ++ /* What's this? */ ++ LOG(L_ERR, "ERROR: check_ua: unexpected regexec error: %d\n", rc); ++ rval = -1; /* 0 maybe??? */ ++ break; ++ } ++ } ++ pkg_free(ua); ++ return rval; ++} ++ ++static void ++check_ua_periodic(void) ++{ ++ reglist_head_t newhead; ++ reglist_entry *re; ++ ++ TAILQ_INIT(&newhead); ++ /* ++ * Reread base and recompile expression list. ++ * As we have no way to check whether regexp list was changed, ++ * do it unconditionally. ++ */ ++ if (load_reglist(&newhead) < 0) { ++ LOG(L_ERR, "check_ua: check_ua_periodic(): error reading new regexp file, keeping list from old one\n"); ++ return; ++ } ++ /* Delete old list and move all entries of new list to old one */ ++ while ((re = TAILQ_FIRST(®list)) != NULL) { ++ TAILQ_REMOVE(®list, re, re_link); ++ reglist_entry_free(re); ++ } ++ while ((re = TAILQ_FIRST(&newhead)) != NULL) { ++ TAILQ_REMOVE(&newhead, re, re_link); ++ TAILQ_INSERT_TAIL(®list, re, re_link); ++ } ++ time(&last_got); ++ last_got -= (rand() % 3); ++} ++ ++static void ++reglist_entry_free(reglist_entry *re) ++{ ++ if (re->re_has_compiled) ++ regfree(&re->re_compiled); ++ if (re->re_regexp) ++ pkg_free(re->re_regexp); ++ pkg_free(re); ++} ++ ++#define UA_DUMMY_STR "Unknown" ++#define UA_DUMMY_LEN 7 ++ ++/* Extract User-Agent */ ++static str * ++getUserAgent(struct sip_msg *msg) ++{ ++ static str notfound = {UA_DUMMY_STR, UA_DUMMY_LEN}; ++ ++ if ((parse_headers(msg, HDR_USERAGENT, 0)!=-1) && msg->user_agent && ++ msg->user_agent->body.len>0) { ++ return &(msg->user_agent->body); ++ } ++ if ((parse_headers(msg, HDR_SERVER, 0)!=-1) && msg->server && ++ msg->server->body.len>0) { ++ return &(msg->server->body); ++ } ++ ++ notfound.s = UA_DUMMY_STR; ++ notfound.len = UA_DUMMY_LEN; ++ ++ return ¬found; ++} diff --git a/net/ser/files/patch-modules::check_ua::tailq.h b/net/ser/files/patch-modules::check_ua::tailq.h new file mode 100644 index 000000000000..3e713ea72af8 --- /dev/null +++ b/net/ser/files/patch-modules::check_ua::tailq.h @@ -0,0 +1,154 @@ + +$FreeBSD$ + +--- modules/check_ua/tailq.h.orig ++++ modules/check_ua/tailq.h +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (c) 1991, 1993 ++ * The Regents of the University of California. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 4. Neither the name of the University nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * @(#)queue.h 8.5 (Berkeley) 8/20/94 ++ * $FreeBSD$ ++ */ ++ ++#ifndef TAILQ_H_ ++#define TAILQ_H_ ++ ++/* ++ * Tail queue declarations. ++ */ ++#define TAILQ_HEAD(name, type) \ ++struct name { \ ++ struct type *tqh_first; /* first element */ \ ++ struct type **tqh_last; /* addr of last next element */ \ ++} ++ ++#define TAILQ_HEAD_INITIALIZER(head) \ ++ { NULL, &(head).tqh_first } ++ ++#define TAILQ_ENTRY(type) \ ++struct { \ ++ struct type *tqe_next; /* next element */ \ ++ struct type **tqe_prev; /* address of previous next element */ \ ++} ++ ++/* ++ * Tail queue functions. ++ */ ++#define TAILQ_CONCAT(head1, head2, field) do { \ ++ if (!TAILQ_EMPTY(head2)) { \ ++ *(head1)->tqh_last = (head2)->tqh_first; \ ++ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ ++ (head1)->tqh_last = (head2)->tqh_last; \ ++ TAILQ_INIT((head2)); \ ++ } \ ++} while (0) ++ ++#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) ++ ++#define TAILQ_FIRST(head) ((head)->tqh_first) ++ ++#define TAILQ_FOREACH(var, head, field) \ ++ for ((var) = TAILQ_FIRST((head)); \ ++ (var); \ ++ (var) = TAILQ_NEXT((var), field)) ++ ++#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ ++ for ((var) = TAILQ_FIRST((head)); \ ++ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ ++ (var) = (tvar)) ++ ++#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ ++ for ((var) = TAILQ_LAST((head), headname); \ ++ (var); \ ++ (var) = TAILQ_PREV((var), headname, field)) ++ ++#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ ++ for ((var) = TAILQ_LAST((head), headname); \ ++ (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ ++ (var) = (tvar)) ++ ++#define TAILQ_INIT(head) do { \ ++ TAILQ_FIRST((head)) = NULL; \ ++ (head)->tqh_last = &TAILQ_FIRST((head)); \ ++} while (0) ++ ++#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ ++ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ ++ TAILQ_NEXT((elm), field)->field.tqe_prev = \ ++ &TAILQ_NEXT((elm), field); \ ++ else { \ ++ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ ++ } \ ++ TAILQ_NEXT((listelm), field) = (elm); \ ++ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ ++} while (0) ++ ++#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ ++ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ ++ TAILQ_NEXT((elm), field) = (listelm); \ ++ *(listelm)->field.tqe_prev = (elm); \ ++ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ ++} while (0) ++ ++#define TAILQ_INSERT_HEAD(head, elm, field) do { \ ++ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ ++ TAILQ_FIRST((head))->field.tqe_prev = \ ++ &TAILQ_NEXT((elm), field); \ ++ else \ ++ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ ++ TAILQ_FIRST((head)) = (elm); \ ++ (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ ++} while (0) ++ ++#define TAILQ_INSERT_TAIL(head, elm, field) do { \ ++ TAILQ_NEXT((elm), field) = NULL; \ ++ (elm)->field.tqe_prev = (head)->tqh_last; \ ++ *(head)->tqh_last = (elm); \ ++ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ ++} while (0) ++ ++#define TAILQ_LAST(head, headname) \ ++ (*(((struct headname *)((head)->tqh_last))->tqh_last)) ++ ++#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) ++ ++#define TAILQ_PREV(elm, headname, field) \ ++ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) ++ ++#define TAILQ_REMOVE(head, elm, field) do { \ ++ if ((TAILQ_NEXT((elm), field)) != NULL) \ ++ TAILQ_NEXT((elm), field)->field.tqe_prev = \ ++ (elm)->field.tqe_prev; \ ++ else { \ ++ (head)->tqh_last = (elm)->field.tqe_prev; \ ++ } \ ++ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ ++} while (0) ++ ++#endif /* !TAILQ_H_ */ diff --git a/net/ser/files/patch-modules::ext::ext.c b/net/ser/files/patch-modules::ext::ext.c deleted file mode 100644 index 785fcda3b3f7..000000000000 --- a/net/ser/files/patch-modules::ext::ext.c +++ /dev/null @@ -1,14 +0,0 @@ - -$FreeBSD$ - ---- modules/ext/ext.c.orig Sun Apr 6 23:25:51 2003 -+++ modules/ext/ext.c Tue May 4 19:11:40 2004 -@@ -49,6 +50,8 @@ - #include "my_exec.h" - #include "config.h" - -+MODULE_VERSION -+ - #define MAX_BUFFER_LEN 1024 - - diff --git a/net/ser/files/patch-modules::group_radius::grouprad_mod.c b/net/ser/files/patch-modules::group_radius::grouprad_mod.c index 914df1c5f001..51da6a47c822 100644 --- a/net/ser/files/patch-modules::group_radius::grouprad_mod.c +++ b/net/ser/files/patch-modules::group_radius::grouprad_mod.c @@ -1,14 +1,14 @@ $FreeBSD$ ---- modules/group_radius/grouprad_mod.c.orig Mon Jul 19 01:56:24 2004 -+++ modules/group_radius/grouprad_mod.c Tue Jul 27 21:01:37 2004 +--- modules/group_radius/grouprad_mod.c.orig ++++ modules/group_radius/grouprad_mod.c @@ -57,7 +57,7 @@ /* * Module parameter variables */ -static char* radius_config = "/usr/local/etc/radiusclient/radiusclient.conf"; +static char* radius_config = (CFG_DIR "radiusclient.conf"); - int use_domain = 1; /* By default we use domain */ + int use_domain = 0; /* By default we use domain */ diff --git a/net/ser/files/patch-modules::nathelper::moh.c b/net/ser/files/patch-modules::nathelper::moh.c new file mode 100644 index 000000000000..5c8ae4f33059 --- /dev/null +++ b/net/ser/files/patch-modules::nathelper::moh.c @@ -0,0 +1,434 @@ + +$FreeBSD$ + +--- modules/nathelper/moh.c ++++ modules/nathelper/moh.c +@@ -0,0 +1,428 @@ ++/* $Id: patch-modules::nathelper::moh.c,v 1.2 2005/04/05 13:10:07 netch Exp $ ++ * ++ * Copyright (C) 2005 Porta Software Ltd ++ * ++ * This file is part of ser, a free SIP server. ++ * ++ * ser is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * For a license to use the ser software under conditions ++ * other than those described here, or to purchase support for this ++ * software, please contact iptel.org by e-mail at the following addresses: ++ * info@iptel.org ++ * ++ * ser is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include <sys/types.h> ++#include <sys/uio.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include "../../parser/parser_f.h" ++#include "../../ut.h" ++#include "nhelpr_funcs.h" ++#include "nathelper.h" ++ ++/* ++ * The following macro is used in force_rtp_proxy2_f() and twice ++ * in start_moh() ++ */ ++ ++#define PARSE_PROXY_REPLY \ ++ do { \ ++ argc = 0; \ ++ memset(argv, 0, sizeof(argv)); \ ++ cpend=cp+strlen(cp); \ ++ next=eat_token_end(cp, cpend); \ ++ for (ap = argv; cp<cpend; cp=next+1, next=eat_token_end(cp, cpend)){ \ ++ *next=0; \ ++ if (*cp != '\0') { \ ++ *ap=cp; \ ++ argc++; \ ++ if ((char*)++ap >= ((char*)argv+sizeof(argv))) \ ++ break; \ ++ } \ ++ } \ ++ } while(0) ++ ++int ++is_hold_f(struct sip_msg* msg, char *str1, char *str2) ++{ ++ /* Look into body and find whether we see 0.0.0.0 as IP address. ++ * extract_mediaport() is designed to parse address from SDP. ++ * XXX Check all addresses or only first one? What if have some ++ * real addresses and some zero ones? ++ */ ++ str body, ip; ++ int pf; ++ ++ if (extract_body(msg, &body) == -1) { ++ LOG(L_ERR,"ERROR: is_hold: cannot extract body from msg!\n"); ++ return 0; ++ } ++ if (extract_mediaip(&body, &ip, &pf) == -1) { ++ LOG(L_ERR, "ERROR: is_hold: can't extract media IP from the SDP\n"); ++ return 0; ++ } ++ return isnulladdr(&ip, pf) ? 1 : -1; ++} ++ ++int ++start_moh_f(struct sip_msg* msg, char* str1, char* str2) ++{ ++ str callid, from_tag, to_tag; ++ int asymmetric, flookup, force, real; ++ int oidx, argc, medianum, c1p_altered, pf, pf1; ++ int seen_audio, seen_video; ++ str body, body1, tmpstr1, oldip, newip, oldport, newport; ++ str medianum_str; ++ char *cpend, *next, *bodylimit, *v1p, *v2p, *c1p, *c2p, *m1p, *m2p; ++ char *cp; ++ char medianum_buf[20], opts[16]; ++ char **ap, *argv[10]; ++ unsigned port; ++ struct rtpp_node *node; ++ struct iovec v_create[14] = { ++ {NULL, 0}, /* command */ ++ {NULL, 0}, /* options */ ++ {" ", 1}, /* separator */ ++ {NULL, 0}, /* callid */ ++ {" ", 1}, /* separator */ ++ {NULL, 7}, /* newip */ ++ {" ", 1}, /* separator */ ++ {NULL, 1}, /* oldport */ ++ {" ", 1}, /* separator */ ++ {NULL, 0}, /* from_tag */ ++ {";", 1}, /* separator */ ++ {NULL, 0}, /* medianum */ ++ {" ", 1}, /* separator */ ++ {NULL, 0} /* to_tag */ ++ }; ++ struct iovec v_play[14] = { ++ {NULL, 0}, /* command */ ++ {NULL, 0}, /* options */ ++ {" ", 1}, /* separator */ ++ {NULL, 0}, /* callid */ ++ {" ", 1}, /* separator */ ++ {NULL, 7}, /* pname */ ++ {" ", 1}, /* separator */ ++ {NULL, 1}, /* codecs */ ++ {" ", 1}, /* separator */ ++ {NULL, 0}, /* to_tag */ ++ {";", 1}, /* separator */ ++ {NULL, 0}, /* medianum */ ++ {" ", 1}, /* separator */ ++ {NULL, 0} /* from_tag */ ++ }; ++ ++ /* extract_body will also parse all the headers in the message as ++ * a side effect => don't move get_callid/get_to_tag in front of it ++ * -- andrei */ ++ if (extract_body(msg, &body) == -1) { ++ LOG(L_ERR, "ERROR: force_rtp_proxy2: can't extract body " ++ "from the message\n"); ++ return -1; ++ } ++ if (get_callid(msg, &callid) == -1 || callid.len == 0) { ++ LOG(L_ERR, "ERROR: start_moh: can't get Call-Id field\n"); ++ return -1; ++ } ++ if (get_to_tag(msg, &to_tag) == -1 || to_tag.len <= 0) { ++ LOG(L_ERR, "ERROR: start_moh: can't get To tag\n"); ++ return -1; ++ } ++ if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) { ++ LOG(L_ERR, "ERROR: start_moh: can't get From tag\n"); ++ return -1; ++ } ++ /* Setting specific options. XXX Do we really need this? */ ++ v_create[1].iov_base = opts; ++ asymmetric = flookup = force = real = 0; ++ force = 1; /* XXX we must force the proxying in this case */ ++ oidx = 2; /* 'UW' */ ++#if 0 ++ for (cp = str1; cp != NULL && *cp != '\0'; cp++) { ++ switch (*cp) { ++ case 'a': ++ case 'A': ++ opts[oidx++] = 'A'; ++ asymmetric = 1; ++ real = 1; ++ break; ++ ++ case 'i': ++ case 'I': ++ opts[oidx++] = 'I'; ++ break; ++ ++ case 'e': ++ case 'E': ++ opts[oidx++] = 'E'; ++ break; ++ ++ case 'l': ++ case 'L': ++ flookup = 1; ++ break; ++ ++ case 'f': ++ case 'F': ++ force = 1; ++ break; ++ ++ case 'r': ++ case 'R': ++ real = 1; ++ break; ++ ++ default: ++ LOG(L_ERR, "ERROR: force_rtp_proxy2: unknown option `%c'\n", *cp); ++ return -1; ++ } ++ } ++#endif ++ /* ++ * Parsing of SDP body. ++ * It can contain a few session descriptions (each start with ++ * "v=" line), and each session may contain a few media descriptions ++ * (each start with "m=" line). ++ * We have to change ports in "m=", and also change IP addresses in ++ * "c=" which can be placed either in session header (fallback for ++ * all medias) or media description. ++ * Ports should be allocated for any media. IPs all should be changed ++ * to the same value (RTP proxy IP), so we can change all "c=" ++ * unconditionally. ++ * ++ * Note start_moh() specifics: use only audio media or video media ++ * and stop after first of them of both kinds. But, medianum should ++ * reflect all of them. ++ */ ++ bodylimit = body.s + body.len; ++ v2p = v1p = find_sdp_line(body.s, bodylimit, 'v'); ++ if (v1p == NULL) { ++ LOG(L_ERR, "ERROR: start_moh: no sessions in SDP\n"); ++ return -1; ++ } ++ medianum = 0; ++ for(;;) { ++ /* Per-session iteration. */ ++ v1p = v2p; ++ if (v1p == NULL || v1p >= bodylimit) ++ break; /* No sessions left */ ++ v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit); ++ /* v2p is text limit for session parsing. */ ++ m1p = find_sdp_line(v1p, v2p, 'm'); ++ /* Have this session media description? */ ++ if (m1p == NULL) { ++ LOG(L_ERR, "ERROR: start_moh: no m= in session\n"); ++ return -1; ++ } ++ /* ++ * Find c1p only between session begin and first media. ++ * c1p will give common c= for all medias. ++ */ ++ c1p = find_sdp_line(v1p, m1p, 'c'); ++ c1p_altered = 0; ++ /* Have session. Iterate media descriptions in session */ ++ seen_audio = seen_video = 0; ++ m2p = m1p; ++ while (!seen_audio || !seen_video) { ++ int is_audio, is_video; ++ /* We pass address to proxy and get some port from ++ * its resources. Then, if old address was empty ++ * (0.0.0.0), create a play stream for this media. ++ */ ++ m1p = m2p; ++ if (m1p == NULL || m1p >= v2p) ++ break; ++ m2p = find_next_sdp_line(m1p, v2p, 'm', v2p); ++ /* c2p will point to per-media "c=" */ ++ c2p = find_sdp_line(m1p, m2p, 'c'); ++ ++medianum; ++ /* ++ * start_moh() specifics: work only for audio/video ++ * media and apply to first of any in session. ++ */ ++ is_audio = (strncmp(m1p, "m=audio ", 8) == 0); ++ is_video = (strncmp(m1p, "m=video ", 8) == 0); ++ if ((is_audio && seen_audio) || ++ (is_video && seen_video) || ++ (!is_audio && !is_video)) ++ continue; ++ seen_audio = seen_audio || is_audio; ++ seen_video = seen_video || is_video; ++ /* Extract address and port */ ++ tmpstr1.s = c2p ? c2p : c1p; ++ if (tmpstr1.s == NULL) { ++ /* No "c=" */ ++ LOG(L_ERR, "ERROR: start_moh: can't find media IP in the message\n"); ++ return -1; ++ } ++ tmpstr1.len = v2p - tmpstr1.s; /* limit is session limit text */ ++ if (extract_mediaip(&tmpstr1, &oldip, &pf) == -1) { ++ LOG(L_ERR, "ERROR: start_moh: can't extract media IP " ++ "from the message\n"); ++ return -1; ++ } ++ tmpstr1.s = m1p; ++ tmpstr1.len = m2p - m1p; ++ if (extract_mediaport(&tmpstr1, &oldport) == -1) { ++ LOG(L_ERR, "ERROR: start_moh: can't extract media port " ++ "from the message\n"); ++ return -1; ++ } ++ if (asymmetric != 0 || real != 0) { ++ newip = oldip; ++ } else { ++ newip.s = ip_addr2a(&msg->rcv.src_ip); ++ newip.len = strlen(newip.s); ++ } ++ /* XXX must compare address families in all addresses */ ++ if (pf == AF_INET6) { ++ opts[oidx] = '6'; ++ oidx++; ++ } ++ ++ /* ++ * If don't see NULL addr, this is not hold. ++ * So, skip to next one. ++ * XXX should also support "a=sendonly" ++ */ ++ if (!isnulladdr(&oldip, pf)) ++ continue; ++ ++ /* Prepare proxy command strings. */ ++ snprintf(medianum_buf, sizeof medianum_buf, "%d", medianum); ++ medianum_str.s = medianum_buf; ++ medianum_str.len = strlen(medianum_buf); ++ opts[0] = 'U'; opts[1] = 'W'; ++ v_create[1].iov_len = oidx; ++ STR2IOVEC(callid, v_create[3]); ++ STR2IOVEC(newip, v_create[5]); ++ STR2IOVEC(oldport, v_create[7]); ++ STR2IOVEC(from_tag, v_create[9]); ++ STR2IOVEC(medianum_str, v_create[11]); ++ STR2IOVEC(to_tag, v_create[13]); ++ STR2IOVEC(callid, v_play[3]); ++ if (is_audio) { ++ SZ2IOVEC(pname_audio, v_play[5]); ++ SZ2IOVEC(codecs_audio, v_play[7]); ++ } else { ++ SZ2IOVEC(pname_video, v_play[5]); ++ SZ2IOVEC(codecs_video, v_play[7]); ++ } ++ STR2IOVEC(to_tag, v_play[9]); ++ STR2IOVEC(medianum_str, v_play[11]); ++ STR2IOVEC(from_tag, v_play[13]); ++ SZ2IOVEC("P", v_play[1]); ++ /* Send command. */ ++ do { ++ node = select_rtpp_node(callid, 1); ++ if (!node) { ++ LOG(L_ERR, "ERROR: start_moh: no available proxies\n"); ++ return -1; ++ } ++ cp = send_rtpp_command(node, v_create, 14); ++ if (cp == NULL) ++ continue; ++ LOG(L_DBG, "start_moh: proxy reply to update: %s\n", cp); ++ PARSE_PROXY_REPLY; ++ if (argc < 1) { ++ LOG(L_ERR, "start_moh: no reply from rtp proxy\n"); ++ return -1; ++ } ++ port = atoi(argv[0]); ++ if (port <= 0 || port > 65535) { ++ LOG(L_ERR, "start_moh: incorrect port in reply from rtp proxy\n"); ++ return -1; ++ } ++ ++ pf1 = (argc >= 3 && argv[2][0] == '6') ? AF_INET6 : AF_INET; ++ newip.s = (argc < 2) ? str2 : argv[1]; ++ newip.len = strlen(newip.s); ++ newport.s = int2str(port, &newport.len); /* beware static buffer */ ++ /* Alter port. */ ++ body1.s = m1p; ++ body1.len = bodylimit - body1.s; ++ if (alter_mediaport(msg, &body1, &oldport, &newport, 0) == -1) { ++ LOG(L_ERR, "start_mon: alter_mediaport() failed\n"); ++ return -1; ++ } ++ /* Alter IP. Don't alter IP common for the session ++ * more than once. ++ */ ++ if (c2p != NULL || !c1p_altered) { ++ body1.s = c2p ? c2p : c1p; ++ body1.len = m2p - body1.s; ++ if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 2) == -1) { ++ LOG(L_ERR, "start_moh: alter_mediaip() failed\n"); ++ return -1; ++ } ++ if (!c2p) ++ c1p_altered = 1; ++ } ++ cp = send_rtpp_command(node, v_play, 14); ++ LOG(L_DBG, "start_moh: proxy reply to play: %s\n", cp); ++ if (cp == NULL) ++ continue; ++ PARSE_PROXY_REPLY; ++ if (argc < 1) { ++ LOG(L_ERR, "start_moh: no reply from rtp proxy\n"); ++ return -1; ++ } ++ } while(cp == NULL); ++ } /* Iterate medias in session */ ++ } /* Iterate sessions */ ++ return 1; ++} ++ ++int ++stop_moh_f(struct sip_msg* msg, char* str1, char* str2) ++{ ++ str callid, to_tag, from_tag; ++ struct rtpp_node *node; ++ struct iovec v_noplay[8] = {{NULL, 0}, {"S", 1}, {" ", 1}, ++ {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}}; ++ struct iovec v_del[8] = {{NULL, 0}, {"DW", 2}, {" ", 1}, ++ {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}}; ++ ++ if (get_callid(msg, &callid) == -1 || callid.len == 0) { ++ LOG(L_ERR, "ERROR: stop_moh: can't get Call-Id field\n"); ++ return -1; ++ } ++ if (get_to_tag(msg, &to_tag) == -1 || to_tag.len <= 0) { ++ LOG(L_ERR, "ERROR: stop_moh: can't get To tag\n"); ++ return -1; ++ } ++ if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) { ++ LOG(L_ERR, "ERROR: stop_moh: can't get From tag\n"); ++ return -1; ++ } ++ /* Ask RTP proxy to stop all plays for this tag. We don't iterate ++ * separate sessions; RTP proxy has knowledge of them. ++ */ ++ STR2IOVEC(callid, v_noplay[3]); ++ STR2IOVEC(to_tag, v_noplay[5]); ++ STR2IOVEC(from_tag, v_noplay[7]); ++ node = select_rtpp_node(callid, 1); ++ send_rtpp_command(node, v_noplay, 8); ++ /* Ask weak deletion for the session. The same as previous; ++ * RTP proxy knows all sessions. ++ */ ++ STR2IOVEC(callid, v_del[3]); ++ STR2IOVEC(to_tag, v_del[5]); ++ STR2IOVEC(from_tag, v_del[7]); ++ send_rtpp_command(node, v_del, 8); ++ return 1; ++} diff --git a/net/ser/files/patch-modules::nathelper::nathelper.c b/net/ser/files/patch-modules::nathelper::nathelper.c new file mode 100644 index 000000000000..de2bf4107771 --- /dev/null +++ b/net/ser/files/patch-modules::nathelper::nathelper.c @@ -0,0 +1,1701 @@ + +$FreeBSD$ + +--- modules/nathelper/nathelper.c.orig ++++ modules/nathelper/nathelper.c +@@ -110,14 +110,42 @@ + * + * 2004-03-22 Fix get_body position (should be called before get_callid) + * (andrei) ++ * + * 2004-03-24 Fix newport for null ip address case (e.g onhold re-INVITE) + * (andrei) +- * 2004-09-30 added received port != via port test (andrei) ++ * ++ * 2004-09-30 added received port != via port test (andrei) ++ * + * 2004-10-10 force_socket option introduced (jiri) ++ * 2004-12-21 support for multiple medias added (netch) ++ * 2005-01-18 proxying on protocol type (RTP/AVP, udp, udptl), not ++ * media type. (sobomax,netch) ++ * ++ * 2005-02-24 Added support for using more than one rtp proxy, in which ++ * case traffic will be distributed evenly among them. In addition, ++ * each such proxy can be assigned a weight, which will specify ++ * which share of the traffic should be placed to this particular ++ * proxy. ++ * ++ * Introduce failover mechanism, so that if SER detects that one ++ * of many proxies is no longer available it temporarily decreases ++ * its weight to 0, so that no traffic will be assigned to it. ++ * Such "disabled" proxies are periodically checked to see if they ++ * are back to normal in which case respective weight is restored ++ * resulting in traffic being sent to that proxy again. ++ * ++ * Those features can be enabled by specifying more than one "URI" ++ * in the rtpproxy_sock parameter, optionally followed by the weight, ++ * which if absent is assumed to be 1, for example: + * ++ * rtpproxy_sock="unix:/foo/bar=4 udp:1.2.3.4:3456=3 udp:5.6.7.8:5432=1" ++ * ++ * 2005-03-24 music-on-hold implemented (netch) + */ + + #include "nhelpr_funcs.h" ++#include "nathelper.h" ++#include "../../action.h" + #include "../../flags.h" + #include "../../sr_module.h" + #include "../../dprint.h" +@@ -127,6 +155,7 @@ + #include "../../forward.h" + #include "../../mem/mem.h" + #include "../../parser/parse_from.h" ++#include "../../parser/parse_hostport.h" + #include "../../parser/parse_to.h" + #include "../../parser/parse_uri.h" + #include "../../parser/parser_f.h" +@@ -171,39 +200,30 @@ + #define NAT_UAC_TEST_S_1918 0x08 + #define NAT_UAC_TEST_RPORT 0x10 + +-/* Handy macros */ +-#define STR2IOVEC(sx, ix) {(ix).iov_base = (sx).s; (ix).iov_len = (sx).len;} +- + /* Supported version of the RTP proxy command protocol */ + #define SUP_CPROTOVER 20040107 ++/* Required additional version of the RTP proxy command protocol */ ++#define REQ_CPROTOVER "20050322" + #define CPORT "22222" + + static int nat_uac_test_f(struct sip_msg* msg, char* str1, char* str2); + static int fix_nated_contact_f(struct sip_msg *, char *, char *); + static int fix_nated_sdp_f(struct sip_msg *, char *, char *); +-static int extract_mediaip(str *, str *, int *); +-static int extract_mediaport(str *, str *); +-static int alter_mediaip(struct sip_msg *, str *, str *, int, str *, int, int); +-static int alter_mediaport(struct sip_msg *, str *, str *, str *, int); ++static int fixate_sdp_f(struct sip_msg *, char *, char *); + static char *gencookie(); +-static int rtpp_test(int, int); +-static char *send_rtpp_command(struct iovec *, int); ++static int rtpp_test(struct rtpp_node*, int, int); + static int unforce_rtp_proxy_f(struct sip_msg *, char *, char *); + static int force_rtp_proxy0_f(struct sip_msg *, char *, char *); + static int force_rtp_proxy1_f(struct sip_msg *, char *, char *); + static int force_rtp_proxy2_f(struct sip_msg *, char *, char *); + static int fix_nated_register_f(struct sip_msg *, char *, char *); + static int add_rcv_param_f(struct sip_msg *, char *, char *); ++static int rewrite_from_from_f(struct sip_msg *, char *, char *); + +-static void timer(unsigned int, void *); + inline static int fixup_str2int(void**, int); + static int mod_init(void); + static int child_init(int); + +-static usrloc_api_t ul; +- +-static int cblen = 0; +-static int natping_interval = 0; + struct socket_info* force_socket = 0; + + +@@ -218,27 +238,51 @@ + {NULL, 0, 0} + }; + +-/* +- * If this parameter is set then the natpinger will ping only contacts +- * that have the NAT flag set in user location database +- */ +-static int ping_nated_only = 0; +-static const char sbuf[4] = {0, 0, 0, 0}; +-static char *rtpproxy_sock = "unix:/var/run/rtpproxy.sock"; ++static str sup_ptypes[] = { ++ {.s = "udp", .len = 3}, ++ {.s = "udptl", .len = 5}, ++ {.s = "rtp/avp", .len = 7}, ++ {.s = NULL, .len = 0} ++}; ++ ++static char *rtpproxy_sock = "unix:/var/run/rtpproxy.sock"; /* list */ + static char *force_socket_str = 0; + static int rtpproxy_disable = 0; + static int rtpproxy_disable_tout = 60; + static int rtpproxy_retr = 5; + static int rtpproxy_tout = 1; +-static int umode = 0; +-static int controlfd; + static pid_t mypid; + static unsigned int myseqn = 0; +-static int rcv_avp_no=42; ++static int rcv_avp_no = 42; ++char *pname_audio = "-"; ++char *pname_video = "-"; ++char *codecs_audio = "-"; ++char *codecs_video = "-"; ++ ++struct rtpp_head { ++ struct rtpp_node *rn_first; ++ struct rtpp_node *rn_last; ++}; ++ ++struct rtpp_node { ++ char *rn_url; /* unparsed, deletable */ ++ int rn_umode; ++ char *rn_address; /* substring of rn_url */ ++ int rn_fd; /* control fd */ ++ int rn_disabled; /* found unaccessible? */ ++ unsigned rn_weight; /* for load balancing */ ++ int rn_recheck_ticks; ++ struct rtpp_node *rn_next; ++}; ++ ++/* RTP proxy balancing list */ ++static struct rtpp_head rtpp_list; ++static int rtpp_node_count = 0; + + static cmd_export_t cmds[] = { + {"fix_nated_contact", fix_nated_contact_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, + {"fix_nated_sdp", fix_nated_sdp_f, 1, fixup_str2int, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE }, ++ {"fixate_sdp", fixate_sdp_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, + {"unforce_rtp_proxy", unforce_rtp_proxy_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE }, + {"force_rtp_proxy", force_rtp_proxy0_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, + {"force_rtp_proxy", force_rtp_proxy1_f, 1, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, +@@ -246,11 +290,16 @@ + {"nat_uac_test", nat_uac_test_f, 1, fixup_str2int, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE }, + {"fix_nated_register", fix_nated_register_f, 0, 0, REQUEST_ROUTE }, + {"add_rcv_param", add_rcv_param_f, 0, 0, REQUEST_ROUTE }, ++ {"rewrite_from_from", rewrite_from_from_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, ++ {"is_hold", is_hold_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, ++ {"start_moh", start_moh_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, ++ {"stop_moh", stop_moh_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, + {0, 0, 0, 0, 0} + }; + + static param_export_t params[] = { + {"natping_interval", INT_PARAM, &natping_interval }, ++ {"natping_method", STR_PARAM, &natping_method }, + {"ping_nated_only", INT_PARAM, &ping_nated_only }, + {"rtpproxy_sock", STR_PARAM, &rtpproxy_sock }, + {"rtpproxy_disable", INT_PARAM, &rtpproxy_disable }, +@@ -259,6 +308,10 @@ + {"rtpproxy_tout", INT_PARAM, &rtpproxy_tout }, + {"received_avp", INT_PARAM, &rcv_avp_no }, + {"force_socket", STR_PARAM, &force_socket_str }, ++ {"pname_audio", STR_PARAM, &pname_audio }, ++ {"pname_video", STR_PARAM, &pname_video }, ++ {"codecs_audio", STR_PARAM, &codecs_audio }, ++ {"codecs_video", STR_PARAM, &codecs_video }, + {0, 0, 0} + }; + +@@ -277,8 +330,6 @@ + mod_init(void) + { + int i; +- char *cp; +- bind_usrloc_t bind_usrloc; + struct in_addr addr; + str socket_str; + +@@ -288,18 +339,9 @@ + force_socket=grep_sock_info(&socket_str,0,0); + } + +- if (natping_interval > 0) { +- bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); +- if (!bind_usrloc) { +- LOG(L_ERR, "nathelper: Can't find usrloc module\n"); +- return -1; +- } +- +- if (bind_usrloc(&ul) < 0) { +- return -1; +- } +- +- register_timer(timer, NULL, natping_interval); ++ if (natpinger_init() < 0) { ++ LOG(L_ERR, "nathelper: natpinger_init() failed\n"); ++ return -1; + } + + /* Prepare 1918 networks list */ +@@ -309,25 +351,72 @@ + nets_1918[i].netaddr = ntohl(addr.s_addr) & nets_1918[i].mask; + } + ++ memset(&rtpp_list, 0, sizeof(rtpp_list)); ++ rtpp_node_count = 0; + if (rtpproxy_disable == 0) { +- /* Make rtpproxy_sock writable */ +- cp = pkg_malloc(strlen(rtpproxy_sock) + 1); +- if (cp == NULL) { +- LOG(L_ERR, "nathelper: Can't allocate memory\n"); +- return -1; +- } +- strcpy(cp, rtpproxy_sock); +- rtpproxy_sock = cp; ++ /* Make rtp proxies list. */ ++ char *p, *p1, *p2, *plim; + +- if (strncmp(rtpproxy_sock, "udp:", 4) == 0) { +- umode = 1; +- rtpproxy_sock += 4; +- } else if (strncmp(rtpproxy_sock, "udp6:", 5) == 0) { +- umode = 6; +- rtpproxy_sock += 5; +- } else if (strncmp(rtpproxy_sock, "unix:", 5) == 0) { +- umode = 0; +- rtpproxy_sock += 5; ++ p = rtpproxy_sock; ++ plim = p + strlen(p); ++ for(;;) { ++ struct rtpp_node *pnode; ++ int weight; ++ ++ weight = 1; ++ while (*p && isspace(*p)) ++ ++p; ++ if (p >= plim) ++ break; ++ p1 = p; ++ while (*p && !isspace(*p)) ++ ++p; ++ if (p <= p1) ++ break; /* may happen??? */ ++ /* Have weight specified? If yes, scan it */ ++ p2 = memchr(p1, '=', p - p1); ++ if (p2 != NULL) { ++ weight = strtoul(p2 + 1, NULL, 10); ++ } else { ++ p2 = p; ++ } ++ pnode = pkg_malloc(sizeof(struct rtpp_node)); ++ if (pnode == NULL) { ++ LOG(L_ERR, "nathelper: Can't allocate memory\n"); ++ return -1; ++ } ++ memset(pnode, 0, sizeof(*pnode)); ++ pnode->rn_recheck_ticks = 0; ++ pnode->rn_weight = weight; ++ pnode->rn_umode = 0; ++ pnode->rn_fd = -1; ++ pnode->rn_disabled = 0; ++ pnode->rn_url = pkg_malloc(p2 - p1 + 1); ++ if (pnode->rn_url == NULL) { ++ LOG(L_ERR, "nathelper: Can't allocate memory\n"); ++ return -1; ++ } ++ memmove(pnode->rn_url, p1, p2 - p1); ++ pnode->rn_url[p2 - p1] = 0; ++ if (rtpp_list.rn_first == NULL) { ++ rtpp_list.rn_first = pnode; ++ } else { ++ rtpp_list.rn_last->rn_next = pnode; ++ } ++ rtpp_list.rn_last = pnode; ++ ++rtpp_node_count; ++ /* Leave only address in rn_address */ ++ pnode->rn_address = pnode->rn_url; ++ if (strncmp(pnode->rn_address, "udp:", 4) == 0) { ++ pnode->rn_umode = 1; ++ pnode->rn_address += 4; ++ } else if (strncmp(pnode->rn_address, "udp6:", 5) == 0) { ++ pnode->rn_umode = 6; ++ pnode->rn_address += 5; ++ } else if (strncmp(pnode->rn_address, "unix:", 5) == 0) { ++ pnode->rn_umode = 0; ++ pnode->rn_address += 5; ++ } + } + } + +@@ -340,52 +429,66 @@ + int n; + char *cp; + struct addrinfo hints, *res; ++ struct rtpp_node *pnode; + +- if (rtpproxy_disable == 0) { +- mypid = getpid(); +- if (umode != 0) { +- cp = strrchr(rtpproxy_sock, ':'); +- if (cp != NULL) { +- *cp = '\0'; +- cp++; +- } +- if (cp == NULL || *cp == '\0') +- cp = CPORT; ++ /* Iterate known RTP proxies - create sockets */ ++ mypid = getpid(); ++ for (pnode = rtpp_list.rn_first; pnode != NULL; pnode = pnode->rn_next) { ++ char *old_colon; + +- memset(&hints, 0, sizeof(hints)); +- hints.ai_flags = 0; +- hints.ai_family = (umode == 6) ? AF_INET6 : AF_INET; +- hints.ai_socktype = SOCK_DGRAM; +- if ((n = getaddrinfo(rtpproxy_sock, cp, &hints, &res)) != 0) { +- LOG(L_ERR, "nathelper: getaddrinfo: %s\n", gai_strerror(n)); +- return -1; +- } ++ if (pnode->rn_umode == 0) ++ goto rptest; ++ /* ++ * This is UDP or UDP6. Detect host and port; lookup host; ++ * do connect() in order to specify peer address ++ */ ++ old_colon = cp = strrchr(pnode->rn_address, ':'); ++ if (cp != NULL) { ++ old_colon = cp; ++ *cp = '\0'; ++ cp++; ++ } ++ if (cp == NULL || *cp == '\0') ++ cp = CPORT; + +- controlfd = socket((umode == 6) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); +- if (controlfd == -1) { +- LOG(L_ERR, "nathelper: can't create socket\n"); +- freeaddrinfo(res); +- return -1; +- } ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_flags = 0; ++ hints.ai_family = (pnode->rn_umode == 6) ? AF_INET6 : AF_INET; ++ hints.ai_socktype = SOCK_DGRAM; ++ if ((n = getaddrinfo(pnode->rn_address, cp, &hints, &res)) != 0) { ++ LOG(L_ERR, "nathelper: getaddrinfo: %s\n", gai_strerror(n)); ++ return -1; ++ } ++ if (old_colon) ++ *old_colon = ':'; /* restore rn_address */ + +- if (connect(controlfd, res->ai_addr, res->ai_addrlen) == -1) { +- LOG(L_ERR, "nathelper: can't connect to a RTP proxy\n"); +- close(controlfd); +- freeaddrinfo(res); +- return -1; +- } ++ pnode->rn_fd = socket((pnode->rn_umode == 6) ++ ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); ++ if (pnode->rn_fd == -1) { ++ LOG(L_ERR, "nathelper: can't create socket\n"); + freeaddrinfo(res); ++ return -1; + } + +- rtpproxy_disable = rtpp_test(0, 1); +- } else { +- rtpproxy_disable_tout = -1; ++ if (connect(pnode->rn_fd, res->ai_addr, res->ai_addrlen) == -1) { ++ LOG(L_ERR, "nathelper: can't connect to a RTP proxy\n"); ++ close(pnode->rn_fd); ++ pnode->rn_fd = -1; ++ freeaddrinfo(res); ++ return -1; ++ } ++ freeaddrinfo(res); ++rptest: ++ pnode->rn_disabled = rtpp_test(pnode, 0, 1); + } + ++ if (rtpproxy_disable) ++ rtpproxy_disable_tout = -1; ++ + return 0; + } + +-static int ++int + isnulladdr(str *sx, int pf) + { + char *cp; +@@ -440,7 +543,7 @@ + * assumes the to header is already parsed, so + * make sure it really is before calling this function + */ +-static inline int ++int + get_to_tag(struct sip_msg* _m, str* _tag) + { + +@@ -463,7 +566,7 @@ + /* + * Extract tag from From header field of a request + */ +-static inline int ++int + get_from_tag(struct sip_msg* _m, str* _tag) + { + +@@ -488,7 +591,7 @@ + * (so make sure it is, before calling this function or + * it might fail even if the message _has_ a callid) + */ +-static inline int ++int + get_callid(struct sip_msg* _m, str* _cid) + { + +@@ -562,9 +665,13 @@ + if (anchor == 0) + return -1; + +- hostport = uri.host; +- if (uri.port.len > 0) +- hostport.len = uri.port.s + uri.port.len - uri.host.s; ++ if (uri.maddr_val.len == 0) { ++ hostport = uri.host; ++ if (uri.port.len > 0) ++ hostport.len = uri.port.s + uri.port.len - uri.host.s; ++ } else { ++ hostport = uri.maddr_val; ++ } + + cp = ip_addr2a(&msg->rcv.src_ip); + len = c->uri.len + strlen(cp) + 6 /* :port */ - hostport.len + 1; +@@ -651,11 +758,22 @@ + { + struct sip_uri uri; + contact_t* c; ++ char t; ++ str host; ++ short int port; + + if (get_contact_uri(msg, &uri, &c) == -1) + return -1; + +- return (is1918addr(&(uri.host)) == 1) ? 1 : 0; ++ if (uri.maddr_val.len == 0) ++ return (is1918addr(&(uri.host)) == 1) ? 1 : 0; ++ t = uri.maddr_val.s[uri.maddr_val.len]; ++ uri.maddr_val.s[uri.maddr_val.len] = '\0'; ++ parse_hostport(uri.maddr_val.s, &host, &port); ++ uri.maddr_val.s[uri.maddr_val.len] = t; ++ if (host.len <= 0) ++ return 0; ++ return (is1918addr(&host) == 1) ? 1 : 0; + } + + /* +@@ -755,8 +873,8 @@ + static int + fix_nated_sdp_f(struct sip_msg* msg, char* str1, char* str2) + { +- str body, body1, oldip, oldip1, newip; +- int level, pf, pf1; ++ str body, body1, oldip, newip; ++ int level, pf; + char *buf; + struct lump* anchor; + +@@ -803,37 +921,43 @@ + } + + if (level & FIX_MEDIP) { +- if (extract_mediaip(&body, &oldip, &pf) == -1) { +- LOG(L_ERR, "ERROR: fix_nated_sdp: can't extract media IP from the SDP\n"); +- goto finalize; +- } +- if (pf != AF_INET) { +- LOG(L_ERR, "ERROR: fix_nated_sdp: " +- "not an IPv4 address in SDP\n"); +- goto finalize; +- } +- body1.s = oldip.s + oldip.len; +- body1.len = body.s + body.len - body1.s; +- if (extract_mediaip(&body1, &oldip1, &pf1) == -1) { +- oldip1.len = 0; +- } +- if (oldip1.len > 0 && pf != pf1) { +- LOG(L_ERR, "ERROR: fix_nated_sdp: mismatching " +- "address families in SDP\n"); +- return -1; +- } +- ++ /* Iterate all c= and replace ips in them. */ ++ unsigned hasreplaced = 0; ++ int pf1 = 0; ++ str body2; ++ char* bodylimit = body.s + body.len; + newip.s = ip_addr2a(&msg->rcv.src_ip); + newip.len = strlen(newip.s); +- if (alter_mediaip(msg, &body, &oldip, pf, &newip, pf, +- 1) == -1) { +- LOG(L_ERR, "ERROR: fix_nated_sdp: can't alter media IP"); +- return -1; ++ body1 = body; ++ for(;;) { ++ if (extract_mediaip(&body1, &oldip, &pf) == -1) ++ break; ++ if (pf != AF_INET) { ++ LOG(L_ERR, "ERROR: fix_nated_sdp: " ++ "not an IPv4 address in SDP\n"); ++ goto finalize; ++ } ++ if (!pf1) ++ pf1 = pf; ++ else if (pf != pf1) { ++ LOG(L_ERR, "ERROR: fix_nated_sdp: mismatching " ++ "address families in SDP\n"); ++ return -1; ++ } ++ body2.s = oldip.s + oldip.len; ++ body2.len = bodylimit - body2.s; ++ if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf, ++ 1) == -1) ++ { ++ LOG(L_ERR, "ERROR: fix_nated_sdp: can't alter media IP"); ++ return -1; ++ } ++ hasreplaced = 1; ++ body1 = body2; + } +- if (oldip1.len > 0 && alter_mediaip(msg, &body, &oldip1, pf1, +- &newip, pf, 0) == -1) { +- LOG(L_ERR, "ERROR: fix_nated_sdp: can't alter media IP"); +- return -1; ++ if (!hasreplaced) { ++ LOG(L_ERR, "ERROR: fix_nated_sdp: can't extract media IP from the SDP\n"); ++ goto finalize; + } + } + +@@ -841,7 +965,7 @@ + return 1; + } + +-static int ++int + extract_mediaip(str *body, str *mediaip, int *pf) + { + char *cp, *cp1; +@@ -855,7 +979,7 @@ + cp = cp1 + 2; + } + if (cp1 == NULL) { +- LOG(L_DBG, "ERROR: extract_mediaip: no `c=' in SDP\n"); ++ LOG(L_ERR, "ERROR: extract_mediaip: no `c=' in SDP\n"); + return -1; + } + mediaip->s = cp1 + 2; +@@ -897,11 +1021,12 @@ + return 1; + } + +-static int ++int + extract_mediaport(str *body, str *mediaport) + { + char *cp, *cp1; +- int len; ++ int len, i; ++ str ptype; + + cp1 = NULL; + for (cp = body->s; (len = body->s + body->len - cp) > 0;) { +@@ -914,32 +1039,62 @@ + LOG(L_ERR, "ERROR: extract_mediaport: no `m=' in SDP\n"); + return -1; + } +- mediaport->s = cp1 + 2; ++ mediaport->s = cp1 + 2; /* skip `m=' */ + mediaport->len = eat_line(mediaport->s, body->s + body->len - + mediaport->s) - mediaport->s; + trim_len(mediaport->len, mediaport->s, *mediaport); + +- if (mediaport->len > 6 && memcmp(mediaport->s, "audio", 5) == 0 && +- isspace((int)mediaport->s[5])) { +- mediaport->s += 5; +- mediaport->len -= 5; +- } else if (mediaport->len > 12 && memcmp(mediaport->s, "application", 11) == 0 && +- isspace((int)mediaport->s[11])) { +- mediaport->s += 11; +- mediaport->len -= 11; +- } else { +- LOG(L_ERR, "ERROR: extract_mediaport: can't parse `m=' in SDP\n"); ++ /* Skip media supertype and spaces after it */ ++ cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len); ++ mediaport->len -= cp - mediaport->s; ++ if (mediaport->len <= 0 || cp == mediaport->s) { ++ LOG(L_ERR, "ERROR: extract_mediaport: no port in `m='\n"); + return -1; + } ++ mediaport->s = cp; + cp = eat_space_end(mediaport->s, mediaport->s + mediaport->len); +- mediaport->len = eat_token_end(cp, mediaport->s + mediaport->len) - cp; ++ mediaport->len -= cp - mediaport->s; ++ if (mediaport->len <= 0 || cp == mediaport->s) { ++ LOG(L_ERR, "ERROR: extract_mediaport: no port in `m='\n"); ++ return -1; ++ } ++ /* Extract port */ + mediaport->s = cp; +- return 1; ++ cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len); ++ ptype.len = mediaport->len - (cp - mediaport->s); ++ if (ptype.len <= 0 || cp == mediaport->s) { ++ LOG(L_ERR, "ERROR: extract_mediaport: no port in `m='\n"); ++ return -1; ++ } ++ ptype.s = cp; ++ mediaport->len = cp - mediaport->s; ++ /* Skip spaces after port */ ++ cp = eat_space_end(ptype.s, ptype.s + ptype.len); ++ ptype.len -= cp - ptype.s; ++ if (ptype.len <= 0 || cp == ptype.s) { ++ LOG(L_ERR, "ERROR: extract_mediaport: no protocol type in `m='\n"); ++ return -1; ++ } ++ /* Extract protocol type */ ++ ptype.s = cp; ++ cp = eat_token_end(ptype.s, ptype.s + ptype.len); ++ if (cp == ptype.s) { ++ LOG(L_ERR, "ERROR: extract_mediaport: no protocol type in `m='\n"); ++ return -1; ++ } ++ ptype.len = cp - ptype.s; ++ ++ for (i = 0; sup_ptypes[i].s != NULL; i++) ++ if (ptype.len == sup_ptypes[i].len && ++ strncasecmp(ptype.s, sup_ptypes[i].s, ptype.len) == 0) ++ return 0; ++ /* Unproxyable protocol type. Generally it isn't error. */ ++ return -1; + } + +-static int ++int + alter_mediaip(struct sip_msg *msg, str *body, str *oldip, int oldpf, +- str *newip, int newpf, int preserve) ++ str *newip, int newpf, int flags) + { + char *buf; + int offset; +@@ -947,7 +1102,7 @@ + str omip, nip, oip; + + /* check that updating mediaip is really necessary */ +- if (oldpf == newpf && isnulladdr(oldip, oldpf)) ++ if (oldpf == newpf && isnulladdr(oldip, oldpf) && !(flags & 2)) + return 0; + if (newip->len == oldip->len && + memcmp(newip->s, oldip->s, newip->len) == 0) +@@ -960,7 +1115,7 @@ + * another request comes. + */ + #if 0 +- /* disabled: ++ /* disabled: + * - alter_mediaip is called twice if 2 c= lines are present + * in the sdp (and we want to allow it) + * - the message flags are propagated in the on_reply_route +@@ -975,7 +1130,7 @@ + } + #endif + +- if (preserve != 0) { ++ if ((flags & 1) != 0) { + anchor = anchor_lump(msg, body->s + body->len - msg->buf, 0, 0); + if (anchor == NULL) { + LOG(L_ERR, "ERROR: alter_mediaip: anchor_lump failed\n"); +@@ -1051,7 +1206,7 @@ + return 0; + } + +-static int ++int + alter_mediaport(struct sip_msg *msg, str *body, str *oldport, str *newport, + int preserve) + { +@@ -1127,6 +1282,161 @@ + return 0; + } + ++/* ++ * Finds specified text in area [*pp...bodylimit) at line beginning. ++ * Returns pointer to text, updates *pp to position after it. ++ */ ++ ++static char* ++find_sdp_text_bol(char **pp, char *plimit, char *text, size_t textlen) ++{ ++ /* Find text at beginning of line */ ++ if (*pp == NULL) ++ return NULL; ++ for(;;) { ++ char* p; ++ if (*pp >= plimit) ++ return NULL; ++ if (!(p = ser_memmem(*pp, text, plimit - *pp, textlen))) { ++ *pp = plimit; ++ return NULL; ++ } ++ *pp = p + 1; ++ if (p[-1] != '\n' && p[-1] != '\r') ++ continue; ++ return p; ++ } ++ /*UNREACHED*/ ++ return NULL; ++} ++ ++static int ++fixate_sdp_f(struct sip_msg* msg, char* str1, char* str2) ++{ ++ char *cp; ++ int newpf; ++ str body, newip, newport, dest, oldip, oldport; ++ struct sip_uri ruri; ++ struct hdr_field *hdr; ++ struct via_body *rvia; ++ char *bodylimit, *v1p, *v2p, *m1p, *m2p, *c1p, *c2p; ++ char *om_ip_pos, *om_port_pos; ++ int c1_altered; ++ ++ if (msg->first_line.type == SIP_REQUEST && ++ msg->first_line.u.request.method_value == METHOD_INVITE) { ++ LOG(L_ERR, "DEBUG: fixate_sdp: request\n"); ++ if (msg->parsed_uri_ok) { ++ dest = msg->parsed_uri.host; ++ } else { ++ if (parse_uri(msg->new_uri.s, msg->new_uri.len, &ruri) < 0) { ++ LOG(L_ERR, "ERROR: fixate_sdp: can't parse request uri\n"); ++ return -1; ++ } ++ dest = ruri.host; ++ } ++ } else if (msg->first_line.type == SIP_REPLY) { ++ LOG(L_ERR, "DEBUG: fixate_sdp: reply\n"); ++ rvia = NULL; ++ for (hdr=msg->headers; hdr; hdr=hdr->next) { ++ if (hdr->type == HDR_VIA) ++ rvia = hdr->parsed; ++ } ++ if (rvia == NULL) { ++ LOG(L_ERR, "ERROR: fixate_sdp: no or incorrect Via in reply\n"); ++ return -1; ++ } ++ if (rvia->received != NULL) { ++ dest = rvia->received->value; ++ } else { ++ dest = rvia->host; ++ } ++ } else { ++ return -1; ++ } ++ ++ if (extract_body(msg, &body) == -1 || body.len == 0) { ++ LOG(L_ERR, "ERROR: fixate_sdp: can't extract body " ++ "from the message\n"); ++ return -1; ++ } ++ bodylimit = body.s + body.len; ++ v2p = v1p = find_sdp_line(body.s, bodylimit, 'v'); ++ if (!v1p) { ++ LOG(L_ERR, "fixate_sdp: no sessions found\n"); ++ return -1; ++ } ++ om_ip_pos = body.s; ++ om_port_pos = body.s; ++ for(;;) { ++ v1p = v2p; ++ if (v1p == NULL || v1p >= bodylimit) ++ break; ++ v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit); ++ m2p = m1p = find_sdp_line(v1p, v2p, 'm'); ++ c1p = find_sdp_line(v1p, v2p, 'c'); ++ c1_altered = 0; ++ if (!m1p) { ++ LOG(L_ERR, "fixate_sdp: session without media\n"); ++ return -1; ++ } ++ for(;;) { ++ str tmpstr1; ++ m1p = m2p; ++ if (m1p == NULL || m1p >= v2p) ++ break; ++ m2p = find_next_sdp_line(m1p, v2p, 'm', v2p); ++ c2p = find_sdp_line(m1p, m2p, 'c'); ++ /* Set old port and IP. Order doesn't matter. */ ++ tmpstr1.s = m1p; ++ tmpstr1.len = bodylimit - m1p; ++ if (extract_mediaport(&tmpstr1, &newport) == -1) { ++ LOG(L_ERR, "ERROR: fixate_sdp: can't extract media port from the SDP\n"); ++ return -1; ++ } ++ cp = find_sdp_text_bol(&om_port_pos, bodylimit, AOLDMEDPRT, AOLDMEDPRT_LEN); ++ if (cp) { ++ oldport.s = cp + AOLDMEDPRT_LEN; ++ oldport.len = eat_line(oldport.s, bodylimit - oldport.s) - oldport.s; ++ trim_len(oldport.len, oldport.s, oldport); ++ if (oldport.len != 0 && ++ alter_mediaport(msg, &body, &newport, &oldport, 0) == -1) ++ return -1; ++ } ++ if (c2p || !c1_altered) { ++ tmpstr1.s = c2p ? c2p : c1p; ++ tmpstr1.len = bodylimit - tmpstr1.s; ++ if (extract_mediaip(&tmpstr1, &newip, &newpf) == -1) { ++ LOG(L_ERR, "ERROR: fixate_sdp: can't extract media IP from the SDP\n"); ++ return -1; ++ } ++ if (newip.len != dest.len || memcmp(newip.s, dest.s, dest.len) != 0 || ++ isnulladdr(&newip, newpf)) ++ return -1; ++ cp = find_sdp_text_bol(&om_ip_pos, bodylimit, AOLDMEDIP, AOLDMEDIP_LEN); ++ if (cp) { ++ oldip.s = cp + AOLDMEDIP_LEN; ++ oldip.len = eat_line(oldip.s, bodylimit - oldip.s) - oldip.s; ++ trim_len(oldip.len, oldip.s, oldip); ++ } ++ if (newip.len == oldip.len && ++ memcmp(newip.s, oldip.s, newip.len) == 0) ++ oldip.len = 0; ++ ++ if (oldip.len != 0) { ++ if (alter_mediaip(msg, &body, &newip, newpf, &oldip, AF_INET, ++ 0) == -1) ++ return -1; ++ } ++ if (!c2p) ++ c1_altered = 1; ++ } /* if rewrite IP */ ++ } /* medias */ ++ } /* sessions */ ++ ++ return 1; ++} ++ + static char * + gencookie() + { +@@ -1138,45 +1448,58 @@ + } + + static int +-rtpp_test(int isdisabled, int force) ++rtpp_test(struct rtpp_node *node, int isdisabled, int force) + { + int rtpp_ver; +- static int recheck_ticks = 0; + char *cp; + struct iovec v[2] = {{NULL, 0}, {"V", 1}}; ++ struct iovec vf[4] = {{NULL, 0}, {"VF", 2}, {" ", 1}, ++ {REQ_CPROTOVER, 8}}; + + if (force == 0) { + if (isdisabled == 0) + return 0; +- if (recheck_ticks > get_ticks()) ++ if (node->rn_recheck_ticks > get_ticks()) + return 1; + } +- cp = send_rtpp_command(v, 2); +- if (cp == NULL) { +- LOG(L_WARN,"WARNING: rtpp_test: can't get version of " +- "the RTP proxy\n"); +- } else { ++ do { ++ cp = send_rtpp_command(node, v, 2); ++ if (cp == NULL) { ++ LOG(L_WARN,"WARNING: rtpp_test: can't get version of " ++ "the RTP proxy\n"); ++ break; ++ } + rtpp_ver = atoi(cp); +- if (rtpp_ver == SUP_CPROTOVER) { +- LOG(L_INFO, "rtpp_test: RTP proxy found, support for " +- "it %senabled\n", force == 0 ? "re-" : ""); +- return 0; ++ if (rtpp_ver != SUP_CPROTOVER) { ++ LOG(L_WARN, "WARNING: rtpp_test: unsupported " ++ "version of RTP proxy <%s> found: %d supported, " ++ "%d present\n", node->rn_url, ++ SUP_CPROTOVER, rtpp_ver); ++ break; + } +- LOG(L_WARN, "WARNING: rtpp_test: unsupported " +- "version of RTP proxy found: %d supported, " +- "%d present\n", SUP_CPROTOVER, rtpp_ver); +- } +- LOG(L_WARN, "WARNING: rtpp_test: support for RTP proxy " +- "has been disabled%s\n", ++ cp = send_rtpp_command(node, vf, 4); ++ if (cp[0] == 'E' || atoi(cp) != 1) { ++ LOG(L_WARN, "WARNING: rtpp_test: of RTP proxy <%s>" ++ "doesn't support required protocol version %s\n", ++ node->rn_url, REQ_CPROTOVER); ++ break; ++ } ++ LOG(L_INFO, "rtpp_test: RTP proxy <%s> found, support for " ++ "it %senabled\n", ++ node->rn_url, force == 0 ? "re-" : ""); ++ return 0; ++ } while(0); ++ LOG(L_WARN, "WARNING: rtpp_test: support for RTP proxy <%s>" ++ "has been disabled%s\n", node->rn_url, + rtpproxy_disable_tout < 0 ? "" : " temporarily"); + if (rtpproxy_disable_tout >= 0) +- recheck_ticks = get_ticks() + rtpproxy_disable_tout; ++ node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout; + + return 1; + } + +-static char * +-send_rtpp_command(struct iovec *v, int vcnt) ++char * ++send_rtpp_command(struct rtpp_node *node, struct iovec *v, int vcnt) + { + struct sockaddr_un addr; + int fd, len, i; +@@ -1186,10 +1509,10 @@ + + len = 0; + cp = buf; +- if (umode == 0) { ++ if (node->rn_umode == 0) { + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_LOCAL; +- strncpy(addr.sun_path, rtpproxy_sock, ++ strncpy(addr.sun_path, node->rn_address, + sizeof(addr.sun_path) - 1); + #ifdef HAVE_SOCKADDR_SA_LEN + addr.sun_len = strlen(addr.sun_path); +@@ -1198,12 +1521,12 @@ + fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (fd < 0) { + LOG(L_ERR, "ERROR: send_rtpp_command: can't create socket\n"); +- return NULL; ++ goto badproxy; + } + if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(fd); + LOG(L_ERR, "ERROR: send_rtpp_command: can't connect to RTP proxy\n"); +- return NULL; ++ goto badproxy; + } + + do { +@@ -1212,7 +1535,7 @@ + if (len <= 0) { + close(fd); + LOG(L_ERR, "ERROR: send_rtpp_command: can't send command to a RTP proxy\n"); +- return NULL; ++ goto badproxy; + } + do { + len = read(fd, buf, sizeof(buf) - 1); +@@ -1220,38 +1543,38 @@ + close(fd); + if (len <= 0) { + LOG(L_ERR, "ERROR: send_rtpp_command: can't read reply from a RTP proxy\n"); +- return NULL; ++ goto badproxy; + } + } else { +- fds[0].fd = controlfd; ++ fds[0].fd = node->rn_fd; + fds[0].events = POLLIN; + fds[0].revents = 0; + /* Drain input buffer */ + while ((poll(fds, 1, 0) == 1) && + ((fds[0].revents & POLLIN) != 0)) { +- recv(controlfd, buf, sizeof(buf) - 1, 0); ++ recv(node->rn_fd, buf, sizeof(buf) - 1, 0); + fds[0].revents = 0; + } + v[0].iov_base = gencookie(); + v[0].iov_len = strlen(v[0].iov_base); + for (i = 0; i < rtpproxy_retr; i++) { + do { +- len = writev(controlfd, v, vcnt); ++ len = writev(node->rn_fd, v, vcnt); + } while (len == -1 && (errno == EINTR || errno == ENOBUFS)); + if (len <= 0) { + LOG(L_ERR, "ERROR: send_rtpp_command: " + "can't send command to a RTP proxy\n"); +- return NULL; ++ goto badproxy; + } + while ((poll(fds, 1, rtpproxy_tout * 1000) == 1) && + (fds[0].revents & POLLIN) != 0) { + do { +- len = recv(controlfd, buf, sizeof(buf) - 1, 0); ++ len = recv(node->rn_fd, buf, sizeof(buf) - 1, 0); + } while (len == -1 && errno == EINTR); + if (len <= 0) { + LOG(L_ERR, "ERROR: send_rtpp_command: " + "can't read reply from a RTP proxy\n"); +- return NULL; ++ goto badproxy; + } + if (len >= (v[0].iov_len - 1) && + memcmp(buf, v[0].iov_base, (v[0].iov_len - 1)) == 0) { +@@ -1269,28 +1592,97 @@ + if (i == rtpproxy_retr) { + LOG(L_ERR, "ERROR: send_rtpp_command: " + "timeout waiting reply from a RTP proxy\n"); +- return NULL; ++ goto badproxy; + } + } + + out: + cp[len] = '\0'; + return cp; ++badproxy: ++ LOG(L_ERR, "send_rtpp_command(): proxy <%s> does not responding, disable it\n", node->rn_url); ++ node->rn_disabled = 1; ++ node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout; ++ return NULL; ++} ++ ++/* ++ * Main balancing routine. This does not try to keep the same proxy for ++ * the call if some proxies were disabled or enabled; proxy death considered ++ * too rare. Otherwise we should implement "mature" HA clustering, which is ++ * too expensive here. ++ */ ++struct rtpp_node * ++select_rtpp_node(str callid, int do_test) ++{ ++ unsigned sum, sumcut, weight_sum; ++ struct rtpp_node* node; ++ int was_forced; ++ ++ /* Most popular case: 1 proxy, nothing to calculate */ ++ if (rtpp_node_count == 1) { ++ node = rtpp_list.rn_first; ++ return node->rn_disabled ? NULL : node; ++ } ++ ++ /* XXX Use quick-and-dirty hashing algo */ ++ for(sum = 0; callid.len > 0; callid.len--) ++ sum += callid.s[callid.len - 1]; ++ sum &= 0xff; ++ ++ was_forced = 0; ++retry: ++ weight_sum = 0; ++ for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) { ++ if (node->rn_disabled) { ++ /* Try to enable if it's time to try. */ ++ if (node->rn_recheck_ticks <= get_ticks()) ++ node->rn_disabled = rtpp_test(node, 1, 0); ++ } ++ if (!node->rn_disabled) ++ weight_sum += node->rn_weight; ++ } ++ if (weight_sum == 0) { ++ /* No proxies? Force all to be redetected, if not yet */ ++ if (was_forced) ++ return NULL; ++ was_forced = 1; ++ for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) { ++ node->rn_disabled = rtpp_test(node, 1, 1); ++ } ++ goto retry; ++ } ++ sumcut = sum % weight_sum; ++ /* ++ * sumcut here lays from 0 to weight_sum-1. ++ * Scan proxy list and decrease until appropriate proxy is found. ++ */ ++ for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) { ++ if (node->rn_disabled) ++ continue; ++ if (sumcut < node->rn_weight) ++ goto found; ++ sumcut -= node->rn_weight; ++ } ++ /* No node list */ ++ return NULL; ++found: ++ if (do_test) { ++ node->rn_disabled = rtpp_test(node, node->rn_disabled, 0); ++ if (node->rn_disabled) ++ goto retry; ++ } ++ return node; + } + + static int + unforce_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2) + { + str callid, from_tag, to_tag; ++ struct rtpp_node *node; + struct iovec v[1 + 4 + 3] = {{NULL, 0}, {"D", 1}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}}; + /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 1 */ + +- rtpproxy_disable = rtpp_test(rtpproxy_disable, 0); +- if (rtpproxy_disable != 0) { +- LOG(L_ERR, "ERROR: unforce_rtp_proxy: support for RTP proxy " +- "is disabled\n"); +- return -1; +- } + if (get_callid(msg, &callid) == -1 || callid.len == 0) { + LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get Call-Id field\n"); + return -1; +@@ -1306,29 +1698,139 @@ + STR2IOVEC(callid, v[3]); + STR2IOVEC(from_tag, v[5]); + STR2IOVEC(to_tag, v[7]); +- send_rtpp_command(v, (to_tag.len > 0) ? 8 : 6); ++ node = select_rtpp_node(callid, 1); ++ if (!node) { ++ LOG(L_ERR, "ERROR: unforce_rtp_proxy: no available proxies\n"); ++ return -1; ++ } ++ send_rtpp_command(node, v, (to_tag.len > 0) ? 8 : 6); ++ ++ return 1; ++} ++ ++/* ++ * Auxiliary for some functions. ++ * Returns pointer to first character of found line, or NULL if no such line. ++ */ ++ ++char* ++find_sdp_line(char *p, char *plimit, char linechar) ++{ ++ static char linehead[3] = "x="; ++ char *cp, *cp1; ++ linehead[0] = linechar; ++ /* Iterate thru body */ ++ cp = p; ++ for (;;) { ++ if (cp >= plimit) ++ return NULL; ++ cp1 = ser_memmem(cp, linehead, plimit-cp, 2); ++ if (cp1 == NULL) ++ return NULL; ++ /* ++ * As it is body, we assume it has previous line and we can ++ * lookup previous character. ++ */ ++ if (cp1[-1] == '\n' || cp1[-1] == '\r') ++ return cp1; ++ /* ++ * Having such data, but not at line beginning. ++ * Skip them and reiterate. ser_memmem() will find next ++ * occurence. ++ */ ++ if (plimit - cp1 < 2) ++ return NULL; ++ cp = cp1 + 2; ++ } ++ /*UNREACHED*/ ++ return NULL; ++} ++ ++/* This function assumes p points to a line of requested type. */ ++ ++char* ++find_next_sdp_line(char *p, char *plimit, char linechar, char *defptr) ++{ ++ char* t; ++ if (p >= plimit || plimit - p < 3) ++ return defptr; ++ t = find_sdp_line(p + 2, plimit, linechar); ++ return t ? t : defptr; ++} + ++static int ++alter_line(struct sip_msg *msg, str *where, str *what) ++{ ++ struct lump *anchor; ++ anchor = del_lump(msg, where->s - msg->buf, where->len, 0); ++ if (!anchor) { ++ LOG(L_ERR, "del_lump() failed\n"); ++ return 0; ++ } ++ if (insert_new_lump_after(anchor, what->s, what->len, 0) == 0) { ++ LOG(L_ERR, "insert_new_lump_after() failed\n"); ++ return 0; ++ } + return 1; + } + ++/* ++ * The following macro is used in force_rtp_proxy2_f() and twice ++ * in start_moh() ++ */ ++ ++#define PARSE_PROXY_REPLY \ ++ do { \ ++ argc = 0; \ ++ memset(argv, 0, sizeof(argv)); \ ++ cpend=cp+strlen(cp); \ ++ next=eat_token_end(cp, cpend); \ ++ for (ap = argv; cp<cpend; cp=next+1, next=eat_token_end(cp, cpend)){ \ ++ *next=0; \ ++ if (*cp != '\0') { \ ++ *ap=cp; \ ++ argc++; \ ++ if ((char*)++ap >= ((char*)argv+sizeof(argv))) \ ++ break; \ ++ } \ ++ } \ ++ } while(0) ++ + static int + force_rtp_proxy2_f(struct sip_msg* msg, char* str1, char* str2) + { +- str body, body1, oldport, oldip, oldip1, newport, newip; +- str callid, from_tag, to_tag, tmp; ++ str body, body1, oldport, oldip, newport, newip; ++ str callid, from_tag, to_tag; + int create, port, len, asymmetric, flookup, argc, proxied, real; ++ int create1; + int oidx, pf, pf1, force; + char opts[16]; + char *cp, *cp1; + char *cpend, *next; + char **ap, *argv[10]; + struct lump* anchor; +- struct iovec v[1 + 6 + 5] = {{NULL, 0}, {NULL, 0}, {" ", 1}, {NULL, 0}, +- {" ", 1}, {NULL, 7}, {" ", 1}, {NULL, 1}, {" ", 1}, {NULL, 0}, +- {" ", 1}, {NULL, 0}}; +- /* 1 */ /* 2 */ /* 3 */ /* 4 */ +- /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* 10 */ +- /* 11 */ ++ struct rtpp_node *node; ++ struct iovec v[14] = { ++ {NULL, 0}, /* command */ ++ {NULL, 0}, /* options */ ++ {" ", 1}, /* separator */ ++ {NULL, 0}, /* callid */ ++ {" ", 1}, /* separator */ ++ {NULL, 7}, /* newip */ ++ {" ", 1}, /* separator */ ++ {NULL, 1}, /* oldport */ ++ {" ", 1}, /* separator */ ++ {NULL, 0}, /* from_tag */ ++ {";", 1}, /* separator */ ++ {NULL, 0}, /* medianum */ ++ {" ", 1}, /* separator */ ++ {NULL, 0} /* to_tag */ ++ }; ++ char *v1p, *v2p, *c1p, *c2p, *m1p, *m2p, *bodylimit; ++ char medianum_buf[20]; ++ int medianum, media_multi; ++ str medianum_str, tmpstr1; ++ int c1_altered; + + v[1].iov_base=opts; + asymmetric = flookup = force = real = 0; +@@ -1373,13 +1875,6 @@ + } + } + +- rtpproxy_disable = rtpp_test(rtpproxy_disable, 0); +- if (rtpproxy_disable != 0) { +- LOG(L_ERR, "ERROR: force_rtp_proxy2: support for RTP proxy " +- "is disabled\n"); +- return -1; +- } +- + if (msg->first_line.type == SIP_REQUEST && + msg->first_line.u.request.method_value == METHOD_INVITE) { + create = 1; +@@ -1408,14 +1903,7 @@ + LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get From tag\n"); + return -1; + } +- if (flookup != 0) { +- if (create == 0 || to_tag.len == 0) +- return -1; +- create = 0; +- tmp = from_tag; +- from_tag = to_tag; +- to_tag = tmp; +- } ++ + proxied = 0; + for (cp = body.s; (len = body.s + body.len - cp) >= ANORTPPROXY_LEN;) { + cp1 = ser_memmem(cp, ANORTPPROXY, len, ANORTPPROXY_LEN); +@@ -1429,88 +1917,198 @@ + } + if (proxied != 0 && force == 0) + return -1; +- if (extract_mediaip(&body, &oldip, &pf) == -1) { +- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't extract media IP " +- "from the message\n"); +- return -1; +- } +- if (asymmetric != 0 || real != 0) { +- newip = oldip; +- } else { +- newip.s = ip_addr2a(&msg->rcv.src_ip); +- newip.len = strlen(newip.s); +- } +- body1.s = oldip.s + oldip.len; +- body1.len = body.s + body.len - body1.s; +- if (extract_mediaip(&body1, &oldip1, &pf1) == -1) { +- oldip1.len = 0; +- } +- if (oldip1.len > 0 && pf != pf1) { +- LOG(L_ERR, "ERROR: force_rtp_proxy2: mismatching address " +- "families in SDP\n"); +- return -1; +- } +- if (extract_mediaport(&body, &oldport) == -1) { +- LOG(L_ERR, "ERROR: force_rtp_proxy2: can't extract media port " +- "from the message\n"); ++ /* ++ * Parsing of SDP body. ++ * It can contain a few session descriptions (each start with ++ * "v=" line), and each session may contain a few media descriptions ++ * (each start with "m=" line). ++ * We have to change ports in "m=", and also change IP addresses in ++ * "c=" which can be placed either in session header (fallback for ++ * all medias) or media description. ++ * Ports should be allocated for any media. IPs all should be changed ++ * to the same value (RTP proxy IP), so we can change all "c=" ++ * unconditionally. ++ */ ++ bodylimit = body.s + body.len; ++ v1p = find_sdp_line(body.s, bodylimit, 'v'); ++ if (v1p == NULL) { ++ LOG(L_ERR, "ERROR: force_rtp_proxy2: no sessions in SDP\n"); + return -1; + } +- if (pf == AF_INET6) { +- opts[oidx] = '6'; +- oidx++; +- } +- opts[0] = (create == 0) ? 'L' : 'U'; +- v[1].iov_len = oidx; +- STR2IOVEC(callid, v[3]); +- STR2IOVEC(newip, v[5]); +- STR2IOVEC(oldport, v[7]); +- STR2IOVEC(from_tag, v[9]); +- STR2IOVEC(to_tag, v[11]); +- cp = send_rtpp_command(v, (to_tag.len > 0) ? 12 : 10); +- if (cp == NULL) +- return -1; +- argc = 0; +- memset(argv, 0, sizeof(argv)); +- cpend=cp+strlen(cp); +- next=eat_token_end(cp, cpend); +- for (ap = argv; cp<cpend; cp=next+1, next=eat_token_end(cp, cpend)){ +- *next=0; +- if (*cp != '\0') { +- *ap=cp; +- argc++; +- if ((char*)++ap >= ((char*)argv+sizeof(argv))) +- break; ++ v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit); ++ media_multi = (v2p != bodylimit); ++ v2p = v1p; ++ medianum = 0; ++ for (;;) { ++ unsigned nmseen, nmchanged; ++ /* Per-session iteration. */ ++ v1p = v2p; ++ if (v1p == NULL || v1p >= bodylimit) ++ break; /* No sessions left */ ++ v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit); ++ /* v2p is text limit for session parsing. */ ++ m1p = find_sdp_line(v1p, v2p, 'm'); ++ /* Have this session media description? */ ++ if (m1p == NULL) { ++ LOG(L_ERR, "ERROR: force_rtp_proxy2: no m= in session\n"); ++ return -1; + } +- } +- if (argc < 1) +- return -1; +- port = atoi(argv[0]); +- if (port <= 0 || port > 65535) +- return -1; ++ /* ++ * Find c1p only between session begin and first media. ++ * c1p will give common c= for all medias. ++ */ ++ c1p = find_sdp_line(v1p, m1p, 'c'); ++ c1_altered = 0; ++ /* Have session. Iterate media descriptions in session */ ++ m2p = m1p; ++ nmseen = nmchanged = 0; ++ for (;;) { ++ create1 = create; ++ if (flookup != 0) { ++ if (!create || to_tag.len <= 0) { ++ LOG(L_ERR, "force_rtp_proxy(): inappropriate 'l'\n"); ++ return -1; ++ } ++ create1 = 0; ++ } ++ m1p = m2p; ++ if (m1p == NULL || m1p >= v2p) ++ break; ++ m2p = find_next_sdp_line(m1p, v2p, 'm', v2p); ++ /* c2p will point to per-media "c=" */ ++ c2p = find_sdp_line(m1p, m2p, 'c'); ++ /* Extract address and port */ ++ tmpstr1.s = c2p ? c2p : c1p; ++ ++nmseen; ++ if (tmpstr1.s == NULL) { ++ /* No "c=" */ ++ LOG(L_ERR, "ERROR: force_rtp_proxy2: can't find media IP " ++ "in the message\n"); ++ return -1; ++ } ++ tmpstr1.len = v2p - tmpstr1.s; /* limit is session limit text */ ++ if (extract_mediaip(&tmpstr1, &oldip, &pf) == -1) { ++ LOG(L_ERR, "ERROR: force_rtp_proxy2: can't extract media IP " ++ "from the message\n"); ++ return -1; ++ } ++ tmpstr1.s = m1p; ++ tmpstr1.len = m2p - m1p; ++ if (extract_mediaport(&tmpstr1, &oldport) == -1) { ++ LOG(L_ERR, "ERROR: force_rtp_proxy2: can't extract media port " ++ "from the message\n"); ++ return -1; ++ } ++ ++medianum; ++ if (asymmetric != 0 || real != 0) { ++ newip = oldip; ++ } else { ++ newip.s = ip_addr2a(&msg->rcv.src_ip); ++ newip.len = strlen(newip.s); ++ } ++ /* XXX must compare address families in all addresses */ ++ if (pf == AF_INET6) { ++ opts[oidx] = '6'; ++ oidx++; ++ } ++ snprintf(medianum_buf, sizeof medianum_buf, "%d", medianum); ++ medianum_str.s = medianum_buf; ++ medianum_str.len = strlen(medianum_buf); ++ opts[0] = (create1 == 0) ? 'L' : 'U'; ++ v[1].iov_len = oidx; ++ STR2IOVEC(callid, v[3]); ++ STR2IOVEC(newip, v[5]); ++ STR2IOVEC(oldport, v[7]); ++ /*assert(!flookup || to_tag.len > 0);*/ ++ STR2IOVEC(flookup ? to_tag : from_tag, v[9]); ++ if (1 || media_multi) /* XXX */ { ++ STR2IOVEC(medianum_str, v[11]); ++ } else { ++ v[10].iov_len = v[11].iov_len = 0; ++ } ++ STR2IOVEC(flookup ? from_tag : to_tag, v[13]); ++ do { ++ node = select_rtpp_node(callid, 1); ++ if (!node) { ++ LOG(L_ERR, "ERROR: force_rtp_proxy2: no available proxies\n"); ++ return -1; ++ } ++ cp = send_rtpp_command(node, v, ++ (to_tag.len > 0) ? 14 : 12); ++ } while (cp == NULL); ++ LOG(L_DBG, "force_rtp_proxy2: proxy reply: %s\n", cp); ++ PARSE_PROXY_REPLY; ++ if (argc < 1) { ++ LOG(L_ERR, "force_rtp_proxy2: no reply from rtp proxy\n"); ++ return -1; ++ } ++ port = atoi(argv[0]); ++ if (port <= 0 || port > 65535) { ++ LOG(L_ERR, "force_rtp_proxy2: incorrect port in reply from rtp proxy\n"); ++ return -1; ++ } + +- pf1 = (argc >= 3 && argv[2][0] == '6') ? AF_INET6 : AF_INET; ++ pf1 = (argc >= 3 && argv[2][0] == '6') ? AF_INET6 : AF_INET; + +- if (isnulladdr(&oldip, pf)) { +- if (pf1 == AF_INET6) { +- newip.s = "::"; +- newip.len = 2; +- } else { +- newip.s = "0.0.0.0"; +- newip.len = 7; ++ if (isnulladdr(&oldip, pf)) { ++ if (pf1 == AF_INET6) { ++ newip.s = "::"; ++ newip.len = 2; ++ } else { ++ newip.s = "0.0.0.0"; ++ newip.len = 7; ++ } ++ } else { ++ newip.s = (argc < 2) ? str2 : argv[1]; ++ newip.len = strlen(newip.s); ++ } ++ newport.s = int2str(port, &newport.len); /* beware static buffer */ ++ /* Alter port. */ ++ body1.s = m1p; ++ body1.len = bodylimit - body1.s; ++ if (alter_mediaport(msg, &body1, &oldport, &newport, 0) == -1) ++ return -1; ++ /* ++ * Alter IP. Don't alter IP common for the session ++ * more than once. ++ */ ++ if (c2p != NULL || !c1_altered) { ++ body1.s = c2p ? c2p : c1p; ++ body1.len = bodylimit - body1.s; ++ if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 0) == -1) ++ return -1; ++ if (!c2p) ++ c1_altered = 1; ++ } ++ ++nmchanged; ++ /* ++ * Gross hack: turn off flookup here, after first ++ * media stream. This is used to allow changing number ++ * of media streams during re-INVITE. ++ */ ++ flookup = 0; ++ } /* Iterate medias in session */ ++ if (c1p && nmseen == nmchanged && !c1_altered) { ++ /* Alter default c-line of this session. */ ++ str c1s, janus; ++ size_t newlen; ++ c1s.s = c1p; ++ c1s.len = eat_line(c1p, bodylimit - c1p) - c1p; ++ newlen = c1s.len + 6 + 1; ++ janus.s = pkg_malloc(c1s.len); ++ if (janus.s == NULL) { ++ LOG(L_ERR, "pkg_malloc failed\n"); ++ return 0; ++ } ++ sprintf(janus.s, "a=oldc:%*.*s", ++ (int) c1s.len, (int) c1s.len, c1s.s); ++ janus.len = strlen(janus.s); ++ if (alter_line(msg, &c1s, &janus) <= 0) { ++ LOG(L_ERR, "alter_line() failed\n"); ++ return 0; ++ } + } +- } else { +- newip.s = (argc < 2) ? str2 : argv[1]; +- newip.len = strlen(newip.s); +- } +- newport.s = int2str(port, &newport.len); /* beware static buffer */ +- +- if (alter_mediaip(msg, &body, &oldip, pf, &newip, pf1, 0) == -1) +- return -1; +- if (oldip1.len > 0 && +- alter_mediaip(msg, &body1, &oldip1, pf, &newip, pf1, 0) == -1) +- return -1; +- if (alter_mediaport(msg, &body, &oldport, &newport, 0) == -1) +- return -1; ++ } /* Iterate sessions */ + + if (proxied == 0) { + cp = pkg_malloc(ANORTPPROXY_LEN * sizeof(char)); +@@ -1554,75 +2152,41 @@ + return force_rtp_proxy1_f(msg, arg, NULL); + } + +-static void +-timer(unsigned int ticks, void *param) ++static int ++rewrite_from_from_f(struct sip_msg* msg, char* str1, char* str2) + { +- int rval; +- void *buf, *cp; +- str c; +- struct sip_uri curi; +- union sockaddr_union to; +- struct hostent* he; +- struct socket_info* send_sock; ++ struct action act; ++ struct sip_uri uri; ++ str ruri; + +- buf = NULL; +- if (cblen > 0) { +- buf = pkg_malloc(cblen); +- if (buf == NULL) { +- LOG(L_ERR, "ERROR: nathelper::timer: out of memory\n"); +- return; +- } ++ /* parsing from header */ ++ if (parse_from_header(msg) == -1) { ++ LOG(L_ERR, "rewrite_from_from(): cannot get FROM header\n"); ++ return -1; + } +- rval = ul.get_all_ucontacts(buf, cblen, (ping_nated_only ? FL_NAT : 0)); +- if (rval > 0) { +- if (buf != NULL) +- pkg_free(buf); +- cblen = rval * 2; +- buf = pkg_malloc(cblen); +- if (buf == NULL) { +- LOG(L_ERR, "ERROR: nathelper::timer: out of memory\n"); +- return; +- } +- rval = ul.get_all_ucontacts(buf, cblen, (ping_nated_only ? FL_NAT : 0)); +- if (rval != 0) { +- pkg_free(buf); +- return; +- } ++ ruri.len = get_from(msg)->uri.len; ++ ruri.s = pkg_malloc(ruri.len + 1); ++ memcpy(ruri.s, get_from(msg)->uri.s, ruri.len + 1); ++ if (parse_uri(ruri.s, ruri.len, &uri) < 0) { ++ LOG(L_ERR, "rewrite_from_from(): can't parse FROM URI\n"); ++ pkg_free(ruri.s); ++ return -1; ++ } ++ if (uri.user.len <= 0) { ++ uri.user.s = "Unknown"; ++ uri.user.len = 7; ++ } else { ++ uri.user.s[uri.user.len] = '\0'; + } + +- if (buf == NULL) +- return; ++ bzero(&act, sizeof(act)); ++ act.type = SET_USER_T; ++ act.p1_type = STRING_ST; ++ act.p1.string = uri.user.s; ++ do_action(&act, msg); + +- cp = buf; +- while (1) { +- memcpy(&(c.len), cp, sizeof(c.len)); +- if (c.len == 0) +- break; +- c.s = (char*)cp + sizeof(c.len); +- cp = (char*)cp + sizeof(c.len) + c.len; +- if (parse_uri(c.s, c.len, &curi) < 0) { +- LOG(L_ERR, "ERROR: nathelper::timer: can't parse contact uri\n"); +- continue; +- } +- if (curi.proto != PROTO_UDP && curi.proto != PROTO_NONE) +- continue; +- if (curi.port_no == 0) +- curi.port_no = SIP_PORT; +- he = sip_resolvehost(&curi.host, &curi.port_no, PROTO_UDP); +- if (he == NULL){ +- LOG(L_ERR, "ERROR: nathelper::timer: can't resolve_hos\n"); +- continue; +- } +- hostent2su(&to, he, 0, curi.port_no); +- send_sock=force_socket ? force_socket : +- get_send_socket(0, &to, PROTO_UDP); +- if (send_sock == NULL) { +- LOG(L_ERR, "ERROR: nathelper::timer: can't get sending socket\n"); +- continue; +- } +- udp_send(send_sock, (char *)sbuf, sizeof(sbuf), &to); +- } +- pkg_free(buf); ++ pkg_free(ruri.s); ++ return 1; + } + + diff --git a/net/ser/files/patch-modules::nathelper::nathelper.h b/net/ser/files/patch-modules::nathelper::nathelper.h new file mode 100644 index 000000000000..7edb4b1641d3 --- /dev/null +++ b/net/ser/files/patch-modules::nathelper::nathelper.h @@ -0,0 +1,77 @@ +--- modules/nathelper/nathelper.h ++++ modules/nathelper/nathelper.h +@@ -0,0 +1,74 @@ ++/* ++ * $Id: patch-modules::nathelper::nathelper.h,v 1.2 2005/04/05 13:10:08 netch Exp $ ++ * ++ * ++ * Copyright (C) 2005 Porta Software Ltd. ++ * ++ * This file is part of ser, a free SIP server. ++ * ++ * ser is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * For a license to use the ser software under conditions ++ * other than those described here, or to purchase support for this ++ * software, please contact iptel.org by e-mail at the following addresses: ++ * info@iptel.org ++ * ++ * ser is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef nathelper_H_ ++#define nathelper_H_ ++ ++/* Handy macros */ ++#define STR2IOVEC(sx, ix) do {(ix).iov_base = (sx).s; (ix).iov_len = (sx).len;} while(0) ++#define SZ2IOVEC(sx, ix) do {char *_t_p = (ix).iov_base = (sx); (ix).iov_len = strlen(_t_p);} while(0) ++ ++struct rtpp_node; ++ ++/* Parameters from nathelper.c */ ++extern struct socket_info* force_socket; ++ ++/* Functions from nathelper.c */ ++int isnulladdr(str *, int); ++int get_to_tag(struct sip_msg* _m, str* _tag); ++int get_from_tag(struct sip_msg* _m, str* _tag); ++int get_callid(struct sip_msg* _m, str* _cid); ++int extract_mediaip(str *, str *, int *); ++int extract_mediaport(str *, str *); ++int alter_mediaip(struct sip_msg *, str *, str *, int, str *, int, int); ++int alter_mediaport(struct sip_msg *, str *, str *, str *, int); ++struct rtpp_node * select_rtpp_node(str, int); ++char *send_rtpp_command(struct rtpp_node*, struct iovec *, int); ++char* find_sdp_line(char*, char*, char); ++char* find_next_sdp_line(char*, char*, char, char*); ++ ++/* Functions from moh.c */ ++int is_hold_f(struct sip_msg *msg, char *str1, char *str2); ++int start_moh_f(struct sip_msg *msg, char *str1, char *str2); ++int stop_moh_f(struct sip_msg *msg, char *str1, char *str2); ++ ++/* Functions from natping.c */ ++int natpinger_init(void); ++ ++/* Variables from moh.c referenced from nathelper.c */ ++extern char *pname_audio; ++extern char *pname_video; ++extern char *codecs_audio; ++extern char *codecs_video; ++ ++/* Variables from natping.c referenced from nathelper.c */ ++extern int natping_interval; ++extern int ping_nated_only; ++extern char *natping_method; ++ ++#endif diff --git a/net/ser/files/patch-modules::nathelper::natping.c b/net/ser/files/patch-modules::nathelper::natping.c new file mode 100644 index 000000000000..34826f9ae337 --- /dev/null +++ b/net/ser/files/patch-modules::nathelper::natping.c @@ -0,0 +1,196 @@ + +$FreeBSD$ + +--- modules/nathelper/natping.c.orig ++++ modules/nathelper/natping.c +@@ -0,0 +1,190 @@ ++/* $Id: patch-modules::nathelper::natping.c,v 1.4 2005/04/27 13:35:34 sobomax Exp $ ++ * ++ * Copyright (C) 2005 Porta Software Ltd ++ * ++ * This file is part of ser, a free SIP server. ++ * ++ * ser is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * For a license to use the ser software under conditions ++ * other than those described here, or to purchase support for this ++ * software, please contact iptel.org by e-mail at the following addresses: ++ * info@iptel.org ++ * ++ * ser is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include "../usrloc/usrloc.h" ++#include "../tm/tm_load.h" ++#include "../../dprint.h" ++#include "../../parser/parse_hostport.h" ++#include "../../resolve.h" ++#include "nathelper.h" ++ ++int natping_interval = 0; ++/* ++ * If this parameter is set then the natpinger will ping only contacts ++ * that have the NAT flag set in user location database ++ */ ++int ping_nated_only = 0; ++ ++/* ++ * Ping method. Any word except NULL is treated as method name. ++ */ ++char *natping_method = NULL; ++ ++static usrloc_api_t ul; ++/* TM bind */ ++static struct tm_binds tmb; ++static int cblen = 0; ++static const char sbuf[4] = {0, 0, 0, 0}; ++ ++static void natping(unsigned int ticks, void *param); ++ ++int ++natpinger_init(void) ++{ ++ bind_usrloc_t bind_usrloc; ++ load_tm_f load_tm; ++ char *p; ++ ++ if (natping_interval > 0) { ++ bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); ++ if (!bind_usrloc) { ++ LOG(L_ERR, "ERROR: nathelper: natpinger_init: Can't find usrloc module\n"); ++ return -1; ++ } ++ ++ if (bind_usrloc(&ul) < 0) { ++ return -1; ++ } ++ if (natping_method != NULL) { ++ for (p = natping_method; *p != '\0'; ++p) ++ *p = toupper(*p); ++ if (strcmp(natping_method, "NULL") == 0) ++ natping_method = NULL; ++ } ++ if (natping_method != NULL) { ++ /* import the TM auto-loading function */ ++ if (!(load_tm = (load_tm_f)find_export("load_tm", NO_SCRIPT, 0))) { ++ LOG(L_ERR, "ERROR: nathelper: natpinger_init: can't import load_tm\n"); ++ return -1; ++ } ++ /* let the auto-loading function load all TM stuff */ ++ if (load_tm(&tmb) == -1) ++ return -1; ++ } ++ ++ register_timer(natping, NULL, natping_interval); ++ } ++ ++ return 0; ++} ++ ++static void ++natping(unsigned int ticks, void *param) ++{ ++ int rval; ++ void *buf, *cp; ++ str c; ++ struct sip_uri curi; ++ union sockaddr_union to; ++ struct hostent* he; ++ struct socket_info* send_sock; ++ char t; ++ str p_method, p_from; ++ ++ buf = NULL; ++ if (cblen > 0) { ++ buf = pkg_malloc(cblen); ++ if (buf == NULL) { ++ LOG(L_ERR, "ERROR: nathelper::natping: out of memory\n"); ++ return; ++ } ++ } ++ rval = ul.get_all_ucontacts(buf, cblen, (ping_nated_only ? FL_NAT : 0)); ++ if (rval > 0) { ++ if (buf != NULL) ++ pkg_free(buf); ++ cblen = rval * 2; ++ buf = pkg_malloc(cblen); ++ if (buf == NULL) { ++ LOG(L_ERR, "ERROR: nathelper::natping: out of memory\n"); ++ return; ++ } ++ rval = ul.get_all_ucontacts(buf, cblen, (ping_nated_only ? FL_NAT : 0)); ++ if (rval != 0) { ++ pkg_free(buf); ++ return; ++ } ++ } ++ ++ if (buf == NULL) ++ return; ++ ++ cp = buf; ++ while (1) { ++ memcpy(&(c.len), cp, sizeof(c.len)); ++ if (c.len == 0) ++ break; ++ c.s = (char*)cp + sizeof(c.len); ++ cp = (char*)cp + sizeof(c.len) + c.len; ++ if (parse_uri(c.s, c.len, &curi) < 0) { ++ LOG(L_ERR, "ERROR: nathelper::natping: can't parse contact uri\n"); ++ continue; ++ } ++ if (curi.proto != PROTO_UDP && curi.proto != PROTO_NONE) ++ continue; ++ ++ if (natping_method != NULL) { ++ p_method.s = natping_method; ++ p_method.len = strlen(p_method.s); ++ p_from.s = "sip:registrar"; /* XXX */ ++ p_from.len = strlen(p_from.s); ++ if (tmb.t_request(&p_method, &c, &c, &p_from, ++ NULL, NULL, NULL, NULL) == -1) ++ { ++ LOG(L_ERR, "nathelper::natping(): request() failed\n"); ++ } ++ } else { ++ if (curi.maddr_val.len != 0) { ++ t = curi.maddr_val.s[curi.maddr_val.len]; ++ curi.maddr_val.s[curi.maddr_val.len] = '\0'; ++ parse_hostport(curi.maddr_val.s, &curi.host, &curi.port_no); ++ curi.maddr_val.s[curi.maddr_val.len] = t; ++ if (curi.host.len <= 0) { ++ LOG(L_ERR, "ERROR: nathelper::natping: invalid maddr in contact uri\n"); ++ continue; ++ } ++ } ++ ++ if (curi.port_no == 0) ++ curi.port_no = SIP_PORT; ++ he = sip_resolvehost(&curi.host, &curi.port_no, PROTO_UDP); ++ if (he == NULL){ ++ LOG(L_ERR, "ERROR: nathelper::natping: can't resolve host\n"); ++ continue; ++ } ++ hostent2su(&to, he, 0, curi.port_no); ++ send_sock=force_socket ? force_socket : ++ get_send_socket(0, &to, PROTO_UDP); ++ if (send_sock == NULL) { ++ LOG(L_ERR, "ERROR: nathelper::natping: can't get sending socket\n"); ++ continue; ++ } ++ udp_send(send_sock, (char *)sbuf, sizeof(sbuf), &to); ++ } ++ } ++ pkg_free(buf); ++} diff --git a/net/ser/files/patch-modules::postgres::Makefile b/net/ser/files/patch-modules::postgres::Makefile deleted file mode 100644 index 56e292602036..000000000000 --- a/net/ser/files/patch-modules::postgres::Makefile +++ /dev/null @@ -1,16 +0,0 @@ - -$FreeBSD$ - ---- modules/postgres/Makefile.orig Wed Jul 30 19:29:00 2003 -+++ modules/postgres/Makefile Mon Apr 12 19:12:53 2004 -@@ -7,8 +7,8 @@ - NAME=postgres.so - - # libpq-fe.h locations --DEFS +=-I/usr/local/pgsql/include -I/usr/include/postgresql --LIBS=-L$(LOCALBASE)/pgsql/lib -L$(LOCALBASE)/lib/pgsql -L/usr/pkg/lib \ -+DEFS +=-I$(LOCALBASE)/include -I$(LOCALBASE)/pgsql/include -I/usr/include/postgresql -+LIBS=-L$(LOCALBASE)/lib -L$(LOCALBASE)/pgsql/lib -L$(LOCALBASE)/lib/pgsql -L/usr/pkg/lib \ - -L/usr/pkg/lib/pgsql -lpq - - include ../../Makefile.modules diff --git a/net/ser/files/patch-modules::postgres::db_mod.c b/net/ser/files/patch-modules::postgres::db_mod.c deleted file mode 100644 index 3602a861aade..000000000000 --- a/net/ser/files/patch-modules::postgres::db_mod.c +++ /dev/null @@ -1,13 +0,0 @@ - -$FreeBSD$ - ---- modules/postgres/db_mod.c.orig Wed Oct 8 16:07:22 2003 -+++ modules/postgres/db_mod.c Tue Apr 13 22:27:28 2004 -@@ -35,6 +35,7 @@ - - #include <stdio.h> - #include "../../sr_module.h" -+#include "../../db/db_con.h" - #include "dbase.h" - - MODULE_VERSION diff --git a/net/ser/files/patch-modules::postgres::db_res.c b/net/ser/files/patch-modules::postgres::db_res.c deleted file mode 100644 index 61c77a98f3bf..000000000000 --- a/net/ser/files/patch-modules::postgres::db_res.c +++ /dev/null @@ -1,13 +0,0 @@ - -$FreeBSD$ - ---- modules/postgres/db_res.c.orig Tue Apr 8 04:25:35 2003 -+++ modules/postgres/db_res.c Tue Apr 13 22:27:28 2004 -@@ -38,6 +38,7 @@ - - #include <stdlib.h> - #include "../../db/db_res.h" -+#include "../../db/db_con.h" - #include "../../dprint.h" - #include "../../mem/mem.h" - #include "defs.h" diff --git a/net/ser/files/patch-modules::postgres::db_val.c b/net/ser/files/patch-modules::postgres::db_val.c deleted file mode 100644 index 5d59e16f6d27..000000000000 --- a/net/ser/files/patch-modules::postgres::db_val.c +++ /dev/null @@ -1,13 +0,0 @@ - -$FreeBSD$ - ---- modules/postgres/db_val.c.orig Mon Apr 14 21:52:47 2003 -+++ modules/postgres/db_val.c Tue Apr 13 22:27:28 2004 -@@ -188,6 +188,7 @@ - - switch(_t) { - case DB_INT: -+ case DB_BITMAP: - sprintf(dbuf, "got int %s", _s); - DLOG("str2valp", dbuf); - if (str2int(_s, &VAL_INT(_v)) < 0) { diff --git a/net/ser/files/patch-modules::postgres::dbase.h b/net/ser/files/patch-modules::postgres::dbase.h deleted file mode 100644 index 268ec7ccc2b8..000000000000 --- a/net/ser/files/patch-modules::postgres::dbase.h +++ /dev/null @@ -1,22 +0,0 @@ - -$FreeBSD$ - ---- modules/postgres/dbase.h.orig Tue Apr 8 04:25:35 2003 -+++ modules/postgres/dbase.h Tue Apr 13 22:27:28 2004 -@@ -106,4 +106,16 @@ - db_key_t* _uk, db_val_t* _uv, int _n, int _un); - - -+/* -+ * Store name of table that will be used by -+ * subsequent database functions -+ */ -+int use_table(db_con_t* _h, const char* _t); -+ -+int val2str(db_val_t* _v, char* _s, int* _len); -+ -+int free_result(db_res_t* _r); -+ -+int convert_result(db_con_t* _h, db_res_t* _r); -+ - #endif /* DBASE_H */ diff --git a/net/ser/files/patch-modules::registrar::doc::registrar_user.sgml b/net/ser/files/patch-modules::registrar::doc::registrar_user.sgml new file mode 100644 index 000000000000..24ba9046222b --- /dev/null +++ b/net/ser/files/patch-modules::registrar::doc::registrar_user.sgml @@ -0,0 +1,51 @@ + +$FreeBSD$ + +--- modules/registrar/doc/registrar_user.sgml ++++ modules/registrar/doc/registrar_user.sgml +@@ -29,7 +29,12 @@ + </listitem> + <listitem> + <para> +- <emphasis>sl - Stateless Replies</emphasis>. ++ <emphasis>sl - Stateless Replies (if <varname>use_tm</varname> is 0)</emphasis>. ++ </para> ++ </listitem> ++ <listitem> ++ <para> ++ <emphasis>tm - Transaction module (if <varname>use_tm</varname> is 1)</emphasis>. + </para> + </listitem> + </itemizedlist> +@@ -321,6 +326,31 @@ + modparam("registrar", "retry_after", 30) + ... + </programlisting> ++ </example> ++ </section> ++ ++ <section> ++ <title><varname>use_tm</varname> (integer)</title> ++ <para> ++ If set to 1 then the registrar will use <function>t_reply()</function> function from ++ the tm module instead of <function>sl_send_reply()</function> function from the sl ++ module for sending replies. This allows registration transactions to be processed ++ statefully if necessary. When set to 1 script writer need to ensure that transaction ++ exists when <function>save()</function> is called, usually by calling ++ <function>t_newtran()</function>. ++ </para> ++ <para> ++ <emphasis> ++ Default value is 0. ++ </emphasis> ++ </para> ++ <example> ++ <title>Set <varname>use_tm</varname> parameter</title> ++ <programlisting format="linespecific"> ++... ++modparam("registrar", "use_tm", 1) ++... ++</programlisting> + </example> + </section> + diff --git a/net/ser/files/patch-modules::registrar::reg_mod.c b/net/ser/files/patch-modules::registrar::reg_mod.c new file mode 100644 index 000000000000..14d4f5629dc8 --- /dev/null +++ b/net/ser/files/patch-modules::registrar::reg_mod.c @@ -0,0 +1,66 @@ + +$FreeBSD$ + +--- modules/registrar/reg_mod.c.orig ++++ modules/registrar/reg_mod.c +@@ -70,6 +70,7 @@ + int use_domain = 0; + char* realm_pref = ""; /* Realm prefix to be removed */ + str realm_prefix; ++int use_tm = 0; + + #define RCV_NAME "received" + #define RCV_NAME_LEN (sizeof(RCV_NAME) - 1) +@@ -84,6 +85,9 @@ + int (*sl_reply)(struct sip_msg* _m, char* _s1, char* _s2); + + ++struct tm_binds tmb; ++ ++ + /* + * Exported functions + */ +@@ -115,6 +119,7 @@ + {"use_domain", INT_PARAM, &use_domain }, + {"max_contacts", INT_PARAM, &max_contacts }, + {"retry_after", INT_PARAM, &retry_after }, ++ {"use_tm", INT_PARAM, &use_tm }, + {0, 0, 0} + }; + +@@ -140,17 +145,26 @@ + static int mod_init(void) + { + bind_usrloc_t bind_usrloc; ++ load_tm_f load_tm; + + DBG("registrar - initializing\n"); + +- /* +- * We will need sl_send_reply from stateless +- * module for sending replies +- */ +- sl_reply = find_export("sl_send_reply", 2, 0); +- if (!sl_reply) { +- LOG(L_ERR, "registrar: This module requires sl module\n"); +- return -1; ++ if (use_tm != 0) { ++ load_tm = (load_tm_f)find_export("load_tm", NO_SCRIPT, 0); ++ if (load_tm == NULL || load_tm(&tmb) == -1) { ++ LOG(L_ERR, "Can't import tm\n"); ++ return -1; ++ } ++ } else { ++ /* ++ * We will need sl_send_reply from stateless ++ * module for sending replies ++ */ ++ sl_reply = find_export("sl_send_reply", 2, 0); ++ if (!sl_reply) { ++ LOG(L_ERR, "registrar: This module requires sl module\n"); ++ return -1; ++ } + } + + realm_prefix.s = realm_pref; diff --git a/net/ser/files/patch-modules::registrar::reg_mod.h b/net/ser/files/patch-modules::registrar::reg_mod.h new file mode 100644 index 000000000000..6e2dfdd85859 --- /dev/null +++ b/net/ser/files/patch-modules::registrar::reg_mod.h @@ -0,0 +1,29 @@ + +$FreeBSD$ + +--- modules/registrar/reg_mod.h.orig ++++ modules/registrar/reg_mod.h +@@ -35,6 +35,7 @@ + #include "../../qvalue.h" + #include "../../usr_avp.h" + #include "../usrloc/usrloc.h" ++#include "../tm/tm_load.h" + + extern int default_expires; + extern qvalue_t default_q; +@@ -48,6 +49,7 @@ + extern int use_domain; + extern str realm_prefix; + extern float def_q; ++extern int use_tm; + + extern str rcv_param; + extern int rcv_avp_no; +@@ -57,5 +59,7 @@ + usrloc_api_t ul; /* Structure containing pointers to usrloc functions */ + + extern int (*sl_reply)(struct sip_msg* _m, char* _s1, char* _s2); ++ ++extern struct tm_binds tmb; + + #endif /* REG_MOD_H */ diff --git a/net/ser/files/patch-modules::registrar::reply.c b/net/ser/files/patch-modules::registrar::reply.c new file mode 100644 index 000000000000..f48757ecf6ce --- /dev/null +++ b/net/ser/files/patch-modules::registrar::reply.c @@ -0,0 +1,23 @@ + +$FreeBSD$ + +--- modules/registrar/reply.c.orig ++++ modules/registrar/reply.c +@@ -314,6 +314,7 @@ + long code; + char* msg = MSG_200; /* makes gcc shut up */ + char* buf; ++ int result; + + if (contact.data_len > 0) { + add_lump_rpl( _m, contact.buf, contact.data_len, LUMP_RPL_HDR|LUMP_RPL_NODUP|LUMP_RPL_NOFREE); +@@ -347,7 +348,8 @@ + } + } + +- if (sl_reply(_m, (char*)code, msg) == -1) { ++ result = (use_tm != 0) ? tmb.t_reply(_m, code, msg) : sl_reply(_m, (char*)code, msg); ++ if (result == -1) { + LOG(L_ERR, "send_reply(): Error while sending %ld %s\n", code, msg); + return -1; + } else return 0; diff --git a/net/ser/files/patch-modules::tm::t_fwd.c b/net/ser/files/patch-modules::tm::t_fwd.c deleted file mode 100644 index 11f12d2d7cf8..000000000000 --- a/net/ser/files/patch-modules::tm::t_fwd.c +++ /dev/null @@ -1,29 +0,0 @@ - -$FreeBSD$ - ---- modules/tm/t_fwd.c.orig -+++ modules/tm/t_fwd.c -@@ -359,6 +359,15 @@ - DBG("DEBUG: e2e_cancel: e2e cancel -- no more pending branches\n"); - t_reply( t_cancel, cancel_msg, 200, CANCEL_DONE ); - } -+ -+#ifdef LOCAL_487 -+ -+ /* local 487s have been deprecated -- it better handles -+ * race conditions (UAS sending 200); hopefuly there are -+ * no longer UACs who go crazy waiting for the 487 whose -+ * forwarding is being blocked by other unreponsive branch -+ */ -+ - /* we could await downstream UAS's 487 replies; however, - if some of the branches does not do that, we could wait - long time and annoy upstream UAC which wants to see -@@ -375,6 +384,7 @@ - "can't reply twice" - */ - t_reply(t_invite, t_invite->uas.request, 487, CANCELLED ); -+#endif - } - - diff --git a/net/ser/files/patch-modules::tm::t_msgbuilder.c b/net/ser/files/patch-modules::tm::t_msgbuilder.c new file mode 100644 index 000000000000..159c904895dd --- /dev/null +++ b/net/ser/files/patch-modules::tm::t_msgbuilder.c @@ -0,0 +1,55 @@ + +$FreeBSD$ + +--- modules/tm/t_msgbuilder.c 2004/06/29 19:22:35 1.1 ++++ modules/tm/t_msgbuilder.c 2004/06/29 19:56:19 +@@ -124,7 +124,7 @@ + + /* User Agent */ + if (server_signature) { +- *len += USER_AGENT_LEN + CRLF_LEN; ++ *len += USER_AGENT_LEN + CRLF_LEN + (server_name ? strlen(server_name) : UA_NAME_LEN); + } + /* Content Length, EoM */ + *len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN; +@@ -164,7 +164,13 @@ + + /* User Agent header */ + if (server_signature) { +- append_mem_block(p,USER_AGENT CRLF, USER_AGENT_LEN+CRLF_LEN ); ++ append_mem_block(p, USER_AGENT, USER_AGENT_LEN); ++ if (server_name) { ++ append_mem_block(p, server_name, strlen(server_name)); ++ } else { ++ append_mem_block(p, UA_NAME, UA_NAME_LEN); ++ } ++ append_mem_block(p, CRLF, CRLF_LEN); + } + /* Content Length, EoM */ + append_mem_block(p, CONTENT_LENGTH "0" CRLF CRLF , +@@ -397,7 +403,7 @@ + *len += CSEQ_LEN + cseq.len + 1 + method->len + CRLF_LEN; /* CSeq */ + *len += calculate_routeset_length(dialog); /* Route set */ + *len += (body ? (CONTENT_LENGTH_LEN + content_length.len + CRLF_LEN) : 0); /* Content-Length */ +- *len += (server_signature ? (USER_AGENT_LEN + CRLF_LEN) : 0); /* Signature */ ++ *len += (server_signature ? (USER_AGENT_LEN + CRLF_LEN + (server_name ? strlen(server_name) : UA_NAME_LEN)) : 0);/* Signature */ + *len += (headers ? headers->len : 0); /* Additional headers */ + *len += (body ? body->len : 0); /* Message body */ + *len += CRLF_LEN; /* End of Header */ +@@ -426,7 +432,15 @@ + } + + /* Server signature */ +- if (server_signature) memapp(w, USER_AGENT CRLF, USER_AGENT_LEN + CRLF_LEN); ++ if (server_signature) { ++ memapp(w, USER_AGENT, USER_AGENT_LEN); ++ if (server_name) { ++ memapp(w, server_name, strlen(server_name)); ++ } else { ++ memapp(w, UA_NAME, UA_NAME_LEN); ++ } ++ memapp(w, CRLF, CRLF_LEN); ++ } + if (headers) memapp(w, headers->s, headers->len); + memapp(w, CRLF, CRLF_LEN); + if (body) memapp(w, body->s, body->len); diff --git a/net/ser/files/patch-modules::usrloc::udomain.c b/net/ser/files/patch-modules::usrloc::udomain.c deleted file mode 100644 index 3e627f8ef7eb..000000000000 --- a/net/ser/files/patch-modules::usrloc::udomain.c +++ /dev/null @@ -1,14 +0,0 @@ - -$FreeBSD$ - ---- modules/usrloc/udomain.c -+++ modules/usrloc/udomain.c -@@ -288,7 +288,7 @@ - } - flags = VAL_BITMAP(ROW_VALUES(row) + 8); - ua.s = (char*)VAL_STRING(ROW_VALUES(row) + 9); -- ua.len = strlen(ua.s); -+ ua.len = (ua.s != NULL) ? strlen(ua.s) : 0; - - if (use_domain) { - domain = (char*)VAL_STRING(ROW_VALUES(row) + 10); diff --git a/net/ser/files/patch-modules::xlog::xl_lib.c b/net/ser/files/patch-modules::xlog::xl_lib.c deleted file mode 100644 index 75750eee91d9..000000000000 --- a/net/ser/files/patch-modules::xlog::xl_lib.c +++ /dev/null @@ -1,29 +0,0 @@ - -$FreeBSD$ - ---- modules/xlog/xl_lib.c 2003/11/17 11:31:59 1.1 -+++ modules/xlog/xl_lib.c 2003/11/17 11:38:37 -@@ -38,6 +38,7 @@ - #include "../../ut.h" - #include "../../trim.h" - -+#include "../../parser/contact/parse_contact.h" - #include "../../parser/parse_from.h" - #include "../../parser/parse_uri.h" - -@@ -195,7 +196,14 @@ - DBG("XLOG: xl_get_contact: no contact header\n"); - return xl_get_null(msg, res); - } -- -+ -+ if (msg->contact && msg->contact->parsed && -+ ((contact_body_t*)msg->contact->parsed)->contacts && -+ ((contact_body_t*)msg->contact->parsed)->contacts->uri.len > 0) { -+ *res = ((contact_body_t*)msg->contact->parsed)->contacts->uri; -+ return 0; -+ } -+ - if(!msg->contact || !msg->contact->body.s || msg->contact->body.len<=0) - { - DBG("XLOG: xl_get_contact: no contact header!\n"); diff --git a/net/ser/files/patch-msg_translator.c b/net/ser/files/patch-msg_translator.c new file mode 100644 index 000000000000..a88cb932c4ba --- /dev/null +++ b/net/ser/files/patch-msg_translator.c @@ -0,0 +1,28 @@ + +$FreeBSD$ + +--- msg_translator.c 2004/06/29 19:19:33 1.1 ++++ msg_translator.c 2004/06/29 19:55:57 +@@ -1657,7 +1657,7 @@ + } + /* server header */ + if (server_signature) +- len += SERVER_HDR_LEN + CRLF_LEN; ++ len += SERVER_HDR_LEN + CRLF_LEN + (server_name ? strlen(server_name) : UA_NAME_LEN); + /* warning hdr */ + if (sip_warning) { + warning_buf = warning_builder(msg,&warning_len); +@@ -1788,6 +1788,13 @@ + if (server_signature) { + memcpy( p, SERVER_HDR , SERVER_HDR_LEN ); + p+=SERVER_HDR_LEN; ++ if (server_name) { ++ memcpy( p, server_name, strlen(server_name) ); ++ p+=strlen(server_name); ++ } else { ++ memcpy( p, UA_NAME, UA_NAME_LEN ); ++ p+=UA_NAME_LEN; ++ } + memcpy( p, CRLF, CRLF_LEN ); + p+=CRLF_LEN; + } diff --git a/net/ser/files/patch-parser::parse_hostport.c b/net/ser/files/patch-parser::parse_hostport.c new file mode 100644 index 000000000000..b00d03bd6219 --- /dev/null +++ b/net/ser/files/patch-parser::parse_hostport.c @@ -0,0 +1,27 @@ + +$FreeBSD$ + +--- parser/parse_hostport.c.orig ++++ parser/parse_hostport.c +@@ -25,8 +25,6 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +-#ifdef _OBSOLETED +- + #include "parse_hostport.h" + #include <string.h> /* strlen */ + #include "../dprint.h" +@@ -43,7 +41,6 @@ + if (*tmp==0) { + *port=0; + } else { +- *tmp=0; + *port=str2s((unsigned char*)(tmp+1), strlen(tmp+1), &err); + if (err ){ + LOG(L_INFO, +@@ -56,4 +53,3 @@ + return host->s; + } + +-#endif diff --git a/net/ser/files/patch-server b/net/ser/files/patch-server new file mode 100644 index 000000000000..38c0da21007a --- /dev/null +++ b/net/ser/files/patch-server @@ -0,0 +1,187 @@ +Index: parser/case_serv.h +=================================================================== +RCS file: parser/case_serv.h +diff -N parser/case_serv.h +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ parser/case_serv.h 20 Dec 2004 18:52:54 -0000 1.1 +@@ -0,0 +1,45 @@ ++/* ++ * $Id: patch-server,v 1.2 2005/04/05 13:10:08 netch Exp $ ++ * ++ * Subject Header Field Name Parsing Macros ++ * ++ * Copyright (C) 2001-2003 Fhg Fokus ++ * ++ * This file is part of ser, a free SIP server. ++ * ++ * ser is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version ++ * ++ * For a license to use the ser software under conditions ++ * other than those described here, or to purchase support for this ++ * software, please contact iptel.org by e-mail at the following addresses: ++ * info@iptel.org ++ * ++ * ser is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ ++#ifndef CASE_SERV_H ++#define CASE_SERV_H ++ ++ ++#define serv_CASE \ ++ p += 4; \ ++ if (LOWER_BYTE(*p) == 'e' && LOWER_BYTE(p[1]) == 'r') { \ ++ hdr->type = HDR_SERVER; \ ++ p+= 2; \ ++ goto dc_end; \ ++ } \ ++ goto other; ++ ++ ++#endif /* CASE_SERV_H */ +Index: parser/hf.c +=================================================================== +RCS file: /cvsroot/ser/sip_router/parser/hf.c,v +retrieving revision 1.21 +retrieving revision 1.22 +diff -d -u -d -u -r1.21 -r1.22 +--- parser/hf.c 3 Dec 2004 17:11:36 -0000 1.21 ++++ parser/hf.c 20 Dec 2004 18:52:54 -0000 1.22 +@@ -130,10 +130,10 @@ + + case HDR_ACCEPTLANGUAGE: + break; +- ++ + case HDR_ORGANIZATION: + break; +- ++ + case HDR_PRIORITY: + break; + +@@ -156,6 +156,9 @@ + + case HDR_RPID: + free_to(hf->parsed); ++ break; ++ ++ case HDR_SERVER: + break; + + default: +Index: parser/hf.h +=================================================================== +RCS file: /cvsroot/ser/sip_router/parser/hf.h,v +retrieving revision 1.16 +retrieving revision 1.17 +diff -d -u -d -u -r1.16 -r1.17 +--- parser/hf.h 3 Dec 2004 17:11:36 -0000 1.16 ++++ parser/hf.h 20 Dec 2004 18:52:54 -0000 1.17 +@@ -73,7 +73,8 @@ + #define HDR_CONTENTDISPOSITION (1 << 27) /* Content-Disposition hdr field */ + #define HDR_DIVERSION (1 << 28) /* Diversion header field */ + #define HDR_RPID (1 << 29) /* Remote-Party-ID header field */ +-#define HDR_OTHER (1 << 30) /* Some other header field */ ++#define HDR_SERVER (1 << 30) /* Server header field */ ++#define HDR_OTHER (1 << 31) /* Some other header field */ + + + /* returns true if the header links allocated memory on parse field */ +Index: parser/keys.h +=================================================================== +RCS file: /cvsroot/ser/sip_router/parser/keys.h,v +retrieving revision 1.11 +retrieving revision 1.12 +diff -d -u -d -u -r1.11 -r1.12 +--- parser/keys.h 3 Dec 2004 17:11:36 -0000 1.11 ++++ parser/keys.h 20 Dec 2004 18:52:54 -0000 1.12 +@@ -115,6 +115,8 @@ + #define _pt_d_ 0x64617470 /* "pt-d" */ + #define _ispo_ 0x6f707369 /* "ispo" */ + #define _siti_ 0x69746973 /* "siti" */ ++ ++#define _serv_ 0x76726573 /* "serv" */ + + #define _dive_ 0x65766964 /* "dive" */ + #define _rsio_ 0x6f697372 /* "rsio" */ +Index: parser/msg_parser.c +=================================================================== +RCS file: /cvsroot/ser/sip_router/parser/msg_parser.c,v +retrieving revision 1.44 +retrieving revision 1.45 +diff -d -u -d -u -r1.44 -r1.45 +--- parser/msg_parser.c 3 Dec 2004 17:11:36 -0000 1.44 ++++ parser/msg_parser.c 20 Dec 2004 18:52:54 -0000 1.45 +@@ -204,6 +204,7 @@ + case HDR_ACCEPTDISPOSITION: + case HDR_DIVERSION: + case HDR_RPID: ++ case HDR_SERVER: + case HDR_OTHER: + /* just skip over it */ + hdr->body.s=tmp; +@@ -406,6 +407,10 @@ + case HDR_RPID: + if (msg->rpid==0) msg->rpid = hf; + msg->parsed_flag|=HDR_RPID; ++ break; ++ case HDR_SERVER: ++ if (msg->server==0) msg->server = hf; ++ msg->parsed_flag|=HDR_SERVER; + break; + case HDR_VIA: + msg->parsed_flag|=HDR_VIA; +Index: parser/msg_parser.h +=================================================================== +RCS file: /cvsroot/ser/sip_router/parser/msg_parser.h,v +retrieving revision 1.49 +retrieving revision 1.50 +diff -d -u -d -u -r1.49 -r1.50 +--- parser/msg_parser.h 3 Dec 2004 17:11:36 -0000 1.49 ++++ parser/msg_parser.h 20 Dec 2004 18:52:54 -0000 1.50 +@@ -193,6 +193,7 @@ + struct hdr_field* accept_disposition; + struct hdr_field* diversion; + struct hdr_field* rpid; ++ struct hdr_field* server; + + char* eoh; /* pointer to the end of header (if found) or null */ + char* unparsed; /* here we stopped parsing*/ +Index: parser/parse_hname2.c +=================================================================== +RCS file: /cvsroot/ser/sip_router/parser/parse_hname2.c,v +retrieving revision 1.19 +retrieving revision 1.20 +diff -d -u -d -u -r1.19 -r1.20 +--- parser/parse_hname2.c 3 Dec 2004 17:11:36 -0000 1.19 ++++ parser/parse_hname2.c 20 Dec 2004 18:52:54 -0000 1.20 +@@ -84,6 +84,7 @@ + #include "case_supp.h" /* Supported */ + #include "case_dive.h" /* Diversion */ + #include "case_remo.h" /* Remote-Party-ID */ ++#include "case_serv.h" /* Server */ + + + #define READ(val) \ +@@ -114,7 +115,8 @@ + case _subj_: subj_CASE; \ + case _user_: user_CASE; \ + case _dive_: dive_CASE; \ +- case _remo_: remo_CASE; ++ case _remo_: remo_CASE; \ ++ case _serv_: serv_CASE; + + + #define PARSE_COMPACT(id) \ |