/**
   * Class constructor
   *
   * @param config ServerConfiguration
   */
  public PortMapperServer(ServerConfiguration config) {
    super("Portmap", config);

    //	Set the server version

    setVersion(ServerVersion);

    //  Get the NFS configuration

    m_nfsConfig = (NFSConfigSection) config.getConfigSection(NFSConfigSection.SectionName);

    if (m_nfsConfig != null) {

      //	Enable/disable debug output

      setDebug(getNFSConfiguration().hasPortMapperDebug());

      //	Set the port to use

      if (getNFSConfiguration().getPortMapperPort() != 0)
        setPort(getNFSConfiguration().getPortMapperPort());
      else setPort(DefaultPort);

      //	Create the mappings tables

      m_mappings = new Hashtable<Integer, PortMapping>();
      m_noVerMappings = new Hashtable<Integer, PortMapping>();
    } else setEnabled(false);
  }
  /** Thread method */
  public void run() {

    // Clear the shutdown flag

    m_shutdown = false;

    // If Winsock NetBIOS is not enabled then initialize the sockets interface

    ServerConfiguration config = m_server.getConfiguration();
    CIFSConfigSection cifsConfig =
        (CIFSConfigSection) config.getConfigSection(CIFSConfigSection.SectionName);

    if (cifsConfig.useWinsockNetBIOS() == false) {

      try {
        NetBIOSSocket.initializeSockets();
      } catch (WinsockNetBIOSException ex) {

        // DEBUG

        if (Debug.EnableError && hasDebug()) {
          Debug.println("[SMB] Win32 NetBIOS initialization error");
          Debug.println(ex);
        }

        // Shutdown the LANA monitor thread

        m_shutdown = true;
      }
    }

    // Loop until shutdown

    BitSet curLanas = new BitSet();

    while (m_shutdown == false) {

      // Wait for a network address change event

      Win32NetBIOS.waitForNetworkAddressChange();

      // Check if the monitor has been closed

      if (m_shutdown == true) continue;

      // Clear the current active LANA bit set

      curLanas.clear();

      // Get the available LANA list

      int[] lanas = Win32NetBIOS.LanaEnumerate();
      if (lanas != null) {

        // Check if there are any new LANAs available

        Win32NetBIOSSessionSocketHandler sessHandler = null;

        for (int i = 0; i < lanas.length; i++) {

          // Get the current LANA id, check if it's a known LANA

          int lana = lanas[i];
          curLanas.set(lana, true);

          if (m_lanas.get(lana) == false) {

            // DEBUG

            if (Debug.EnableInfo && hasDebug())
              Debug.println("[SMB] Win32 NetBIOS found new LANA, " + lana);

            // Create a single Win32 NetBIOS session handler using the specified LANA

            sessHandler = new Win32NetBIOSSessionSocketHandler(m_server, lana, hasDebug());

            try {
              sessHandler.initializeSessionHandler(m_server);
            } catch (Exception ex) {

              // DEBUG

              if (Debug.EnableError && hasDebug()) {
                Debug.println(
                    "[SMB] Win32 NetBIOS failed to create session handler for LANA " + lana);
                Debug.println(ex);
              }

              // Clear the session handler

              sessHandler = null;
            }

            // If the session handler was initialized successfully add it to the
            // SMB/CIFS server

            if (sessHandler != null) {

              // Add the session handler to the SMB/CIFS server

              //							m_server.addSessionHandler(sessHandler);

              // Run the NetBIOS session handler in a seperate thread

              Thread nbThread = new Thread(sessHandler);
              nbThread.setName("Win32NB_Handler_" + lana);
              nbThread.start();

              // DEBUG

              if (Debug.EnableInfo && hasDebug())
                Debug.println("[SMB] Win32 NetBIOS created session handler on LANA " + lana);

              // Check if a host announcer should be enabled

              if (cifsConfig.hasWin32EnableAnnouncer()) {

                // Create a host announcer

                Win32NetBIOSHostAnnouncer hostAnnouncer =
                    new Win32NetBIOSHostAnnouncer(
                        sessHandler,
                        cifsConfig.getDomainName(),
                        cifsConfig.getWin32HostAnnounceInterval());

                // Add the host announcer to the SMB/CIFS server list

                addHostAnnouncer(hostAnnouncer);
                hostAnnouncer.start();

                // DEBUG

                if (Debug.EnableInfo && hasDebug())
                  Debug.println("[SMB] Win32 NetBIOS host announcer enabled on LANA " + lana);
              }

              // Set the LANA in the available LANA list, and set the current status
              // to online

              m_lanas.set(lana);
              m_lanaSts.set(lana, true);
            }
          } else {

            // Check if the LANA has just come back online

            if (m_lanaSts.get(lana) == false) {

              // Change the LANA status to indicate the LANA is back online

              m_lanaSts.set(lana, true);

              // Inform the listener that the LANA is back online

              if (m_listeners != null && lana < m_listeners.length && m_listeners[lana] != null)
                m_listeners[lana].lanaStatusChange(lana, true);

              // DEBUG

              if (Debug.EnableError && hasDebug())
                Debug.println("[SMB] Win32 NetBIOS LANA online - " + lana);
            }
          }
        }

        // Check if there are any LANAs that have gone offline

        for (int i = 0; i < m_lanaSts.length(); i++) {

          if (curLanas.get(i) == false && m_lanaSts.get(i) == true) {

            // DEBUG

            if (Debug.EnableError && hasDebug())
              Debug.println("[SMB] Win32 NetBIOS LANA offline - " + i);

            // Change the LANA status

            m_lanaSts.set(i, false);

            // Check if there is an associated listener for the LANA

            if (m_listeners != null && m_listeners[i] != null) {

              // Notify the LANA listener that the LANA is now offline

              m_listeners[i].lanaStatusChange(i, false);
            }
          }
        }
      } else if (m_lanaSts.length() == 0) {

        // No network devices, sleep for a while as waitForNetworkAddressChange() does not
        // wait
        // if there are no network devices

        try {
          Thread.sleep(10000);
        } catch (InterruptedException e) {
        }
      }
    }
  }