/* 
 * $Id$
 * 
 * Copyright (C) 2009 iptelorg GmbH
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "../../rpc_lookup.h"
#include "../../socket_info.h"
#include "../../globals.h"
#include "../../config.h"

#ifdef USE_SCTP
#include "sctp_options.h"
#include "sctp_server.h"
#endif


static const char* core_sctp_options_doc[] = {
	"Returns active sctp options. With one parameter"
	" it returns the sctp options set in the kernel for a specific socket"
	"(debugging), with 0 filled in for non-kernel related options."
	" The parameter can be: \"default\" | \"first\" | address[:port] ."
	" With no parameters it returns ser's idea of the current sctp options"
	 " (intended non-debugging use).",
	/* Documentation string */
	0                                 /* Method signature(s) */
};

static void core_sctp_options(rpc_t* rpc, void* c)
{
#ifdef USE_SCTP
	void *handle;
	struct cfg_group_sctp t;
	char* param;
	struct socket_info* si;
	char* host;
	str hs;
	int hlen;
	int port;
	int proto;

	param=0;
	if (!sctp_disable){
		/* look for optional socket parameter */
		if (rpc->scan(c, "*s", &param)>0){
			si=0;
			if (strcasecmp(param, "default")==0){
				si=sendipv4_sctp?sendipv4_sctp:sendipv6_sctp;
			}else if (strcasecmp(param, "first")==0){
				si=sctp_listen;
			}else{
				if (parse_phostport(param, &host, &hlen, &port, &proto)!=0){
					rpc->fault(c, 500, "bad param (use address, address:port,"
										" default or first)");
					return;
				}
				if (proto && proto!=PROTO_SCTP){
					rpc->fault(c, 500, "bad protocol in param (only SCTP"
										" allowed)");
					return;
				}
				hs.s=host;
				hs.len=hlen;
				si=grep_sock_info(&hs, port, PROTO_SCTP);
				if (si==0){
					rpc->fault(c, 500, "not listening on sctp %s", param);
					return;
				}
			}
			if (si==0 || si->socket==-1){
				rpc->fault(c, 500, "could not find a sctp socket");
				return;
			}
			memset(&t, 0, sizeof(t));
			if (sctp_get_cfg_from_sock(si->socket, &t)!=0){
				rpc->fault(c, 500, "failed to get socket options");
				return;
			}
		}else{
			sctp_options_get(&t);
		}
		rpc->add(c, "{", &handle);
		rpc->struct_add(handle, "ddddddddddddddddddd",
			"sctp_socket_rcvbuf",	t.so_rcvbuf,
			"sctp_socket_sndbuf",	t.so_sndbuf,
			"sctp_autoclose",		t.autoclose,
			"sctp_send_ttl",	t.send_ttl,
			"sctp_send_retries",	t.send_retries,
			"sctp_assoc_tracking",	t.assoc_tracking,
			"sctp_assoc_reuse",	t.assoc_reuse,
			"sctp_max_assocs", t.max_assocs,
			"sctp_srto_initial",	t.srto_initial,
			"sctp_srto_max",		t.srto_max,
			"sctp_srto_min",		t.srto_min,
			"sctp_asocmaxrxt",	t.asocmaxrxt,
			"sctp_init_max_attempts",	t.init_max_attempts,
			"sctp_init_max_timeo",t.init_max_timeo,
			"sctp_hbinterval",	t.hbinterval,
			"sctp_pathmaxrxt",	t.pathmaxrxt,
			"sctp_sack_delay",	t.sack_delay,
			"sctp_sack_freq",	t.sack_freq,
			"sctp_max_burst",	t.max_burst
		);
	}else{
		rpc->fault(c, 500, "sctp support disabled");
	}
#else
	rpc->fault(c, 500, "sctp support not compiled");
#endif
}



static const char* core_sctpinfo_doc[] = {
	"Returns sctp related info.",    /* Documentation string */
	0                               /* Method signature(s) */
};

static void core_sctpinfo(rpc_t* rpc, void* c)
{
#ifdef USE_SCTP
	void *handle;
	struct sctp_gen_info i;

	if (!sctp_disable){
		sctp_get_info(&i);
		rpc->add(c, "{", &handle);
		rpc->struct_add(handle, "ddd",
			"opened_connections", i.sctp_connections_no,
			"tracked_connections", i.sctp_tracked_no,
			"total_connections", i.sctp_total_connections
		);
	}else{
		rpc->fault(c, 500, "sctp support disabled");
	}
#else
	rpc->fault(c, 500, "sctp support not compiled");
#endif
}


/*
 * RPC Methods exported by this module
 */
static rpc_export_t scp_rpc_methods[] = {
	{"sctp.options",      core_sctp_options,      core_sctp_options_doc,
		0},
	{"sctp.info",         core_sctpinfo,          core_sctpinfo_doc,   0},

	{0, 0, 0, 0}
};


int sctp_register_rpc(void)
{
	if (rpc_register_array(scp_rpc_methods)!=0)
	{
		LM_ERR("failed to register RPC commands\n");
		return -1;
	}

	return 0;
}