all: updated FSF address in GPL text
[sip-router] / modules / ims_registrar_pcscf / ul_callback.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
5  * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
6  * 
7  * The initial version of this code was written by Dragos Vingarzan
8  * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
9  * Fruanhofer Institute. It was and still is maintained in a separate
10  * branch of the original SER. We are therefore migrating it to
11  * Kamailio/SR and look forward to maintaining it from here on out.
12  * 2011/2012 Smile Communications, Pty. Ltd.
13  * ported/maintained/improved by 
14  * Jason Penton (jason(dot)penton(at)smilecoms.com and
15  * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
16  * effort to add full IMS support to Kamailio/SR using a new and
17  * improved architecture
18  * 
19  * NB: Alot of this code was originally part of OpenIMSCore,
20  * FhG Fokus. 
21  * Copyright (C) 2004-2006 FhG Fokus
22  * Thanks for great work! This is an effort to 
23  * break apart the various CSCF functions into logically separate
24  * components. We hope this will drive wider use. We also feel
25  * that in this way the architecture is more complete and thereby easier
26  * to manage in the Kamailio/SR environment
27  *
28  * This file is part of Kamailio, a free SIP server.
29  *
30  * Kamailio is free software; you can redistribute it and/or modify
31  * it under the terms of the GNU General Public License as published by
32  * the Free Software Foundation; either version 2 of the License, or
33  * (at your option) any later version
34  *
35  * Kamailio is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  * GNU General Public License for more details.
39  *
40  * You should have received a copy of the GNU General Public License 
41  * along with this program; if not, write to the Free Software 
42  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
43  * 
44  */
45
46 #include "ul_callback.h"
47 #include "../pua/pua.h"
48 #include "../pua/send_publish.h"
49
50 #include "../pua/pua_bind.h"
51
52 #include <libxml/parser.h>
53
54 /*
55 Contact: <sip:carsten@10.157.87.36:44733;transport=udp>;expires=600000;+g.oma.sip-im;language="en,fr";+g.3gpp.smsip;+g.oma.sip-im.large-message;audio;+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-application.ims.iari.gsma-vs";+g.3gpp.cs-voice.
56 Call-ID: 9ad9f89f-164d-bb86-1072-52e7e9eb5025.
57 */
58
59 /*<?xml version="1.0"?>
60 <reginfo xmlns="urn:ietf:params:xml:ns:reginfo" version="0" state="full">
61 .<registration aor="sip:carsten@ng-voice.com" id="0xb33fa860" state="active">
62 ..<contact id="0xb33fa994" state="active" event="registered" expires="3600">
63 ...<uri>sip:carsten@10.157.87.36:43582;transport=udp</uri>
64 ...<unknown-param name="+g.3gpp.cs-voice"></unknown-param>
65 ...<unknown-param name="+g.3gpp.icsi-ref">urn0X0.0041FB74E7B54P-1022urn-70X0P+03gpp-application.ims.iari.gsma-vs</unknown-param>
66 ...<unknown-param name="audio"></unknown-param>
67 ...<unknown-param name="+g.oma.sip-im.large-message"></unknown-param>
68 ...<unknown-param name="+g.3gpp.smsip"></unknown-param>
69 ...<unknown-param name="language">en,fr</unknown-param>
70 ...<unknown-param name="+g.oma.sip-im"></unknown-param>
71 ...<unknown-param name="expires">600000</unknown-param>
72 ..</contact>
73 .</registration>
74 </reginfo> */
75
76 extern pua_api_t pua;
77 extern char* pcscf_uri;
78 extern int publish_reginfo;
79
80 /* methods for building reg publish */
81 str* build_reginfo_partial(ppublic_t *impu, struct pcontact* c, int type) {
82         xmlDocPtr doc = NULL;
83         xmlNodePtr root_node = NULL;
84         xmlNodePtr registration_node = NULL;
85         xmlNodePtr contact_node = NULL;
86         xmlNodePtr uri_node = NULL;
87         str * body = NULL;
88         char buf[512];
89
90         /* create the XML-Body */
91         doc = xmlNewDoc(BAD_CAST "1.0");
92         if (doc == 0) {
93                 LM_ERR("Unable to create XML-Doc\n");
94                 return NULL;
95         }
96
97         root_node = xmlNewNode(NULL, BAD_CAST "reginfo");
98         if (root_node == 0) {
99                 LM_ERR("Unable to create reginfo-XML-Element\n");
100                 return NULL;
101         }
102         /* This is our Root-Element: */
103         xmlDocSetRootElement(doc, root_node);
104
105         xmlNewProp(root_node, BAD_CAST "xmlns", BAD_CAST "urn:ietf:params:xml:ns:reginfo");
106
107         /* we set the version to 0 but it should be set to the correct value in the pua module */
108         xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0");
109         xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "partial" );
110
111         /* Registration Node */
112         registration_node = xmlNewChild(root_node, NULL, BAD_CAST "registration", NULL);
113         if (registration_node == NULL) {
114                 LM_ERR("while adding child\n");
115                 goto error;
116         }
117
118         /* Add the properties to this Node for AOR and ID: */
119         //registration aor nodes
120         memset(buf, 0, sizeof(buf));
121         snprintf(buf, sizeof(buf), "%.*s", impu->public_identity.len, impu->public_identity.s);
122         xmlNewProp(registration_node, BAD_CAST "aor", BAD_CAST buf);
123         
124         //registration id
125         memset(buf, 0, sizeof(buf));
126         snprintf(buf, sizeof(buf), "%p", impu);
127         xmlNewProp(registration_node, BAD_CAST "id", BAD_CAST buf);
128
129         //now the updated contact
130         contact_node =xmlNewChild(registration_node, NULL, BAD_CAST "contact", NULL);
131         if (contact_node == NULL) {
132                 LM_ERR("while adding child\n");
133                 goto error;
134         }
135         memset(buf, 0, sizeof(buf));
136         snprintf(buf, sizeof(buf), "%p", c);
137         xmlNewProp(contact_node, BAD_CAST "id", BAD_CAST buf);
138
139         //TODO: currently we only support publish of termination for event unregistered and expires 0
140         xmlNewProp(contact_node, BAD_CAST "state", BAD_CAST "terminated");
141         xmlNewProp(contact_node, BAD_CAST "event", BAD_CAST "unregistered");
142         memset(buf, 0, sizeof(buf));
143         snprintf(buf, sizeof(buf), "%i", 0);
144         xmlNewProp(contact_node, BAD_CAST "expires", BAD_CAST buf);
145
146         /* URI-Node */
147         memset(buf, 0, sizeof(buf));
148         snprintf(buf, sizeof(buf), "%.*s", c->aor.len, c->aor.s);
149         uri_node = xmlNewChild(contact_node, NULL, BAD_CAST "uri", BAD_CAST buf);
150         if (uri_node == NULL) {
151                 LM_ERR("while adding child\n");
152                 goto error;
153         }
154
155         /* create the body */
156         body = (str*) pkg_malloc(sizeof(str));
157         if (body == NULL) {
158                 LM_ERR("while allocating memory\n");
159                 return NULL;
160         }
161         memset(body, 0, sizeof(str));
162
163         /* Write the XML into the body */
164         xmlDocDumpFormatMemory(doc, (unsigned char**) (void*) &body->s, &body->len,
165                         1);
166
167         /*free the document */
168         xmlFreeDoc(doc);
169         xmlCleanupParser();
170
171         return body;
172
173 error:
174         if (body) {
175                 if (body->s)
176                         xmlFree(body->s);
177                 pkg_free(body);
178         }
179         if (doc)
180                 xmlFreeDoc(doc);
181         return NULL;
182
183 }
184
185 #define P_ASSERTED_IDENTITY_HDR_PREFIX  "P-Asserted-Identity: <"
186 int send_partial_publish(ppublic_t *impu, struct pcontact *c, int type)
187 {
188         publ_info_t publ;
189         str content_type;
190         int id_buf_len;
191         char id_buf[512];
192         str server_address = {pcscf_uri, strlen(pcscf_uri)};
193         str p_asserted_identity_header;
194
195         content_type.s = "application/reginfo+xml";
196         content_type.len = 23;
197         
198         int len = strlen(P_ASSERTED_IDENTITY_HDR_PREFIX) + server_address.len + 1 + CRLF_LEN;
199         p_asserted_identity_header.s = (char *)pkg_malloc( len );
200         if ( p_asserted_identity_header.s == NULL ) {
201             LM_ERR( "insert_asserted_identity: pkg_malloc %d bytes failed", len );
202             goto error;
203         }
204         
205         memcpy(p_asserted_identity_header.s, P_ASSERTED_IDENTITY_HDR_PREFIX, strlen(P_ASSERTED_IDENTITY_HDR_PREFIX));
206         p_asserted_identity_header.len = strlen(P_ASSERTED_IDENTITY_HDR_PREFIX);
207         memcpy(p_asserted_identity_header.s + p_asserted_identity_header.len, server_address.s, server_address.len);
208         p_asserted_identity_header.len += server_address.len;
209         *(p_asserted_identity_header.s + p_asserted_identity_header.len) = '>';
210         p_asserted_identity_header.len ++;
211         memcpy( p_asserted_identity_header.s + p_asserted_identity_header.len, CRLF, CRLF_LEN );
212         p_asserted_identity_header.len += CRLF_LEN;
213         
214         LM_DBG("p_asserted_identity_header: [%.*s]", p_asserted_identity_header.len, p_asserted_identity_header.s);
215         
216         LM_DBG("Sending publish\n");
217         str *body = build_reginfo_partial(impu, c, type);
218
219         if (body == NULL || body->s == NULL) {
220                 LM_ERR("Error on creating XML-Body for publish\n");
221                 goto error;
222         }
223         LM_DBG("XML-Body:\n%.*s\n", body->len, body->s);
224
225         memset(&publ, 0, sizeof(publ_info_t));
226         publ.pres_uri = &impu->public_identity;
227         publ.body = body;
228         id_buf_len = snprintf(id_buf, sizeof(id_buf), "IMSPCSCF_PUBLISH.%.*s", c->aor.len, c->aor.s);
229         publ.id.s = id_buf;
230         publ.id.len = id_buf_len;
231         publ.content_type = content_type;
232         publ.expires = 3600;
233
234         /* make UPDATE_TYPE, as if this "publish dialog" is not found
235          by pua it will fallback to INSERT_TYPE anyway */
236         publ.flag |= UPDATE_TYPE;
237         publ.source_flag |= REGINFO_PUBLISH;
238         publ.event |= REGINFO_EVENT;
239         publ.extra_headers = &p_asserted_identity_header;
240
241         if (pua.send_publish(&publ) < 0) {
242                 LM_ERR("Error while sending publish\n");
243         }
244         if (p_asserted_identity_header.s) {
245                 pkg_free(p_asserted_identity_header.s);
246         }
247         
248         return 1;
249
250 error:
251         
252         if (p_asserted_identity_header.s) {
253                 pkg_free(p_asserted_identity_header.s);
254         }
255         if (body) {
256                 if (body->s)
257                         xmlFree(body->s);
258                 pkg_free(body);
259         }
260         return -1;
261 }
262
263 void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param) {
264         ppublic_t *ptr;
265
266         LM_DBG("----------------------!\n");
267         LM_DBG("PCSCF Contact Callback in regsitrar!\n");
268         LM_DBG("Contact AOR: [%.*s]\n", c->aor.len, c->aor.s);
269         LM_DBG("Callback type [%d]\n", type);
270         LM_DBG("Reg state [%d]\n", c->reg_state);
271
272         if ((type&PCSCF_CONTACT_UPDATE)) {
273                 //send publish for each associated IMPU
274                 ptr = c->head;
275                         while (ptr) {
276                                 if (c->reg_state == PCONTACT_DEREG_PENDING_PUBLISH && publish_reginfo) {
277                                         LM_DBG("delete/update on contact <%.*s> associated with IMPU <%.*s> (sending publish)\n",
278                                                                                         c->aor.len, c->aor.s,
279                                                                                         ptr->public_identity.len, ptr->public_identity.s);
280                                         if (ptr->public_identity.len > 4 && strncasecmp(ptr->public_identity.s,"tel:",4)==0) {
281                                             LM_DBG("This is a tel URI - it is not routable so we don't publish for it");
282                                         }else{
283                                             send_partial_publish(ptr, c, type);
284                                         }
285                                 }
286
287                                 ptr = ptr->next;
288                         }
289
290         }
291 }
292