pike_funcs.c

Go to the documentation of this file.
00001 /* 
00002  * $Id: pike_funcs.c 4518 2008-07-28 15:39:28Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * --------
00024  *  2003-03-11  converted to the new locking interface: locking.h --
00025  *               major changes (andrei)
00026  *  2005-05-02  flags field added to node stucture -better sync between timer
00027  *              and worker processes; some races eliminated (bogdan)
00028  *  2008-04-17  new parameter to control the module's log regarding the
00029  *               blocking/unblocking of IPs (bogdan)
00030  *  2008-04-17  the leaf nodes memorize (via flags) if they are in RED state
00031  *               (detected) or not -> better logging and MI (bogdan)
00032  */
00033 
00034 
00035 
00036 #include <stdio.h>
00037 #include <string.h>
00038 #include <stdlib.h>
00039 #include <assert.h>
00040 
00041 #include "../../mem/shm_mem.h"
00042 #include "../../locking.h"
00043 #include "../../timer.h"
00044 #include "../../ip_addr.h"
00045 #include "../../resolve.h"
00046 #include "ip_tree.h"
00047 #include "pike_funcs.h"
00048 #include "timer.h"
00049 
00050 
00051 
00052 
00053 extern gen_lock_t*       timer_lock;
00054 extern struct list_link* timer;
00055 extern int               timeout;
00056 extern int               pike_log_level;
00057 
00058 
00059 
00060 int pike_check_req(struct sip_msg *msg, char *foo, char *bar)
00061 {
00062    struct ip_node *node;
00063    struct ip_node *father;
00064    unsigned char flags;
00065    struct ip_addr* ip;
00066 
00067 
00068 #ifdef _test
00069    /* get the ip address from second via */
00070    if (parse_headers(msg, HDR_VIA1_F, 0)!=0 )
00071       return -1;
00072    if (msg->via1==0 )
00073       return -1;
00074    /* convert from string to ip_addr */
00075    ip = str2ip( &msg->via1->host );
00076    if (ip==0)
00077       return -1;
00078 #else
00079    ip = &(msg->rcv.src_ip);
00080 #endif
00081 
00082 
00083    /* first lock the proper tree branch and mark the IP with one more hit*/
00084    lock_tree_branch( ip->u.addr[0] );
00085    node = mark_node( ip->u.addr, ip->len, &father, &flags);
00086    if (node==0) {
00087       unlock_tree_branch( ip->u.addr[0] );
00088       /* even if this is an error case, we return true in script to avoid
00089        * considering the IP as marked (bogdan) */
00090       return 1;
00091    }
00092 
00093    LM_DBG("src IP [%s],node=%p; hits=[%d,%d],[%d,%d] node_flags=%d"
00094       " func_flags=%d\n", ip_addr2a( ip ), node,
00095       node->hits[PREV_POS],node->hits[CURR_POS],
00096       node->leaf_hits[PREV_POS],node->leaf_hits[CURR_POS],
00097       node->flags, flags);
00098 
00099    /* update the timer */
00100    lock_get(timer_lock);
00101    if ( flags&NEW_NODE ) {
00102       /* put this node into the timer list and remove its
00103          father only if this has one kid and is not a LEAF_NODE*/
00104       node->expires =  get_ticks() + timeout;
00105       append_to_timer( timer, &(node->timer_ll) );
00106       node->flags |= NODE_INTIMER_FLAG;
00107       if (father) {
00108          LM_DBG("father %p: flags=%d kids->next=%p\n",
00109             father,father->flags,father->kids->next);
00110          if (!(father->flags&NODE_IPLEAF_FLAG) && !father->kids->next){
00111             /* debug */
00112             assert( has_timer_set(&(father->timer_ll))
00113                && (father->flags&(NODE_EXPIRED_FLAG|NODE_INTIMER_FLAG)) );
00114             /* if the node is maked as expired by timer, let the timer
00115              * to finish and remove the node */
00116             if ( !(father->flags&NODE_EXPIRED_FLAG) ) {
00117                remove_from_timer( timer, &(father->timer_ll) );
00118                father->flags &= ~NODE_INTIMER_FLAG;
00119             } else {
00120                father->flags &= ~NODE_EXPIRED_FLAG;
00121             }
00122          }
00123       }
00124    } else {
00125       /* update the timer -> in timer can be only nodes
00126        * as IP-leaf(complete address) or tree-leaf */
00127       if (node->flags&NODE_IPLEAF_FLAG || node->kids==0) {
00128          /* tree leafs which are not potential red nodes are not update in
00129           * order to make them to expire */
00130          /* debug */
00131          assert( has_timer_set(&(node->timer_ll)) 
00132             && (node->flags&(NODE_EXPIRED_FLAG|NODE_INTIMER_FLAG)) );
00133          /* if node exprired, ignore the current hit and let is
00134           * expire in timer process */
00135          if ( !(flags&NO_UPDATE) && !(node->flags&NODE_EXPIRED_FLAG) ) {
00136             node->expires = get_ticks() + timeout;
00137             update_in_timer( timer, &(node->timer_ll) );
00138          }
00139       } else {
00140          /* debug */
00141          assert( !has_timer_set(&(node->timer_ll)) 
00142             && !(node->flags&(NODE_INTIMER_FLAG|NODE_EXPIRED_FLAG)) );
00143          /* debug */
00144          assert( !(node->flags&NODE_IPLEAF_FLAG) && node->kids );
00145       }
00146    }
00147    /*print_timer_list( timer );*/ /* debug*/
00148    lock_release(timer_lock);
00149 
00150    unlock_tree_branch( ip->u.addr[0] );
00151    /*print_tree( 0 );*/ /* debug */
00152 
00153    if (flags&RED_NODE) {
00154       if (flags&NEWRED_NODE) {
00155          LM_GEN1( pike_log_level,
00156             "PIKE - BLOCKing ip %s, node=%p\n",ip_addr2a(ip),node);
00157          return -2;
00158       }
00159       return -1;
00160    }
00161    return 1;
00162 }
00163 
00164 
00165 
00166 void clean_routine(unsigned int ticks , void *param)
00167 {
00168    static unsigned char mask[32];  /* 256 positions mask */
00169    struct list_link head;
00170    struct list_link *ll;
00171    struct ip_node   *dad;
00172    struct ip_node   *node;
00173    int i;
00174 
00175    /* LM_DBG("entering (%d)\n",ticks); */
00176    /* before locking check first if the list is not empty and if can
00177     * be at least one element removed */
00178    if ( is_list_empty( timer )) return; /* quick exit */
00179 
00180    /* get the expired elements */
00181    lock_get( timer_lock );
00182    /* check again for empty list */
00183    if (is_list_empty(timer) || (ll2ipnode(timer->next)->expires>ticks )){
00184       lock_release( timer_lock );
00185       return;
00186    }
00187    check_and_split_timer( timer, ticks, &head, mask);
00188    /*print_timer_list(timer);*/ /* debug */
00189    lock_release( timer_lock );
00190    /*print_tree( 0 );*/  /*debug*/
00191 
00192    /* got something back? */
00193    if ( is_list_empty(&head) )
00194       return;
00195 
00196    /* process what we got -> don't forget to lock the tree!! */
00197    for(i=0;i<MAX_IP_BRANCHES;i++) {
00198       /* if no element from this branch -> skip it */
00199       if ( ((mask[i>>3])&(1<<(i&0x07)))==0 )
00200          continue;
00201 
00202       lock_tree_branch( i );
00203       for( ll=head.next ; ll!=&head ; ) {
00204          node = ll2ipnode( ll );
00205          ll = ll->next;
00206          /* skip nodes from a different branch */
00207          if (node->branch!=i)
00208             continue;
00209 
00210          /* unlink the node -> the list will get shorter and it will be
00211           * faster for the next branches to process it */
00212          ll->prev->prev->next = ll;
00213          ll->prev = ll->prev->prev;
00214          node->expires = 0;
00215          node->timer_ll.prev = node->timer_ll.next = 0;
00216          if ( node->flags&NODE_EXPIRED_FLAG )
00217             node->flags &= ~NODE_EXPIRED_FLAG;
00218          else
00219             continue;
00220 
00221          /* process the node */
00222          LM_DBG("clean node %p (kids=%p; hits=[%d,%d];leaf=[%d,%d])\n", 
00223             node,node->kids,
00224             node->hits[PREV_POS],node->hits[CURR_POS],
00225             node->leaf_hits[PREV_POS],node->leaf_hits[CURR_POS]);
00226          /* if it's a node, leaf for an ipv4 address inside an
00227           * ipv6 address -> just remove it from timer it will be deleted
00228           * only when all its kids will be deleted also */
00229          if (node->kids) {
00230             assert( node->flags&NODE_IPLEAF_FLAG );
00231             node->flags &= ~NODE_IPLEAF_FLAG;
00232             node->leaf_hits[CURR_POS] = 0;
00233          } else {
00234             /* if the node has no prev, means its a top branch node -> just
00235              * removed and destroy it */
00236             if (node->prev!=0) {
00237                /* if this is the last kid, we have to put the father
00238                 * into timer list */
00239                if (node->prev->kids==node && node->next==0) {
00240                   /* this is the last kid node */
00241                   dad = node->prev;
00242                   /* put it in the list only if it's not an IP leaf
00243                    * (in this case, it's already there) */
00244                   if ( !(dad->flags&NODE_IPLEAF_FLAG) ) {
00245                      lock_get(timer_lock);
00246                      dad->expires = get_ticks() + timeout;
00247                      assert( !has_timer_set(&(dad->timer_ll)) );
00248                      append_to_timer( timer, &(dad->timer_ll));
00249                      dad->flags |= NODE_INTIMER_FLAG;
00250                      lock_release(timer_lock);
00251                   } else {
00252                      assert( has_timer_set(&(dad->timer_ll)) );
00253                   }
00254                }
00255             }
00256             LM_DBG("rmv node %p[%d] \n", node,node->byte);
00257             /* del the node */
00258             remove_node( node);
00259          }
00260       } /* for all expired elements */
00261       unlock_tree_branch( i );
00262    } /* for all branches */
00263 }
00264 
00265 
00266 
00267 
00268 static inline void refresh_node( struct ip_node *node)
00269 {
00270    for( ; node ; node=node->next ) {
00271       node->hits[PREV_POS] = node->hits[CURR_POS];
00272       node->hits[CURR_POS] = 0;
00273       node->leaf_hits[PREV_POS] = node->leaf_hits[CURR_POS];
00274       node->leaf_hits[CURR_POS] = 0;
00275       if ( node->flags&NODE_ISRED_FLAG && !is_node_hot_leaf(node) ) {
00276          node->flags &= ~(NODE_ISRED_FLAG);
00277          LM_GEN1( pike_log_level,"PIKE - UNBLOCKing node %p\n",node);
00278       }
00279       if (node->kids)
00280          refresh_node( node->kids );
00281    }
00282 }
00283 
00284 
00285 
00286 
00287 void swap_routine( unsigned int ticks, void *param)
00288 {
00289    struct ip_node *node;
00290    int i;
00291 
00292    /* LM_DBG("entering \n"); */
00293    for(i=0;i<MAX_IP_BRANCHES;i++) {
00294       node = get_tree_branch(i);
00295       if (node) {
00296          lock_tree_branch( i );
00297          node = get_tree_branch(i); /* again, to avoid races */
00298          if (node) refresh_node( node );
00299          unlock_tree_branch( i );
00300       }
00301    }
00302 }
00303 
00304 
00305 

Generated on Thu May 24 02:00:29 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6