core_cmd.c
58c1870c
 /*
  * $Id$
  *
  * Copyright (C) 2005 iptelorg GmbH
  *
  * 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.
  *
566cde2d
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
58c1870c
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <time.h>
 #include <sys/types.h>
 #include <signal.h>
 #include "mem/mem.h"
566cde2d
 #include "mem/shm_mem.h"
58c1870c
 #include "sr_module.h"
 #include "dprint.h"
 #include "core_cmd.h"
 #include "globals.h"
 #include "pt.h"
 #include "ut.h"
d9515405
 #include "tcp_info.h"
58c1870c
 #include "core_cmd.h"
 
 
 #define MAX_CTIME_LEN 128
 
 /* up time */
 static time_t up_since;
 static char up_since_ctime[MAX_CTIME_LEN];
 
 
 static const char* system_listMethods_doc[] = {
 	"Lists all RPC methods supported by the server.",  /* Documentation string */
 	0                                                  /* Method signature(s) */
 };
 
 static void system_listMethods(rpc_t* rpc, void* c)
 {
 	struct sr_module* t;
 	rpc_export_t* ptr;
566cde2d
 
58c1870c
 	for(ptr = core_rpc_methods; ptr && ptr->name; ptr++) {
 		if (rpc->add(c, "s", ptr->name) < 0) return;
 	}
 
 	for(t = modules; t; t = t->next) {
 		for(ptr = t->exports->rpc_methods; ptr && ptr->name; ptr++) {
 			if (rpc->add(c, "s", ptr->name) < 0) return;
 		}
 	}
 }
 
 static const char* system_methodSignature_doc[] = {
 	"Returns signature of given method.",  /* Documentation string */
 	0                                      /* Method signature(s) */
 };
 
 static void system_methodSignature(rpc_t* rpc, void* c)
 {
 	rpc->fault(c, 500, "Not Implemented Yet");
 }
 
 
 static const char* system_methodHelp_doc[] = {
 	"Print the help string for given method.",  /* Documentation string */
 	0                                           /* Method signature(s) */
 };
 
 static void system_methodHelp(rpc_t* rpc, void* c)
566cde2d
 {
58c1870c
 	struct sr_module* t;
 	rpc_export_t* ptr;
 	char* name;
 
dab2c420
 	if (rpc->scan(c, "s", &name) < 1) {
e46483c8
 		rpc->fault(c, 400, "Method Name Expected");
 		return;
 	}
58c1870c
 
 	for(t = modules; t; t = t->next) {
 		for(ptr = t->exports->rpc_methods; ptr && ptr->name; ptr++) {
 			if (strcmp(name, ptr->name) == 0) {
 				if (ptr->doc_str && ptr->doc_str[0]) {
 					rpc->add(c, "s", ptr->doc_str[0]);
 				} else {
8abbb5e4
 					rpc->add(c, "s", "undocumented");
58c1870c
 				}
 				return;
 			}
 		}
 	}
8abbb5e4
 	/* try the core methods too */
 	for (ptr=core_rpc_methods;ptr && ptr->name; ptr++){
 			if (strcmp(name, ptr->name) == 0) {
 				if (ptr->doc_str && ptr->doc_str[0]) {
 					rpc->add(c, "s", ptr->doc_str[0]);
 				} else {
 					rpc->add(c, "s", "undocumented");
 				}
 				return;
 			}
 	}
6be3b3f7
 	rpc->fault(c, 400, "command not found");
58c1870c
 }
 
 
 static const char* core_prints_doc[] = {
 	"Returns the string given as parameter.",   /* Documentation string */
 	0                                           /* Method signature(s) */
 };
 
e46483c8
 
58c1870c
 static void core_prints(rpc_t* rpc, void* c)
 {
e46483c8
 	char* string = 0;
8abbb5e4
 	if (rpc->scan(c, "s", &string)>0)
 		rpc->add(c, "s", string);
58c1870c
 }
 
 
 static const char* core_version_doc[] = {
 	"Returns the version string of the server.", /* Documentation string */
 	0                                           /* Method signature(s) */
 };
 
 static void core_version(rpc_t* rpc, void* c)
 {
 	rpc->add(c, "s", SERVER_HDR);
 }
 
 
 
 static const char* core_uptime_doc[] = {
 	"Returns uptime of SER server.",  /* Documentation string */
 	0                                 /* Method signature(s) */
 };
 
 
 static void core_uptime(rpc_t* rpc, void* c)
 {
1abf9a2d
 	void* s;
58c1870c
 	time_t now;
 
 	time(&now);
566cde2d
 
1abf9a2d
 	if (rpc->add(c, "{", &s) < 0) return;
 	rpc->struct_add(s, "s", "now", ctime(&now));
 	rpc->struct_add(s, "s", "up_since", up_since_ctime);
a74b76d8
 	/* no need for a float here (unless you're concerned that your uptime)
 	rpc->struct_add(s, "f", "uptime",  difftime(now, up_since));
 	*/
 	/* on posix system we can substract time_t directly */
 	rpc->struct_add(s, "d", "uptime",  (int)(now-up_since));
58c1870c
 }
 
 
 static const char* core_ps_doc[] = {
 	"Returns the description of running SER processes.",  /* Documentation string */
 	0                                                     /* Method signature(s) */
 };
 
 
 static void core_ps(rpc_t* rpc, void* c)
 {
 	int p;
 
55a45269
 	for (p=0; p<process_count;p++) {
1abf9a2d
 		rpc->add(c, "d", pt[p].pid);
 		rpc->add(c, "s", pt[p].desc);
58c1870c
 	}
 }
 
 
 static const char* core_pwd_doc[] = {
 	"Returns the working directory of SER server.",    /* Documentation string */
 	0                                                  /* Method signature(s) */
 };
 
 
 static void core_pwd(rpc_t* rpc, void* c)
 {
         char *cwd_buf;
         int max_len;
 
         max_len = pathmax();
         cwd_buf = pkg_malloc(max_len);
         if (!cwd_buf) {
                 ERR("core_pwd: No memory left\n");
                 rpc->fault(c, 500, "Server Ran Out of Memory");
 		return;
         }
 
         if (getcwd(cwd_buf, max_len)) {
 		rpc->add(c, "s", cwd_buf);
         } else {
 		rpc->fault(c, 500, "getcwd Failed");
         }
         pkg_free(cwd_buf);
 }
 
 
 static const char* core_arg_doc[] = {
 	"Returns the list of command line arguments used on SER startup.",  /* Documentation string */
 	0                                                                   /* Method signature(s) */
 };
 
 
 static void core_arg(rpc_t* rpc, void* c)
 {
         int p;
 
         for (p = 0; p < my_argc; p++) {
 		if (rpc->add(c, "s", my_argv[p]) < 0) return;
         }
 }
 
 
 static const char* core_kill_doc[] = {
 	"Sends the given signal to SER.",  /* Documentation string */
 	0                                  /* Method signature(s) */
 };
 
 
 static void core_kill(rpc_t* rpc, void* c)
 {
e46483c8
 	int sig_no = 15;
 	rpc->scan(c, "d", &sig_no);
58c1870c
 	rpc->send(c);
 	kill(0, sig_no);
 }
 
566cde2d
 static void core_shmmem(rpc_t* rpc, void* c)
 {
 	struct mem_info mi;
 	void *handle;
 
 	shm_info(&mi);
 	rpc->add(c, "{", &handle);
 	rpc->struct_add(handle, "ddddd",
 		"total", mi.total_size,
 		"free", mi.free,
 		"used", mi.real_used,
 		"max_used", mi.max_used,
 		"fragments", mi.total_frags
 	);
 }
 
 static const char* core_shmmem_doc[] = {
 	"Returns shared memory info.",  /* Documentation string */
 	0                               /* Method signature(s) */
e46483c8
 };
 
58c1870c
 
d9515405
 static const char* core_tcpinfo_doc[] = {
 	"Returns tcp related info.",    /* Documentation string */
 	0                               /* Method signature(s) */
 };
 
 static void core_tcpinfo(rpc_t* rpc, void* c)
 {
 	void *handle;
 #ifdef USE_TCP
 	struct tcp_gen_info ti;
 	
 	if (!tcp_disable){
 		tcp_get_info(&ti);
 		rpc->add(c, "{", &handle);
e85eac0a
 		rpc->struct_add(handle, "ddd",
d9515405
 			"readers", ti.tcp_readers,
 			"max_connections", ti.tcp_max_connections,
e85eac0a
 			"opened_connections", ti.tcp_connections_no
d9515405
 		);
 	}else{
 		rpc->fault(c, 500, "tcp support disabled");
 	}
 #else
 	rpc->fault(c, 500, "tcp support not compiled");
 #endif
 }
 
566cde2d
 /*
  * RPC Methods exported by this module
58c1870c
  */
 rpc_export_t core_rpc_methods[] = {
 	{"system.listMethods",     system_listMethods,     system_listMethods_doc,     RET_ARRAY},
e46483c8
 	{"system.methodSignature", system_methodSignature, system_methodSignature_doc, 0        },
 	{"system.methodHelp",      system_methodHelp,      system_methodHelp_doc,      0        },
 	{"core.prints",            core_prints,            core_prints_doc,            0        },
 	{"core.version",           core_version,           core_version_doc,           0        },
 	{"core.uptime",            core_uptime,            core_uptime_doc,            0        },
58c1870c
 	{"core.ps",                core_ps,                core_ps_doc,                RET_ARRAY},
e46483c8
 	{"core.pwd",               core_pwd,               core_pwd_doc,               RET_ARRAY},
58c1870c
 	{"core.arg",               core_arg,               core_arg_doc,               RET_ARRAY},
e46483c8
 	{"core.kill",              core_kill,              core_kill_doc,              0        },
566cde2d
 	{"core.shmmem",            core_shmmem,            core_shmmem_doc,            0	},
d9515405
 	{"core.tcp_info",          core_tcpinfo,           core_tcpinfo_doc,          0	},
58c1870c
 	{0, 0, 0, 0}
 };
 
 int rpc_init_time(void)
 {
 	char *t;
 	time(&up_since);
 	t=ctime(&up_since);
 	if (strlen(t)+1>=MAX_CTIME_LEN) {
 		ERR("Too long data %d\n", (int)strlen(t));
 		return -1;
 	}
 	memcpy(up_since_ctime,t,strlen(t)+1);
 	return 0;
 }