Przeglądaj źródła

modules/ims_qos: Added IMS QoS module
- This module provides Diameter Rx IMS interface between PCSCF and PCRF
functions

Jason Penton 12 lat temu
rodzic
commit
06fb17e57e

+ 18 - 0
modules/ims_qos/Makefile

@@ -0,0 +1,18 @@
+# $Id$
+#
+# ims_qos make file
+#
+# 
+
+include ../../Makefile.defs
+auto_gen=
+NAME=ims_qos.so
+LIBS=
+
+DEFS+=-DOPENSER_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/ims/kamailio_ims
+
+include ../../Makefile.modules

+ 294 - 0
modules/ims_qos/cdpeventprocessor.c

@@ -0,0 +1,294 @@
+/*
+ * $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 "sem.h"
+#include "../ims_usrloc_pcscf/usrloc.h"
+#include "../dialog_ng/dlg_load.h"
+#include "../cdp/session.h"
+#include "mod.h"
+#include "cdpeventprocessor.h"
+#include "rx_str.h"
+
+cdp_cb_event_list_t *cdp_event_list = 0;
+extern usrloc_api_t ul;
+extern struct dlg_binds dlgb;
+extern int cdp_event_latency;
+extern int cdp_event_threshold;
+extern int cdp_event_latency_loglevel;
+
+int init_cdp_cb_event_list() {
+    cdp_event_list = shm_malloc(sizeof (cdp_cb_event_list_t));
+    if (!cdp_event_list) {
+        LM_ERR("No more SHM mem\n");
+        return 0;
+    }
+    memset(cdp_event_list, 0, sizeof (cdp_cb_event_list_t));
+    cdp_event_list->lock = lock_alloc();
+    if (!cdp_event_list->lock) {
+        LM_ERR("failed to create cdp event list lock\n");
+        return 0;
+    }
+    cdp_event_list->lock = lock_init(cdp_event_list->lock);
+
+    sem_new(cdp_event_list->empty, 0); //pre-locked - as we assume list is empty at start
+
+    return 1;
+}
+
+void destroy_cdp_cb_event_list() {
+    cdp_cb_event_t *ev, *tmp;
+
+    lock_get(cdp_event_list->lock);
+    ev = cdp_event_list->head;
+    while (ev) {
+        tmp = ev->next;
+        free_cdp_cb_event(ev);
+        ev = tmp;
+    }
+    lock_destroy(cdp_event_list->lock);
+    lock_dealloc(cdp_event_list->lock);
+    shm_free(cdp_event_list);
+}
+
+cdp_cb_event_t* new_cdp_cb_event(int event, str *rx_session_id, rx_authsessiondata_t *session_data) {
+    cdp_cb_event_t *new_event = shm_malloc(sizeof (cdp_cb_event_t));
+    if (!new_event) {
+        LM_ERR("no more shm mem\n");
+        return NULL;
+    }
+    memset(new_event, 0, sizeof (cdp_cb_event_t));
+
+    //we have to make a copy of the rx session id because it is not in shm mem
+    if ((rx_session_id->len > 0) && rx_session_id->s) {
+        LM_DBG("Creating new event for rx session [%.*s]\n", rx_session_id->len, rx_session_id->s);
+        new_event->rx_session_id.s = (char*) shm_malloc(rx_session_id->len);
+        if (!new_event->rx_session_id.s) {
+            LM_ERR("no more shm memory\n");
+            shm_free(new_event);
+            return NULL;
+        }
+        memcpy(new_event->rx_session_id.s, rx_session_id->s, rx_session_id->len);
+        new_event->rx_session_id.len = rx_session_id->len;
+    }
+
+    new_event->event = event;
+    new_event->registered = time(NULL);
+    new_event->session_data = session_data; //session_data is already in shm mem
+
+    return new_event;
+}
+//add to tail
+
+void push_cdp_cb_event(cdp_cb_event_t* event) {
+    lock_get(cdp_event_list->lock);
+    if (cdp_event_list->head == 0) { //empty list
+        cdp_event_list->head = cdp_event_list->tail = event;
+    } else {
+        cdp_event_list->tail->next = event;
+        cdp_event_list->tail = event;
+    }
+    sem_release(cdp_event_list->empty);
+    lock_release(cdp_event_list->lock);
+}
+
+//pop from head
+
+cdp_cb_event_t* pop_cdp_cb_event() {
+    cdp_cb_event_t *ev;
+
+    lock_get(cdp_event_list->lock);
+    while (cdp_event_list->head == 0) {
+        lock_release(cdp_event_list->lock);
+        sem_get(cdp_event_list->empty);
+        lock_get(cdp_event_list->lock);
+    }
+
+    ev = cdp_event_list->head;
+    cdp_event_list->head = ev->next;
+
+    if (ev == cdp_event_list->tail) { //list now empty
+        cdp_event_list->tail = 0;
+    }
+    ev->next = 0; //make sure whoever gets this cant access our list
+    lock_release(cdp_event_list->lock);
+
+    return ev;
+}
+
+/*main event process function*/
+void cdp_cb_event_process() {
+    cdp_cb_event_t *ev;
+    udomain_t* domain;
+    pcontact_t* pcontact;
+    str release_reason = {"QoS released", 12}; /* TODO: This could be a module parameter */
+    struct pcontact_info ci;
+    memset(&ci, 0, sizeof (struct pcontact_info));
+
+    for (;;) {
+        ev = pop_cdp_cb_event();
+
+        if (cdp_event_latency) { //track delays
+            unsigned int diff = time(NULL) - ev->registered;
+            if (diff > cdp_event_threshold) {
+                switch (cdp_event_latency_loglevel) {
+                    case 0:
+                        LM_ERR("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
+                        break;
+                    case 1:
+                        LM_WARN("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
+                        break;
+                    case 2:
+                        LM_INFO("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
+                        break;
+                    case 3:
+                        LM_DBG("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
+                        break;
+                    default:
+                        LM_DBG("Unknown log level....printing as debug\n");
+                        LM_DBG("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold);
+                        break;
+                }
+            }
+        }
+        LM_DBG("processing event [%d]\n", ev->event);
+        rx_authsessiondata_t *p_session_data = ev->session_data;
+        str *rx_session_id = &ev->rx_session_id;
+
+        switch (ev->event) {
+            case AUTH_EV_SESSION_TIMEOUT:
+            case AUTH_EV_SESSION_GRACE_TIMEOUT:
+            case AUTH_EV_SESSION_LIFETIME_TIMEOUT:
+                LM_DBG("Rx CDP Session: AUTH EV SESSION TIMEOUT or GRACE TIMEOUT or LIFE TIMEOUT\n");
+
+                if (p_session_data->subscribed_to_signaling_path_status) {
+                    LM_DBG("Received notification of CDP timeout of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
+                            " and domain [%.*s]\n",
+                            rx_session_id->len, rx_session_id->s,
+                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
+                            p_session_data->domain.len, p_session_data->domain.s);
+                    LM_DBG("This is a subscription to signalling bearer session");
+                } else {
+                    LM_DBG("Received notification of CDP timeout of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
+                            " and domain [%.*s]\n",
+                            rx_session_id->len, rx_session_id->s,
+                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
+                            p_session_data->domain.len, p_session_data->domain.s);
+                    LM_DBG("This is a media bearer session session");
+                }
+                break;
+
+            case AUTH_EV_SERVICE_TERMINATED:
+                LM_DBG("Rx CDP Session: Service terminated\n");
+                
+                if (p_session_data->subscribed_to_signaling_path_status) {
+                    LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
+                            " and domain [%.*s]\n",
+                            rx_session_id->len, rx_session_id->s,
+                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
+                            p_session_data->domain.len, p_session_data->domain.s);
+                    LM_DBG("This is a subscription to signalling bearer session");
+                    
+                    //instead of removing the contact from usrloc_pcscf we just change the state of the contact to TERMINATE_PENDING_NOTIFY
+                    //pcscf_registrar sees this, sends a SIP PUBLISH and on SIP NOTIFY the contact is deleted
+                    
+                    if (ul.register_udomain(p_session_data->domain.s, &domain)
+                            < 0) {
+                        LM_DBG("Unable to register usrloc domain....aborting\n");
+                        return;
+                    }
+                    ul.lock_udomain(domain, &p_session_data->registration_aor);
+                    if (ul.get_pcontact(domain, &p_session_data->registration_aor,
+                            &pcontact) != 0) {
+                        LM_DBG("no contact found for terminated Rx reg session..... ignoring\n");
+                    } else {
+                        LM_DBG("Updating contact [%.*s] after Rx reg session terminated, setting state to PCONTACT_DEREG_PENDING_PUBLISH\n", pcontact->aor.len, pcontact->aor.s);
+                        ci.reg_state = PCONTACT_DEREG_PENDING_PUBLISH;
+                        ci.num_service_routes = 0;
+                        ul.update_pcontact(domain, &ci, pcontact);
+                    }
+                    ul.unlock_udomain(domain, &p_session_data->registration_aor);
+                } else {
+                    LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
+                            " and domain [%.*s]\n",
+                            rx_session_id->len, rx_session_id->s,
+                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
+                            p_session_data->domain.len, p_session_data->domain.s);
+                    LM_DBG("This is a media bearer session session");
+                    LM_DBG("Terminating dialog with callid, ftag, ttag: [%.*s], [%.*s], [%.*s]\n",
+                            p_session_data->callid.len, p_session_data->callid.s,
+                            p_session_data->ftag.len, p_session_data->ftag.s,
+                            p_session_data->ttag.len, p_session_data->ttag.s);
+                    dlgb.terminate_dlg(&p_session_data->callid,
+                            &p_session_data->ftag, &p_session_data->ttag, NULL,
+                            &release_reason);
+                }
+                
+                //free callback data
+                if (p_session_data) {
+                    shm_free(p_session_data);
+                    p_session_data = 0;
+                }
+                break;
+            default:
+                break;
+        }
+
+        free_cdp_cb_event(ev);
+    }
+}
+
+void free_cdp_cb_event(cdp_cb_event_t *ev) {
+    if (ev) {
+        LM_DBG("Freeing cdpb CB event structure\n");
+        if (ev->rx_session_id.len > 0 && ev->rx_session_id.s) {
+            LM_DBG("about to free string from cdp CB event [%.*s]\n", ev->rx_session_id.len, ev->rx_session_id.s);
+            shm_free(ev->rx_session_id.s);
+        }
+        shm_free(ev);
+    }
+}
+
+

+ 78 - 0
modules/ims_qos/cdpeventprocessor.h

@@ -0,0 +1,78 @@
+/*
+ * $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 CDPEVENTPROCESSOR
+#define	CDPEVENTPROCESSOR
+
+#include "../../locking.h"
+#include "sem.h"
+#include "rx_authdata.h"
+
+typedef struct _cdp_cb_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 */
+	rx_authsessiondata_t *session_data;	/* associated auth session data - can be null */
+	str rx_session_id;
+	struct _cdp_cb_event *next;
+} cdp_cb_event_t;
+
+typedef struct {
+	gen_lock_t *lock;
+	cdp_cb_event_t *head;
+	cdp_cb_event_t *tail;
+	gen_sem_t *empty;
+} cdp_cb_event_list_t;
+
+int init_cdp_cb_event_list();
+void destroy_cdp_cb_event_list();
+
+cdp_cb_event_t* new_cdp_cb_event (int event, str *rx_session_id, rx_authsessiondata_t *session_data); 			/*create new event*/
+void push_cdp_cb_event(cdp_cb_event_t* event);	/*add event to stack*/
+cdp_cb_event_t* pop_cdp_cb_event();				/*pop next (head) event off list*/
+void free_cdp_cb_event(cdp_cb_event_t*);		/*free memory allocated for event*/
+
+void cdp_cb_event_process();
+
+#endif

+ 875 - 0
modules/ims_qos/mod.c

@@ -0,0 +1,875 @@
+/*
+ * $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 "stats.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "../../sr_module.h"
+#include "../../events.h"
+#include "../../dprint.h"
+#include "../../ut.h"
+#include "../../lib/ims/ims_getters.h"
+#include "../tm/tm_load.h"
+#include "../../mod_fix.h"
+#include "../../parser/parse_uri.h"
+#include "../../parser/parse_content.h"
+#include "../ims_usrloc_pcscf/usrloc.h"
+#include "../../modules/dialog_ng/dlg_load.h"
+#include "../../modules/dialog_ng/dlg_hash.h"
+#include "../cdp/cdp_load.h"
+#include "../cdp_avp/mod_export.h"
+#include "../../cfg/cfg_struct.h"
+#include "cdpeventprocessor.h"
+#include "rx_authdata.h"
+#include "rx_asr.h"
+#include "rx_str.h"
+#include "rx_aar.h"
+#include "mod.h"
+
+#include "../../lib/ims/useful_defs.h"
+
+
+MODULE_VERSION
+
+extern gen_lock_t* process_lock; /* lock on the process table */
+
+str orig_session_key = {"originating", 11};
+str term_session_key = {"terminating", 11};
+
+int rx_auth_expiry = 7200;
+
+int must_send_str = 1;
+
+struct tm_binds tmb;
+struct cdp_binds cdpb;
+struct dlg_binds dlgb;
+bind_usrloc_t bind_usrloc;
+cdp_avp_bind_t *cdp_avp;
+usrloc_api_t ul;
+
+int cdp_event_latency = 1; /*flag: report slow processing of CDP callback events or not - default enabled */
+int cdp_event_threshold = 500; /*time in ms above which we should report slow processing of CDP callback event - default 500ms*/
+int cdp_event_latency_loglevel = 0; /*log-level to use to report slow processing of CDP callback event - default ERROR*/
+
+/** module functions */
+static int mod_init(void);
+static int mod_child_init(int);
+static void mod_destroy(void);
+
+static int fixup_aar_register(void** param, int param_no);
+
+static void free_dialog_data(void *data);
+
+int * callback_singleton; /*< Callback singleton */
+
+/* parameters storage */
+char* rx_dest_realm_s = "ims.smilecoms.com";
+str rx_dest_realm;
+/* Only used if we want to force the Rx peer usually this is configured at a stack level and the first request uses realm routing */
+char* rx_forced_peer_s = "";
+str rx_forced_peer;
+
+/* commands wrappers and fixups */
+static int w_rx_aar(struct sip_msg *msg, char* direction, char *bar);
+static int w_rx_aar_register(struct sip_msg *msg, char* str1, char *bar);
+
+static cmd_export_t cmds[] = {
+    { "Rx_AAR", (cmd_function) w_rx_aar, 1, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE},
+    { "Rx_AAR_Register", (cmd_function) w_rx_aar_register, 1, fixup_aar_register, 0, REQUEST_ROUTE},
+    { 0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[] = {
+    { "rx_dest_realm", STR_PARAM, &rx_dest_realm_s},
+    { "rx_forced_peer", STR_PARAM, &rx_forced_peer_s},
+    { "rx_auth_expiry", INT_PARAM, &rx_auth_expiry},
+    { "cdp_event_latency", INT_PARAM, &cdp_event_latency}, /*flag: report slow processing of CDP callback events or not */
+    { "cdp_event_threshold", INT_PARAM, &cdp_event_threshold}, /*time in ms above which we should report slow processing of CDP callback event*/
+    { "cdp_event_latency_log", INT_PARAM, &cdp_event_latency_loglevel}, /*log-level to use to report slow processing of CDP callback event*/
+    { 0, 0, 0}
+};
+
+stat_export_t mod_stats[] = {
+	{"aar_avg_response_time" ,  STAT_IS_FUNC, 	(stat_var**)get_avg_aar_response_time	},
+	{"aar_timeouts" ,  			0, 				(stat_var**)&stat_aar_timeouts  		},
+	{0,0,0}
+};
+
+/** module exports */
+struct module_exports exports = {"ims_qos", DEFAULT_DLFLAGS, /* dlopen flags */
+    cmds, /* Exported functions */
+    params, 0, /* exported statistics */
+    0, /* exported MI functions */
+    0, /* exported pseudo-variables */
+    0, /* extra processes */
+    mod_init, /* module initialization function */
+    0, mod_destroy, mod_child_init /* per-child init function */};
+
+int fix_parameters() {
+    rx_dest_realm.s = rx_dest_realm_s;
+    rx_dest_realm.len = strlen(rx_dest_realm_s);
+
+    rx_forced_peer.s = rx_forced_peer_s;
+    rx_forced_peer.len = strlen(rx_forced_peer_s);
+
+    return RX_RETURN_TRUE;
+}
+
+/**
+ * init module function
+ */
+static int mod_init(void) {
+
+    /* fix the parameters */
+    if (!fix_parameters())
+        goto error;
+
+#ifdef STATISTICS
+	/* register statistics */
+	if (register_module_stats( exports.name, mod_stats)!=0 ) {
+		LM_ERR("failed to register core statistics\n");
+		goto error;
+	}
+
+	if (!register_stats()){
+		LM_ERR("Unable to register statistics\n");
+		goto error;
+	}
+#endif
+
+    callback_singleton = shm_malloc(sizeof (int));
+    *callback_singleton = 0;
+
+    /*register space for event processor*/
+    register_procs(1);
+
+    cdp_avp = 0;
+    /* load the TM API */
+    if (load_tm_api(&tmb) != 0) {
+        LM_ERR("can't load TM API\n");
+        goto error;
+    }
+
+    /* load the CDP API */
+    if (load_cdp_api(&cdpb) != 0) {
+        LM_ERR("can't load CDP API\n");
+        goto error;
+    }
+
+    /* load the dialog API */
+    if (load_dlg_api(&dlgb) != 0) {
+        LM_ERR("can't load Dialog API\n");
+        goto error;
+    }
+
+    cdp_avp = load_cdp_avp();
+    if (!cdp_avp) {
+        LM_ERR("can't load CDP_AVP API\n");
+        goto error;
+    }
+
+    /* load the usrloc API */
+    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 RX_RETURN_FALSE;
+    }
+
+    if (bind_usrloc(&ul) < 0) {
+        LM_ERR("can't bind to usrloc pcscf\n");
+        return RX_RETURN_FALSE;
+    }
+    LM_DBG("Successfully bound to PCSCF Usrloc module\n");
+
+    LM_DBG("Diameter RX interface successfully bound to TM, Dialog, Usrloc and CDP modules\n");
+
+    /*init cdb cb event list*/
+    if (!init_cdp_cb_event_list()) {
+        LM_ERR("unable to initialise cdp callback event list\n");
+        return -1;
+    }
+
+    return 0;
+error:
+    LM_ERR("Failed to initialise ims_qos module\n");
+    return RX_RETURN_FALSE;
+}
+
+/**
+ * Initializes the module in child.
+ */
+static int mod_child_init(int rank) {
+    LM_DBG("Initialization of module in child [%d] \n", rank);
+
+    if (rank == PROC_MAIN) {
+        int pid = fork_process(PROC_NOCHLDINIT, "Rx Event Processor", 1);
+        if (pid < 0)
+            return -1; //error
+        if (pid == 0) {
+            if (cfg_child_init())
+                return -1; //error
+            cdp_cb_event_process();
+        }
+    }
+    /* don't do anything for main process and TCP manager process */
+    if (rank == PROC_MAIN || rank == PROC_TCP_MAIN) {
+        return 0;
+    }
+
+    lock_get(process_lock);
+    if ((*callback_singleton) == 0) {
+        *callback_singleton = 1;
+        cdpb.AAAAddRequestHandler(callback_cdp_request, NULL);
+    }
+    lock_release(process_lock);
+
+    return 0;
+}
+
+static void mod_destroy(void) {
+}
+
+/*callback of CDP session*/
+void callback_for_cdp_session(int event, void *session) {
+    rx_authsessiondata_t* p_session_data = 0;
+    AAASession *x = session;
+
+    str* rx_session_id = (str*) & x->id;
+    p_session_data = (rx_authsessiondata_t*) x->u.auth.generic_data;
+
+    if (!rx_session_id || rx_session_id->len <= 0 || !rx_session_id->s) {
+        LM_ERR("Invalid Rx session id");
+        return;
+    }
+
+    if (!p_session_data) {
+        LM_ERR("Invalid associated session data\n");
+        return;
+    }
+
+    //only put the events we care about on the event stack
+    if (event == AUTH_EV_SESSION_TIMEOUT ||
+            event == AUTH_EV_SESSION_GRACE_TIMEOUT ||
+            event == AUTH_EV_SESSION_LIFETIME_TIMEOUT ||
+            event == AUTH_EV_SERVICE_TERMINATED) {
+
+        LOG(L_DBG, "callback_for_cdp session(): called with event %d and session id [%.*s]\n", event, rx_session_id->len, rx_session_id->s);
+
+        //create new event to process async
+        cdp_cb_event_t *new_event = new_cdp_cb_event(event, rx_session_id, p_session_data);
+        if (!new_event) {
+            LM_ERR("Unable to create event for cdp callback\n");
+            return;
+        }
+        //push the new event onto the stack (FIFO)
+        push_cdp_cb_event(new_event);
+    } else {
+        LM_DBG("Ignoring event [%d] from CDP session\n", event);
+    }
+}
+
+/**
+ * Handler for incoming Diameter requests.
+ * @param request - the received request
+ * @param param - generic pointer
+ * @returns the answer to this request
+ */
+AAAMessage* callback_cdp_request(AAAMessage *request, void *param) {
+    if (is_req(request)) {
+
+        switch (request->applicationId) {
+            case IMS_Rx:
+            case IMS_Gq:
+                switch (request->commandCode) {
+                    case IMS_RAR:
+                        LM_INFO("Rx request handler():- Received an IMS_RAR \n");
+                        /* TODO: Add support for Re-Auth Requests */
+                        return 0;
+                        break;
+                    case IMS_ASR:
+                        LM_INFO("Rx request handler(): - Received an IMS_ASR \n");
+                        return rx_process_asr(request);
+                        break;
+                    default:
+                        LM_ERR("Rx request handler(): - Received unknown request for Rx/Gq command %d, flags %#1x endtoend %u hopbyhop %u\n", request->commandCode, request->flags, request->endtoendId, request->hopbyhopId);
+                        return 0;
+                        break;
+                }
+                break;
+            default:
+                LM_ERR("Rx request handler(): - Received unknown request for app %d command %d\n", request->applicationId, request->commandCode);
+                return 0;
+                break;
+        }
+    }
+    return 0;
+}
+
+static void free_dialog_data(void *data) {
+    str *rx_session_id = (str*) data;
+    if (rx_session_id) {
+        if (rx_session_id->s) {
+            shm_free(rx_session_id->s);
+            rx_session_id->s = 0;
+        }
+        shm_free(rx_session_id);
+        rx_session_id = 0;
+    }
+
+}
+
+void callback_dialog_terminated(struct dlg_cell* dlg, int type, struct dlg_cb_params * params) {
+    LM_DBG("Dialog has ended - we need to terminate Rx bearer session\n");
+
+    str *rx_session_id;
+    rx_session_id = (str*) * params->param;
+
+    if (!rx_session_id) {
+        LM_ERR("Invalid Rx session id");
+        return;
+    }
+
+    LM_DBG("Received notification of termination of dialog with Rx session ID: [%.*s]\n",
+            rx_session_id->len, rx_session_id->s);
+
+    LM_DBG("Retrieving Rx auth data for this session id");
+
+    LM_DBG("Sending STR\n");
+    rx_send_str(rx_session_id);
+
+    return;
+}
+
+void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param) {
+    LM_DBG("----------------------!\n");
+    LM_DBG("PCSCF Contact Callback!\n");
+    LM_DBG("Contact AOR: [%.*s]\n", c->aor.len, c->aor.s);
+    LM_DBG("Callback type [%d]\n", type);
+
+
+    if (type == PCSCF_CONTACT_EXPIRE || type == PCSCF_CONTACT_DELETE) {
+        //we dont need to send STR if no QoS was ever succesfully registered!
+        if (must_send_str && (c->reg_state != PCONTACT_REG_PENDING) && (c->reg_state != PCONTACT_REG_PENDING_AAR)) {
+            LM_DBG("Received notification of contact (in state [%d] deleted for signalling bearer with  with Rx session ID: [%.*s]\n",
+                    c->reg_state, c->rx_session_id.len, c->rx_session_id.s);
+            LM_DBG("Sending STR\n");
+            rx_send_str(&c->rx_session_id);
+        }
+    }
+}
+
+/* Wrapper to send AAR from config file - this only allows for AAR for calls - not register, which uses r_rx_aar_register
+ * return: 1 - success, <=0 failure. 2 - message not a AAR generating message (ie proceed without PCC if you wish)
+ */
+static int w_rx_aar(struct sip_msg *msg, char* direction, char* bar) {
+    struct cell *t;
+    AAAMessage* resp;
+    AAASession* auth_session;
+    rx_authsessiondata_t* rx_authdata_p = 0;
+    unsigned int result = AAA_SUCCESS;
+    str *rx_session_id;
+    str callid = {0, 0};
+    str ftag = {0, 0};
+    str ttag = {0, 0};
+
+    //We don't ever do AAR on request for calling scenario...
+    if (msg->first_line.type != SIP_REPLY) {
+        LM_DBG("Can't do AAR for call session in request\n");
+        goto error;
+    }
+
+    //is it appropriate to send AAR at this stage?
+    t = tmb.t_gett();
+    if (!t) {
+        LM_WARN("Cannot get transaction for AAR based on SIP Request\n");
+        goto aarna;
+    }
+
+    //we dont apply QoS if its not a reply to an INVITE! or UPDATE or PRACK!
+    if ((t->method.len == 5 && memcmp(t->method.s, "PRACK", 5) == 0)
+            || (t->method.len == 6 && (memcmp(t->method.s, "INVITE", 6) == 0
+            || memcmp(t->method.s, "UPDATE", 6) == 0))) {
+        if (cscf_get_content_length(msg) == 0
+                || cscf_get_content_length(t->uas.request) == 0) {
+            goto aarna; //AAR na if we dont have offer/answer pair
+        }
+    } else {
+        goto aarna;
+    }
+
+    /* get callid, from and to tags to be able to identify dialog */
+    callid = cscf_get_call_id(msg, 0);
+    if (callid.len <= 0 || !callid.s) {
+        LM_ERR("unable to get callid\n");
+        goto error;
+    }
+    if (!cscf_get_from_tag(msg, &ftag)) {
+        LM_ERR("Unable to get ftag\n");
+        goto error;
+    }
+    if (!cscf_get_to_tag(msg, &ttag)) {
+        LM_ERR("Unable to get ttag\n");
+        goto error;
+    }
+
+    //check to see that this is not a result of a retransmission in reply route only
+    if (msg->cseq == NULL
+            && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || (msg->cseq == NULL))) {
+        LM_ERR("No Cseq header found - aborting\n");
+        goto error;
+    }
+
+    //Check that we dont already have an auth session for this specific dialog
+    //if not we create a new one and attach it to the dialog (via session ID).
+    enum dialog_direction dlg_direction = get_dialog_direction(direction);
+    if (dlg_direction == DLG_MOBILE_ORIGINATING) {
+        rx_session_id = dlgb.get_dlg_var(&callid, &ftag, &ttag,
+                &orig_session_key);
+    } else {
+        rx_session_id = dlgb.get_dlg_var(&callid, &ftag, &ttag,
+                &term_session_key);
+    }
+
+    if (!rx_session_id || rx_session_id->len <= 0 || !rx_session_id->s) {
+        LM_DBG("New AAR session for this dialog in mode %s\n", direction);
+        //create new diameter auth session
+        int ret = create_new_callsessiondata(&callid, &ftag, &ttag, &rx_authdata_p);
+        if (!ret) {
+            LM_DBG("Unable to create new media session data parcel\n");
+            goto error;
+        }
+        auth_session = cdpb.AAACreateClientAuthSession(1, callback_for_cdp_session, rx_authdata_p); //returns with a lock
+        if (!auth_session) {
+            LM_ERR("Rx: unable to create new Rx Media Session\n");
+            if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash);
+            if (rx_authdata_p) {
+                shm_free(rx_authdata_p);
+                rx_authdata_p = 0;
+            }
+            goto error;
+        }
+
+        //attach new cdp auth session to dlg for this direction
+        if (dlg_direction == DLG_MOBILE_ORIGINATING) {
+            dlgb.set_dlg_var(&callid, &ftag, &ttag,
+                    &orig_session_key, &auth_session->id);
+        } else {
+            dlgb.set_dlg_var(&callid, &ftag, &ttag,
+                    &term_session_key, &auth_session->id);
+        }
+        LM_DBG("Attached CDP auth session [%.*s] for Rx to dialog in %s mode\n", auth_session->id.len, auth_session->id.s, direction);
+    } else {
+        LM_DBG("Update AAR session for this dialog in mode %s\n", direction);
+        //TODO - what to do on updates - reinvites, etc
+        goto aarna; //TODO: for now we ignore
+    }
+
+    resp = rx_send_aar(t->uas.request, msg, auth_session, &callid, &ftag, &ttag,
+            direction, &rx_authdata_p);
+
+    if (!resp) {
+        LM_ERR("No response received for AAR request\n");
+        goto error;
+    }
+
+    if (!rx_authdata_p) {
+        LM_ERR("Rx: mod.c: error creating new rx_auth_data\n");
+        goto error;
+    }
+    //
+    //    /* Process the response to AAR, retrieving result code and associated Rx session ID */
+    if (rx_process_aaa(resp, &result) < 0) {
+        LM_DBG("Failed to process AAA from PCRF\n");
+        cdpb.AAAFreeMessage(&resp);
+        goto error;
+    }
+    cdpb.AAAFreeMessage(&resp);
+
+
+    if (result >= 2000 && result < 3000) {
+        LM_DBG("Success, received code: [%i] from PCRF for AAR request\n", result);
+
+        str * passed_rx_session_id = shm_malloc(sizeof (struct _str));
+
+        passed_rx_session_id->s = 0;
+        passed_rx_session_id->len = 0;
+        STR_SHM_DUP(*passed_rx_session_id, auth_session->id, "cb_passed_rx_session_id");
+
+        LM_DBG("passed rx session id %.*s", passed_rx_session_id->len, passed_rx_session_id->s);
+
+        dlgb.register_dlgcb_nodlg(&callid, &ftag, &ttag, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED, callback_dialog_terminated, (void*) (passed_rx_session_id), free_dialog_data);
+
+        return RX_RETURN_TRUE;
+    } else {
+        LM_DBG("Received negative reply from PCRF for AAR Request\n");
+        //we don't free rx_authdata_p here - it is free-ed when the CDP session expires
+        goto error; // if its not a success then that means i want to reject this call!
+    }
+out_of_memory:
+    error :
+            LM_ERR("Error trying to send AAR (calling)\n");
+    return RX_RETURN_FALSE;
+aarna:
+    LM_DBG("Policy and Charging Control non-applicable\n");
+    return RX_RETURN_AAR_NA;
+}
+
+/* Wrapper to send AAR from config file - only used for registration */
+static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
+
+    int ret = CSCF_RETURN_ERROR;
+    struct pcontact_info ci;
+    struct cell *t;
+    contact_t* c;
+    struct hdr_field* h;
+    pcontact_t* pcontact;
+    contact_body_t* cb = 0;
+    AAASession* auth;
+    rx_authsessiondata_t* rx_regsession_data_p;
+    cfg_action_t* cfg_action = 0;
+    char* p;
+    int aar_sent = 0;
+    saved_transaction_local_t* local_data = 0;		//data to be shared across all async calls
+    saved_transaction_t* saved_t_data = 0;			//data specific to each contact's AAR async call
+    aar_param_t* ap = (aar_param_t*) str1;
+    udomain_t* domain_t = ap->domain;
+    cfg_action = ap->paction->next;
+    int is_rereg = 0;								//is this a reg/re-reg
+
+    LM_DBG("Rx AAR Register called\n");
+
+    //create the default return code AVP
+    create_return_code(ret);
+
+    memset(&ci, 0, sizeof (struct pcontact_info));
+
+    /** If this is a response then let's check the status before we try and do an AAR.
+     * We will only do AAR for register on success response and of course if message is register
+     */
+    if (msg->first_line.type == SIP_REPLY) {
+        //check this is a response to a register
+        /* Get the SIP request from this transaction */
+        t = tmb.t_gett();
+        if (!t) {
+            LM_ERR("Cannot get transaction for AAR based on SIP Request\n");
+            goto error;
+        }
+        if ((strncmp(t->method.s, "REGISTER", 8) != 0)) {
+            LM_ERR("Method is not a response to a REGISTER\n");
+            goto error;
+        }
+        if (msg->first_line.u.reply.statuscode < 200
+                || msg->first_line.u.reply.statuscode >= 300) {
+            LM_DBG("Message is not a 2xx OK response to a REGISTER\n");
+            goto error;
+        }
+        tmb.t_release(msg);
+    } else { //SIP Request
+        /* in case of request make sure it is a REGISTER */
+        if (msg->first_line.u.request.method_value != METHOD_REGISTER) {
+            LM_DBG("This is not a register request\n");
+            goto error;
+        }
+
+        if ((cscf_get_max_expires(msg, 0) == 0)) {
+            //if ((cscf_get_expires(msg) == 0)) {
+            LM_DBG("This is a de registration\n");
+            LM_DBG("We ignore it as these are dealt with by usrloc callbacks \n");
+            create_return_code(RX_RETURN_TRUE);
+            return RX_RETURN_TRUE;
+        }
+    }
+
+    //before we continue, make sure we have a transaction to work with (viz. cdp async)
+	t = tmb.t_gett();
+	if (t == NULL || t == T_UNDEFINED) {
+		if (tmb.t_newtran(msg) < 0) {
+			LM_ERR("cannot create the transaction for UAR async\n");
+			return CSCF_RETURN_ERROR;
+		}
+		t = tmb.t_gett();
+		if (t == NULL || t == T_UNDEFINED) {
+			LM_ERR("cannot lookup the transaction\n");
+			return CSCF_RETURN_ERROR;
+		}
+	}
+
+	saved_t_data = (saved_transaction_t*)shm_malloc(sizeof(saved_transaction_t));
+	if (!saved_t_data){
+		LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n");
+		return CSCF_RETURN_ERROR;
+	}
+	memset(saved_t_data,0,sizeof(saved_transaction_t));
+	saved_t_data->act = cfg_action;
+	saved_t_data->domain = domain_t;
+	saved_t_data->lock = lock_alloc();
+	if (saved_t_data->lock == NULL) {
+		LM_ERR("unable to allocate init lock for saved_t_transaction reply counter\n");
+		return CSCF_RETURN_ERROR;
+	}
+	if (lock_init(saved_t_data->lock) == NULL) {
+		LM_ERR("unable to init lock for saved_t_transaction reply counter\n");
+		return CSCF_RETURN_ERROR;
+	}
+
+	LM_DBG("Suspending SIP TM transaction\n");
+	if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
+		LM_ERR("failed to suspend the TM processing\n");
+		free_saved_transaction_global_data(saved_t_data);
+		return CSCF_RETURN_ERROR;
+	}
+
+	LM_DBG("Successfully suspended transaction\n");
+
+	//now get the contacts in the REGISTER and do AAR for each one.
+    cb = cscf_parse_contacts(msg);
+    if (!cb || (!cb->contacts && !cb->star)) {
+        LM_DBG("No contact headers in Register message\n");
+        goto error;
+    }
+
+    lock_get(saved_t_data->lock);		//we lock here to make sure we send all requests before processing replies asynchronously
+    for (h = msg->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) {
+                ul.lock_udomain(domain_t, &c->uri);
+                if (ul.get_pcontact(domain_t, &c->uri, &pcontact) != 0) {
+                    LM_DBG("This contact does not exist in PCSCF usrloc - error in cfg file\n");
+                    ul.unlock_udomain(domain_t, &c->uri);
+                    lock_release(saved_t_data->lock);
+                    goto error;
+                } else if (pcontact->reg_state == PCONTACT_REG_PENDING
+                        || pcontact->reg_state == PCONTACT_REGISTERED) { //NEW reg request
+                    LM_DBG("Contact [%.*s] exists and is in state PCONTACT_REG_PENDING or PCONTACT_REGISTERED\n"
+                    		, pcontact->aor.len, pcontact->aor.s);
+
+                    //get IP address from contact
+                    struct sip_uri puri;
+                    if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) {
+                        LM_ERR("failed to parse Contact\n");
+                        ul.unlock_udomain(domain_t, &c->uri);
+                        lock_release(saved_t_data->lock);
+                        goto error;
+
+                    }
+                    LM_DBG("Parsed URI of from host is [%.*s]\n", puri.host.len, puri.host.s);
+                    uint16_t ip_version = AF_INET; //TODO IPv6!!!?
+
+                    //check for existing Rx session
+                    if (pcontact->rx_session_id.len > 0
+                            && pcontact->rx_session_id.s
+                            && (auth = cdpb.AAAGetAuthSession(pcontact->rx_session_id))) {
+                        LM_DBG("Rx session already exists for this user\n");
+                        if (memcmp(pcontact->rx_session_id.s, auth->id.s, auth->id.len) != 0) {
+                            LM_ERR("Rx session mismatch when URI is [%.*s].......Aborting\n", puri.host.len, puri.host.s);
+                            if (auth) cdpb.AAASessionsUnlock(auth->hash);
+                            lock_release(saved_t_data->lock);
+                            goto error;
+                        }
+                        //re-registration - update auth lifetime
+                        auth->u.auth.lifetime = time(NULL) + rx_auth_expiry;
+                        is_rereg = 1;
+                    } else {
+                        LM_DBG("Creating new Rx session for contact <%.*s>\n", pcontact->aor.len, pcontact->aor.s);
+                        int ret = create_new_regsessiondata(domain_t->name, &pcontact->aor, &rx_regsession_data_p);
+                        if (!ret) {
+                            LM_ERR("Unable to create regsession data parcel when URI is [%.*s]...Aborting\n", puri.host.len, puri.host.s);
+                            ul.unlock_udomain(domain_t, &c->uri);
+                            if (rx_regsession_data_p) {
+                                shm_free(rx_regsession_data_p);
+                                rx_regsession_data_p = 0;
+                            }
+                            lock_release(saved_t_data->lock);
+                            goto error;
+                        }
+                        auth = cdpb.AAACreateClientAuthSession(1, callback_for_cdp_session, rx_regsession_data_p); //returns with a lock
+                        if (!auth) {
+                            LM_ERR("Rx: unable to create new Rx Reg Session when URI is [%.*s]\n", puri.host.len, puri.host.s);
+                            if (rx_regsession_data_p) {
+                                shm_free(rx_regsession_data_p);
+                                rx_regsession_data_p = 0;
+                            }
+                            ul.unlock_udomain(domain_t, &c->uri);
+                            if (auth) cdpb.AAASessionsUnlock(auth->hash);
+                            if (rx_regsession_data_p) {
+                                shm_free(rx_regsession_data_p);
+                                rx_regsession_data_p = 0;
+                            }
+                            lock_release(saved_t_data->lock);
+                            goto error;
+                        }
+                    }
+
+                    //we are ready to send the AAR async. lets save the local data data
+                    int local_data_len = sizeof(saved_transaction_local_t) + c->uri.len + auth->id.len;
+                    local_data = shm_malloc(local_data_len);
+                    if (!local_data) {
+                    	LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n");
+                    	lock_release(saved_t_data->lock);
+                    	goto error;
+                    }
+                    memset(local_data, 0, local_data_len);
+
+                    local_data->is_rereg = is_rereg;
+                    local_data->global_data = saved_t_data;
+                    p = (char*) (local_data + 1);
+
+                    local_data->contact.s = p;
+                    local_data->contact.len = c->uri.len;
+                    memcpy(p, c->uri.s, c->uri.len);
+                    p+=c->uri.len;
+
+                    local_data->auth_session_id.s = p;
+                    local_data->auth_session_id.len = auth->id.len;
+                    memcpy(p, auth->id.s, auth->id.len);
+                    p+=auth->id.len;
+
+                    if (p!=( ((char*)local_data) + local_data_len) ) {
+                    	LM_CRIT("buffer overflow\n");
+                    	free_saved_transaction_data(local_data);
+                    	goto error;
+                    }
+
+                    LM_DBG("Calling send aar register");
+                    ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object
+                    ul.unlock_udomain(domain_t, &c->uri);
+
+                    if (!ret) {
+                    	LM_ERR("Failed to send AAR\n");
+                    	lock_release(saved_t_data->lock);
+                    	free_saved_transaction_data(local_data);	//free the local data becuase the CDP async request was not successful (we must free here)
+                    	goto error;
+                    } else {
+                    	aar_sent = 1;
+                    	//before we send - bump up the reply counter
+			saved_t_data->answers_not_received++;		//we dont need to lock as we already hold the lock above
+                    }
+                } else {
+                    //contact exists - this is a re-registration, for now we just ignore this
+                    LM_DBG("This contact exists and is not in state REGISTER PENDING - we assume re (or de) registration and ignore\n");
+                    ul.unlock_udomain(domain_t, &c->uri);
+                    //now we loop for any other contacts.
+                }
+            }
+        } else {
+        	if (h->type == HDR_CONTACT_T) { //means we couldnt parse the contact - this is an error
+        		LM_ERR("Failed to parse contact header\n");
+        		lock_release(saved_t_data->lock);
+        		goto error;
+        	}
+        }
+    }
+    //all requests sent at this point - we can unlock the reply lock
+    lock_release(saved_t_data->lock);
+
+    /*if we get here, we have either:
+     * 1. Successfully sent AAR's for ALL contacts, or
+     * 2. haven't needed to send ANY AAR's for ANY contacts
+     */
+    if (aar_sent) {
+    	LM_DBG("Successful async send of AAR\n");
+    	return RX_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process
+    } else {
+    	create_return_code(RX_RETURN_TRUE);
+    	free_saved_transaction_global_data(saved_t_data);	//no aar sent so we must free the global data
+    	return RX_RETURN_TRUE;
+    }
+error:
+    LM_ERR("Error trying to send AAR\n");
+    if (!aar_sent)
+    	if (saved_t_data)
+    		free_saved_transaction_global_data(saved_t_data); 	//only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
+    															//otherwise the callback will segfault
+    return RX_RETURN_FALSE;
+}
+
+static int fixup_aar_register(void** param, int param_no)
+{
+	udomain_t* d;
+	aar_param_t *ap;
+
+	if(param_no!=1)
+		return 0;
+	ap = (aar_param_t*)pkg_malloc(sizeof(aar_param_t));
+	if(ap==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		return -1;
+	}
+	memset(ap, 0, sizeof(aar_param_t));
+	ap->paction = get_action_from_param(param, param_no);
+
+	if (ul.register_udomain((char*) *param, &d) < 0) {
+		LM_ERR("failed to register domain\n");
+		return E_UNSPEC;
+	}
+	ap->domain = d;
+
+	*param = (void*)ap;
+	return 0;
+}
+
+/*create a return code to be passed back into config file*/
+int create_return_code(int result) {
+    int rc;
+    int_str avp_val, avp_name;
+    avp_name.s.s = "aar_return_code";
+    avp_name.s.len = 15;
+
+    LM_DBG("Creating return code of [%d] for aar_return_code\n", result);
+    //build avp spec for uaa_return_code
+    avp_val.n = result;
+
+    rc = add_avp(AVP_NAME_STR, avp_name, avp_val);
+
+    if (rc < 0)
+        LM_ERR("couldn't create [aar_return_code] AVP\n");
+    else
+        LM_DBG("created AVP successfully : [%.*s]\n", avp_name.s.len, avp_name.s.s);
+
+    return rc;
+}

+ 80 - 0
modules/ims_qos/mod.h

@@ -0,0 +1,80 @@
+/*
+ * $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 MOD_H
+#define	MOD_H
+
+#define MOD_NAME "ims_qos"
+
+/** Return and break the execution of routing script */
+#define RX_RETURN_BREAK	0 
+/** Return true in the routing script */
+#define RX_RETURN_TRUE	1
+/** Return positive but indicate AAR not viable and wasnt sent */
+#define RX_RETURN_AAR_NA	2
+/** Return false in the routing script */
+#define RX_RETURN_FALSE -1
+/** Return error in the routing script */
+#define RX_RETURN_ERROR -2
+
+/** callback functions */
+
+struct AAAMessage;
+struct pcontact;
+
+AAAMessage* callback_cdp_request(AAAMessage *request, void *param);
+void callback_for_cdp_session(int event,void *session);
+
+void callback_dialog_terminated(struct dlg_cell* dlg, int type, struct dlg_cb_params * params);
+
+void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param);
+
+int create_return_code(int result);
+
+
+
+#endif	/* MOD_H */
+

+ 588 - 0
modules/ims_qos/rx_aar.c

@@ -0,0 +1,588 @@
+/*
+ * $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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+#include "stats.h"
+#include "../../mem/shm_mem.h"
+#include "../../parser/sdp/sdp.h"
+#include "../cdp_avp/mod_export.h"
+
+#include "../../modules/dialog_ng/dlg_load.h"
+#include "../../modules/tm/tm_load.h"
+#include "../ims_usrloc_pcscf/usrloc.h"
+#include "rx_authdata.h"
+
+#include "rx_aar.h"
+#include "rx_avp.h"
+
+#include "../../lib/ims/ims_getters.h"
+
+#include "mod.h"
+
+#define macro_name(_rc)	#_rc
+
+//extern struct tm_binds tmb;
+usrloc_api_t ul;
+
+str IMS_Serv_AVP_val = {"IMS Services", 12};
+str IMS_Em_Serv_AVP_val = {"Emergency IMS Call", 18};
+str IMS_Reg_AVP_val = {"IMS Registration", 16};
+
+void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
+    struct cell *t = 0;
+    pcontact_t* pcontact;
+    unsigned int cdp_result;
+    struct pcontact_info ci;
+    udomain_t* domain_t;
+    int finalReply = 0;
+    int result = CSCF_RETURN_ERROR;
+
+    LM_DBG("Received AAR callback\n");
+    saved_transaction_local_t* local_data = (saved_transaction_local_t*) param;
+    saved_transaction_t* data = local_data->global_data;
+    domain_t = data->domain;
+
+    int is_rereg = local_data->is_rereg;
+
+    //before we do anything else, lets decrement the reference counter on replies
+    lock_get(data->lock);
+    data->answers_not_received--;
+    if (data->answers_not_received <= 0) {
+        finalReply = 1;
+    }
+    if (data->ignore_replies) { //there was obv. a subsequent error AFTER we had sent one/more AAR's - so we can ignore these replies and just free memory
+        free_saved_transaction_data(local_data);
+        if (finalReply) {
+            free_saved_transaction_global_data(data);
+        }
+        return;
+    }
+    lock_release(data->lock);
+
+    LM_DBG("received answer and we are waiting for [%d] answers so far failures flag is [%d]\n", data->answers_not_received, data->failed);
+
+    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
+        LM_ERR("t_continue: transaction not found\n");
+        goto error;
+    }
+    //we have T, lets restore our state (esp. for AVPs)
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);
+
+    if (is_timeout != 0) {
+        LM_ERR("Error timeout when sending AAR message via CDP\n");
+        update_stat(stat_aar_timeouts, 1);
+        goto error;
+    }
+    if (!aaa) {
+        LM_ERR("Error sending message via CDP\n");
+        goto error;
+    }
+
+    update_stat(aar_replies_received, 1);
+    update_stat(aar_replies_response_time, elapsed_msecs);
+
+    /* Process the response to AAR, retrieving result code and associated Rx session ID */
+    if (rx_process_aaa(aaa, &cdp_result) < 0) {
+        LM_ERR("Failed to process AAA from PCRF\n"); //puri.host.len, puri.host.s);
+        goto error;
+    }
+
+    if (cdp_result >= 2000 && cdp_result < 3000) {
+    	if (is_rereg) {
+    		LM_DBG("this is a re-registration, therefore we don't need to do anything except know that the the subscription was successful\n");
+    		result = CSCF_RETURN_TRUE;
+    		create_return_code(result);
+    		goto done;
+    	}
+        LM_DBG("Success, received code: [%i] from PCRF for AAR request (contact: [%.*s]), (auth session id: %.*s)\n",
+                cdp_result, local_data->contact.len, local_data->contact.s,
+                local_data->auth_session_id.len, local_data->auth_session_id.s);
+        LM_DBG("Registering for Usrloc callbacks on DELETE\n");
+
+        ul.lock_udomain(domain_t, &local_data->contact);
+        if (ul.get_pcontact(domain_t, &local_data->contact, &pcontact) != 0) {
+            LM_ERR("Shouldn't get here, can find contact....\n");
+            ul.unlock_udomain(domain_t, &local_data->contact);
+            goto error;
+        }
+
+        //at this point we have the contact
+        /*set the contact state to say we have succesfully done ARR for register and that we dont need to do it again
+         * for the duration of the registration.
+         * */
+        if (ul.update_rx_regsession(domain_t, &local_data->auth_session_id, pcontact) != 0) {
+            LM_ERR("unable to update pcontact......\n");
+            ul.unlock_udomain(domain_t, &local_data->contact);
+            goto error;
+        }
+        memset(&ci, 0, sizeof(struct pcontact_info));
+        ci.reg_state = PCONTACT_REG_PENDING_AAR;
+        ci.num_service_routes = 0;
+        ci.num_public_ids = 0;
+        LM_DBG("impu: [%.*s] updating status to PCONTACT_REG_PENDING\n", pcontact->aor.len, pcontact->aor.s);
+        ul.update_pcontact(domain_t, &ci, pcontact);
+        //register for callbacks on contact
+        ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE,
+                callback_pcscf_contact_cb, NULL);
+        ul.unlock_udomain(domain_t, &local_data->contact);
+        result = CSCF_RETURN_TRUE;
+    } else {
+        LM_ERR("Received negative reply from PCRF for AAR Request\n");
+        result = CSCF_RETURN_FALSE;
+        goto error;
+    }
+
+    //set success response code AVP
+    create_return_code(result);
+    goto done;
+
+error:
+    //set failure response code
+    create_return_code(result);
+
+done:
+    if (t) tmb.unref_cell(t);
+    //free memory
+    if (aaa)
+        cdpb.AAAFreeMessage(&aaa);
+
+    if (finalReply) {
+        tmb.t_continue(data->tindex, data->tlabel, data->act);
+        free_saved_transaction_global_data(data);
+    }
+    free_saved_transaction_data(local_data);
+}
+
+/* handle an AAA response to an AAR for resource reservation for a successful registration or initiated/updated dialog
+ * @param aaa - the diameter reply
+ * @return -  1 if result code found and processing ok, -1 if error
+ */
+int rx_process_aaa(AAAMessage *aaa, unsigned int * rc) {
+    int ret = 1;
+
+    ret = rx_get_result_code(aaa, rc);
+
+    if (ret == 0) {
+        LM_DBG("AAA message without result code\n");
+        return ret;
+    }
+
+    return ret;
+}
+
+/** Helper function for adding media component AVPs for each SDP stream*/
+int add_media_components(AAAMessage* aar, struct sip_msg *req,
+        struct sip_msg *rpl, enum dialog_direction direction, str *ip,
+        uint16_t *ip_version) {
+    int sdp_session_num;
+    int sdp_stream_num;
+    sdp_session_cell_t* req_sdp_session, *rpl_sdp_session;
+    sdp_stream_cell_t* req_sdp_stream, *rpl_sdp_stream;
+
+    if (!req || !rpl) {
+        return RX_RETURN_FALSE;
+    }
+
+    if (parse_sdp(req) < 0) {
+        LM_ERR("Unable to parse req SDP\n");
+        return RX_RETURN_FALSE;
+    }
+
+    if (parse_sdp(rpl) < 0) {
+        LM_ERR("Unable to parse res SDP\n");
+        return RX_RETURN_FALSE;
+    }
+
+    sdp_session_num = 0;
+
+    //Loop through req sessions and streams and get corresponding rpl sessions and streams and populate avps
+    for (;;) {
+        //we only cater for one session at the moment: TDOD: extend
+        if (sdp_session_num > 0) {
+            break;
+        }
+
+        req_sdp_session = get_sdp_session(req, sdp_session_num);
+        rpl_sdp_session = get_sdp_session(rpl, sdp_session_num);
+        if (!req_sdp_session || !rpl_sdp_session) {
+            if (!req_sdp_session)
+                LM_ERR("Missing SDP session information from req\n");
+
+            if (!rpl_sdp_session)
+                LM_ERR("Missing SDP session information from rpl\n");
+            break;
+        }
+
+        if (direction == DLG_MOBILE_ORIGINATING) {
+            *ip_version = req_sdp_session->pf;
+            *ip = req_sdp_session->ip_addr;
+        } else if (direction == DLG_MOBILE_TERMINATING) {
+            *ip_version = rpl_sdp_session->pf;
+            *ip = rpl_sdp_session->ip_addr;
+        }
+
+        sdp_stream_num = 0;
+        for (;;) {
+            req_sdp_stream = get_sdp_stream(req, sdp_session_num,
+                    sdp_stream_num);
+            rpl_sdp_stream = get_sdp_stream(rpl, sdp_session_num,
+                    sdp_stream_num);
+            if (!req_sdp_stream || !rpl_sdp_stream) {
+                //LM_ERR("Missing SDP stream information\n");
+                break;
+            }
+            //is this a stream to add to AAR.
+            if (req_sdp_stream->is_rtp) {
+
+                rx_add_media_component_description_avp(aar, sdp_stream_num + 1,
+                        &req_sdp_stream->media, &req_sdp_session->ip_addr,
+                        &req_sdp_stream->port, &rpl_sdp_session->ip_addr,
+                        &rpl_sdp_stream->port, &rpl_sdp_stream->transport,
+                        &req_sdp_stream->raw_stream,
+                        &rpl_sdp_stream->raw_stream, direction);
+            }
+            sdp_stream_num++;
+        }
+        sdp_session_num++;
+    }
+
+    free_sdp((sdp_info_t**) (void*) &req->body);
+    free_sdp((sdp_info_t**) (void*) &rpl->body);
+
+    return 0;
+}
+
+/**
+ * Sends the Authorization Authentication Request.
+ * @param req - SIP request
+ * @param res - SIP response
+ * @param direction - 0/o/orig for originating side, 1/t/term for terminating side
+ * @param rx_auth_data - the returned rx auth data
+ * @returns AAA message or NULL on error
+ */
+
+AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res,
+        AAASession* auth, str* callid, str* ftag, str* ttag, char* direction,
+        rx_authsessiondata_t **rx_authdata) {
+    AAAMessage* aar = 0;
+    AAAMessage* aaa = 0;
+    AAA_AVP* avp = 0;
+    char x[4];
+
+    str ip;
+    uint16_t ip_version;
+
+    /* find direction for AAR (orig/term) */
+    //need this to add the media component details
+    enum dialog_direction dlg_direction = get_dialog_direction(direction);
+    if (dlg_direction == DLG_MOBILE_UNKNOWN) {
+        LM_DBG("Asked to send AAR for unknown direction.....Aborting...\n");
+        goto error;
+    }
+
+    aar = cdpb.AAACreateRequest(IMS_Rx, IMS_AAR, Flag_Proxyable, auth);
+
+    LM_DBG("Created aar request...\n");
+
+    if (!aar)
+        goto error;
+
+    /*Adding AVPs*/
+
+    LM_DBG("Adding auth app id AVP...\n");
+    /* Add Auth-Application-Id AVP */
+    if (!rx_add_auth_application_id_avp(aar, IMS_Rx))
+        goto error;
+    if (!rx_add_vendor_specific_application_id_group(aar, IMS_vendor_id_3GPP,
+            IMS_Rx))
+        goto error;
+
+    LM_DBG("Adding dest realm if not there already...\n");
+    /* Add Destination-Realm AVP, if not already there */
+    avp = cdpb.AAAFindMatchingAVP(aar, aar->avpList.head, AVP_Destination_Realm,
+            0, AAA_FORWARD_SEARCH);
+    if (!avp) {
+        str realm = rx_dest_realm;
+        if (realm.len && !rx_add_destination_realm_avp(aar, realm))
+            goto error;
+    }
+
+    LM_DBG("Adding AF App identifier...\n");
+    /* Add AF-Application-Identifier AVP */
+    str af_id = {0, 0};
+    af_id = IMS_Serv_AVP_val;
+    if (!rx_add_avp(aar, af_id.s, af_id.len, AVP_IMS_AF_Application_Identifier,
+            AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
+            __FUNCTION__))
+        goto error;
+
+    LM_DBG("Adding service info status...\n");
+    /* Add Service-Info-Status AVP, if prelimiary
+     * by default(when absent): final status is considered*/
+    if (!res) {
+        set_4bytes(x,
+                AVP_EPC_Service_Info_Status_Preliminary_Service_Information);
+        if (!rx_add_avp(aar, x, 4, AVP_IMS_Service_Info_Status,
+                AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
+                __FUNCTION__))
+            goto error;
+    }
+
+    /* Add Auth lifetime AVP */LM_DBG("auth_lifetime %u\n", rx_auth_expiry); //TODO check why this is 0 all the time
+    if (rx_auth_expiry) {
+        set_4bytes(x, rx_auth_expiry);
+        if (!rx_add_avp(aar, x, 4, AVP_Authorization_Lifetime,
+                AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__))
+            goto error;
+    }
+
+    LM_DBG("Adding subscription id...\n");
+    /* Add Subscription ID AVP*/
+    int identifier_type = AVP_Subscription_Id_Type_SIP_URI; //we only do IMPU now
+    //to get the SIP URI I use the dlg direction - if its mo I get the from uri from the req, if its mt I get the to uri from the req
+    str identifier;
+    if (dlg_direction == DLG_MOBILE_ORIGINATING) {
+        cscf_get_from_uri(req, &identifier);
+    } else {
+        cscf_get_to_uri(req, &identifier);
+    }
+    rx_add_subscription_id_avp(aar, identifier, identifier_type);
+
+    LM_DBG("Adding reservation priority...\n");
+    /* Add Reservation Priority AVP*/
+    set_4bytes(x, 0);
+    if (!rx_add_avp(aar, x, 4, AVP_ETSI_Reservation_Priority,
+            AAA_AVP_FLAG_VENDOR_SPECIFIC, IMS_vendor_id_ETSI,
+            AVP_DUPLICATE_DATA, __FUNCTION__))
+        goto error;
+
+    LM_DBG("Adding media component...\n");
+    //Note we add this AVP first as it gets the IP address which we need to create the auth session
+    //Could and maybe should have a separate method that retrieves the IP from SDP - TODO
+
+    /*---------- 2. Create and add Media-Component-Description AVP ----------*/
+
+    /*
+     *  See 3GPP TS29214
+     *
+     *  <Media-Component-Description> = {Media-Component-Number}
+     * 								 	[Media-Sub-Component]
+     * 								 	[AF-Application-Identifier]
+     * 								 	[Media-Type]
+     * 								 	[Max-Requested-Bandwidth-UL]
+     * 									[Max-Requested-Bandwidth-DL]
+     * 									[Flow-Status]
+     * 									[Reservation-Priority] (Not used yet)
+     * 								 	[RS-Bandwidth]
+     * 									[RR-Bandwidth]
+     * 									*[Codec-Data]
+     */
+
+    add_media_components(aar, req, res, dlg_direction, &ip, &ip_version);
+
+    LM_DBG("Adding framed ip address [%.*s]\n", ip.len, ip.s);
+    /* Add Framed IP address AVP*/
+    if (!rx_add_framed_ip_avp(&aar->avpList, ip, ip_version)) {
+        LM_ERR("Unable to add framed IP AVP\n");
+        goto error;
+    }
+    LM_DBG("Unlocking AAA session...\n");
+
+    if (auth)
+        cdpb.AAASessionsUnlock(auth->hash);
+
+    LM_DBG("sending AAR to PCRF\n");
+    if (rx_forced_peer.len)
+        aaa = cdpb.AAASendRecvMessageToPeer(aar, &rx_forced_peer);
+    else
+        aaa = cdpb.AAASendRecvMessage(aar);
+
+    return aaa;
+
+error:
+    LM_ERR("unexpected error\n");
+    if (aar)
+        cdpb.AAAFreeMessage(&aar);
+    if (auth) {
+        cdpb.AAASessionsUnlock(auth->hash);
+        cdpb.AAADropAuthSession(auth);
+        auth = 0;
+    }
+    return NULL;
+}
+
+/**
+ * Sends the Authorization Authentication Request for Register messages
+ * @param req - SIP Register msg
+ * @param rx_auth_data - the returned rx auth data
+ * @param ip - ip address extracted from contact to register
+ * @param ip_version - AF_INET or AF_INET6
+ * @returns int >0 if sent AAR successfully, otherwise 0
+ */
+int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip,
+        uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data) {
+    AAAMessage* aar = 0;
+    int ret = 0;
+    AAA_AVP* avp = 0;
+    char x[4];
+
+    LM_DBG("Send AAR register\n");
+
+    aar = cdpb.AAACreateRequest(IMS_Rx, IMS_AAR, Flag_Proxyable, auth);
+
+    if (!aar)
+        goto error;
+
+    /*Add AVPs*/
+
+    /* Add Auth-Application-Id AVP */
+    if (!rx_add_auth_application_id_avp(aar, IMS_Rx))
+        goto error;
+    if (!rx_add_vendor_specific_application_id_group(aar, IMS_vendor_id_3GPP,
+            IMS_Rx))
+        goto error;
+
+    /* Add Destination-Realm AVP, if not already there */
+    avp = cdpb.AAAFindMatchingAVP(aar, aar->avpList.head, AVP_Destination_Realm,
+            0, AAA_FORWARD_SEARCH);
+    if (!avp) {
+        str realm = rx_dest_realm;
+        if (realm.len && !rx_add_destination_realm_avp(aar, realm))
+            goto error;
+    }
+
+    /* Add Subscription ID AVP*/
+    str identifier;
+    cscf_get_from_uri(msg, &identifier);
+    int identifier_type = AVP_Subscription_Id_Type_SIP_URI; //we only do IMPU now
+    rx_add_subscription_id_avp(aar, identifier, identifier_type);
+
+    /* Add media component description avp for register*/
+    rx_add_media_component_description_avp_register(aar);
+
+    /* Add Framed IP address AVP*/
+    if (!rx_add_framed_ip_avp(&aar->avpList, *ip, *ip_version)) {
+        LM_ERR("Unable to add framed IP AVP\n");
+        goto error;
+    }
+
+    /* Add Auth lifetime AVP */LM_DBG("auth_lifetime %u\n", rx_auth_expiry); //TODO check why this is 0 all the time
+    if (rx_auth_expiry) {
+        set_4bytes(x, rx_auth_expiry);
+        if (!rx_add_avp(aar, x, 4, AVP_Authorization_Lifetime,
+                AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__))
+            goto error;
+    }
+
+    if (auth)
+        cdpb.AAASessionsUnlock(auth->hash);
+
+    LM_DBG("sending AAR to PCRF\n");
+    if (rx_forced_peer.len)
+        ret = cdpb.AAASendMessageToPeer(aar, &rx_forced_peer,
+            (void*) async_cdp_callback, (void*) saved_t_data);
+    else
+        ret = cdpb.AAASendMessage(aar, (void*) async_cdp_callback,
+            (void*) saved_t_data);
+
+    return ret;
+
+error:
+    LM_ERR("unexpected error\n");
+    if (aar)
+        cdpb.AAAFreeMessage(&aar);
+    if (auth) {
+        cdpb.AAASessionsUnlock(auth->hash);
+        cdpb.AAADropAuthSession(auth);
+        auth = 0;
+    }
+    return ret;
+}
+
+enum dialog_direction get_dialog_direction(char *direction) {
+    if (!direction) {
+        LM_CRIT("Unknown direction NULL");
+        return DLG_MOBILE_UNKNOWN;
+    }
+    switch (direction[0]) {
+        case 'o':
+        case 'O':
+        case '0':
+            return DLG_MOBILE_ORIGINATING;
+        case 't':
+        case 'T':
+        case '1':
+            return DLG_MOBILE_TERMINATING;
+        default:
+            LM_CRIT("Unknown direction %s", direction);
+            return DLG_MOBILE_UNKNOWN;
+    }
+}
+
+void free_saved_transaction_global_data(saved_transaction_t* data) {
+    if (!data)
+        return;
+
+    lock_dealloc(data->lock);
+    lock_destroy(data->lock);
+    shm_free(data);
+}
+
+void free_saved_transaction_data(saved_transaction_local_t* data) {
+    if (!data)
+        return;
+
+
+    shm_free(data);
+}

+ 112 - 0
modules/ims_qos/rx_aar.h

@@ -0,0 +1,112 @@
+/*
+ * $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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+#ifndef RX_AAR_H
+#define RX_AAR_H
+
+#include "../../mod_fix.h"
+#include "../../locking.h"
+
+struct cdp_binds cdpb;
+cdp_avp_bind_t *cdp_avp;
+
+/*storage for data coming into AAR_register from config file
+ * holds next action (async CDP) and domain
+ */
+typedef struct aar_param {
+	int type;
+	udomain_t* domain;
+	cfg_action_t *paction;
+} aar_param_t;
+
+
+/*this is the parcel to pass for CDP async for AAR*/
+typedef struct saved_transaction {
+	gen_lock_t *lock;
+	unsigned int ignore_replies;
+	unsigned int answers_not_received;
+	unsigned int failed;	//will start at 0 - if 1 fails we can set the flag up (1)
+	unsigned int tindex;
+	unsigned int tlabel;
+	unsigned int ticks;
+	cfg_action_t *act;
+	udomain_t* domain;
+} saved_transaction_t;
+
+typedef struct saved_transaction_local {
+	int is_rereg;
+	str contact;
+	str auth_session_id;
+	saved_transaction_t* global_data;
+} saved_transaction_local_t;
+
+/* the destination realm*/
+extern str rx_dest_realm;
+extern str rx_forced_peer;
+extern int rx_auth_expiry;
+
+
+/* AAR */
+struct AAAMessage;
+struct sip_msg;
+struct rx_authdata;
+
+void free_saved_transaction_data(saved_transaction_local_t* data);
+void free_saved_transaction_global_data(saved_transaction_t* data);
+
+AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, str *callid, str *ftag, str *ttag, char *direction, rx_authsessiondata_t **rx_authdata);
+int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data);
+int rx_process_aaa(AAAMessage *aaa, unsigned int * rc);
+enum dialog_direction get_dialog_direction(char *direction);
+
+void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs);
+
+#endif
+

+ 101 - 0
modules/ims_qos/rx_asr.c

@@ -0,0 +1,101 @@
+/*
+ * $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
+ * 
+ *
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+
+
+#include "../cdp_avp/mod_export.h"
+
+#include "../../modules/dialog_ng/dlg_load.h"
+#include "../ims_usrloc_pcscf/usrloc.h"
+#include "rx_authdata.h"
+
+#include "rx_asr.h"
+#include "rx_avp.h"
+#include "../../lib/ims/ims_getters.h"
+
+/*
+ * Called upon receipt of an ASR. Terminates the user session and returns the ASA.
+ * Terminates the corresponding dialog
+ * @param request - the received request
+ * @returns 0 always because ASA will be generated by the State Machine
+ *
+ */
+AAAMessage* rx_process_asr(AAAMessage *request) {
+    AAASession* session;
+    unsigned int code = 0;
+
+    rx_authsessiondata_t* p_session_data = 0;
+
+    if (!request || !request->sessionId) return 0;
+
+    session = cdpb.AAAGetAuthSession(request->sessionId->data);
+
+    if (!session) {
+        LM_DBG("received an ASR but the session is already deleted\n");
+        return 0;
+    }
+
+    code = rx_get_abort_cause(request);
+    LM_DBG("abort-cause code is %u\n", code);
+
+    LM_DBG("PCRF requested an ASR");
+
+
+    p_session_data = (rx_authsessiondata_t*) session->u.auth.generic_data;
+    if (p_session_data->subscribed_to_signaling_path_status) {
+        LM_DBG("This is a subscription to signalling status\n");
+    } else {
+        LM_DBG("This is a normal media bearer -  bearer is releaed by CDP callbacks\n");
+    }
+    cdpb.AAASessionsUnlock(session->hash);
+    return 0;
+}
+

+ 57 - 0
modules/ims_qos/rx_asr.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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+#ifndef RX_ASR_H
+#define RX_ASR_H
+
+AAAMessage* rx_process_asr(AAAMessage *request);
+
+#endif
+

+ 152 - 0
modules/ims_qos/rx_authdata.c

@@ -0,0 +1,152 @@
+/*
+ * $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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+#include "../../sr_module.h"
+#include "../../ut.h"
+#include "../../mem/shm_mem.h"
+#include "../../parser/contact/parse_contact.h"
+#include "../../locking.h"
+#include "../tm/tm_load.h"
+#include "../../modules/dialog_ng/dlg_load.h"
+#include "../../modules/dialog_ng/dlg_hash.h"
+#include "../ims_usrloc_pcscf/usrloc.h"
+
+#include "../../mem/shm_mem.h"
+#include "../../parser/sdp/sdp_helpr_funcs.h"
+#include "../../parser/sdp/sdp.h"
+#include "../../parser/parse_rr.h"
+#include "../cdp/cdp_load.h"
+#include "rx_authdata.h"
+#include "rx_avp.h"
+#include "../../lib/ims/ims_getters.h"
+#include "mod.h"
+
+int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** session_data) {
+
+	int len = (domain->len + 1) + aor->len + sizeof(rx_authsessiondata_t);
+	rx_authsessiondata_t* p_session_data = shm_malloc(len);
+	if (!p_session_data) {
+		LM_ERR("no more shm memory\n");
+		return -1;
+	}
+	memset(p_session_data, 0, len);
+
+	p_session_data->subscribed_to_signaling_path_status = 1;
+
+	char* p = (char*)(p_session_data + 1);
+	p_session_data->domain.s = p;
+	memcpy(p, domain->s, domain->len);
+	p_session_data->domain.len = domain->len;
+	p += domain->len;
+	*p++ = '\0';
+
+	p_session_data->registration_aor.s = p;
+	memcpy(p, aor->s, aor->len);
+	p_session_data->registration_aor.len = aor->len;
+	p += aor->len;
+	if (p != (((char*)p_session_data) + len)) {
+		LM_ERR("buffer over/underflow\n");
+		shm_free(p_session_data);
+		p_session_data = 0;
+		return -1;
+	}
+	*session_data = p_session_data;
+
+	return 1;
+}
+
+int create_new_callsessiondata(str* callid, str* ftag, str* ttag, rx_authsessiondata_t** session_data) {
+
+	int len = callid->len + ftag->len + ttag->len + sizeof(rx_authsessiondata_t);
+	rx_authsessiondata_t* call_session_data = shm_malloc(len);
+	if (!call_session_data){
+		LM_ERR("no more shm mem trying to create call_session_data of size %d\n", len);
+		return -1;
+	}
+	memset(call_session_data, 0, len);
+	call_session_data->subscribed_to_signaling_path_status = 0; //this is for a media session not regitration
+
+	char *p = (char*)(call_session_data + 1);
+
+	if (callid && callid->len>0 && callid->s) {
+		LM_DBG("Copying callid [%.*s] into call session data\n", callid->len, callid->s);
+		call_session_data->callid.s = p;
+		memcpy(call_session_data->callid.s, callid->s, callid->len);
+                call_session_data->callid.len = callid->len;
+		p+=callid->len;
+	}
+	if (ftag && ftag->len > 0 && ftag->s) {
+		LM_DBG("Copying ftag [%.*s] into call session data\n", ftag->len, ftag->s);
+		call_session_data->ftag.s = p;
+		memcpy(call_session_data->ftag.s, ftag->s, ftag->len);
+                call_session_data->ftag.len = ftag->len;
+		p += ftag->len;
+	}
+	if (ttag && ttag->len > 0 && ttag->s) {
+		LM_DBG("Copying ttag [%.*s] into call session data\n", ttag->len, ttag->s);
+		call_session_data->ttag.s = p;
+		memcpy(call_session_data->ttag.s, ttag->s, ttag->len);
+                call_session_data->ttag.len = ttag->len;
+		p += ttag->len;
+	}
+	if (p != ((char*)(call_session_data) + len)) {
+		LM_ERR("buffer under/overflow\n");
+		shm_free(call_session_data);
+		return -1;
+	}
+
+	*session_data = call_session_data;
+	return 1;
+}
+
+
+
+
+

+ 78 - 0
modules/ims_qos/rx_authdata.h

@@ -0,0 +1,78 @@
+/*
+ * $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
+ * 
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+#ifndef RX_AUTH_DATA_H
+#define RX_AUTH_DATA_H
+
+extern struct tm_binds tmb;
+extern struct cdp_binds cdpb;
+extern struct dlg_binds dlgb;
+
+enum dialog_direction {
+    DLG_MOBILE_ORIGINATING = 1,
+    DLG_MOBILE_TERMINATING = 2,
+    DLG_MOBILE_REGISTER = 3,
+    DLG_MOBILE_UNKNOWN = 4
+};
+
+typedef struct rx_authsessiondata {
+    str callid;
+    str ftag;
+    str ttag;
+    //for registration session
+    int subscribed_to_signaling_path_status; // 0 not subscribed 1 is subscribed
+    str domain;				//the domain the registration aor belongs to (for registration)
+    str registration_aor; //the aor if this rx session is a subscription to signalling status
+} rx_authsessiondata_t;
+
+int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** session_data);
+int create_new_callsessiondata(str* callid, str* ftag, str* ttag, rx_authsessiondata_t** session_data);
+
+#endif
+

+ 771 - 0
modules/ims_qos/rx_avp.c

@@ -0,0 +1,771 @@
+/*
+ * $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
+ * 
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+
+#include <arpa/inet.h>
+#include "../cdp_avp/mod_export.h"
+#include "../../modules/dialog_ng/dlg_load.h"
+#include "../ims_usrloc_pcscf/usrloc.h"
+#include "rx_authdata.h"
+#include "rx_avp.h"
+#include "mod.h"
+
+/**< Structure with pointers to cdp funcs, global variable defined in mod.c  */
+extern struct cdp_binds cdpb;
+extern cdp_avp_bind_t *cdp_avp;
+
+/**
+ * Create and add an AVP to a Diameter message.
+ * @param m - Diameter message to add to 
+ * @param d - the payload data
+ * @param len - length of the payload data
+ * @param avp_code - the code of the AVP
+ * @param flags - flags for the AVP
+ * @param vendorid - the value of the vendor id or 0 if none
+ * @param data_do - what to do with the data when done
+ * @param func - the name of the calling function, for debugging purposes
+ * @returns 1 on success or 0 on failure
+ */
+inline int rx_add_avp(AAAMessage *m, char *d, int len, int avp_code,
+        int flags, int vendorid, int data_do, const char *func) {
+    AAA_AVP *avp;
+    if (vendorid != 0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
+    avp = cdpb.AAACreateAVP(avp_code, flags, vendorid, d, len, data_do);
+    if (!avp) {
+        LM_ERR("Rx: :%s: Failed creating avp\n", func);
+        return 0;
+    }
+    if (cdpb.AAAAddAVPToMessage(m, avp, m->avpList.tail) != AAA_ERR_SUCCESS) {
+        LM_ERR(":%s: Failed adding avp to message\n", func);
+        cdpb.AAAFreeAVP(&avp);
+        return 0;
+    }
+    return RX_RETURN_TRUE;
+}
+
+/**
+ * Create and add an AVP to a list of AVPs.
+ * @param list - the AVP list to add to 
+ * @param d - the payload data
+ * @param len - length of the payload data
+ * @param avp_code - the code of the AVP
+ * @param flags - flags for the AVP
+ * @param vendorid - the value of the vendor id or 0 if none
+ * @param data_do - what to do with the data when done
+ * @param func - the name of the calling function, for debugging purposes
+ * @returns 1 on success or 0 on failure
+ */
+static inline int rx_add_avp_list(AAA_AVP_LIST *list, char *d, int len, int avp_code,
+        int flags, int vendorid, int data_do, const char *func) {
+    AAA_AVP *avp;
+    if (vendorid != 0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
+    avp = cdpb.AAACreateAVP(avp_code, flags, vendorid, d, len, data_do);
+    if (!avp) {
+        LM_ERR(":%s: Failed creating avp\n", func);
+        return 0;
+    }
+    if (list->tail) {
+        avp->prev = list->tail;
+        avp->next = 0;
+        list->tail->next = avp;
+        list->tail = avp;
+    } else {
+        list->head = avp;
+        list->tail = avp;
+        avp->next = 0;
+        avp->prev = 0;
+    }
+
+    return RX_RETURN_TRUE;
+}
+
+/**
+ * Returns the value of a certain AVP from a Diameter message.
+ * @param m - Diameter message to look into
+ * @param avp_code - the code to search for
+ * @param vendorid - the value of the vendor id to look for or 0 if none
+ * @param func - the name of the calling function, for debugging purposes
+ * @returns the str with the payload on success or an empty string on failure
+ */
+static inline str rx_get_avp(AAAMessage *msg, int avp_code, int vendor_id,
+        const char *func) {
+    AAA_AVP *avp;
+    str r = {0, 0};
+
+    avp = cdpb.AAAFindMatchingAVP(msg, 0, AVP_Result_Code, 0, 0);
+    if (avp == 0) {
+        //LOG(L_INFO,"INFO:"M_NAME":%s: Failed finding avp\n",func);
+        return r;
+    } else
+        return avp->data;
+}
+
+/*creates an AVP for the framed-ip info: 
+ * 	if ipv4: AVP_Framed_IP_Address, 
+ * 	otherwise: AVP_Framed_IPv6_Prefix
+ * 	using inet_pton to convert the IP addresses 
+ * 	from human-readable strings to their bynary representation
+ * 	see http://beej.us/guide/bgnet/output/html/multipage/inet_ntopman.html
+ * 	http://beej.us/guide/bgnet/output/html/multipage/sockaddr_inman.html
+ */
+int rx_add_framed_ip_avp(AAA_AVP_LIST * list, str ip, uint16_t version) {
+    ip_address_prefix ip_adr;
+    char* ip_pkg = 0;
+    int ret = 0;
+
+    if (ip.len < 0) return 0;
+    if (version == AF_INET) {
+        if (ip.len > INET_ADDRSTRLEN)
+            goto error;
+    } else {
+        if (ip.len > INET6_ADDRSTRLEN)
+            goto error;
+    }
+    ip_pkg = (char*) pkg_malloc((ip.len + 1) * sizeof (char));
+    if (!ip_pkg) {
+        LM_ERR("PCC_create_framed_ip_avp: could not allocate %i from pkg\n", ip.len + 1);
+        goto error;
+    }
+    memcpy(ip_pkg, ip.s, ip.len);
+    ip_pkg[ip.len] = '\0';
+
+    ip_adr.addr.ai_family = version;
+
+    if (version == AF_INET) {
+
+        if (inet_pton(AF_INET, ip_pkg, &(ip_adr.addr.ip.v4.s_addr)) != 1) goto error;
+        ret = cdp_avp->nasapp.add_Framed_IP_Address(list, ip_adr.addr);
+    } else {
+
+        if (inet_pton(AF_INET6, ip_pkg, &(ip_adr.addr.ip.v6.s6_addr)) != 1) goto error;
+        ret = cdp_avp->nasapp.add_Framed_IPv6_Prefix(list, ip_adr);
+    }
+
+error:
+    if (ip_pkg) pkg_free(ip_pkg);
+    return ret;
+}
+
+/**
+ * Creates and adds a Vendor-Specifig-Application-ID AVP.
+ * @param msg - the Diameter message to add to.
+ * @param vendor_id - the value of the vendor_id,
+ * @param auth_id - the authorization application id
+ * @param acct_id - the accounting application id
+ * @returns 1 on success or 0 on error
+ */
+inline int rx_add_vendor_specific_appid_avp(AAAMessage *msg, unsigned int vendor_id,
+        unsigned int auth_id, unsigned int acct_id) {
+    AAA_AVP_LIST list;
+    str group;
+    char x[4];
+
+    list.head = 0;
+    list.tail = 0;
+
+    set_4bytes(x, vendor_id);
+    rx_add_avp_list(&list,
+            x, 4,
+            AVP_Vendor_Id,
+            AAA_AVP_FLAG_MANDATORY,
+            0,
+            AVP_DUPLICATE_DATA,
+            __FUNCTION__);
+
+    if (auth_id) {
+        set_4bytes(x, auth_id);
+        rx_add_avp_list(&list,
+                x, 4,
+                AVP_Auth_Application_Id,
+                AAA_AVP_FLAG_MANDATORY,
+                0,
+                AVP_DUPLICATE_DATA,
+                __FUNCTION__);
+    }
+    if (acct_id) {
+        set_4bytes(x, acct_id);
+        rx_add_avp_list(&list,
+                x, 4,
+                AVP_Acct_Application_Id,
+                AAA_AVP_FLAG_MANDATORY,
+                0,
+                AVP_DUPLICATE_DATA,
+                __FUNCTION__);
+    }
+
+    group = cdpb.AAAGroupAVPS(list);
+
+    cdpb.AAAFreeAVPList(&list);
+
+    return
+    rx_add_avp(msg, group.s, group.len,
+            AVP_Vendor_Specific_Application_Id,
+            AAA_AVP_FLAG_MANDATORY,
+            0,
+            AVP_FREE_DATA,
+            __FUNCTION__);
+}
+
+/**
+ * Creates and adds a Destination-Realm AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int rx_add_destination_realm_avp(AAAMessage *msg, str data) {
+    return
+    rx_add_avp(msg, data.s, data.len,
+            AVP_Destination_Realm,
+            AAA_AVP_FLAG_MANDATORY,
+            0,
+            AVP_DUPLICATE_DATA,
+            __FUNCTION__);
+}
+
+/**
+ * Creates and adds an Acct-Application-Id AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @return RX_RETURN_TRUE on success or 0 on error
+ */
+inline int rx_add_auth_application_id_avp(AAAMessage *msg, unsigned int data) {
+    char x[4];
+    set_4bytes(x, data);
+
+    return
+    rx_add_avp(msg, x, 4,
+            AVP_Auth_Application_Id,
+            AAA_AVP_FLAG_MANDATORY,
+            0,
+            AVP_DUPLICATE_DATA,
+            __FUNCTION__);
+}
+
+/*
+ * Creates and adds a Subscription_Id AVP
+ * @param msg - the Diameter message to add to.
+ * @param r - the sip_message to extract the data from.
+ * @param tag - originating (0) terminating (1)
+ * @return RX_RETURN_TRUE on success or 0 on error
+ * 
+ */
+
+int rx_add_subscription_id_avp(AAAMessage *msg, str identifier, int identifier_type) {
+    
+    AAA_AVP_LIST list;
+    AAA_AVP *type, *data;
+    str subscription_id_avp;
+    char x[4];
+    list.head = 0;
+    list.tail = 0;
+
+    set_4bytes(x, identifier_type);
+
+    type = cdpb.AAACreateAVP(AVP_IMS_Subscription_Id_Type,
+            AAA_AVP_FLAG_MANDATORY,
+            0, x, 4,
+            AVP_DUPLICATE_DATA);
+
+    data = cdpb.AAACreateAVP(AVP_IMS_Subscription_Id_Data,
+            AAA_AVP_FLAG_MANDATORY,
+            0, identifier.s, identifier.len,
+            AVP_DUPLICATE_DATA);
+
+    cdpb.AAAAddAVPToList(&list, type);
+    cdpb.AAAAddAVPToList(&list, data);
+
+    subscription_id_avp = cdpb.AAAGroupAVPS(list);
+
+    cdpb.AAAFreeAVPList(&list);
+    
+    return rx_add_avp(msg, subscription_id_avp.s, subscription_id_avp.len, AVP_IMS_Subscription_Id,
+            AAA_AVP_FLAG_MANDATORY, 0,
+            AVP_FREE_DATA,
+            __FUNCTION__);
+}
+
+inline int rx_add_media_component_description_avp(AAAMessage *msg, int number, str *media_description, str *ipA, str *portA, str *ipB, str *portB, str *transport,
+        str *req_raw_payload, str *rpl_raw_payload, enum dialog_direction dlg_direction) {
+    str data;
+    AAA_AVP_LIST list;
+    AAA_AVP *media_component_number, *media_type;
+    AAA_AVP *codec_data1, *codec_data2;
+    AAA_AVP * media_sub_component[PCC_Media_Sub_Components];
+    AAA_AVP *flow_status;
+
+    int media_sub_component_number = 0;
+
+    int type;
+    char x[4];
+
+    list.head = 0;
+    list.tail = 0;
+
+    /*media-component-number*/
+    set_4bytes(x, number);
+    media_component_number = cdpb.AAACreateAVP(AVP_IMS_Media_Component_Number,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, x, 4,
+            AVP_DUPLICATE_DATA);
+
+    if (media_component_number != NULL) {
+        cdpb.AAAAddAVPToList(&list, media_component_number);
+    } else {
+        LM_ERR("Unable to create media_component_number AVP");
+        return 0;
+    }
+
+    /*media-sub-component*/
+    if (dlg_direction != DLG_MOBILE_ORIGINATING) {
+        media_sub_component[media_sub_component_number] = rx_create_media_subcomponent_avp(number, transport->s, ipA, portA, ipB, portB);
+        cdpb.AAAAddAVPToList(&list, media_sub_component[media_sub_component_number]);
+    } else {
+        media_sub_component[media_sub_component_number] = rx_create_media_subcomponent_avp(number, transport->s, ipB, portB, ipA, portA);
+        cdpb.AAAAddAVPToList(&list, media_sub_component[media_sub_component_number]);
+    }
+
+
+    /*media type*/
+    if (strncmp(media_description->s, "audio", 5) == 0) {
+        type = AVP_IMS_Media_Type_Audio;
+    } else if (strncmp(media_description->s, "video", 5) == 0) {
+        type = AVP_IMS_Media_Type_Video;
+    } else if (strncmp(media_description->s, "data", 4) == 0) {
+        type = AVP_IMS_Media_Type_Data;
+    } else if (strncmp(media_description->s, "application", 11) == 0) {
+        type = AVP_IMS_Media_Type_Application;
+    } else if (strncmp(media_description->s, "control", 7) == 0) {
+        type = AVP_IMS_Media_Type_Control;
+    } else if (strncmp(media_description->s, "text", 4) == 0) {
+        type = AVP_IMS_Media_Type_Text;
+    } else if (strncmp(media_description->s, "message", 7) == 0) {
+        type = AVP_IMS_Media_Type_Message;
+    } else {
+        type = AVP_IMS_Media_Type_Other;
+    }
+
+
+    set_4bytes(x, type);
+    media_type = cdpb.AAACreateAVP(AVP_IMS_Media_Type,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, x, 4,
+            AVP_DUPLICATE_DATA);
+    cdpb.AAAAddAVPToList(&list, media_type);
+
+    /*RR and RS*/
+
+    /*codec-data*/
+
+    if (dlg_direction == DLG_MOBILE_ORIGINATING) {
+        //0 means uplink offer
+        codec_data1 = rx_create_codec_data_avp(req_raw_payload, number, 0);
+        cdpb.AAAAddAVPToList(&list, codec_data1);
+        //3 means downlink answer
+        codec_data2 = rx_create_codec_data_avp(rpl_raw_payload, number, 3);
+        cdpb.AAAAddAVPToList(&list, codec_data2);
+    } else {
+        //2 means downlink offer
+        codec_data1 = rx_create_codec_data_avp(req_raw_payload, number, 2);
+        cdpb.AAAAddAVPToList(&list, codec_data1);
+        //1 means uplink answer
+        codec_data2 = rx_create_codec_data_avp(rpl_raw_payload, number, 1);
+        cdpb.AAAAddAVPToList(&list, codec_data2);
+
+    }
+
+
+    set_4bytes(x, AVP_IMS_Flow_Status_Enabled);
+    flow_status = cdpb.AAACreateAVP(AVP_IMS_Flow_Status,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, x, 4,
+            AVP_DUPLICATE_DATA);
+    cdpb.AAAAddAVPToList(&list, flow_status);
+
+    /*now group them in one big AVP and free them*/
+    data = cdpb.AAAGroupAVPS(list);
+    cdpb.AAAFreeAVPList(&list);
+    
+    
+    return rx_add_avp(msg, data.s, data.len, AVP_IMS_Media_Component_Description,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP,
+            AVP_FREE_DATA,
+            __FUNCTION__);
+}
+
+
+//just for registration to signalling path - much cut down MCD AVP
+//See 3GPP TS 29.214 section 4.4.5
+inline int rx_add_media_component_description_avp_register(AAAMessage *msg) {
+    str data;
+    AAA_AVP_LIST list;
+    AAA_AVP *media_component_number;
+
+    char x[4];
+
+    list.head = 0;
+    list.tail = 0;
+
+    /*media-component-number*/
+    set_4bytes(x, 0);
+    media_component_number = cdpb.AAACreateAVP(AVP_IMS_Media_Component_Number,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, x, 4,
+            AVP_DUPLICATE_DATA);
+
+    if (media_component_number != NULL) {
+        cdpb.AAAAddAVPToList(&list, media_component_number);
+    } else {
+        LM_ERR("Unable to create media_component_number AVP");
+        return 0;
+    }
+
+    /*media-sub-component*/
+    cdpb.AAAAddAVPToList(&list, rx_create_media_subcomponent_avp_register());
+  
+    /*now group them in one big AVP and free them*/
+    data = cdpb.AAAGroupAVPS(list);
+    cdpb.AAAFreeAVPList(&list);
+    return rx_add_avp(msg, data.s, data.len, AVP_IMS_Media_Component_Description,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP,
+            AVP_FREE_DATA,
+            __FUNCTION__);
+}
+
+
+/**
+ * Creates a media-sub-component AVP
+ * 
+ * TODO - fix this ... or just delete it and do it again! It adds 2x Flow-Description for example, as a bug!
+ * I don't think that more than 1 can be in one Media Subcomponent.
+ * 
+ * @param number - the flow number
+ * @param proto - the protocol of the IPFilterRule
+ * @param ipA - ip of the INVITE  (if creating rule for UE that sent INVITE)
+ * @param portA - port of the INVITE (if creating rule for UE that sent INVITE)
+ * @param ipB - ip of 200 OK (if creating rule for UE that sent INVITE)
+ * @param portB - port of 200 OK (if creating rule for UE that sent INVITE)
+ * @param options - any options to append to the IPFilterRules
+ * @param attributes - indication of attributes 
+ * 						0 no attributes , 1 sendonly , 2 recvonly , 3 RTCP flows, 4 AF signaling flows
+ * @param bwUL - bandwidth uplink
+ * @param bwDL - bandiwdth downlink
+ */
+
+static str permit_out = {"permit out ", 11};
+static str permit_in = {"permit in ", 10};
+static str from_s = {" from ", 6};
+static str to_s = {" to ", 4};
+static char * permit_out_with_ports = "permit out %i from %.*s %u to %.*s %u %s";
+static char * permit_in_with_ports = "permit in %i from %.*s %u to %.*s %u %s";
+
+AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
+        str *ipA, str *portA,
+        str *ipB, str *portB) {
+
+    str data;
+    int len, len2;
+    str flow_data = {0, 0};
+    str flow_data2 = {0, 0};
+    AAA_AVP *flow_description1 = 0, *flow_description2 = 0, *flow_number = 0;
+    AAA_AVP *flow_usage = 0;
+
+    AAA_AVP_LIST list;
+    list.tail = 0;
+    list.head = 0;
+    char x[4];
+    int proto_int = 0, proto_len = 0;
+
+    proto_int = 17;
+
+    int intportA = atoi(portA->s);
+    int intportB = atoi(portB->s);
+
+    len = (permit_out.len + from_s.len + to_s.len + ipB->len + ipA->len + 4 +
+            proto_len + portA->len + portB->len) * sizeof (char);
+
+    flow_data.s = (char*) pkg_malloc(len);
+    if (!flow_data.s) {
+        LM_ERR("PCC_create_media_component: out of memory \
+					when allocating %i bytes in pkg\n", len);
+        return NULL;
+    }
+
+    len2 = len - (permit_out.len - permit_in.len) * sizeof (char);
+    flow_data2.s = (char*) pkg_malloc(len2);
+    if (!flow_data2.s) {
+        LM_ERR("PCC_create_media_component: out of memory \
+					when allocating %i bytes in pkg\n", len);
+        pkg_free(flow_data.s);
+        flow_data.s = 0;
+        return NULL;
+    }
+
+    set_4bytes(x, number);
+
+    flow_number = cdpb.AAACreateAVP(AVP_IMS_Flow_Number,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, x, 4,
+            AVP_DUPLICATE_DATA);
+    cdpb.AAAAddAVPToList(&list, flow_number);
+
+    /*IMS Flow descriptions*/
+    /*first flow is the receive flow*/
+    flow_data.len = snprintf(flow_data.s, len, permit_out_with_ports, proto_int,
+            ipB->len, ipB->s, intportB,
+            ipA->len, ipA->s, intportA);
+
+    flow_data.len = strlen(flow_data.s);
+    flow_description1 = cdpb.AAACreateAVP(AVP_IMS_Flow_Description,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, flow_data.s, flow_data.len,
+            AVP_DUPLICATE_DATA);
+    cdpb.AAAAddAVPToList(&list, flow_description1);
+
+    /*second flow*/
+    flow_data2.len = snprintf(flow_data2.s, len2, permit_in_with_ports, proto_int,
+            ipA->len, ipA->s, intportA,
+            ipB->len, ipB->s, intportB);
+
+    flow_data2.len = strlen(flow_data2.s);
+    flow_description2 = cdpb.AAACreateAVP(AVP_IMS_Flow_Description,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, flow_data2.s, flow_data2.len,
+            AVP_DUPLICATE_DATA);
+    cdpb.AAAAddAVPToList(&list, flow_description2);
+
+    set_4bytes(x, AVP_EPC_Flow_Usage_No_Information);
+    flow_usage = cdpb.AAACreateAVP(AVP_IMS_Flow_Usage,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, x, 4,
+            AVP_DUPLICATE_DATA);
+    cdpb.AAAAddAVPToList(&list, flow_usage);
+
+    /*group all AVPS into one big.. and then free the small ones*/
+
+    data = cdpb.AAAGroupAVPS(list);
+
+
+    cdpb.AAAFreeAVPList(&list);
+    pkg_free(flow_data.s);
+    flow_data.s = 0;
+    pkg_free(flow_data2.s);
+    flow_data2.s = 0;
+
+    return (cdpb.AAACreateAVP(AVP_IMS_Media_Sub_Component,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, data.s, data.len,
+            AVP_FREE_DATA));
+}
+
+
+//just for registration to signalling status much cut down MSC AVP
+//see 3GPP TS 29.214 4.4.5
+
+AAA_AVP *rx_create_media_subcomponent_avp_register() {
+
+    char x[4];
+
+    AAA_AVP *flow_usage = 0;
+    AAA_AVP *flow_number = 0;
+    
+    str data;
+    AAA_AVP_LIST list;
+    list.tail = 0;
+    list.head = 0;
+    
+    //always set to zero for subscription to signalling status
+    set_4bytes(x, 0);
+
+    flow_number = cdpb.AAACreateAVP(AVP_IMS_Flow_Number,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, x, 4,
+            AVP_DUPLICATE_DATA);
+    cdpb.AAAAddAVPToList(&list, flow_number);
+
+    set_4bytes(x, AVP_EPC_Flow_Usage_AF_Signaling);
+    
+    flow_usage = cdpb.AAACreateAVP(AVP_IMS_Flow_Usage,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, x, 4,
+            AVP_DUPLICATE_DATA);
+    cdpb.AAAAddAVPToList(&list, flow_usage);
+
+    /*group all AVPS into one big.. and then free the small ones*/
+
+    data = cdpb.AAAGroupAVPS(list);
+
+    cdpb.AAAFreeAVPList(&list);
+
+    return (cdpb.AAACreateAVP(AVP_IMS_Media_Sub_Component,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, data.s, data.len,
+            AVP_FREE_DATA));
+}
+
+/*
+ * Creates a Codec-Data AVP as defined in TS29214 (Rx interface)
+ * @param sdp - sdp body of message
+ * @param number - the number of the m= line being used
+ * @param direction - 0 means uplink offer 1 means uplink answer ,
+ * 	2 means downlink offer , 3 downlink answer
+ * returns NULL on failure or the pointer to the AAA_AVP on success
+ * (this AVP should be freed!)
+ */
+
+AAA_AVP* rx_create_codec_data_avp(str *raw_sdp_stream, int number, int direction) {
+    char data[PCC_MAX_Char4];
+    char *p;
+    int l, len;
+
+    switch (direction) {
+
+        case 0: sprintf(data, "uplink\noffer\n");
+            break;
+        case 1: sprintf(data, "uplink\nanswer\n");
+            break;
+        case 2: sprintf(data, "downlink\noffer\n");
+            break;
+        case 3: sprintf(data, "downlink\nanswer\n");
+            break;
+        default:
+            break;
+
+    }
+
+    l = strlen(data);
+
+    if ((l + raw_sdp_stream->len) >= PCC_MAX_Char4) {
+        len = PCC_MAX_Char4 - l - 1;
+    } else {
+        len = raw_sdp_stream->len;
+    }
+
+    memcpy(data + l, raw_sdp_stream->s, len);
+    p = data + l + len;
+    *p = '\0';
+
+    return (cdpb.AAACreateAVP(AVP_IMS_Codec_Data,
+            AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
+            IMS_vendor_id_3GPP, data, strlen(data),
+            AVP_DUPLICATE_DATA));
+
+}
+
+
+/**
+ * Creates and adds a Vendor Specific Application ID Group AVP.
+ * @param msg - the Diameter message to add to.
+ * @param vendor_id - the value for the vendor id AVP
+ * @param auth_app_id - the value of the authentication application AVP
+ * @returns 1 on success or 0 on error
+ */
+int rx_add_vendor_specific_application_id_group(AAAMessage * msg, uint32_t vendor_id, uint32_t auth_app_id) {
+    return cdp_avp->base.add_Vendor_Specific_Application_Id_Group(&(msg->avpList), vendor_id, auth_app_id, 0);
+}
+
+/**
+ * Returns the Result-Code AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+unsigned int rx_get_abort_cause(AAAMessage *msg) {
+    AAA_AVP *avp = 0;
+    unsigned int code = 0;
+    //getting abort cause
+    avp = cdpb.AAAFindMatchingAVP(msg, msg->avpList.head, AVP_IMS_Abort_Cause, IMS_vendor_id_3GPP, AAA_FORWARD_SEARCH);
+    if (avp) {
+        code = get_4bytes(avp->data.s);
+    }
+    return code;
+}
+
+/**
+ * Returns the Result-Code AVP from a Diameter message.
+ * or the Experimental-Result-Code if there is no Result-Code , because .. who cares
+ * @param msg - the Diameter message
+ * @returns 1 if result code found or 0 if error
+ */
+inline int rx_get_result_code(AAAMessage *msg, unsigned int *data) {
+
+    AAA_AVP *avp;
+    AAA_AVP_LIST list;
+    list.head = 0;
+    list.tail = 0;
+    *data = 0;
+    int ret = 0;
+
+    for (avp = msg->avpList.tail; avp; avp = avp->prev) {
+        //LOG(L_INFO,"pcc_get_result_code: looping with avp code %i\n",avp->code);
+        if (avp->code == AVP_Result_Code) {
+            *data = get_4bytes(avp->data.s);
+            ret = 1;
+
+        } else if (avp->code == AVP_Experimental_Result) {
+            list = cdpb.AAAUngroupAVPS(avp->data);
+            for (avp = list.head; avp; avp = avp->next) {
+                //LOG(L_CRIT,"in the loop with avp code %i\n",avp->code);
+                if (avp->code == AVP_IMS_Experimental_Result_Code) {
+                    *data = get_4bytes(avp->data.s);
+                    cdpb.AAAFreeAVPList(&list);
+                    ret = 1;
+                    break;
+                }
+            }
+            cdpb.AAAFreeAVPList(&list);
+            break; // this has to be here because i have changed the avp!!!
+
+        }
+
+    }
+    return ret;
+}
+
+

+ 93 - 0
modules/ims_qos/rx_avp.h

@@ -0,0 +1,93 @@
+/*
+ * $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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+
+#ifndef __PCC_AVP_H
+#define __PCC_AVP_H
+
+
+#define PCC_MAX_Char 64
+#define PCC_MAX_Char4 256
+/* Maximum Number of characters to represent some AVP datas*/
+/*and ipv6 addresses in character*/
+#define PCC_Media_Sub_Components 10
+
+
+struct AAA_AVP_List;
+struct AAAMessage;
+enum dialog_direction;
+
+/*helper*/
+int rx_add_framed_ip_avp(AAA_AVP_LIST * list, str ip, uint16_t version);
+
+int rx_add_avp(AAAMessage *m, char *d, int len, int avp_code,
+        int flags, int vendorid, int data_do, const char *func);
+
+int rx_add_vendor_specific_application_id_group(AAAMessage *msg, unsigned int vendorid, unsigned int auth_app_id);
+int rx_add_destination_realm_avp(AAAMessage *msg, str data);
+inline int rx_add_subscription_id_avp(AAAMessage *msg, str identifier, int identifier_type);
+inline int rx_add_auth_application_id_avp(AAAMessage *msg, unsigned int data);
+
+inline int rx_add_media_component_description_avp(AAAMessage *msg, int number, str *media_description, str *ipA, str *portA, str *ipB, str *portB, str *transport, 
+        str *raw_payload, str *rpl_raw_payload, enum dialog_direction dlg_direction);
+
+inline int rx_add_media_component_description_avp_register(AAAMessage *msg);
+
+AAA_AVP *rx_create_media_subcomponent_avp(int number, char *proto, str *ipA, str *portA, str *ipB, str *portB);
+
+AAA_AVP *rx_create_media_subcomponent_avp_register();
+
+AAA_AVP* rx_create_codec_data_avp(str *raw_sdp_stream, int number, int direction);
+
+inline int rx_get_result_code(AAAMessage *msg, unsigned int *data);
+unsigned int rx_get_abort_cause(AAAMessage *msg);
+
+
+#endif /*__PCC_AVP_H*/

+ 170 - 0
modules/ims_qos/rx_str.c

@@ -0,0 +1,170 @@
+/*
+ * $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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+
+
+#include "../cdp_avp/mod_export.h"
+#include "../../modules/dialog_ng/dlg_load.h"
+#include "../ims_usrloc_pcscf/usrloc.h"
+#include "rx_authdata.h"
+#include "mod.h"
+#include "rx_avp.h"
+#include "rx_str.h"
+
+extern str IMS_Serv_AVP_val;
+
+int rx_send_str(str *rx_session_id) {
+
+    
+    LM_DBG("Sending STR\n");
+
+    AAASession *auth = 0;
+    AAAMessage *str = NULL;
+
+    AAA_AVP * avp = NULL;
+
+    if (!rx_session_id || !rx_session_id->s || !rx_session_id->len) {
+        LM_ERR("Dialog has no Rx session associated\n");
+        return RX_RETURN_FALSE;
+    }else
+    {
+        LM_DBG("Rx session id exists\n");
+    }
+
+    
+    LM_DBG("About to try get Auth session\n");
+    auth = cdpb.AAAGetAuthSession(*rx_session_id);
+    if (!auth) {
+        LM_ERR("Could not get Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
+        return RX_RETURN_FALSE;
+    }else{
+        LM_DBG("Retrieved Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
+    }
+    
+    LM_DBG("Got auth session\n");
+    
+    LM_DBG("dest host [%.*s]\n", auth->dest_host.len, auth->dest_host.s);
+    LM_DBG("dest realm [%.*s]\n", auth->dest_realm.len, auth->dest_realm.s);
+    LM_DBG("id [%.*s]\n", auth->id.len, auth->id.s);
+    
+    //create STR
+
+    char x[4];
+
+    LM_DBG("Checking auth state\n");
+
+    if (auth->u.auth.state == AUTH_ST_DISCON) {
+        // If we are in DISCON is because an STR was already sent
+        // so just wait for STA or for Grace Timout to happen
+        LM_DBG("Hmmm, auth session already in disconnected state\n");
+        goto error;
+    }
+
+    LM_DBG("Creating STR\n");
+    str = cdpb.AAACreateRequest(IMS_Rx, IMS_STR, Flag_Proxyable, auth);
+
+    if (!str) {
+        LM_ERR("Unable to create STR request\n");
+        goto error;
+    }
+
+    LM_DBG("Adding Auth app id\n");
+    /* Add Auth-Application-Id AVP */
+    if (!rx_add_auth_application_id_avp(str, IMS_Rx)) goto error;
+    if (!rx_add_vendor_specific_application_id_group(str, IMS_vendor_id_3GPP, IMS_Rx)) goto error;
+
+
+    LM_DBG("Adding destination realm\n");
+    /* Add Destination-Realm AVP, if not already there */
+    avp = cdpb.AAAFindMatchingAVP(str, str->avpList.head, AVP_Destination_Realm, 0, AAA_FORWARD_SEARCH);
+    if (!avp) {
+        if (rx_dest_realm.len && !rx_add_destination_realm_avp(str, rx_dest_realm)) goto error;
+    }
+
+    LM_DBG("Adding AF app id\n");
+    /* Add AF-Application-Identifier AVP */
+    if (!rx_add_avp(str, IMS_Serv_AVP_val.s, IMS_Serv_AVP_val.len,
+            AVP_IMS_AF_Application_Identifier,
+            AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP,
+            AVP_DUPLICATE_DATA, __FUNCTION__)) goto error;
+
+
+    LM_DBG("Adding Termination cause\n");
+    /* Termination-Cause */
+    set_4bytes(x, 1);
+    if (!rx_add_avp(str, x, 4, AVP_Termination_Cause,
+            AAA_AVP_FLAG_MANDATORY, 0,
+            AVP_DUPLICATE_DATA, __FUNCTION__)) goto error;
+
+    
+    LM_DBG("Unlocking AAA session...\n");
+    cdpb.AAASessionsUnlock(auth->hash);
+    
+    LM_DBG("sending STR to PCRF\n");
+    if (rx_forced_peer.len)
+        cdpb.AAASendMessageToPeer(str, &rx_forced_peer , NULL, NULL);
+    else
+        cdpb.AAASendMessage(str, NULL, NULL);
+
+    LM_DBG("Successfully sent Rx STR for session: [%.*s]\n", rx_session_id->len, rx_session_id->s);
+
+    return RX_RETURN_TRUE;
+
+error:
+    LM_DBG("Error sending Rx STR for session: [%.*s]\n", rx_session_id->len, rx_session_id->s);
+    if (str) cdpb.AAAFreeMessage(&str);
+    if (auth) {
+        cdpb.AAASessionsUnlock(auth->hash);
+        cdpb.AAADropAuthSession(auth);
+        auth = 0;
+    }
+
+    return RX_RETURN_FALSE;
+}

+ 62 - 0
modules/ims_qos/rx_str.h

@@ -0,0 +1,62 @@
+/*
+ * $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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+#ifndef RX_STR_H
+#define RX_STR_H
+
+/* the destination realm*/
+extern str rx_dest_realm;
+extern str rx_forced_peer;
+
+int rx_send_str(str *rx_session_id);
+
+
+#endif
+

+ 90 - 0
modules/ims_qos/sem.h

@@ -0,0 +1,90 @@
+/*
+ * $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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+#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

+ 76 - 0
modules/ims_qos/stats.c

@@ -0,0 +1,76 @@
+/*
+ * $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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+#include "stats.h"
+
+int register_stats() {
+	//AAR
+	if (register_stat(MOD_NAME, "aar_replies_response_time", &aar_replies_response_time,0 )
+			!= 0) {
+		LM_ERR("failed to register stat\n");
+		return -1;
+	}
+	if (register_stat(MOD_NAME, "aar_replies_received", &aar_replies_received, 0)
+			!= 0) {
+		LM_ERR("failed to register stat\n");
+		return -1;
+	}
+
+	return 1;
+}
+
+unsigned long get_avg_aar_response_time() {
+
+	long rpls_received = get_stat_val(aar_replies_received);
+	if (!rpls_received)
+		return 0;
+
+	return get_stat_val(aar_replies_response_time)/rpls_received;
+}

+ 63 - 0
modules/ims_qos/stats.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
+ * 
+ *
+ *
+ * History:
+ * --------
+ *  2011-02-02  initial version (jason.penton)
+ */
+
+#ifndef STATISTICS_H_
+#define STATISTICS_H_
+
+#include "../../lib/kcore/statistics.h"
+
+stat_var* stat_aar_timeouts;
+stat_var* aar_replies_received;
+stat_var* aar_replies_response_time;
+
+int register_stats();
+unsigned long get_avg_aar_response_time();
+
+#endif /* STATISTICS_H_ */