// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1993 
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        daemon.h
// 
// Purpose:     generic Hyper-G viewer daemon
// 
// Created:     18 Oct 93   Joerg Faschingbauer
// 
// Modified:    
// 
// 
// </file> 
#include "rvwstuff.h"

#include <iostream.h>
#if !defined(hpux) && !defined(UnixWare)
#include <osfcn.h>
#endif
#include <stdlib.h>

// Signal handling
#include <signal.h>

// Environment-variables
#include <hyperg/utils/options.h>
#include <sys/file.h>
#include <fcntl.h>

#ifdef sparc
#include <sys/wait.h>
#endif

#include <InterViews/session.h>
#include <hyperg/Dispatch/dispatcher.h>
#include <hyperg/Dispatch/rpcservice.h>







// #define VERBOSE
// 
// #ifdef VERBOSE
// extern long verbose ;
// #define Debug(x) {if (::verbose) {cerr << x << ' ';}}
// #define DebugNl(x) Debug(x << endl)
// #else
// #define Debug(x)
// #define DebugNl(x)
// #endif


#define HgDaemonImplement(GENERICVIEWER,CLASSNAMEHG)			      \
class ViewerServer : public RpcService {				      \
public:									      \
   ViewerServer (int port) ;						      \
   virtual ~ViewerServer() {}						      \
   int newfd() const { return _newfd; }					      \
   int port() const { return _port; }					      \
   									      \
private:								      \
   virtual void createReader(int fd) ;					      \
									      \
   int _newfd;								      \
} ;									      \
ViewerServer :: ViewerServer(int port = 0) : RpcService(port) {		      \
   _newfd = 0 ;								      \
}									      \
void ViewerServer :: createReader(int fd) {				      \
   long pid;								      \
   if (!(pid = fork())) {						      \
      _newfd = fd ;							      \
      quitRunning() ;							      \
   }									      \
   else									      \
      close(fd) ;							      \
}									      \
									      \
									      \
ViewerServer* server = nil ;						      \
Dispatcher* dispatcher = nil ;						      \
									      \
									      \
									      \
static void syserr(const char* msg) {					      \
   extern int  errno, sys_nerr;						      \
   extern char *sys_errlist[];						      \
									      \
   cerr << "ViewerServer: " << msg << " (Error #" << errno;		      \
   if (errno > 0  && errno < sys_nerr)					      \
      cerr << ": " << sys_errlist[errno] << ") -- process stopped\n";	      \
   else									      \
      cerr << ") -- process stopped\n";					      \
   exit(1);								      \
}									      \
									      \
static void SigTerm(int sig) {						      \
   if (signal(sig, SIG_IGN) == BADSIG)					      \
      syserr("signal") ;						      \
   delete server ;							      \
   delete dispatcher ;							      \
   									      \
   cerr << "Program stopped (caught signal " << sig << ")." << endl ;	      \
   close(2);								      \
   exit(0);								      \
}									      \
									      \
static void cleanup(int i) {						      \
   if (signal(i, SIG_IGN) == BADSIG)					      \
      syserr("signal");							      \
   if (i) {								      \
      cerr << "ViewerServer: got signal " << i << endl ;		      \
   }									      \
   cerr << "Program stopped" << endl ;					      \
   exit(i);								      \
}									      \
									      \
									      \
#ifndef SYSV								      \
/*									      \
* void wait_for_child()							      \
* =====================							      \
*/									      \
void wait_for_child(int) {						      \
   int pid;								      \
   union wait status;							      \
   static int options = WNOHANG;					      \
   struct rusage rusage;						      \
   									      \
   if ( (pid = wait3(&status, options, &rusage)) <= 0 ) {		      \
   }									      \
}									      \
#endif									      \
									      \
									      \
int main (int argc, char** argv) {					      \
cout << "futoascheier" << endl ;\
   const char* progname = argv[0] ;					      \
									      \
   // ignore 'Death of Child' to avoid 'Zombie'-processes		      \
   // ---------------------------------------------------		      \
#ifndef SYSV								      \
   signal(SIGSEGV, cleanup);						      \
   signal(SIGINT, cleanup);						      \
   signal(SIGKILL, cleanup);						      \
   signal(SIGHUP, cleanup);						      \
   signal(SIGTERM, SigTerm);						      \
   signal(SIGILL, cleanup);						      \
   signal(SIGCLD, wait_for_child);                                            \
#else									      \
   signal(SIGSEGV, (void(*)(int ...))cleanup);				      \
   signal(SIGINT, (void(*)(int ...))cleanup);				      \
   signal(SIGKILL, (void(*)(int ...))cleanup);				      \
   signal(SIGHUP, (void(*)(int ...))cleanup);				      \
   signal(SIGTERM, (void(*)(int ...))SigTerm);				      \
   signal(SIGILL, (void(*)(int ...))cleanup);				      \
#if defined(SVR2) || defined(SVR3)					      \
   if ( signal(SIGCLD, SIG_IGN) == (void(*)(int ...))-1 )		      \
#else									      \
      if ( signal(SIGCLD, SIG_IGN) == (void(*)(int ))-1 )		      \
#endif									      \
   									      \
#endif									      \
									      \
									      \
   int port = 0 ;  // default: get the next free port number		      \
   int caller_port = 0 ;						      \
   									      \
   extern int optind ;							      \
   extern char* optarg ;						      \
   int copt ;								      \
   while ((copt = getopt (argc, argv, "p:c:"))  !=   EOF) {		      \
      switch (copt) {							      \
	 case 'p': port = atoi(optarg) ;          break ;		      \
	 case 'c': caller_port = atoi(optarg) ;    break ;		      \
      }									      \
   }									      \
									      \
									      \
									      \
   dispatcher = new Dispatcher() ;					      \
   Dispatcher::instance(dispatcher) ;					      \
									      \
   server = new ViewerServer (port) ;					      \
									      \
   if (caller_port) {							      \
      // tell the caller who listens at caller_port about your port number    \
      sleep (1) ;							      \
      char caller_host[32] ;   gethostname (caller_host, 32) ;		      \
      rpcstream to_caller ;						      \
      to_caller.connect (caller_host, caller_port) ;			      \
      if (to_caller.fail()) {						      \
	 cerr << "nix connect" << endl ;				      \
	 exit (-1) ;							      \
      }									      \
      to_caller << server->port() ;					      \
      to_caller.close() ;						      \
   }									      \
   else									      \
      // the caller doesn't listen at any port				      \
      cout << "Port: " << server->port() << endl ;			      \
									      \
   server->run() ;							      \
									      \
									      \
									      \
   // this is a child of the server					      \
   int fd = server->newfd() ;						      \
									      \
   delete server;							      \
   delete dispatcher;							      \
   									      \
   server = nil;							      \
   dispatcher = nil;							      \
   									      \
   if (fd) {								      \
      dispatcher = new Dispatcher();					      \
      Dispatcher::instance(dispatcher);					      \
									      \
      Session* session = new Session (CLASSNAMEHG, argc, argv) ;		      \
									      \
      RemoteViewerManager* manager = new RemoteViewerManager (fd) ;	      \
									      \
      HgViewer* hgviewer = new GENERICVIEWER (manager) ;		      \
									      \
      manager->viewer (hgviewer) ;					      \
									      \
      session->run() ;							      \
									      \
      delete hgviewer ;							      \
      delete manager ;							      \
      delete dispatcher ;						      \
									      \
      close (fd);							      \
      exit (0);								      \
   }									      \
									      \
   exit (0);								      \
}									      \
