/***********************************************************************
 * 
 *  Copyright (C) 2005-2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library 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
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 ***********************************************************************/


using System;
using System.Net;
using System.Net.Sockets;
using Mono.Unix;
using Mono.Unix.Native;
using System.IO;
using System.Text;
using System.Threading;
using sscs.common;
using sscs.constants;

namespace sscs.communication
{

/* Platform specific class which implements 
 * the 'Communication' interface.
 */

    class UnixCommunication : Communication
    {
        private Socket listeningSocket;
        private Socket connectedSocket;
        private string socketFileName = "/tmp/.novellCASA";
        private Mono.Unix.UnixEndPoint sockEndPoint;
        private ManualResetEvent eventVar = null;


        //Methods
        internal UnixCommunication()
        {
            CSSSLogger.ExecutionTrace(this);
            Syscall.umask(0);
			if(File.Exists(socketFileName))
			{
				File.Delete(socketFileName);
			}
            listeningSocket = new Socket( AddressFamily.Unix,
                                          SocketType.Stream,
                                          ProtocolType.IP );
            sockEndPoint = new Mono.Unix.UnixEndPoint(socketFileName);
            eventVar = new ManualResetEvent(true);

        }

        ~UnixCommunication()
        {
            CSSSLogger.ExecutionTrace(this);
            eventVar.Close();
            CloseCommunicationEndPoint();
            
        }  

        // This code executes in the listening thread.
        public void StartCommunicationEndPoint()
        {
            CSSSLogger.ExecutionTrace(this);
            try
            {
        	UnixFileSystemInfo sockFileInfo = new UnixFileInfo(socketFileName);
               UnixUserInfo sockFileOwner = sockFileInfo.OwnerUser;
                
		// check if ROOT is the owner of the file: /tmp/.novellCASA
		if (sockFileOwner.UserId != 0)
		{
			File.Delete(socketFileName);
		}

            }
            catch(Exception e)
            {
                CSSSLogger.ExpLog(e.ToString());
            }

            listeningSocket.Bind(sockEndPoint);
            listeningSocket.Listen(50);
            
	    while(true)
            {
                try
                {
                    eventVar.Reset();
                    listeningSocket.BeginAccept(new AsyncCallback(ListenCb),
                                               listeningSocket);
                    eventVar.WaitOne();
                }
                catch(Exception e)
                {
                    CSSSLogger.ExpLog(e.ToString());
                    throw e;
                }
            }
        }

        public void CloseCommunicationEndPoint()
        {
            CSSSLogger.ExecutionTrace(this);
            listeningSocket.Close();
            if(File.Exists( socketFileName ))
                File.Delete(socketFileName);    
        }

        // On receipt of a new client, this method is called.
        private void ListenCb (IAsyncResult state)
        {
            try
            {
                CSSSLogger.ExecutionTrace(this);
                connectedSocket = ((Socket)state.AsyncState).EndAccept (state);
                eventVar.Set();
                ServiceClient();
            }
            catch(Exception e)
            {
                /* All resources would have been cleaned up before reaching
                 * here. 
                 */ 
                CSSSLogger.ExpLog(e.ToString());
            }
            /* End of thread function */
        }

        private void ServiceClient()
        {
            CSSSLogger.ExecutionTrace(this);
            IPCChannel ipcChannel = IPCChannel.Create(connectedSocket);
            AppHandler appHandler = new AppHandler(ipcChannel);

            try
            {
               int retVal = appHandler.ServiceApp();
               if( retVal != RetCodes.SUCCESS )
                   CSSSLogger.DbgLog("Servicing client failed.");
            } 
            catch( Exception e )
            {
                CSSSLogger.ExpLog(e.ToString());
            }
            finally
            {
                ipcChannel.Close();
            }
        }
    }
}