registrar(k): add gruu parameters only when supported
[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_to.h"
54 #include "../../parser/parse_uri.h"
55 #include "../../dprint.h"
56 #include "../../trim.h"
57 #include "../../ut.h"
58 #include "../../qvalue.h"
59 #include "../../dset.h"
60 #include "../../xavp.h"
61 #include "../../mod_fix.h"
62 #include "../../lib/srutils/sruid.h"
63 #include "../../lib/kcore/cmpapi.h"
64 #include "../../lib/kcore/statistics.h"
65 #ifdef USE_TCP
66 #include "../../tcp_server.h"
67 #endif
68 #include "../usrloc/usrloc.h"
69 #include "common.h"
70 #include "sip_msg.h"
71 #include "rerrno.h"
72 #include "reply.h"
73 #include "reg_mod.h"
74 #include "regtime.h"
75 #include "path.h"
76 #include "save.h"
77 #include "config.h"
78
79 static int mem_only = 0;
80
81 extern sruid_t _reg_sruid;
82
83 /*! \brief
84  * Process request that contained a star, in that case, 
85  * we will remove all bindings with the given username 
86  * from the usrloc and return 200 OK response
87  */
88 static inline int star(sip_msg_t *_m, udomain_t* _d, str* _a, str *_h)
89 {
90         urecord_t* r;
91         ucontact_t* c;
92         
93         ul.lock_udomain(_d, _a);
94
95         if (!ul.get_urecord(_d, _a, &r)) {
96                 c = r->contacts;
97                 while(c) {
98                         if (mem_only) {
99                                 c->flags |= FL_MEM;
100                         } else {
101                                 c->flags &= ~FL_MEM;
102                         }
103                         c = c->next;
104                 }
105         } else {
106                 r = NULL;
107         }
108
109         if (ul.delete_urecord(_d, _a, r) < 0) {
110                 LM_ERR("failed to remove record from usrloc\n");
111                 
112                      /* Delete failed, try to get corresponding
113                       * record structure and send back all existing
114                       * contacts
115                       */
116                 rerrno = R_UL_DEL_R;
117                 if (!ul.get_urecord(_d, _a, &r)) {
118                         build_contact(_m, r->contacts, _h);
119                         ul.release_urecord(r);
120                 }
121                 ul.unlock_udomain(_d, _a);
122                 return -1;
123         }
124         ul.unlock_udomain(_d, _a);
125         return 0;
126 }
127
128
129 /*! \brief
130  */
131 static struct socket_info *get_sock_hdr(struct sip_msg *msg)
132 {
133         struct socket_info *sock;
134         struct hdr_field *hf;
135         str socks;
136         str hosts;
137         int port;
138         int proto;
139         char c;
140
141         if (parse_headers( msg, HDR_EOH_F, 0) == -1) {
142                 LM_ERR("failed to parse message\n");
143                 return 0;
144         }
145
146         for (hf=msg->headers; hf; hf=hf->next) {
147                 if (cmp_hdrname_str(&hf->name, &sock_hdr_name)==0)
148                         break;
149         }
150
151         /* hdr found? */
152         if (hf==0)
153                 return 0;
154
155         trim_len( socks.len, socks.s, hf->body );
156         if (socks.len==0)
157                 return 0;
158
159         /*FIXME: This is a hack */
160         c = socks.s[socks.len];
161         socks.s[socks.len] = '\0';
162         if (parse_phostport( socks.s, &hosts.s, &hosts.len,
163         &port, &proto)!=0) {
164                 socks.s[socks.len] = c;
165                 LM_ERR("bad socket <%.*s> in \n",
166                         socks.len, socks.s);
167                 return 0;
168         }
169         socks.s[socks.len] = c;
170         sock = grep_sock_info(&hosts,(unsigned short)port,(unsigned short)proto);
171         if (sock==0) {
172                 LM_ERR("non-local socket <%.*s>\n",     socks.len, socks.s);
173                 return 0;
174         }
175
176         LM_DBG("%d:<%.*s>:%d -> p=%p\n", proto,socks.len,socks.s,port_no,sock );
177
178         return sock;
179 }
180
181
182
183 /*! \brief
184  * Process request that contained no contact header
185  * field, it means that we have to send back a response
186  * containing a list of all existing bindings for the
187  * given username (in To HF)
188  */
189 static inline int no_contacts(sip_msg_t *_m, udomain_t* _d, str* _a, str* _h)
190 {
191         urecord_t* r;
192         int res;
193         
194         ul.lock_udomain(_d, _a);
195         res = ul.get_urecord(_d, _a, &r);
196         if (res < 0) {
197                 rerrno = R_UL_GET_R;
198                 LM_ERR("failed to retrieve record from usrloc\n");
199                 ul.unlock_udomain(_d, _a);
200                 return -1;
201         }
202         
203         if (res == 0) {  /* Contacts found */
204                 build_contact(_m, r->contacts, _h);
205                 ul.release_urecord(r);
206         } else {  /* No contacts found */
207                 build_contact(_m, NULL, _h);
208         }
209         ul.unlock_udomain(_d, _a);
210         return 0;
211 }
212
213
214
215 /*! \brief
216  * Fills the common part (for all contacts) of the info structure
217  */
218 static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
219                                                                                         unsigned int _e, unsigned int _f)
220 {
221         static ucontact_info_t ci;
222         static str no_ua = str_init("n/a");
223         static str callid;
224         static str path_received = {0,0};
225         static str path;
226         static str received = {0,0};
227         static int received_found;
228         static unsigned int allowed, allow_parsed;
229         static struct sip_msg *m = 0;
230         int_str val;
231
232         if (_m!=0) {
233                 memset( &ci, 0, sizeof(ucontact_info_t));
234
235                 /* Get callid of the message */
236                 callid = _m->callid->body;
237                 trim_trailing(&callid);
238                 if (callid.len > CALLID_MAX_SIZE) {
239                         rerrno = R_CALLID_LEN;
240                         LM_ERR("callid too long\n");
241                         goto error;
242                 }
243                 ci.callid = &callid;
244
245                 /* Get CSeq number of the message */
246                 if (str2int(&get_cseq(_m)->number, (unsigned int*)&ci.cseq) < 0) {
247                         rerrno = R_INV_CSEQ;
248                         LM_ERR("failed to convert cseq number\n");
249                         goto error;
250                 }
251
252                 /* set received socket */
253                 if (_m->flags&sock_flag) {
254                         ci.sock = get_sock_hdr(_m);
255                         if (ci.sock==0)
256                                 ci.sock = _m->rcv.bind_address;
257                 } else {
258                         ci.sock = _m->rcv.bind_address;
259                 }
260
261                 /* additional info from message */
262                 if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent &&
263                 _m->user_agent->body.len>0 && _m->user_agent->body.len<UA_MAX_SIZE) {
264                         ci.user_agent = &_m->user_agent->body;
265                 } else {
266                         ci.user_agent = &no_ua;
267                 }
268
269                 /* extract Path headers */
270                 if (path_enabled) {
271                         if (build_path_vector(_m, &path, &path_received) < 0) {
272                                 rerrno = R_PARSE_PATH;
273                                 goto error;
274                         }
275                         if (path.len && path.s) {
276                                 ci.path = &path;
277                                 if (path_mode != PATH_MODE_OFF) {
278                                         /* save in msg too for reply */
279                                         if (set_path_vector(_m, &path) < 0) {
280                                                 rerrno = R_PARSE_PATH;
281                                                 goto error;
282                                         }
283                                 }
284                         }
285                 }
286
287                 ci.last_modified = act_time;
288
289                 /* set flags */
290                 ci.flags  = _f;
291                 getbflagsval(0, &ci.cflags);
292
293                 /* get received */
294                 if (path_received.len && path_received.s) {
295                         ci.cflags |= ul.nat_flag;
296                         ci.received = path_received;
297                 }
298
299                 allow_parsed = 0; /* not parsed yet */
300                 received_found = 0; /* not found yet */
301                 m = _m; /* remember the message */
302         }
303
304         if(_c!=0) {
305                 /* Calculate q value of the contact */
306                 if (calc_contact_q(_c->q, &ci.q) < 0) {
307                         rerrno = R_INV_Q;
308                         LM_ERR("failed to calculate q\n");
309                         goto error;
310                 }
311
312                 /* set expire time */
313                 ci.expires = _e;
314
315                 /* Get methods of contact */
316                 if (_c->methods) {
317                         if (parse_methods(&(_c->methods->body), &ci.methods) < 0) {
318                                 rerrno = R_PARSE;
319                                 LM_ERR("failed to parse contact methods\n");
320                                 goto error;
321                         }
322                 } else {
323                         /* check on Allow hdr */
324                         if (allow_parsed == 0) {
325                                 if (m && parse_allow( m ) != -1) {
326                                         allowed = get_allow_methods(m);
327                                 } else {
328                                         allowed = ALL_METHODS;
329                                 }
330                                 allow_parsed = 1;
331                         }
332                         ci.methods = allowed;
333                 }
334
335                 /* get received */
336                 if (ci.received.len==0) {
337                         if (_c->received) {
338                                 ci.received = _c->received->body;
339                         } else {
340                                 if (received_found==0) {
341                                         memset(&val, 0, sizeof(int_str));
342                                         if (rcv_avp_name.n!=0
343                                                                 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0)
344                                                                 && val.s.len > 0) {
345                                                 if (val.s.len>RECEIVED_MAX_SIZE) {
346                                                         rerrno = R_CONTACT_LEN;
347                                                         LM_ERR("received too long\n");
348                                                         goto error;
349                                                 }
350                                                 received = val.s;
351                                         } else {
352                                                 received.s = 0;
353                                                 received.len = 0;
354                                         }
355                                         received_found = 1;
356                                 }
357                                 ci.received = received;
358                         }
359                 }
360                 if(reg_gruu_enabled==1 && _c->instance!=NULL
361                                 && _c->instance->body.len>0)
362                         ci.instance = _c->instance->body;
363                 if(sruid_next(&_reg_sruid)<0)
364                         goto error;
365                 ci.ruid = _reg_sruid.uid;
366         }
367
368         return &ci;
369 error:
370         return 0;
371 }
372
373
374 int reg_get_crt_max_contacts(void)
375 {
376         int n;
377         sr_xavp_t *ravp=NULL;
378         sr_xavp_t *vavp=NULL;
379         str vname = {"max_contacts", 12};
380
381         n = 0;
382
383         if(reg_xavp_cfg.s!=NULL)
384         {
385                 ravp = xavp_get(&reg_xavp_cfg, NULL);
386                 if(ravp!=NULL && ravp->val.type==SR_XTYPE_XAVP)
387                 {
388                         vavp = xavp_get(&vname, ravp->val.v.xavp);
389                         if(vavp!=NULL && vavp->val.type==SR_XTYPE_INT)
390                         {
391                                 n = vavp->val.v.i;
392                                 LM_ERR("using max contacts value from xavp: %d\n", n);
393                         } else {
394                                 ravp = NULL;
395                         }
396                 } else {
397                         ravp = NULL;
398                 }
399         }
400
401         if(ravp==NULL)
402         {
403                 n = cfg_get(registrar, registrar_cfg, max_contacts);
404         }
405
406         return n;
407 }
408
409 /*! \brief
410  * Message contained some contacts, but record with same address
411  * of record was not found so we have to create a new record
412  * and insert all contacts from the message that have expires
413  * > 0
414  */
415 static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
416 {
417         ucontact_info_t* ci;
418         urecord_t* r = NULL;
419         ucontact_t* c;
420         contact_t* _c;
421         unsigned int flags;
422         int num, expires;
423         int maxc;
424 #ifdef USE_TCP
425         int e_max, tcp_check;
426         struct sip_uri uri;
427 #endif
428         sip_uri_t *u;
429
430         u = parse_to_uri(_m);
431         if(u==NULL)
432                 goto error;
433
434         flags = mem_only;
435 #ifdef USE_TCP
436         if ( (_m->flags&tcp_persistent_flag) &&
437         (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS)) {
438                 e_max = 0;
439                 tcp_check = 1;
440         } else {
441                 e_max = tcp_check = 0;
442         }
443 #endif
444         _c = get_first_contact(_m);
445         maxc = reg_get_crt_max_contacts();
446         for( num=0,r=0,ci=0 ; _c ; _c = get_next_contact(_c) ) {
447                 /* calculate expires */
448                 calc_contact_expires(_m, _c->expires, &expires);
449                 /* Skip contacts with zero expires */
450                 if (expires == 0)
451                         continue;
452
453
454                 if (maxc > 0 && num >= maxc) {
455                         LM_INFO("too many contacts (%d) for AOR <%.*s>\n", 
456                                         num, _a->len, _a->s);
457                         rerrno = R_TOO_MANY;
458                         goto error;
459                 }
460                 num++;
461
462                 if (r==0) {
463                         if (ul.insert_urecord(_d, _a, &r) < 0) {
464                                 rerrno = R_UL_NEW_R;
465                                 LM_ERR("failed to insert new record structure\n");
466                                 goto error;
467                         }
468                 }
469
470                 /* pack the contact_info */
471                 if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags))==0 ) {
472                         LM_ERR("failed to extract contact info\n");
473                         goto error;
474                 }
475
476                 if ( r->contacts==0 ||
477                 ul.get_ucontact_by_instance(r, &_c->uri, ci->callid, ci->path, ci->cseq+1,
478                                         &ci->instance, &c) != 0) {
479                         if (ul.insert_ucontact( r, &_c->uri, ci, &c) < 0) {
480                                 rerrno = R_UL_INS_C;
481                                 LM_ERR("failed to insert contact\n");
482                                 goto error;
483                         }
484                 } else {
485                         if (ul.update_ucontact( r, c, ci) < 0) {
486                                 rerrno = R_UL_UPD_C;
487                                 LM_ERR("failed to update contact\n");
488                                 goto error;
489                         }
490                 }
491 #ifdef USE_TCP
492                 if (tcp_check) {
493                         /* parse contact uri to see if transport is TCP */
494                         if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) {
495                                 LM_ERR("failed to parse contact <%.*s>\n", 
496                                                 _c->uri.len, _c->uri.s);
497                         } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS) {
498                                 if (e_max) {
499                                         LM_WARN("multiple TCP contacts on single REGISTER\n");
500                                         if (expires>e_max) e_max = expires;
501                                 } else {
502                                         e_max = expires;
503                                 }
504                         }
505                 }
506 #endif
507         }
508
509         if (r) {
510                 if (r->contacts)
511                         build_contact(_m, r->contacts, &u->host);
512                 ul.release_urecord(r);
513         } else { /* No contacts found */
514                 build_contact(_m, NULL, &u->host);
515         }
516
517 #ifdef USE_TCP
518         if ( tcp_check && e_max>0 ) {
519                 e_max -= act_time;
520                 /*FIXME: Do we want this in the sr core?*/
521                 /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/
522         }
523 #endif
524
525         return 0;
526 error:
527         if (r)
528                 ul.delete_urecord(_d, _a, r);
529         return -1;
530 }
531
532
533 static int test_max_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c,
534                                                                                 ucontact_info_t *ci, int mc)
535 {
536         int num;
537         int e;
538         ucontact_t* ptr, *cont;
539         int ret;
540         
541         num = 0;
542         ptr = _r->contacts;
543         while(ptr) {
544                 if (VALID_CONTACT(ptr, act_time)) {
545                         num++;
546                 }
547                 ptr = ptr->next;
548         }
549         LM_DBG("%d valid contacts\n", num);
550         
551         for( ; _c ; _c = get_next_contact(_c) ) {
552                 /* calculate expires */
553                 calc_contact_expires(_m, _c->expires, &e);
554
555                 ret = ul.get_ucontact_by_instance( _r, &_c->uri, ci->callid, ci->path, ci->cseq,
556                                 &ci->instance, &cont);
557                 if (ret==-1) {
558                         LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
559                         rerrno = R_INV_CSEQ;
560                         return -1;
561                 } else if (ret==-2) {
562                         continue;
563                 }
564                 if (ret > 0) {
565                         /* Contact not found */
566                         if (e != 0) num++;
567                 } else {
568                         if (e == 0) num--;
569                 }
570         }
571         
572         LM_DBG("%d contacts after commit\n", num);
573         if (num > mc) {
574                 LM_INFO("too many contacts for AOR <%.*s>\n", _r->aor.len, _r->aor.s);
575                 rerrno = R_TOO_MANY;
576                 return -1;
577         }
578
579         return 0;
580 }
581
582
583 /*! \brief
584  * Message contained some contacts and appropriate
585  * record was found, so we have to walk through
586  * all contacts and do the following:
587  * 1) If contact in usrloc doesn't exists and
588  *    expires > 0, insert new contact
589  * 2) If contact in usrloc exists and expires
590  *    > 0, update the contact
591  * 3) If contact in usrloc exists and expires
592  *    == 0, delete contact
593  */
594 static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
595                                                                                 int _mode)
596 {
597         ucontact_info_t *ci;
598         ucontact_t *c, *ptr, *ptr0;
599         int expires, ret, updated;
600         unsigned int flags;
601 #ifdef USE_TCP
602         int e_max, tcp_check;
603         struct sip_uri uri;
604 #endif
605         int rc;
606         contact_t* _c;
607         int maxc;
608
609         /* mem flag */
610         flags = mem_only;
611
612         rc = 0;
613         /* pack the contact_info */
614         if ( (ci=pack_ci( _m, 0, 0, flags))==0 ) {
615                 LM_ERR("failed to initial pack contact info\n");
616                 goto error;
617         }
618
619         if (!_mode) {
620                 maxc = reg_get_crt_max_contacts();
621                 if(maxc>0) {
622                         _c = get_first_contact(_m);
623                         if(test_max_contacts(_m, _r, _c, ci, maxc) != 0)
624                                 goto error;
625                 }
626         }
627
628 #ifdef USE_TCP
629         if ( (_m->flags&tcp_persistent_flag) &&
630         (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS)) {
631                 e_max = -1;
632                 tcp_check = 1;
633         } else {
634                 e_max = tcp_check = 0;
635         }
636 #endif
637
638         _c = get_first_contact(_m);
639         updated=0;
640         for( ; _c ; _c = get_next_contact(_c) ) {
641                 /* calculate expires */
642                 calc_contact_expires(_m, _c->expires, &expires);
643
644                 /* search for the contact*/
645                 ret = ul.get_ucontact_by_instance( _r, &_c->uri, ci->callid, ci->path,
646                                 ci->cseq, &ci->instance, &c);
647                 if (ret==-1) {
648                         LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
649                         rerrno = R_INV_CSEQ;
650                         goto error;
651                 } else if (ret==-2) {
652                         if(expires!=0 && _mode)
653                                 break;
654                         continue;
655                 }
656
657                 if ( ret > 0 ) {
658                         /* Contact not found -> expired? */
659                         if (expires==0)
660                                 continue;
661
662                         /* pack the contact_info */
663                         if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
664                                 LM_ERR("failed to extract contact info\n");
665                                 goto error;
666                         }
667
668                         if (ul.insert_ucontact( _r, &_c->uri, ci, &c) < 0) {
669                                 rerrno = R_UL_INS_C;
670                                 LM_ERR("failed to insert contact\n");
671                                 goto error;
672                         }
673                         rc = 1;
674                         if(_mode)
675                         {
676                                 ptr=_r->contacts;
677                                 while(ptr)
678                                 {
679                                         ptr0 = ptr;
680                                         if(ptr!=c)
681                                                 ul.delete_ucontact(_r, ptr);
682                                         ptr=ptr0->next;
683                                 }
684                                 updated=1;
685                         }
686                 } else {
687                         /* Contact found */
688                         if (expires == 0) {
689                                 /* it's expired */
690                                 if (mem_only) {
691                                         c->flags |= FL_MEM;
692                                 } else {
693                                         c->flags &= ~FL_MEM;
694                                 }
695
696                                 if (ul.delete_ucontact(_r, c) < 0) {
697                                         rerrno = R_UL_DEL_C;
698                                         LM_ERR("failed to delete contact\n");
699                                         goto error;
700                                 }
701                                 rc = 3;
702                         } else {
703                                 /* do update */
704                                 /* pack the contact specific info */
705                                 if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
706                                         LM_ERR("failed to pack contact specific info\n");
707                                         goto error;
708                                 }
709
710                                 if(_mode)
711                                 {
712                                         ptr=_r->contacts;
713                                         while(ptr)
714                                         {
715                                                 ptr0 = ptr;
716                                                 if(ptr!=c)
717                                                         ul.delete_ucontact(_r, ptr);
718                                                 ptr=ptr0->next;
719                                         }
720                                         updated=1;
721                                 }
722                                 if (ul.update_ucontact(_r, c, ci) < 0) {
723                                         rerrno = R_UL_UPD_C;
724                                         LM_ERR("failed to update contact\n");
725                                         goto error;
726                                 }
727                                 rc = 2;
728                         }
729                 }
730 #ifdef USE_TCP
731                 if (tcp_check) {
732                         /* parse contact uri to see if transport is TCP */
733                         if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) {
734                                 LM_ERR("failed to parse contact <%.*s>\n", 
735                                                 _c->uri.len, _c->uri.s);
736                         } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS) {
737                                 if (e_max>0) {
738                                         LM_WARN("multiple TCP contacts on single REGISTER\n");
739                                 }
740                                 if (expires>e_max) e_max = expires;
741                         }
742                 }
743 #endif
744                 /* have one contact only -- break */
745                 if(updated)
746                         break;
747         }
748
749 #ifdef USE_TCP
750         if ( tcp_check && e_max>-1 ) {
751                 if (e_max) e_max -= act_time;
752                 /*FIXME: Do we want this in the sr core? */
753                 /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/
754         }
755 #endif
756
757         return rc;
758 error:
759         return -1;
760 }
761
762
763 /*! \brief
764  * This function will process request that
765  * contained some contact header fields
766  */
767 static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
768                 str* _a, int _mode)
769 {
770         int res;
771         int ret;
772         urecord_t* r;
773         sip_uri_t *u;
774
775         u = parse_to_uri(_m);
776         if(u==NULL)
777                 return -2;
778
779         ret = 0;
780         ul.lock_udomain(_d, _a);
781         res = ul.get_urecord(_d, _a, &r);
782         if (res < 0) {
783                 rerrno = R_UL_GET_R;
784                 LM_ERR("failed to retrieve record from usrloc\n");
785                 ul.unlock_udomain(_d, _a);
786                 return -2;
787         }
788
789         if (res == 0) { /* Contacts found */
790                 if ((ret=update_contacts(_m, r, _mode)) < 0) {
791                         build_contact(_m, r->contacts, &u->host);
792                         ul.release_urecord(r);
793                         ul.unlock_udomain(_d, _a);
794                         return -3;
795                 }
796                 build_contact(_m, r->contacts, &u->host);
797                 ul.release_urecord(r);
798         } else {
799                 if (insert_contacts(_m, _d, _a) < 0) {
800                         ul.unlock_udomain(_d, _a);
801                         return -4;
802                 }
803                 ret = 1;
804         }
805         ul.unlock_udomain(_d, _a);
806         return ret;
807 }
808
809
810 /*!\brief
811  * Process REGISTER request and save it's contacts
812  */
813 #define is_cflag_set(_name) (((unsigned int)_cflags)&(_name))
814 int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
815 {
816         contact_t* c;
817         int st, mode;
818         str aor;
819         int ret;
820         sip_uri_t *u;
821
822         u = parse_to_uri(_m);
823         if(u==NULL)
824                 goto error;
825
826         rerrno = R_FINE;
827         ret = 1;
828
829         if (parse_message(_m) < 0) {
830                 goto error;
831         }
832
833         if (check_contacts(_m, &st) > 0) {
834                 goto error;
835         }
836         
837         get_act_time();
838         c = get_first_contact(_m);
839
840         if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor, NULL) < 0) {
841                 LM_ERR("failed to extract Address Of Record\n");
842                 goto error;
843         }
844
845         mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE;
846
847         if (c == 0) {
848                 if (st) {
849                         if (star(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error;
850                         else ret=3;
851                 } else {
852                         if (no_contacts(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error;
853                         else ret=4;
854                 }
855         } else {
856                 mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0;
857                 if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode)) < 0)
858                         goto error;
859                 ret = (ret==0)?1:ret;
860         }
861
862         update_stat(accepted_registrations, 1);
863
864         /* Only send reply upon request, not upon reply */
865         if ((is_route_type(REQUEST_ROUTE)) && !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0))
866                 return -1;
867
868         return ret;
869 error:
870         update_stat(rejected_registrations, 1);
871         if (is_route_type(REQUEST_ROUTE) && !is_cflag_set(REG_SAVE_NORPL_FL) )
872                 reg_send_reply(_m);
873
874         return 0;
875 }
876
877 int unregister(struct sip_msg* _m, udomain_t* _d, str* _uri)
878 {
879         str aor = {0, 0};
880         sip_uri_t *u;
881
882         u = parse_to_uri(_m);
883         if(u==NULL)
884                 return -2;
885
886
887         if (extract_aor(_uri, &aor, NULL) < 0) {
888                 LM_ERR("failed to extract Address Of Record\n");
889                 return -1;
890         }
891
892         if (star(_m, _d, &aor, &u->host) < 0)
893         {
894                 LM_ERR("error unregistering user [%.*s]\n", aor.len, aor.s);
895                 return -1;
896         }
897         return 1;
898 }
899