Browse Source

Merge commit 'origin/daniel/pv'

* commit 'origin/daniel/pv':
  - sync transformations add/lookup with kamailio
  init_mi_core() exported via mi.h
  mi include file
  MI: core part
Andrei Pelinescu-Onciul 16 years ago
parent
commit
7f9af44626
13 changed files with 1457 additions and 76 deletions
  1. 9 0
      lib/kmi/Makefile
  2. 176 0
      lib/kmi/attr.c
  3. 61 0
      lib/kmi/attr.h
  4. 54 0
      lib/kmi/fmt.c
  5. 71 0
      lib/kmi/fmt.h
  6. 180 0
      lib/kmi/mi.c
  7. 97 0
      lib/kmi/mi.h
  8. 378 0
      lib/kmi/mi_core.c
  9. 41 0
      lib/kmi/mi_core.h
  10. 286 0
      lib/kmi/tree.c
  11. 103 0
      lib/kmi/tree.h
  12. 1 65
      mi/mi.h
  13. 0 11
      pvapi.c

+ 9 - 0
lib/kmi/Makefile

@@ -0,0 +1,9 @@
+include ../../Makefile.defs
+auto_gen=
+NAME:=kmi
+MAJOR_VER=1
+MINOR_VER=0
+BUGFIX_VER=0
+LIBS=
+
+include ../../Makefile.libs

+ 176 - 0
lib/kmi/attr.c

@@ -0,0 +1,176 @@
+/*
+ * $Id: attr.c 4518 2008-07-28 15:39:28Z henningw $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+/*!
+ * \file 
+ * \brief MI :: Attributes
+ * \ingroup mi
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "attr.h"
+#include "fmt.h"
+
+
+extern char *mi_ap_buf;
+extern int  mi_ap_buf_len;
+
+
+struct mi_attr *add_mi_attr(struct mi_node *node, int flags,
+						char *name, int name_len, char *value, int value_len)
+{
+	struct mi_attr *new, *p;
+	int size_mem, name_pos, value_pos;
+
+	if(!node)
+		return NULL;
+
+	if (!name) name_len=0;
+	if (!name_len) name=0;
+	if (!value) value_len=0;
+	if (!value_len) value=0;
+
+	if(!name && !value)
+		return NULL;
+
+	size_mem = sizeof(struct mi_attr);
+	value_pos = name_pos = 0;
+
+	if(name && (flags & MI_DUP_NAME)){
+		name_pos = size_mem;
+		size_mem += name_len;
+	}
+	if(value && (flags & MI_DUP_VALUE)){
+		value_pos = size_mem;
+		size_mem += value_len;
+	}
+
+	new = (struct mi_attr *)pkg_malloc(size_mem);
+	if (!new) {
+		LM_ERR("no more pkg mem (%d)\n",size_mem);
+		return NULL;
+	}
+	memset(new,0,size_mem);
+
+	if (name) {
+		new->name.len = name_len;
+		if(flags & MI_DUP_NAME){
+			new->name.s = ((char *)new) + name_pos;
+			strncpy(new->name.s, name, name_len);
+		} else{
+			new->name.s = name;
+		}
+	}
+
+	if (value) {
+		new->value.len = value_len;
+		if(flags & MI_DUP_VALUE){
+			new->value.s = ((char *)new) + value_pos;
+			strncpy(new->value.s, value, value_len);
+		}else{
+			new->value.s = value;
+		}
+	}
+	if(flags & MI_DUP_NAME){
+		name_pos = size_mem;
+		size_mem += name_len * sizeof(char);
+	}
+	if(flags & MI_DUP_VALUE){
+		value_pos = size_mem;
+		size_mem += value_len * sizeof(char);
+	}
+
+	if(!(node->attributes)){
+		new->next = NULL;
+		return (node->attributes = new);
+	}
+
+	for(p = node->attributes ; p->next ; p = p->next);
+
+	new->next = NULL;
+	p->next = new;
+
+	return new;
+}
+
+
+
+struct mi_attr *addf_mi_attr(struct mi_node *node, int flags,
+							char *name, int name_len, char *fmt_val, ...)
+{
+	va_list ap;
+	char *p;
+	int  len = 0;
+
+	va_start(ap, fmt_val);
+	p = mi_print_fmt( fmt_val, ap, &len);
+	va_end(ap);
+	if (p==NULL)
+		return 0;
+	return add_mi_attr(node, flags|MI_DUP_VALUE, name, name_len, p, len);
+}
+
+
+
+struct mi_attr *get_mi_attr_by_name(struct mi_node *node, char *name, int len)
+{
+	struct mi_attr *head;
+
+	if(!node || !name || !(node->attributes))
+		return NULL;
+
+	for(head = node->attributes ; head->next ; head = head->next)
+		if(len == head->name.len 
+		&& !strncasecmp(name, head->name.s, head->name.len))
+			return head;
+
+	return NULL;
+}
+
+
+void del_mi_attr_list(struct mi_node *node)
+{
+	struct mi_attr *p, *head;
+
+	if(!node || !(node->attributes))
+		return;
+
+	for(head = node->attributes; head ;){
+		p = head->next;
+		pkg_free(head);
+		head = p;
+	}
+
+	node->attributes = NULL;
+}
+

+ 61 - 0
lib/kmi/attr.h

@@ -0,0 +1,61 @@
+/*
+ * $Id: attr.h 4518 2008-07-28 15:39:28Z henningw $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+/*!
+ * \file 
+ * \brief MI :: Attributes
+ * \ingroup mi
+ */
+
+#ifndef _MI_ATTR_H
+#define _MI_ATTR_H
+
+#include <stdarg.h>
+#include "../../str.h"
+#include "tree.h"
+
+struct mi_attr{
+	str name;
+	str value;
+	struct mi_attr *next;
+};
+
+
+struct mi_attr *add_mi_attr(struct mi_node *node, int flags,
+	char *name, int name_len, char *value, int value_len);
+
+struct mi_attr *addf_mi_attr(struct mi_node *node, int flags,
+	char *name, int name_len, char *fmt_val, ...);
+
+struct mi_attr *get_mi_attr_by_name(struct mi_node *node,
+	char *name, int len);
+
+void del_mi_attr_list(struct mi_node *node);
+
+
+#endif
+

+ 54 - 0
lib/kmi/fmt.c

@@ -0,0 +1,54 @@
+/*
+ * $Id: fmt.c 4518 2008-07-28 15:39:28Z henningw $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+/*!
+ * \file 
+ * \brief MI :: Format handling
+ * \ingroup mi
+ */
+
+
+#include <string.h>
+#include "../../dprint.h"
+#include "../../mem/mem.h"
+
+char *mi_fmt_buf = 0;
+int  mi_fmt_buf_len = 0;
+
+
+int mi_fmt_init( unsigned int size )
+{
+	mi_fmt_buf = (char*)pkg_malloc(size);
+	if (mi_fmt_buf==NULL) {
+		LM_ERR("no more pkg mem\n");
+		return -1;
+	}
+	mi_fmt_buf_len = size;
+	return 0;
+}
+
+

+ 71 - 0
lib/kmi/fmt.h

@@ -0,0 +1,71 @@
+/*
+ * $Id: fmt.h 4518 2008-07-28 15:39:28Z henningw $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+/*!
+ * \file 
+ * \brief MI :: Format handling
+ * \ingroup mi
+ */
+
+
+
+#ifndef _MI_FMT_H_
+#define _MI_FMT_H_
+
+#include <stdarg.h>
+#include <errno.h>
+
+/*! \brief size of the buffer used for printing the FMT */
+#define DEFAULT_MI_FMT_BUF_SIZE 2048
+
+extern char *mi_fmt_buf;
+extern int  mi_fmt_buf_len;
+
+int mi_fmt_init( unsigned int size );
+
+static inline char* mi_print_fmt(char *fmt, va_list ap, int *len)
+{
+	int n;
+
+	if (mi_fmt_buf==NULL) {
+		if (mi_fmt_init(DEFAULT_MI_FMT_BUF_SIZE)!=0) {
+			LM_ERR("failed to init\n");
+			return 0;
+		}
+	}
+
+	n = vsnprintf( mi_fmt_buf, mi_fmt_buf_len, fmt, ap);
+	if (n<0 || n>=mi_fmt_buf_len) {
+		LM_ERR("formatting failed with n=%d, %s\n",n,strerror(errno));
+		return 0;
+	}
+
+	*len = n;
+	return mi_fmt_buf;
+}
+
+#endif

+ 180 - 0
lib/kmi/mi.c

@@ -0,0 +1,180 @@
+/*
+ * $Id: mi.c 4565 2008-08-05 14:58:52Z klaus_darilion $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+/*!
+ * \file 
+ * \brief MI :: Attributes
+ * \ingroup mi
+ */
+
+/*!
+ * \defgroup mi Kamailio Management Interface
+ * 
+ * The Kamailio management interface (MI) is a plugin architecture with a few different 
+ * handlers that gives access to the management interface over various transports.
+ *
+ * The Kamailio core and modules register commands to the interface at runtime.
+ * Look into the various module documentation files for information of these
+ * commands.
+ *
+ */
+
+#include <string.h>
+
+#include "../../dprint.h"
+#include "../../mem/mem.h"
+#include "mi.h"
+
+static struct mi_cmd*  mi_cmds = 0;
+static int mi_cmds_no = 0;
+
+
+static inline int get_mi_id( char *name, int len)
+{
+	int n;
+	int i;
+
+	for( n=0,i=0 ; i<len ; n+=name[i] ,i++ );
+	return n;
+}
+
+
+static inline struct mi_cmd* lookup_mi_cmd_id(int id,char *name, int len)
+{
+	int i;
+
+	for( i=0 ; i<mi_cmds_no ; i++ ) {
+		if ( id==mi_cmds[i].id && len==mi_cmds[i].name.len &&
+		memcmp(mi_cmds[i].name.s,name,len)==0 )
+			return &mi_cmds[i];
+	}
+
+	return 0;
+}
+
+
+int register_mi_mod( char *mod_name, mi_export_t *mis)
+{
+	int ret;
+	int i;
+
+	if (mis==0)
+		return 0;
+
+	for ( i=0 ; mis[i].name ; i++ ) {
+		ret = register_mi_cmd( mis[i].cmd, mis[i].name, mis[i].param,
+			mis[i].init_f, mis[i].flags);
+		if (ret!=0) {
+			LM_ERR("failed to register cmd <%s> for module %s\n",
+					mis[i].name,mod_name);
+		}
+	}
+	return 0;
+}
+
+
+int init_mi_child(void)
+{
+	int i;
+
+	for ( i=0 ; i<mi_cmds_no ; i++ ) {
+		if ( mi_cmds[i].init_f && mi_cmds[i].init_f()!=0 ) {
+			LM_ERR("failed to init <%.*s>\n",
+					mi_cmds[i].name.len,mi_cmds[i].name.s);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+
+
+int register_mi_cmd( mi_cmd_f f, char *name, void *param,
+									mi_child_init_f in, unsigned int flags)
+{
+	struct mi_cmd *cmds;
+	int id;
+	int len;
+
+	if (f==0 || name==0) {
+		LM_ERR("invalid params f=%p, name=%s\n", f, name);
+		return -1;
+	}
+
+	if (flags&MI_NO_INPUT_FLAG && flags&MI_ASYNC_RPL_FLAG) {
+		LM_ERR("invalids flags for <%s> - "
+			"async functions must take input\n",name);
+	}
+
+	len = strlen(name);
+	id = get_mi_id(name,len);
+
+	if (lookup_mi_cmd_id( id, name, len)) {
+		LM_ERR("command <%.*s> already registered\n", len, name);
+		return -1;
+	}
+
+	cmds = (struct mi_cmd*)pkg_realloc( mi_cmds,
+			(mi_cmds_no+1)*sizeof(struct mi_cmd) );
+	if (cmds==0) {
+		LM_ERR("no more pkg memory\n");
+		return -1;
+	}
+
+	mi_cmds = cmds;
+	mi_cmds_no++;
+
+	cmds = &cmds[mi_cmds_no-1];
+
+	cmds->f = f;
+	cmds->init_f = in;
+	cmds->flags = flags;
+	cmds->name.s = name;
+	cmds->name.len = len;
+	cmds->id = id;
+	cmds->param = param;
+
+	return 0;
+}
+
+
+struct mi_cmd* lookup_mi_cmd( char *name, int len)
+{
+	int id;
+
+	id = get_mi_id(name,len);
+	return lookup_mi_cmd_id( id, name, len);
+}
+
+
+void get_mi_cmds( struct mi_cmd** cmds, int *size)
+{
+	*cmds = mi_cmds;
+	*size = mi_cmds_no;
+}
+
+

+ 97 - 0
lib/kmi/mi.h

@@ -0,0 +1,97 @@
+/*
+ * $Id: mi.h 5003 2008-09-26 11:01:51Z henningw $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+/*!
+ * \file 
+ * \brief MI :: Management
+ * \ingroup mi
+ */
+
+
+#ifndef _MI_MI_H_
+#define _MI_MI_H_
+
+#include "../../str.h"
+#include "tree.h"
+
+#define MI_ASYNC_RPL_FLAG   (1<<0)
+#define MI_NO_INPUT_FLAG    (1<<1)
+
+#define MI_ROOT_ASYNC_RPL   ((struct mi_root*)-1)
+
+struct mi_handler;
+
+typedef struct mi_root* (mi_cmd_f)(struct mi_root*, void *param);
+typedef int (mi_child_init_f)(void);
+typedef void (mi_handler_f)(struct mi_root *, struct mi_handler *, int);
+
+
+struct mi_handler {
+	mi_handler_f *handler_f;
+	void * param;
+};
+
+
+struct mi_cmd {
+	int id;
+	str name;
+	mi_child_init_f *init_f;
+	mi_cmd_f *f;
+	unsigned int flags;
+	void *param;
+};
+
+
+typedef struct mi_export_ {
+	char *name;
+	mi_cmd_f *cmd;
+	unsigned int flags;
+	void *param;
+	mi_child_init_f *init_f;
+}mi_export_t;
+
+
+int register_mi_cmd( mi_cmd_f f, char *name, void *param,
+		mi_child_init_f in, unsigned int flags);
+
+int register_mi_mod( char *mod_name, mi_export_t *mis);
+
+int init_mi_child(void);
+
+struct mi_cmd* lookup_mi_cmd( char *name, int len);
+
+static inline struct mi_root* run_mi_cmd(struct mi_cmd *cmd, struct mi_root *t)
+{
+	return cmd->f( t, cmd->param);
+}
+
+void get_mi_cmds( struct mi_cmd** cmds, int *size);
+
+int init_mi_core(void);
+
+#endif
+

+ 378 - 0
lib/kmi/mi_core.c

@@ -0,0 +1,378 @@
+/*
+ * $Id: mi_core.c 4762 2008-08-28 11:27:31Z henningw $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+
+/*!
+ * \file 
+ * \brief MI :: Core 
+ * \ingroup mi
+ */
+
+
+
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include "../../dprint.h"
+#include "../../globals.h"
+#include "../../ut.h"
+#include "../../pt.h"
+#include "../../mem/mem.h"
+#include "mi.h"
+#include "../../version.h"
+
+#define BUILD_STR __FILE__ " compiled on "__TIME__ " " __DATE__ " with " COMPILER "\n"
+#define BUILD_STR_LEN (sizeof(BUILD_STR)-1)
+
+#ifndef SVNREVISION
+#define SVNREVISION "unknown"
+#endif
+
+static time_t kmi_up_since;
+static str    kmi_up_since_ctime;
+
+static int init_mi_uptime(void)
+{
+	char *p;
+
+	time(&kmi_up_since);
+	p = ctime(&kmi_up_since);
+	kmi_up_since_ctime.len = strlen(p)-1;
+	kmi_up_since_ctime.s = (char*)pkg_malloc(kmi_up_since_ctime.len);
+	if (kmi_up_since_ctime.s==0) {
+		LM_ERR("no more pkg mem\n");
+		return -1;
+	}
+	memcpy(kmi_up_since_ctime.s, p, kmi_up_since_ctime.len);
+	return 0;
+}
+
+
+static struct mi_root *mi_uptime(struct mi_root *cmd, void *param)
+{
+	struct mi_root *rpl_tree;
+	struct mi_node *rpl;
+	struct mi_node *node;
+	time_t now;
+	char   *p;
+
+	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
+	if (rpl_tree==0)
+		return 0;
+	rpl = &rpl_tree->node;
+
+	time(&now);
+	p = ctime(&now);
+	node = add_mi_node_child( rpl, MI_DUP_VALUE, MI_SSTR("Now"),
+		p, strlen(p)-1);
+	if (node==0)
+		goto error;
+
+	node = add_mi_node_child( rpl, 0, MI_SSTR("Up since"),
+		kmi_up_since_ctime.s, kmi_up_since_ctime.len);
+	if (node==0)
+		goto error;
+
+	node = addf_mi_node_child( rpl, 0, MI_SSTR("Up time"),
+		"%lu [sec]", (unsigned long)difftime(now, kmi_up_since) );
+	if (node==0)
+		goto error;
+
+	return rpl_tree;
+error:
+	LM_ERR("failed to add node\n");
+	free_mi_tree(rpl_tree);
+	return 0;
+}
+
+static struct mi_root *mi_version(struct mi_root *cmd, void *param)
+{
+	struct mi_root *rpl_tree;
+	struct mi_node *rpl;
+	struct mi_node *node;
+
+	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
+	if (rpl_tree==0)
+		return 0;
+	rpl = &rpl_tree->node;
+
+	node = add_mi_node_child( rpl, 0, MI_SSTR("Server"), SERVER_HDR+8,
+		SERVER_HDR_LEN-8);
+	if (node==0) 
+		goto error;
+
+	node = add_mi_node_child( rpl, 0, MI_SSTR("Build"), BUILD_STR,
+			BUILD_STR_LEN);
+	if (node==0) 
+		goto error;
+
+#ifndef KAMAILIO_COMPILE_FLAGS
+#define KAMAILIO_COMPILE_FLAGS SER_COMPILE_FLAGS
+#endif
+
+	node = add_mi_node_child( rpl, 0, MI_SSTR("Flags"), KAMAILIO_COMPILE_FLAGS,
+			sizeof(KAMAILIO_COMPILE_FLAGS)-1);
+	if (node==0) 
+		goto error;	
+	
+	node = add_mi_node_child( rpl, 0, MI_SSTR("SVN"), SVNREVISION,
+			sizeof(SVNREVISION)-1);
+	if (node==0) 
+		goto error;
+
+		
+	
+	return rpl_tree;
+error:
+	LM_ERR("failed to add node\n");
+	free_mi_tree(rpl_tree);
+	return 0;
+
+}
+
+
+
+static struct mi_root *mi_pwd(struct mi_root *cmd, void *param)
+{
+	static int max_len = 0;
+	static char *cwd_buf = 0;
+	struct mi_root *rpl_tree;
+	struct mi_node *rpl;
+	struct mi_node *node;
+
+	if (cwd_buf==NULL) {
+		max_len = pathmax();
+		cwd_buf = pkg_malloc(max_len);
+		if (cwd_buf==NULL) {
+			LM_ERR("no more pkg mem\n");
+			return 0;
+		}
+	}
+
+	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
+	if (rpl_tree==0)
+		return 0;
+	rpl = &rpl_tree->node;
+
+	if (getcwd(cwd_buf, max_len)==0) {
+		LM_ERR("getcwd failed = %s\n",strerror(errno));
+		goto error;
+	}
+
+	node = add_mi_node_child( rpl, 0, MI_SSTR("WD"), cwd_buf,strlen(cwd_buf));
+	if (node==0) {
+		LM_ERR("failed to add node\n");
+		goto error;
+	}
+
+	return rpl_tree;
+error:
+	free_mi_tree(rpl_tree);
+	return 0;
+}
+
+
+
+static struct mi_root *mi_arg(struct mi_root *cmd, void *param)
+{
+	struct mi_root *rpl_tree;
+	struct mi_node *rpl;
+	struct mi_node *node;
+	int n;
+
+	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
+	if (rpl_tree==0)
+		return 0;
+	rpl = &rpl_tree->node;
+
+	for ( n=0; n<my_argc ; n++ ) {
+		node = add_mi_node_child(rpl, 0, 0, 0, my_argv[n], strlen(my_argv[n]));
+		if (node==0) {
+			LM_ERR("failed to add node\n");
+			free_mi_tree(rpl_tree);
+			return 0;
+		}
+	}
+
+	return rpl_tree;
+}
+
+
+
+static struct mi_root *mi_which(struct mi_root *cmd, void *param)
+{
+	struct mi_root *rpl_tree;
+	struct mi_cmd  *cmds;
+	struct mi_node *rpl;
+	struct mi_node *node;
+	int size;
+	int i;
+
+	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
+	if (rpl_tree==0)
+		return 0;
+	rpl = &rpl_tree->node;
+
+	get_mi_cmds( &cmds, &size);
+	for ( i=0 ; i<size ; i++ ) {
+		node = add_mi_node_child( rpl, 0, 0, 0, cmds[i].name.s,
+			cmds[i].name.len);
+		if (node==0) {
+			LM_ERR("failed to add node\n");
+			free_mi_tree(rpl_tree);
+			return 0;
+		}
+	}
+
+	return rpl_tree;
+}
+
+
+#if 0
+static struct mi_root *mi_ps(struct mi_root *cmd, void *param)
+{
+	struct mi_root *rpl_tree;
+	struct mi_node *rpl;
+	struct mi_node *node;
+	struct mi_attr *attr;
+	char *p;
+	int len;
+	int i;
+
+	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
+	if (rpl_tree==0)
+		return 0;
+	rpl = &rpl_tree->node;
+
+	for ( i=0 ; i<counted_processes ; i++ ) {
+		node = add_mi_node_child(rpl, 0, MI_SSTR("Process"), 0, 0 );
+		if (node==0)
+			goto error;
+
+		p = int2str((unsigned long)i, &len);
+		attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("ID"), p, len);
+		if (attr==0)
+			goto error;
+
+		p = int2str((unsigned long)pt[i].pid, &len);
+		attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("PID"), p, len);
+		if (attr==0)
+			goto error;
+
+		attr = add_mi_attr( node, 0, MI_SSTR("Type"),
+			pt[i].desc, strlen(pt[i].desc));
+		if (attr==0)
+			goto error;
+	}
+
+	return rpl_tree;
+error:
+	LM_ERR("failed to add node\n");
+	free_mi_tree(rpl_tree);
+	return 0;
+}
+#endif
+
+
+static struct mi_root *mi_kill(struct mi_root *cmd, void *param)
+{
+	kill(0, SIGTERM);
+
+	return 0;
+}
+
+
+#if 0
+static struct mi_root *mi_debug(struct mi_root *cmd, void *param)
+{
+	struct mi_root *rpl_tree;
+	struct mi_node *node;
+	char *p;
+	int len;
+	int new_debug;
+
+#ifdef CHANGEABLE_DEBUG_LEVEL
+	node = cmd->node.kids;
+	if (node!=NULL) {
+		if (str2sint( &node->value, &new_debug) < 0)
+			return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
+	} else
+		new_debug = *debug;
+#else
+		new_debug = debug;
+#endif
+
+	rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
+	if (rpl_tree==0)
+		return 0;
+
+	p = sint2str((long)new_debug, &len);
+	node = add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE,
+		MI_SSTR("DEBUG"),p, len);
+	if (node==0) {
+		free_mi_tree(rpl_tree);
+		return 0;
+	}
+
+#ifdef CHANGEABLE_DEBUG_LEVEL
+	*debug = new_debug;
+#endif
+
+	return rpl_tree;
+}
+#endif
+
+
+static mi_export_t mi_core_cmds[] = {
+	{ "uptime",   mi_uptime,   MI_NO_INPUT_FLAG,  0,  init_mi_uptime },
+	{ "version",  mi_version,  MI_NO_INPUT_FLAG,  0,  0 },
+	{ "pwd",      mi_pwd,      MI_NO_INPUT_FLAG,  0,  0 },
+	{ "arg",      mi_arg,      MI_NO_INPUT_FLAG,  0,  0 },
+	{ "which",    mi_which,    MI_NO_INPUT_FLAG,  0,  0 },
+	{ "kill",     mi_kill,     MI_NO_INPUT_FLAG,  0,  0 },
+#if 0
+	{ "ps",       mi_ps,       MI_NO_INPUT_FLAG,  0,  0 },
+	{ "debug",    mi_debug,                   0,  0,  0 },
+#endif
+	{ 0, 0, 0, 0, 0}
+};
+
+
+
+int init_mi_core(void)
+{
+	if (register_mi_mod( "core", mi_core_cmds)<0) {
+		LM_ERR("unable to register core MI cmds\n");
+		return -1;
+	}
+
+	return 0;
+}

+ 41 - 0
lib/kmi/mi_core.h

@@ -0,0 +1,41 @@
+/*
+ * $Id: mi_core.h 5003 2008-09-26 11:01:51Z henningw $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+/*!
+ * \file 
+ * \brief MI :: Core
+ * \ingroup mi
+ */
+
+
+
+#ifndef _MI_MI_CORE_H_
+#define _MI_MI_CORE_H_
+
+// int init_mi_core(void);
+
+#endif

+ 286 - 0
lib/kmi/tree.c

@@ -0,0 +1,286 @@
+/*
+ * $Id: tree.c 4518 2008-07-28 15:39:28Z henningw $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+/*!
+ * \file 
+ * \brief MI :: Tree 
+ * \ingroup mi
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include "../../mem/mem.h"
+#include "../../mem/shm_mem.h"
+#include "../../dprint.h"
+#include "tree.h"
+#include "fmt.h"
+
+
+static int use_shm = 0;
+
+struct mi_root *init_mi_tree(unsigned int code, char *reason, int reason_len)
+{
+	struct mi_root *root;
+
+	if (use_shm)
+		root = (struct mi_root *)shm_malloc(sizeof(struct mi_root));
+	else
+		root = (struct mi_root *)pkg_malloc(sizeof(struct mi_root));
+	if (!root) {
+		LM_ERR("no more pkg mem\n");
+		return NULL;
+	}
+
+	memset(root,0,sizeof(struct mi_root));
+	root->node.next = root->node.last = &root->node;
+
+	if (reason && reason_len) {
+		root->reason.s = reason;
+		root->reason.len = reason_len;
+	}
+	root->code = code;
+
+	return root;
+}
+
+
+static void free_mi_node(struct mi_node *parent)
+{
+	struct mi_node *p, *q;
+
+	for(p = parent->kids ; p ; ){
+		q = p;
+		p = p->next;
+		free_mi_node(q);
+	}
+
+	if (use_shm) {
+		shm_free(parent);
+	} else {
+		del_mi_attr_list(parent);
+		pkg_free(parent);
+	}
+}
+
+void free_mi_tree(struct mi_root *parent)
+{
+	struct mi_node *p, *q;
+
+	for(p = parent->node.kids ; p ; ){
+		q = p;
+		p = p->next;
+		free_mi_node(q);
+	}
+
+	if (use_shm)
+		shm_free(parent);
+	else
+		pkg_free(parent);
+}
+
+
+static inline struct mi_node *create_mi_node(char *name, int name_len,
+									char *value, int value_len, int flags)
+{
+	struct mi_node *new;
+	int size_mem;
+	int name_pos;
+	int value_pos;
+
+	if (!name) name_len=0;
+	if (!name_len) name=0;
+	if (!value) value_len=0;
+	if (!value_len) value=0;
+
+	if (!name && !value)
+		return NULL;
+
+	size_mem = sizeof(struct mi_node);
+	value_pos = name_pos = 0;
+
+	if (name && (flags & MI_DUP_NAME)){
+		name_pos = size_mem;
+		size_mem += name_len;
+	}
+	if (value && (flags & MI_DUP_VALUE)){
+		value_pos = size_mem;
+		size_mem += value_len;
+	}
+
+	if (use_shm)
+		new = (struct mi_node *)shm_malloc(size_mem);
+	else
+		new = (struct mi_node *)pkg_malloc(size_mem);
+	if(!new) {
+		LM_ERR("no more pkg mem\n");
+		return NULL;
+	}
+	memset(new,0,size_mem);
+
+	if (name) {
+		new->name.len = name_len;
+		if(flags & MI_DUP_NAME){
+			new->name.s = ((char *)new) + name_pos;
+			strncpy(new->name.s, name, name_len);
+		} else{
+			new->name.s = name;
+		}
+	}
+
+	if (value) {
+		new->value.len = value_len;
+		if(flags & MI_DUP_VALUE){
+			new->value.s = ((char *)new) + value_pos;
+			strncpy(new->value.s, value, value_len);
+		}else{
+			new->value.s = value;
+		}
+	}
+	new->last = new;
+
+	return new;
+}
+
+
+static inline struct mi_node *add_next(struct mi_node *brother,
+			char *name, int name_len, char *value, int value_len, int flags)
+{
+	struct mi_node *new;
+
+	if(!brother)
+		return NULL;
+	
+	new = create_mi_node(name, name_len, value, value_len, flags);
+	if(!new)
+		return NULL;
+
+	brother->last->next = new;
+	brother->last = new;
+
+	return new;
+}
+
+
+struct mi_node *add_mi_node_sibling( struct mi_node *brother, int flags,
+						char *name, int name_len, char *value, int value_len)
+{
+	return add_next(brother, name, name_len, value, value_len, flags);
+}
+
+
+struct mi_node *addf_mi_node_sibling(struct mi_node *brother, int flags,
+							char *name, int name_len, char *fmt_val, ...)
+{
+	va_list ap;
+	char *p;
+	int  len;
+
+	va_start(ap, fmt_val);
+	p = mi_print_fmt( fmt_val, ap, &len);
+	va_end(ap);
+	if (p==NULL)
+		return 0;
+	return add_mi_node_sibling( brother, flags|MI_DUP_VALUE,
+		name, name_len, p, len);
+}
+
+
+struct mi_node *add_mi_node_child( struct mi_node *parent, int flags,
+						char *name, int name_len, char *value, int value_len)
+{
+	if(parent->kids){
+		return add_next(parent->kids, name, name_len, value, value_len, flags);
+	}else{
+		parent->kids = create_mi_node(name, name_len, value, value_len, flags);
+		return parent->kids;
+	}
+}
+
+
+struct mi_node *addf_mi_node_child(struct mi_node *parent, int flags,
+							char *name, int name_len, char *fmt_val, ...)
+{
+	va_list ap;
+	char *p;
+	int  len;
+
+	va_start(ap, fmt_val);
+	p = mi_print_fmt( fmt_val, ap, &len);
+	va_end(ap);
+	if (p==NULL)
+		return 0;
+	return add_mi_node_child( parent, flags|MI_DUP_VALUE,
+		name, name_len, p, len);
+}
+
+
+static int clone_mi_node(struct mi_node *org, struct mi_node *parent)
+{
+	struct mi_node *p, *q;
+
+	for(p = org->kids ; p ; p=p->next){
+		q = add_mi_node_child( parent, MI_DUP_VALUE|MI_DUP_NAME,
+			p->name.s, p->name.len, p->value.s, p->value.len);
+		if (q==NULL)
+			return -1;
+		if (clone_mi_node( p, q)!=0)
+			return -1;
+	}
+	return 0;
+}
+
+
+struct mi_root* clone_mi_tree(struct mi_root *org, int shm)
+{
+	struct mi_root *root;
+
+	use_shm = shm?1:0;
+
+	root = init_mi_tree( org->code, org->reason.s, org->reason.len);
+	if (root==NULL)
+		goto done;
+
+	if (clone_mi_node( &(org->node), &(root->node) )!=0 ) {
+		free_mi_tree(root);
+		root = NULL;
+		goto done;
+	}
+
+done:
+	use_shm=0;
+	return root;
+}
+
+
+
+void free_shm_mi_tree(struct mi_root *parent)
+{
+	use_shm = 1;
+	free_mi_tree(parent);
+	use_shm = 0;
+}

+ 103 - 0
lib/kmi/tree.h

@@ -0,0 +1,103 @@
+/*
+ * $Id: tree.h 4518 2008-07-28 15:39:28Z henningw $
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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.
+ *
+ * Kamailio 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:
+ * ---------
+ *  2006-09-08  first version (bogdan)
+ */
+
+/*!
+ * \file 
+ * \brief MI :: Tree
+ * \ingroup mi
+ */
+
+
+
+
+#ifndef _MI_TREE_H
+#define _MI_TREE_H
+
+#include <stdarg.h>
+#include "../../str.h"
+
+struct mi_node;
+struct mi_handler;
+
+#include "attr.h"
+
+#define MI_DUP_NAME   (1<<0)
+#define MI_DUP_VALUE  (1<<1)
+
+#define MI_OK_S              "OK"
+#define MI_OK_LEN            (sizeof(MI_OK_S)-1)
+#define MI_INTERNAL_ERR_S    "Server Internal Error"
+#define MI_INTERNAL_ERR_LEN  (sizeof(MI_INTERNAL_ERR_S)-1)
+#define MI_MISSING_PARM_S    "Too few or too many arguments"
+#define MI_MISSING_PARM_LEN  (sizeof(MI_MISSING_PARM_S)-1)
+#define MI_BAD_PARM_S        "Bad parameter"
+#define MI_BAD_PARM_LEN      (sizeof(MI_BAD_PARM_S)-1)
+
+#define MI_SSTR(_s)           _s,(sizeof(_s)-1)
+#define MI_OK                 MI_OK_S
+#define MI_INTERNAL_ERR       MI_INTERNAL_ERR_S
+#define MI_MISSING_PARM       MI_MISSING_PARM_S
+#define MI_BAD_PARM           MI_BAD_PARM_S
+
+struct mi_node {
+	str value;
+	str name;
+	struct mi_node *kids;
+	struct mi_node *next;
+	struct mi_node *last;
+	struct mi_attr *attributes;
+};
+
+struct mi_root {
+	unsigned int       code;
+	str                reason;
+	struct mi_handler  *async_hdl;
+	struct mi_node     node;
+};
+
+struct mi_root *init_mi_tree(unsigned int code, char *reason, int reason_len);
+
+void free_mi_tree(struct mi_root *parent);
+
+struct mi_node *add_mi_node_sibling(struct mi_node *brother, int flags,
+	char *name, int name_len, char *value, int value_len);
+
+struct mi_node *addf_mi_node_sibling(struct mi_node *brother, int flags,
+	char *name, int name_len, char *fmt_val, ...);
+
+struct mi_node *add_mi_node_child(struct mi_node *parent, int flags,
+	char *name, int name_len, char *value, int value_len);
+
+struct mi_node *addf_mi_node_child(struct mi_node *parent, int flags,
+	char *name, int name_len, char *fmt_val, ...);
+
+struct mi_root* clone_mi_tree(struct mi_root *org, int shm);
+
+void free_shm_mi_tree(struct mi_root *parent);
+
+#endif
+

+ 1 - 65
mi/mi.h

@@ -28,71 +28,7 @@
 #ifndef _mi_h_
 #define _mi_h_
 
-#include "../str.h"
-
-#define MI_DUP_NAME   (1<<0)
-#define MI_DUP_VALUE  (1<<1)
-
-#define MI_OK_S              "OK"
-#define MI_OK_LEN            (sizeof(MI_OK_S)-1)
-#define MI_INTERNAL_ERR_S    "Server Internal Error"
-#define MI_INTERNAL_ERR_LEN  (sizeof(MI_INTERNAL_ERR_S)-1)
-#define MI_MISSING_PARM_S    "Too few or too many arguments"
-#define MI_MISSING_PARM_LEN  (sizeof(MI_MISSING_PARM_S)-1)
-#define MI_BAD_PARM_S        "Bad parameter"
-#define MI_BAD_PARM_LEN      (sizeof(MI_BAD_PARM_S)-1)
-
-#define MI_SSTR(_s)           _s,(sizeof(_s)-1)
-#define MI_OK                 MI_OK_S
-#define MI_INTERNAL_ERR       MI_INTERNAL_ERR_S
-#define MI_MISSING_PARM       MI_MISSING_PARM_S
-#define MI_BAD_PARM           MI_BAD_PARM_S
-
-
-
-struct mi_attr{
-	str name;
-	str value;
-	struct mi_attr *next;
-};
-
-
-struct mi_node {
-	str value;
-	str name;
-	struct mi_node *kids;
-	struct mi_node *next;
-	struct mi_node *last;
-	struct mi_attr *attributes;
-};
-
-
-struct mi_root {
-	unsigned int       code;
-	str                reason;
-	struct mi_handler  *async_hdl;
-	struct mi_node     node;
-};
-
-typedef struct mi_root* (mi_cmd_f)(struct mi_root*, void *param);
-typedef int (mi_child_init_f)(void);
-
-
-typedef struct mi_export_ {
-	char *name;
-	mi_cmd_f *cmd;
-	unsigned int flags;
-	void *param;
-	mi_child_init_f *init_f;
-}mi_export_t;
-
-
-#define init_mi_tree(code, reason, reason_len) 0
-#define free_mi_tree(parent)
-#define add_mi_node_sibling(node, flags, name, name_len, val, val_len) 0
-#define add_mi_node_child(node, flags, name, name_len, val, val_len) 0
-#define addf_mi_node_child(node, flags, name, name_len, fmt, ...) 0
-
+#include "../lib/kmi/mi.h"
 
 #endif /* _mi_h_ */
 

+ 0 - 11
pvapi.c

@@ -1362,15 +1362,9 @@ int tr_table_add(tr_export_t *e)
 	tri = _tr_table[trid%TR_TABLE_SIZE];
 	while(tri)
 	{
-		if(tri->trid > trid)
-			break;
-		if(tri->tre.tclass.len > e->tclass.len)
-			break;
 		if(tri->tre.tclass.len==e->tclass.len)
 		{
 			found = strncmp(tri->tre.tclass.s, e->tclass.s, e->tclass.len);
-			if(found>0)
-				break;
 			if(found==0)
 			{
 				LM_ERR("TR class [%.*s] already exists\n", e->tclass.len,
@@ -1470,11 +1464,6 @@ tr_export_t* tr_lookup_class(str *tclass)
 	tri = _tr_table[trid%TR_TABLE_SIZE];
 	while(tri)
 	{
-		if(tri->trid > trid)
-			break;
-		if(tri->tre.tclass.len > tclass->len)
-			break;
-
 		if(tri->trid==trid && tri->tre.tclass.len==tclass->len
 				&& memcmp(tri->tre.tclass.s, tclass->s, tclass->len)==0)
 			return &(tri->tre);