浏览代码

sl(s): added more functions to SL API

- new function send_reply() that replies stateful using TM if
  transaction is created
- internal functions to get To-tag for stateful (if T exists) or
  stateless reply
- internal function to be able to send reply with pre-set To-tag
- wrapper function that takes reason phrashe parameter as str*
- callback mechanism to handle sl reply ready and sl filtered ack events
Daniel-Constantin Mierla 15 年之前
父节点
当前提交
f169badde2
共有 4 个文件被更改,包括 444 次插入78 次删除
  1. 186 43
      modules_s/sl/sl.c
  2. 87 6
      modules_s/sl/sl.h
  3. 165 26
      modules_s/sl/sl_funcs.c
  4. 6 3
      modules_s/sl/sl_funcs.h

+ 186 - 43
modules_s/sl/sl.c

@@ -1,28 +1,7 @@
 /*
  * $Id$
  *
- * sl module
- *
- *
- * ************************************************ *
- * * Bogdan's Source Memorial                       *
- * *                                                *
- * * Welcome, pilgrim! This is one of rare places  *
- * * kept untouched in memory of brave heart,       *
- * * Bogdan, one of most active ser contributors,   *
- * * and winner of the longest line of code content.*
- * *                                                *
- * * Please, preserve this codework heritage, as    *
- * * most of other work has been smashed away during*
- * * extensive clean-up floods.                     *
- * *                                                *
- * * Hereby, we solicit you to adopt this historical*
- * * piece of code. For $100, your name will be     *
- * * be printed in this banner and we will use      *
- * * collected funds to create and display an ASCII *
- * * statue of Bogdan.                              *
- * **************************************************
- *
+ * sl module - stateless reply
  *
  * Copyright (C) 2001-2003 FhG Fokus
  *
@@ -57,6 +36,23 @@
  *              the request (bogdan)
  */
 
+/**
+ * @file
+ * @brief SL :: module definitions
+ *
+ * @ingroup sl
+ * Module: @ref sl
+ */
+
+/*!
+ * @defgroup sl SL :: The SER SL Module
+ *
+ * The SL module allows SER to act as a stateless UA server and
+ * generate replies to SIP requests without keeping state. That is beneficial
+ * in many scenarios, in which you wish not to burden server's memory and scale
+ * well.
+ */
+
 
 #include <stdio.h>
 #include <string.h>
@@ -68,6 +64,9 @@
 #include "../../ut.h"
 #include "../../script_cb.h"
 #include "../../mem/mem.h"
+
+#include "../../modules/tm/tm_load.h"
+
 #include "sl_stats.h"
 #include "sl_funcs.h"
 #include "sl.h"
@@ -77,7 +76,11 @@ MODULE_VERSION
 static int default_code = 500;
 static str default_reason = STR_STATIC_INIT("Internal Server Error");
 
+static int sl_bind_tm = 1;
+static struct tm_binds tmb;
+
 static int w_sl_send_reply(struct sip_msg* msg, char* str, char* str2);
+static int w_send_reply(struct sip_msg* msg, char* str1, char* str2);
 static int w_sl_reply_error(struct sip_msg* msg, char* str, char* str2);
 static int bind_sl(sl_api_t* api);
 static int mod_init(void);
@@ -86,11 +89,15 @@ static void mod_destroy();
 static int fixup_sl_reply(void** param, int param_no);
 
 static cmd_export_t cmds[]={
-	{"sl_send_reply",  w_sl_send_reply,             2, fixup_sl_reply, REQUEST_ROUTE},
-	{"sl_reply",       w_sl_send_reply,             2, fixup_sl_reply, REQUEST_ROUTE},
-	{"sl_reply_error", w_sl_reply_error,            0, 0,              REQUEST_ROUTE},
+	{"sl_send_reply",  w_sl_send_reply,             2, fixup_sl_reply,
+		REQUEST_ROUTE},
+	{"sl_reply",       w_sl_send_reply,             2, fixup_sl_reply,
+		REQUEST_ROUTE},
+	{"send_reply",     w_send_reply,                2, fixup_sl_reply,
+		REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
+	{"sl_reply_error", w_sl_reply_error,            0, 0,
+		REQUEST_ROUTE},
 	{"bind_sl",        (cmd_function)bind_sl,       0, 0,              0},
-	{"api_sl_reply",   (cmd_function)sl_send_reply, 2, 0,              0},
 	{0,0,0,0,0}
 };
 
@@ -99,8 +106,10 @@ static cmd_export_t cmds[]={
  * Exported parameters
  */
 static param_export_t params[] = {
-    {"default_code",   PARAM_INT, &default_code},
-    {"default_reason", PARAM_STR, &default_reason},
+	{"default_code",   PARAM_INT, &default_code},
+	{"default_reason", PARAM_STR, &default_reason},
+	{ "bind_tm",       PARAM_INT, &sl_bind_tm },
+
     {0, 0, 0}
 };
     
@@ -133,12 +142,26 @@ static int mod_init(void)
 		return -1;
 	}
 
-	     /* if SL loaded, filter ACKs on beginning */
+	/* if SL loaded, filter ACKs on beginning */
 	if (register_script_cb( sl_filter_ACK, PRE_SCRIPT_CB|REQUEST_CB, 0 )<0) {
 		ERR("Failed to install SCRIPT callback\n");
 		return -1;
 	}
-	sl_startup();
+	if(sl_startup()<0)
+	{
+		ERR("Failed to do startup tasks\n");
+		return -1;
+	}
+
+	if(sl_bind_tm!=0)
+	{
+		if(load_tm_api(&tmb)==-1)
+		{
+			LM_INFO("could not bind tm module - only stateless mode"
+					" available\n");
+			sl_bind_tm=0;
+		}
+	}
 
 	return 0;
 }
@@ -162,6 +185,13 @@ static void mod_destroy()
 }
 
 
+/**
+ * @brief Small wrapper around sl_send_reply
+ *
+ * Warapper around sl_send_rply() which accepts parameters that include
+ * config variables
+ *
+ */
 static int w_sl_send_reply(struct sip_msg* msg, char* p1, char* p2)
 {
     int code, ret;
@@ -169,50 +199,163 @@ static int w_sl_send_reply(struct sip_msg* msg, char* p1, char* p2)
     char* r;
 
     if (get_int_fparam(&code, msg, (fparam_t*)p1) < 0) {
-	code = default_code;
+		code = default_code;
     }
     
     if (get_str_fparam(&reason, msg, (fparam_t*)p2) < 0) {
-	reason = default_reason;;
+		reason = default_reason;;
     }
 
-    r = as_asciiz(&reason);
-    if (r == NULL) r = default_reason.s;
-    ret = sl_send_reply(msg, code, r);
-    if (r) pkg_free(r);
+	if(reason.s[reason.len-1]=='\0') {
+		r = reason.s;
+	} else {
+		r = as_asciiz(&reason);
+		if (r == NULL) r = default_reason.s;
+	}
+	ret = sl_send_reply(msg, code, r);
+    if (r!=reason.s) pkg_free(r);
     return ret;
 }
 
 
+/**
+ * @brief Small wrapper around sl_reply_error
+ */
 static int w_sl_reply_error( struct sip_msg* msg, char* str, char* str2)
 {
 	return sl_reply_error( msg );
 }
 
+/**
+ * @brief send stateful reply if transaction was created
+ *
+ * Check if transation was created for respective SIP request and reply
+ * in stateful mode, otherwise send stateless reply
+ *
+ * @param msg - SIP message structure
+ * @param code - reply status code
+ * @param reason - reply reason phrase
+ * @return 1 for success and -1 for failure
+ */
+int send_reply(struct sip_msg *msg, int code, str *reason)
+{
+    char *r = NULL;
+	struct cell *t;
+	int ret = 1;
+
+	if(reason->s[reason->len-1]=='\0') {
+		r = reason->s;
+	} else {
+		r = as_asciiz(reason);
+		if (r == NULL)
+		{
+			LM_ERR("no pkg for reason phrase\n");
+			return -1;
+		}
+	}
+
+	if(sl_bind_tm!=0)
+	{
+		t = tmb.t_gett();
+		if(t!= NULL && t!=T_UNDEFINED)
+		{
+			if(tmb.t_reply(msg, code, r)< 0)
+			{
+				LM_ERR("failed to reply stateful (tm)\n");
+				goto error;
+			}
+			LM_DBG("reply in stateful mode (tm)\n");
+			goto done;
+		}
+	}
+
+	LM_DBG("reply in stateless mode (sl)\n");
+	ret = sl_send_reply(msg, code, r);
+
+done:
+	if(r!=reason->s) pkg_free(r);
+	return ret;
+
+error:
+	if(r!=reason->s) pkg_free(r);
+	return -1;
+}
+
+/**
+ * @brief Small wrapper around send_reply
+ */
+static int w_send_reply(struct sip_msg* msg, char* p1, char* p2)
+{
+    int code;
+    str reason;
+
+    if (get_int_fparam(&code, msg, (fparam_t*)p1) < 0) {
+		code = default_code;
+    }
+
+    if (get_str_fparam(&reason, msg, (fparam_t*)p2) < 0) {
+		reason = default_reason;
+    }
+
+	return send_reply(msg, code, &reason);
+}
+
+/**
+ * @brief store To-tag value in totag parameter
+ */
+int get_reply_totag(struct sip_msg *msg, str *totag)
+{
+	struct cell * t;
+	if(msg==NULL || totag==NULL)
+		return -1;
+	if(sl_bind_tm!=0)
+	{
+		t = tmb.t_gett();
+		if(t!= NULL && t!=T_UNDEFINED)
+		{
+			if(tmb.t_get_reply_totag(msg, totag)< 0)
+			{
+				LM_ERR("failed to get totag (tm)\n");
+				return -1;
+			}
+			LM_DBG("totag stateful mode (tm)\n");
+			return 1;
+		}
+	}
+
+	LM_DBG("totag stateless mode (sl)\n");
+	return sl_get_reply_totag(msg, totag);
+}
+
 
+/**
+ * @brief fixup for SL reply config file functions
+ */
 static int fixup_sl_reply(void** param, int param_no)
 {
 	if (param_no == 1) {
 		return fixup_var_int_12(param, 1);
 	} else if (param_no == 2) {
-	        return fixup_var_str_12(param, 2);
+		return fixup_var_str_12(param, 2);
 	}
 	return 0;
 }
 
 
+/**
+ * @brief bind functions to SL API structure
+ */
 static int bind_sl(sl_api_t* api)
 {
 	if (!api) {
 		ERR("Invalid parameter value\n");
 		return -1;
 	}
-
-	api->reply = (sl_send_reply_f)find_export("api_sl_reply", 2, 0);
-	if (api->reply == 0) {
-		ERR("Can't bind sl_reply functionn");
-		return -1;
-	}
+	api->zreply = sl_send_reply;
+	api->sreply = sl_send_reply_str;
+	api->dreply = sl_send_reply_dlg;
+	api->freply = send_reply;
+	api->get_reply_totag = get_reply_totag;
 
 	return 0;
 }

+ 87 - 6
modules_s/sl/sl.h

@@ -24,17 +24,98 @@
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#ifndef _SL_H
-#define _SL_H
 
+/**
+ * @file
+ * @brief SL - API definitions
+ * @ingroup sl
+ * Module: @ref sl
+ */
+#ifndef _SL_H_
+#define _SL_H_
+
+#include "../../sr_module.h"
 #include "../../parser/msg_parser.h"
 
-typedef int (*sl_send_reply_f)(struct sip_msg* msg, int code, char* reason);
+/* callback for SL events */
+#define SLCB_REPLY_READY       (1<<0)  /* stateless reply ready to be sent */
+#define SLCB_ACK_FILTERED      (1<<1)  /* stateless ACK filtered */
+
+/**
+ * @brief SL callback parameter structure
+ */
+typedef struct sl_cbp {
+	unsigned int type;     /* type of callback */
+	sip_msg_t *req;        /* SIP request to reply to, or filtered ACK */
+	int  code;             /* reply status code */
+	str  *reason;          /* reply reason phrase */
+	str  *reply;           /* raw content of the reply to be sent */
+	struct dest_info *dst; /* info about destination address */
+	void *cbp;             /* parameter from callback registration */
+} sl_cbp_t;
+
+/**
+ * @brief SL callback function prototype
+ */
+typedef void (*sl_cbf_f)(sl_cbp_t *slcbp);
+
+/**
+ * @bried SL callback structure definition
+ */
+typedef struct sl_cbelem {
+	unsigned int type;         /* type of callback - can be a mask of types */
+	sl_cbf_f cbf;              /* pointer to callback function */
+	void *cbp;                 /* param to callback function */
+	struct sl_cbelem* next;    /* next sl_cbelem value */
+} sl_cbelem_t;
+
+void sl_destroy_callbacks_list(void);
+
+typedef int (*sl_register_cb_f)(sl_cbelem_t *cbe);
+int sl_register_callback(sl_cbelem_t *cbe);
+
+void sl_run_callbacks(unsigned int type, struct sip_msg *req,
+		int code, str *reason, str *reply, struct dest_info *dst);
+
+/* prototypes for SL API funtions */
+typedef int (*get_reply_totag_f)(struct sip_msg *msg, str *tag);
+typedef int (*send_reply_f)(struct sip_msg *msg, int code, str *reason);
+typedef int (*sl_send_reply_f)(struct sip_msg *msg, int code, char *reason);
+typedef int (*sl_send_sreply_f)(struct sip_msg *msg, int code, str *reason);
+typedef int (*sl_send_dreply_f)(struct sip_msg *msg, int code, str *reason,
+		str *tag);
 
+/**
+ * @brief Stateless (sl) API structure
+ */
 typedef struct sl_api {
-	sl_send_reply_f reply;  /* Send stateless reply */
+	sl_send_reply_f  zreply; /* send sl reply, reason is charz */
+	sl_send_sreply_f sreply; /* send sl reply, reason is str */
+	sl_send_dreply_f dreply; /* send sl reply with tag, reason is str */
+	send_reply_f     freply; /* send sl reply with tag, reason is str */
+	get_reply_totag_f get_reply_totag;
+	sl_register_cb_f  register_cb;
 } sl_api_t;
 
-typedef int (*bind_sl_t)(sl_api_t* api);
+typedef int (*bind_sl_f)(sl_api_t* api);
+
+/**
+ * @brief Load the SL API
+ */
+static inline int sl_load_api(sl_api_t *slb)
+{
+	bind_sl_f bind_sl;
+
+	if ( !(bind_sl=(bind_sl_f)find_export("bind_sl", 0, 0))) {
+		LM_ERR("cannot find bind_sl\n");
+		return -1;
+	}
+	if (bind_sl(slb)==-1)
+	{
+		LM_ERR("cannot bind sl api\n");
+		return -1;
+	}
+	return 0;
+}
 
-#endif /* _SL_H */
+#endif /* _SL_H_ */

+ 165 - 26
modules_s/sl/sl_funcs.c

@@ -60,6 +60,7 @@
 #include "../../parser/parse_to.h"
 #include "sl_stats.h"
 #include "sl_funcs.h"
+#include "sl.h"
 
 
 /* to-tag including pre-calculated and fixed part */
@@ -72,9 +73,11 @@ static char           *tag_suffix;
 static unsigned int  *sl_timeout;
 
 
+/*!
+ * init sl internal structures
+ */
 int sl_startup()
 {
-
 	init_tags( sl_tag.s, &tag_suffix,
 			"SER-stateless",
 			SL_TOTAG_SEPARATOR );
@@ -91,9 +94,9 @@ int sl_startup()
 	return 1;
 }
 
-
-
-
+/*!
+ * free sl internal structures
+ */
 int sl_shutdown()
 {
 	if (sl_timeout)
@@ -101,36 +104,49 @@ int sl_shutdown()
 	return 1;
 }
 
-int sl_send_reply(struct sip_msg *msg , int code, char* reason)
+/*!
+ * get the To-tag for stateless reply
+ */
+int sl_get_reply_totag(struct sip_msg *msg, str *totag)
 {
-	char *buf, *dset;
-	unsigned int len;
+	if(msg==NULL || totag==NULL)
+		return -1;
+	calc_crc_suffix(msg, tag_suffix);
+	*totag = sl_tag;
+	return 1;
+}
+
+
+/*!
+ * helper function for stateless reply
+ */
+int sl_reply_helper(struct sip_msg *msg, int code, char *reason, str *tag)
+{
+	str buf = {0, 0};
+	str dset = {0, 0};
 	struct dest_info dst;
 	struct bookmark dummy_bm;
-	int backup_mhomed, ret, dset_len;
+	int backup_mhomed, ret;
 
 
-	if ( msg->first_line.u.request.method_value==METHOD_ACK)
-	{
-		LOG(L_WARN, "Warning: sl_send_reply: I won't send a reply for ACK!!\n");
+	if (msg->first_line.u.request.method_value==METHOD_ACK)
 		goto error;
-	}
+
 	init_dest_info(&dst);
 	if (reply_to_via) {
-		if (update_sock_struct_from_via(  &dst.to, msg, msg->via1 )==-1)
+		if (update_sock_struct_from_via(&dst.to, msg, msg->via1 )==-1)
 		{
-			LOG(L_ERR, "ERROR: sl_send_reply: "
-				"cannot lookup reply dst: %s\n",
-				msg->via1->host.s );
+			LOG(L_ERR, "ERROR: sl_reply_helper: cannot lookup reply dst: %s\n",
+				msg->via1->host.s);
 			goto error;
 		}
-	} else update_sock_struct_from_ip( &dst.to, msg );
+	} else update_sock_struct_from_ip(&dst.to, msg);
 
 	/* if that is a redirection message, dump current message set to it */
 	if (code>=300 && code<400) {
-		dset=print_dset(msg, &dset_len);
-		if (dset) {
-			add_lump_rpl(msg, dset, dset_len, LUMP_RPL_HDR);
+		dset.s=print_dset(msg, &dset.len);
+		if (dset.s) {
+			add_lump_rpl(msg, dset.s, dset.len, LUMP_RPL_HDR);
 		}
 	}
 
@@ -142,12 +158,19 @@ int sl_send_reply(struct sip_msg *msg , int code, char* reason)
 		(msg->to || (parse_headers(msg,HDR_TO_F, 0)!=-1 && msg->to))
 		&& (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) ) 
 	{
-		calc_crc_suffix( msg, tag_suffix );
-		buf = build_res_buf_from_sip_req(code,reason,&sl_tag,msg,&len,&dummy_bm);
+		if(tag!=NULL && tag->s!=NULL) {
+			buf.s = build_res_buf_from_sip_req(code, reason, tag,
+						msg, (unsigned int*)&buf.len, &dummy_bm);
+		} else {
+			calc_crc_suffix( msg, tag_suffix );
+			buf.s = build_res_buf_from_sip_req(code,reason, &sl_tag, msg,
+					(unsigned int*)&buf.len, &dummy_bm);
+		}
 	} else {
-		buf = build_res_buf_from_sip_req(code,reason,0,msg,&len,&dummy_bm);
+		buf.s = build_res_buf_from_sip_req(code, reason, 0, msg,
+				(unsigned int*)&buf.len, &dummy_bm);
 	}
-	if (!buf)
+	if (!buf.s)
 	{
 		DBG("DEBUG: sl_send_reply: response building failed\n");
 		goto error;
@@ -169,9 +192,9 @@ int sl_send_reply(struct sip_msg *msg , int code, char* reason)
 	dst.comp=msg->via1->comp_no;
 #endif
 	dst.send_flags=msg->rpl_send_flags;
-	ret = msg_send(&dst, buf, len);
+	ret = msg_send(&dst, buf.s, buf.len);
 	mhomed=backup_mhomed;
-	pkg_free(buf);
+	pkg_free(buf.s);
 
 	if (ret<0) {
 		goto error;
@@ -187,6 +210,57 @@ error:
 	return -1;
 }
 
+/*! wrapper of sl_reply_helper - reason is charz, tag is null */
+int sl_send_reply(struct sip_msg *msg, int code, char *reason)
+{
+	return sl_reply_helper(msg, code, reason, 0);
+}
+
+/*! wrapper of sl_reply_helper - reason is str, tag is null */
+int sl_send_reply_str(struct sip_msg *msg, int code, str *reason)
+{
+	char *r;
+	int ret;
+
+	if(reason->s[reason->len-1]=='\0') {
+		r = reason->s;
+	} else {
+		r = as_asciiz(reason);
+		if (r == NULL)
+		{
+			LM_ERR("no pkg for reason phrase\n");
+			return -1;
+		}
+	}
+
+	ret = sl_reply_helper(msg, code, r, 0);
+
+    if (r!=reason->s) pkg_free(r);
+	return ret;
+}
+
+/*! wrapper of sl_reply_helper - reason is str, tag is str */
+int sl_send_reply_dlg(struct sip_msg *msg, int code, str *reason, str *tag)
+{
+	char *r;
+	int ret;
+
+	if(reason->s[reason->len-1]=='\0') {
+		r = reason->s;
+	} else {
+		r = as_asciiz(reason);
+		if (r == NULL)
+		{
+			LM_ERR("no pkg for reason phrase\n");
+			return -1;
+		}
+	}
+
+	ret = sl_reply_helper(msg, code, r, tag);
+
+    if (r!=reason->s) pkg_free(r);
+	return ret;
+}
 
 int sl_reply_error(struct sip_msg *msg )
 {
@@ -254,3 +328,68 @@ pass_it:
 	return 1;
 }
 
+/**
+ * SL callbacks handling
+ */
+
+static sl_cbelem_t *_sl_cbelem_list = NULL;
+
+void sl_destroy_callbacks_list(void)
+{
+	sl_cbelem_t *p1;
+	sl_cbelem_t *p2;
+
+	p1 = _sl_cbelem_list;
+	while(p1) {
+		p2 = p1;
+		p1 = p1->next;
+		pkg_free(p2);
+	}
+}
+
+int sl_register_callback(sl_cbelem_t *cbe)
+{
+	sl_cbelem_t *p1;
+
+	if(cbe==NULL) {
+		LM_ERR("invalid parameter\n");
+		return -1;
+	}
+	p1 = (sl_cbelem_t*)pkg_malloc(sizeof(sl_cbelem_t));
+
+	if(p1==NULL) {
+		LM_ERR("no more pkg\n");
+		return -1;
+	}
+
+	memcpy(p1, cbe, sizeof(sl_cbelem_t));
+	p1->next = _sl_cbelem_list;
+	_sl_cbelem_list = p1;
+
+	return 0;
+}
+
+void sl_run_callbacks(unsigned int type, struct sip_msg *req,
+		int code, str *reason, str *reply, struct dest_info *dst)
+{
+	sl_cbp_t param;
+	sl_cbelem_t *p1;
+
+	/* memset(&cbp, 0, sizeof(sl_cbp_t)); */
+	param.type   = type;
+	param.req    = req;
+	param.code   = code;
+	param.reason = reason;
+	param.reply  = reply;
+	param.dst    = dst;
+
+	for(p1=_sl_cbelem_list; p1; p1=p1->next) {
+		if (p1->type&type) {
+			LM_DBG("execute callback for event type %d\n", type);
+			param.cbp = p1->cbp;
+			p1->cbf(&param);
+		}
+	}
+}
+
+

+ 6 - 3
modules_s/sl/sl_funcs.h

@@ -39,10 +39,13 @@
 int sl_startup();
 int sl_shutdown();
 
-int sl_send_reply(struct sip_msg* msg, int code, char* reason);
+int sl_send_reply(struct sip_msg *msg, int code, char *reason);
+int sl_send_reply_str(struct sip_msg *msg, int code, str *reason);
+int sl_send_reply_dlg(struct sip_msg *msg, int code, str *reason, str *tag);
 
-int sl_filter_ACK(struct sip_msg*, unsigned int flags, void *bar );
-int sl_reply_error(struct sip_msg *msg );
+int sl_filter_ACK(struct sip_msg *msg, unsigned int flags, void *bar);
+int sl_reply_error(struct sip_msg *msg);
 
+int sl_get_reply_totag(struct sip_msg *msg, str *totag);
 
 #endif