obsolete/permissions/ip_set_rpc.c
3d2616ae
 /* 
  * $Id$
  *
  * allow_trusted related functions
  *
  * Copyright (C) 2003 Juha Heinanen
  *
  * 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.
  *
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
3d2616ae
  *
  * History:
  * --------
  *   2008-08-01: released
  */
 
 #include "../../dprint.h"
7a7f1a7b
 #include "../../lib/srdb2/db.h"
3d2616ae
 #include "../../mem/shm_mem.h"
 #include "permissions.h"
 #include "ip_set.h"
 #include "ip_set_rpc.h"
 
 
 static struct ip_set_list_item *ip_set_list = NULL;
 static int ip_set_list_count = 0;
 
 int ip_set_list_malloc(int num, str* names) {
a8679aa4
 	int i, j;
3d2616ae
 	if (num) {
 		ip_set_list = shm_malloc(num*sizeof(*ip_set_list));
 		if (!ip_set_list) return -1;
 		ip_set_list_count = num;
 		for (i=0; i<ip_set_list_count; i++) {
 			ip_set_list[i].idx = i;
 			ip_set_list[i].name = names[i];
 			lock_init(&ip_set_list[i].read_lock);
 			lock_init(&ip_set_list[i].write_lock);
 			ip_set_list[i].ip_set = NULL;
 			ip_set_init(&ip_set_list[i].ip_set_pending, 1);
a8679aa4
 			for (j=0; j<ip_set_list[i].name.len; j++) {
 				if (ip_set_list[i].name.s[j]=='=') {
 					str s;
 					s.s = ip_set_list[i].name.s + j + 1;
 					s.len = ip_set_list[i].name.len - j - 1;
 					ip_set_list[i].name.len = j;
29f9568c
 					ip_set_list[i].ip_set = shm_malloc(sizeof(*ip_set_list[i].ip_set));
a8679aa4
 					if (!ip_set_list[i].ip_set) return -1;
29f9568c
 					atomic_set(&ip_set_list[i].ip_set->refcnt, 1);
a8679aa4
 					ip_set_add_list(&ip_set_list[i].ip_set->ip_set, s); /* allow pass even in case of error */
 				}
 			}
3d2616ae
 		}
 	}
 	return 0;
 }
 
 void ip_set_list_free() {
 	int i;
 	if (!ip_set_list) return;
 	for (i=0; i<ip_set_list_count; i++) {
 		lock_destroy(&ip_set_list[i].read_lock);
 		lock_destroy(&ip_set_list[i].write_lock);
 		if (ip_set_list[i].ip_set) {
 			if (atomic_dec_and_test(&ip_set_list[i].ip_set->refcnt)) { /* do not destroy cloned sets because if they can live only in local copy after commit,
 										   they must be deleted separately in local copy before this procedure is called*/
 				ip_set_destroy(&ip_set_list[i].ip_set->ip_set);
 				shm_free(ip_set_list[i].ip_set);
 			}			
 		}
 		ip_set_destroy(&ip_set_list[i].ip_set_pending);
 	}
 	shm_free(ip_set_list);
 	ip_set_list = NULL;
 
 }
 
 struct ip_set_list_item* ip_set_list_find_by_name(str name) {
 	int i;
 	for (i=0; i<ip_set_list_count; i++) {
 		if (ip_set_list[i].name.len == name.len && memcmp(ip_set_list[i].name.s, name.s, name.len) == 0)
 			return &ip_set_list[i];
 	}
 	return NULL;
 }
 
 
 const char* rpc_ip_set_clean_doc[] = {
 	"Clean ip set.",
 	0
 };
 
 
 void rpc_ip_set_clean(rpc_t* rpc, void* ctx) {
 	str name;
 	struct ip_set_list_item *p;
 	if (rpc->scan(ctx, "S", &name) < 1) {
 		return;
 	}
 	p = ip_set_list_find_by_name(name);
 	if (!p) {
 		rpc->fault(ctx, 400, "Ip set not found");
 		return;
 	}
 	lock_get(&p->write_lock);
 	ip_set_destroy(&p->ip_set_pending);
 	ip_set_init(&p->ip_set_pending, 1);
 	lock_release(&p->write_lock);
 }
 
 const char* rpc_ip_set_add_doc[] = {
 	"Add IP/mask in ip set.",
 	0
 };
 
 
 void rpc_ip_set_add(rpc_t* rpc, void* ctx) {
 	str name, ip, mask;
 	struct ip_set_list_item* p;
 	if (rpc->scan(ctx, "SSS", &name, &ip, &mask) < 1) {
 		return;
 	}
 	while (mask.len && mask.s[0]=='/') {  /* rpc cannot read plain number as string, adding '/' helps */
 		mask.s++;
 		mask.len--;
 	}
 	p = ip_set_list_find_by_name(name);
 	if (!p) {
 		rpc->fault(ctx, 400, "Ip set not found");
 		return;
 	}
 	lock_get(&p->write_lock);
 	if (ip_set_add_ip_s(&p->ip_set_pending, ip, mask) < 0) {
 		lock_release(&p->write_lock);
 		rpc->fault(ctx, 400, "Cannot add ip/mask into ip set");
 		return;
 	}
 	lock_release(&p->write_lock);
 }
 
 const char* rpc_ip_set_commit_doc[] = {
 	"Commit changes in ip set.",
 	0
 };
 
 void rpc_ip_set_commit(rpc_t* rpc, void* ctx) {
 	str name;
 	struct ip_set_list_item *p;
 	struct ip_set_ref *new_ip_set;
 	if (rpc->scan(ctx, "S", &name) < 1) {
 		return;
 	}
 	p = ip_set_list_find_by_name(name);
 	if (!p) {
 		rpc->fault(ctx, 400, "Ip set not found");
 		return;
 	}
 	lock_get(&p->write_lock);
 	lock_get(&p->read_lock);
 	new_ip_set = shm_malloc(sizeof(*new_ip_set));
 	if (!new_ip_set) {
 		rpc->fault(ctx, 500, "Not enough memory");
a8679aa4
 		goto err;
3d2616ae
 	}
 	
 	if (p->ip_set) {
 		if (atomic_dec_and_test(&p->ip_set->refcnt)) {
 			ip_set_destroy(&p->ip_set->ip_set);  /* not used in local copy */
 			shm_free(p->ip_set);
 		}
 	}
 	new_ip_set->ip_set = p->ip_set_pending;
 	atomic_set(&new_ip_set->refcnt, 1);
 	p->ip_set = new_ip_set;
 	
 	ip_set_init(&p->ip_set_pending, 1);
a8679aa4
 err:	
3d2616ae
 	lock_release(&p->read_lock);
 	lock_release(&p->write_lock);
 }
 
 const char* rpc_ip_set_list_doc[] = {
 	"List ip set names.",
 	0
 };
 
 
 void rpc_ip_set_list(rpc_t* rpc, void* ctx) {
 	int i;
 	void *c;
 	rpc->add(ctx, "{", &c);
 	for (i=0; i<ip_set_list_count; i++) {
 		if (rpc->struct_add(c, "S", "Name", &ip_set_list[i].name) < 0) {
 			 rpc->fault(ctx, 500, "Error when listing ip sets");
 		}
 	}
 }
 
 const char* rpc_ip_set_print_doc[] = {
 	"Print ip set.",
 	0
 };
 
 
 static int rpc_ip_tree_print(rpc_t* rpc, void *ctx, char *prefix, struct ip_tree_leaf *tree, unsigned int indent) {
 	int j;
 	if (!tree) {
 		if (rpc->struct_printf(ctx, "", "%*snil", indent, prefix) < 0) return -1;
 	}
 	else {
 		str s;
 		s = ip_tree_mask_to_str(tree->prefix_match, tree->prefix_match_len);
 		if (rpc->struct_printf(ctx, "", "%*smatch %d bits {%.*s}", indent, prefix, tree->prefix_match_len, s.len, s.s) < 0) 
 			return -1;
 		for (j=0; j<=1; j++) {
 			if (rpc_ip_tree_print(rpc, ctx, j==0?"0:":"1:", tree->next[j], indent+2) < 0)
 				return -1;
 		}
 	}
 	return 0;
 }
 
 	
 void rpc_ip_set_print(rpc_t* rpc, void* ctx) {
 	struct ip_set_list_item *p;
 	struct ip_set *ip_set, ip_set2;
 	void *c;
 	str name;
 	int pending;
 	if (rpc->scan(ctx, "Sd", &name, &pending) < 1) {
 		return;
 	}
 	p = ip_set_list_find_by_name(name);
 	if (!p) {
 		rpc->fault(ctx, 400, "Ip set not found");
 		return;
 	}
 	if (pending) {
 		lock_get(&p->write_lock);
 		ip_set = &p->ip_set_pending;
 	} else {
 		lock_get(&p->read_lock);
 		if (!p->ip_set) {
 			ip_set_init(&ip_set2, 1); /* dummy to return empty ip set */
 			ip_set = &ip_set2;
 		}
 		else
 			ip_set = &p->ip_set->ip_set;
 	}
 
 	/* nested array/struct not supported */
 	rpc->add(ctx, "{", &c);
 	if (rpc->struct_add(c, "s", "IPv", "4") < 0) 
 		goto err;	
 	if (rpc_ip_tree_print(rpc, c, "", ip_set->ipv4_tree, 0) < 0) 
 		goto err;
 	rpc->add(ctx, "{", &c);
 	if (rpc->struct_add(c, "s", "IPv", "6") < 0) 
 		goto err;	
 	if (rpc_ip_tree_print(rpc, c, "", ip_set->ipv6_tree, 0) < 0) 
 		goto err;
 
 err:		
 	if (pending)
 		lock_release(&p->write_lock);
 	else
 		lock_release(&p->read_lock);
 
 }