registrar_subscribe.c

Go to the documentation of this file.
00001 /*
00002  * $Id: registrar_subscribe.c 435 2007-08-20 11:51:14Z vingarzan $
00003  *  
00004  * Copyright (C) 2004-2006 FhG Fokus
00005  *
00006  * This file is part of Open IMS Core - an open source IMS CSCFs & HSS
00007  * implementation
00008  *
00009  * Open IMS Core is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * For a license to use the Open IMS Core software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact Fraunhofer FOKUS by e-mail at the following
00017  * addresses:
00018  *     info@open-ims.org
00019  *
00020  * Open IMS Core is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  * 
00025  * It has to be noted that this Open Source IMS Core System is not 
00026  * intended to become or act as a product in a commercial context! Its 
00027  * sole purpose is to provide an IMS core reference implementation for 
00028  * IMS technology testing and IMS application prototyping for research 
00029  * purposes, typically performed in IMS test-beds.
00030  * 
00031  * Users of the Open Source IMS Core System have to be aware that IMS
00032  * technology may be subject of patents and licence terms, as being 
00033  * specified within the various IMS-related IETF, ITU-T, ETSI, and 3GPP
00034  * standards. Thus all Open IMS Core users have to take notice of this 
00035  * fact and have to agree to check out carefully before installing, 
00036  * using and extending the Open Source IMS Core System, if related 
00037  * patents and licences may become applicable to the intended usage 
00038  * context.  
00039  *
00040  * You should have received a copy of the GNU General Public License
00041  * along with this program; if not, write to the Free Software
00042  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00043  * 
00044  */
00045 
00056 #include "registrar_subscribe.h"
00057 
00058 #include <libxml/xmlschemas.h>
00059 #include <libxml/parser.h>
00060  
00061 
00062 #include "registrar_storage.h"
00063 #include "mod.h" 
00064 #include "../../mem/mem.h"
00065 #include "../../mem/shm_mem.h"
00066 #include "../../parser/parse_uri.h"
00067 #include "../../locking.h"
00068 #include "../tm/tm_load.h"
00069 #include "../dialog/dlg_mod.h"
00070 #include "sip.h"
00071 #include "ims_pm.h"
00072 
00073 extern struct tm_binds tmb;         
00074 extern dlg_func_t dialogb;          
00076 extern str pcscf_name_str;          
00077 extern str pcscf_path_str;          
00079 extern time_t time_now;             
00081 extern r_hash_slot *registrar;      
00082 extern int r_hash_size;             
00084 extern int pcscf_subscribe_retries; 
00086 r_subscription_hash_slot *subscriptions=0;
00087 extern int subscriptions_hash_size; 
00098 inline unsigned int get_subscription_hash(str uri)
00099 {
00100 #define h_inc h+=v^(v>>3)
00101    char* p;
00102    register unsigned v;
00103    register unsigned h;
00104    h=0;
00105    for (p=uri.s; p<=(uri.s+uri.len-4); p+=4){
00106        v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
00107        h_inc;
00108    }
00109    v=0;
00110    for (;p<(uri.s+uri.len); p++) {
00111        v<<=8;
00112        v+=*p;
00113    }
00114    h_inc;
00115    h=((h)+(h>>11))+((h>>13)+(h>>23));
00116    return (h)%subscriptions_hash_size;
00117 #undef h_inc 
00118 }
00119 
00124 inline void subs_lock(unsigned int hash)
00125 {
00126 //  LOG(L_CRIT,"GET %d\n",hash);
00127     lock_get(subscriptions[hash].lock);
00128 //  LOG(L_CRIT,"GOT %d\n",hash);
00129 }
00134 inline void subs_unlock(unsigned int hash)
00135 {
00136 //  LOG(L_CRIT,"REL %d\n",hash);    
00137     lock_release(subscriptions[hash].lock);
00138 }
00143 int r_subscription_init()
00144 {
00145     int i;
00146     subscriptions = shm_malloc(sizeof(r_subscription_hash_slot)*subscriptions_hash_size);
00147     if (!subscriptions) return 0;
00148     memset(subscriptions,0,sizeof(r_subscription_hash_slot)*subscriptions_hash_size);
00149     for(i=0;i<subscriptions_hash_size;i++){
00150         subscriptions[i].lock = lock_alloc();
00151         if (!subscriptions[i].lock) return 0;
00152         subscriptions[i].lock = lock_init(subscriptions[i].lock);
00153     }
00154     return 1;
00155 }
00156 
00160 void r_subscription_destroy()
00161 {
00162     int i;
00163     r_subscription *s,*ns;
00164     for(i=0;i<subscriptions_hash_size;i++){
00165         subs_lock(i);
00166         s = subscriptions[i].head;
00167         while(s){
00168             ns = s->next;
00169             //TODO send out unSUBSCRIBE
00170             free_r_subscription(s);
00171             s = ns;
00172         }
00173         lock_destroy(subscriptions[i].lock);
00174         lock_dealloc(subscriptions[i].lock);
00175     }   
00176     shm_free(subscriptions);
00177 }
00178 
00179 
00187 int P_subscribe(struct sip_msg *rpl, char* str1, char* str2)
00188 {
00189     int expires_hdr=0,r,max_expires;
00190     str public_id={0,0};
00191     contact_t* c=0;
00192     contact_body_t* b=0;    
00193     
00194     cscf_get_first_p_associated_uri(rpl,&public_id);
00195     
00196     expires_hdr = cscf_get_expires_hdr(rpl);
00197     
00198     if (parse_headers(rpl, HDR_EOH_F, 0) <0) {
00199         LOG(L_ERR,"ERR:"M_NAME":P_subscribe: error parsing headers\n");
00200         return CSCF_RETURN_ERROR;
00201     }   
00202     
00203     b = cscf_parse_contacts(rpl);
00204     
00205     if (!b||!b->contacts) {
00206         LOG(L_DBG,"DBG:"M_NAME":P_subscribe: No contacts found\n");
00207         return CSCF_RETURN_FALSE;
00208     }
00209     
00210     if (b) c = b->contacts;
00211     
00212     max_expires = expires_hdr;
00213     while(c){
00214         r = expires_hdr;
00215         if (str2int(&(c->expires->body), (unsigned int*)&r) < 0) {
00216             r = 0;
00217         }
00218         if (r>max_expires) max_expires = r;
00219         c = c->next;
00220     }
00221     if (max_expires<=0){
00222         LOG(L_INFO,"DBG:"M_NAME":P_subscribe: skipped because de-register\n");      
00223         return CSCF_RETURN_FALSE;       
00224     }
00225     
00226     if (public_id.s){
00227 //      if (max_expires==0)
00228 //          r_subscribe(public_id,0);
00229 //      else
00230         r_subscribe(public_id,max_expires+30);
00231         return CSCF_RETURN_TRUE;
00232     }else{
00233         return CSCF_RETURN_FALSE;
00234     }
00235 }
00236 
00243 int r_subscribe(str uri,int duration)
00244 {
00245     r_subscription *s;
00246     /* first we try to update. if not found, add it */
00247     s = get_r_subscription(uri);    
00248     if (s){
00249         s->duration = duration;
00250         s->attempts_left=pcscf_subscribe_retries;
00251         subs_unlock(s->hash);
00252     }else{          
00253         s = new_r_subscription(uri,duration);
00254         if (!s){
00255             LOG(L_ERR,"ERR:"M_NAME":r_subscribe: Error creating new subscription\n");
00256             return 0;
00257         }
00258         add_r_subscription(s);
00259         s->attempts_left=pcscf_subscribe_retries;
00260     }
00261         
00262     return 1;
00263 }
00264 
00265 
00266 static str method={"SUBSCRIBE",9};
00267 static str event_hdr={"Event: reg\r\n",12};
00268 static str accept_hdr={"Accept: application/reginfo+xml\r\n",33};
00269 static str content_len_hdr={"Content-Length: 0\r\n",19};
00270 static str max_fwds_hdr={"Max-Forwards: 10\r\n",18};
00271 static str expires_s={"Expires: ",9};
00272 static str expires_e={"\r\n",2};
00273 static str contact_s={"Contact: <",10};
00274 static str contact_e={">\r\n",3};
00275 static str p_asserted_identity_s={"P-Asserted-Identity: <",22};
00276 static str p_asserted_identity_e={">\r\n",3};
00284 int r_send_subscribe(r_subscription *s,int duration)
00285 {
00286     str h={0,0};
00287 
00288     LOG(L_DBG,"DBG:"M_NAME":r_send_subscribe: SUBSCRIBE to <%.*s>\n",
00289         s->req_uri.len,s->req_uri.s);
00290     
00291     h.len = event_hdr.len+accept_hdr.len+content_len_hdr.len+max_fwds_hdr.len;
00292     h.len += expires_s.len + 12 + expires_e.len;
00293 
00294     h.len += contact_s.len + pcscf_name_str.len + contact_e.len;
00295     if (pcscf_path_str.len) h.len += p_asserted_identity_s.len + 
00296         p_asserted_identity_e.len + pcscf_path_str.len;
00297 
00298     h.s = pkg_malloc(h.len);
00299     if (!h.s){
00300         LOG(L_ERR,"ERR:"M_NAME":r_send_subscribe: Error allocating %d bytes\n",h.len);
00301         h.len = 0;
00302         return 0;
00303     }
00304 
00305     h.len = 0;
00306     STR_APPEND(h,event_hdr);
00307     STR_APPEND(h,accept_hdr);
00308     STR_APPEND(h,content_len_hdr);
00309     STR_APPEND(h,max_fwds_hdr);
00310 
00311     STR_APPEND(h,expires_s);
00312     sprintf(h.s+h.len,"%d",duration);
00313     h.len += strlen(h.s+h.len);
00314     STR_APPEND(h,expires_e);
00315 
00316     STR_APPEND(h,contact_s);
00317     STR_APPEND(h,pcscf_name_str);
00318     STR_APPEND(h,contact_e);
00319     
00320     if (pcscf_path_str.len) {
00321         STR_APPEND(h,p_asserted_identity_s);
00322         STR_APPEND(h,pcscf_path_str);
00323         STR_APPEND(h,p_asserted_identity_e);
00324     }
00325     
00326     if (!s->dialog){
00327         /* this is the first request in the dialog */
00328         if (tmb.new_dlg_uac(0,0,1,&pcscf_name_str,&s->req_uri,&s->dialog)<0){
00329             LOG(L_ERR,"ERR:"M_NAME":r_send_subscribe: Error creating a dialog for SUBSCRIBE\n");
00330             goto error;
00331         }
00332         if (dialogb.request_outside(&method, &h, 0, s->dialog, r_subscribe_response,  0) < 0){
00333             LOG(L_ERR,"ERR:"M_NAME":r_send_subscribe: Error sending initial request in a SUBSCRIBE dialog\n");
00334             goto error;
00335         }       
00336     }else{
00337         /* this is a subsequent subscribe */
00338         if (dialogb.request_inside(&method, &h, 0, s->dialog, r_subscribe_response,  0) < 0){
00339             LOG(L_ERR,"ERR:"M_NAME":r_send_subscribe: Error sending subsequent request in a SUBSCRIBE dialog\n");
00340             goto error;
00341         }               
00342     }
00343 
00344     if (h.s) pkg_free(h.s);
00345     return 1;
00346 
00347 error:
00348     if (h.s) pkg_free(h.s);
00349     return 0;
00350 }
00351 
00355 void r_subscribe_response(struct cell *t,int type,struct tmcb_params *ps)
00356 {
00357     str req_uri;
00358     int expires;
00359     r_subscription *s=0;
00360     LOG(L_DBG,"DBG:"M_NAME":r_subscribe_response: code %d\n",ps->code);
00361     if (!ps->rpl || ps->rpl==(void*) -1) {
00362         LOG(L_ERR,"INF:"M_NAME":r_subscribe_response: No reply\n");
00363         return; 
00364     }
00365     if (!cscf_get_to_uri(ps->rpl,&req_uri)){
00366         LOG(L_ERR,"INF:"M_NAME":r_subscribe_response: Error extracting the original Req-URI from To header\n");
00367         return;
00368     }       
00369     s = get_r_subscription(req_uri);
00370     if (!s){
00371         LOG(L_ERR,"INF:"M_NAME":r_subscribe_response: received a SUBSCRIBE response but no subscription for <%.*s>\n",
00372             req_uri.len,req_uri.s);
00373         return;
00374     }
00375     if (ps->code>=200 && ps->code<300){
00376         expires = cscf_get_expires_hdr(ps->rpl);
00377         update_r_subscription(s,expires);
00378         tmb.dlg_response_uac(s->dialog, ps->rpl, IS_TARGET_REFRESH);
00379     }else
00380         if (ps->code==404){
00381             update_r_subscription(s,0);         
00382             //tmb.dlg_response_uac(s->dialog, ps->rpl, IS_TARGET_REFRESH);
00383         }else{
00384             LOG(L_INFO,"INF:"M_NAME":r_subscribe_response: SUBSCRIRE response code %d ignored\n",ps->code);             
00385         }   
00386     if (s) subs_unlock(s->hash);        
00387 }
00388 
00389 
00390 #ifdef WITH_IMS_PM
00391     static str zero={0,0};
00392 #endif
00393 
00399 void subscription_timer(unsigned int ticks, void* param)
00400 {
00401     r_subscription *s,*ns;
00402     int i;
00403     #ifdef WITH_IMS_PM
00404         int subs_cnt=0;
00405     #endif
00406     for(i=0;i<subscriptions_hash_size;i++){
00407         subs_lock(i);
00408         s = subscriptions[i].head;
00409         r_act_time();
00410         while(s){
00411             ns = s->next;           
00412             if (s->attempts_left > 0 ){
00413                 /* attempt to send a subscribe */
00414                 if (!r_send_subscribe(s,s->duration)){
00415                     LOG(L_ERR,"ERR:"M_NAME":subscription_timer: Error on SUBSCRIBE (%d times)... droping\n",
00416                         pcscf_subscribe_retries);
00417                     del_r_subscription_nolock(s);
00418                 }else{
00419                     s->attempts_left--;
00420                     #ifdef WITH_IMS_PM
00421                         subs_cnt++;
00422                     #endif
00423                 }
00424             }else if (s->attempts_left==0) {
00425                 /* we failed to many times, drop the subscription */
00426                 LOG(L_ERR,"ERR:"M_NAME":subscription_timer: Error on SUBSCRIBE for %d times... aborting\n",pcscf_subscribe_retries);
00427                 del_r_subscription_nolock(s);                                       
00428             }else{
00429                 /* we are subscribed already */
00430                 /* if expired, drop it */
00431                 if (s->expires<time_now) 
00432                     del_r_subscription_nolock(s);
00433                 #ifdef WITH_IMS_PM
00434                     else subs_cnt++;
00435                 #endif
00436                     
00437                 /* if not expired, check for renewal */
00438 //      Commented as the S-CSCF should adjust the subscription time accordingly             
00439 //              if ((s->duration<1200 && s->expires-time_now<s->duration/2)||
00440 //                  (s->duration>=1200 && s->expires-time_now<600))
00441 //              {
00442 //                  /* if we need a resubscribe, we mark it as such and try to subscribe again */                   
00443 //                  s->attempts_left = pcscf_subscribe_retries;
00444 //                  ns = s;
00445 //              }
00446             }
00447             s = ns;
00448         }   
00449         subs_unlock(i);
00450     }
00451     print_subs(L_INFO);
00452     #ifdef WITH_IMS_PM
00453         IMS_PM_LOG01(RD_NbrSubs,subs_cnt);
00454     #endif  
00455 }
00456 
00457 
00458 
00459 
00460 
00469 r_subscription* new_r_subscription(str req_uri,int duration)
00470 {
00471     r_subscription *s=0;
00472     
00473     s = shm_malloc(sizeof(r_subscription));
00474     if (!s){
00475         LOG(L_ERR,"ERR:"M_NAME":new_r_subscription: Error allocating %d bytes\n",
00476             sizeof(r_subscription));
00477         goto error;
00478     }
00479     memset(s,0,sizeof(r_subscription));
00480     
00481     STR_SHM_DUP(s->req_uri,req_uri,"new_r_subscription");
00482     if (!s->req_uri.s) goto error;
00483         
00484     s->duration = duration;
00485     s->expires = 0;
00486     
00487     return s;
00488 error:
00489 out_of_memory:
00490     if (s->req_uri.s) shm_free(s->req_uri.s);
00491     if (s) shm_free(s); 
00492     return 0;
00493 }
00494 
00499 void add_r_subscription(r_subscription *s)
00500 {
00501     if (!s) return;
00502     s->hash = get_subscription_hash(s->req_uri);
00503     subs_lock(s->hash);
00504         s->next = 0;
00505         s->prev = subscriptions[s->hash].tail;
00506         if (subscriptions[s->hash].tail) subscriptions[s->hash].tail->next = s;         
00507         subscriptions[s->hash].tail = s;
00508         if (!subscriptions[s->hash].head) subscriptions[s->hash].head = s;      
00509     subs_unlock(s->hash);
00510 }
00511 
00519 int update_r_subscription(r_subscription *s,int expires)
00520 {
00521     LOG(L_DBG,"DBG:"M_NAME":update_r_subscription: refreshing subscription for <%.*s> [%d]\n",
00522         s->req_uri.len,s->req_uri.s,expires);
00523     s->attempts_left = -1;
00524     if (expires == 0) del_r_subscription_nolock(s);
00525     else s->expires = expires+time_now;;
00526     subs_unlock(s->hash);   
00527     return 1;
00528 }
00529 
00536 r_subscription* get_r_subscription(str aor)
00537 {
00538     r_subscription *s;
00539     unsigned int hash = get_subscription_hash(aor);
00540     subs_lock(hash);
00541         s = subscriptions[hash].head;
00542         while(s){
00543             if (s->req_uri.len == aor.len &&
00544                 strncasecmp(s->req_uri.s,aor.s,aor.len)==0)
00545             {
00546                 return s;
00547             }
00548             s = s->next;
00549         }
00550     subs_unlock(hash);  
00551     return 0;
00552 }
00553 
00559 int is_r_subscription(str aor)
00560 {
00561     r_subscription *s;
00562     unsigned int hash = get_subscription_hash(aor);
00563     subs_lock(hash);
00564         s = subscriptions[hash].head;
00565         while(s){
00566             if (s->req_uri.len == aor.len &&
00567                 strncasecmp(s->req_uri.s,aor.s,aor.len)==0)
00568             {
00569                 subs_unlock(hash);  
00570                 return 1;
00571             }
00572             s = s->next;
00573         }
00574     subs_unlock(hash);  
00575     return 0;
00576 }
00577 
00582 void del_r_subscription(r_subscription *s)
00583 {
00584     if (!s) return;
00585     subs_lock(s->hash);
00586         if (subscriptions[s->hash].head == s) subscriptions[s->hash].head = s->next;
00587         else s->prev->next = s->next;
00588         if (subscriptions[s->hash].tail == s) subscriptions[s->hash].tail = s->prev;
00589         else s->next->prev = s->prev;
00590     subs_unlock(s->hash);
00591     free_r_subscription(s);
00592 }
00593 
00599 void del_r_subscription_nolock(r_subscription *s)
00600 {
00601     if (!s) return;
00602     if (subscriptions[s->hash].head == s) subscriptions[s->hash].head = s->next;
00603     else s->prev->next = s->next;
00604     if (subscriptions[s->hash].tail == s) subscriptions[s->hash].tail = s->prev;
00605     else s->next->prev = s->prev;
00606     free_r_subscription(s);
00607 }
00608 
00613 void free_r_subscription(r_subscription *s)
00614 {
00615     if (s){
00616         if (s->req_uri.s) shm_free(s->req_uri.s);
00617         if (s->dialog) tmb.free_dlg(s->dialog);
00618         shm_free(s);
00619     }
00620 }
00621 
00622 void print_subs(int log_level)
00623 {
00624     r_subscription *s;
00625     int i;
00626     if (debug<log_level) return; /* to avoid useless calls when nothing will be printed */  
00627     LOG(log_level,ANSI_GREEN"INF:"M_NAME":----------  Subscription list begin ---------\n");
00628     for(i=0;i<subscriptions_hash_size;i++){
00629         subs_lock(i);
00630         s = subscriptions[i].head;
00631         r_act_time();
00632         while(s){
00633             LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4u]\tP: <"ANSI_BLUE"%.*s"ANSI_GREEN"> D:["ANSI_CYAN"%5d"ANSI_GREEN"] E:["ANSI_MAGENTA"%5d"ANSI_GREEN"] Att:[%2d]\n",
00634                 s->hash,s->req_uri.len,s->req_uri.s,s->duration,(int)(s->expires-time_now),s->attempts_left);
00635             s = s->next;            
00636         }
00637         subs_unlock(i);
00638     }
00639     LOG(log_level,ANSI_GREEN"INF:"M_NAME":----------  Subscription list end -----------\n");    
00640 }
00641 
00642 
00643 
00644 
00645 
00646 
00647 
00648 
00649 char *pcscf_reginfo_dtd;
00651 static xmlDtdPtr    dtd=0;  
00652 static xmlValidCtxt cvp;    
00659 int parser_init(char *dtd_filename)
00660 {
00661     dtd = xmlParseDTD(NULL,(unsigned char*)dtd_filename);
00662     if (!dtd){
00663         LOG(L_ERR,"ERR:"M_NAME":parser_init: unsuccesful DTD parsing from file <%s>\n",
00664             dtd_filename);
00665         return 0;
00666     }
00667     cvp.userData = (void*)stderr;
00668     cvp.error = (xmlValidityErrorFunc) fprintf;
00669     cvp.warning = (xmlValidityWarningFunc) fprintf;
00670     return 1;
00671 }
00672 
00676 void parser_destroy()
00677 {
00678     xmlCleanupParser();
00679 }
00680 
00681 
00682 
00688 static inline void space_trim_dup(str *dest, char *src)
00689 {
00690     int i;
00691     dest->s=0;
00692     dest->len=0;
00693     if (!src) return;
00694     dest->len = strlen(src);
00695     i = dest->len-1;
00696     while((src[i]==' '||src[i]=='\t') && i>0) 
00697         i--;
00698     i=0;
00699     while((src[i]==' '||src[i]=='\t') && i<dest->len)
00700         i++;
00701     dest->len -= i;
00702     dest->s = pkg_malloc(dest->len);
00703     if (!dest->s) {
00704         LOG(L_ERR,"ERR:"M_NAME":space_trim_dup: Out of memory allocating %d bytes\n",dest->len);
00705         dest->len=0;
00706         return;
00707     }
00708     memcpy(dest->s,src+i,dest->len);
00709 }
00710 
00716 r_notification* r_notification_parse(str xml)
00717 {
00718     r_notification *n;
00719     r_registration *r;
00720     r_regcontact *rc;
00721     xmlDocPtr doc=0;
00722     xmlNodePtr root=0,child=0,nephew=0,node=0;
00723     xmlChar *reginfo_state=0,*x;
00724     char c=0;
00725     
00726     n = pkg_malloc(sizeof(r_notification));
00727     if (!n) {
00728         LOG(L_ERR,"ERR:"M_NAME":r_notification_parse: Error allocating %d bytes\n",
00729             sizeof(r_notification));
00730         goto error;
00731     }
00732     memset(n,0,sizeof(r_notification));
00733 
00734     if (!dtd) parser_init(pcscf_reginfo_dtd);
00735     doc=0;
00736     c = xml.s[xml.len];
00737     xml.s[xml.len]=0;
00738     doc = xmlParseDoc((unsigned char *)xml.s);
00739     if (!doc){
00740         LOG(L_ERR,"ERR:"M_NAME":r_notification_parse:  This is not a valid XML <%.*s>\n",
00741             xml.len,xml.s);
00742         goto error;
00743     }
00744     if (xmlValidateDtd(&cvp,doc,dtd)!=1){
00745         LOG(L_ERR,"ERR:"M_NAME":r_notification_parse:  Verification of XML against DTD failed <%.*s>\n",
00746             xml.len,xml.s);
00747         goto error;
00748     }
00749     root = xmlDocGetRootElement(doc);
00750     if (!root){
00751         LOG(L_ERR,"ERR:"M_NAME":r_notification_parse:  Empty XML <%.*s>\n",
00752             xml.len,xml.s);
00753         goto error;
00754     }
00755 
00756     reginfo_state = xmlGetProp(root,(xmlChar*)"state");
00757     LOG(L_DBG,"DBG:"M_NAME":r_notification_parse: reginfo_state <%s>\n",
00758             reginfo_state);
00759     if (reginfo_state[0]=='f'||reginfo_state[0]=='F')
00760         n->state = IMS_REGINFO_FULL;
00761     else 
00762         n->state = IMS_REGINFO_PARTIAL;
00763     
00764     for(child = root->children; child; child = child->next)
00765         if (child->type == XML_ELEMENT_NODE)
00766     {
00767         r = pkg_malloc(sizeof(r_registration));
00768         if (!r){
00769             LOG(L_ERR,"ERR:"M_NAME":r_notification_parse: Error allocating %d bytes\n",
00770                 sizeof(r_registration));
00771             goto error;
00772         }
00773         memset(r,0,sizeof(r_registration));
00774         
00775         x = xmlGetProp(child,(xmlChar*)"id");
00776         space_trim_dup(&(r->id),(char*)x);
00777         xmlFree(x);
00778 
00779         x = xmlGetProp(child,(xmlChar*)"aor");
00780         space_trim_dup(&(r->aor),(char*)x);
00781         xmlFree(x);
00782         
00783         x = xmlGetProp(child,(xmlChar*)"state");
00784         
00785         if (x[0]=='a'||x[0]=='A') 
00786             r->state = IMS_REGINFO_ACTIVE;
00787         else 
00788             r->state = IMS_REGINFO_TERMINATED;
00789         xmlFree(x);
00790 
00791         for(nephew = child->children; nephew; nephew = nephew->next)
00792                 if (nephew->type == XML_ELEMENT_NODE)
00793         {
00794             rc = pkg_malloc(sizeof(r_regcontact));
00795             if (!rc){
00796                 LOG(L_ERR,"ERR:"M_NAME":r_notification_parse: Error allocating %d bytes\n",
00797                     sizeof(r_regcontact));
00798                 goto error;
00799             }
00800             memset(rc,0,sizeof(r_regcontact));
00801             
00802             x = xmlGetProp(nephew,(xmlChar*)"id");
00803             space_trim_dup(&(rc->id),(char*)x);
00804             xmlFree(x);
00805                 
00806             x = xmlGetProp(nephew,(xmlChar*)"state");
00807             if (x[0]=='a'||x[0]=='A') 
00808                 rc->state = IMS_REGINFO_ACTIVE;
00809             else 
00810                 rc->state = IMS_REGINFO_TERMINATED;
00811             xmlFree(x);
00812             
00813             x = xmlGetProp(nephew,(xmlChar*)"event");
00814             switch(x[0]){
00815                 case 'r':case 'R':
00816                     switch (x[2]){
00817                         case 'g': case 'G':
00818                             rc->event = IMS_REGINFO_CONTACT_REGISTERED;
00819                             break;
00820                         case 'f': case 'F':
00821                             rc->event = IMS_REGINFO_CONTACT_REFRESHED;
00822                             break;                      
00823                         case 'j': case 'J':
00824                             rc->event = IMS_REGINFO_CONTACT_REJECTED;
00825                             break;                      
00826                         default:
00827                             rc->event = IMS_REGINFO_NONE;
00828                     }
00829                     break;
00830                 case 'c':case 'C':
00831                     rc->event = IMS_REGINFO_CONTACT_CREATED;    
00832                     break;
00833                 case 's':case 'S':
00834                     rc->event = IMS_REGINFO_CONTACT_SHORTENED;  
00835                     break;
00836                 case 'e':case 'E':
00837                     rc->event = IMS_REGINFO_CONTACT_EXPIRED;    
00838                     break;
00839                 case 'd':case 'D':
00840                     rc->event = IMS_REGINFO_CONTACT_DEACTIVATED;    
00841                     break;
00842                 case 'p':case 'P':
00843                     rc->event = IMS_REGINFO_CONTACT_PROBATION;  
00844                     break;
00845                 case 'u':case 'U':
00846                     rc->event = IMS_REGINFO_CONTACT_UNREGISTERED;   
00847                     break;
00848                 default:
00849                     rc->event = IMS_REGINFO_NONE;   
00850             }
00851             xmlFree(x);
00852 
00853             x = xmlGetProp(nephew,(xmlChar*)"expires");         
00854             if (x) {
00855                 rc->expires = atoi((char*)x);
00856                 xmlFree(x);
00857             }
00858             
00859             node = nephew->children;
00860             while(node && node->type!=XML_ELEMENT_NODE)
00861                 node =node->next;
00862             if (node) {
00863                 x = xmlNodeGetContent(node);
00864                 space_trim_dup(&(rc->uri),(char*)x);
00865                 xmlFree(x);
00866             }
00867             
00868             rc->next = r->contact;
00869             r->contact = rc;
00870         }
00871         
00872         r->next = n->registration;
00873         n->registration = r;
00874                     
00875     }
00876             
00877     if (reginfo_state) xmlFree(reginfo_state);      
00878     
00879     if (doc) xmlFreeDoc(doc);
00880     xml.s[xml.len]=c;
00881     return n;
00882 error:  
00883     if (reginfo_state) xmlFree(reginfo_state);      
00884 
00885     if (doc) xmlFreeDoc(doc);
00886     xml.s[xml.len]=c;
00887     if (n) r_notification_free(n);
00888     return 0;
00889 }
00890 
00891 
00892 
00899 int r_notification_process(r_notification *n,int expires)
00900 {
00901     r_registration *r;
00902     r_regcontact *rc;   
00903     r_contact *c;
00904     struct sip_uri puri;
00905     enum Reg_States reg_state;
00906     int expires2;
00907     r_subscription *s=0;
00908     
00909     r_notification_print(n);    
00910     if (!n) return 0;
00911     
00912     r_act_time();
00913     r = n->registration;
00914     while(r){
00915         
00916         rc = r->contact;
00917         while(rc){
00918             if (parse_uri(rc->uri.s,rc->uri.len,&puri)<0){
00919                 LOG(L_ERR,"ERR:"M_NAME":r_notification_process: Error parsing Contact URI <%.*s>\n",
00920                     rc->uri.len,rc->uri.s);
00921                 goto next;
00922             }
00923 //          LOG(L_CRIT,"DBG:"M_NAME":r_notification_process: refreshing contacts <%.*s> [%d]\n",rc->uri.len,rc->uri.s,rc->expires);
00924             if (rc->state==IMS_REGINFO_TERMINATED){
00925                 reg_state = DEREGISTERED;
00926                 expires2 = time_now+30;
00927                 c = update_r_contact(puri.host,puri.port_no,puri.proto,
00928                     0,&reg_state,&expires2,0,0,0);
00929                 if (c) {
00930                     LOG(L_DBG,"DBG:"M_NAME":r_notification_process: expired contact <%.*s>\n",
00931                         c->uri.len,c->uri.s);
00932                     r_unlock(c->hash);                  
00933                 }
00934             }else{
00935                 reg_state = REGISTERED;
00936                 expires2 = rc->expires+time_now;
00937                 c = update_r_contact(puri.host,puri.port_no,puri.proto,
00938                     0,&reg_state,&expires2,0,0,0);
00939                 if (c) {
00940                     LOG(L_DBG,"DBG:"M_NAME":r_notification_process: refreshing contact <%.*s> [%d]\n",
00941                         c->uri.len,c->uri.s,rc->expires);
00942                     r_unlock(c->hash);                  
00943                 }
00944 
00945             }
00946 next:               
00947             rc = rc->next;  
00948         }
00949         s = get_r_subscription(r->aor);
00950         if (s){
00951             update_r_subscription(s,expires);
00952             subs_unlock(s->hash);
00953         }
00954         r = r->next;
00955     }
00956 
00957     return 1;
00958 }
00959 
00964 void r_notification_print(r_notification *n)
00965 {
00966     r_registration *r;
00967     r_regcontact *c;
00968     
00969     if (!n) return;
00970     LOG(L_DBG,"DBG:"M_NAME":r_notification_print: State %d\n",n->state);
00971     r = n->registration;
00972     while(r){
00973         LOG(L_DBG,"DBG:"M_NAME":r_notification_print: \tR [%d] ID<%.*s> AOR<%.*s>\n",r->state,
00974             r->id.len,r->id.s,r->aor.len,r->aor.s);
00975         c = r->contact;
00976         while(c){
00977             LOG(L_DBG,"DBG:"M_NAME":r_notification_print: \t\tC [%d]>[%d] ID<%.*s> URI<%.*s>\n",c->state,
00978                 c->event,c->id.len,c->id.s,c->uri.len,c->uri.s);
00979             c = c->next;
00980         }
00981         r = r->next;
00982     }   
00983 }
00984 
00989 void r_notification_free(r_notification *n)
00990 {
00991     r_registration *r,*nr;
00992     r_regcontact *c,*nc;
00993     r = n->registration;
00994     while(r){
00995         nr = r->next;
00996         if (r->id.s) pkg_free(r->id.s);
00997         if (r->aor.s) pkg_free(r->aor.s);
00998         c = r->contact;
00999         while(c){
01000             nc = c->next;
01001             if (c->id.s) pkg_free(c->id.s);         
01002             if (c->uri.s) pkg_free(c->uri.s);
01003             pkg_free(c);
01004             c = c->next;
01005         }
01006         pkg_free(r);
01007         r = nr;
01008     }
01009     if (n) pkg_free(n);
01010 }
01011 
01012 
01013 
01014 
01015 
01016 

Generated on Thu Oct 23 04:14:39 2008 for Open IMS Core CSCFs by  doxygen 1.5.2