void print_subs(int log_level) { r_subscription *s; int i; #ifdef SER_MOD_INTERFACE if (!is_printable(log_level)) #else if (debug<log_level) #endif return; /* to avoid useless calls when nothing will be printed */ LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Subscription list begin ---------\n"); for(i=0;i<subscriptions_hash_size;i++){ subs_lock(i); s = subscriptions[i].head; r_act_time(); while(s){ 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", s->hash,s->req_uri.len,s->req_uri.s,s->duration,(int)(s->expires-time_now),s->attempts_left); s = s->next; } subs_unlock(i); } LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Subscription list end -----------\n"); }
/** * The Subscription timer looks for almost expired subscriptions and subscribes again. * @param ticks - the current time * @param param - the generic parameter */ void subscription_timer(unsigned int ticks, void* param) { r_subscription *s,*ns; int i; #ifdef WITH_IMS_PM int subs_cnt=0; #endif for(i=0;i<subscriptions_hash_size;i++){ subs_lock(i); s = subscriptions[i].head; r_act_time(); while(s){ ns = s->next; if (s->attempts_left > 0 ){ /* attempt to send a subscribe */ if (!r_send_subscribe(s,s->duration)){ LOG(L_ERR,"ERR:"M_NAME":subscription_timer: Error on SUBSCRIBE (%d times)... droping\n", pcscf_subscribe_retries); del_r_subscription_nolock(s); }else{ s->attempts_left--; #ifdef WITH_IMS_PM subs_cnt++; #endif } }else if (s->attempts_left==0) { /* we failed to many times, drop the subscription */ LOG(L_ERR,"ERR:"M_NAME":subscription_timer: Error on SUBSCRIBE for %d times... aborting\n",pcscf_subscribe_retries); del_r_subscription_nolock(s); }else{ /* we are subscribed already */ /* if expired, drop it */ if (s->expires<time_now) del_r_subscription_nolock(s); #ifdef WITH_IMS_PM else subs_cnt++; #endif /* if not expired, check for renewal */ // Commented as the S-CSCF should adjust the subscription time accordingly // if ((s->duration<1200 && s->expires-time_now<s->duration/2)|| // (s->duration>=1200 && s->expires-time_now<600)) // { // /* if we need a resubscribe, we mark it as such and try to subscribe again */ // s->attempts_left = pcscf_subscribe_retries; // ns = s; // } } s = ns; } subs_unlock(i); } print_subs(L_INFO); #ifdef WITH_IMS_PM IMS_PM_LOG01(RD_NbrSubs,subs_cnt); #endif }
/** * Deletes a subscription from the list of subscriptions * @param s - the subscription to be deleted */ void del_r_subscription(r_subscription *s) { if (!s) return; subs_lock(s->hash); if (subscriptions[s->hash].head == s) subscriptions[s->hash].head = s->next; else s->prev->next = s->next; if (subscriptions[s->hash].tail == s) subscriptions[s->hash].tail = s->prev; else s->next->prev = s->prev; subs_unlock(s->hash); free_r_subscription(s); }
/** * Adds a subscription to the list of subscriptions at the end (FIFO). * @param s - the subscription to be added */ void add_r_subscription(r_subscription *s) { if (!s) return; s->hash = get_subscription_hash(s->req_uri); subs_lock(s->hash); s->next = 0; s->prev = subscriptions[s->hash].tail; if (subscriptions[s->hash].tail) subscriptions[s->hash].tail->next = s; subscriptions[s->hash].tail = s; if (!subscriptions[s->hash].head) subscriptions[s->hash].head = s; subs_unlock(s->hash); }
/** * Returns a subscription if it exists * \note - this returns with a lock on the subscriptions[s->hash] if found. Don't forget to unlock when done!!! * @param aor - AOR to look for * @returns 1 if found, 0 if not */ r_subscription* get_r_subscription(str aor) { r_subscription *s; unsigned int hash = get_subscription_hash(aor); subs_lock(hash); s = subscriptions[hash].head; while(s){ if (s->req_uri.len == aor.len && strncasecmp(s->req_uri.s,aor.s,aor.len)==0) { return s; } s = s->next; } subs_unlock(hash); return 0; }
void print_subs(int log_level) { r_subscription *s; int i; LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Subscription list begin ---------\n"); for(i=0;i<subscriptions_hash_size;i++){ subs_lock(i); s = subscriptions[i].head; r_act_time(); while(s){ 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", s->hash,s->req_uri.len,s->req_uri.s,s->duration,(int)(s->expires-time_now),s->attempts_left); s = s->next; } subs_unlock(i); } LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Subscription list end -----------\n"); }
/** * Destroys the subscription list */ void r_subscription_destroy() { int i; r_subscription *s,*ns; for(i=0;i<subscriptions_hash_size;i++){ subs_lock(i); s = subscriptions[i].head; while(s){ ns = s->next; //TODO send out unSUBSCRIBE free_r_subscription(s); s = ns; } lock_destroy(subscriptions[i].lock); lock_dealloc(subscriptions[i].lock); } shm_free(subscriptions); }
/** * Loads the subscriptions data from the last snapshot. * @returns 1 on success or 0 on failure */ int load_snapshot_subscriptions() { bin_data x; r_subscription *s; int k,max; FILE *f; switch (pcscf_persistency_mode){ case NO_PERSISTENCY: k=0; case WITH_FILES: f = bin_load_from_file_open(pcscf_persistency_location,"psubscriptions"); if (!f) return 0; bin_alloc(&x,128*1024); k=bin_load_from_file_read(f,&x); max = x.max; x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_subscriptions: max %d len %d\n",x.max,x.len); while(x.max<x.len){ s = bin_decode_r_subscription(&x); if (!s) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_subscriptions: Loaded r_subscription for <%.*s>\n",s->req_uri.len,s->req_uri.s); subs_lock(s->hash); s->prev = subscriptions[s->hash].tail; s->next = 0; if (subscriptions[s->hash].tail) subscriptions[s->hash].tail->next = s; subscriptions[s->hash].tail = s; if (!subscriptions[s->hash].head) subscriptions[s->hash].head = s; subs_unlock(s->hash); memmove(x.s,x.s+x.max,x.len-x.max); x.len = x.max; x.max = max; k=bin_load_from_file_read(f,&x); max = x.max; x.max = 0; } bin_free(&x); bin_load_from_file_close(f); k = 1; break; case WITH_DATABASE_BULK: k=bin_load_from_db(&x, P_SUBSCRIPTIONS); x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_subscriptions: max %d len %d\n",x.max,x.len); while(x.max<x.len){ s = bin_decode_r_subscription(&x); if (!s) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_subscriptions: Loaded r_subscription for <%.*s>\n",s->req_uri.len,s->req_uri.s); subs_lock(s->hash); s->prev = subscriptions[s->hash].tail; s->next = 0; if (subscriptions[s->hash].tail) subscriptions[s->hash].tail->next = s; subscriptions[s->hash].tail = s; if (!subscriptions[s->hash].head) subscriptions[s->hash].head = s; subs_unlock(s->hash); } bin_free(&x); break; case WITH_DATABASE_CACHE: k=bin_load_from_db(NULL, P_SUBSCRIPTIONS); //ignore x, x is empty break; default: LOG(L_ERR,"ERR:"M_NAME":load_snapshot_subscriptions: Can't resume because no such mode %d\n",pcscf_persistency_mode); k=0; } if (!k) goto error; return 1; error: return 0; }
/** * Creates a snapshots of the subscriptions and then calls the dumping function. * @returns 1 on success or 0 on failure */ int make_snapshot_subscriptions() { bin_data x={0,0,0}; r_subscription *s; int i,k; time_t unique = time(0); FILE *f; switch (pcscf_persistency_mode) { case NO_PERSISTENCY: return 0; case WITH_FILES: f = bin_dump_to_file_create(pcscf_persistency_location,"psubscriptions",unique); if (!f) return 0; for(i=0;i<subscriptions_hash_size;i++){ if (!bin_alloc(&x,1024)) goto error; subs_lock(i); s = subscriptions[i].head; if (s) { while(s){ if (!bin_encode_r_subscription(&x,s)) goto error; s = s->next; } subs_unlock(i); k = bind_dump_to_file_append(f,&x); if (k!=x.len) { LOG(L_ERR,"ERR:"M_NAME":make_snapshot_registrar: error while dumping to file - only wrote %d bytes of %d \n",k,x.len); subs_unlock(i); bin_free(&x); return 0; } } else subs_unlock(i); bin_free(&x); } return bind_dump_to_file_close(f,pcscf_persistency_location,"psubscriptions",unique); break; case WITH_DATABASE_BULK: if (!bin_alloc(&x,1024)) goto error; for(i=0;i<subscriptions_hash_size;i++){ subs_lock(i); s = subscriptions[i].head; while(s){ if (!bin_encode_r_subscription(&x,s)) goto error; s = s->next; } subs_unlock(i); } return bin_dump_to_db(&x, P_SUBSCRIPTIONS); case WITH_DATABASE_CACHE: return bin_dump_to_db(NULL, P_SUBSCRIPTIONS); //ignore x, x is empty default: LOG(L_ERR,"ERR:"M_NAME":make_snapshot_registrar: Snapshot done but no such mode %d\n",pcscf_persistency_mode); return 0; } error: if (x.s) bin_free(&x); return 0; }