- use dedicated function to match header name
[sip-router] / modules_k / registrar / save.c
1 /*
2  * $Id$
3  *
4  * Process REGISTER request and send reply
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  * Copyright (C) 2006 Voice Sistem SRL
8  *
9  * This file is part of Kamailio, a free SIP server.
10  *
11  * Kamailio is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version
15  *
16  * Kamailio is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License 
22  * along with this program; if not, write to the Free Software 
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  * History:
26  * ----------
27  * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
28  * 2003-02-28 scrathcpad compatibility abandoned (jiri)
29  * 2003-03-21 save_noreply added, patch provided by Maxim Sobolev 
30  *            <sobomax@portaone.com> (janakj)
31  * 2005-07-11 added sip_natping_flag for nat pinging with SIP method
32  *            instead of UDP package (bogdan)
33  * 2006-04-13 added tcp_persistent_flag for keeping the TCP connection as long
34  *            as a TCP contact is registered (bogdan)
35  * 2006-11-22 save_noreply and save_memory merged into save() (bogdan)
36  * 2006-11-28 Added statistic support for the number of accepted/rejected 
37  *            registrations. (Jeffrey Magder - SOMA Networks) 
38  * 2007-02-24  sip_natping_flag moved into branch flags, so migrated to 
39  *             nathelper module (bogdan)
40  */
41 /*!
42  * \file
43  * \brief SIP registrar module - Process REGISTER request and send reply
44  * \ingroup registrar   
45  */  
46
47
48 #include "../../str.h"
49 #include "../../socket_info.h"
50 #include "../../parser/parse_allow.h"
51 #include "../../parser/parse_methods.h"
52 #include "../../parser/msg_parser.h"
53 #include "../../parser/parse_uri.h"
54 #include "../../dprint.h"
55 #include "../../trim.h"
56 #include "../../ut.h"
57 #include "../../qvalue.h"
58 #include "../../dset.h"
59 #include "../../mod_fix.h"
60 #include "../../cmpapi.h"
61 #ifdef USE_TCP
62 #include "../../tcp_server.h"
63 #endif
64 #include "../usrloc/usrloc.h"
65 #include "common.h"
66 #include "sip_msg.h"
67 #include "rerrno.h"
68 #include "reply.h"
69 #include "reg_mod.h"
70 #include "regtime.h"
71 #include "path.h"
72 #include "save.h"
73
74 static int mem_only = 0;
75
76 /*! \brief
77  * Process request that contained a star, in that case, 
78  * we will remove all bindings with the given username 
79  * from the usrloc and return 200 OK response
80  */
81 static inline int star(udomain_t* _d, str* _a)
82 {
83         urecord_t* r;
84         ucontact_t* c;
85         
86         ul.lock_udomain(_d, _a);
87
88         if (!ul.get_urecord(_d, _a, &r)) {
89                 c = r->contacts;
90                 while(c) {
91                         if (mem_only) {
92                                 c->flags |= FL_MEM;
93                         } else {
94                                 c->flags &= ~FL_MEM;
95                         }
96                         c = c->next;
97                 }
98         } else {
99                 r = NULL;
100         }
101
102         if (ul.delete_urecord(_d, _a, r) < 0) {
103                 LM_ERR("failed to remove record from usrloc\n");
104                 
105                      /* Delete failed, try to get corresponding
106                       * record structure and send back all existing
107                       * contacts
108                       */
109                 rerrno = R_UL_DEL_R;
110                 if (!ul.get_urecord(_d, _a, &r)) {
111                         build_contact(r->contacts);
112                         ul.release_urecord(r);
113                 }
114                 ul.unlock_udomain(_d, _a);
115                 return -1;
116         }
117         ul.unlock_udomain(_d, _a);
118         return 0;
119 }
120
121
122 /*! \brief
123  */
124 static struct socket_info *get_sock_hdr(struct sip_msg *msg)
125 {
126         struct socket_info *sock;
127         struct hdr_field *hf;
128         str socks;
129         str hosts;
130         int port;
131         int proto;
132
133         if (parse_headers( msg, HDR_EOH_F, 0) == -1) {
134                 LM_ERR("failed to parse message\n");
135                 return 0;
136         }
137
138         for (hf=msg->headers; hf; hf=hf->next) {
139                 if (cmp_hdrname_str(&hf->name, &sock_hdr_name)==0)
140                         break;
141         }
142
143         /* hdr found? */
144         if (hf==0)
145                 return 0;
146
147         trim_len( socks.len, socks.s, hf->body );
148         if (socks.len==0)
149                 return 0;
150
151         if (parse_phostport( socks.s, socks.len, &hosts.s, &hosts.len, 
152         &port, &proto)!=0) {
153                 LM_ERR("bad socket <%.*s> in \n",
154                         socks.len, socks.s);
155                 return 0;
156         }
157         sock = grep_sock_info(&hosts,(unsigned short)port,(unsigned short)proto);
158         if (sock==0) {
159                 LM_ERR("non-local socket <%.*s>\n",     socks.len, socks.s);
160                 return 0;
161         }
162
163         LM_DBG("%d:<%.*s>:%d -> p=%p\n", proto,socks.len,socks.s,port_no,sock );
164
165         return sock;
166 }
167
168
169
170 /*! \brief
171  * Process request that contained no contact header
172  * field, it means that we have to send back a response
173  * containing a list of all existing bindings for the
174  * given username (in To HF)
175  */
176 static inline int no_contacts(udomain_t* _d, str* _a)
177 {
178         urecord_t* r;
179         int res;
180         
181         ul.lock_udomain(_d, _a);
182         res = ul.get_urecord(_d, _a, &r);
183         if (res < 0) {
184                 rerrno = R_UL_GET_R;
185                 LM_ERR("failed to retrieve record from usrloc\n");
186                 ul.unlock_udomain(_d, _a);
187                 return -1;
188         }
189         
190         if (res == 0) {  /* Contacts found */
191                 build_contact(r->contacts);
192                 ul.release_urecord(r);
193         }
194         ul.unlock_udomain(_d, _a);
195         return 0;
196 }
197
198
199
200 /*! \brief
201  * Fills the common part (for all contacts) of the info structure
202  */
203 static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
204                                                                                         unsigned int _e, unsigned int _f)
205 {
206         static ucontact_info_t ci;
207         static str no_ua = str_init("n/a");
208         static str callid;
209         static str path_received = {0,0};
210         static str path;
211         static str received = {0,0};
212         static int received_found;
213         static unsigned int allowed, allow_parsed;
214         static struct sip_msg *m = 0;
215         int_str val;
216
217         if (_m!=0) {
218                 memset( &ci, 0, sizeof(ucontact_info_t));
219
220                 /* Get callid of the message */
221                 callid = _m->callid->body;
222                 trim_trailing(&callid);
223                 if (callid.len > CALLID_MAX_SIZE) {
224                         rerrno = R_CALLID_LEN;
225                         LM_ERR("callid too long\n");
226                         goto error;
227                 }
228                 ci.callid = &callid;
229
230                 /* Get CSeq number of the message */
231                 if (str2int(&get_cseq(_m)->number, (unsigned int*)&ci.cseq) < 0) {
232                         rerrno = R_INV_CSEQ;
233                         LM_ERR("failed to convert cseq number\n");
234                         goto error;
235                 }
236
237                 /* set received socket */
238                 if (_m->flags&sock_flag) {
239                         ci.sock = get_sock_hdr(_m);
240                         if (ci.sock==0)
241                                 ci.sock = _m->rcv.bind_address;
242                 } else {
243                         ci.sock = _m->rcv.bind_address;
244                 }
245
246                 /* additional info from message */
247                 if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent &&
248                 _m->user_agent->body.len>0 && _m->user_agent->body.len<UA_MAX_SIZE) {
249                         ci.user_agent = &_m->user_agent->body;
250                 } else {
251                         ci.user_agent = &no_ua;
252                 }
253
254                 /* extract Path headers */
255                 if (path_enabled) {
256                         if (build_path_vector(_m, &path, &path_received) < 0) {
257                                 rerrno = R_PARSE_PATH;
258                                 goto error;
259                         }
260                         if (path.len && path.s) {
261                                 ci.path = &path;
262                                 /* save in msg too for reply */
263                                 if (set_path_vector(_m, &path) < 0) {
264                                         rerrno = R_PARSE_PATH;
265                                         goto error;
266                                 }
267                         }
268                 }
269
270                 ci.last_modified = act_time;
271
272                 /* set flags */
273                 ci.flags  = _f;
274                 ci.cflags =  getb0flags();
275
276                 /* get received */
277                 if (path_received.len && path_received.s) {
278                         ci.cflags |= ul.nat_flag;
279                         ci.received = path_received;
280                 }
281
282                 allow_parsed = 0; /* not parsed yet */
283                 received_found = 0; /* not found yet */
284                 m = _m; /* remember the message */
285         }
286
287         if(_c!=0) {
288                 /* Calculate q value of the contact */
289                 if (calc_contact_q(_c->q, &ci.q) < 0) {
290                         rerrno = R_INV_Q;
291                         LM_ERR("failed to calculate q\n");
292                         goto error;
293                 }
294
295                 /* set expire time */
296                 ci.expires = _e;
297
298                 /* Get methods of contact */
299                 if (_c->methods) {
300                         if (parse_methods(&(_c->methods->body), &ci.methods) < 0) {
301                                 rerrno = R_PARSE;
302                                 LM_ERR("failed to parse contact methods\n");
303                                 goto error;
304                         }
305                 } else {
306                         /* check on Allow hdr */
307                         if (allow_parsed == 0) {
308                                 if (m && parse_allow( m ) != -1) {
309                                         allowed = get_allow_methods(m);
310                                 } else {
311                                         allowed = ALL_METHODS;
312                                 }
313                                 allow_parsed = 1;
314                         }
315                         ci.methods = allowed;
316                 }
317
318                 /* get received */
319                 if (ci.received.len==0) {
320                         if (_c->received) {
321                                 ci.received = _c->received->body;
322                         } else {
323                                 if (received_found==0) {
324                                         memset(&val, 0, sizeof(int_str));
325                                         if (rcv_avp_name.n!=0
326                                                                 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0)
327                                                                 && val.s.len > 0) {
328                                                 if (val.s.len>RECEIVED_MAX_SIZE) {
329                                                         rerrno = R_CONTACT_LEN;
330                                                         LM_ERR("received too long\n");
331                                                         goto error;
332                                                 }
333                                                 received = val.s;
334                                         } else {
335                                                 received.s = 0;
336                                                 received.len = 0;
337                                         }
338                                         received_found = 1;
339                                 }
340                                 ci.received = received;
341                         }
342                 }
343
344         }
345
346         return &ci;
347 error:
348         return 0;
349 }
350
351
352
353 /*! \brief
354  * Message contained some contacts, but record with same address
355  * of record was not found so we have to create a new record
356  * and insert all contacts from the message that have expires
357  * > 0
358  */
359 static inline int insert_contacts(struct sip_msg* _m, contact_t* _c,
360                                                                                                         udomain_t* _d, str* _a)
361 {
362         ucontact_info_t* ci;
363         urecord_t* r;
364         ucontact_t* c;
365         unsigned int flags;
366         int num, expires;
367 #ifdef USE_TCP
368         int e_max, tcp_check;
369         struct sip_uri uri;
370 #endif
371
372         flags = mem_only;
373 #ifdef USE_TCP
374         if ( (_m->flags&tcp_persistent_flag) &&
375         (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS)) {
376                 e_max = 0;
377                 tcp_check = 1;
378         } else {
379                 e_max = tcp_check = 0;
380         }
381 #endif
382
383         for( num=0,r=0,ci=0 ; _c ; _c = get_next_contact(_c) ) {
384                 /* calculate expires */
385                 calc_contact_expires(_m, _c->expires, &expires);
386                 /* Skip contacts with zero expires */
387                 if (expires == 0)
388                         continue;
389
390                 if (max_contacts && (num >= max_contacts)) {
391                         LM_INFO("too many contacts (%d) for AOR <%.*s>\n", 
392                                         num, _a->len, _a->s);
393                         rerrno = R_TOO_MANY;
394                         goto error;
395                 }
396                 num++;
397
398                 if (r==0) {
399                         if (ul.insert_urecord(_d, _a, &r) < 0) {
400                                 rerrno = R_UL_NEW_R;
401                                 LM_ERR("failed to insert new record structure\n");
402                                 goto error;
403                         }
404                 }
405
406                 /* pack the contact_info */
407                 if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags))==0 ) {
408                         LM_ERR("failed to extract contact info\n");
409                         goto error;
410                 }
411
412                 if ( r->contacts==0 ||
413                 ul.get_ucontact(r, &_c->uri, ci->callid, ci->cseq+1, &c)!=0 ) {
414                         if (ul.insert_ucontact( r, &_c->uri, ci, &c) < 0) {
415                                 rerrno = R_UL_INS_C;
416                                 LM_ERR("failed to insert contact\n");
417                                 goto error;
418                         }
419                 } else {
420                         if (ul.update_ucontact( r, c, ci) < 0) {
421                                 rerrno = R_UL_UPD_C;
422                                 LM_ERR("failed to update contact\n");
423                                 goto error;
424                         }
425                 }
426 #ifdef USE_TCP
427                 if (tcp_check) {
428                         /* parse contact uri to see if transport is TCP */
429                         if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) {
430                                 LM_ERR("failed to parse contact <%.*s>\n", 
431                                                 _c->uri.len, _c->uri.s);
432                         } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS) {
433                                 if (e_max) {
434                                         LM_WARN("multiple TCP contacts on single REGISTER\n");
435                                         if (expires>e_max) e_max = expires;
436                                 } else {
437                                         e_max = expires;
438                                 }
439                         }
440                 }
441 #endif
442         }
443
444         if (r) {
445                 if (r->contacts)
446                         build_contact(r->contacts);
447                 ul.release_urecord(r);
448         }
449
450 #ifdef USE_TCP
451         if ( tcp_check && e_max>0 ) {
452                 e_max -= act_time;
453                 force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );
454         }
455 #endif
456
457         return 0;
458 error:
459         if (r)
460                 ul.delete_urecord(_d, _a, r);
461         return -1;
462 }
463
464
465 static int test_max_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c,
466                                                                                                                 ucontact_info_t *ci)
467 {
468         int num;
469         int e;
470         ucontact_t* ptr, *cont;
471         int ret;
472         
473         num = 0;
474         ptr = _r->contacts;
475         while(ptr) {
476                 if (VALID_CONTACT(ptr, act_time)) {
477                         num++;
478                 }
479                 ptr = ptr->next;
480         }
481         LM_DBG("%d valid contacts\n", num);
482         
483         for( ; _c ; _c = get_next_contact(_c) ) {
484                 /* calculate expires */
485                 calc_contact_expires(_m, _c->expires, &e);
486                 
487                 ret = ul.get_ucontact( _r, &_c->uri, ci->callid, ci->cseq, &cont);
488                 if (ret==-1) {
489                         LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
490                         rerrno = R_INV_CSEQ;
491                         return -1;
492                 } else if (ret==-2) {
493                         continue;
494                 }
495                 if (ret > 0) {
496                         /* Contact not found */
497                         if (e != 0) num++;
498                 } else {
499                         if (e == 0) num--;
500                 }
501         }
502         
503         LM_DBG("%d contacts after commit\n", num);
504         if (num > max_contacts) {
505                 LM_INFO("too many contacts for AOR <%.*s>\n", _r->aor.len, _r->aor.s);
506                 rerrno = R_TOO_MANY;
507                 return -1;
508         }
509
510         return 0;
511 }
512
513
514 /*! \brief
515  * Message contained some contacts and appropriate
516  * record was found, so we have to walk through
517  * all contacts and do the following:
518  * 1) If contact in usrloc doesn't exists and
519  *    expires > 0, insert new contact
520  * 2) If contact in usrloc exists and expires
521  *    > 0, update the contact
522  * 3) If contact in usrloc exists and expires
523  *    == 0, delete contact
524  */
525 static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
526                                                                                 contact_t* _c, int _mode)
527 {
528         ucontact_info_t *ci;
529         ucontact_t *c, *ptr, *ptr0;
530         int expires, ret, updated;
531         unsigned int flags;
532 #ifdef USE_TCP
533         int e_max, tcp_check;
534         struct sip_uri uri;
535 #endif
536
537         /* mem flag */
538         flags = mem_only;
539
540         /* pack the contact_info */
541         if ( (ci=pack_ci( _m, 0, 0, flags))==0 ) {
542                 LM_ERR("failed to initial pack contact info\n");
543                 goto error;
544         }
545
546         if (max_contacts && test_max_contacts(_m, _r, _c, ci) != 0 )
547                 goto error;
548
549 #ifdef USE_TCP
550         if ( (_m->flags&tcp_persistent_flag) &&
551         (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS)) {
552                 e_max = -1;
553                 tcp_check = 1;
554         } else {
555                 e_max = tcp_check = 0;
556         }
557 #endif
558
559         updated=0;
560         for( ; _c ; _c = get_next_contact(_c) ) {
561                 /* calculate expires */
562                 calc_contact_expires(_m, _c->expires, &expires);
563
564                 /* search for the contact*/
565                 ret = ul.get_ucontact( _r, &_c->uri, ci->callid, ci->cseq, &c);
566                 if (ret==-1) {
567                         LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
568                         rerrno = R_INV_CSEQ;
569                         goto error;
570                 } else if (ret==-2) {
571                         if(expires!=0 && _mode)
572                                 break;
573                         continue;
574                 }
575
576                 if ( ret > 0 ) {
577                         /* Contact not found -> expired? */
578                         if (expires==0)
579                                 continue;
580
581                         /* pack the contact_info */
582                         if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
583                                 LM_ERR("failed to extract contact info\n");
584                                 goto error;
585                         }
586
587                         if (ul.insert_ucontact( _r, &_c->uri, ci, &c) < 0) {
588                                 rerrno = R_UL_INS_C;
589                                 LM_ERR("failed to insert contact\n");
590                                 goto error;
591                         }
592                         if(_mode)
593                         {
594                                 ptr=_r->contacts;
595                                 while(ptr)
596                                 {
597                                         ptr0 = ptr;
598                                         if(ptr!=c)
599                                                 ul.delete_ucontact(_r, ptr);
600                                         ptr=ptr0->next;
601                                 }
602                                 updated=1;
603                         }
604                 } else {
605                         /* Contact found */
606                         if (expires == 0) {
607                                 /* it's expired */
608                                 if (mem_only) {
609                                         c->flags |= FL_MEM;
610                                 } else {
611                                         c->flags &= ~FL_MEM;
612                                 }
613
614                                 if (ul.delete_ucontact(_r, c) < 0) {
615                                         rerrno = R_UL_DEL_C;
616                                         LM_ERR("failed to delete contact\n");
617                                         goto error;
618                                 }
619                         } else {
620                                 /* do update */
621                                 /* pack the contact specific info */
622                                 if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
623                                         LM_ERR("failed to pack contact specific info\n");
624                                         goto error;
625                                 }
626
627                                 if(_mode)
628                                 {
629                                         ptr=_r->contacts;
630                                         while(ptr)
631                                         {
632                                                 ptr0 = ptr;
633                                                 if(ptr!=c)
634                                                         ul.delete_ucontact(_r, ptr);
635                                                 ptr=ptr0->next;
636                                         }
637                                         updated=1;
638                                 }
639                                 if (ul.update_ucontact(_r, c, ci) < 0) {
640                                         rerrno = R_UL_UPD_C;
641                                         LM_ERR("failed to update contact\n");
642                                         goto error;
643                                 }
644                         }
645                 }
646 #ifdef USE_TCP
647                 if (tcp_check) {
648                         /* parse contact uri to see if transport is TCP */
649                         if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) {
650                                 LM_ERR("failed to parse contact <%.*s>\n", 
651                                                 _c->uri.len, _c->uri.s);
652                         } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS) {
653                                 if (e_max>0) {
654                                         LM_WARN("multiple TCP contacts on single REGISTER\n");
655                                 }
656                                 if (expires>e_max) e_max = expires;
657                         }
658                 }
659 #endif
660                 /* have one contact only -- break */
661                 if(updated)
662                         break;
663         }
664
665 #ifdef USE_TCP
666         if ( tcp_check && e_max>-1 ) {
667                 if (e_max) e_max -= act_time;
668                 force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );
669         }
670 #endif
671
672         return 0;
673 error:
674         return -1;
675 }
676
677
678 /*! \brief
679  * This function will process request that
680  * contained some contact header fields
681  */
682 static inline int add_contacts(struct sip_msg* _m, contact_t* _c,
683                                                                 udomain_t* _d, str* _a, int _mode)
684 {
685         int res;
686         urecord_t* r;
687
688         ul.lock_udomain(_d, _a);
689         res = ul.get_urecord(_d, _a, &r);
690         if (res < 0) {
691                 rerrno = R_UL_GET_R;
692                 LM_ERR("failed to retrieve record from usrloc\n");
693                 ul.unlock_udomain(_d, _a);
694                 return -2;
695         }
696
697         if (res == 0) { /* Contacts found */
698                 if (update_contacts(_m, r, _c, _mode) < 0) {
699                         build_contact(r->contacts);
700                         ul.release_urecord(r);
701                         ul.unlock_udomain(_d, _a);
702                         return -3;
703                 }
704                 build_contact(r->contacts);
705                 ul.release_urecord(r);
706         } else {
707                 if (insert_contacts(_m, _c, _d, _a) < 0) {
708                         ul.unlock_udomain(_d, _a);
709                         return -4;
710                 }
711         }
712         ul.unlock_udomain(_d, _a);
713         return 0;
714 }
715
716
717 /*!\brief
718  * Process REGISTER request and save it's contacts
719  */
720 #define is_cflag_set(_name) (((unsigned int)(unsigned long)_cflags)&(_name))
721 int save(struct sip_msg* _m, char* _d, char* _cflags)
722 {
723         contact_t* c;
724         int st, mode;
725         str aor;
726
727         rerrno = R_FINE;
728
729         if (parse_message(_m) < 0) {
730                 goto error;
731         }
732
733         if (check_contacts(_m, &st) > 0) {
734                 goto error;
735         }
736         
737         get_act_time();
738         c = get_first_contact(_m);
739
740         if (extract_aor(&get_to(_m)->uri, &aor) < 0) {
741                 LM_ERR("failed to extract Address Of Record\n");
742                 goto error;
743         }
744
745         mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE;
746
747         if (c == 0) {
748                 if (st) {
749                         if (star((udomain_t*)_d, &aor) < 0) goto error;
750                 } else {
751                         if (no_contacts((udomain_t*)_d, &aor) < 0) goto error;
752                 }
753         } else {
754                 mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0;
755                 if (add_contacts(_m, c, (udomain_t*)_d, &aor, mode) < 0) goto error;
756         }
757
758         update_stat(accepted_registrations, 1);
759
760         if ( !is_cflag_set(REG_SAVE_NORPL_FL) && (send_reply(_m) < 0))
761                 return -1;
762
763         return 1;
764 error:
765         update_stat(rejected_registrations, 1);
766
767         if ( !is_cflag_set(REG_SAVE_NORPL_FL) )
768                 send_reply(_m);
769
770         return 0;
771 }
772
773 int unregister(struct sip_msg* _m, char* _d, char* _uri)
774 {
775         str aor = {0, 0};
776         str uri = {0, 0};
777
778         if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)
779         {
780                 LM_ERR("invalid uri parameter\n");
781                 return -1;
782         }
783
784         if (extract_aor(&uri, &aor) < 0) {
785                 LM_ERR("failed to extract Address Of Record\n");
786                 return -1;
787         }
788
789         if (star((udomain_t*)_d, &aor) < 0)
790         {
791                 LM_ERR("error unregistering user [%.*s]\n", aor.len, aor.s);
792                 return -1;
793         }
794         return 1;
795 }
796