aboutsummaryrefslogtreecommitdiff
path: root/net/ser/files
diff options
context:
space:
mode:
authorMaxim Sobolev <sobomax@FreeBSD.org>2005-07-07 20:16:35 +0000
committerMaxim Sobolev <sobomax@FreeBSD.org>2005-07-07 20:16:35 +0000
commit0fa030f274a2e4f83f08592f507c3f4969d0f643 (patch)
tree84744a0b420d19c6adeba7ba0b6503a6b50205bc /net/ser/files
parenta5ac90db2355b64bd3f39066578a190149810c83 (diff)
downloadports-0fa030f274a2e4f83f08592f507c3f4969d0f643.tar.gz
ports-0fa030f274a2e4f83f08592f507c3f4969d0f643.zip
Notes
Diffstat (limited to 'net/ser/files')
-rw-r--r--net/ser/files/patch-Makefile26
-rw-r--r--net/ser/files/patch-Makefile.defs116
-rw-r--r--net/ser/files/patch-Makefile.rules14
-rw-r--r--net/ser/files/patch-cfg.lex21
-rw-r--r--net/ser/files/patch-cfg.y21
-rw-r--r--net/ser/files/patch-config.h23
-rw-r--r--net/ser/files/patch-fifo_server.c14
-rw-r--r--net/ser/files/patch-globals.h13
-rw-r--r--net/ser/files/patch-main.c16
-rw-r--r--net/ser/files/patch-modules::acc::etc::radiusclient.conf4
-rw-r--r--net/ser/files/patch-modules::auth::auth_mod.c60
-rw-r--r--net/ser/files/patch-modules::auth::auth_mod.h27
-rw-r--r--net/ser/files/patch-modules::auth::common.c12
-rw-r--r--net/ser/files/patch-modules::auth::doc::auth_user.sgml44
-rw-r--r--net/ser/files/patch-modules::auth_radius::authrad_mod.c6
-rw-r--r--net/ser/files/patch-modules::check_ua::Makefile19
-rw-r--r--net/ser/files/patch-modules::check_ua::check_ua.c374
-rw-r--r--net/ser/files/patch-modules::check_ua::tailq.h154
-rw-r--r--net/ser/files/patch-modules::ext::ext.c14
-rw-r--r--net/ser/files/patch-modules::group_radius::grouprad_mod.c6
-rw-r--r--net/ser/files/patch-modules::nathelper::moh.c434
-rw-r--r--net/ser/files/patch-modules::nathelper::nathelper.c1701
-rw-r--r--net/ser/files/patch-modules::nathelper::nathelper.h77
-rw-r--r--net/ser/files/patch-modules::nathelper::natping.c196
-rw-r--r--net/ser/files/patch-modules::postgres::Makefile16
-rw-r--r--net/ser/files/patch-modules::postgres::db_mod.c13
-rw-r--r--net/ser/files/patch-modules::postgres::db_res.c13
-rw-r--r--net/ser/files/patch-modules::postgres::db_val.c13
-rw-r--r--net/ser/files/patch-modules::postgres::dbase.h22
-rw-r--r--net/ser/files/patch-modules::registrar::doc::registrar_user.sgml51
-rw-r--r--net/ser/files/patch-modules::registrar::reg_mod.c66
-rw-r--r--net/ser/files/patch-modules::registrar::reg_mod.h29
-rw-r--r--net/ser/files/patch-modules::registrar::reply.c23
-rw-r--r--net/ser/files/patch-modules::tm::t_fwd.c29
-rw-r--r--net/ser/files/patch-modules::tm::t_msgbuilder.c55
-rw-r--r--net/ser/files/patch-modules::usrloc::udomain.c14
-rw-r--r--net/ser/files/patch-modules::xlog::xl_lib.c29
-rw-r--r--net/ser/files/patch-msg_translator.c28
-rw-r--r--net/ser/files/patch-parser::parse_hostport.c27
-rw-r--r--net/ser/files/patch-server187
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(&reglist);
++ 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(&reglist) < 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(&reglist)) != NULL) {
++ TAILQ_REMOVE(&reglist, 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, &reglist, 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(&reglist)) != NULL) {
++ TAILQ_REMOVE(&reglist, re, re_link);
++ reglist_entry_free(re);
++ }
++ while ((re = TAILQ_FIRST(&newhead)) != NULL) {
++ TAILQ_REMOVE(&newhead, re, re_link);
++ TAILQ_INSERT_TAIL(&reglist, 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 &notfound;
++}
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) \