/*****************************************************************************/
/* File name: Mount.java                                                     */
/* Purpose: to provide NFS mount service                                     */
/*                                                                           */
/* Last modified: 15.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*                                                                           */
/* 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.                                          */
/*                                                                           */
/* This software is distributed under the terms                              */
/* of the GNU General Public License as published                            */
/* by the Free Software Foundation; either version 2, or (at your option)    */
/* any later version.                                                        */
/* See file COPYING for your rights (GNU GPL)                                */
/*****************************************************************************/

package mount;


import java.net.*;
import java.io.*;
import java.util.*;
import rpc.*;
import io.*;
import xdr.*;


public
class

Mount
        extends rpc.RegistrationServer
                                        implements Runnable
{

  private final static String RCSID =
"$Header: /d/NFS/mount/RCS/Mount.java,v 1.24 1999/08/15 23:39:01 vklimov Exp $";


  protected Registry registry = null;
  protected Registry exportedFileSystemsRegistry = null;


  public

  Mount( java.lang.String propertiesFilePath,
         Registry exportedFileSystemsRegistry )

                                         throws  SocketException
/*****************************************************************************/
/* Function name: Mount                                                      */
/* File name: Mount.java                                                     */
/* Purpose: constructor for the Mount class                                  */
/* Throws: SocketException                                                   */
/* Parameters: propertiesFilePath                                            */
/*             exportedFileSystemsRegistry                                   */
/* Returns:                                                                  */
/* Last modified: 15.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {

      super( Constants.MOUNT_PORT,
             propertiesFilePath    );

      int i;
      int nEntries;
      int nFileHandles;
                                                             /* Mount */
/*---------------------------------------------------------------------------*/

      this.exportedFileSystemsRegistry = exportedFileSystemsRegistry;

      registry = Registry.restore();

      if (registry == null)
        registry = new Registry( cacheDir );
      else
        {
          System.out.println( "restored registry !" );

          nEntries = registry.size();
          nFileHandles = registry.nFileHandles();

          System.out.println( "registry contains now " +
                              nEntries + " mount entries" +
                              "\nand " + nFileHandles +
                              " files (fileIds)"             );

          System.out.println( "registry: \n" +
                              registry.toString()  );

        }
    /*end of if on registry*/

    }
/*end of Mount*/


  public
  void

  sendMountErrorReplyRPCReplyMessage(
    ParserResponderReturnArguments
      parserResponderReturnArguments,
    int unixErrorNumber                 )
/*****************************************************************************/
/* Function name: sendMountErrorReplyRPCReplyMessage                         */
/* File name: Mount.java                                                     */
/* Purpose: to send RPC reply message: there was an error in mounting        */
/* Parameters: parserResponderReturnArguments                                */
/*             unixErrorNumber                                               */
/* Returns:                                                                  */
/* Last modified: 30.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      byte[] ibuf = null;
      InetAddress ipAddressWhereToSend = null;
      int portToSendTo = 0;
      DatagramPacket udpPacket = null;
      Message rpcMessage = null;

                                  /* sendMountErrorReplyRPCReplyMessage */
/*---------------------------------------------------------------------------*/

      rpcMessage =
        createRPCMessageAndPutSuccessPrefix(
          Constants.
            MOUNTPROC_MNT_ERR_UDP_PACKET_DATA_LENGTH,
          parserResponderReturnArguments       );

      ibuf = rpcMessage.getData();

      rpcMessage.
        putUnsignedInteger( (long) unixErrorNumber );

      ipAddressWhereToSend =
        parserResponderReturnArguments.
          inRPCMessage.getInetAddress();
      portToSendTo =
        parserResponderReturnArguments.
          inRPCMessage.getPort();

      udpPacket = new
        DatagramPacket( ibuf, ibuf.length,
                        ipAddressWhereToSend,
                        portToSendTo          );

      try
        {
          udpSocket.send( udpPacket,
                          parserResponderReturnArguments.transactionId,
                          "sendMountErrorReplyRPCReplyMessage"          );
        }
      catch( IOException e )
        {
          System.out.println(
            "sendMountErrorReplyRPCReplyMessage: " +
            "IOException in sending reply\n" +
            e.getMessage()                              );
        }
    /*end of try-catch*/

    }
/*end of sendMountErrorReplyRPCReplyMessage*/


  public
  void

  addMountEntryAndSendRPCReplyMessage(
    ParserResponderReturnArguments
      parserResponderReturnArguments   )
/*****************************************************************************/
/* Function name: addMountEntryAndSendRPCReplyMessage                        */
/* File name: Mount.java                                                     */
/* Purpose: to add a mount entry to a client's mount list                    */
/*          RPC reply message - send filehandle if mounted  OK               */
/*                              otherwise send UNIX error code in fhstatus   */
/* Parameters: parserResponderReturnArguments                                */
/* Returns:                                                                  */
/* Last modified: 10.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      boolean filableInstanceSet;
      long fileId;
      Fhandle fhandle;
      Entry mountEntry;
      Class dirFileClass = null;
      FileSystemable fileSystem = null;
      String dirPath;
      boolean registeredOK;
      byte[] ibuf = null;
      InetAddress ipAddressWhereToSend = null;
      int portToSendTo = 0;
      DatagramPacket udpPacket = null;
      Message rpcMessage = null;
      String hostName = null;
      Message rpcMessageWithParametersToRemoteProcedure = null;

                                    /* addMountEntryAndSendRPCReplyMessage */
/*---------------------------------------------------------------------------*/

      ipAddressWhereToSend =
        parserResponderReturnArguments.
          inRPCMessage.getInetAddress();

      rpcMessageWithParametersToRemoteProcedure = new
        Message(
          parserResponderReturnArguments.
            byteArrayContainingParametersToRemoteProcedure );

      dirPath =
        rpcMessageWithParametersToRemoteProcedure.getString();

      fhandle = exportedFileSystemsRegistry.get( dirPath );

      if (fhandle == null)
        {
          sendMountErrorReplyRPCReplyMessage(
            parserResponderReturnArguments,
            Constants.MNT_ERR_ENOENT           );
          return;                                          /* return ! */
        }
      else
        {
          if ( (logTransactions) &&
               (log != null)
             )
            {
              log.write( 
                "Mount, addMountEntryAndSendRPCReplyMessage\n" +
                "transaction ID=" +
                parserResponderReturnArguments.
                  transactionId +
                " dirPath=" + dirPath +
                "\nfhandle.fileId=" +
                fhandle.getFileId() +
                " fhandle.dirPath=" +
                fhandle.getDirPath()  +
                " fhandle.name=" +
                fhandle.getName()    );
            }
          else
            ;
        /*end of if on logTransactions*/
        }
    /*end of if on fhandle eq null*/

      fileSystem = fhandle.getFileSystem();

      if (fileSystem == null)
        {
          sendMountErrorReplyRPCReplyMessage(
            parserResponderReturnArguments,
            Constants.MNT_ERR_ENOENT           );
          return;                                          /* return ! */
        }
      else
        {
        }
    /*end of if*/

      dirFileClass = fileSystem.getFileClass();

      if (dirFileClass == null)
        {
          sendMountErrorReplyRPCReplyMessage(
            parserResponderReturnArguments,
            Constants.MNT_ERR_ENOENT           );
          return;                                          /* return ! */
        }
      else
        {
        }
    /*end of if*/

      hostName =
        ipAddressWhereToSend.getHostName();

      if (hostName == null)
        hostName = general.Constants.LOCAL_HOST_DESIGNATION;
      else
        ;
    /*end of if*/

      mountEntry =
        registry.get( dirPath, hostName );

      if (mountEntry == null)                          /* register anew */
        {
          fileId = registry.getUniqueFileId();

          if (fileId == Constants.FILE_ID_NOT_VALID)
            {
              sendMountErrorReplyRPCReplyMessage(
                parserResponderReturnArguments,
                Constants.MNT_ERR_EMFILE           );
              return;                                          /* return ! */
            }
          else
            {
            }
        /*end of if*/

          fhandle = new Fhandle( fileId,
                                 hostName,
                                 dirPath,
                                 fileSystem );
          filableInstanceSet =
            fhandle.setFilableInstance();

          if ( ! filableInstanceSet )
            {
              sendMountErrorReplyRPCReplyMessage(
                parserResponderReturnArguments,
                Constants.MNT_ERR_EMFILE           );
              return;                                          /* return ! */
            }
          else
            {
             FileSystemExpert.setFileHandle( fhandle );
            }
        /*end of if*/

          mountEntry = new Entry( fhandle );

          registeredOK =
            registry.put( mountEntry );

          if ( ! registeredOK )
            {
              sendMountErrorReplyRPCReplyMessage(
                parserResponderReturnArguments,
                Constants.MNT_ERR_ENFILE          );
              return;                                          /* return ! */
            }
          else
            registry.save();
        /*end of if*/

        }
      else /* we have it already */
        {
          fhandle = mountEntry.getFileHandle();
        }
    /*end of if on mountEntry*/

      rpcMessage =
        createRPCMessageAndPutSuccessPrefix(
          Constants.
            MOUNTPROC_MNT_REPLY_UDP_PACKET_DATA_LENGTH,
          parserResponderReturnArguments       );

      ibuf = rpcMessage.getData();

      rpcMessage.
        putUnsignedInteger( (long) Constants.FHSTATUS_OK );

      fhandle.putItselfIntoRPCMessage(
        rpcMessage               );

      if ( (logTransactions) &&
           (log != null)
         )
        {
          log.write( 
            "Mount, addMountEntryAndSendRPCReplyMessage\n" +
            "transaction ID=" +
            parserResponderReturnArguments.
              transactionId +
            " going to send fhandle.fileId=" +
            fhandle.getFileId()                               );
        }
      else
        ;
    /*end of if on logTransactions*/

      portToSendTo =
        parserResponderReturnArguments.
          inRPCMessage.getPort();

      udpPacket = new
        DatagramPacket( ibuf, ibuf.length,
                        ipAddressWhereToSend,
                        portToSendTo          );

      try
        {
          udpSocket.send( udpPacket,
                          parserResponderReturnArguments.transactionId,
                          "addMountEntryAndSendRPCReplyMessage"         );
        }
      catch( IOException e )
        {
          System.out.println(
            "Mount, " +
            "addMountEntryAndSendRPCReplyMessage: " +
            "IOException in sending reply\n" +
            e.getMessage()                              );
        }
    /*end of try-catch*/

    }
/*end of addMountEntryAndSendRPCReplyMessage*/


  public
  void

  sendUnmountReplyRPCReplyMessage(
    ParserResponderReturnArguments
      parserResponderReturnArguments )
/*****************************************************************************/
/* Function name: sendUnmountReplyRPCReplyMessage                            */
/* File name: Mount.java                                                     */
/* Purpose: to send a message on umount                                      */
/* Parameters: parserResponderReturnArguments                                */
/* Returns:                                                                  */
/* Last modified: 30.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      byte[] ibuf = null;
      InetAddress ipAddressWhereToSend = null;
      int portToSendTo = 0;
      DatagramPacket udpPacket = null;
      Message rpcMessage = null;

                                        /* sendUnmountReplyRPCReplyMessage */
/*---------------------------------------------------------------------------*/

      rpcMessage =
        createRPCMessageAndPutSuccessPrefix(
          Constants.
            MOUNTPROC_MNT_ERR_UDP_PACKET_DATA_LENGTH,
          parserResponderReturnArguments       );

      ibuf = rpcMessage.getData();

      ipAddressWhereToSend =
        parserResponderReturnArguments.
          inRPCMessage.getInetAddress();
      portToSendTo =
        parserResponderReturnArguments.
          inRPCMessage.getPort();

      udpPacket = new
        DatagramPacket( ibuf, ibuf.length,
                        ipAddressWhereToSend,
                        portToSendTo          );

      try
        {
          udpSocket.send( udpPacket,
                          parserResponderReturnArguments.transactionId,
                          "sendUnmountReplyRPCReplyMessage"             );
        }
      catch( IOException e )
        {
          System.out.println(
            "Mount, " +
            "sendUnmountReplyRPCReplyMessage: " +
            "IOException in sending reply\n" +
            e.getMessage()                              );
        }
    /*end of try-catch*/

    }
/*end of sendUnmountReplyRPCReplyMessage*/


  public
  void

  removeMountEntryAndSendRPCReplyMessage(
    ParserResponderReturnArguments
      parserResponderReturnArguments      )
/*****************************************************************************/
/* Function name: removeMountEntryAndSendRPCReplyMessage                     */
/* File name: Mount.java                                                     */
/* Purpose: to remove mount entry for a directory - host name pair           */
/*          from the mount list                                              */
/* Parameters: parserResponderReturnArguments                                */
/* Returns:                                                                  */
/* Last modified: 01.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      String dirPath = null;
      String hostName = null;
      boolean unmountedOK;
      InetAddress ipAddressWhereToSend = null;
      Entry mountEntry = null;
      Message rpcMessageWithParametersToRemoteProcedure = null;

                               /* removeMountEntryAndSendRPCReplyMessage */
/*---------------------------------------------------------------------------*/

      rpcMessageWithParametersToRemoteProcedure = new
        Message(
          parserResponderReturnArguments.
            byteArrayContainingParametersToRemoteProcedure );

      dirPath =
        rpcMessageWithParametersToRemoteProcedure.getString();

      if ( (logTransactions) &&
           (log != null)
         )
        {
          log.write( 
            "Mount, removeMountEntryAndSendRPCReplyMessage\n" +
            "transaction ID=" +
            parserResponderReturnArguments.
              transactionId +
            " dirPath=" + dirPath                              );
        }
      else
        ;
    /*end of if*/

      if (dirPath == null)
        {
          sendUnmountReplyRPCReplyMessage(
            parserResponderReturnArguments  );
          return;                                          /* return ! */
        }
      else
        ;
    /*end of if*/

      ipAddressWhereToSend =
        parserResponderReturnArguments.
          inRPCMessage.getInetAddress();

      hostName =
        ipAddressWhereToSend.getHostName();

      if (hostName == null)
        hostName = general.Constants.LOCAL_HOST_DESIGNATION;
      else
        ;
    /*end of if*/

      mountEntry =
        registry.get( dirPath, hostName );

      if (mountEntry == null)                          /* register anew */
        {
        }
      else
        {
          unmountedOK =
            registry.remove( mountEntry );

          if (unmountedOK)
            registry.save();
          else
            ;
        /*end of if on unmountedOK*/

        }
    /*end of if on null*/

      sendUnmountReplyRPCReplyMessage(
        parserResponderReturnArguments  );

    }
/*end of removeMountEntryAndSendRPCReplyMessage*/


  public
  void

  removeAllMountEntriesAndSendRPCReplyMessage(
    ParserResponderReturnArguments
      parserResponderReturnArguments           )
/*****************************************************************************/
/* Function name: removeAllMountEntriesAndSendRPCReplyMessage                */
/* File name: Mount.java                                                     */
/* Purpose: to remove all mount list entries for this client                 */
/* Parameters: parserResponderReturnArguments                                */
/* Returns:                                                                  */
/* Last modified: 15.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      byte[] ibuf = null;
      InetAddress ipAddressWhereToSend = null;
      int portToSendTo = 0;
      DatagramPacket udpPacket = null;
      Message rpcMessage = null;

                           /* removeAllMountEntriesAndSendRPCReplyMessage */
/*---------------------------------------------------------------------------*/

      if ( (logTransactions) &&
           (log != null)
         )
        {
          log.write( 
            "Mount, removeAllMountEntriesAndSendRPCReplyMessage\n" +
            "transaction ID=" +
            parserResponderReturnArguments.
              transactionId                                          );
        }
      else
        ;
    /*end of if*/

      FileSystemExpert.processAllUnmount( cacheDir );
      registry.clear();
      registry.save();

      rpcMessage =
        createRPCMessageAndPutSuccessPrefix(
          rpc.Constants.
            PROC_NULL_UDP_PACKET_DATA_LENGTH,
          parserResponderReturnArguments       );

      ibuf = rpcMessage.getData();

      ipAddressWhereToSend =
        parserResponderReturnArguments.
          inRPCMessage.getInetAddress();
      portToSendTo =
        parserResponderReturnArguments.
          inRPCMessage.getPort();

      udpPacket = new
        DatagramPacket( ibuf, ibuf.length,
                        ipAddressWhereToSend,
                        portToSendTo          );

      try
        {
          udpSocket.send( udpPacket,
                          parserResponderReturnArguments.transactionId,
                          "removeAllMountEntriesAndSendRPCReplyMessage" );
        }
      catch( IOException e )
        {
          System.out.println(
            "Mount, " +
            "removeAllMountEntriesAndSendRPCReplyMessage: " +
            "IOException in sending reply\n" +
            e.getMessage()                              );
        }
    /*end of try-catch*/

    }
/*end of removeAllMountEntriesAndSendRPCReplyMessage*/


  public
  void

  dumpExportListAndSendRPCReplyMessage(
    ParserResponderReturnArguments
      parserResponderReturnArguments )
/*****************************************************************************/
/* Function name: dumpExportListAndSendRPCReplyMessage                       */
/* File name: Mount.java                                                     */
/* Purpose: to dump entries of the export list                               */
/* Parameters: parserResponderReturnArguments                                */
/* Returns:                                                                  */
/* Last modified: 01.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      byte[] ibuf = null;
      InetAddress ipAddressWhereToSend = null;
      int portToSendTo = 0;
      DatagramPacket udpPacket = null;
      Message rpcMessage = null;
      Message rpcMessageWithParametersToRemoteProcedure = null;
      int nBytesForMountEntries;
      String groupName = null;
      String dirPath = null;

                                   /* dumpExportListAndSendRPCReplyMessage */
/*---------------------------------------------------------------------------*/

      if ( (logTransactions) &&
           (log != null)
         )
        {
          log.write( 
            "Mount, dumpExportListAndSendRPCReplyMessage\n" +
            "transaction ID=" +
            parserResponderReturnArguments.
              transactionId                                   );
        }
      else
        ;
    /*end of if*/

      nBytesForMountEntries =
        Constants.N_BYTES_PER_MOUNT_ENTRY      +
        Constants.N_BYTES_PER_NULL_MOUNT_ENTRY;

      rpcMessage =
        createRPCMessageAndPutSuccessPrefix(
          Constants.
            MOUNTPROC_DUMP_UDP_DATA_PREFIX_LENGTH +
          nBytesForMountEntries,
          parserResponderReturnArguments       );

      ibuf = rpcMessage.getData();

      try
        {
          groupName = Constants.ALL_THE_WORLD_GROUP_NAME;
          dirPath = Constants.ALL_FILESYSTEMS_DIR_PATH;

          rpcMessage.
            putString( dirPath,
                       Constants.MNTPATHLEN );
          rpcMessage.
            putString( groupName,
                       Constants.MNTNAMLEN );

          groupName = "";
          dirPath = "";

          rpcMessage.
            putString( groupName,
                       Constants.MNTNAMLEN );
          rpcMessage.
            putString( dirPath,
                       Constants.MNTPATHLEN );

        }
      catch( ArrayIndexOutOfBoundsException e )
        {
          System.out.println(
            "dumpExportListAndSendRPCReplyMessage:\n" +
            "putString - a string is too long!" );
          e.printStackTrace( System.out );
          return;                                      /* return ! */
        }
      catch( ArrayStoreException e )
        {
          System.out.println(
            "dumpExportListAndSendRPCReplyMessage:\n" +
            "putString!" +
          "\n" + e.getMessage() );
          e.printStackTrace( System.out );
          return;                                      /* return ! */
        }
    /*end of try-catch*/

      ipAddressWhereToSend =
        parserResponderReturnArguments.
          inRPCMessage.getInetAddress();
      portToSendTo =
        parserResponderReturnArguments.
          inRPCMessage.getPort();

      udpPacket = new
        DatagramPacket( ibuf, ibuf.length,
                        ipAddressWhereToSend,
                        portToSendTo          );

      try
        {
          udpSocket.send( udpPacket,
                          parserResponderReturnArguments.transactionId,
                          "dumpExportListAndSendRPCReplyMessage"        );
        }
      catch( IOException e )
        {
          System.out.println(
            "Mount, " +
            "dumpExportListAndSendRPCReplyMessage: " +
            "IOException in sending reply\n" +
            e.getMessage()                              );
        }
    /*end of try-catch*/



    }
/*end of dumpExportListAndSendRPCReplyMessage*/


  public
  void

  dumpMountEntriesAndSendRPCReplyMessage(
    ParserResponderReturnArguments
      parserResponderReturnArguments )
/*****************************************************************************/
/* Function name: dumpMountEntriesAndSendRPCReplyMessage                     */
/* File name: Mount.java                                                     */
/* Purpose: to dump list of remote mounted filesystems                       */
/* Parameters: parserResponderReturnArguments                                */
/* Returns:                                                                  */
/* Last modified: 01.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      int i;
      boolean continueToLoopOnMountEntries = true;
      byte[] ibuf = null;
      InetAddress ipAddressWhereToSend = null;
      int portToSendTo = 0;
      DatagramPacket udpPacket = null;
      Message rpcMessage = null;
      Entry mountEntry = null;
      Message rpcMessageWithParametersToRemoteProcedure = null;
      int nBytesForMountEntries;
      String hostName = null;
      String dirPath = null;
      Enumeration mountEntries;
      int nEntriesInRegistry;
      int nEntriesToSendMax;
      int nEntriesToSend;

                                /* dumpMountEntriesAndSendRPCReplyMessage */
/*---------------------------------------------------------------------------*/

      if ( (logTransactions) &&
           (log != null)
         )
        {
          log.write( 
            "Mount, dumpMountEntriesAndSendRPCReplyMessage\n" +
            "transaction ID=" +
            parserResponderReturnArguments.
              transactionId                                       );
        }
      else
        ;
    /*end of if*/

      nEntriesInRegistry = registry.size();

      nEntriesToSendMax = Constants.N_ENTRIES_MAX_DUMP_TO_SEND;

      if (nEntriesInRegistry >
          nEntriesToSendMax   )
        nEntriesToSend = nEntriesToSendMax;
      else
        nEntriesToSend = nEntriesInRegistry;
    /*end of if*/

      nBytesForMountEntries =
        (Constants.N_BYTES_PER_MOUNT_ENTRY *
         nEntriesToSend                       ) +
        Constants.N_BYTES_PER_NULL_MOUNT_ENTRY;

      rpcMessage =
        createRPCMessageAndPutSuccessPrefix(
          Constants.
            MOUNTPROC_DUMP_UDP_DATA_PREFIX_LENGTH +
          nBytesForMountEntries,
          parserResponderReturnArguments       );

      ibuf = rpcMessage.getData();

      mountEntries =
        registry.mountEntries();

      i = 0;
      while( (i < nEntriesToSend) &&
             continueToLoopOnMountEntries &&
             mountEntries.hasMoreElements()  )
        {
          try
            {
              mountEntry = (Entry) mountEntries.nextElement();

              hostName =
                mountEntry.getHostName();
              dirPath =
                mountEntry.getDirPath();

              rpcMessage.
                putString( hostName,
                           Constants.MNTNAMLEN );
              rpcMessage.
                putString( dirPath,
                           Constants.MNTPATHLEN );
            }
          catch( ArrayIndexOutOfBoundsException e )
            {
              System.out.println(
                "dumpMountEntriesAndSendRPCReplyMessage:\n" +
                "putString - a string is too long!" );
              e.printStackTrace( System.out );
              return;                                      /* return ! */
            }
          catch( ArrayStoreException e )
            {
              System.out.println(
                "dumpMountEntriesAndSendRPCReplyMessage:\n" +
                "putString!" +
              "\n" + e.getMessage() );
              e.printStackTrace( System.out );
              return;                                      /* return ! */
            }
          catch( NoSuchElementException e )
            {
                                                       /* end of list */
              hostName = "";
              dirPath = "";

              rpcMessage.
                putString( hostName,
                           Constants.MNTNAMLEN );
              rpcMessage.
                putString( dirPath,
                           Constants.MNTPATHLEN );

              continueToLoopOnMountEntries = false;
            }
        /*end of try-catch*/
          i++;
        }
    /*end of while-loop*/

      ipAddressWhereToSend =
        parserResponderReturnArguments.
          inRPCMessage.getInetAddress();
      portToSendTo =
        parserResponderReturnArguments.
          inRPCMessage.getPort();

      udpPacket = new
        DatagramPacket( ibuf, ibuf.length,
                        ipAddressWhereToSend,
                        portToSendTo          );

      try
        {
          udpSocket.send( udpPacket,
                          parserResponderReturnArguments.transactionId,
                          "dumpMountEntriesAndSendRPCReplyMessage"      );
        }
      catch( IOException e )
        {
          System.out.println(
            "Mount, " +
            "dumpMountEntriesAndSendRPCReplyMessage: " +
            "IOException in sending reply\n" +
            e.getMessage()                              );
        }
    /*end of try-catch*/

    }
/*end of dumpMountEntriesAndSendRPCReplyMessage*/


  public
  void

  listenAndProcessRequests()
/*****************************************************************************/
/* Function name: listenAndProcessRequests                                   */
/* File name: Mount.java                                                     */
/* Purpose: to perform actual NFS mount service                              */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 31.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      Long remoteProcedureNumberLong = null;
      int i;
      boolean thereWasAGeneralError = false;
      int dataLength = 0;
      byte[] byteBuffer = null;
      byte[] dataReceived;
      DatagramPacket udpPacket = null;
      long transactionId;
      long messageType;
      boolean nowMayProcessTheParametersToRemoteProcedure;
      ParserResponderReturnArguments parserResponderReturnArguments;
      boolean continueLoopReceivePackets = true;
                                               /* listenAndProcessRequests */
/*---------------------------------------------------------------------------*/

      while (continueLoopReceivePackets)
        {
          byteBuffer = new byte[
            Constants.MOUNT_REQUEST_UDP_PACKET_DATA_LENGTH ];

          udpPacket = new
            DatagramPacket( byteBuffer,
                            byteBuffer.length );

          try
            {
              udpSocket.receive( udpPacket );
            }
          catch( IOException e )
            {
              System.out.println(
                "udpSocket.receive: " +
                e.getMessage()          );
            }
        /*end of try-catch*/

          parserResponderReturnArguments = new
            ParserResponderReturnArguments();

          nowMayProcessTheParametersToRemoteProcedure =
            processUDPPacket(
              udpPacket,
              parserResponderReturnArguments      );

          thereWasAGeneralError =
            processGeneralErrors(
              parserResponderReturnArguments,
              Constants.MOUNTPROG,
              Constants.MOUNT_VERS_LOW,
              Constants.MOUNT_VERS_HIGH        );

          if (thereWasAGeneralError)
            continue;                                  /* continue ! */
          else
            ;
        /*end of if*/

          if ( nowMayProcessTheParametersToRemoteProcedure )
            {                                /* OK, do procedure, */
                                             /* process arguments */

              switch ( (int) parserResponderReturnArguments.
                               remoteProcedureNumber         )
                {
                case Constants.MOUNTPROC_NULL:
                  sendProcedureNullRPCReplyMessage(
                    parserResponderReturnArguments );
                  break;
                case Constants.MOUNTPROC_MNT:
                  addMountEntryAndSendRPCReplyMessage(
                    parserResponderReturnArguments    );
                  break;
                case Constants.MOUNTPROC_UMNT:
                  removeMountEntryAndSendRPCReplyMessage(
                    parserResponderReturnArguments       );
                  break;
                case Constants.MOUNTPROC_UMNTALL:
                  removeAllMountEntriesAndSendRPCReplyMessage(
                    parserResponderReturnArguments );
                  break;
                case Constants.MOUNTPROC_DUMP:
                  dumpMountEntriesAndSendRPCReplyMessage(
                    parserResponderReturnArguments        );
                  break;
                case Constants.MOUNTPROC_EXPORT:
                  dumpExportListAndSendRPCReplyMessage(
                    parserResponderReturnArguments );
                  break;
                default:
                  remoteProcedureNumberLong = new Long(
                    parserResponderReturnArguments.
                      remoteProcedureNumber            );
                  sendProcedureUnavailableRPCReplyMessage(
                    parserResponderReturnArguments,
                    remoteProcedureNumberLong.toString()   );
                  break;
                }
            /*end of switch*/

            }
          else /* there was an error */
            ;
        /*end of if on nowMayProcessTheParametersToRemoteProcedure*/

        }
    /*end of while-loop*/

      udpSocket.close();

    }
/*end of listenAndProcessRequests*/


  public
  void

  run()
/*****************************************************************************/
/* Function name: run                                                        */
/* File name: Mount.java                                                     */
/* Purpose: to perform actual NFS mount service                              */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 01.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      boolean registeredOK = false;
      boolean unregisteredOK = false;
                                                                 /* run */
/*---------------------------------------------------------------------------*/

      if (registerWithPortMapper)
        {
          sendRegistrationRPCMessageToPortMapper(
            nfs.Constants.INITIAL_TRANSACTION_ID,
            Constants.MOUNTPROG,
            Constants.MOUNT_VERS,
            pm.Constants.IPPROTO_UDP,
            Constants.MOUNT_PORT                 );

          registeredOK =
            receiveRegistrationConfirmationRPCMessageFromPortMapper();

        }
      else
        ;
    /*end of if on registerWithPortMapper*/

      if ( ( ! registerWithPortMapper ) ||
           registeredOK                    )
        {
          listenAndProcessRequests();
        }
      else
        ;
    /*end of if on registerWithPortMapper*/

      if (registeredOK)
        {
          sendUnregisterRPCMessageToPortMapper(
            nfs.Constants.INITIAL_TRANSACTION_ID,
            Constants.MOUNTPROG,
            Constants.MOUNT_VERS,
            pm.Constants.IPPROTO_UDP,
            Constants.MOUNT_PORT                 );

          unregisteredOK =
            receiveUnregisterConfirmationRPCMessageFromPortMapper();
        }
      else
        ;
    /*end of if on registeredOK*/

      udpSocket.close();

  }
/*end of run*/

  public
  mount.Registry

  getRegistry()
/*****************************************************************************/
/* Function name: getRegistry                                                */
/* File name: Mount.java                                                     */
/* Purpose: to get the registry object of this mount server                  */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 21.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                        /* getRegistry */
/*---------------------------------------------------------------------------*/

      return registry;

  }
/*end of getRegistry*/


  public
  static
  void

  main( String[] args )
/*****************************************************************************/
/* Function name: main                                                       */
/* File name: Mount.java                                                     */
/* Purpose: main method for the Mount class                                  */
/* Parameters: agrument strings array                                        */
/* Returns:                                                                  */
/* Last modified: 24.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      pm.Mapper portmapper = null;
      Mount mount = null;
                                                          /* main */
/*---------------------------------------------------------------------------*/

      try
        {
          mount = new Mount( Constants.PROPERTIES_FILE_PATH,
                             null                            );
        }
      catch( SocketException e )
        {
          System.out.println(
            "can\'t create io.UdpSocket: " +
            e.getMessage()                      );
          System.exit( 1 );
        }
    /*end of try-catch*/

      if (args.length > 0)
        {
          if (args[0].equals( "noreg" ))
            mount.registerWithPortMapper = false;
          else
            {
              if (args[0].equals( "pmthread" ))
                {
                  try
                    {
                      portmapper = new
                        pm.Mapper( Constants.PROPERTIES_FILE_PATH );
                    }
                  catch( SocketException e )
                    {
                      System.out.println(
                        "can\'t create " +
                        "io.UdpSocket for portmapper: " +
                        e.getMessage()                      );
                      System.exit( 1 );
                    }
                /*end of try-catch*/

                  mount.portmapperThread = new
                    Thread( portmapper,
                            nfs.Constants.
                              PORTMAPPER_THREAD_NAME_STRING );

                  mount.portmapperThread.start();

                }
              else
                ;
            /*end of if on pmthread*/
            }
        /*end of if on noreg*/
        }
      else
        ;
    /*end of if on args.length*/


      mount.run();
      System.exit( 0 );

    }
/*end of main*/


} /* end of Mount class */

/*****************************************************************************/
/* End of file: Mount.java                                                   */
/*****************************************************************************/
