modules_k/maxfwd/maxfwd.c
31ccf6a2
 /*
  * $Id$
  *
  * MAXFWD module
  *
  * Copyright (C) 2001-2003 FhG Fokus
  *
27642a08
  * This file is part of Kamailio, a free SIP server.
31ccf6a2
  *
27642a08
  * Kamailio is free software; you can redistribute it and/or modify
31ccf6a2
  * 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
  *
27642a08
  * Kamailio is distributed in the hope that it will be useful,
31ccf6a2
  * 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:
  * --------
  *  2003-03-11  updated to the new module interface (andrei)
  *  2003-03-16  flags export parameter added (janakj)
  *  2003-03-19  all mallocs/frees replaced w/ pkg_malloc/pkg_free (andrei)
  *  2004-08-15  max value of max-fwd header is configurable via max_limit
  *              module param (bogdan)
772dbe96
  *  2005-09-15  max_limit param cannot be disabled anymore (according to RFC)
  *              (bogdan)
9202af99
  *  2005-11-03  is_maxfwd_lt() function added; MF value saved in 
  *              msg->maxforwards->parsed (bogdan)
31ccf6a2
  */
 
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 #include "../../sr_module.h"
 #include "../../dprint.h"
 #include "../../error.h"
 #include "../../ut.h"
 #include "../../mem/mem.h"
 #include "mf_funcs.h"
 
 MODULE_VERSION
 
772dbe96
 #define MAXFWD_UPPER_LIMIT 256
 
 static int max_limit = MAXFWD_UPPER_LIMIT;
31ccf6a2
 
 static int fixup_maxfwd_header(void** param, int param_no);
 static int w_process_maxfwd_header(struct sip_msg* msg,char* str,char* str2);
9202af99
 static int is_maxfwd_lt(struct sip_msg *msg, char *slimit, char *foo);
31ccf6a2
 static int mod_init(void);
 
 static cmd_export_t cmds[]={
c4d2e802
 	{"mf_process_maxfwd_header", (cmd_function)w_process_maxfwd_header, 1,
80998a7f
 		fixup_maxfwd_header, 0, REQUEST_ROUTE},
c4d2e802
 	{"is_maxfwd_lt", (cmd_function)is_maxfwd_lt, 1,
80998a7f
 		fixup_maxfwd_header, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
 	{0,0,0,0,0,0}
31ccf6a2
 };
 
 static param_export_t params[]={
 	{"max_limit",    INT_PARAM,  &max_limit},
 	{0,0,0}
 };
 
 
 
 struct module_exports exports= {
 	"maxfwd",
51716422
 	DEFAULT_DLFLAGS, /* dlopen flags */
31ccf6a2
 	cmds,
 	params,
739aec8b
 	0,          /* exported statistics */
de26de44
 	0,          /* exported MI functions */
71c26efd
 	0,          /* exported pseudo-variables */
3eee3a4e
 	0,          /* extra processes */
31ccf6a2
 	mod_init,
3ed44241
 	0,
 	0,
 	0           /* per-child init function */
31ccf6a2
 };
 
 
 
 static int mod_init(void)
 {
772dbe96
 	if ( max_limit<1 || max_limit>MAXFWD_UPPER_LIMIT ) {
e4a6f52c
 		LM_ERR("invalid max limit (%d) [1,%d]\n",
772dbe96
 			max_limit,MAXFWD_UPPER_LIMIT);
9202af99
 		return E_CFG;
31ccf6a2
 	}
 	return 0;
 }
 
 
 
 static int fixup_maxfwd_header(void** param, int param_no)
 {
 	unsigned long code;
 	int err;
 
 	if (param_no==1){
 		code=str2s(*param, strlen(*param), &err);
 		if (err==0){
772dbe96
 			if (code<1 || code>MAXFWD_UPPER_LIMIT){
e4a6f52c
 				LM_ERR("invalid MAXFWD number <%ld> [1,%d]\n",
 					code,MAXFWD_UPPER_LIMIT);
31ccf6a2
 				return E_UNSPEC;
 			}
772dbe96
 			if (code>max_limit) {
e4a6f52c
 				LM_ERR("default value <%ld> bigger than max limit(%d)\n",
 					code, max_limit);
31ccf6a2
 				return E_UNSPEC;
 			}
 			pkg_free(*param);
 			*param=(void*)code;
 			return 0;
 		}else{
e4a6f52c
 			LM_ERR("bad  number <%s>\n",(char*)(*param));
31ccf6a2
 			return E_UNSPEC;
 		}
 	}
 	return 0;
 }
 
 
 
 static int w_process_maxfwd_header(struct sip_msg* msg, char* str1,char* str2)
 {
 	int val;
 	str mf_value;
 
 	val=is_maxfwd_present(msg, &mf_value);
 	switch (val) {
9202af99
 		/* header not found */
31ccf6a2
 		case -1:
9202af99
 			if (add_maxfwd_header( msg, (unsigned int)(unsigned long)str1)!=0)
 				goto error;
 			return 2;
 		/* error */
31ccf6a2
 		case -2:
 			break;
9202af99
 		/* found */
31ccf6a2
 		case 0:
 			return -1;
 		default:
772dbe96
 			if (val>max_limit){
e4a6f52c
 				LM_DBG("value %d decreased to %d\n", val, max_limit);
31ccf6a2
 				val = max_limit+1;
 			}
9202af99
 			if ( decrement_maxfwd(msg, val, &mf_value)!=0 ) {
e4a6f52c
 				LM_ERR("decrement failed!\n");
9202af99
 				goto error;
 			}
31ccf6a2
 	}
9202af99
 
31ccf6a2
 	return 1;
9202af99
 error:
 	return -2;
31ccf6a2
 }
 
 
 
9202af99
 static int is_maxfwd_lt(struct sip_msg *msg, char *slimit, char *foo)
 {
 	str mf_value;
 	int limit;
 	int val;
 
 	limit = (int)(long)slimit;
 	val = is_maxfwd_present( msg, &mf_value);
e4a6f52c
 	LM_DBG("value = %d \n",val);
9202af99
 
 	if ( val<0 ) {
 		/* error or not found */
 		return val-1;
 	} else if ( val>=limit ) {
 		/* greater or equal than/to limit */
 		return -1;
 	}
 
 	return 1;
 }
31ccf6a2