Package de.desy.tine.addrUtils

Source Code of de.desy.tine.addrUtils.TSrvEntry

//: TLink.java
// TODO: get rid of some of the hard-wired numbers below, such as '200' for the addr cache limit
package de.desy.tine.addrUtils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.util.ArrayList;

import de.desy.tine.client.TLinkFactory;
import de.desy.tine.client.TLink;
import de.desy.tine.csvUtils.csv;
import de.desy.tine.dataUtils.TDataType;
import de.desy.tine.definitions.*;
import de.desy.tine.server.logger.DbgLog;
import de.desy.tine.server.logger.MsgLog;
import de.desy.tine.startup.TInitializer;
import de.desy.tine.startup.TInitializerFactory;
import de.desy.tine.structUtils.TStructRegistry;
import de.desy.tine.types.*;

// TODO:  change all of the hardwired 200s and 100s below ...
public final class TSrvEntry
{
  private static TInitializer initializer = TInitializerFactory.getInstance().getInitializer();
  private static TLinkFactory tlf = null;
  private static TLinkFactory getLinkFactory()
  {
    if (tlf == null) tlf = TLinkFactory.getInstance();
    return tlf;
  }
  private static final String fecHdr = "FecName, FecNetwork, FecNode, IPAddr, PortOffset, TineProtocol";
  private static final String srvHdr = "Name, FecName, EqpModule, Context, SubSystem";
  private static String crlf = System.getProperty("line.separator");
  private static String cacheFilePath = null;
  private static String tineHomePath = null;
  private static final int CACHE_TABLE_LENGTH = 2048;
  public static final String SRVEQM_NAME = "_SRV__";
  public static final String SRVFEC_NAME = "NETWORK";
  public static final String SRVEXP_NAME = "NETWORK";
  public static final String DOOCSEQM = "DCSEQM";
  public boolean isDoocsSrv()
  {
    return isDoocsSrv(eqmName);
  }
  public static boolean isDoocsSrv(String eqm)
  {
    return (eqm != null && eqm.compareTo(DOOCSEQM) == 0);
  }
  public static boolean isDoocsSrv(String context, String server)
  {
    String eqm = getSrvEntryEqmName(context,server);
    return (eqm != null && eqm.compareTo(DOOCSEQM) == 0);
  }
  private static BufferedReader fecR = null;
  private static BufferedReader ensR = null;
  private static BufferedReader srvR = null;
  private static BufferedReader fecCacheR = null;
  private static BufferedWriter fecCacheW = null;
  private static BufferedWriter srvCacheW = null;
  private static String fecCacheFile = null;
  private static String srvCacheFile = null;
  private static boolean initialized = false;
  private static boolean initializing = false;
  private static int ensSrvCacheIndex = -1;
  private static int ensDevCacheIndex = -1;
  private static int gensSrvCacheIndex = -1;
  private static int gensDevCacheIndex = -1;
  public String srvName;
  public String eqmName;
  public String fecName;
  public String cntName;
  static NameCache[] srvNameCache = new NameCache[CACHE_TABLE_LENGTH];
  static String[] modNameCache = new String[CACHE_TABLE_LENGTH];
  static TFecEntry[] fecAddrCache = new TFecEntry[CACHE_TABLE_LENGTH];
  static int modNameCacheLength = 0;
  static int fecAddrCacheLength = 0;
  static int NameCacheLength = 0;
  static int numConfiguredNameServers = 0;
  static int currentConfiguredNameServer = 0;
  public static String currentConfiguredNameServerTag;
  public static TFecEntry getFecEntry(String fecName)
  {
    if (fecName == null) return null;
    for (int i=0; i<fecAddrCacheLength; i++)
    {
      if (fecAddrCache[i] == null) continue;
      if (fecName.compareToIgnoreCase(fecAddrCache[i].fecName) == 0)
      {
        return fecAddrCache[i];
      }
    }
    return null;
  }
  public static String getSrvEntryEqmName(String context,String server)
  {
    if (server == null) return null;
    for (int i=0; i<NameCacheLength; i++)
    {
      if (context != null && context.length() > 0 &&
          context.compareToIgnoreCase("DEFAULT") != 0 &&
          context.compareToIgnoreCase(srvNameCache[i].cntName) != 0) continue;
      if (server.compareToIgnoreCase(srvNameCache[i].srvName) == 0)
      {
        return modNameCache[srvNameCache[i].modNameIndex];
      }
    }
    return null;
  }
  public TFecEntry fecAddr;
  private csv srvFile;
  static int debugLevel = 0;
  public boolean isLegacy = false;
  private String resolutionHistory = "";
  public String getResolutionHistory() { return resolutionHistory; }
  public static void reset()
  {
    // leave the configured ENS and GENS in the table ..
    int keep = numConfiguredNameServers * 2;
    if (modNameCacheLength > keep) modNameCacheLength = keep;
    if (fecAddrCacheLength > keep) fecAddrCacheLength = keep;
    if (NameCacheLength > keep) NameCacheLength = keep;
    // and clear the acquired structures ...
    TStructRegistry.clear();
  }
  public String toString(String srvName,String ctxName)
  {
    if (eqmName == null) return new String("module does not exist");
    StaticAddress(srvName,ctxName);
    String modstr = new String("");
    modstr +=   "Local Equipment Module : " + eqmName.trim();
    modstr += "\nFront End Computer     : " + fecName.trim();
    if (fecAddr != null && fecAddr.fecHost != null)
    {
      modstr += "\nIP Address             : " + fecAddr.fecHost.getHostAddress();
      modstr += "\nPort Offset            : " + fecAddr.fecPortOffset;
      modstr += "\nHost Name              : " + fecAddr.fecHost.getHostName();
    }
    return modstr;
  }
  void StaticAddress(String srvName,String ctxName)
  {
    int i;
    if (srvName == null || ctxName == null)
    {
      eqmName = ""; fecName = ""; cntName = "";
      return;
    }
    cntName = ctxName;
    if (isENSCall(srvName, ctxName)) srvName = currentConfiguredNameServerTag;
    for (i=0; i<NameCacheLength; i++)
    {
      if (ctxName.length() > 0 &&
          ctxName.compareToIgnoreCase("DEFAULT") != 0 &&
          ctxName.compareToIgnoreCase(srvNameCache[i].cntName) != 0) continue;
      if (srvName.compareToIgnoreCase(srvNameCache[i].srvName) == 0)
      {
        eqmName = modNameCache[srvNameCache[i].modNameIndex];
        fecName = fecAddrCache[srvNameCache[i].fecNameIndex].fecName;
        fecAddr = fecAddrCache[srvNameCache[i].fecNameIndex];
        return;
      }
    }
    // acquire name info from ens or file:
    if (srvName.startsWith("ENS"))
    {
      eqmName = new String("ENSEQM");
      fecName = new String("ENS");
      cntName = new String("SITE");
    }
    if (srvName.compareTo("NAMEQRY") == 0)
    {
      eqmName = new String("ENSEQM");
      fecName = new String("ENS");
      cntName = new String("SITE");
    }
    if (srvName.startsWith("GENS"))
    {
      eqmName = new String("GRPEQM");
      fecName = new String("GENS");
      cntName = new String("SITE");
    }
    if (eqmName == null) return;
    if (modNameCacheLength >= CACHE_TABLE_LENGTH) return;
    if (fecAddrCacheLength >= CACHE_TABLE_LENGTH) return;
    if (NameCacheLength >= CACHE_TABLE_LENGTH) return;
    int nameCacheIndex = NameCacheLength;
    srvNameCache[nameCacheIndex] = new NameCache();
    for (i=0; i<modNameCacheLength; i++)
      if (eqmName.compareTo(modNameCache[i]) == 0) break;
    if (i == modNameCacheLength) modNameCache[modNameCacheLength++] = eqmName;
    srvNameCache[nameCacheIndex].modNameIndex = i;
    for (i=0; i<fecAddrCacheLength; i++)
      if (fecName.compareTo(fecAddrCache[i].fecName) == 0) break;
    if (i == fecAddrCacheLength)
    { // last ditch effort (works only if the address is hard-wired in the initializer)
      TFecEntry tfe = new TFecEntry(fecName);
      if (!tfe.fecRegistered) return;
      fecAddrCache[fecAddrCacheLength] = tfe;
      fecAddr = fecAddrCache[fecAddrCacheLength++];
      if (fecName.startsWith("ENS")) numConfiguredNameServers++;
    }
    srvNameCache[nameCacheIndex].fecNameIndex = i;
    srvNameCache[nameCacheIndex].srvName = srvName;
    srvNameCache[nameCacheIndex].cntName = cntName;
    if (nameCacheIndex < CACHE_TABLE_LENGTH) NameCacheLength++;
  }
  static int addNameServerToServerCache(TFecEntry sa)
  {
    debugLevel = TLinkFactory.debugLevel;
    if (fecAddrCacheLength >= CACHE_TABLE_LENGTH ||
        NameCacheLength >= CACHE_TABLE_LENGTH ||
        numConfiguredNameServers > 10) return -1;
    MsgLog.log("addNameServerToServerCache","Adding ENS "+numConfiguredNameServers+" ("+sa.fecHost.getHostAddress()+ ") to address cache",0,null,1);
    synchronized(getLinkFactory().ensMutex)
    {
      if (ensSrvCacheIndex == -1) ensSrvCacheIndex = fecAddrCacheLength;
      if (ensDevCacheIndex == -1) ensDevCacheIndex = NameCacheLength;
    }
    fecAddrCache[fecAddrCacheLength] = sa;
    srvNameCache[NameCacheLength] = new NameCache();
    srvNameCache[NameCacheLength].fecNameIndex = fecAddrCacheLength;
    srvNameCache[NameCacheLength].modNameIndex = modNameCacheLength;
    srvNameCache[NameCacheLength].srvName = sa.fecName; // fec = srv for ENS
    srvNameCache[NameCacheLength].cntName = "SITE";
    modNameCache[modNameCacheLength] = "ENSEQM";
    fecAddrCacheLength++;
    modNameCacheLength++;
    NameCacheLength++;
    numConfiguredNameServers++;
    if (numConfiguredNameServers == 1// been called at least once ...
    {
      currentConfiguredNameServerTag = new String(sa.fecName);
    }
    return 0;
  }
  static int addGroupServerToServerCache(TFecEntry sa)
  { // TODO: meld this cut-and-paster with the above routine ...
    if (fecAddrCacheLength >= CACHE_TABLE_LENGTH ||
        NameCacheLength >= CACHE_TABLE_LENGTH ||
        numConfiguredNameServers > 10)
      return -1;
    if (debugLevel > 1) DbgLog.log("addGroupServerToServerCache","Adding GENS " + numConfiguredNameServers + " to address cache");
    if (gensSrvCacheIndex == -1) gensSrvCacheIndex = fecAddrCacheLength;
    if (gensDevCacheIndex == -1) gensDevCacheIndex = NameCacheLength;
    fecAddrCache[fecAddrCacheLength] = sa;
    srvNameCache[NameCacheLength] = new NameCache();
    srvNameCache[NameCacheLength].fecNameIndex = fecAddrCacheLength;
    srvNameCache[NameCacheLength].modNameIndex = modNameCacheLength;
    srvNameCache[NameCacheLength].srvName = sa.fecName; // fec = srv for GENS
    srvNameCache[NameCacheLength].cntName = "SITE";
    modNameCache[modNameCacheLength] = "GRPEQM";
    fecAddrCacheLength++;
    NameCacheLength++;
    modNameCacheLength++;
    return 0;
  }
  static int addNameServer(String ip)
  {
    TFecEntry sa;
    SrvAddr da;
    da = new SrvAddr();
    da.fecName = new String("ENS#" + numConfiguredNameServers);
    da.eqmContext = new String("SITE");
    da.eqmName = new String("ENSEQM");
    da.ipAddr = new String(ip);
    da.portOffset = 0;
    da.inetProtocol = TTransport.UDP; // 2;
    da.tineProtocol = TTransport.DEFAULT_PROTOCOL_LEVEL;
    sa = new TFecEntry(da);
    if (!sa.fecRegistered) return -1;
    addNameServerToServerCache(sa);
    // now add the GENS ...
    da.fecName = new String("GENS#" + numConfiguredNameServers);
    da.eqmName = new String("GRPEQM");   
    da.portOffset = 101;
    sa = new TFecEntry(da);
    if (!sa.fecRegistered) return -1;
    addGroupServerToServerCache(sa);
    return 0;
  }
  static Object srvEntryMutex = new Object();
  public static String getAddrFileLocation()
  {
    if (cacheFilePath == null) setAddrFileLocation();
    return new String(cacheFilePath);
  }
  static void setAddrFileLocation()
  {
    synchronized (srvEntryMutex)
    {
      if (initialized) return;
      try
      {
        if (fecR.ready() && srvR.ready())
        {
          if (TLinkFactory.debugLevel > 1) DbgLog.log("SetAddrFileLocation","static database readers ready");
        }
      }
      catch (Exception e)
      { // null or IO exception (just starting up ...)
        fecR = initializer.getAddressResource();
        srvR = initializer.getEquipmentResource();
      }
      if (initializing) return;
      initializing = true;
     
      String ensName;
      TFecEntry sa;
      currentConfiguredNameServerTag = new String("ENS")// default
      String ensEnv = System.getProperty("tine.ens");
      if (ensEnv != null)
      { // property setting !
        MsgLog.log("TSrvEntry.setAddrFileLocation", "ENS address set from property setting",0,null,1);       
      }
      else
      { // try environment
        if ((ensEnv=System.getenv("TINE_ENS")) != null)
        { // found this in the environment
          MsgLog.log("TSrvEntry.setAddrFileLocation", "ENS address set from environment",0,null,1);         
        }
      }
      String[] ensLst = null;
      if (ensEnv != null && ensEnv.length() > 0)
      {
        ensLst = ensEnv.split(",");
      }
      for (int i=0; i<5; i++
      { // don't allow more than 5 configured name servers ...
        if (ensLst != null)
        { // something from the environment (TINE_ENS)
          if (i < ensLst.length)
          {
            addNameServer(ensLst[i]);
            MsgLog.log("TSrvEntry.setAddrFileLocation", "ENS#"+i+" from environment or property",0,null,1);         
          }
          continue;
        }
        ensName = new String("ENS#" + i);
        if (debugLevel > 1) DbgLog.log("SetAddrFileLocation","ENS: looking for " + ensName);
        ensR = initializer.getHostsResource(); // will be closed in the csv reader
        if (ensR != null)     
        { // there is a local cshosts.csv file !
          sa = new TFecEntry(ensR,ensName);
          if (!sa.fecRegistered)
          { // maybe a simple name is entered in the cshosts.csv file ?
            sa = new TFecEntry(ensR,"ENS");
          }
          if (sa.fecRegistered)
          {
            MsgLog.log("TSrvEntry.setAddrFileLocation", "ENS#"+i+" from cshosts.csv",0,null,1);
          }
        }
        else
        { // try to discover it
          findNameServerFromDNS();
          if (numConfiguredNameServers > 0)
          {
            for (int k=0; k<numConfiguredNameServers; k++)
              MsgLog.log("TSrvEntry.setAddrFileLocation", "ENS#"+k+" from DNS",0,null,1);         
            break;
          }
          findNameServerOnNetwork();
          if (numConfiguredNameServers > 0)
          {
            for (int k=0; k<numConfiguredNameServers; k++)
              MsgLog.log("TSrvEntry.setAddrFileLocation", "ENS#"+k+" from multicast discovery",0,null,1);         
            break;
          }
          // not found in DNS/on network: use a hard-wired address
          MsgLog.log("TSrvEntry.setAddrFileLocation", "ENS#"+i+" address hard-wired",0,null,1);         
          sa = new TFecEntry("ENS");
        }
        if (!sa.fecRegistered)
        {
          if (debugLevel > 1) DbgLog.log("SetAddrFileLocation",ensName + " Not Registered");
          continue;
        }
        addNameServerToServerCache(sa);
        // now add the GENS ...
        SrvAddr da = new SrvAddr();
        da.fecName = new String("GENS#" + numConfiguredNameServers);
        da.eqmName = new String("GRPEQM");
        da.ipAddr = sa.fecHost.getHostAddress();
        da.portOffset = 101;
        sa = new TFecEntry(da);
        addGroupServerToServerCache(sa);
        if (ensR == null) break;
      }
      if (ensR != null)
      { // there was a cshosts.csv found and we're finished with it
        try { ensR.close(); } catch (Exception x) { x.printStackTrace(); }
      }
      if (tineHomePath == null) tineHomePath = initializer.getTineHome();
      if (cacheFilePath == null)
      {
        cacheFilePath = initializer.getTineCache();
        cacheFilePath += File.separator + "tine" + File.separator + "cache" + File.separator;
      }
      if (File.separatorChar == '\\') crlf = "\r\n";
    
      srvCacheFile = cacheFilePath + "eqpdbase.csv";
      fecCacheFile = cacheFilePath + "fecaddr.csv";
 
      initialized = true;
      initializing = false;
    }
  }
  public TSrvEntry()
  {
    eqmName = ""; srvName = ""; cntName = ""; fecName = "";
    setAddrFileLocation();
  }
  private static boolean isInSrvFile(SrvAddr srv)
  {
    boolean hasEntry = false;
    csv csvf = new csv(srvCacheFile);
    try
    {
      String s, hdr;
      int srv_col = -1,eqn_col = -1 ,fec_col = -1,ctx_col = -1;
      boolean done = false;
      while((s=csvf.readLine()) != null)
      {
        if (s.length() == 0) continue;
        if (s.startsWith("#") || s.startsWith(";") || s.startsWith("%")) continue;
        if (!done)
        {
          hdr = s;
          if ((srv_col=csvf.findcol(hdr,"NAME")) < 0) throw new NoSuchFieldException();
          if ((eqn_col=csvf.findcol(hdr,"EQPMODULE")) < 0) throw new NoSuchFieldException();
          if ((fec_col=csvf.findcol(hdr,"FECNAME")) < 0) throw new NoSuchFieldException();
          if ((ctx_col=csvf.findcol(hdr,"CONTEXT")) < 0) throw new NoSuchFieldException();
          done = true;
          continue;
        }
        if (csvf.namcmp(srv.expName,s,srv_col) != 0) continue;
        if (csvf.namcmp(srv.eqmName,s,eqn_col) != 0) continue;
        if (csvf.namcmp(srv.fecName,s,fec_col) != 0) continue;
        if (csvf.namcmp(srv.eqmContext,s,ctx_col) != 0) continue;
        hasEntry = true;
        break;
      }
    }
    catch (Exception e)
    { // database corrupt or not found
      MsgLog.log("TSrvEntry.isInSrvFile", e.getMessage(),TErrorList.database_not_loaded,e,1);
      hasEntry = false;
    }
    finally
    {
      csvf.close();
    }
    return hasEntry;
  }
  private static boolean isInFecFile(SrvAddr srv)
  {
    boolean hasEntry = false;
    csv csvf = new csv(fecCacheFile);
    try
    {
      String s, hdr;
      int fec_col = -1,ip_col = -1 ,port_col = -1,prot_col = -1;
      boolean done = false;
      while((s=csvf.readLine()) != null)
      {
        if (s.length() == 0) continue;
        if (s.startsWith("#") || s.startsWith(";") || s.startsWith("%")) continue;
        if (!done)
        {
          hdr = s;
          if ((fec_col=csvf.findcol(hdr,"FEC_NAME")) < 0) throw new NoSuchFieldException();
          if ((ip_col=csvf.findcol(hdr,"IP_ADDR")) < 0) throw new NoSuchFieldException();
          if ((port_col=csvf.findcol(hdr,"PORT_OFFSET")) < 0) throw new NoSuchFieldException();
          prot_col = csvf.findcol(hdr,"TINE_PROTOCOL");
          done = true;
          continue;
        }
        if (csvf.namcmp(srv.fecName,s,fec_col) != 0) continue;
        if (csvf.namcmp(srv.ipAddr,s,ip_col) != 0) continue;
        try
        {
          if (srv.portOffset != Integer.parseInt(csvf.colptr(port_col,s))) continue;
          if (prot_col < 0) continue;
          if (srv.tineProtocol != Integer.parseInt(csvf.colptr(prot_col,s))) continue;
        }
        catch (Exception e)
        {
          continue;
        }
        hasEntry = true;
        break;
      }
    }
    catch (Exception e)
    { // database corrupt or not found
      MsgLog.log("TSrvEntry.isInFecFile", e.getMessage(),TErrorList.database_not_loaded,e,1);
      hasEntry = false;
    }
    finally
    {
      csvf.close();
    }
    return hasEntry;
  }
  private static boolean addToSrvFile(SrvAddr srv)
  {
    boolean hasEntry = false;
    boolean needHeader = true;
    csv csvr = new csv(srvCacheFile);
    try
    {
      File csvw = new File(cacheFilePath);
      csvw.mkdirs();
      csvw = new File(srvCacheFile + ".tmp");
      if (csvw.exists() && csvw.lastModified() > System.currentTimeMillis() - 300000)
      { // file more recent than the last 5 minutes -> some other client app is updating ?
        return false;
      }
      srvCacheW = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(srvCacheFile + ".tmp")));
      String s, hdr;
      int srv_col = -1,ctx_col = -1;
      boolean done = false;
      while((s=csvr.readLine()) != null)
      {
        if (s.length() == 0) continue;
        if (s.startsWith("#") || s.startsWith(";") || s.startsWith("%")) continue;
        if (!done)
        {
          hdr = s;
          if ((srv_col=csvr.findcol(hdr,"NAME")) < 0) throw new NoSuchFieldException();
          if ((ctx_col=csvr.findcol(hdr,"CONTEXT")) < 0) throw new NoSuchFieldException();
          srvCacheW.write(srvHdr.trim() + crlf);
          needHeader = false;
          done = true;
          continue;
        }
        if (csvr.namcmp(srv.expName,s,srv_col) == 0 &&
            csvr.namcmp(srv.eqmContext,s,ctx_col) == 0)
        { // found the entry -> update the particulars
          s = srv.expName.trim() + ", " + srv.fecName.trim() + ", " + srv.eqmName.trim()
              + ", " +  srv.eqmContext.trim() + ", " + srv.subSystem.trim();
          hasEntry = true;
        }
        srvCacheW.write(s + crlf);
      }
      if (needHeader) srvCacheW.write(srvHdr.trim() + crlf);
      if (!hasEntry)
      { // it's a new one !
        s = srv.expName.trim() + "," + srv.fecName.trim() + "," + srv.eqmName.trim()
            + "," +  srv.eqmContext.trim() + "," + srv.subSystem.trim();
        srvCacheW.write(s + crlf);       
      }
      srvCacheW.close();
      csvr.close();
      csvw = new File(srvCacheFile);
      csvw.delete();
      File srvf = new File(srvCacheFile + ".tmp");
      srvf.renameTo(new File(srvCacheFile));
    }
    catch (Exception e)
    { // database corrupt or not found
      MsgLog.log("TSrvEntry.addToSrvFile", e.getMessage(),TErrorList.database_not_loaded,e,1);
      hasEntry = false;
    }
    finally
    {
      csvr.close();
    }
    return hasEntry;
  }
  private static boolean addToFecFile(SrvAddr srv)
  {
    boolean needHeader = true;
    boolean hasEntry = false;
    csv csvr = new csv(fecCacheFile);
    try
    {
      File csvw = new File(cacheFilePath);
      csvw.mkdirs();
      csvw = new File(fecCacheFile + ".tmp");
      if (csvw.exists() && csvw.lastModified() > System.currentTimeMillis() - 300000)
      { // file more recent than the last 5 minutes -> some other client app is updating ?
        return false;
      }
      fecCacheW = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fecCacheFile + ".tmp")));
      String s, hdr;
      int fec_col = -1;
      boolean done = false;
      while((s=csvr.readLine()) != null)
      {
        if (s.length() == 0) continue;
        if (s.startsWith("#") || s.startsWith(";") || s.startsWith("%")) continue;
        if (!done)
        {
          hdr = s;
          if ((fec_col=csvr.findcol(hdr,"FEC_NAME")) < 0) throw new NoSuchFieldException();
          fecCacheW.write(fecHdr.trim() + crlf);
          done = true;
          needHeader = false;
          continue;
        }
        if (csvr.namcmp(srv.fecName,s,fec_col) == 0)
        {
          s = srv.fecName.trim() + ",00000000,000000000000," + srv.ipAddr.trim() + "," +
              srv.portOffset + "," + srv.tineProtocol; 
          hasEntry = true;
        }
        fecCacheW.write(s + crlf);
      }
      if (needHeader) fecCacheW.write(fecHdr.trim() + crlf);
      if (!hasEntry)
      { // it's a new one !
        s = srv.fecName.trim() + ",00000000,000000000000," + srv.ipAddr.trim() + "," +
            srv.portOffset + "," + srv.tineProtocol; 
        fecCacheW.write(s + crlf);       
      }
      csvr.close();
      fecCacheW.close();
      csvw = new File(fecCacheFile);
      csvw.delete();
      File fecf = new File(fecCacheFile + ".tmp");
      fecf.renameTo(new File(fecCacheFile));
    }
    catch (Exception e)
    { // database corrupt or not found
      MsgLog.log("TSrvEntry.addToFecFile", e.getMessage(),TErrorList.database_not_loaded,e,1);
      hasEntry = false;
    }
    finally
    {
      csvr.close();
    }
    return hasEntry;
  }
  private static boolean addToGroupCacheFile(String filename,String column,String tgt)
  {
    boolean needHeader = true;
    boolean hasEntry = false;
    String tfn = filename+".tmp";
    String gfn = filename+".csv";
    csv csvr = new csv(gfn);
    BufferedWriter grpCacheW;
    try
    {
      File csvw = new File(tfn);
      if (csvw.exists() && csvw.lastModified() > System.currentTimeMillis() - 600000)
      { // file more recent than the last 5 minutes -> some other client app is updating ?
        return false;
      }
      csvw = new File(tfn.substring(0, tfn.lastIndexOf(File.separatorChar)));
      csvw.mkdirs();
      grpCacheW = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tfn)));
      String s, hdr;
      int col = -1;
      boolean done = false;
      while((s=csvr.readLine()) != null)
      {
        if (s.length() == 0) continue;
        if (s.startsWith("#") || s.startsWith(";") || s.startsWith("%")) continue;
        if (!done)
        {
          hdr = s;
          if ((col=csvr.findcol(hdr,column)) < 0) throw new NoSuchFieldException();
          grpCacheW.write(column + crlf);
          done = true;
          needHeader = false;
          continue;
        }
        if (csvr.namcmp(tgt,s,col) == 0) hasEntry = true;
        grpCacheW.write(s + crlf);
      }
      if (needHeader) grpCacheW.write(column + crlf);
      if (!hasEntry)
      { // it's a new one !
        grpCacheW.write(tgt + crlf);       
      }
      grpCacheW.close();
      if (hasEntry)
      { // remove the .tmp file
        new File(tfn).delete();
      }
      else
      { // do the shuffle ...
        csvr.close();
        new File(gfn).delete();
        File tf = new File(tfn);
        tf.renameTo(new File(gfn));
      }
    }
    catch (Exception e)
    { // database corrupt or not found
      MsgLog.log("TSrvEntry.addToGroupCacheFile", e.getMessage(),TErrorList.database_not_loaded,e,1);
      hasEntry = false;
    }
    finally
    {
      csvr.close();
    }
    return hasEntry;
  }
  public static void addServerToGroupCacheFile(String ctx,String grp,String srv)
  {
    try
    { // trap null pointers and other garbage input with try/catch
      String filename = cacheFilePath+"GROUPS"+File.separator+ctx+File.separator+grp;
      addToGroupCacheFile(filename,"Members",srv);
    }
    catch (Exception ignore) {}   
  }
  public static void addDeviceToMemberCacheFile(String ctx,String srv,String dev)
  {
    try
    { // trap null pointers and other garbage input with try/catch
      String filename = cacheFilePath+"GROUPS"+File.separator+ctx+File.separator+srv+File.separator+"devices";
      addToGroupCacheFile(filename,"Devices",dev);
    }
    catch (Exception ignore) {}       
  }
  public static void addAddressToCacheFile(SrvAddr srv)
  {
    if (srv == null) return;
    if (!isInSrvFile(srv)) addToSrvFile(srv);
    if (!isInFecFile(srv)) addToFecFile(srv);   
  }
  private int fillinAddressFromFileCache(String devName,String srvName,String ctxName)
  {
    int cc = TErrorList.non_existent;
    String fn = srvFile.getFileName();
    if (fn == null)
      fn = TInitializerFactory.getInstance().getInitializer().getFecHome()+File.separator+"eqpdbase.csv";
    if (ctxName == null) ctxName = "";
    String msg;
    String tag = makeMsgTag(srvName, ctxName);
    try
    {
      if (devName != null) srvFile.mark();
      String s, hdr;
      int i, nam_col = -1,eqn_col = -1 ,srv_col = -1,ctxt_col = -1;
      boolean done = false;
      while((s=srvFile.readLine()) != null)
      {
        if (s.length() == 0) continue;
        if (s.startsWith("#") || s.startsWith(";") || s.startsWith("%")) continue;
        if (!done)
        {
          hdr = s;
          if ((nam_col=srvFile.findcol(hdr,"NAME")) < 0) throw new NoSuchFieldException();
          if ((eqn_col=srvFile.findcol(hdr,"EQPMODULE")) < 0) throw new NoSuchFieldException();
          if ((srv_col=srvFile.findcol(hdr,"FECNAME")) < 0) throw new NoSuchFieldException();
          if ((ctxt_col=srvFile.findcol(hdr,"CONTEXT")) < 0) throw new NoSuchFieldException();
          done = true;
          continue;
        }
        if (srvFile.namcmp(srvName,s,nam_col) == 0)
        {
          eqmName = srvFile.colptr(eqn_col,s);
          fecName = srvFile.colptr(srv_col,s);
          cntName = srvFile.colptr(ctxt_col,s);
          if (ctxName.compareToIgnoreCase(cntName) != 0) continue;
          if (fecName.compareTo("GENS") == 0 && devName != null)
          { // local file has resolved to the GENS !
            String[] memLst = getGroupMembersFromFileCache(cntName, srvName);
            for (i=0; i<memLst.length; i++)
            {
              if (groupFileHasDevice(cntName, memLst[i], devName))
              {
                String key = "/"+cntName+"/GENS/"+devName+"[*]";
                TLinkFactory.getInstance().appendRedirectionList(key, cntName, memLst[i], devName, "*");
                srvFile.rewind();
                cc = fillinAddressFromFileCache(null,memLst[i],cntName);
                break;
              }
            }
            srvFile.close();
            return cc;
          }
          if (modNameCacheLength >= CACHE_TABLE_LENGTH) break;
          if (fecAddrCacheLength >= CACHE_TABLE_LENGTH) break;
          if (NameCacheLength >= CACHE_TABLE_LENGTH) break;
          int nameCacheIndex = NameCacheLength;
          srvNameCache[nameCacheIndex] = new NameCache();
          for (i=0; i<modNameCacheLength; i++)
            if (eqmName.compareTo(modNameCache[i]) == 0) break;
          if (i == modNameCacheLength) modNameCache[modNameCacheLength++] = eqmName;
          srvNameCache[nameCacheIndex].modNameIndex = i;
          for (i=0; i<fecAddrCacheLength; i++)
            if (fecName.compareToIgnoreCase(fecAddrCache[i].fecName) == 0) break;
          if (i == fecAddrCacheLength)
          { // it's a new one
            fecCacheR = new BufferedReader(new InputStreamReader(new FileInputStream(fecCacheFile)));
            fecAddrCache[fecAddrCacheLength] = new TFecEntry(fecCacheR,fecName);
            if (fecAddrCache[fecAddrCacheLength].fecRegistered)
            { // local cache successful
              msg = "found FEC address in local file cache "+fn;
              resolutionHistory += msg + "\n";
              MsgLog.log("TSrvEntry.fillinAddressFromFileCache",tag+" "+msg,0,null,1);
            }
            else
            { // try static cache
              fecAddrCache[fecAddrCacheLength] = new TFecEntry(fecR,fecName);
              if (fecAddrCache[fecAddrCacheLength].fecRegistered)
              {
                msg = "found FEC address in static file cache "+fn;
                resolutionHistory += msg + "\n";
                MsgLog.log("TSrvEntry.fillinAddressFromFileCache",tag+" "+msg,0,null,1);
              }
            }
            if (fecAddrCache[fecAddrCacheLength].fecRegistered)
            { // okay to increment the cache table
              fecAddr = fecAddrCache[fecAddrCacheLength++];
            }
            else
            { // not found anywhere !
              fecAddr = null;
              cc = TErrorList.non_existent_fec;
              break;
            }
          }
          else
          {
            if (fecAddr == null) fecAddr = fecAddrCache[i];
          }
          srvNameCache[nameCacheIndex].fecNameIndex = i;
          srvNameCache[nameCacheIndex].srvName = srvName;
          srvNameCache[nameCacheIndex].cntName = ctxName;
          if (nameCacheIndex < CACHE_TABLE_LENGTH) NameCacheLength++;
          // found it
          cc = 0;
          break;
        }
      }
    }
    catch (Exception e)
    { // database corrupt or not found
      MsgLog.log("fillinAddressFromFileCache", e.getMessage(),TErrorList.database_not_loaded,e,1);
      cc = TErrorList.database_not_loaded;
      resolutionHistory += "fillinAddressFromFileCache: "+e.getMessage()+"\n";
    }
    finally
    {
      srvFile.close();
    }
    if (cc != 0)
    {
      msg = "address not found in file cache "+fn;
      resolutionHistory += msg + "\n";
      MsgLog.log("TSrvEntry.fillinAddressFromFileCache",tag+" "+msg,0,null,0);
    }
    return cc;
  }
  int getAddressFromFileCache(String devName,String srvName,String ctxName)
  {
    String lkupname;
    setAddrFileLocation();
    if (debugLevel > 1) DbgLog.log("getAddressFromFileCache","FILE lookup: looking for \\" + ctxName + "\\" + srvName);
    if (srvName.startsWith("ENS") && numConfiguredNameServers > 0)
    {
      lkupname = currentConfiguredNameServerTag;
    }
    else if (srvName.startsWith("GENS") && numConfiguredNameServers > 0)
    {
      lkupname = "G" + currentConfiguredNameServerTag;
    }
    else
    {
      lkupname = srvName;
    }
    this.srvName = lkupname;
    for (int i=0; i<NameCacheLength; i++)
    {
      if (ctxName.length() > 0 &&
          ctxName.compareToIgnoreCase("DEFAULT") != 0 &&
          ctxName.compareToIgnoreCase(srvNameCache[i].cntName) != 0) continue;
      if (lkupname.compareToIgnoreCase(srvNameCache[i].srvName) == 0)
      {
        eqmName = modNameCache[srvNameCache[i].modNameIndex];
        fecName = fecAddrCache[srvNameCache[i].fecNameIndex].fecName;
        fecAddr = fecAddrCache[srvNameCache[i].fecNameIndex];
        resolutionHistory += "address found in local cache\n";
        return 0;
      }
    }
    // try the dynamic cache
    srvFile = new csv(srvCacheFile);
    dbFilePath = cacheFilePath;
    int cc = fillinAddressFromFileCache(devName,srvName,ctxName);
    if (cc != 0)
    { // not found, try the static cache
      srvFile = new csv(srvR);
      dbFilePath = tineHomePath;
      cc = fillinAddressFromFileCache(devName,srvName,ctxName);
    }
    return cc;
  }
  private static String dbFilePath = null;
  public String[] getGroupMembersFromFileCache(String ctxName,String srvName)
  {
    String grpCacheFile = dbFilePath+"GROUPS"+File.separator+
                   ctxName+File.separator+srvName+".csv";
    csv grpDbFile = new csv(grpCacheFile);
   
    String fn = grpDbFile.getFileName();
    if (fn == null)
      fn = TInitializerFactory.getInstance().getInitializer().getFecHome()+File.separator+"eqpdbase.csv";
    ArrayList<String> lst = new ArrayList<String>();
    try
    {
      String s, hdr;
      int mem_col = -1;
      boolean done = false;
      while((s=grpDbFile.readLine()) != null)
      {
        if (s.length() == 0) continue;
        if (s.startsWith("#") || s.startsWith(";") || s.startsWith("%")) continue;
        if (!done)
        {
          hdr = s;
          if ((mem_col=grpDbFile.findcol(hdr,"MEMBERS")) < 0) throw new NoSuchFieldException();
          done = true;
          continue;
        }
        lst.add(srvFile.colptr(mem_col,s));
      }
    }
    catch (Exception e)
    { // database corrupt or not found
      MsgLog.log("getGroupMembersFromFileCache", e.getMessage(),TErrorList.database_not_loaded,e,1);
      resolutionHistory += "getGroupMembersFromFileCache: "+e.getMessage()+"\n";
    }
    finally
    {
      grpDbFile.close();
    }
    return lst.toArray(new String[0])
  }
  boolean groupFileHasDevice(String ctxName,String memName,String tgtName)
  {
    String grpCacheFile = dbFilePath+"GROUPS"+File.separator+
                   ctxName+File.separator+memName+File.separator+
                   "devices.csv";
    csv grpDbFile = new csv(grpCacheFile);
   
    String fn = grpDbFile.getFileName();
    if (fn == null)
      fn = TInitializerFactory.getInstance().getInitializer().getFecHome()+File.separator+"eqpdbase.csv";
    boolean found = false;
    try
    {
      String s, hdr;
      int dev_col = -1;
      boolean done = false;
      while((s=grpDbFile.readLine()) != null)
      {
        if (s.length() == 0) continue;
        if (s.startsWith("#") || s.startsWith(";") || s.startsWith("%")) continue;
        if (!done)
        {
          hdr = s;
          if ((dev_col=grpDbFile.findcol(hdr,"DEVICES")) < 0) throw new NoSuchFieldException();
          done = true;
          continue;
        }
        if (grpDbFile.namcmp(tgtName,s,dev_col) == 0)
        {
          found = true;
          break;
        }
      }
    }
    catch (Exception e)
    { // database corrupt or not found
      MsgLog.log("groupFileHasDevice", e.getMessage(),TErrorList.database_not_loaded,e,1);
      resolutionHistory += "groupFileHasDevice: "+e.getMessage()+"\n";
    }
    finally
    {
      grpDbFile.close();
    }   
    return found;
  }
  public static void which(String target)
  {
    String res = "";
    try
    {
      String[] parts;
      if (target.startsWith("/"))
      {
        parts = target.split("/");
        if (parts.length > 2)
        {
          TSrvEntry se = new TSrvEntry(parts[2],parts[1]);
          res = se.toString(parts[2],parts[1]);
        }
      }
      else
      {
        if (target.compareToIgnoreCase("ENS") == 0 ||
            target.compareToIgnoreCase("GENS") == 0)
        {
          TSrvEntry se = new TSrvEntry(target,"SITE");
          res = se.toString(target,"SITE");
        }
        else
        {
          TFecEntry fe = TSrvEntry.getFecEntry(target);
          if (fe != null)
          {
            res += "\nIP Address             : " + fe.fecHost.getHostAddress();
            res += "\nPort Offset            : " + fe.fecPortOffset;
            res += "\nHost Name              : " + fe.fecHost.getHostName();
          }
        }
      }
    }
    catch (Exception bail)
    {
      res = "error in supplied argument";
    }
    TLinkFactory.dbgPrint(res);
    return;
  }
  public TSrvEntry(String devName,String srvName,String ctxName)
  {
   // getAddressFromFileCache(devName,srvName,ctxName);
    getAddress(devName,srvName,ctxName);
 
  public TSrvEntry(String srvName,String ctxName)
  {
    getAddress(null,srvName,ctxName);
  }
  public TSrvEntry(TLink lnk)
  {
    getAddress(lnk.devName,lnk.expName,lnk.cntName);
  }
  public boolean isENSCall(String srvName,String ctxName)
  {
    if (srvName == null) return false;
    if (srvName.startsWith("ENS"))
    { // local systematics => context == "DEFAULT" then is an ENS Request
      if (ctxName.compareToIgnoreCase("DEFAULT") == 0) return true;
      if (ctxName.compareToIgnoreCase("SITE") == 0 || ctxName.compareToIgnoreCase("SERVICE") == 0)
      { // must exactly == "ENS"
        if (srvName.compareTo("ENS") == 0) return true;
      }
    }   
    return false;
  }
  private static Object cacheMtx = new Object();
  public void getAddress(String devName,String srvName,String ctxName)
  {
    int i;
    if (srvName == null) return;
    if (ctxName == null) ctxName = "";
    debugLevel = TLinkFactory.debugLevel;
    if (TLinkFactory.debugLevel > 1) DbgLog.log("getAddress","TModAddress() has been called from factory");
    setAddrFileLocation();
   
    if (TLinkFactory.debugLevel > 1) DbgLog.log("getAddress","looking for /" + ctxName + "/" + srvName);

    String lkupname = srvName;
    boolean isENSRequest = isENSCall(srvName,ctxName);
    if (isENSRequest)
    {
      if (numConfiguredNameServers == 0)
      { // if I'm looking for the ENS and it's not configured, add static address to cache
        MsgLog.log("getAddress","add static ENS address",0,null,1);
        StaticAddress(srvName,ctxName);
        if (numConfiguredNameServers != 0)
        {
          resolutionHistory += "ENS address configured statically\n";
        }
        else
        {
          resolutionHistory += "no static ENS entry available\n";
          MsgLog.log("getAddress","no static ENS entry available",0,null,1);
        }
        return;
      }
      lkupname = currentConfiguredNameServerTag;
    }
    boolean isGENSRequest = false;
    if (srvName.compareTo("GENS") == 0 && currentConfiguredNameServerTag != null)
    {
      lkupname = "G" + currentConfiguredNameServerTag;
      if (TLinkFactory.debugLevel > 1) DbgLog.log("getAddress","setting GENS entry to " + lkupname);
      int idx=0;
      if ((idx=lkupname.indexOf('#')) != -1) lkupname = lkupname.substring(0, idx);
      isGENSRequest = true;
    }
    this.srvName = lkupname;
    synchronized(getLinkFactory().ensMutex)
    {
      for (i=0; i<NameCacheLength; i++)
      { // check address cache for requested device server
        if (ctxName.length() > 0 &&
            ctxName.compareToIgnoreCase("DEFAULT") != 0 &&
            ctxName.compareToIgnoreCase(srvNameCache[i].cntName) != 0) continue;
        if (lkupname.compareToIgnoreCase(srvNameCache[i].srvName) == 0)
        { // found an entry in the existing cache
          eqmName = modNameCache[srvNameCache[i].modNameIndex];
          fecName = fecAddrCache[srvNameCache[i].fecNameIndex].fecName;
          if (eqmName.length() == 0 || fecName.length() == 0) continue; // invalid entry ?
          fecAddr = fecAddrCache[srvNameCache[i].fecNameIndex];
          isLegacy = fecAddr.getTineProtocol() < TTransport.DEFAULT_PROTOCOL_LEVEL;
          if (TLinkFactory.debugLevel > 1) DbgLog.log("getAddress","found it in cache");
          resolutionHistory += "address found in cache\n";
          if (isENSRequest) ensDevCacheIndex = i;
          if (isGENSRequest) gensDevCacheIndex = i;
          return;
        }
      }
      if (isENSRequest)
      { // standard ENS request
        i = ensDevCacheIndex == -1 ? 0 : ensDevCacheIndex;
      }
      else if (isGENSRequest)
      { // standard GENS address
        i = gensDevCacheIndex == -1 ? 1 : gensDevCacheIndex;     
      }
      else
      {
        i = -1;
      }
    }
    if (i >= 0)
    { // ENS request made it this far without a hit, so return canonical entry
      eqmName = modNameCache[srvNameCache[i].modNameIndex];
      fecName = fecAddrCache[srvNameCache[i].fecNameIndex].fecName;
      fecAddr = fecAddrCache[srvNameCache[i].fecNameIndex];
      resolutionHistory += "standard ENS address\n";
      return;     
    }
    synchronized (cacheMtx)
    { // if an ENS address request is underway, wait for it ...
      if (srvName.compareTo(SRVEXP_NAME) == 0)
      { // asking the NETWORK for the address
        if (NameCacheLength < CACHE_TABLE_LENGTH && modNameCacheLength < CACHE_TABLE_LENGTH && fecAddrCacheLength < CACHE_TABLE_LENGTH)
        { // add to cache ...
          SrvAddr srv = new SrvAddr();
          srv.ipAddr = getLinkFactory().getInitializer().getNetCastAddress();
          srv.portOffset = 0;
          srv.tineProtocol = TTransport.DEFAULT_PROTOCOL_LEVEL;
          srv.fecName = SRVFEC_NAME; srv.eqmContext = "";
          srv.eqmName = SRVEQM_NAME; srv.expName = SRVEXP_NAME;
          fecAddrCache[fecAddrCacheLength] = new TFecEntry(srv);
          modNameCache[modNameCacheLength] = SRVEQM_NAME;
          srvNameCache[NameCacheLength] = new NameCache();
          srvNameCache[NameCacheLength].cntName = "";
          srvNameCache[NameCacheLength].srvName = SRVEXP_NAME;
          srvNameCache[NameCacheLength].modNameIndex = modNameCacheLength;
          srvNameCache[NameCacheLength].fecNameIndex = fecAddrCacheLength;
          fecAddr = fecAddrCache[fecAddrCacheLength];
          fecName = fecAddrCache[fecAddrCacheLength].fecName;
          eqmName = SRVEQM_NAME;
          NameCacheLength++; modNameCacheLength++; fecAddrCacheLength++;
          resolutionHistory += "adding NETWORK to the address cache\n";
        }
        return;
      }
      if (numConfiguredNameServers == 0)
      {
        MsgLog.log("getAddress","No configured ENS",TErrorList.configuration_error,null,1);
        resolutionHistory += "No configured ENS\n";
      }
      synchronized (fecAddrCache)
      {
        if (numConfiguredNameServers == 0 || // no configured ENS
            getAddressFromENS(srvName,ctxName) != 0) // the ENS didn't have the address
        { // try the cache system (now 'devName' is important)
          getAddressFromFileCache(devName,srvName,ctxName);
        }
        if (eqmName == null)
        { // address unknown
          if (getLinkFactory().allowNeworkAddressResolution())
          { // -> one last chance to acquire the address
            FECAddr fec = new FECAddr();
            SrvAddr srv = new SrvAddr();
            if (findServerOnNetwork(ctxName, "", srvName, fec, srv) == 0)
            {
              resolutionHistory += "address acquired from NETWORK\n";
              if (addAddressToCache(srvName,ctxName,srv) == 0) return;
            }
            MsgLog.log("getAddress","No address available from network",TErrorList.address_unresolved,null,1);
          }
          String tag = makeMsgTag(srvName, ctxName);
          resolutionHistory += "address is unresolved\n";
          MsgLog.log("TSrvEntry.getAddress",tag+" address is unresolved",TErrorList.host_not_resolved,null,0);
          if (srvName.compareToIgnoreCase("GLOBALS") == 0)
          { // address unknown but pin the equipment module name
            MsgLog.log("getAddress", "globals server address for "+ctxName+" unresolved",TErrorList.address_unresolved,null,0);
            return;
          }
        }
      }
    }
  }
  private static boolean legacyEns = false;
  public static boolean isLegacyEns() { return legacyEns; }
  public static void setLegacyEns(boolean value) { legacyEns = value; }
  private static int lastENScc = TErrorList.not_initialized;
  public static synchronized SrvAddr getSrvAddrFromENS(String dname,String cname)
  {
    synchronized (cacheMtx)
    { // don't go looking for an address at the same time we're scanning thru the cache for it.
      if (numConfiguredNameServers == 0 ||
          currentConfiguredNameServerTag == null) return null;
      String tagName;
      int cc = TErrorList.connection_timeout;
      tagName = new String(currentConfiguredNameServerTag + "/");
      tagName = cname.length() > 0 ? tagName.concat(cname) : tagName.concat("#2");
      SrvAddr srv = new SrvAddr();
      TDataType d_null = new TDataType();
      TDataType d_srv = new TDataType(srv.toByteArray(legacyEns),"");
      synchronized(getLinkFactory().ensMutex)
      {
        TLink ma = getLinkFactory().simpleLink(tagName,dname,d_srv,d_null,(short)1);
        if (ma == null)
        {
          if (TLinkFactory.debugLevel > 1) DbgLog.log("getAddress","cannot create link to ENS");
          return null;         
        }
        ma.cannotNotifyFromWatchdogThread = true;
        for (int i=0; i<2 && cc == TErrorList.connection_timeout; i++)
        { // watchdog thread won't handle the retries, so do it here
          cc = ma.execute(TLink.defaultTimeout,true);
          if (cc == TErrorList.illegal_data_size && !legacyEns)
          {
            legacyEns = true;
            d_srv = new TDataType(srv.toByteArray(legacyEns),"");
            ma = getLinkFactory().simpleLink(tagName,dname,d_srv,d_null,(short)1);
            i = 0;
          }
        }
        ma.close();
      }
      if (cc == TErrorList.link_blacklisted) cc = TErrorList.host_not_resolved;
      lastENScc = cc;
      if (cc == 0)
      {
        srv.toStruct(legacyEns);
        if (srv.tineProtocol == 0) srv.tineProtocol = TTransport.DEFAULT_PROTOCOL_LEVEL;
        return srv;
      }
      MsgLog.log("getAddress","link to ENS "+currentConfiguredNameServer+" : "+TErrorList.toString(cc),cc,null,1);
      return null;         
    }
  }
  private int addAddressToCache(String srvName, String ctxName, SrvAddr srv)
  {
    if (srv == null)return TErrorList.argument_list_error;
    int mod_idx, fec_idx;
    boolean augmentModNameCacheLength = false;
    boolean augmentNameCacheLength = false;
    boolean replaceAddress = false;
    eqmName = srv.eqmName;
    if (ctxName == null) ctxName = "";
    for (mod_idx=0; mod_idx<modNameCacheLength; mod_idx++)
    { // is it already in the tables ?
      if (eqmName.compareTo(modNameCache[mod_idx]) == 0) break;
    }
    if (mod_idx == modNameCacheLength)
    { // didn't find it
      if (modNameCacheLength >= CACHE_TABLE_LENGTH-1)
      { // and there's no room to grow
        // TODO: recycle some of the older addresses ? (why does an app need to talk to 1000 different servers ?)
        return TErrorList.resources_exhausted;
      }
      augmentModNameCacheLength = true;
    }
    modNameCache[mod_idx] = eqmName;
    fecName = srv.fecName;
    for (fec_idx=0; fec_idx<fecAddrCacheLength; fec_idx++)
    { // is it already in the tables ?
      if (fecName.compareToIgnoreCase(fecAddrCache[fec_idx].fecName) == 0)
      { // found the fec name !
        if (srv.ipAddr.compareTo(fecAddrCache[fec_idx].fecHost.getHostAddress()) != 0)
          replaceAddress = true;
        break;
      }
    }
    if (augmentModNameCacheLength) modNameCacheLength++;
    if (fec_idx == fecAddrCacheLength)
    { // didn't find it
      if (fecAddrCacheLength >= CACHE_TABLE_LENGTH-1)
      { // and there's no room to grow
        // TODO: recycle some of the older addresses ? (why does an app need to talk to 1000 different servers ?)
        return TErrorList.resources_exhausted;
      }
      fecAddrCache[fec_idx] = new TFecEntry(srv);
      fecAddrCacheLength++;
    }
    else if (replaceAddress)
    {
      fecAddrCache[fec_idx] = new TFecEntry(srv);     
    }
    fecAddr = fecAddrCache[fec_idx];

    int srv_idx;
    for (srv_idx=0; srv_idx<NameCacheLength; srv_idx++)
    {
      if (ctxName.length() > 0 && ctxName.compareToIgnoreCase(srvNameCache[srv_idx].cntName) != 0) continue;
      if (srvName.compareToIgnoreCase(srvNameCache[srv_idx].srvName) != 0) continue;
      break;
    }
    if (srv_idx == NameCacheLength)
    { // not found in cache: at end of list
      if (NameCacheLength >= CACHE_TABLE_LENGTH-1) return TErrorList.resources_exhausted;
      srvNameCache[NameCacheLength] = new NameCache();
      augmentNameCacheLength = true;
    }
    srvNameCache[srv_idx].modNameIndex = mod_idx;
    srvNameCache[srv_idx].fecNameIndex = fec_idx;
    srvNameCache[srv_idx].srvName = srvName;
    srvNameCache[srv_idx].cntName = ctxName;
    if (augmentNameCacheLength) NameCacheLength++;
    isLegacy = srv.tineProtocol < TTransport.DEFAULT_PROTOCOL_LEVEL;
   
    addAddressToCacheFile(srv); // add address to local file cache
    if (TLinkFactory.debugLevel > 1) DbgLog.log("getAddress","ENS success");
    return 0;
  }
  private String makeMsgTag(String srvName,String ctxName)
  {
    String tag = "/";
    tag += ctxName == null ? "DEFAULT" : ctxName;
    tag += "/" + srvName;
    return tag;
  }
  public static void toggleENS()
  {
    synchronized(getLinkFactory().ensMutex)
    {
      int pre_toggle_ens = currentConfiguredNameServer;
      currentConfiguredNameServer = (currentConfiguredNameServer+1) % numConfiguredNameServers;
      currentConfiguredNameServerTag = new String("ENS#" + currentConfiguredNameServer);
      MsgLog.log("TSrvEntry.toggleENS", "switch from ENS "+pre_toggle_ens+" to "+currentConfiguredNameServer,0,null,1);
    }
  }
  public static String[] getKnownENSes()
  {
    int i,n=0;
    ArrayList<String> al = new ArrayList<String>();
    for (i=0; i<fecAddrCacheLength; i++)
    {
      if (fecAddrCache[i].fecName.startsWith("ENS#"))
      {
        al.add(fecAddrCache[i].fecHost.getHostAddress());
        if (++n == numConfiguredNameServers) break;
      }
    }
    return al.toArray(new String[0]);
  }
  public synchronized int getAddressFromENS(String srvName,String ctxName)
  {
    if (srvName == null) return TErrorList.argument_list_error;
    if (isENSCall(srvName, ctxName)) return 0;
    if (srvName.compareToIgnoreCase("NETWORK") == 0) return 0;
    if (numConfiguredNameServers == 0) return 0;
    if (getLinkFactory().isRunningStandAlone())
      return TErrorList.not_accepted;
    int n = 0;
    String msg;
    String tag = makeMsgTag(srvName,ctxName);
    do
    {
      SrvAddr srv = getSrvAddrFromENS(srvName,ctxName);
      if (srv != null)
      {
        addAddressToCache(srvName,ctxName,srv);
        msg = "address acquired from ENS#"+currentConfiguredNameServer+" at "+fecAddrCache[ensDevCacheIndex].fecHost.getHostAddress();
        resolutionHistory += msg + "\n";
        MsgLog.log("TSrvEntry.getAddressFromENS",tag+" "+msg,0,null,1);
        return 0;
      }
      msg = "address unknown to ENS#"+currentConfiguredNameServer+" at "+fecAddrCache[ensDevCacheIndex].fecHost.getHostAddress()+
            " : "+TErrorList.getErrorString(lastENScc);
      resolutionHistory += msg + "\n";
      int cc = TErrorList.address_unknown;
      MsgLog.log("TSrvEntry.getAddressFromENS",tag+" "+msg,cc,null,1);
      currentConfiguredNameServer = (currentConfiguredNameServer+1) % numConfiguredNameServers;
      currentConfiguredNameServerTag = new String("ENS#" + currentConfiguredNameServer);
      MsgLog.log("getAddress","toggle to ENS "+currentConfiguredNameServerTag,cc,null,1);
    } while (++n < numConfiguredNameServers);
    if (TLinkFactory.debugLevel > 1) DbgLog.log("getAddress","ens failure");
    return TErrorList.address_unknown;
  }
  private static InetAddress getHostIpv4Addr(String host)
  { // we just want a null or an address (no exception nonsense)
    InetAddress iaddr = null;
    try
    {
      iaddr = java.net.Inet4Address.getByName(host);
    } catch (Exception ignore) {}
    return iaddr;
  }
  private static int findNameServerFromDNS()
  {
    int cc = 0;
    if (numConfiguredNameServers > 0) return 0;
    InetAddress iaddr = getHostIpv4Addr("tineens");
    if (iaddr == null) iaddr = getHostIpv4Addr("tineens1");
    if (iaddr != null)
    { // try up to 3 ENSes ...
      addNameServer(iaddr.getHostAddress());
      if ((iaddr=getHostIpv4Addr("tineens2")) != null)
      {
        addNameServer(iaddr.getHostAddress());
        if ((iaddr=getHostIpv4Addr("tineens3")) != null)
          addNameServer(iaddr.getHostAddress());
      }
    }
    else
    {
      cc = TErrorList.host_not_resolved;
    }
    return cc;
  }
  public static int findNameServerOnNetwork()
  {
    int cc = 0;
    FECAddr fec = new FECAddr();
    SrvAddr srv = new SrvAddr();
    if (numConfiguredNameServers > 0) return 0;
    if ((cc=findServerOnNetwork("", "ENSEQM", "", fec, srv)) == 0)
    {
      addNameServer(fec.strAdr);
    }
    return cc;
  }
  public static int findServerOnNetwork(String context,String eqmName,String exportName,FECAddr fec,SrvAddr srv)
  {
    int p=0,cc=0;
    NAME16[] n16in = new NAME16[3];
    NAME16[] n16out = new NAME16[5];
   
    n16in[0] = new NAME16(context);
    n16in[1] = new NAME16(eqmName);
    n16in[2] = new NAME16(exportName);
   
    TDataType dout = new TDataType(n16out);
    TDataType din = new TDataType(n16in);

    TLink tl = new TLink(SRVEXP_NAME,"SRVADDR",dout,din,TAccess.CA_READ);
    cc = tl.execute(TLink.defaultTimeout, true);
    if (cc == 0)
    {
      if (fec != null)
      {
        p = Integer.valueOf(n16out[0].getName());
        fec.fecName = n16out[1].getName();
        fec.portOffset = p;
        byte[] bAdr = tl.linkPeer.getAddress();
        int len = bAdr.length; if (len > 16) len = 16;
        System.arraycopy(bAdr, 0, fec.netAdr, 0, len);
        fec.strAdr = tl.linkPeer.getHostAddress();
      }
      if (srv != null)
      {
        srv.fecName = n16out[1].getName();
        srv.eqmContext = n16out[2].getName();
        srv.eqmName = n16out[3].getName();
        srv.expName = n16out[4].getName();
        srv.tineProtocol = TTransport.DEFAULT_PROTOCOL_LEVEL;
        srv.ipAddr = tl.linkPeer.getHostAddress();
        if (fec == null) p = Integer.valueOf(n16out[0].getName());
        srv.portOffset = p;
      }
    }
    return cc;
  }
  public TFecEntry getFecAddr()
  {
    return fecAddr;
  }
  public String getContextName()
  {
    return cntName;
  }
  public String getDeviceName()
  {
    return srvName;
  }
  public String getEqmName()
  {
    return eqmName;
  }
  public String getFecName()
  {
    return fecName;
  }
}
TOP

Related Classes of de.desy.tine.addrUtils.TSrvEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.