瀏覽代碼

modules/registrar_pcscf: firs commit of registrar_pcscf module
- registrar for P-CSCF functionality

Jason Penton 12 年之前
父節點
當前提交
bd26883f8c

+ 20 - 0
modules/registrar_pcscf/Makefile

@@ -0,0 +1,20 @@
+# $Id$
+#
+# registrar module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=registrar_pcscf.so
+LIBS=
+
+DEFS+=-DOPENSER_MOD_INTERFACE -I/usr/include/libxml2 -I$(LOCALBASE)/include/libxml2
+
+LIBS += -L$(LOCALBASE)/lib -lrt
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/ims/kamailio_ims
+include ../../Makefile.modules

+ 168 - 0
modules/registrar_pcscf/async_reginfo.c

@@ -0,0 +1,168 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */
+
+#include <time.h>
+#include "async_reginfo.h"
+
+reginfo_event_list_t *reginfo_event_list = 0;
+
+int init_reginfo_event_list()
+{
+	reginfo_event_list = shm_malloc(sizeof(reginfo_event_list_t));
+	if (!reginfo_event_list) {
+		LM_ERR("No more SHM mem\n");
+		return 0;
+	}
+	memset(reginfo_event_list, 0, sizeof(reginfo_event_list_t));
+	reginfo_event_list->lock = lock_alloc();
+	if (!reginfo_event_list->lock) {
+		LM_ERR("failed to create reginfo event list lock\n");
+		return 0;
+	}
+	reginfo_event_list->lock = lock_init(reginfo_event_list->lock);
+
+	sem_new(reginfo_event_list->empty, 0); //pre-locked - as we assume list is empty at start
+
+	return 1;
+}
+void destroy_reginfo_event_list()
+{
+	reginfo_event_t *ev, *tmp;
+
+	lock_get(reginfo_event_list->lock);
+	ev = reginfo_event_list->head;
+	while (ev) {
+		tmp = ev->next;
+		free_reginfo_event(ev);
+		ev = tmp;
+	}
+	lock_destroy(reginfo_event_list->lock);
+	lock_dealloc(reginfo_event_list->lock);
+	shm_free(reginfo_event_list);
+}
+
+reginfo_event_t* new_reginfo_event (int event)
+{
+	reginfo_event_t *new_event = shm_malloc(sizeof(reginfo_event_t));
+	if (!new_event) {
+		LM_ERR("No more shm mem\n");
+		return NULL;
+	}
+	new_event->registered = time(NULL);
+	new_event->event = event;
+	new_event->next = 0;
+
+	return new_event;
+}
+
+void push_reginfo_event(reginfo_event_t* event)
+{
+	lock_get(reginfo_event_list->lock);
+	if (reginfo_event_list->head == 0) { //empty list
+		reginfo_event_list->head = reginfo_event_list->tail = event;
+	} else {
+		reginfo_event_list->tail->next = event;
+		reginfo_event_list->tail = event;
+	}
+	sem_release(reginfo_event_list->empty);
+	lock_release(reginfo_event_list->lock);
+}
+
+reginfo_event_t* pop_reginfo_event()
+{
+	reginfo_event_t *ev;
+
+	lock_get(reginfo_event_list->lock);
+	while (reginfo_event_list->head == 0) {
+		lock_release(reginfo_event_list->lock);
+		sem_get(reginfo_event_list->empty);
+		lock_get(reginfo_event_list->lock);
+	}
+
+	ev = reginfo_event_list->head;
+	reginfo_event_list->head = ev->next;
+
+	if (ev == reginfo_event_list->tail) { //list now empty
+		reginfo_event_list->tail = 0;
+	}
+	ev->next = 0; //make sure whoever gets this cant access our list
+	lock_release(reginfo_event_list->lock);
+
+	return ev;
+}
+
+void free_reginfo_event(reginfo_event_t* ev)
+{
+	if (ev) {
+		LM_DBG("Freeing reginfo event structure\n");
+		shm_free(ev);
+	}
+}
+
+void reginfo_event_process()
+{
+	reginfo_event_t *ev;
+	for (;;) {
+			LM_DBG("POPPING REGINFO EVENT\n");
+	        ev = pop_reginfo_event();
+	        LM_DBG("PROCESSING REGINFO EVENT with event [%d]\n", ev->event);
+
+	        switch (ev->event) {
+	        case REG_EVENT_PUBLISH:
+	        	LM_DBG("Sending out-of-band publish\n");
+	        	break;
+	        case REG_EVENT_SUBSCRIBE:
+	        	LM_DBG("Sending out-of-band subscribe\n");
+	        	break;
+	        default:
+	        	LM_ERR("Unknown REG event.....ignoring\n");
+	        	break;
+	        }
+	        free_reginfo_event(ev);
+	}
+}
+
+
+

+ 81 - 0
modules/registrar_pcscf/async_reginfo.h

@@ -0,0 +1,81 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */
+
+#ifndef ASYNC_REGINFO_H_
+#define ASYNC_REGINFO_H_
+
+#include "../../locking.h"
+#include "sem.h"
+
+#define REG_EVENT_UNKNOWN -1
+#define REG_EVENT_SUBSCRIBE 0
+#define REG_EVENT_PUBLISH 1
+
+typedef struct _reginfo_event{
+	int event;							/* event id */
+	time_t registered;					/* time event was added to list - useful if we want to report on things that have taken too long to process */
+	struct _reginfo_event *next;
+} reginfo_event_t;
+
+typedef struct {
+	gen_lock_t *lock;
+	reginfo_event_t *head;
+	reginfo_event_t *tail;
+	gen_sem_t *empty;
+} reginfo_event_list_t;
+
+
+int init_reginfo_event_list();
+void destroy_reginfo_event_list();
+
+reginfo_event_t* new_reginfo_event (int event); 			/*create new event*/
+void push_reginfo_event(reginfo_event_t* event);	/*add event to stack*/
+reginfo_event_t* pop_reginfo_event();				/*pop next (head) event off list*/
+void free_reginfo_event(reginfo_event_t*);			/*free memory allocated for event*/
+
+void reginfo_event_process();
+
+
+#endif /* ASYNC_REGINFO_H_ */

+ 44 - 0
modules/registrar_pcscf/blurb

@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */

+ 405 - 0
modules/registrar_pcscf/reg_mod.c

@@ -0,0 +1,405 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */
+
+
+#include <stdio.h>
+#include "../../data_lump.h"
+#include "../../ip_addr.h"
+#include "../../ut.h"
+#include "../../sr_module.h"
+#include "../../timer.h"
+#include "../../dprint.h"
+#include "../../error.h"
+#include "../../socket_info.h"
+#include "../../pvar.h"
+#include "../usrloc_pcscf/usrloc.h"
+#include "../../lib/kcore/statistics.h"
+#include "../../modules/sl/sl.h"
+#include "../../mod_fix.h"
+
+/* Bindings to PUA */
+//#include "../../modules_k/pua/pua_bind.h"
+
+#include "reg_mod.h"
+#include "save.h"
+#include "service_routes.h"
+
+MODULE_VERSION
+
+usrloc_api_t ul;						/**!< Structure containing pointers to usrloc functions*/
+sl_api_t slb;							/**!< SL API structure */
+struct tm_binds tmb;					/**!< TM API structure */
+//pua_api_t pua; 							/**!< PUA API structure */
+
+
+time_t time_now;
+char * pcscf_uri = "sip:pcscf.ims.smilecoms.com:4060";
+str pcscf_uri_str;
+unsigned int pending_reg_expires = 30;			/**!< parameter for expiry time of a pending registration before receiving confirmation from SCSCF */
+
+char* rcv_avp_param = 0;
+unsigned short rcv_avp_type = 0;
+int_str rcv_avp_name;
+
+// static str orig_prefix = {"sip:orig@",9};
+
+/*! \brief Module init & destroy function */
+static int  mod_init(void);
+static int  child_init(int);
+static void mod_destroy(void);
+static int w_save(struct sip_msg* _m, char* _d, char* _cflags);
+static int w_save_pending(struct sip_msg* _m, char* _d, char* _cflags);
+
+static int w_follows_service_routes(struct sip_msg* _m, char* _d, char* _foo);
+static int w_force_service_routes(struct sip_msg* _m, char* _d, char* _foo);
+static int w_is_registered(struct sip_msg* _m, char* _d, char* _foo);
+
+static int w_assert_identity(struct sip_msg* _m, char* _d, char* _preferred_uri);
+
+/*! \brief Fixup functions */
+static int domain_fixup(void** param, int param_no);
+static int save_fixup2(void** param, int param_no);
+static int assert_identity_fixup(void ** param, int param_no);
+
+/* Pseudo-Variables */
+static int pv_get_asserted_identity_f(struct sip_msg *, pv_param_t *, pv_value_t *);
+
+/**
+ * Update the time.
+ */
+inline void pcscf_act_time()
+{
+        time_now=time(0);
+}
+
+/*! \brief
+ * Exported functions
+ */
+static cmd_export_t cmds[] = {
+	{"pcscf_save",     		(cmd_function)w_save,       	1,  	save_fixup2, 	0,		ONREPLY_ROUTE },
+	{"pcscf_save_pending",	(cmd_function)w_save_pending,       	1,  	save_fixup2, 	0,		REQUEST_ROUTE },
+
+	{"pcscf_follows_service_routes", (cmd_function)w_follows_service_routes,       	1,  	save_fixup2, 	0,		REQUEST_ROUTE },
+	{"pcscf_force_service_routes", (cmd_function)w_force_service_routes,       	1,  	save_fixup2, 	0,		REQUEST_ROUTE },
+
+	{"pcscf_is_registered", (cmd_function)w_is_registered,       	1,  	save_fixup2, 	0,		REQUEST_ROUTE },
+
+	{"pcscf_assert_identity", (cmd_function)w_assert_identity,      2,  	assert_identity_fixup, 	0,		REQUEST_ROUTE },
+
+	{0, 0, 0, 0, 0, 0}
+};
+
+
+/*! \brief
+ * Exported parameters
+ */
+static param_export_t params[] = {
+	{"pcscf_uri",         	STR_PARAM, &pcscf_uri    						},
+	{"pending_reg_expires",	INT_PARAM, &pending_reg_expires					},
+
+	{"received_avp",       STR_PARAM, &rcv_avp_param       					},
+
+
+//	{"ims_mode",           INT_PARAM, &registrar_ims_mode                  	}, /* 0-PCSCF ; 1-SCSCF */
+//	{"subscription_max_expires",INT_PARAM, &subscription_max_expires       	},
+//	{"subscription_min_expires",INT_PARAM, &subscription_min_expires       	},
+//	{"store_profile_dereg",	INT_PARAM, &store_data_on_dereg},
+	{0, 0, 0}
+};
+
+
+/*! \brief We expose internal variables via the statistic framework below.*/
+stat_export_t mod_stats[] = {
+	{0, 0, 0}
+};
+
+
+static pv_export_t mod_pvs[] = {
+    {{"pcscf_asserted_identity", (sizeof("pcscf_asserted_identity")-1)}, /* The first identity of the contact. */
+     PVT_OTHER, pv_get_asserted_identity_f, 0, 0, 0, 0, 0},
+    {{0, 0}, 0, 0, 0, 0, 0, 0, 0}
+};
+
+/*! \brief
+ * Module exports structure
+ */
+struct module_exports exports = {
+	"registrar_pcscf",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,        	/* Exported functions */
+	params,      	/* Exported parameters */
+	mod_stats,   	/* exported statistics */
+	0,           	/* exported MI functions */
+	mod_pvs,     	/* exported pseudo-variables */
+	0,           	/* extra processes */
+	mod_init,    	/* module initialization function */
+	0,
+	mod_destroy, 	/* destroy function */
+	child_init,  	/* Per-child init function */
+};
+
+int fix_parameters() {
+	str s;
+	pv_spec_t avp_spec;
+
+	pcscf_uri_str.s = pcscf_uri;
+	pcscf_uri_str.len = strlen(pcscf_uri);
+
+	if (rcv_avp_param && *rcv_avp_param) {
+		s.s = rcv_avp_param; s.len = strlen(s.s);
+		if (pv_parse_spec(&s, &avp_spec)==0
+				|| avp_spec.type!=PVT_AVP) {
+			LM_ERR("malformed or non AVP %s AVP definition\n", rcv_avp_param);
+			return -1;
+		}
+
+		if(pv_get_avp_name(0, &avp_spec.pvp, &rcv_avp_name, &rcv_avp_type)!=0)
+		{
+			LM_ERR("[%s]- invalid AVP definition\n", rcv_avp_param);
+			return -1;
+		}
+	} else {
+		rcv_avp_name.n = 0;
+		rcv_avp_type = 0;
+	}
+
+	return 1;
+}
+
+/*! \brief
+ * Initialize parent
+ */
+static int mod_init(void) {
+	bind_usrloc_t bind_usrloc;
+//	bind_pua_t bind_pua;
+
+	if (!fix_parameters()) goto error;
+
+	/* bind the SL API */
+	if (sl_load_api(&slb) != 0) {
+		LM_ERR("cannot bind to SL API\n");
+		return -1;
+	}
+	LM_DBG("Successfully bound to SL module\n");
+
+	/* load the TM API */
+	if (load_tm_api(&tmb) != 0) {
+		LM_ERR("can't load TM API\n");
+		return -1;
+	}
+	LM_DBG("Successfully bound to TM module\n");
+
+	bind_usrloc = (bind_usrloc_t) find_export("ul_bind_usrloc_pcscf", 1, 0);
+	if (!bind_usrloc) {
+		LM_ERR("can't bind usrloc_pcscf\n");
+		return -1;
+	}
+
+	if (bind_usrloc(&ul) < 0) {
+		return -1;
+	}
+	LM_DBG("Successfully bound to PCSCF Usrloc module\n");
+
+	/* Bind to PUA: */
+//	bind_pua = (bind_pua_t) find_export("bind_pua", 1, 0);
+//	if (!bind_pua) {
+//		LM_ERR("Can't bind pua\n");
+//		return -1;
+//	}
+//	if (bind_pua(&pua) < 0) {
+//		LM_ERR("Can't bind pua\n");
+//		return -1;
+//	}
+//	/* Check for Publish/Subscribe methods */
+//	if (pua.send_publish == NULL) {
+//		LM_ERR("Could not import send_publish\n");
+//		return -1;
+//	}
+//	if (pua.send_subscribe == NULL) {
+//		LM_ERR("Could not import send_subscribe\n");
+//		return -1;
+//	}
+//	LM_DBG("Successfully bound to PUA module\n");
+
+	return 0;
+
+error:
+	return -1;
+}
+
+static void mod_destroy(void)
+{
+
+}
+
+static int child_init(int rank)
+{
+	if (rank == PROC_MAIN || rank == PROC_TCP_MAIN)
+		return 0;
+	if (rank == 1) {
+		/* init stats */
+		//TODO if parameters are modified via cfg framework do i change them?
+		//update_stat( max_expires_stat, default_registrar_cfg.max_expires ); update_stat( max_contacts_stat, default_registrar_cfg.max_contacts ); update_stat( default_expire_stat, default_registrar_cfg.default_expires );
+	}
+
+	/* don't do anything for main process and TCP manager process */
+	if (rank == PROC_MAIN || rank == PROC_TCP_MAIN)
+		return 0;
+
+	return 0;
+}
+
+/* fixups */
+static int domain_fixup(void** param, int param_no)
+{
+	udomain_t* d;
+
+	if (param_no == 1) {
+		if (ul.register_udomain((char*)*param, &d) < 0) {
+			LM_ERR("failed to register domain\n");
+			return E_UNSPEC;
+		}
+		*param = (void*)d;
+	}
+	return 0;
+}
+
+/*! \brief
+ * Fixup for "save" function - both domain and flags
+ */
+static int save_fixup2(void** param, int param_no)
+{
+	if (param_no == 1) {
+		return domain_fixup(param,param_no);
+	}
+        return 0;
+}
+
+/*! \brief
+ * Fixup for "assert_identity" function - both domain and URI to be asserted
+ */
+static int assert_identity_fixup(void ** param, int param_no) {
+	if (param_no == 1) {
+		return domain_fixup(param,param_no);
+	}
+	if (param_no == 2) {
+		pv_elem_t *model=NULL;
+		str s;
+
+		/* convert to str */
+		s.s = (char*)*param;
+		s.len = strlen(s.s);
+
+		model = NULL;
+		if(s.len==0) {
+			LM_ERR("no param!\n");
+			return E_CFG;
+		}
+		if(pv_parse_format(&s, &model)<0 || model==NULL) {
+			LM_ERR("wrong format [%s]!\n", s.s);
+			return E_CFG;
+		}
+		*param = (void*)model;
+		return 0;
+	}
+	return E_CFG;
+}
+
+/*! \brief
+ * Wrapper to save(location)
+ */
+static int w_save(struct sip_msg* _m, char* _d, char* _cflags)
+{
+	return save(_m, (udomain_t*)_d, ((int)(unsigned long)_cflags));
+}
+
+static int w_save_pending(struct sip_msg* _m, char* _d, char* _cflags)
+{
+	return save_pending(_m, (udomain_t*)_d);
+}
+
+static int w_follows_service_routes(struct sip_msg* _m, char* _d, char* _foo)
+{
+	return check_service_routes(_m, (udomain_t*)_d);
+}
+
+static int w_force_service_routes(struct sip_msg* _m, char* _d, char* _foo)
+{
+	return force_service_routes(_m, (udomain_t*)_d);
+}
+
+static int w_is_registered(struct sip_msg* _m, char* _d, char* _foo)
+{
+	return is_registered(_m, (udomain_t*)_d);
+}
+
+static int w_assert_identity(struct sip_msg* _m, char* _d, char* _preferred_uri) {
+	pv_elem_t *model;
+	str identity;
+
+	if(_preferred_uri == NULL) {
+		LM_ERR("error - bad parameters\n");
+		return -1;
+	}
+
+	model = (pv_elem_t*)_preferred_uri;
+	if (pv_printf_s(_m, model, &identity)<0) {
+		LM_ERR("error - cannot print the format\n");
+		return -1;
+	}
+
+	return assert_identity( _m, (udomain_t*)_d, identity);
+}
+
+/*
+ * Returns the current RTP-Statistics from the RTP-Proxy
+ */
+static int
+pv_get_asserted_identity_f(struct sip_msg *msg, pv_param_t *param,
+		  pv_value_t *res)
+{
+    str * ret_val = get_asserted_identity(msg);
+    return pv_get_strval(msg, param, res, ret_val);
+}

+ 63 - 0
modules/registrar_pcscf/reg_mod.h

@@ -0,0 +1,63 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */
+
+#ifndef REG_MOD_H
+#define REG_MOD_H
+
+#include "../../parser/msg_parser.h"
+#include "../../qvalue.h"
+#include "../../usr_avp.h"
+#include "../usrloc_pcscf/usrloc.h"
+#include "../../modules/sl/sl.h"
+#include "../../modules/tm/tm_load.h"
+
+#define RECEIVED_MAX_SIZE      255
+
+extern unsigned short rcv_avp_type;
+extern int_str rcv_avp_name;
+
+#endif /* REG_MOD_H */
+
+void pcscf_act_time();

+ 354 - 0
modules/registrar_pcscf/save.c

@@ -0,0 +1,354 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */
+
+#include "../../parser/contact/contact.h"
+#include "save.h"
+#include "reg_mod.h"
+#include "ul_callback.h"
+
+extern struct tm_binds tmb;
+extern usrloc_api_t ul;
+extern time_t time_now;
+extern unsigned int pending_reg_expires;
+
+struct sip_msg* get_request_from_reply(struct sip_msg* reply)
+{
+    struct cell *t;
+	t = tmb.t_gett();
+	if (!t || t == (void*) -1) {
+		LM_ERR("Reply without transaction\n");
+		return 0;
+	}
+	if (t)
+		return t->uas.request;
+	else
+		return 0;
+
+}
+
+/**
+ * Calculates the expiration time for one contact.
+ * Tries to use the Expiration header, if not present then use the
+ * expires parameter of the contact, if param not present it defaults
+ * to the default value.
+ * Also checks
+ * @param c - the contact to calculate for
+ * @param expires_hdr - value of expires hdr if present, if not -1
+ * @param local_time_now - the local time
+ * @returns the time of expiration
+ */
+static inline int calc_contact_expires(contact_t *c,int expires_hdr, int local_time_now)
+{
+    unsigned int r = 0;
+	if (expires_hdr >= 0)
+		r = expires_hdr;
+
+	if (c && c->expires && c->expires->body.len) {
+		str2int(&(c->expires->body), (unsigned int*) &r);
+	}
+	return local_time_now + r;
+}
+
+
+/**
+ * Updates the registrar with the new values
+ * @param req - the REGISTER request - to extract NAT info
+ * @param rpl - the REGISTER reply - to extract contact info
+ * @param is_star - whether this was a STAR contact header
+ * @param expires_hdr - value of the Expires header
+ * @param public_id - array of public identities attached to this contact
+ * @param public_id_cnt - size of the public_id array
+ * @param service_route - array of Service-Routes
+ * @param service_route_cnt - size of the service_route array
+ * @param requires_nat - if to create pinholes
+ * @returns the maximum expiration time, -1 on error
+ */
+static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udomain_t* _d, unsigned char is_star,int expires_hdr,
+        str *public_id,int public_id_cnt,str *service_route,int service_route_cnt, int requires_nat)
+{
+	int local_time_now, expires=0;
+	struct hdr_field* h;
+	contact_t* c;
+	struct sip_uri puri;
+	struct sip_uri parsed_received;
+	struct pcontact_info ci;
+	pcontact_t* pcontact;
+	char srcip[50];
+	int_str val;
+
+	pcscf_act_time();
+	local_time_now = time_now;
+	if (is_star) {
+		/* first of all, we shouldn't get here...
+		 * then, we will update on NOTIFY */
+		return 0;
+	}
+	for (h = rpl->contact; h; h = h->next) {
+		if (h->type == HDR_CONTACT_T && h->parsed)
+			for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) {
+				expires = calc_contact_expires(c, expires_hdr, local_time_now);
+				if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) {
+					LM_DBG("Error parsing Contact URI <%.*s>\n", c->uri.len, c->uri.s);
+					continue;
+				}
+				//build contact info
+				ci.expires = expires;
+				ci.public_ids = public_id;
+				ci.num_public_ids = public_id_cnt;
+				ci.service_routes = service_route;
+				ci.num_service_routes = service_route_cnt;
+				ci.reg_state = PCONTACT_REGISTERED;
+
+				// Received Info: First try AVP, otherwise simply take the source of the request:
+				memset(&val, 0, sizeof(int_str));
+				if (rcv_avp_name.n!=0 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0) && val.s.len > 0) {
+					if (val.s.len>RECEIVED_MAX_SIZE) {
+						LM_ERR("received too long\n");
+						goto error;
+					}
+					if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) {
+						LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s);
+						continue;
+					}
+					ci.received_host = parsed_received.host;
+					ci.received_port = parsed_received.port_no;
+					ci.received_proto = parsed_received.proto;
+				} else {
+					ci.received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, sizeof(srcip));
+					ci.received_host.s = srcip;
+					ci.received_port = req->rcv.src_port;
+					ci.received_proto = req->rcv.proto;
+				}
+				// Set to default, if not set:
+				if (ci.received_port == 0) ci.received_port = 5060;
+
+				ul.lock_udomain(_d, &c->uri);
+				if (ul.get_pcontact(_d, &c->uri, &pcontact) != 0) { //need to insert new contact
+					LM_DBG("Adding pcontact: <%.*s>, expires: %d which is in %d seconds\n", c->uri.len, c->uri.s, expires, expires-local_time_now);
+					if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {
+						LM_ERR("Failed inserting new pcontact\n");
+					} else {
+						//register for callbacks on this contact so we can send PUBLISH to SCSCF should status change
+						LM_DBG("registering for UL callback\n");
+						ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL);
+						//we also need to subscribe to reg event of this contact at SCSCF
+					}
+				} else { //contact already exists - update
+					LM_DBG("contact already exists and is in state (%d) : [%s]\n",pcontact->reg_state, reg_state_to_string(pcontact->reg_state));
+					if ((expires-local_time_now)<=0) { //remove contact - de-register
+						LM_DBG("This is a de-registration for contact <%.*s>\n", c->uri.len, c->uri.s);
+						if (ul.delete_pcontact(_d, &c->uri, pcontact) != 0) {
+							LM_ERR("failed to delete pcscf contact <%.*s>\n", c->uri.len, c->uri.s);
+						}
+					} else { //update contact
+						LM_DBG("Updating contact: <%.*s>, old expires: %li, new expires: %i which is in %i seconds\n", c->uri.len, c->uri.s,
+								pcontact->expires-local_time_now,
+								expires,
+								expires-local_time_now);
+						if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
+							LM_ERR("failed to update pcscf contact\n");
+						}
+						pcontact->expires = expires;
+					}
+				}
+				ul.unlock_udomain(_d, &c->uri);
+			}
+	}
+	return 1;
+error:
+	return 0;
+}
+
+/**
+ * Save contact based on REGISTER request. this will be a pending save, until we receive response
+ * from SCSCF. If no response after pending_timeout seconds, the contacts is removed
+ */
+int save_pending(struct sip_msg* _m, udomain_t* _d) {
+	contact_body_t* cb = 0;
+	int cexpires = 0;
+	pcontact_t* pcontact;
+	contact_t* c;
+	struct pcontact_info ci;
+	int_str val;
+	struct sip_uri parsed_received;
+	char srcip[50];
+
+	memset(&ci, 0, sizeof(struct pcontact_info));
+
+	cb = cscf_parse_contacts(_m);
+	if (!cb || (!cb->contacts)) {
+		LM_ERR("No contact headers\n");
+		goto error;
+	}
+	c = cb->contacts;
+	if (!c) {
+		LM_ERR("no valid contact to register\n");
+		goto error;
+	}
+	//TODO: need support for multiple contacts - currently assume one contact
+	//make sure this is not a de-registration
+	int expires_hdr = cscf_get_expires_hdr(_m, 0);
+	if (expires_hdr < 0) {
+		//no global header we have to check the contact expiry
+		if (c && c->expires && c->expires->body.len) {
+				str2int(&(c->expires->body), (unsigned int*) &cexpires);
+		}
+		if (!cexpires){ //assume de-registration
+			LM_DBG("not doing pending reg on de-registration\n");
+			return 1;
+		}
+	}
+	pcscf_act_time();
+	int local_time_now = time_now;
+	int expires = calc_contact_expires(c, expires_hdr, local_time_now);
+	if (expires <= 0) {
+		LM_DBG("not doing pending reg on de-registration\n");
+		return 1;
+	}
+	LM_DBG("contact requesting to expire in %d seconds\n", expires-local_time_now);
+
+	/*populate CI with bare minimum*/
+	ci.num_public_ids=0;
+	ci.num_service_routes=0;
+	ci.expires=local_time_now + pending_reg_expires;
+	ci.reg_state=PCONTACT_REG_PENDING;
+
+	// Received Info: First try AVP, otherwise simply take the source of the request:
+	memset(&val, 0, sizeof(int_str));
+	if (rcv_avp_name.n != 0
+			&& search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0)
+			&& val.s.len > 0) {
+		if (val.s.len > RECEIVED_MAX_SIZE) {
+			LM_ERR("received too long\n");
+			goto error;
+		}
+		if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) {
+			LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s);
+			goto error;
+		}
+		ci.received_host = parsed_received.host;
+		ci.received_port = parsed_received.port_no;
+		ci.received_proto = parsed_received.proto;
+	} else {
+		ci.received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip,
+				sizeof(srcip));
+		ci.received_host.s = srcip;
+		ci.received_port = _m->rcv.src_port;
+		ci.received_proto = _m->rcv.proto;
+	}
+	// Set to default, if not set:
+	if (ci.received_port == 0)
+		ci.received_port = 5060;
+
+	ul.lock_udomain(_d, &c->uri);
+	if (ul.get_pcontact(_d, &c->uri, &pcontact) != 0) { //need to insert new contact
+		LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s);
+		if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {
+			LM_ERR("Failed inserting new pcontact\n");
+		} else {
+			LM_DBG("registering for UL callback\n");
+			ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE | PCSCF_CONTACT_UPDATE, callback_pcscf_contact_cb, NULL);
+		}
+	} else { //contact already exists - update
+		LM_DBG("Contact already exists - not doing anything for now\n");
+	}
+	ul.unlock_udomain(_d, &c->uri);
+
+	return 1;
+
+error:
+	LM_DBG("Error saving pending contact\n");
+	return -1;
+}
+
+/**
+ * Save the contacts and their associated public ids.
+ * @param rpl - the SIP Register 200 OK response that contains the Expire and Contact and P-associated-uri headers
+ * @param _d - domain
+ * @param _cflags - flags
+ * @returns #CSCF_RETURN_TRUE if OK, #CSCF_RETURN_ERROR on error
+ */
+int save(struct sip_msg* _m, udomain_t* _d, int _cflags) {
+	struct sip_msg* req;
+	int expires_hdr = 0;
+	contact_body_t* cb = 0;
+	str *public_ids=0;
+	int num_public_ids = 0;
+	str *service_routes=0;
+	int num_service_routes = 0;
+
+	//get request from reply
+	req = get_request_from_reply(_m);
+	if (!req) {
+		LM_ERR("Unable to get request from reply for REGISTER. No transaction\n");
+		goto error;
+	}
+	expires_hdr = cscf_get_expires_hdr(_m, 0);
+	cb = cscf_parse_contacts(_m);
+	if (!cb || (!cb->contacts && !cb->star)) {
+		LM_ERR("No contact headers and not *\n");
+		goto error;
+	}
+	cscf_get_p_associated_uri(_m, &public_ids, &num_public_ids, 1);
+	service_routes = cscf_get_service_route(_m, &num_service_routes, 1);
+
+	//update contacts
+	if (!update_contacts(req, _m, _d, cb->star, expires_hdr, public_ids, num_public_ids, service_routes, num_service_routes, 0)) {
+		LM_ERR("failed to update pcontact\n");
+		goto error;
+	}
+
+	//TODO: we need to subscribe to SCSCF for reg events on the impu!
+
+	if (public_ids && public_ids->s) pkg_free(public_ids);
+	if (service_routes && service_routes->s) pkg_free(service_routes);
+	return 1;
+
+error:
+	if (public_ids && public_ids->s) pkg_free(public_ids);
+	if (service_routes && service_routes->s) pkg_free(service_routes);
+	return -1;
+
+}

+ 61 - 0
modules/registrar_pcscf/save.h

@@ -0,0 +1,61 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */
+
+#ifndef SAVE_H
+#define SAVE_H
+
+#include "../../parser/msg_parser.h"
+#include "../../modules/usrloc_pcscf/usrloc.h"
+#include "../../lib/ims/ims_getters.h"
+
+/*! \brief
+ * Process REGISTER request and save it's contacts
+ */
+int save(struct sip_msg* _m, udomain_t* _d, int _cflags);
+int save_pending(struct sip_msg* _m, udomain_t* _d);
+int unregister(struct sip_msg* _m, char* _d, char* _uri);
+
+
+#endif /* SAVE_H */

+ 85 - 0
modules/registrar_pcscf/sem.h

@@ -0,0 +1,85 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */
+
+#ifndef __SEM_H
+#define __SEM_H
+
+	#include <semaphore.h>
+
+	typedef sem_t gen_sem_t;
+
+	/**
+	 * Create a new unnamed semaphore and initialize it
+	 * @param value - 0 if it should be pre-locked, 1 if not, or how many locks until block
+	 * @return
+	 */
+    #define sem_new(sem_ptr,value)\
+	do {\
+		sem_ptr=shm_malloc(sizeof(gen_sem_t));\
+		if (!sem_ptr){\
+			LM_ERR("Error allocating %lx bytes of shm!\n",sizeof(gen_sem_t));\
+		}	\
+		if (sem_init(sem_ptr, 1, value)<0) {\
+			LM_ERR("Error > %s\n",strerror(errno));\
+		}\
+	} while(0)
+	
+    #define sem_free(sem)\
+	do {\
+		if (sem) {\
+			sem_destroy(sem);\
+			shm_free(sem);\
+			sem=0;\
+		}\
+	} while(0)
+	
+	
+	#define sem_get(sem) sem_wait(sem)
+	#define sem_tryget(sem) sem_trywait(sem)
+	#define sem_timedget(sem,abs_timeout) sem_trywait(sem,abs_timeout)
+	
+	#define sem_release(sem) sem_post(sem)
+
+#endif

+ 429 - 0
modules/registrar_pcscf/service_routes.c

@@ -0,0 +1,429 @@
+/** 
+ * Functions to force or check the service-routes
+ *
+ * Copyright (c) 2012 Carsten Bock, ng-voice GmbH
+ *
+ * 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
+ */
+
+#include "service_routes.h"
+#include "reg_mod.h"
+#include "../../data_lump.h"
+#include "../../lib/ims/ims_getters.h"
+
+#define STR_APPEND(dst,src)\
+        {memcpy((dst).s+(dst).len,(src).s,(src).len);\
+        (dst).len = (dst).len + (src).len;}
+
+// ID of current message
+static unsigned int current_msg_id = 0;
+// Pointer to current contact_t
+static pcontact_t * c = NULL;
+
+extern usrloc_api_t ul;
+
+static str * asserted_identity;
+
+/*!
+ * \brief Parse the message and find first occurrence of Route header field.
+ * \param _m SIP message 
+ * \return -1 or -2 on a parser error, 0 if there is a Route HF and 1 if there is no Route HF
+ */
+static inline int find_first_route(struct sip_msg* _m)
+{
+	if (parse_headers(_m, HDR_ROUTE_F, 0) == -1) {
+		LM_ERR("failed to parse headers\n");
+		return -1;
+	} else {
+		if (_m->route) {
+			if (parse_rr(_m->route) < 0) {
+				LM_ERR("failed to parse Route HF\n");
+				return -2;
+			}
+			return 0;
+		} else {
+			LM_DBG("No Route headers found\n");
+			return 1;
+		}
+	}
+}
+
+/*!
+ * \brief Find and parse next Route header field
+ * \param _m SIP message
+ * \param _hdr SIP header
+ * \return negative on failure, 0 if the Route header was already parsed, 1 if no next
+ * Route header could be found
+ */
+static inline int find_next_route(struct sip_msg* _m, struct hdr_field** _hdr)
+{
+	struct hdr_field* ptr;
+
+	ptr = (*_hdr)->next;
+
+	/* Try to find already parsed Route headers */
+	while(ptr) {
+		if (ptr->type == HDR_ROUTE_T) goto found;
+		ptr = ptr->next;
+	}
+
+	/* There are no already parsed Route headers, try to find next
+	 * occurrence of Route header
+	 */
+	if (parse_headers(_m, HDR_ROUTE_F, 1) == -1) {
+		LM_ERR("failed to parse headers\n");
+		return -1;
+	}
+
+	if ((_m->last_header->type!=HDR_ROUTE_T) || (_m->last_header==*_hdr)) {
+		LM_DBG("No next Route HF found\n");
+		return 1;
+	}
+
+	ptr = _m->last_header;
+
+ found:
+	if (parse_rr(ptr) < 0) {
+		LM_ERR("failed to parse Route body\n");
+		return -2;
+	}
+
+	*_hdr = ptr;
+	return 0;
+}
+
+/**
+ * get PContact-Structure for message
+ * (search only once per Request)
+ */
+pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d) {
+	ppublic_t * p;
+	str received_host = {0, 0};
+	char srcip[50];	
+
+	if (_m->id != current_msg_id) {
+		current_msg_id = _m->id;
+		c = NULL;
+		received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
+		received_host.s = srcip;
+		if (ul.get_pcontact_by_src(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &c) == 1)
+			LM_WARN("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto);
+	}
+	asserted_identity = NULL;
+	if (c) {
+		p = c->head;
+		while (p) {
+			if (p->is_default == 1)
+				asserted_identity = &p->public_identity;
+			p = p->next;
+		}
+	}
+
+	return c;
+}
+
+pcontact_t * getContactP_from_via(struct sip_msg* _m, udomain_t* _d) {
+	ppublic_t * p;
+	struct via_body *vb;
+
+	vb = cscf_get_ue_via(_m);
+	if (!vb) {
+		LM_WARN("no via header.....strange!\n");
+		return NULL;
+	}
+
+	if (vb->port == 0)
+		vb->port = 5060;
+
+	if (_m->id != current_msg_id) {
+		current_msg_id = _m->id;
+		c = NULL;
+		LM_DBG("Looking for <%d://%.*s:%d>\n", vb->proto, vb->host.len, vb->host.s, vb->port);
+		if (ul.get_pcontact_by_src(_d, &vb->host, vb->port, vb->proto, &c) == 1)
+			LM_WARN("No entry in usrloc for %.*s:%i (Proto %i) found!\n", vb->host.len, vb->host.s, vb->port, vb->proto);
+	}
+
+	asserted_identity = NULL;
+	if (c) {
+		p = c->head;
+		while (p) {
+			if (p->is_default == 1)
+				asserted_identity = &p->public_identity;
+			p = p->next;
+		}
+	}
+
+	return c;
+}
+
+/**
+ * Check, if a user-agent follows the indicated service-routes
+ */
+int check_service_routes(struct sip_msg* _m, udomain_t* _d) {
+	struct sip_uri uri;
+	int i;
+	struct hdr_field *hdr;
+	rr_t *r;
+	pcontact_t * c = getContactP(_m, _d);
+	/* Contact not found => not following service-routes */
+	if (c == NULL) return -1;
+
+	/* Search for the first Route-Header: */
+	if (find_first_route(_m) < 0) return -1;
+
+	LM_DBG("Got %i Route-Headers.\n", c->num_service_routes);
+
+	/* Lock this record while working with the data: */
+	ul.lock_udomain(_d, &c->aor);
+
+	/* Check the route-set: */
+	if (_m->route) {
+		hdr = _m->route;
+		LM_DBG("hdr is %p\n", hdr);
+		/* Check, if the first host is ourself: */
+		r = (rr_t*)hdr->parsed;
+		if (r) {
+			LM_DBG("Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s);
+			/* Skip first headers containing myself: */
+			while (parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &uri) == 0
+			  && check_self(&uri.host,uri.port_no?uri.port_no:SIP_PORT,0)) {
+				LM_DBG("Self\n");
+				/* Check for more headers and fail, if it was the last one
+				   Check, if service-routes are indicated.
+				   If yes, request is not following service-routes */
+				if (find_next_route(_m, &hdr) != 0) r = NULL;
+				else r = (rr_t*)hdr->parsed;
+
+				if (!r && (c->num_service_routes > 0)) {
+					LM_DBG("Not enough route-headers in Message\n");
+					goto error;
+				}
+				LM_DBG("hdr is %p\n", hdr);
+				LM_DBG("r is %p\n", r);
+				if (r)
+					LM_ERR("Next Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s);
+			}
+			/* Then check the following headers: */
+			for (i=0; i< c->num_service_routes; i++) {
+				LM_DBG("Route must be: %.*s\n", c->service_routes[i].len, c->service_routes[i].s);
+
+				/* No more Route-Headers? Not following service-routes */
+				if (!r) {
+					LM_ERR("No more route headers in message.\n");
+					 goto error;
+				}
+				
+				LM_DBG("Route is: %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s);
+ 				
+				/* Check length: */
+				if (r->nameaddr.uri.len != c->service_routes[i].len) {
+					LM_DBG("Length does not match.\n");
+					 goto error;
+				}
+				/* Check contents: */
+				if (strncasecmp(r->nameaddr.uri.s, c->service_routes[i].s, c->service_routes[i].len) != 0) {
+					LM_DBG("String comparison failed.\n");
+					 goto error;
+				}
+				if (find_next_route(_m, &hdr) != 0) r = NULL;
+				else r = (rr_t*)hdr->parsed;
+			}
+
+			/* Check, if it was the last route-header in the message: */
+			if (r) {
+				LM_ERR("Too many route headers in message.\n");
+				 goto error;
+			}
+		} else {
+			LM_WARN("Strange: Route-Header is present, but not parsed?!?");
+			if (c->num_service_routes > 0) goto error;
+		}
+	} else {
+		LM_ERR("No route header in Message.\n");
+		/* No route-header? Check, if service-routes are indicated.
+		   If yes, request is not following service-routes */
+		if (c->num_service_routes > 0) goto error;
+	}
+	/* Unlock domain */
+	ul.unlock_udomain(_d, &c->aor);
+	return 1;
+error:
+	/* Unlock domain */
+	ul.unlock_udomain(_d, &c->aor);
+	return -1;
+}
+
+static str route_start={"Route: <",8};
+static str route_sep={">, <",4};
+static str route_end={">\r\n",3};
+
+/**
+ * Force Service routes (upon request)
+ */
+int force_service_routes(struct sip_msg* _m, udomain_t* _d) {
+	struct hdr_field *it;
+	int i;
+	str new_route_header;
+	struct lump* lmp = NULL;
+	char * buf;
+	pcontact_t * c = getContactP(_m, _d);
+	
+	// Contact not found => not following service-routes
+	if (c == NULL) return -1;
+
+	/* we need to be sure we have seen all HFs */
+	parse_headers(_m, HDR_EOH_F, 0);
+
+	/* Savbe current buffer */
+	buf = _m->buf;
+
+	// Delete old Route headers:
+	if (_m->route) {
+		for (it = _m->route; it; it = it->next) {
+			if (it->type == HDR_ROUTE_T) {
+				if ((lmp = del_lump(_m, it->name.s - buf, it->len, HDR_ROUTE_T)) == 0) {
+					LM_ERR("del_lump failed \n");
+					return -1;
+				}
+			}
+		}
+	}
+
+	/* Reset dst_uri if previously set either by loose route or manually */
+	if (_m->dst_uri.s && _m->dst_uri.len) {
+		pkg_free(_m->dst_uri.s);
+		_m->dst_uri.s = NULL;
+		_m->dst_uri.len = 0;
+	}
+
+	/* Lock this record while working with the data: */
+	ul.lock_udomain(_d, &c->aor);
+
+	if (c->num_service_routes > 0) {
+		/* Create anchor for new Route-Header: */
+		lmp = anchor_lump(_m, _m->headers->name.s - buf,0,0);
+		if (lmp == 0) {
+			LM_ERR("Failed to get anchor lump\n");
+			goto error;
+		}	
+		/* Calculate the length: */
+		new_route_header.len = route_start.len + route_end.len + (c->num_service_routes-1) * route_sep.len;
+		for(i=0; i< c->num_service_routes; i++)
+			new_route_header.len+=c->service_routes[i].len;		
+		/* Allocate the memory for this new header: */
+		new_route_header.s = pkg_malloc(new_route_header.len);
+		if (!new_route_header.s) {
+			LM_ERR("Error allocating %d bytes\n", new_route_header.len);
+			goto error;
+		}
+		
+		/* Construct new header */
+		new_route_header.len = 0;
+		STR_APPEND(new_route_header, route_start);
+		for(i=0; i < c->num_service_routes; i++) {
+			if (i) STR_APPEND(new_route_header, route_sep);
+			STR_APPEND(new_route_header, c->service_routes[i]);
+		}
+		STR_APPEND(new_route_header, route_end);
+
+		LM_DBG("Setting route header to <%.*s> \n", new_route_header.len, new_route_header.s);
+
+		if ((lmp = insert_new_lump_after(lmp, new_route_header.s, new_route_header.len, HDR_ROUTE_T)) == 0) {
+			LM_ERR("Error inserting new route set\n");
+			pkg_free(new_route_header.s);
+			goto error;
+		}
+
+		LM_DBG("Setting dst_uri to <%.*s> \n", c->service_routes[0].len,
+			c->service_routes[i].s);
+
+		if (set_dst_uri(_m, &c->service_routes[0]) !=0 ) {
+			LM_ERR("Error setting new dst uri\n");
+			goto error;
+		}
+	}
+	/* Unlock domain */
+	ul.unlock_udomain(_d, &c->aor);
+	return 1;
+error:
+	/* Unlock domain */
+	ul.unlock_udomain(_d, &c->aor);
+	return -1;
+	
+}
+
+/**
+ * Check, if source is registered.
+ */
+int is_registered(struct sip_msg* _m, udomain_t* _d) {
+	if (getContactP(_m, _d) != NULL) return 1;		//I think Carsten wrote this but IMO it should be based on Via, not received IP
+//	if (getContactP_from_via(_m, _d) != NULL) return 1;	// It was really intended that way :-)
+
+	return -1;	
+}
+
+/**
+ * Get the current asserted identity for the user
+ */
+str * get_asserted_identity(struct sip_msg* _m) {
+	if (_m->id != current_msg_id) {
+		LM_ERR("Unable to get asserted identity: Please call is_registered first!\n");
+		return NULL;
+	} else return asserted_identity;
+}
+
+/**
+ * Add proper asserted identies based on registration
+ */
+int assert_identity(struct sip_msg* _m, udomain_t* _d, str identity) {
+	// Get the contact:
+	pcontact_t * c = getContactP(_m, _d);
+	// Public identities of this contact
+	ppublic_t * p;
+	
+	// Contact not found => Identity not asserted.
+	if (c == NULL) return -2;
+
+	/* Lock this record while working with the data: */
+	ul.lock_udomain(_d, &c->aor);
+
+	LM_DBG("Checking identity: %.*s\n", identity.len, identity.s);
+
+	LM_DBG("AOR of contact: %.*s\n", c->aor.len, c->aor.s);
+
+	for (p = c->head; p; p = p->next) {
+		LM_DBG("Public identity: %.*s\n", p->public_identity.len, p->public_identity.s);
+		/* Check length: */
+		if (identity.len == p->public_identity.len) {
+			/* Check contents: */
+			if (strncasecmp(identity.s, p->public_identity.s, identity.len) != 0) {
+				LM_DBG("Match!\n");
+				goto success;
+			}
+		} else LM_DBG("Length does not match.\n");
+	}
+
+	// We should only get here, if we failed:
+	/* Unlock domain */
+	ul.unlock_udomain(_d, &c->aor);
+	return -1;
+success:
+	/* Unlock domain */
+	ul.unlock_udomain(_d, &c->aor);
+	return 1;
+}
+

+ 54 - 0
modules/registrar_pcscf/service_routes.h

@@ -0,0 +1,54 @@
+/** 
+ * Functions to force or check the service-routes
+ *
+ * Copyright (c) 2012 Carsten Bock, ng-voice GmbH
+ *
+ * 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
+ */
+
+#ifndef SERVICE_ROUTES_H
+#define SERVICE_ROUTES_H
+
+#include "../../parser/msg_parser.h"
+#include "../usrloc_pcscf/usrloc.h"
+
+/**
+ * Check, if a user-agent follows the indicated service-routes
+ */
+int check_service_routes(struct sip_msg* _m, udomain_t* _d);
+
+/**
+ * Force Service routes (upon request)
+ */
+int force_service_routes(struct sip_msg* _m, udomain_t* _d);
+
+/**
+ * Check, if source is registered.
+ */
+int is_registered(struct sip_msg* _m, udomain_t* _d);
+
+/**
+ * Get the current asserted identity for the user
+ */
+str * get_asserted_identity(struct sip_msg* _m);
+
+/**
+ * Assert a given identity of a user
+ */
+int assert_identity(struct sip_msg* _m, udomain_t* _d, str identity);
+
+#endif /* SERVICE_ROUTES_H */

+ 229 - 0
modules/registrar_pcscf/ul_callback.c

@@ -0,0 +1,229 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */
+
+#include "ul_callback.h"
+//#include "../../modules_k/pua/pua.h"
+//#include "../../modules_k/pua/send_publish.h"
+#include <libxml/parser.h>
+
+/* methods for building reg publish */
+//str* build_reginfo_partial(ppublic_t *impu, struct pcontact* c, int type) {
+//	xmlDocPtr doc = NULL;
+//	xmlNodePtr root_node = NULL;
+//	xmlNodePtr registration_node = NULL;
+//	xmlNodePtr contact_node = NULL;
+//	xmlNodePtr uri_node = NULL;
+//	str * body = NULL;
+//	struct pcontact * ptr;
+//	char buf[512];
+//	int buf_len;
+//	int reg_active = 0;
+//	time_t cur_time = time(0);
+//
+//	/* create the XML-Body */
+//	doc = xmlNewDoc(BAD_CAST "1.0");
+//	if (doc == 0) {
+//		LM_ERR("Unable to create XML-Doc\n");
+//		return NULL;
+//	}
+//
+//	root_node = xmlNewNode(NULL, BAD_CAST "reginfo");
+//	if (root_node == 0) {
+//		LM_ERR("Unable to create reginfo-XML-Element\n");
+//		return NULL;
+//	}
+//	/* This is our Root-Element: */
+//	xmlDocSetRootElement(doc, root_node);
+//
+//	xmlNewProp(root_node, BAD_CAST "xmlns", BAD_CAST "urn:ietf:params:xml:ns:reginfo");
+//
+//	/* we set the version to 0 but it should be set to the correct value in the pua module */
+//	xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0");
+//	xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "partial" );
+//
+//	/* Registration Node */
+//	registration_node = xmlNewChild(root_node, NULL, BAD_CAST "registration", NULL);
+//	if (registration_node == NULL) {
+//		LM_ERR("while adding child\n");
+//		goto error;
+//	}
+//
+//	/* Add the properties to this Node for AOR and ID: */
+//	xmlNewProp(registration_node, BAD_CAST "aor", BAD_CAST impu->public_identity.s);
+//	buf_len = snprintf(buf, sizeof(buf), "%p", impu);
+//	xmlNewProp(registration_node, BAD_CAST "id", BAD_CAST buf);
+//
+//
+//	//now the updated contact
+//	contact_node =xmlNewChild(registration_node, NULL, BAD_CAST "contact", NULL);
+//	if (contact_node == NULL) {
+//		LM_ERR("while adding child\n");
+//		goto error;
+//	}
+//	memset(buf, 0, sizeof(buf));
+//	buf_len = snprintf(buf, sizeof(buf), "%p", c);
+//	xmlNewProp(contact_node, BAD_CAST "id", BAD_CAST buf);
+//
+//	//TODO: this needs to be dependent on state
+//	xmlNewProp(contact_node, BAD_CAST "state", BAD_CAST "terminated");
+//	xmlNewProp(contact_node, BAD_CAST "event", BAD_CAST "unregistered");
+//	memset(buf, 0, sizeof(buf));
+//    //buf_len = snprintf(buf, sizeof(buf), "%i", (int)(ptr->expires-cur_time));
+//    //xmlNewProp(contact_node, BAD_CAST "expires", BAD_CAST buf);
+//
+//	/* URI-Node */
+//	memset(buf, 0, sizeof(buf));
+//	buf_len = snprintf(buf, sizeof(buf), "%.*s", c->aor.len, c->aor.s);
+//	uri_node = xmlNewChild(contact_node, NULL, BAD_CAST "uri", BAD_CAST buf);
+//	if (uri_node == NULL) {
+//		LM_ERR("while adding child\n");
+//		goto error;
+//	}
+//
+//	/* create the body */
+//	body = (str*) pkg_malloc(sizeof(str));
+//	if (body == NULL) {
+//		LM_ERR("while allocating memory\n");
+//		return NULL;
+//	}
+//	memset(body, 0, sizeof(str));
+//
+//	/* Write the XML into the body */
+//	xmlDocDumpFormatMemory(doc, (unsigned char**) (void*) &body->s, &body->len,
+//			1);
+//
+//	/*free the document */
+//	xmlFreeDoc(doc);
+//	xmlCleanupParser();
+//
+//	return body;
+//
+//error:
+//	if (body) {
+//		if (body->s)
+//			xmlFree(body->s);
+//		pkg_free(body);
+//	}
+//	if (doc)
+//		xmlFreeDoc(doc);
+//	return NULL;
+//
+//}
+//
+//int send_partial_publish(ppublic_t *impu, struct pcontact *c, int type)
+//{
+//	publ_info_t publ;
+//    str content_type;
+//    int id_buf_len;
+//    char id_buf[512];
+//
+//    content_type.s = "application/reginfo+xml";
+//    content_type.len = 23;
+//
+//	LM_DBG("Sending publish\n");
+//	str *body = build_reginfo_partial(impu, c, type);
+//
+//	if (body == NULL || body->s == NULL) {
+//		LM_ERR("Error on creating XML-Body for publish\n");
+//		goto error;
+//	}
+//	LM_DBG("XML-Body:\n%.*s\n", body->len, body->s);
+//
+//	memset(&publ, 0, sizeof(publ_info_t));
+//	publ.pres_uri = &impu->public_identity;
+//	publ.body = body;
+//	id_buf_len = snprintf(id_buf, sizeof(id_buf), "IMSPCSCF_PUBLISH.%.*s", c->aor.len, c->aor.s);
+//	publ.id.s = id_buf;
+//	publ.id.len = id_buf_len;
+//	publ.content_type = content_type;
+//	publ.expires = 3600;
+//
+//	/* make UPDATE_TYPE, as if this "publish dialog" is not found
+//	 by pua it will fallback to INSERT_TYPE anyway */
+//	publ.flag |= UPDATE_TYPE;
+//	publ.source_flag |= REGINFO_PUBLISH;
+//	publ.event |= REGINFO_EVENT;
+//	publ.extra_headers = NULL;
+//
+//	if (pua.send_publish(&publ) < 0) {
+//		LM_ERR("Error while sending publish\n");
+//	}
+//
+//	return 1;
+//
+//error:
+//	if (body) {
+//		if (body->s)
+//			xmlFree(body->s);
+//		pkg_free(body);
+//	}
+//	return -1;
+//}
+
+void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param) {
+	ppublic_t *ptr;
+
+	LM_DBG("----------------------!\n");
+	LM_DBG("PCSCF Contact Callback in regsitrar!\n");
+	LM_DBG("Contact AOR: [%.*s]\n", c->aor.len, c->aor.s);
+	LM_DBG("Callback type [%d]\n", type);
+
+	if (type == (PCSCF_CONTACT_DELETE | PCSCF_CONTACT_UPDATE)) {
+		//send publish for each associated IMPU
+		ptr = c->head;
+			while (ptr) {
+				if (c->reg_state == PCONTACT_DEREG_PENDING_PUBLISH) {
+					LM_DBG("delete/update on contact <%.*s> associated with IMPU <%.*s> (sending publish)\n",
+											c->aor.len, c->aor.s,
+											ptr->public_identity.len, ptr->public_identity.s);
+					//send_partial_publish(ptr, c, type);
+				}
+
+				ptr = ptr->next;
+			}
+
+	}
+}
+

+ 57 - 0
modules/registrar_pcscf/ul_callback.h

@@ -0,0 +1,57 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * 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
+ * 
+ */
+
+
+#ifndef UL_CALLBACK_H_
+#define UL_CALLBACK_H_
+
+#include "../usrloc_pcscf/usrloc.h"
+//#include "../../modules_k/pua/pua_bind.h"
+
+//extern pua_api_t pua;
+
+void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param);
+
+#endif /* UL_CALLBACK_H_ */