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 <time.h>
47 #include "async_reginfo.h"
48 #include "../pua/pua.h"
49 #include "../pua/send_publish.h"
50
51 #include "../pua/pua_bind.h"
52
53 extern pua_api_t pua;
54 extern int reginfo_queue_size_threshold;
55 reginfo_event_list_t *reginfo_event_list = 0;
56
init_reginfo_event_list()57 int init_reginfo_event_list()
58 {
59 if (reginfo_event_list)
60 return 1;
61
62 reginfo_event_list = shm_malloc(sizeof(reginfo_event_list_t));
63 if (!reginfo_event_list) {
64 LM_ERR("No more SHM mem\n");
65 return 0;
66 }
67 memset(reginfo_event_list, 0, sizeof(reginfo_event_list_t));
68 reginfo_event_list->lock = lock_alloc();
69 if (!reginfo_event_list->lock) {
70 LM_ERR("failed to create reginfo event list lock\n");
71 return 0;
72 }
73 reginfo_event_list->lock = lock_init(reginfo_event_list->lock);
74 reginfo_event_list->size = 0;
75
76 sem_new(reginfo_event_list->empty, 0); //pre-locked - as we assume list is empty at start
77
78 return 1;
79 }
destroy_reginfo_event_list()80 void destroy_reginfo_event_list()
81 {
82 reginfo_event_t *ev, *tmp;
83
84 lock_get(reginfo_event_list->lock);
85 ev = reginfo_event_list->head;
86 while (ev) {
87 tmp = ev->next;
88 free_reginfo_event(ev);
89 ev = tmp;
90 }
91 lock_destroy(reginfo_event_list->lock);
92 lock_dealloc(reginfo_event_list->lock);
93 shm_free(reginfo_event_list);
94 }
95
new_reginfo_event(int event,str * publ_body,str * publ_id,str * publ_content_type,str * subs_remote_target,str * subs_watcher_uri,str * subs_contact,str * subs_outbound_proxy,int expires,int flag,int source_flag,int reg_info_event,str * extra_headers,str * pres_uri)96 reginfo_event_t* new_reginfo_event (int event, str *publ_body, str *publ_id, str *publ_content_type, str *subs_remote_target, str *subs_watcher_uri,
97 str *subs_contact, str *subs_outbound_proxy, int expires, int flag, int source_flag, int reg_info_event, str *extra_headers, str *pres_uri)
98 {
99 char *p;
100 int len;
101 reginfo_event_t *new_event;
102
103 len = sizeof(reginfo_event_t);
104 if(publ_body){
105 len += publ_body->len;
106 }
107 if(publ_id){
108 len += publ_id->len;
109 }
110 if(publ_content_type){
111 len += publ_content_type->len;
112 }
113 if(subs_remote_target){
114 len += subs_remote_target->len;
115 }
116 if(subs_watcher_uri){
117 len += subs_watcher_uri->len;
118 }
119 if(subs_contact){
120 len += subs_contact->len;
121 }
122 if(subs_outbound_proxy){
123 len += subs_outbound_proxy->len;
124 }
125 if(extra_headers){
126 len += extra_headers->len;
127 }
128 if(pres_uri){
129 len += pres_uri->len;
130 }
131
132 LM_DBG("Shm alloc'ing %d for new reg info event\n", len);
133 new_event = (reginfo_event_t*) shm_malloc(len);
134
135 if (!new_event) {
136 LM_ERR("No more shm mem\n");
137 return NULL;
138 }
139 memset(new_event, 0, len);
140
141 p = (char*) (new_event + 1);
142
143 if(publ_body) {
144 LM_DBG("publ_body [%.*s]\n", publ_body->len, publ_body->s);
145 new_event->publ_body.s = p;
146 new_event->publ_body.len = publ_body->len;
147 memcpy(p, publ_body->s, publ_body->len);
148 p += publ_body->len;
149 }
150 if(publ_id) {
151 LM_DBG("publ_id [%.*s]\n", publ_id->len, publ_id->s);
152 new_event->publ_id.s = p;
153 new_event->publ_id.len = publ_id->len;
154 memcpy(p, publ_id->s, publ_id->len);
155 p += publ_id->len;
156 }
157 if(publ_content_type) {
158 LM_DBG("publ_content_type [%.*s]\n", publ_content_type->len, publ_content_type->s);
159 new_event->publ_content_type.s = p;
160 new_event->publ_content_type.len = publ_content_type->len;
161 memcpy(p, publ_content_type->s, publ_content_type->len);
162 p += publ_content_type->len;
163 }
164 if(subs_remote_target) {
165 LM_DBG("subs_remote_target [%.*s]\n", subs_remote_target->len, subs_remote_target->s);
166 new_event->subs_remote_target.s = p;
167 new_event->subs_remote_target.len = subs_remote_target->len;
168 memcpy(p, subs_remote_target->s, subs_remote_target->len);
169 p += subs_remote_target->len;
170 }
171 if(subs_watcher_uri) {
172 LM_DBG("subs_watcher_uri [%.*s]\n", subs_watcher_uri->len, subs_watcher_uri->s);
173 new_event->subs_watcher_uri.s = p;
174 new_event->subs_watcher_uri.len = subs_watcher_uri->len;
175 memcpy(p, subs_watcher_uri->s, subs_watcher_uri->len);
176 p += subs_watcher_uri->len;
177 }
178 if(subs_contact) {
179 LM_DBG("subs_contact [%.*s]\n", subs_contact->len, subs_contact->s);
180 new_event->subs_contact.s = p;
181 new_event->subs_contact.len = subs_contact->len;
182 memcpy(p, subs_contact->s, subs_contact->len);
183 p += subs_contact->len;
184 }
185 if(subs_outbound_proxy) {
186 LM_DBG("subs_outbound_proxy [%.*s]\n", subs_outbound_proxy->len, subs_outbound_proxy->s);
187 new_event->subs_outbound_proxy.s = p;
188 new_event->subs_outbound_proxy.len = subs_outbound_proxy->len;
189 memcpy(p, subs_outbound_proxy->s, subs_outbound_proxy->len);
190 p += subs_outbound_proxy->len;
191 }
192 if(extra_headers) {
193 LM_DBG("extra_headers [%.*s]\n", extra_headers->len, extra_headers->s);
194 new_event->extra_headers.s = p;
195 new_event->extra_headers.len = extra_headers->len;
196 memcpy(p, extra_headers->s, extra_headers->len);
197 p += extra_headers->len;
198 }
199 if(pres_uri) {
200 LM_DBG("pres_uri [%.*s]\n", pres_uri->len, pres_uri->s);
201 new_event->pres_uri.s = p;
202 new_event->pres_uri.len = pres_uri->len;
203 memcpy(p, pres_uri->s, pres_uri->len);
204 p += pres_uri->len;
205 }
206
207 if (p != (((char*) new_event) + len)) {
208 LM_CRIT("buffer overflow\n");
209 shm_free(new_event);
210 return 0;
211 }
212
213 new_event->expires = expires;
214 new_event->flag = flag;
215 new_event->reg_info_event = reg_info_event;
216 new_event->sourge_flag = source_flag;
217
218 new_event->registered = time(NULL);
219 new_event->event = event;
220 new_event->next = 0;
221
222 return new_event;
223 }
224
push_reginfo_event(reginfo_event_t * event)225 void push_reginfo_event(reginfo_event_t* event)
226 {
227 lock_get(reginfo_event_list->lock);
228 if (reginfo_event_list->head == 0) { //empty list
229 reginfo_event_list->head = reginfo_event_list->tail = event;
230 } else {
231 reginfo_event_list->tail->next = event;
232 reginfo_event_list->tail = event;
233 }
234 reginfo_event_list->size++;
235
236 if(reginfo_queue_size_threshold > 0 && reginfo_event_list->size > reginfo_queue_size_threshold) {
237 LM_WARN("Reginfo queue is size [%d] and has exceed reginfo_queue_size_threshold of [%d]", reginfo_event_list->size, reginfo_queue_size_threshold);
238 }
239
240 sem_release(reginfo_event_list->empty);
241 lock_release(reginfo_event_list->lock);
242 }
243
pop_reginfo_event()244 reginfo_event_t* pop_reginfo_event()
245 {
246 reginfo_event_t *ev;
247
248 // Make sure, it's initialized:
249 init_reginfo_event_list();
250
251 lock_get(reginfo_event_list->lock);
252 while (reginfo_event_list->head == 0) {
253 lock_release(reginfo_event_list->lock);
254 sem_get(reginfo_event_list->empty);
255 lock_get(reginfo_event_list->lock);
256 }
257
258 ev = reginfo_event_list->head;
259 reginfo_event_list->head = ev->next;
260
261 if (ev == reginfo_event_list->tail) { //list now empty
262 reginfo_event_list->tail = 0;
263 }
264 ev->next = 0; //make sure whoever gets this cant access our list
265
266 reginfo_event_list->size--;
267
268 lock_release(reginfo_event_list->lock);
269
270 return ev;
271 }
272
free_reginfo_event(reginfo_event_t * ev)273 void free_reginfo_event(reginfo_event_t* ev)
274 {
275 if (ev) {
276 LM_DBG("Freeing reginfo event structure\n");
277 shm_free(ev);
278 }
279 }
280
reginfo_event_process()281 void reginfo_event_process()
282 {
283 publ_info_t publ;
284 subs_info_t subs;
285 reginfo_event_t *ev;
286 for (;;) {
287 LM_DBG("POPPING REGINFO EVENT\n");
288 ev = pop_reginfo_event();
289 LM_DBG("PROCESSING REGINFO EVENT with event [%d]\n", ev->event);
290
291 switch (ev->event) {
292 case REG_EVENT_PUBLISH:
293 LM_DBG("Sending out-of-band publish with pres_uri [%.*s] publ_id [%.*s] publ_content_type [%.*s] extra_headers [%.*s]"
294 "expires [%d] event [%d]\n",
295 ev->pres_uri.len, ev->pres_uri.s, ev->publ_id.len, ev->publ_id.s, ev->publ_content_type.len, ev->publ_content_type.s,
296 ev->extra_headers.len, ev->extra_headers.s, ev->expires, ev->reg_info_event);
297 LM_DBG("publ_body [%.*s] \n",
298 ev->publ_body.len, ev->publ_body.s);
299
300 memset(&publ, 0, sizeof(publ_info_t));
301 publ.pres_uri = &ev->pres_uri;
302 publ.body = &ev->publ_body;
303 publ.id = ev->publ_id;
304 publ.content_type = ev->publ_content_type;
305 publ.expires = ev->expires;
306
307 /* make UPDATE_TYPE, as if this "publish dialog" is not found
308 by pua it will fallback to INSERT_TYPE anyway */
309 publ.flag |= ev->flag;
310 publ.source_flag |= ev->sourge_flag;
311 publ.event |= ev->reg_info_event;
312 publ.extra_headers = &ev->extra_headers;
313
314 if (pua.send_publish(&publ) < 0) {
315 LM_ERR("Error while sending publish\n");
316 }
317 break;
318 case REG_EVENT_SUBSCRIBE:
319 memset(&subs, 0, sizeof(subs_info_t));
320
321 subs.remote_target = &ev->subs_remote_target;
322 subs.pres_uri= &ev->pres_uri;
323 subs.watcher_uri= &ev->subs_watcher_uri;
324 subs.expires = ev->expires;
325
326 subs.source_flag= ev->sourge_flag;
327 subs.event= ev->reg_info_event;
328 subs.contact= &ev->subs_contact;
329 subs.extra_headers = &ev->extra_headers;
330
331 if(ev->subs_outbound_proxy.s) {
332 subs.outbound_proxy= &ev->subs_outbound_proxy;
333 }
334
335 subs.flag|= ev->flag;
336
337
338 LM_DBG("Sending out-of-band subscribe with remote_target [%.*s] pres_uri [%.*s] subs_watcher_uri [%.*s] subs_contact [%.*s] extra_headers [%.*s] "
339 "expires [%d] event [%d] flag [%d] source_flag [%d]\n",
340 subs.remote_target->len, subs.remote_target->s, subs.pres_uri->len, subs.pres_uri->s, subs.watcher_uri->len, subs.watcher_uri->s,
341 subs.contact->len, subs.contact->s, subs.extra_headers->len, subs.extra_headers->s, subs.expires, subs.event, subs.flag, subs.source_flag);
342 if(subs.outbound_proxy) {
343 LM_DBG("subs_outbound_proxy [%.*s]\n",
344 subs.outbound_proxy->len, subs.outbound_proxy->s);
345 }
346
347
348 if(pua.send_subscribe(&subs)< 0) {
349 LM_ERR("while sending subscribe\n");
350 }
351
352 break;
353 default:
354 LM_ERR("Unknown REG event.....ignoring\n");
355 break;
356 }
357 free_reginfo_event(ev);
358 }
359 }
360
361
362
363