Logo Search packages:      
Sourcecode: dctc version File versions  Download package

uaddr.c

/* DCTC - a Direct Connect text clone for Linux
 * Copyright (C) 2001 Eric Prevoteau
 *
 * uaddr.c: Copyright (C) Eric Prevoteau <www@a2pb.gotdns.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
/*
$Id: uaddr.c,v 1.8 2003/12/28 08:12:38 uid68112 Exp $
*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/un.h>
#include <db.h>
#include <glib.h>

#include "var.h"
#include "uaddr.h"
#include "unode.h"
#include "display.h"
#include "action.h"
#include "user_manage.h"
#include "misc.h"
#include "network.h"
#include "dc_com.h"
#include "bdb.h"
#include "tos_key.h"
#include "timed_out_string.h"
#include "lmp.h"

#define MAX_REGISTRATION_TIME (12*3600)         /* up to 12 hours without refresh */

static void init_uaddr_node(void);
static void manage_uaddr_node(void);

/**************************/
/* Global Transfer System */
/*********************************************************************/
/* the following functions provide the capability to move a transfer */
/* from one client to another. Only queued transfers can be moved.   */
/* thus, a transfer can go from one hub to another if the user from  */
/* where we download has gone to another hub. If the .dctc dir is on */
/* a shared disc (NFS or something like that), a transfer can even   */
/* migrate from one computer to another.                             */
/* only /DL are taken into account.                                  */
/*********************************************************************/

#define MAX_UNRESOLVED_IP 1000

static LMP_ENTRY *uaddr_ready=NULL;
G_LOCK_DEFINE_STATIC(uaddr_ready);

static LMP_ENTRY *uaddr_partial=NULL;
G_LOCK_DEFINE_STATIC(uaddr_partial);

static LMP_ENTRY *unode_lmp=NULL;
G_LOCK_DEFINE_STATIC(unode_lmp);

/**************************************************************/
/* scan the list of given address to find associated nickname */
/******************************************************************************************/
/* this function must be called regularly to send $Ping to the IP in the uaddr_partial_db */
/******************************************************************************************/
static void scan_addresses_and_purge_partial_uaddr(void)
{
      int i;
      UADDR_PARTIAL *uap;

      G_LOCK(uaddr_partial);

      if(lmp_lock_and_map(uaddr_partial))
      {
            G_UNLOCK(uaddr_partial);
            return;
      }

      uap=uaddr_partial->mapped_addr;
      for(i=1;i<uaddr_partial->nb_records;i++)  /* skip the first record */
      {
            if(uap[i].valid)
            {
                  char *p;

                  p=strchr(uap[i].dl_addr,':');
                  if(p==NULL)
                        uap[i].valid=0;         /* delete this entry */
                  else
                  {
                        char host[UADDR_DL];
                        unsigned short port;

                        strcpy(host,uap[i].dl_addr);

                        host[p-uap[i].dl_addr]='\0';
                        port=strtoul(p+1,NULL,10);

                        {     /* note: this methode is fast but has one severe problem */
                              /* if the remote client has "registered" a FQDN inside UADDR database, when this client */
                              /* receives the pong string, it contains the remote host IP, not FQDN */
                              struct sockaddr_in dest;
                              dest.sin_family=AF_INET;
                              dest.sin_port=htons(port);
                              if(str_to_inaddr(host,&(dest.sin_addr))==0)
                              {
                                    uap[i].ping_counter++;
                                    if(uap[i].ping_counter>MAX_UADDR_PING)
                                    {
                                          uap[i].valid=0;         /* delete this entry */
                                    }
                                    else
                                    {
                                          int out;
                                          const char *ping_str="$Ping |";
                                          out=sendto(srch_sck,ping_str,strlen(ping_str),MSG_NOSIGNAL,(void*)&dest,sizeof(struct sockaddr_in));
                                          if(out==-1)
                                          {
                                                uap[i].valid=0;         /* delete this entry */
                                          }
                                    }
                              }
                              else
                              {
                                    uap[i].valid=0;         /* delete this entry */
                              }
                        }
                  }
            }
      }

      lmp_unmap_and_unlock(uaddr_partial);
      G_UNLOCK(uaddr_partial);
}

/****************************************************************/
/* scan the ready to use UADDR table and delete too old entries */
/****************************************************************/
static void expire_ready_uaddr(void)
{
      int i;
      UADDR_READY *uar;
      time_t min_time;

      G_LOCK(uaddr_ready);

      if(lmp_lock_and_map(uaddr_ready))
      {
            G_UNLOCK(uaddr_ready);
            return;
      }

      min_time=time(NULL)-MAX_REGISTRATION_TIME;

      uar=uaddr_ready->mapped_addr;
      for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
      {
            if(uar[i].valid)
            {
                  if(uar[i].register_time<min_time)
                        uar[i].valid=0;
            }
      }

      lmp_unmap_and_unlock(uaddr_ready);
      G_UNLOCK(uaddr_ready);
}


/************************************************************************************/
/* this thread purges oldest UADDR entries and tries to fill entry without nickname */
/************************************************************************************/
static void *uaddr_thread(void *dummy)
{
      time_t last_check_step=0;

      init_uaddr_node();

      while(1)
      {
            if((time(NULL)-last_check_step)>60)       /* at least 60 seconds between 2 checks */
            {
                  /* there is maybe some addresses without nickname */
                  scan_addresses_and_purge_partial_uaddr();

                  /* delete uaddr here for a too long time without usage */
                  expire_ready_uaddr();
      
                  last_check_step=time(NULL);
            }

            manage_uaddr_node();
      }
      pthread_exit(NULL);
}

/******************************************************************************/
/* to reduce duplicated code, the DCTC being the clock master is also the one */
/* performing UADDR action                                                    */
/******************************************************************************/
void create_uaddr_thread(void)
{
      static pthread_t thread_id; /* this variable must exist as long as the thread exists */
      pthread_attr_t thread_attr;

      pthread_attr_init (&thread_attr);
      pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
      if(pthread_create(&thread_id,&thread_attr, (void*)uaddr_thread,NULL))
      {
            disp_msg(ERR_MSG,"create_uaddr_thread","Fatal Error","Fail to start UADDR thread",NULL);
      }
      pthread_attr_destroy(&thread_attr);
}

/********************************/
/* perform UADDR initialisation */
/**********************************************************************/
/* this function is the only one which doesn't need to lock the UADDR */
/**********************************************************************/
void init_uaddr(void)
{
      GString *tmp;

      /* create uaddr_ready file */
      tmp=g_string_new(dctc_dir->str);
      g_string_sprintfa(tmp,"/uaddr_ready.%d",sizeof(UADDR_READY));

      uaddr_ready=lmp_new(tmp->str,sizeof(UADDR_READY),-1);
      if(uaddr_ready==NULL)
      {
            disp_msg(ERR_MSG,"init_uaddr","unable to create ","|s",tmp->str,NULL);
            g_string_free(tmp,TRUE);
            exit(1);
      }

      /* create uaddr_partial file */
      tmp=g_string_assign(tmp,dctc_dir->str);
      g_string_sprintfa(tmp,"/uaddr_partial.%d",sizeof(UADDR_PARTIAL));

      uaddr_partial=lmp_new(tmp->str,sizeof(UADDR_PARTIAL),-1);
      if(uaddr_partial==NULL)
      {
            lmp_close(uaddr_ready);
            disp_msg(ERR_MSG,"init_uaddr","unable to create ","|s",tmp->str,NULL);
            g_string_free(tmp,TRUE);
            exit(1);
      }

      g_string_free(tmp,TRUE);
}

/*************************************************************/
/* the following function removes an entry to the UADDR file */
/*************************************************************/
void delete_uaddr_entry_by_name(char *nickname)
{
      /* a deletion by nickname can only occurs on UADDR ready DB */
      int i;
      UADDR_READY *uar;

      G_LOCK(uaddr_ready);

      if(lmp_lock_and_map(uaddr_ready))
      {
            G_UNLOCK(uaddr_ready);
            return;
      }

      uar=uaddr_ready->mapped_addr;
      for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
      {
            if(uar[i].valid)
            {
                  if(!strcmp(uar[i].nick,nickname))
                  {
                        uar[i].valid=0;
                        break;
                  }
            }
      }

      lmp_unmap_and_unlock(uaddr_ready);
      G_UNLOCK(uaddr_ready);
}

/*************************************************************/
/* the following function removes an entry to the UADDR file */
/*************************************************************/
void delete_uaddr_entry_by_addr(char *dl_addr)
{
      /* a deletion by nickname can only occurs on UADDR partial DB */
      int i;
      UADDR_PARTIAL *uap;

      G_LOCK(uaddr_partial);

      if(lmp_lock_and_map(uaddr_partial))
      {
            G_UNLOCK(uaddr_partial);
            return;
      }

      uap=uaddr_partial->mapped_addr;
      for(i=1;i<uaddr_partial->nb_records;i++)  /* skip the first record */
      {
            if(uap[i].valid)
            {
                  if(!strcmp(uap[i].dl_addr,dl_addr))
                  {
                        uap[i].valid=0;         /* delete this entry */
                        break;
                  }
            }
      }

      lmp_unmap_and_unlock(uaddr_partial);
      G_UNLOCK(uaddr_partial);
}

/*****************************************************/
/* check if the given address exists in the database */
/*****************************************************/
/* output: 1=yes, 0=no */
/***********************/
int check_uaddr_entry_by_addr(char *dl_addr)
{
      int i;
      UADDR_READY *uar;
      int ret=0;

      G_LOCK(uaddr_ready);

      if(lmp_lock_and_map(uaddr_ready))
      {
            G_UNLOCK(uaddr_ready);
            return ret;
      }

      uar=uaddr_ready->mapped_addr;
      for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
      {
            if(uar[i].valid)
            {
                  if(!strcmp(uar[i].dl_addr,dl_addr))
                  {
                        if((uar[i].cyclic_dirty==0)||(uar[i].cyclic_dirty==1))      /* currently valid ? */
                              ret=1;      /* found */
                        break;
                  }
            }
      }

      lmp_unmap_and_unlock(uaddr_ready);
      G_UNLOCK(uaddr_ready);

      if(!ret)
      {
            /* not yet found, check the partial db */
            UADDR_PARTIAL *uap;

            G_LOCK(uaddr_partial);

            if(lmp_lock_and_map(uaddr_partial))
            {
                  G_UNLOCK(uaddr_partial);
                  return ret;
            }

            uap=uaddr_partial->mapped_addr;
            for(i=1;i<uaddr_partial->nb_records;i++)  /* skip the first record */
            {
                  if(uap[i].valid)
                  {
                        if(!strcmp(uap[i].dl_addr,dl_addr))
                        {
                              ret=1;
                              break;
                        }
                  }
            }

            lmp_unmap_and_unlock(uaddr_partial);
            G_UNLOCK(uaddr_partial);
      }     

      return ret;
}

/**********************************************************/
/* check if the given nickname has a known remote address */
/**********************************************************/
/* output: 1=yes, 0=no */
/***********************/
int check_uaddr_entry_by_name(char *nickname)
{
      int i;
      UADDR_READY *uar;
      int ret=0;

      G_LOCK(uaddr_ready);

      if(lmp_lock_and_map(uaddr_ready))
      {
            G_UNLOCK(uaddr_ready);
            return ret;
      }

      uar=uaddr_ready->mapped_addr;
      for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
      {
            if(uar[i].valid)
            {
                  if(!strcmp(uar[i].nick,nickname))
                  {
                        if((uar[i].cyclic_dirty==0)||(uar[i].cyclic_dirty==1))      /* currently valid ? */
                              ret=1;      /* found */
                        break;
                  }
            }
      }

      lmp_unmap_and_unlock(uaddr_ready);
      G_UNLOCK(uaddr_ready);
      return ret;
}

/************************************************/
/* get the remote address of the given nickname */
/*********************************************************************************/
/* output: NULL (not found) or a GString (host:port) to free when no more useful */
/*********************************************************************************/
GString *get_uaddr_dl_addr_by_name(char *nickname)
{
      int i;
      UADDR_READY *uar;
      GString *ret=NULL;

      G_LOCK(uaddr_ready);

      if(lmp_lock_and_map(uaddr_ready))
      {
            G_UNLOCK(uaddr_ready);
            return ret;
      }

      uar=uaddr_ready->mapped_addr;
      for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
      {
            if(uar[i].valid)
            {
                  if(!strcmp(uar[i].nick,nickname))
                  {
                        if((uar[i].cyclic_dirty==0)||(uar[i].cyclic_dirty==1))      /* currently valid ? */
                              ret=g_string_new(uar[i].dl_addr);
                        break;
                  }
            }
      }

      lmp_unmap_and_unlock(uaddr_ready);
      G_UNLOCK(uaddr_ready);
      return ret;
}

/**********************************************************/
/* the following function adds an entry to the UADDR file */
/**********************************************************/
/* nick is always uniq in the database */
/***************************************/
/* output: 0= ok    */
/*         1= error */
/********************/
int add_uaddr_entry(char *nickname, const char *addr_dl)
{
      int i;
      UADDR_READY *uar;
      int ret=-1;
      int empty=-1;

      G_LOCK(uaddr_ready);

      if(lmp_lock_and_map(uaddr_ready))
      {
            G_UNLOCK(uaddr_ready);
            return 1;
      }

      uar=uaddr_ready->mapped_addr;
      for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
      {
            if(uar[i].valid)
            {
                  if(!strcmp(uar[i].nick,nickname))
                  {
                        ret=i;      /* found */
                        break;
                  }
            }
            else
            {
                  if(empty==-1)
                        empty=i;
            }
      }

      if(ret!=-1)
      {
            /* an entry already exists, update it */
            /* valid and nick is already ok */
            strncpy_max(uar[ret].dl_addr,addr_dl,UADDR_DL);
            uar[ret].register_time=time(NULL);
            uar[ret].cyclic_dirty=0;
      }
      else
      {
            /* the entry does not exist */
            if(empty!=-1)
            {
                  /* but we have an empty entry to save it */
                  uar[empty].valid=1;
                  strncpy_max(uar[empty].nick,nickname,UADDR_NICK_SIZE);
                  strncpy_max(uar[empty].dl_addr,addr_dl,UADDR_DL);
                  uar[empty].register_time=time(NULL);
                  uar[empty].cyclic_dirty=0;
            }
            else
            {
                  UADDR_READY nw;
      
                  nw.valid=1;
                  strncpy_max(nw.nick,nickname,UADDR_NICK_SIZE);
                  strncpy_max(nw.dl_addr,addr_dl,UADDR_DL);
                  nw.register_time=time(NULL);
                  nw.cyclic_dirty=0;
      
                  lmp_append_record(uaddr_ready,&nw);
            }
      }
      lmp_unmap_and_unlock(uaddr_ready);
      G_UNLOCK(uaddr_ready);
      return 0;
}

/**********************************************************/
/* the following function adds an entry to the UADDR file */
/**********************************************************/
/* addr_dl is always uniq in the database */
/******************************************/
/* output: 0= ok    */
/*         1= error */
/********************/
int add_uaddr_entry_addr_dl_only(char *dl_addr)
{
      int i;
      int pos=-1;
      UADDR_PARTIAL *uap;
      int empty=-1;

      G_LOCK(uaddr_partial);

      if(lmp_lock_and_map(uaddr_partial))
      {
            G_UNLOCK(uaddr_partial);
            return 1;
      }

      uap=uaddr_partial->mapped_addr;
      for(i=1;i<uaddr_partial->nb_records;i++)  /* skip the first record */
      {
            if(uap[i].valid)
            {
                  if(!strcmp(uap[i].dl_addr,dl_addr))
                  {
                        pos=i;
                        break;
                  }
            }
            else
            {
                  if(empty==-1)
                        empty=i;
            }
      }

      if(pos!=-1)
      {
            uap[pos].ping_counter=0;
      }
      else
      {
            if(empty!=-1)
            {
                  uap[empty].valid=1;
                  strncpy_max(uap[empty].dl_addr,dl_addr,UADDR_DL);
                  uap[empty].ping_counter=0;
            }
            else
            {
                  UADDR_PARTIAL nw;

                  nw.valid=1;
                  strncpy_max(nw.dl_addr,dl_addr,UADDR_DL);
                  nw.ping_counter=0;

                  lmp_append_record(uaddr_partial,&nw);
            }
      }
      lmp_unmap_and_unlock(uaddr_partial);
      G_UNLOCK(uaddr_partial);
      return 0;
}

/**********************************************************/
/* the following function adds an entry to the UADDR file */
/**********************************************************/
/* addr_dl is always uniq in the database */
/******************************************/
/* output: 0= ok    */
/*         1= error */
/****************************************************/
/* the function is smarter than the previous one    */
/* it also checks if the address does not exist in  */
/* the uaddr_ready DB and if it does not exist with */
/* a different port.                                */
/****************************************************/
int add_uaddr_entry_addr_dl_only_xtra(char *dl_addr)
{
      int i;
      int pos=-1;
      UADDR_PARTIAL *uap;
      int empty=-1;
      char *t;
      int addr_len;
      int added=-1;

      t=strchr(dl_addr,':');
      if(t==NULL)
            return 1;
      t++;        /* keep the ':' at the end */
      addr_len=t-dl_addr;

      G_LOCK(uaddr_partial);

      if(lmp_lock_and_map(uaddr_partial))
      {
            G_UNLOCK(uaddr_partial);
            return 1;
      }

      uap=uaddr_partial->mapped_addr;
      for(i=1;i<uaddr_partial->nb_records;i++)  /* skip the first record */
      {
            if(uap[i].valid)
            {
                  if(!strncmp(uap[i].dl_addr,dl_addr,addr_len))
                  {
                        pos=i;
                        break;
                  }
            }
            else
            {
                  if(empty==-1)
                        empty=i;
            }
      }

      if(pos!=-1)
      {
            uap[pos].ping_counter=0;
      }
      else
      {
            int ret=-1;

            /* the entry does not exist but perhaps it is already in the uaddr_ready table */
            UADDR_READY *uar;

            G_LOCK(uaddr_ready);

            if(!lmp_lock_and_map(uaddr_ready))
            {
                  uar=uaddr_ready->mapped_addr;
                  for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
                  {
                        if(uar[i].valid)
                        {
                              if(!strncmp(uar[i].dl_addr,dl_addr,addr_len))
                              {
                                    ret=i;      /* found */
                                    break;
                              }
                        }
                  }
                  lmp_unmap_and_unlock(uaddr_ready);
            }
            G_UNLOCK(uaddr_ready);

            if(ret==-1)
            {
                  added=1;

                  /* not exist anywhere */
                  if(empty!=-1)
                  {
                        uap[empty].valid=1;
                        strncpy_max(uap[empty].dl_addr,dl_addr,UADDR_DL);
                        uap[empty].ping_counter=0;
                  }
                  else
                  {
                        UADDR_PARTIAL nw;
      
                        nw.valid=1;
                        strncpy_max(nw.dl_addr,dl_addr,UADDR_DL);
                        nw.ping_counter=0;
      
                        lmp_append_record(uaddr_partial,&nw);
                  }
            }
      }
      lmp_unmap_and_unlock(uaddr_partial);
      G_UNLOCK(uaddr_partial);
      if(added)
      {
            GString *ndl;
            int port_num;

            ndl=g_string_new(dl_addr);

            port_num=atoi(dl_addr+addr_len);          /* current port added */

            if(port_num!=412)
            {
                  g_string_truncate(ndl,addr_len);
                  g_string_append(ndl,"412");
                  add_uaddr_entry_addr_dl_only(ndl->str);
            }

            if(port_num!=1412)
            {
                  g_string_truncate(ndl,addr_len);
                  g_string_append(ndl,"1412");
                  add_uaddr_entry_addr_dl_only(ndl->str);
            }

            g_string_free(ndl,TRUE);
      }
      return 0;
}


#if 0
/*************************************************************************************************/
/* the following function increases the ping_counter of the UADDR entry having the given address */
/*************************************************************************************************/
/* output: -1= error                 */
/*         new value of ping counter */
/*************************************/
static int increase_ping_counter(char *addr_dl)
{
      UADDR_PARTIAL *uap;
      int out;
      int ret=-1;

      if(get_key_data(uaddr_partial_db,addr_dl,strlen(addr_dl),(void**)&uap,&out)==0)
      {
            uap->ping_counter++;
            ret=uap->ping_counter;

            set_key_data(uaddr_partial_db,addr_dl,strlen(addr_dl),(void*)uap,out);
            free(uap);
      }

      return ret;
}
#endif

/******************************************************************************************************************************/
/* the following function increases the cyclic error counter in the ping_counter of the UADDR entry having the given nickname */
/******************************************************************************************************************************/
/* output: -1= error                 */
/*         new value of ping counter */
/*************************************/
int uaddr_increase_error_flag(char *nickname)
{
      int i;
      UADDR_READY *uar;
      int ret=-1;

      G_LOCK(uaddr_ready);

      if(lmp_lock_and_map(uaddr_ready))
      {
            G_UNLOCK(uaddr_ready);
            return ret;
      }

      uar=uaddr_ready->mapped_addr;
      for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
      {
            if(uar[i].valid)
            {
                  if(!strcmp(uar[i].nick,nickname))
                  {
                        uar[i].cyclic_dirty++;
                        ret=uar[i].cyclic_dirty;      /* found */
                        break;
                  }
            }
      }

      lmp_unmap_and_unlock(uaddr_ready);
      G_UNLOCK(uaddr_ready);
      return ret;
}

/***************************************************************************************************************************/
/* the following function resets the cyclic error counter in the ping_counter of the UADDR entry having the given nickname */
/***************************************************************************************************************************/
/* output: -1= error                 */
/*         new value of ping counter */
/*************************************/
int uaddr_reset_error_flag(char *nickname)
{
      int i;
      UADDR_READY *uar;
      int ret=-1;

      G_LOCK(uaddr_ready);

      if(lmp_lock_and_map(uaddr_ready))
      {
            G_UNLOCK(uaddr_ready);
            return ret;
      }

      uar=uaddr_ready->mapped_addr;
      for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
      {
            if(uar[i].valid)
            {
                  if(!strcmp(uar[i].nick,nickname))
                  {
                        uar[i].cyclic_dirty=0;
                        ret=uar[i].cyclic_dirty;      /* found */
                        break;
                  }
            }
      }

      lmp_unmap_and_unlock(uaddr_ready);
      G_UNLOCK(uaddr_ready);
      return ret;
}

/*************/
/* end UADDR */
/*************/
void exit_uaddr(void)
{
      G_LOCK(uaddr_ready);
      if(uaddr_ready)
            lmp_close(uaddr_ready);

      G_LOCK(uaddr_partial);
      if(uaddr_partial)
            lmp_close(uaddr_partial);
}

/*******************************************/
/* output UADDR content into CMD_KB format */
/*******************************************/
void list_uaddr_content(void)
{
      int i;

      disp_msg(UADDR_LST_BEGIN,"",NULL);

      /* first, display the UADDR_READY entries */
      G_LOCK(uaddr_ready);

      if(lmp_lock_and_map(uaddr_ready)==0)
      {
            UADDR_READY *uar;
            uar=uaddr_ready->mapped_addr;
            for(i=1;i<uaddr_ready->nb_records;i++)    /* skip the first record */
            {
                  if(uar[i].valid)
                  {
                        disp_msg(UADDR_LST_ENTRY,NULL,uar[i].nick,uar[i].dl_addr,NULL);
                  }
            }
            lmp_unmap_and_unlock(uaddr_ready);
      }

      G_UNLOCK(uaddr_ready);

      /* and the UADDR partial entries */
      G_LOCK(uaddr_partial);

      if(lmp_lock_and_map(uaddr_partial)==0)
      {
            UADDR_PARTIAL *uap;
            uap=uaddr_partial->mapped_addr;
            for(i=1;i<uaddr_partial->nb_records;i++)  /* skip the first record */
            {
                  if(uap[i].valid)
                  {
                        disp_msg(UADDR_LST_ENTRY,NULL,"",uap[i].dl_addr,NULL);
                  }
            }
            lmp_unmap_and_unlock(uaddr_partial);
      }

      G_UNLOCK(uaddr_partial);

      disp_msg(UADDR_LST_END,"",NULL);
}

/*****************************************************************************/
/* this function scans the UADDR files and looks if there is something to do */
/*****************************************************************************/
/* this function must be called regularly */
/******************************************/
void uaddr_action(void)
{
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* ------------------------------ UADDR node -------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

static GString *l_unode_name=NULL;

static int l_unode_socket=-1;       /* local unix UDP socket */
static int r_unode_socket=-1;       /* internet UDP socket */

#define MAX_D2D_BUF_SIZE 2048

typedef struct
{
      int sock_fd;                                                /* socket descriptor */
      char *ip_addr;                                              /* original IP used to establish this connection */

      /* packet scattering/gathering variables */
      int wanted_size;
      int current_size;
      char *tmp_buf;                                              /* tmp_buf max size is 2KB */
                                                                              /* however, its really size is 2KB+1byte (to store the trailing '\0') */
} DCTC2DCTC_CNX;

static GArray *incoming_sock=NULL;
static GArray *outgoing_sock=NULL;

/***************************************************************************************************/
/* create the uaddr node. The node consists in 2 sockets                                           */
/* 1 unix udp socket named: $HOME/.dctc/dctc-unode.udp (to receive local UADDR and search queries) */
/* 1 internet udp socket using the port number stored in unode_port                                */
/***************************************************************************************************/
/* this function can be called more than 1 time to try to create missing socket */
/********************************************************************************/
static void init_uaddr_node(void)
{
      if(unode_lmp==NULL)
      {
            GString *tmp;

            /* create uaddr_ready file */
            tmp=g_string_new(dctc_dir->str);
            g_string_sprintfa(tmp,"/unode.%d",sizeof(UNODE_DATA));

            unode_lmp=lmp_new(tmp->str,sizeof(UNODE_DATA),-1);
            if(unode_lmp==NULL)
            {
                  disp_msg(ERR_MSG,"init_uaddr_node","unable to create ","|s",tmp->str,NULL);
                  g_string_free(tmp,TRUE);
                  exit(1);
            }
            g_string_free(tmp,TRUE);
      }

      if(l_unode_name==NULL)
      {
            l_unode_name=g_string_new(dctc_dir->str);
            l_unode_name=g_string_append(l_unode_name,"/dctc-unode.udp");
      }

      /* create the local datagram socket */
      if(l_unode_socket==-1)
      {
            l_unode_socket=socket(AF_UNIX,SOCK_DGRAM,0);
            if(l_unode_socket!=-1)
            {
                  int zz;
                  struct sockaddr_un name;

                  name.sun_family=AF_UNIX;
         strcpy(name.sun_path,l_unode_name->str);

                  zz=1;
      
                  if(setsockopt(l_unode_socket,SOL_SOCKET,SO_REUSEADDR,(char*)&zz,sizeof(zz)))
                  {
            perror("l_unode_socket - setsockopt");
                        close(l_unode_socket);
                        l_unode_socket=-1;
                  }
                  else 
                  {
            if(bind(l_unode_socket,(void *)&name,sizeof(struct sockaddr_un)))
            {
                              if((errno!=EINVAL)&&(errno!=EADDRINUSE))
                              {
                        perror("l_unode_socket - bind");
                                    close(l_unode_socket);
                                    l_unode_socket=-1;
                              }
                              else
                              {
                                    /* it looks like we cannot bind an AF_UNIX socket on a FS object even if it is */
                                    /* also an AF_UNIX socket and even if it is not used. Hopefully, thanks to semaphore */
                                    /* we know that we are the only program attached to this socket */
                                    unlink(l_unode_name->str);
                                    name.sun_family=AF_UNIX;
                        strcpy(name.sun_path,l_unode_name->str);
                        if(bind(l_unode_socket,(void *)&name,sizeof(struct sockaddr_un)))
                        {
                              perror("l_unode_socket - bind2");
                                          close(l_unode_socket);
                                          l_unode_socket=-1;
                                    }
                              }
            }
                  }
            }
            else
                  perror("init_uaddr_node: l_unode_socket");
      }

      /* create the TCP/IP socket to establish communication with other clients */
      if(r_unode_socket==-1)
      {
            unode_port=wanted_unode_port;
            r_unode_socket=_x_tcp(unode_port);
            if(r_unode_socket!=-1)
            {
                  set_tos_sock(r_unode_socket,udp_tos);
                  listen(r_unode_socket,5);
                  set_non_bloquant_sock(r_unode_socket);
            }
      }

      if(incoming_sock==NULL)
      {
            incoming_sock=g_array_new(FALSE,FALSE,sizeof(DCTC2DCTC_CNX));
      }

      if(outgoing_sock==NULL)
      {
            outgoing_sock=g_array_new(FALSE,FALSE,sizeof(DCTC2DCTC_CNX));
      }
}

/************************************************/
/* resolve hostname/hostip and update the entry */
/************************************************/
static void refresh_host_ip_assoc(UNODE_DATA *udt)
{
      char *t;
      char *cpy_str;

      udt->resolv_creation_date=time(NULL);
      udt->dest_addr.sin_family=AF_INET;

      cpy_str=strdup(udt->host_unresolved_addr);
      t=strchr(cpy_str,':');
      if(t!=NULL)
      {
            udt->dest_addr.sin_port=htons(atoi(t+1));
            *t='\0';
      }
      else
            udt->dest_addr.sin_port=htons(unode_port);

      if(str_to_inaddr(cpy_str,&(udt->dest_addr.sin_addr))!=0)
      {     /* if the address is not found, force it to 0 */
            udt->dest_addr.sin_addr.s_addr=0;
      }

      free(cpy_str);
}

static void update_unode_ips(void)
{
      static time_t last_update_time=0;
      UNODE_DATA *und;
      time_t cur_time;
      int i;

      cur_time=time(NULL);

      if(cur_time-last_update_time<60)
            return;

      G_LOCK(unode_lmp);

      if(lmp_lock_and_map(unode_lmp))
      {
            G_UNLOCK(unode_lmp);
            return;
      }

      und=unode_lmp->mapped_addr;
      for(i=1;i<unode_lmp->nb_records;i++)      /* skip the first record */
      {
            UNODE_DATA *udt=&(und[i]);

            if(udt->entry_enabled)
            {
                  if(udt->dynamic_ip)
                  {
                        if((cur_time-udt->resolv_creation_date)>MAX_IP_VALIDITY)
                        {
                              refresh_host_ip_assoc(udt);
                        }
                  }
            }
      }

      lmp_unmap_and_unlock(unode_lmp);
      G_UNLOCK(unode_lmp);
}
      
static void add_content_to_cnx_buffer(DCTC2DCTC_CNX *d2dcnx, char *string, int string_len)
{
      if(d2dcnx->sock_fd==-1)
            return;

      if(d2dcnx->wanted_size!=d2dcnx->current_size)
      {
            /* buffer not yet empty */
            if( (MAX_D2D_BUF_SIZE-d2dcnx->wanted_size)>=string_len )
            {     /* but string is small enough to fit in the remaining free bytes of the buffer, so we append it */
                  memcpy(d2dcnx->tmp_buf+d2dcnx->wanted_size,string,string_len);
                  d2dcnx->wanted_size+=string_len;
            }
      }
      else
      {
            /* buffer is empty */
            if(string_len<=MAX_D2D_BUF_SIZE)
            {     /* and string is small enough to fit in the buffer, just copy it */
                  memcpy(d2dcnx->tmp_buf,string,string_len);
                  d2dcnx->current_size=0;
                  d2dcnx->wanted_size=string_len;
            }
      }
}

/******************************************************************************************/
/* send the given string to all other known unode                                         */
/* the function takes care to avoid transmission of multiple identical string in a minute */
/******************************************************************************************/
static void send_to_other_unode(char *string, int string_len)
{
#if 0
      DBC *cursor;
      int ret;
      time_t cur_time;

      if(r_unode_socket==-1)        /* not internet socket exists, abort here */
            return;

      if(tos_entry_exists(UNDSND_TOSKEY,string,string_len,0))     /* don't send the same string too fast */
            return;

      ret=unode_db->cursor(unode_db,NULL,&cursor,0);
      if(ret==0)
      {
            DBT key;
            DBT data;
            char buf1[8192];
            UNODE_DATA udt;

            memset(&key,0,sizeof(key));
            memset(&data,0,sizeof(data));

            key.data=buf1;
            key.ulen=sizeof(buf1)-1;
            key.flags=DB_DBT_USERMEM;

            data.data=&udt;
            data.ulen=sizeof(udt);
            data.flags=DB_DBT_USERMEM;

            cur_time=time(NULL);

            ret=cursor->c_get(cursor,&key,&data,DB_FIRST);
            while(ret==0)
            {
                  if(udt.entry_enabled)
                  {
                        if(udt.dest_addr.sin_addr.s_addr!=0)
                        {
                              int out;

                              out=sendto(r_unode_socket,string,string_len,MSG_NOSIGNAL,(void*)&(udt.dest_addr),sizeof(struct sockaddr_in));
                              if(out!=string_len)
                              {
                                    perror("send_to_other_unode - sendto fails");
                              }
                        }
                  }
                  ret=cursor->c_get(cursor,&key,&data,DB_NEXT);
            }
            
            cursor->c_close(cursor);
      }
      add_tos_entry(UNDSND_TOSKEY,UNODE_MIN_RESEND_DELAY,string,string_len,NULL,0); /* don't send the same string too fast */
#else
      int i;

      if(outgoing_sock==NULL)
            return;

      if(tos_entry_exists(UNDSND_TOSKEY,string,string_len,0))     /* don't send the same string too fast */
            return;

      for(i=outgoing_sock->len-1;i>=0;i--)
      {
            DCTC2DCTC_CNX *d2dcnx;

            d2dcnx=&(g_array_index(outgoing_sock,DCTC2DCTC_CNX,i));
            add_content_to_cnx_buffer(d2dcnx,string,string_len);
      }
      add_tos_entry(UNDSND_TOSKEY,UNODE_MIN_RESEND_DELAY,string,string_len,NULL,0); /* don't send the same string too fast */
#endif
}

/****************************************************/
/* read local unix socket and handle its processing */
/****************************************************/
static void handle_local_unode_message(void)
{
      char buf[8192];
      int ret;
      char *t;

      ret=recv(l_unode_socket,buf,sizeof(buf)-1,MSG_NOSIGNAL);
      if(ret==-1)
      {
            disp_msg(ERR_MSG,"handle_local_unode_message","recv error",strerror(errno),NULL);
            return;
      }

      if(ret<2)
            return;

      buf[ret]='\0';
      t=strrchr(buf,'|');
      if(t==NULL)
            return;

      if(!strncmp(buf,"$Search ",strlen("$Search ")))
      {
            /* it is a search query */
            if(!strncmp(buf,"$Search Hub:",strlen("$Search Hub:")))
            {
                  /* it is a search query in passive mode, discard it */
                  return;
            }

            send_to_other_unode(buf,ret);
      }
      else if(!strncmp(buf,"$UADDR? ",strlen("$UADDR? ")))
      {
            /* it is a UADDR query */
            GString *tmp;
            
            *t='\0';          /* remote the trailing | */

            tmp=get_uaddr_dl_addr_by_name(buf+strlen("$UADDR? "));
            if(tmp!=NULL)
            {     /* a address is already in cache, ignore the query */
                  g_string_free(tmp,TRUE);
                  return;
            }

            *t='|';           /* restore the trailing | */
      
            send_to_other_unode(buf,ret);
      }
}

/**************************************************/
/* check if the given "from" is an allowed client */
/**************************************************/
/* output: 0=no, 1=yes */
/***********************/
static int is_a_valid_from(struct sockaddr_in *from, int from_len, char **org_addr)
{
      int ret_code=0;
      UNODE_DATA *und;
      int i;

      if(from_len!=sizeof(struct sockaddr_in))
            return ret_code;

      update_unode_ips();

      G_LOCK(unode_lmp);

      if(lmp_lock_and_map(unode_lmp))
      {
            G_UNLOCK(unode_lmp);
            return ret_code;
      }

      und=unode_lmp->mapped_addr;
      for(i=1;i<unode_lmp->nb_records;i++)      /* skip the first record */
      {
            UNODE_DATA *udt=&(und[i]);

            if(udt->entry_enabled)
            {
                  if(udt->dest_addr.sin_addr.s_addr!=0)
                  {
                        if(udt->dest_addr.sin_addr.s_addr==from->sin_addr.s_addr)
                        {
                              if(org_addr!=NULL)
                              {
                                    *org_addr=strdup(udt->host_unresolved_addr);
                              }
                              ret_code=1;
                              break;
                        }
                  }
            }
      }

      lmp_unmap_and_unlock(unode_lmp);
      G_UNLOCK(unode_lmp);
      return ret_code;
}

/**************************************************/
/* read internet socket and handle its processing */
/**************************************************/
static void handle_remote_unode_cnx_request(void)
{
      int fd;
      struct sockaddr from;
      int from_len=sizeof(from);
      DCTC2DCTC_CNX nw;

      fd=accept(r_unode_socket,&from,&from_len);
      if(fd==-1)
      {
            if(errno!=EAGAIN)
                  disp_msg(ERR_MSG,"handle_remote_unode_cnx_request","accept error",strerror(errno),NULL);
            return;
      }

      if(!is_a_valid_from((struct sockaddr_in *)&from,from_len,&nw.ip_addr))  /* someone tries to jam the system */
      {
            shutdown(fd,2);
            close(fd);
            return;
      }

      /* nw.ip_addr is already filled */
      nw.sock_fd=fd;
      
      nw.wanted_size=MAX_D2D_BUF_SIZE;
      nw.current_size=0;
      nw.tmp_buf=calloc(MAX_D2D_BUF_SIZE+1,1);

      if(nw.tmp_buf==NULL)
      {
            disp_msg(ERR_MSG,"handle_remote_unode_cnx_request","not enough memory to allocate a new buffer",NULL);
            free(nw.ip_addr);
            shutdown(fd,2);
            close(fd);
            return;
      }

      set_non_bloquant_sock(fd);
      incoming_sock=g_array_append_val(incoming_sock,nw);
}

/********************************************************************************************************************************/
/* find an outgoing_sock having the given sender_addr and if exists and its buffer is empty, put the given string in the buffer */
/********************************************************************************************************************************/
static void send_to_other_given_unode(char *sender_addr, char *str, int str_len)
{
      int i;

      if(outgoing_sock==NULL)
            return;

      for(i=outgoing_sock->len-1;i>=0;i--)
      {
            DCTC2DCTC_CNX *d2dcnx;

            d2dcnx=&(g_array_index(outgoing_sock,DCTC2DCTC_CNX,i));
            if(!strcmp(d2dcnx->ip_addr,sender_addr))
            {
                  add_content_to_cnx_buffer(d2dcnx,str,str_len);
                  break;
            }
      }
}

static void process_incoming_remote_uaddr_cmd(char *buf, char *sender_addr)
{
      if(!strncmp(buf,"$Search ",strlen("$Search ")))
      {
            /* it is a search query */
            if(!strncmp(buf,"$Search Hub:",strlen("$Search Hub:")))
            {
                  /* it is a search query in passive mode, discard it. This case should never happens */
                  return;
            }

            /* send the search query to all other DCTC on this computer */
            send_dc_line_to_dctc_link_direct(NULL,buf);

            /* and also to the my own dctc */
            add_new_sim_input(0,buf);
      }
      else if(!strncmp(buf,"$UADDR? ",strlen("$UADDR? ")))
      {
            /* it is a UADDR query */
            GString *tmp;
            char *t;
      
            t=strrchr(buf,'|');
            *t='\0';          /* remote the trailing | */

            tmp=get_uaddr_dl_addr_by_name(buf+strlen("$UADDR? "));
            if(tmp==NULL)
            {     /* there is no known user having the given name */
                  return;
            }

            /* tip top, this personne is known */
            tmp=g_string_prepend(tmp,"$UADDR |");
            g_string_sprintfa(tmp,"|%s|",buf+strlen("$UADDR? "));

            /* and return the reply to the sender */
            send_to_other_given_unode(sender_addr,tmp->str,tmp->len);
            g_string_free(tmp,TRUE);
      }
      else if(!strncmp(buf,"$UADDR ",strlen("$UADDR ")))
      {
            /* it is an UADDR result */
            gchar **arr;

            arr=g_strsplit(buf,"|",0);
            if(arr!=NULL)
            {
                  add_uaddr_entry(arr[2],arr[1]);
                  g_strfreev(arr);
            }
      }
}

static void close_d2dcnx(DCTC2DCTC_CNX *d2dcnx,int slot_num, GArray **ptr_array)
{
      if(d2dcnx==NULL)
            return;

      if(d2dcnx->sock_fd!=-1)
      {
            shutdown(d2dcnx->sock_fd,2);
            close(d2dcnx->sock_fd);
      }

      if(d2dcnx->ip_addr!=NULL)
            free(d2dcnx->ip_addr);

      if(d2dcnx->tmp_buf!=NULL)
            free(d2dcnx->tmp_buf);

      (*ptr_array)=g_array_remove_index_fast((*ptr_array),slot_num);
}


/***********************************************************************************/
/* this function is called to close an incoming connection after an error occurs   */
/* this function can delete the d2dcnx and remove it from incoming_sock (slot_num) */
/***********************************************************************************/
#define close_incoming_connection(d2dcnx,slot_num)          close_d2dcnx((d2dcnx),(slot_num),&incoming_sock)
#define close_outgoing_connection(d2dcnx,slot_num)          close_d2dcnx((d2dcnx),(slot_num),&outgoing_sock)

static void handle_incoming_remote_packet(DCTC2DCTC_CNX *d2dcnx, int in_slot_num)
{
      int ret;
      int max_size;
      char *t;

      if(d2dcnx->wanted_size==d2dcnx->current_size)
      {     /* either the buffer is empty or it is full, in any case, the only thing we can do is discarding its content */
            d2dcnx->wanted_size=MAX_D2D_BUF_SIZE;
            d2dcnx->current_size=0;
      }

      max_size=d2dcnx->wanted_size-d2dcnx->current_size;

      ret=recv(d2dcnx->sock_fd,d2dcnx->tmp_buf+d2dcnx->current_size,max_size,MSG_NOSIGNAL);
      if(ret==-1)
      {
            if((errno!=EINTR)&&(errno!=EAGAIN))
            {
                  close_incoming_connection(d2dcnx,in_slot_num);
            }
            return;
      }

      if(ret==0)
      {
            close_incoming_connection(d2dcnx,in_slot_num);
            return;
      }
      d2dcnx->current_size+=ret;

      d2dcnx->tmp_buf[d2dcnx->current_size]='\0';

      t=strchr(d2dcnx->tmp_buf,'|');
      while(t!=NULL)
      {     /* message completely received ? */
            char u;

            /* truncate the string just after the | */
            u=t[1];
            t[1]='\0';

            process_incoming_remote_uaddr_cmd(d2dcnx->tmp_buf,d2dcnx->ip_addr);

            /* restore the | */
            t[1]=u;
            strcpy(d2dcnx->tmp_buf,t+1);
            t=strchr(d2dcnx->tmp_buf,'|');
      }

      /* recompute the real size of the buffer */
      d2dcnx->current_size=strlen(d2dcnx->tmp_buf);
}

/*********************************************************************************************/
/* check if the given connection has something to send                                       */
/* on error, this function can delete the d2dcnx and remove it from outgoing_sock (slot_num) */
/*********************************************************************************************/
static void handle_outgoing_connection_management(DCTC2DCTC_CNX *d2dcnx,int slot_num)
{
      int ret;
      int ln;

      if(d2dcnx->sock_fd==-1)
            return;

      if(d2dcnx->wanted_size==d2dcnx->current_size)
            return;

      ln=d2dcnx->wanted_size-d2dcnx->current_size;
      ret=send(d2dcnx->sock_fd,d2dcnx->tmp_buf+d2dcnx->current_size,ln,MSG_NOSIGNAL|MSG_DONTWAIT);
      if(ret==-1)
      {
            if((errno==EAGAIN)||(errno==EINTR)) /* non fatal error code */
                  return;

            shutdown(d2dcnx->sock_fd,2);
            close(d2dcnx->sock_fd);
            d2dcnx->sock_fd=-1;
      }
      else
      {
            d2dcnx->current_size+=ret;

            if(d2dcnx->wanted_size==d2dcnx->current_size)
            {     /* reset position */
                  d2dcnx->wanted_size=d2dcnx->current_size=0;
            }
      }
}     

/**********************************************************************/
/* search inside the unode_db database to find the given host_ip_port */
/* On error, NULL is returned, unode_data is unchanged.               */
/* On success, a pointer on the given unode_data is returned and this */
/* structure is populated with the database content.                  */
/**********************************************************************/
static UNODE_DATA *get_unode_info(char *host_ip_port, UNODE_DATA *unode_data)
{
      UNODE_DATA *und;
      UNODE_DATA *ret_code=NULL;
      int i;

      G_LOCK(unode_lmp);

      if(lmp_lock_and_map(unode_lmp))
      {
            G_UNLOCK(unode_lmp);
            return ret_code;
      }

      und=unode_lmp->mapped_addr;
      for(i=1;i<unode_lmp->nb_records;i++)      /* skip the first record */
      {
            UNODE_DATA *udt=&(und[i]);

            if(udt->entry_enabled)
            {
                  if(!strcmp(udt->host_unresolved_addr,host_ip_port))
                  {
                        memcpy(unode_data,udt,sizeof(UNODE_DATA));
                        ret_code=unode_data;
                  }
            }
      }

      lmp_unmap_and_unlock(unode_lmp);
      G_UNLOCK(unode_lmp);

      return ret_code;
}

/************************************************************************************/
/* search thru the outgoing_sock array for a connection with the given host_ip_port */
/************************************************************************************/
static int get_outgoing_cnx_idx(char *host_ip_port)
{
      int i;

      for(i=0;i<outgoing_sock->len;i++)
      {
            DCTC2DCTC_CNX *d2dcnx;

            d2dcnx=&(g_array_index(outgoing_sock,DCTC2DCTC_CNX,i));
            if(!strcmp(d2dcnx->ip_addr,host_ip_port))
                  return i;
      }
      return -1;
}

void unode_alter_socket_tos(void)
{
      if(r_unode_socket!=-1)
            set_tos_sock(r_unode_socket,udp_tos);
}

static void manage_uaddr_node(void)
{
      fd_set rd,wr;
      int n;

      n=-1;
      FD_ZERO(&rd);
      FD_ZERO(&wr);

      update_unode_ips();

      if(l_unode_socket!=-1)
      {
            FD_SET(l_unode_socket,&rd);
            n=MAX(n,l_unode_socket);
      }

      /* check if we have incoming connection request ? */
      if(r_unode_socket!=-1)
      {
            FD_SET(r_unode_socket,&rd);
            n=MAX(n,r_unode_socket);
      }

      /* check if we have received message from remote client */
      if(incoming_sock!=NULL)
      {
            int i;
            for(i=0;i<incoming_sock->len;i++)
            {
                  DCTC2DCTC_CNX *d2dcnx;

                  d2dcnx=&(g_array_index(incoming_sock,DCTC2DCTC_CNX,i));
                  FD_SET(d2dcnx->sock_fd,&rd);
                  n=MAX(n,d2dcnx->sock_fd);
            }
      }

      /* check if something has to be sent on the outgoing connections */
      if(outgoing_sock!=NULL)
      {
            int i;
            for(i=0;i<outgoing_sock->len;i++)
            {
                  DCTC2DCTC_CNX *d2dcnx;

                  d2dcnx=&(g_array_index(outgoing_sock,DCTC2DCTC_CNX,i));
                  if((d2dcnx->sock_fd!=-1)&&(d2dcnx->wanted_size!=d2dcnx->current_size))
                  {
                        FD_SET(d2dcnx->sock_fd,&wr);
                        n=MAX(n,d2dcnx->sock_fd);
                  }
            }
      }

      if(n==-1)
      {
            /* nothing to monitor */
            sleep(1);
      }
      else
      {
            struct timeval tv;
            int ln;

            /* wait at most 1 second */
            tv.tv_sec=1;
            tv.tv_usec=0;

            ln=select(n+1,&rd,&wr,NULL,&tv);
            if(ln>0)
            {
                  if( (l_unode_socket!=-1) && FD_ISSET(l_unode_socket,&rd) )
                  {
                        handle_local_unode_message();
                  }

                  if( (r_unode_socket!=-1) && FD_ISSET(r_unode_socket,&rd) )
                  {
                        /* check if we have incoming connection request ? */
                        handle_remote_unode_cnx_request();
                  }

                  if(incoming_sock!=NULL)
                  {
                        int i;
                        for(i=incoming_sock->len-1;i>=0;i--)
                        {
                              DCTC2DCTC_CNX *d2dcnx;

                              d2dcnx=&(g_array_index(incoming_sock,DCTC2DCTC_CNX,i));
                              if(FD_ISSET(d2dcnx->sock_fd,&rd))
                              {
                                    handle_incoming_remote_packet(d2dcnx,i);
                              }
                        }
                  }

                  if(outgoing_sock!=NULL)
                  {
                        int i;
                        for(i=outgoing_sock->len-1;i>=0;i--)
                        {
                              DCTC2DCTC_CNX *d2dcnx;

                              d2dcnx=&(g_array_index(outgoing_sock,DCTC2DCTC_CNX,i));
                              if((d2dcnx->sock_fd!=-1)&&(d2dcnx->wanted_size!=d2dcnx->current_size)&&(FD_ISSET(d2dcnx->sock_fd,&wr)))
                              {
                                    handle_outgoing_connection_management(d2dcnx,i);
                              }
                        }
                  }
            }
      }

      /* check if the user wants to modify the UNODE port */
      if(wanted_unode_port!=unode_port)
      {
            if(r_unode_socket!=-1)
            {
                  shutdown(r_unode_socket,2);
                  close(r_unode_socket);
                  r_unode_socket=-1;
            }
      }

      if((l_unode_socket==-1)||(r_unode_socket==-1))
      {
            init_uaddr_node();
      }

      /* we still have 3 things to do: */
      /* 1) remove outgoing_sock connection without existing entry in unode_db */
      if(outgoing_sock!=NULL)
      {
            int i;
            for(i=outgoing_sock->len-1;i>=0;i--)
            {
                  DCTC2DCTC_CNX *d2dcnx;
                  UNODE_DATA unode_data;

                  d2dcnx=&(g_array_index(outgoing_sock,DCTC2DCTC_CNX,i));

                  if(get_unode_info(d2dcnx->ip_addr,&unode_data)==NULL)
                  {
                        close_outgoing_connection(d2dcnx,i);
                  }
            }
      }

      /* 2) add newly inserted entry in unode_db */
      {
            UNODE_DATA *und;
            int i;

            G_LOCK(unode_lmp);

            if(!lmp_lock_and_map(unode_lmp))
            {
                  und=unode_lmp->mapped_addr;
                  for(i=1;i<unode_lmp->nb_records;i++)      /* skip the first record */
                  {
                        UNODE_DATA *udt=&(und[i]);
            
                        if(udt->entry_enabled)
                        {
                              if(get_outgoing_cnx_idx(udt->host_unresolved_addr)==-1)
                              {
                                    DCTC2DCTC_CNX nw;

                                    nw.sock_fd=-1;
                                    nw.ip_addr=strdup(udt->host_unresolved_addr);
                                    if(nw.ip_addr==NULL)
                                          continue;
                                    nw.wanted_size=MAX_D2D_BUF_SIZE;
                                    nw.current_size=0;
                                    nw.tmp_buf=calloc(MAX_D2D_BUF_SIZE+1,1);

                                    if(nw.tmp_buf==NULL)
                                    {
                                          free(nw.ip_addr);
                                          continue;
                                    }

                                    outgoing_sock=g_array_append_val(outgoing_sock,nw);
                              }
                        }
                  }

                  lmp_unmap_and_unlock(unode_lmp);
            }
            G_UNLOCK(unode_lmp);
      }

      /* 3) restart connections having a sock_fd==-1 */
      if(outgoing_sock!=NULL)
      {
            int i;
            for(i=0;i<outgoing_sock->len;i++)
            {
                  DCTC2DCTC_CNX *d2dcnx;

                  d2dcnx=&(g_array_index(outgoing_sock,DCTC2DCTC_CNX,i));

                  if(d2dcnx->sock_fd==-1)
                  {
                        UNODE_DATA unode_data;

                        if(get_unode_info(d2dcnx->ip_addr,&unode_data)!=NULL)
                        {
                              char tmp_addr[64];
                              int tmp_port;

                              if(((tmp_port=ntohs(unode_data.dest_addr.sin_port))!=0)&&(unode_data.dest_addr.sin_addr.s_addr!=0))
                              {
                                    sprintf(tmp_addr,"%u.%u.%u.%u",
                                                            (ntohl(unode_data.dest_addr.sin_addr.s_addr)>>24)&255,
                                                            (ntohl(unode_data.dest_addr.sin_addr.s_addr)>>16)&255,
                                                            (ntohl(unode_data.dest_addr.sin_addr.s_addr)>>8)&255,
                                                            (ntohl(unode_data.dest_addr.sin_addr.s_addr))&255);

                                    d2dcnx->sock_fd=create_and_open_sock_on(tmp_addr,tmp_port,1);
                              }
                        }
                  }
            }
      }
}



Generated by  Doxygen 1.6.0   Back to index