jabber_s/xjab_wlist.c

00001 /*
00002  * $Id$
00003  *
00004  * eXtended JABber module - worker implementation
00005  *
00006  *
00007  * Copyright (C) 2001-2003 FhG Fokus
00008  *
00009  * This file is part of ser, a free SIP server.
00010  *
00011  * ser is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * For a license to use the ser software under conditions
00017  * other than those described here, or to purchase support for this
00018  * software, please contact iptel.org by e-mail at the following addresses:
00019  *    info@iptel.org
00020  *
00021  * ser is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  * GNU General Public License for more details.
00025  *
00026  * You should have received a copy of the GNU General Public License 
00027  * along with this program; if not, write to the Free Software
00028  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00029  *
00030  * ---
00031  *
00032  * History
00033  * -------
00034  * 2003-02-24  added 'xj_wlist_set_flag' function (dcm)
00035  * 2003-03-11  major locking changes - uses locking.h (andrei)
00036  *
00037  */
00038 
00039 
00040 #include <string.h>
00041 #include <unistd.h>
00042 #include <stdio.h>
00043 
00044 #include "../../dprint.h"
00045 #include "../../mem/mem.h"
00046 #include "../../mem/shm_mem.h"
00047 
00048 #include "xjab_worker.h"
00049 #include "mdefines.h"
00050 
00051 #define XJ_DEF_JDELIM '*'
00052 
00060 xj_wlist xj_wlist_init(int **pipes, int size, int max, int cache_time,
00061                 int sleep_time, int delay_time)
00062 {
00063         int i;
00064         xj_wlist jwl = NULL;
00065 
00066         if(pipes == NULL || size <= 0 || max <= 0)
00067                 return NULL;
00068 #ifdef XJ_EXTRA_DEBUG
00069         DBG("XJAB:xj_wlist_init: -----START-----\n");
00070 #endif  
00071         jwl = (xj_wlist)_M_SHM_MALLOC(sizeof(t_xj_wlist));
00072         if(jwl == NULL)
00073                 return NULL;
00074         jwl->len = size;
00075         jwl->maxj = max;
00076         
00077         jwl->cachet = cache_time;
00078         jwl->delayt = delay_time;
00079         jwl->sleept = sleep_time;
00080 
00081         jwl->aliases = NULL;
00082         jwl->sems = NULL;
00083         i = 0;
00084         /* alloc locks*/
00085         if((jwl->sems = lock_set_alloc(size)) == NULL){
00086                 LOG(L_CRIT, "jabber: failed to alloc lock set\n");
00087                 goto clean;
00088         };
00089         /* init the locks*/
00090         if (lock_set_init(jwl->sems)==0){
00091                 LOG(L_CRIT, "jabber: failed to initialize the locks\n");
00092                 goto clean;
00093         };
00094         jwl->workers = (xj_worker)_M_SHM_MALLOC(size*sizeof(t_xj_worker));
00095         if(jwl->workers == NULL){
00096                 lock_set_destroy(jwl->sems);
00097                 goto clean;
00098         }
00099 
00100         for(i = 0; i < size; i++)
00101         {
00102                 jwl->workers[i].nr = 0;
00103                 jwl->workers[i].pid = 0;
00104                 jwl->workers[i].wpipe = pipes[i][1];
00105                 jwl->workers[i].rpipe = pipes[i][0];
00106                 if((jwl->workers[i].sip_ids = newtree234(xj_jkey_cmp)) == NULL){
00107                         lock_set_destroy(jwl->sems);
00108                         goto clean;
00109                 }
00110         }       
00111 
00112         return jwl;
00113 
00114 clean:
00115         DBG("XJAB:xj_wlist_init: error occurred -> cleaning\n");
00116         if(jwl->sems != NULL)
00117                 lock_set_dealloc(jwl->sems);
00118         if(jwl->workers != NULL)
00119         {
00120                 while(i>=0)
00121                 {
00122                         if(jwl->workers[i].sip_ids == NULL)
00123                                 free2tree234(jwl->workers[i].sip_ids, xj_jkey_free_p);
00124                         i--;
00125                 }
00126                 _M_SHM_FREE(jwl->workers);
00127         }
00128         _M_SHM_FREE(jwl);
00129         return NULL;
00130 
00131 }
00132 
00140 int xj_wlist_set_pid(xj_wlist jwl, int pid, int idx)
00141 {
00142         if(jwl == NULL || pid <= 0 || idx < 0 || idx >= jwl->len)
00143                 return -1;
00144         lock_set_get(jwl->sems, idx);
00145         jwl->workers[idx].pid = pid;
00146         lock_set_release(jwl->sems, idx);
00147         return 0;
00148 }
00149 
00154 void xj_wlist_free(xj_wlist jwl)
00155 {
00156         int i;
00157 #ifdef XJ_EXTRA_DEBUG
00158         DBG("XJAB:xj_wlist_free: freeing 'xj_wlist' memory ...\n");
00159 #endif
00160         if(jwl == NULL)
00161                 return;
00162 
00163         if(jwl->workers != NULL)
00164         {
00165                 for(i=0; i<jwl->len; i++)
00166                         free2tree234(jwl->workers[i].sip_ids, xj_jkey_free_p);
00167                 _M_SHM_FREE(jwl->workers);
00168         }
00169 
00170         if(jwl->aliases != NULL)
00171         {
00172                 if(jwl->aliases->d)
00173                         _M_SHM_FREE(jwl->aliases->d);
00174 
00175                 if(jwl->aliases->jdm != NULL)
00176                 {
00177                         _M_SHM_FREE(jwl->aliases->jdm->s);
00178                         _M_SHM_FREE(jwl->aliases->jdm);
00179                 }
00180                 if(jwl->aliases->proxy != NULL)
00181                 {
00182                         _M_SHM_FREE(jwl->aliases->proxy->s);
00183                         _M_SHM_FREE(jwl->aliases->proxy);
00184                 }
00185                 if(jwl->aliases->size > 0)
00186                 {
00187                         for(i=0; i<jwl->aliases->size; i++)
00188                                 _M_SHM_FREE(jwl->aliases->a[i].s);
00189                         _M_SHM_FREE(jwl->aliases->a);
00190                 }
00191                 _M_SHM_FREE(jwl->aliases);
00192                 jwl->aliases = NULL;
00193         }
00194         
00195         if(jwl->sems != NULL){
00196                 lock_set_destroy(jwl->sems);
00197                 lock_set_dealloc(jwl->sems);
00198         }
00199         
00200         _M_SHM_FREE(jwl);
00201 }
00202 
00211 int xj_wlist_check(xj_wlist jwl, xj_jkey jkey, xj_jkey *p)
00212 {
00213         int i;
00214         if(jwl==NULL || jkey==NULL || jkey->id==NULL || jkey->id->s==NULL)
00215                 return -1;
00216         
00217         i = 0;
00218         *p = NULL;
00219         while(i < jwl->len)
00220         {
00221                 lock_set_get(jwl->sems, i);
00222                 if(jwl->workers[i].pid <= 0)
00223                 {
00224                         lock_set_release(jwl->sems, i);
00225                         i++;
00226                         continue;
00227                 }
00228                 if((*p = find234(jwl->workers[i].sip_ids, (void*)jkey, NULL)) != NULL)
00229                 {
00230                         lock_set_release(jwl->sems, i);
00231 #ifdef XJ_EXTRA_DEBUG
00232                         DBG("XJAB:xj_wlist_check: entry exists for <%.*s> in the"
00233                                 " pool of <%d> [%d]\n",jkey->id->len, jkey->id->s,
00234                                 jwl->workers[i].pid,i);
00235 #endif
00236                         return jwl->workers[i].wpipe;
00237                 }
00238                 lock_set_release(jwl->sems, i);
00239                 i++;
00240         }
00241 #ifdef XJ_EXTRA_DEBUG
00242         DBG("XJAB:xj_wlist_check: entry does not exist for <%.*s>\n",
00243                         jkey->id->len, jkey->id->s);
00244 #endif
00245         return -1;
00246 }
00247 
00256 int xj_wlist_get(xj_wlist jwl, xj_jkey jkey, xj_jkey *p)
00257 {
00258         int i = 0, pos = -1, min = 100000;
00259         xj_jkey msid = NULL;
00260         
00261         if(jwl==NULL || jkey==NULL || jkey->id==NULL || jkey->id->s==NULL)
00262                 return -1;
00263 
00264         *p = NULL;
00265         while(i < jwl->len)
00266         {
00267                 lock_set_get(jwl->sems, i);
00268                 if(jwl->workers[i].pid <= 0)
00269                 {
00270                         lock_set_release(jwl->sems, i);
00271                         i++;
00272                         continue;
00273                 }
00274                 if((*p = find234(jwl->workers[i].sip_ids, (void*)jkey, NULL))!=NULL)
00275                 {
00276                         if(pos >= 0)
00277                                 lock_set_release(jwl->sems, pos);
00278                                 lock_set_release(jwl->sems, i);
00279 #ifdef XJ_EXTRA_DEBUG
00280                         DBG("XJAB:xj_wlist_get: entry already exists for <%.*s> in the"
00281                                 " pool of <%d> [%d]\n",jkey->id->len, jkey->id->s,
00282                                 jwl->workers[i].pid,i);
00283 #endif
00284                         return jwl->workers[i].wpipe;
00285                 }
00286                 if(min > jwl->workers[i].nr)
00287                 {
00288                         if(pos >= 0)
00289                                 lock_set_release(jwl->sems, pos);
00290                         pos = i;
00291                         min = jwl->workers[i].nr;
00292                 }
00293                 else
00294                         lock_set_release(jwl->sems, i);
00295                 i++;
00296         }
00297         if(pos >= 0 && jwl->workers[pos].nr < jwl->maxj)
00298         {
00299                 jwl->workers[pos].nr++;
00300 
00301                 msid = (xj_jkey)_M_SHM_MALLOC(sizeof(t_xj_jkey));
00302                 if(msid == NULL)
00303                         goto error;
00304                 msid->id = (str*)_M_SHM_MALLOC(sizeof(str));
00305                 if(msid->id == NULL)
00306                 {
00307                         _M_SHM_FREE(msid);
00308                         goto error;
00309                 }
00310                 
00311                 msid->id->s = (char*)_M_SHM_MALLOC(jkey->id->len);
00312                 if(msid->id == NULL)
00313                 {
00314                         _M_SHM_FREE(msid->id);
00315                         _M_SHM_FREE(msid);
00316                         goto error;
00317                 }
00318                 
00319                 if((*p = add234(jwl->workers[pos].sip_ids, msid)) != NULL)
00320                 {
00321                         msid->id->len = jkey->id->len;
00322                         memcpy(msid->id->s, jkey->id->s, jkey->id->len);
00323                         msid->hash = jkey->hash;
00324                         msid->flag = XJ_FLAG_OPEN;
00325                         lock_set_release(jwl->sems, pos);
00326 #ifdef XJ_EXTRA_DEBUG
00327                         DBG("XJAB:xj_wlist_get: new entry for <%.*s> in the pool of"
00328                                 " <%d> - [%d]\n", jkey->id->len, jkey->id->s,
00329                                 jwl->workers[pos].pid, pos);
00330 #endif
00331                         return jwl->workers[pos].wpipe;
00332                 }
00333                 _M_SHM_FREE(msid->id->s);
00334                 _M_SHM_FREE(msid->id);
00335                 _M_SHM_FREE(msid);
00336         }
00337 
00338 error:
00339         if(pos >= 0)
00340                 lock_set_release(jwl->sems, pos);
00341         DBG("XJAB:xj_wlist_get: cannot create a new entry for <%.*s>\n",
00342                                 jkey->id->len, jkey->id->s);
00343         return -1;
00344 }
00345 
00350 int xj_wlist_set_flag(xj_wlist jwl, xj_jkey jkey, int fl)
00351 {
00352         int i;
00353         xj_jkey p = NULL;
00354         if(jwl==NULL || jkey==NULL || jkey->id==NULL || jkey->id->s==NULL)
00355                 return -1;
00356         
00357 #ifdef XJ_EXTRA_DEBUG
00358         DBG("XJAB:xj_wlist_set_flag: looking for <%.*s>"
00359                 " having id=%d\n", jkey->id->len, jkey->id->s, jkey->hash);
00360 #endif
00361                         
00362         i = 0;
00363         while(i < jwl->len)
00364         {
00365                 lock_set_get(jwl->sems, i);
00366                 if(jwl->workers[i].pid <= 0)
00367                 {
00368                         lock_set_release(jwl->sems, i);
00369                         i++;
00370                         continue;
00371                 }
00372                 if((p=find234(jwl->workers[i].sip_ids, (void*)jkey, NULL)) != NULL)
00373                 {
00374                         p->flag = fl;
00375                         lock_set_release(jwl->sems, i);
00376 #ifdef XJ_EXTRA_DEBUG
00377                         DBG("XJAB:xj_wlist_set_flag: the connection for <%.*s>"
00378                                 " marked with flag=%d", jkey->id->len, jkey->id->s, fl);
00379 #endif
00380                         return jwl->workers[i].wpipe;
00381                 }
00382                 lock_set_release(jwl->sems, i);
00383                 i++;
00384         }
00385 #ifdef XJ_EXTRA_DEBUG
00386         DBG("XJAB:xj_wlist_set_flag: entry does not exist for <%.*s>\n",
00387                         jkey->id->len, jkey->id->s);
00388 #endif
00389         return -1;
00390 }
00391 
00392 
00398 int  xj_wlist_set_aliases(xj_wlist jwl, char *als, char *jd, char *pa)
00399 {
00400         char *p, *p0, *p1;
00401         int i, n;
00402         
00403         if(jwl == NULL)
00404                 return -1;
00405         if(!jd) // || !als || strlen(als)<2)
00406                 return 0;
00407         
00408 #ifdef XJ_EXTRA_DEBUG
00409         DBG("XJAB:xj_wlist_set_aliases\n");
00410 #endif
00411         
00412         if((jwl->aliases = (xj_jalias)_M_SHM_MALLOC(sizeof(t_xj_jalias)))==NULL)
00413         {
00414                 DBG("XJAB:xj_wlist_set_aliases: not enough SHMemory.\n");
00415                 return -1;
00416         }
00417         
00418         jwl->aliases->jdm = NULL;
00419         jwl->aliases->proxy = NULL;
00420         jwl->aliases->dlm = XJ_DEF_JDELIM; // default user part delimiter
00421         jwl->aliases->size = 0;
00422         jwl->aliases->a = NULL;
00423         jwl->aliases->d = NULL;
00424 
00425         // set the jdomain
00426         if(jd != NULL && (n=strlen(jd))>2)
00427         {
00428                 p = jd;
00429                 while(p < jd+n && *p!='=')
00430                         p++;
00431                 if(p<jd+n-1)
00432                 {
00433                         jwl->aliases->dlm = *(p+1);
00434                         n = p - jd;
00435                 }
00436                 if((jwl->aliases->jdm = (str*)_M_SHM_MALLOC(sizeof(str)))== NULL)
00437                 {
00438                         DBG("XJAB:xj_wlist_set_aliases: not enough SHMemory!?\n");
00439                         _M_SHM_FREE(jwl->aliases);
00440                         jwl->aliases = NULL;
00441                         return -1;              
00442                 }
00443                 jwl->aliases->jdm->len = n;
00444                 if((jwl->aliases->jdm->s=(char*)_M_SHM_MALLOC(jwl->aliases->jdm->len))
00445                                 == NULL)
00446                 {
00447                         DBG("XJAB:xj_wlist_set_aliases: not enough SHMemory!?!\n");
00448                         _M_SHM_FREE(jwl->aliases->jdm);
00449                         _M_SHM_FREE(jwl->aliases);
00450                         jwl->aliases = NULL;
00451                 }
00452                 strncpy(jwl->aliases->jdm->s, jd, jwl->aliases->jdm->len);
00453 #ifdef XJ_EXTRA_DEBUG
00454                 DBG("XJAB:xj_wlist_set_aliases: jdomain=%.*s delim=%c\n",
00455                         jwl->aliases->jdm->len, jwl->aliases->jdm->s, jwl->aliases->dlm);
00456 #endif
00457         }
00458         
00459         // set the proxy address
00460         if(pa && strlen(pa)>0)
00461         {
00462                 if((jwl->aliases->proxy = (str*)_M_SHM_MALLOC(sizeof(str)))==NULL)
00463                 {
00464                         DBG("XJAB:xj_wlist_set_aliases: not enough SHMemory!!\n");
00465                         goto clean3;            
00466                 }
00467                 i = jwl->aliases->proxy->len = strlen(pa);
00468                 // check if proxy address has sip: prefix
00469                 if(i < 4 || pa[0]!='s' || pa[1]!='i' || pa[2]!='p' || pa[3]!=':')
00470                         jwl->aliases->proxy->len += 4;
00471                 if((jwl->aliases->proxy->s=
00472                                         (char*)_M_SHM_MALLOC(jwl->aliases->proxy->len))
00473                                 == NULL)
00474                 {
00475                         DBG("XJAB:xj_wlist_set_aliases: not enough SHMemory!!!\n");
00476                         _M_SHM_FREE(jwl->aliases->proxy);
00477                         goto clean3;
00478                 }
00479                 p0 = jwl->aliases->proxy->s;
00480                 if(jwl->aliases->proxy->len != i)
00481                 {
00482                         strncpy(p0, "sip:", 4);
00483                         p0 += 4;
00484                 }
00485                 strncpy(p0, pa, i);
00486 #ifdef XJ_EXTRA_DEBUG
00487                 DBG("XJAB:xj_wlist_set_aliases: outbound proxy=[%.*s]\n",
00488                         jwl->aliases->proxy->len, jwl->aliases->proxy->s);
00489 #endif
00490         }
00491         
00492         // set the IM aliases
00493         if(!als || strlen(als)<2)
00494                 return 0;
00495         
00496         if((p = strchr(als, ';')) == NULL)
00497         {
00498                 DBG("XJAB:xj_wlist_set_aliases: bad parameter value\n");
00499                 return -1;
00500         }
00501         
00502         if((jwl->aliases->size = atoi(als)) <= 0)
00503         {
00504                 DBG("XJAB:xj_wlist_set_aliases: wrong number of aliases\n");
00505                 return 0;
00506         }
00507         
00508         jwl->aliases->d = (char*)_M_SHM_MALLOC(jwl->aliases->size*sizeof(char));
00509         if(jwl->aliases->d == NULL)
00510         {
00511                 DBG("XJAB:xj_wlist_set_aliases: not enough SHMemory..\n");
00512                 goto clean2;
00513         }
00514         memset(jwl->aliases->d, 0, jwl->aliases->size);
00515         
00516         jwl->aliases->a = (str*)_M_SHM_MALLOC(jwl->aliases->size*sizeof(str));
00517         if(jwl->aliases->a == NULL)
00518         {
00519                 DBG("XJAB:xj_wlist_set_aliases: not enough SHMemory..\n");
00520                 goto clean1;
00521         }
00522         
00523         p++;
00524         for(i=0; i<jwl->aliases->size; i++)
00525         {
00526                 if((p0 = strchr(p, ';'))==NULL)
00527                 {
00528                         DBG("XJAB:xj_wlist_set_aliases: bad parameter value format\n");
00529                         goto clean;
00530                 }
00531                 n = p0 - p;
00532                 p1 = strchr(p, '=');
00533                 if(p1 && p1<p0-1)
00534                 {
00535                         jwl->aliases->d[i] = *(p1+1);
00536                         n = p1 - p;
00537                 }
00538                 jwl->aliases->a[i].len = n;
00539                 if((jwl->aliases->a[i].s = (char*)_M_SHM_MALLOC(jwl->aliases->a[i].len))
00540                                 == NULL)
00541                 {
00542                         DBG("XJAB:xj_wlist_set_aliases: not enough SHMemory!\n");
00543                         goto clean;
00544                 }
00545                         
00546                 strncpy(jwl->aliases->a[i].s, p, jwl->aliases->a[i].len);
00547 #ifdef XJ_EXTRA_DEBUG
00548                 DBG("XJAB:xj_wlist_set_aliases: alias[%d/%d]=%.*s delim=%c\n", 
00549                         i+1, jwl->aliases->size, jwl->aliases->a[i].len, 
00550                         jwl->aliases->a[i].s, jwl->aliases->d[i]?jwl->aliases->d[i]:'X');
00551 #endif
00552                 p = p0 + 1;
00553         }
00554         return 0;
00555 
00556 clean:
00557         while(i>0)
00558         {
00559                 _M_SHM_FREE(jwl->aliases->a[i-1].s);
00560                 i--;
00561         }
00562         _M_SHM_FREE(jwl->aliases->a);
00563 
00564 clean1:
00565         if(jwl->aliases->d)
00566                 _M_SHM_FREE(jwl->aliases->d);
00567 
00568 clean2:
00569         if(jwl->aliases->proxy)
00570         {
00571                 _M_SHM_FREE(jwl->aliases->proxy->s);
00572                 _M_SHM_FREE(jwl->aliases->proxy);
00573         }
00574 clean3:
00575         if(jwl->aliases->jdm)
00576         {
00577                 _M_SHM_FREE(jwl->aliases->jdm->s);
00578                 _M_SHM_FREE(jwl->aliases->jdm);
00579         }
00580         _M_SHM_FREE(jwl->aliases);
00581         jwl->aliases = NULL;
00582         return -1;
00583 }
00584 
00585 
00592 int  xj_wlist_check_aliases(xj_wlist jwl, str *addr)
00593 {
00594         char *p, *p0;
00595         int ll, i;
00596         if(!jwl || !jwl->aliases || !addr || !addr->s || addr->len<=0)
00597                 return -1;
00598 
00599         // find '@'
00600         p = addr->s;
00601         while(p < addr->s + addr->len && *p != '@')
00602                 p++;
00603         if(p >= addr->s + addr->len)
00604                 return -1;
00605         
00606         p++;
00607         ll = addr->s + addr->len - p;
00608         
00609         // check parameters
00610         p0 = p;
00611         while(p0 < p + ll && *p0 != ';')
00612                 p0++;
00613         if(p0 < p + ll)
00614                 ll = p0 - p;
00615         
00616         ll = addr->s + addr->len - p;
00617         if(jwl->aliases->jdm && jwl->aliases->jdm->len == ll && 
00618                         !strncasecmp(jwl->aliases->jdm->s, p, ll))
00619                 return 0;
00620 
00621         if(jwl->aliases->size <= 0)
00622                 return 1;
00623         
00624         for(i = 0; i < jwl->aliases->size; i++)
00625                 if(jwl->aliases->a[i].len == ll && 
00626                         !strncasecmp(p, jwl->aliases->a[i].s, ll))
00627                                 return 0;
00628         return 1;
00629 }
00630 
00638 void xj_wlist_del(xj_wlist jwl, xj_jkey jkey, int _pid)
00639 {
00640         int i;
00641         void *p;
00642         if(jwl==NULL || jkey==NULL || jkey->id==NULL || jkey->id->s==NULL)
00643                 return;
00644         for(i=0; i < jwl->len; i++)
00645                 if(jwl->workers[i].pid == _pid)
00646                         break;
00647         if(i >= jwl->len)
00648         {
00649                 DBG("XJAB:xj_wlist_del:%d: key <%.*s> not found in [%d]...\n",
00650                         _pid, jkey->id->len, jkey->id->s, i);
00651                 return;
00652         }
00653 #ifdef XJ_EXTRA_DEBUG
00654         DBG("XJAB:xj_wlist_del:%d: trying to delete entry for <%.*s>...\n",
00655                 _pid, jkey->id->len, jkey->id->s);
00656 #endif
00657         lock_set_get(jwl->sems, i);
00658         p = del234(jwl->workers[i].sip_ids, (void*)jkey);
00659 
00660         if(p != NULL)
00661         {
00662                 jwl->workers[i].nr--;
00663 #ifdef XJ_EXTRA_DEBUG
00664                 DBG("XJAB:xj_wlist_del:%d: sip id <%.*s> deleted\n", _pid,
00665                         jkey->id->len, jkey->id->s);
00666 #endif
00667                 xj_jkey_free_p(p);
00668         }
00669 
00670         lock_set_release(jwl->sems, i);
00671 }
00672