everything: shotgun attempt to put PROTO_WS and PROTO_WSS across core and in modules...
[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(_c->instance!=NULL && _c->instance->body.len>0)
361                         ci.instance = _c->instance->body;
362                 if(_c->reg_id!=NULL && _c->reg_id->body.len>0) {
363                         if(str2int(&_c->reg_id->body, &ci.reg_id)<0)
364                         {
365                                 LM_ERR("invalid reg-id value\n");
366                                 goto error;
367                         }
368                 }
369                 if(sruid_next(&_reg_sruid)<0)
370                         goto error;
371                 ci.ruid = _reg_sruid.uid;
372         }
373
374         return &ci;
375 error:
376         return 0;
377 }
378
379
380 int reg_get_crt_max_contacts(void)
381 {
382         int n;
383         sr_xavp_t *ravp=NULL;
384         sr_xavp_t *vavp=NULL;
385         str vname = {"max_contacts", 12};
386
387         n = 0;
388
389         if(reg_xavp_cfg.s!=NULL)
390         {
391                 ravp = xavp_get(&reg_xavp_cfg, NULL);
392                 if(ravp!=NULL && ravp->val.type==SR_XTYPE_XAVP)
393                 {
394                         vavp = xavp_get(&vname, ravp->val.v.xavp);
395                         if(vavp!=NULL && vavp->val.type==SR_XTYPE_INT)
396                         {
397                                 n = vavp->val.v.i;
398                                 LM_ERR("using max contacts value from xavp: %d\n", n);
399                         } else {
400                                 ravp = NULL;
401                         }
402                 } else {
403                         ravp = NULL;
404                 }
405         }
406
407         if(ravp==NULL)
408         {
409                 n = cfg_get(registrar, registrar_cfg, max_contacts);
410         }
411
412         return n;
413 }
414
415 /*! \brief
416  * Message contained some contacts, but record with same address
417  * of record was not found so we have to create a new record
418  * and insert all contacts from the message that have expires
419  * > 0
420  */
421 static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
422 {
423         ucontact_info_t* ci;
424         urecord_t* r = NULL;
425         ucontact_t* c;
426         contact_t* _c;
427         unsigned int flags;
428         int num, expires;
429         int maxc;
430 #ifdef USE_TCP
431         int e_max, tcp_check;
432         struct sip_uri uri;
433 #endif
434         sip_uri_t *u;
435
436         u = parse_to_uri(_m);
437         if(u==NULL)
438                 goto error;
439
440         flags = mem_only;
441 #ifdef USE_TCP
442         if ( (_m->flags&tcp_persistent_flag) &&
443         (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS||_m->rcv.proto==PROTO_WS||_m->rcv.proto==PROTO_WSS)) {
444                 e_max = 0;
445                 tcp_check = 1;
446         } else {
447                 e_max = tcp_check = 0;
448         }
449 #endif
450         _c = get_first_contact(_m);
451         maxc = reg_get_crt_max_contacts();
452         for( num=0,r=0,ci=0 ; _c ; _c = get_next_contact(_c) ) {
453                 /* calculate expires */
454                 calc_contact_expires(_m, _c->expires, &expires);
455                 /* Skip contacts with zero expires */
456                 if (expires == 0)
457                         continue;
458
459
460                 if (maxc > 0 && num >= maxc) {
461                         LM_INFO("too many contacts (%d) for AOR <%.*s>\n", 
462                                         num, _a->len, _a->s);
463                         rerrno = R_TOO_MANY;
464                         goto error;
465                 }
466                 num++;
467
468                 if (r==0) {
469                         if (ul.insert_urecord(_d, _a, &r) < 0) {
470                                 rerrno = R_UL_NEW_R;
471                                 LM_ERR("failed to insert new record structure\n");
472                                 goto error;
473                         }
474                 }
475
476                 /* pack the contact_info */
477                 if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags))==0 ) {
478                         LM_ERR("failed to extract contact info\n");
479                         goto error;
480                 }
481
482                 /* hack to work with buggy clients having many contacts with same
483                  * address in one REGISTER - increase CSeq to detect if there was
484                  * one alredy added, then update */
485                 ci->cseq++;
486                 if ( r->contacts==0
487                                 || ul.get_ucontact_by_instance(r, &_c->uri, ci, &c) != 0) {
488                         ci->cseq--;
489                         if (ul.insert_ucontact( r, &_c->uri, ci, &c) < 0) {
490                                 rerrno = R_UL_INS_C;
491                                 LM_ERR("failed to insert contact\n");
492                                 goto error;
493                         }
494                 } else {
495                         ci->cseq--;
496                         if (ul.update_ucontact( r, c, ci) < 0) {
497                                 rerrno = R_UL_UPD_C;
498                                 LM_ERR("failed to update contact\n");
499                                 goto error;
500                         }
501                 }
502 #ifdef USE_TCP
503                 if (tcp_check) {
504                         /* parse contact uri to see if transport is TCP */
505                         if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) {
506                                 LM_ERR("failed to parse contact <%.*s>\n", 
507                                                 _c->uri.len, _c->uri.s);
508                         } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS || uri.proto==PROTO_WS || uri.proto==PROTO_WSS) {
509                                 if (e_max) {
510                                         LM_WARN("multiple TCP contacts on single REGISTER\n");
511                                         if (expires>e_max) e_max = expires;
512                                 } else {
513                                         e_max = expires;
514                                 }
515                         }
516                 }
517 #endif
518         }
519
520         if (r) {
521                 if (r->contacts)
522                         build_contact(_m, r->contacts, &u->host);
523                 ul.release_urecord(r);
524         } else { /* No contacts found */
525                 build_contact(_m, NULL, &u->host);
526         }
527
528 #ifdef USE_TCP
529         if ( tcp_check && e_max>0 ) {
530                 e_max -= act_time;
531                 /*FIXME: Do we want this in the sr core?*/
532                 /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/
533         }
534 #endif
535
536         return 0;
537 error:
538         if (r)
539                 ul.delete_urecord(_d, _a, r);
540         return -1;
541 }
542
543
544 static int test_max_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c,
545                                                                                 ucontact_info_t *ci, int mc)
546 {
547         int num;
548         int e;
549         ucontact_t* ptr, *cont;
550         int ret;
551         
552         num = 0;
553         ptr = _r->contacts;
554         while(ptr) {
555                 if (VALID_CONTACT(ptr, act_time)) {
556                         num++;
557                 }
558                 ptr = ptr->next;
559         }
560         LM_DBG("%d valid contacts\n", num);
561         
562         for( ; _c ; _c = get_next_contact(_c) ) {
563                 /* calculate expires */
564                 calc_contact_expires(_m, _c->expires, &e);
565
566                 ret = ul.get_ucontact_by_instance( _r, &_c->uri, ci, &cont);
567                 if (ret==-1) {
568                         LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
569                         rerrno = R_INV_CSEQ;
570                         return -1;
571                 } else if (ret==-2) {
572                         continue;
573                 }
574                 if (ret > 0) {
575                         /* Contact not found */
576                         if (e != 0) num++;
577                 } else {
578                         if (e == 0) num--;
579                 }
580         }
581         
582         LM_DBG("%d contacts after commit\n", num);
583         if (num > mc) {
584                 LM_INFO("too many contacts for AOR <%.*s>\n", _r->aor.len, _r->aor.s);
585                 rerrno = R_TOO_MANY;
586                 return -1;
587         }
588
589         return 0;
590 }
591
592
593 /*! \brief
594  * Message contained some contacts and appropriate
595  * record was found, so we have to walk through
596  * all contacts and do the following:
597  * 1) If contact in usrloc doesn't exists and
598  *    expires > 0, insert new contact
599  * 2) If contact in usrloc exists and expires
600  *    > 0, update the contact
601  * 3) If contact in usrloc exists and expires
602  *    == 0, delete contact
603  */
604 static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
605                                                                                 int _mode)
606 {
607         ucontact_info_t *ci;
608         ucontact_t *c, *ptr, *ptr0;
609         int expires, ret, updated;
610         unsigned int flags;
611 #ifdef USE_TCP
612         int e_max, tcp_check;
613         struct sip_uri uri;
614 #endif
615         int rc;
616         contact_t* _c;
617         int maxc;
618
619         /* mem flag */
620         flags = mem_only;
621
622         rc = 0;
623         /* pack the contact_info */
624         if ( (ci=pack_ci( _m, 0, 0, flags))==0 ) {
625                 LM_ERR("failed to initial pack contact info\n");
626                 goto error;
627         }
628
629         if (!_mode) {
630                 maxc = reg_get_crt_max_contacts();
631                 if(maxc>0) {
632                         _c = get_first_contact(_m);
633                         if(test_max_contacts(_m, _r, _c, ci, maxc) != 0)
634                                 goto error;
635                 }
636         }
637
638 #ifdef USE_TCP
639         if ( (_m->flags&tcp_persistent_flag) &&
640         (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS||_m->rcv.proto==PROTO_WS||_m->rcv.proto==PROTO_WSS)) {
641                 e_max = -1;
642                 tcp_check = 1;
643         } else {
644                 e_max = tcp_check = 0;
645         }
646 #endif
647
648         _c = get_first_contact(_m);
649         updated=0;
650         for( ; _c ; _c = get_next_contact(_c) ) {
651                 /* calculate expires */
652                 calc_contact_expires(_m, _c->expires, &expires);
653
654                 /* search for the contact*/
655                 ret = ul.get_ucontact_by_instance( _r, &_c->uri, ci, &c);
656                 if (ret==-1) {
657                         LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
658                         rerrno = R_INV_CSEQ;
659                         goto error;
660                 } else if (ret==-2) {
661                         if(expires!=0 && _mode)
662                                 break;
663                         continue;
664                 }
665
666                 if ( ret > 0 ) {
667                         /* Contact not found -> expired? */
668                         if (expires==0)
669                                 continue;
670
671                         /* pack the contact_info */
672                         if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
673                                 LM_ERR("failed to extract contact info\n");
674                                 goto error;
675                         }
676
677                         if (ul.insert_ucontact( _r, &_c->uri, ci, &c) < 0) {
678                                 rerrno = R_UL_INS_C;
679                                 LM_ERR("failed to insert contact\n");
680                                 goto error;
681                         }
682                         rc = 1;
683                         if(_mode)
684                         {
685                                 ptr=_r->contacts;
686                                 while(ptr)
687                                 {
688                                         ptr0 = ptr;
689                                         if(ptr!=c)
690                                                 ul.delete_ucontact(_r, ptr);
691                                         ptr=ptr0->next;
692                                 }
693                                 updated=1;
694                         }
695                 } else {
696                         /* Contact found */
697                         if (expires == 0) {
698                                 /* it's expired */
699                                 if (mem_only) {
700                                         c->flags |= FL_MEM;
701                                 } else {
702                                         c->flags &= ~FL_MEM;
703                                 }
704
705                                 if (ul.delete_ucontact(_r, c) < 0) {
706                                         rerrno = R_UL_DEL_C;
707                                         LM_ERR("failed to delete contact\n");
708                                         goto error;
709                                 }
710                                 rc = 3;
711                         } else {
712                                 /* do update */
713                                 /* pack the contact specific info */
714                                 if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
715                                         LM_ERR("failed to pack contact specific info\n");
716                                         goto error;
717                                 }
718
719                                 if(_mode)
720                                 {
721                                         ptr=_r->contacts;
722                                         while(ptr)
723                                         {
724                                                 ptr0 = ptr;
725                                                 if(ptr!=c)
726                                                         ul.delete_ucontact(_r, ptr);
727                                                 ptr=ptr0->next;
728                                         }
729                                         updated=1;
730                                 }
731                                 if (ul.update_ucontact(_r, c, ci) < 0) {
732                                         rerrno = R_UL_UPD_C;
733                                         LM_ERR("failed to update contact\n");
734                                         goto error;
735                                 }
736                                 rc = 2;
737                         }
738                 }
739 #ifdef USE_TCP
740                 if (tcp_check) {
741                         /* parse contact uri to see if transport is TCP */
742                         if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) {
743                                 LM_ERR("failed to parse contact <%.*s>\n", 
744                                                 _c->uri.len, _c->uri.s);
745                         } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS || uri.proto==PROTO_WS || uri.proto==PROTO_WSS) {
746                                 if (e_max>0) {
747                                         LM_WARN("multiple TCP contacts on single REGISTER\n");
748                                 }
749                                 if (expires>e_max) e_max = expires;
750                         }
751                 }
752 #endif
753                 /* have one contact only -- break */
754                 if(updated)
755                         break;
756         }
757
758 #ifdef USE_TCP
759         if ( tcp_check && e_max>-1 ) {
760                 if (e_max) e_max -= act_time;
761                 /*FIXME: Do we want this in the sr core? */
762                 /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/
763         }
764 #endif
765
766         return rc;
767 error:
768         return -1;
769 }
770
771
772 /*! \brief
773  * This function will process request that
774  * contained some contact header fields
775  */
776 static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
777                 str* _a, int _mode)
778 {
779         int res;
780         int ret;
781         urecord_t* r;
782         sip_uri_t *u;
783
784         u = parse_to_uri(_m);
785         if(u==NULL)
786                 return -2;
787
788         ret = 0;
789         ul.lock_udomain(_d, _a);
790         res = ul.get_urecord(_d, _a, &r);
791         if (res < 0) {
792                 rerrno = R_UL_GET_R;
793                 LM_ERR("failed to retrieve record from usrloc\n");
794                 ul.unlock_udomain(_d, _a);
795                 return -2;
796         }
797
798         if (res == 0) { /* Contacts found */
799                 if ((ret=update_contacts(_m, r, _mode)) < 0) {
800                         build_contact(_m, r->contacts, &u->host);
801                         ul.release_urecord(r);
802                         ul.unlock_udomain(_d, _a);
803                         return -3;
804                 }
805                 build_contact(_m, r->contacts, &u->host);
806                 ul.release_urecord(r);
807         } else {
808                 if (insert_contacts(_m, _d, _a) < 0) {
809                         ul.unlock_udomain(_d, _a);
810                         return -4;
811                 }
812                 ret = 1;
813         }
814         ul.unlock_udomain(_d, _a);
815         return ret;
816 }
817
818
819 /*!\brief
820  * Process REGISTER request and save it's contacts
821  */
822 #define is_cflag_set(_name) (((unsigned int)_cflags)&(_name))
823 int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri)
824 {
825         contact_t* c;
826         int st, mode;
827         str aor;
828         int ret;
829         sip_uri_t *u;
830
831         u = parse_to_uri(_m);
832         if(u==NULL)
833                 goto error;
834
835         rerrno = R_FINE;
836         ret = 1;
837
838         if (parse_message(_m) < 0) {
839                 goto error;
840         }
841
842         if (check_contacts(_m, &st) > 0) {
843                 goto error;
844         }
845         
846         get_act_time();
847         c = get_first_contact(_m);
848
849         if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor, NULL) < 0) {
850                 LM_ERR("failed to extract Address Of Record\n");
851                 goto error;
852         }
853
854         mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE;
855
856         if (c == 0) {
857                 if (st) {
858                         if (star(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error;
859                         else ret=3;
860                 } else {
861                         if (no_contacts(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error;
862                         else ret=4;
863                 }
864         } else {
865                 mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0;
866                 if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode)) < 0)
867                         goto error;
868                 ret = (ret==0)?1:ret;
869         }
870
871         update_stat(accepted_registrations, 1);
872
873         /* Only send reply upon request, not upon reply */
874         if ((is_route_type(REQUEST_ROUTE)) && !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0))
875                 return -1;
876
877         return ret;
878 error:
879         update_stat(rejected_registrations, 1);
880         if (is_route_type(REQUEST_ROUTE) && !is_cflag_set(REG_SAVE_NORPL_FL) )
881                 reg_send_reply(_m);
882
883         return 0;
884 }
885
886 int unregister(struct sip_msg* _m, udomain_t* _d, str* _uri)
887 {
888         str aor = {0, 0};
889         sip_uri_t *u;
890
891         u = parse_to_uri(_m);
892         if(u==NULL)
893                 return -2;
894
895
896         if (extract_aor(_uri, &aor, NULL) < 0) {
897                 LM_ERR("failed to extract Address Of Record\n");
898                 return -1;
899         }
900
901         if (star(_m, _d, &aor, &u->host) < 0)
902         {
903                 LM_ERR("error unregistering user [%.*s]\n", aor.len, aor.s);
904                 return -1;
905         }
906         return 1;
907 }
908