[omniORB] omniNames NT service available

Dietmar May dcmay at dmis.com
Sat Dec 9 23:03:43 GMT 2006


I've just added Win32 service support to omninames. This allows =
omniNames
to be installed as an NT service without using the SRVANY utility. This
may be useful for distribution of omniNames with application packages.

DUNCAN: binary file omniNames.exe posted to upload.sf.net/incoming - =
please rename as appropriate.

omniNames supports the following additional command line switches:

-install [<port>]: installs the service with NT/2K/XP, w/optional portno
like -start

-man: used with -install, specifies manual startup type; default is
automatic

-remove: removes the service

Once installed, the service will be started and stopped automatically,
unless -man was specified with -install. If omniNames is run without
having been installed, it should detect that the service has not been
installed, and run normally (as a console app). If the service is =
already
running, then omniNames may appear to hang for a few seconds, but will
then report the same error as if two instances of omniNames were =
started.

-remove does not delete existing omninames.log files, so even though
a -remove followed by -install will work, an error is reported about
writing the logfile. If -remove is specified while the service is =
running,
it will be automatically stopped first.

Simply replace omniNames.cc in the src/appl/omniNames directory with the =
following (complete file text).

There is a bug in the win32_log_msg function that causes a very ugly =
error event to be logged in the Application Event Log. The actual =
message text can be found at the end of this ugly event message. This =
issue has not yet been debugged.

An executable file (omniNames.exe) has been uploaded to sourceforge.net, =
and may be available for download soon. Please note that this file =
requires the installer version of the omniorb and omnithread DLLs built =
using msvc 6.0 (ie. omniorb407_ms6_rt.dll, omnithread32_ms6_rt.dll).

Dietmar May

=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

// -*- Mode: C++; -*-
//                          Package   : omniNames
// omniNames.cc             Author    : Tristan Richardson (tjr)
//
//    Copyright (C) 1997-1999 AT&T Laboratories Cambridge
//
//  This file is part of omniNames.
//
//  omniNames is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  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.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  =
02111-1307,
//  USA.
//

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <omnithread.h>
#include <NamingContext_i.h>

#ifdef HAVE_STD
#  include <iostream>
   using namespace std;
#else
#  include <iostream.h>
#endif

#ifdef __WIN32__
#  include <io.h>
#else
#  include <unistd.h>
#endif

#ifndef O_SYNC
#  ifdef  O_FSYNC              // FreeBSD 3.2 does not have O_SYNC???
#    define O_SYNC O_FSYNC
#  endif
#endif

// Minimum idle period before we take a checkpoint (15 mins)
#define DEFAULT_IDLE_TIME_BTW_CHKPT  (15*60)


PortableServer::POA_var the_poa;
PortableServer::POA_var the_ins_poa;


void
usage()
{
  cerr << "\nusage: omniNames [-start [<port>]]\n"
#ifdef __WIN32__
	   <<   "                 [-install [<port>]]\n"
	   <<   "                 [-remove]\n"
#endif
       <<   "                 [-logdir <directory name>]\n"
       <<   "                 [-errlog <file name>]\n"
       <<   "                 [-ignoreport]\n"
       <<   "                 [<omniORB-options>...]" << endl;
  cerr << "\nUse -start option to start omniNames for the first time."
	   << endl
#ifdef __WIN32__
	   << "Use -install option to install omniNames as Windows service."
       << endl
	   << "Use -remove option to de-install the omniNames Windows service."
	   << endl
#endif
       << "With no <port> argument, the standard default of "
       << IIOP::DEFAULT_CORBALOC_PORT << " is used."
       << endl;
  cerr << "\nUse -logdir option to specify the directory where the
log/data files are kept.\n";
  cerr << "\nUse -errlog option to specify where standard error output =
is
redirected.\n";
  cerr << "\nUse -ignoreport option to ignore the port =
specification.\n";
  cerr << "\nYou can also set the environment variable " << =
LOGDIR_ENV_VAR
       << " to specify the\ndirectory where the log/data files are
kept.\n"
       << endl;
  exit(1);
}


static void
removeArgs(int& argc, char** argv, int idx, int nargs)
{
  if ((idx+nargs) > argc) return;
  for (int i =3D idx+nargs; i < argc; i++) {
    argv[i-nargs] =3D argv[i];
  }
  argc -=3D nargs;
}


static void
insertArgs(int& argc, char**& argv, int idx, int nargs)
{
  char** newArgv =3D new char*[argc+nargs];
  int i;
  for (i =3D 0; i < idx; i++) {
    newArgv[i] =3D argv[i];
  }
  for (i =3D idx; i < argc; i++) {
    newArgv[i+nargs] =3D argv[i];
  }
  argv =3D newArgv;
  argc +=3D nargs;
}


//
// main
//

unsigned char flag_stop =3D 0;

#ifdef __WIN32__
DWORD                   err_code =3D NO_ERROR;
TCHAR                   err_msg[256];
SERVICE_STATUS          s_status;       // current status of the service
SERVICE_STATUS_HANDLE   h_status =3D NULL;

static const TCHAR* WIN32_DISP_NAME =3D "omniNames";
static const TCHAR* WIN32_SVC_NAME =3D "omninames";

int win32_svc_main(int, char **);
void WINAPI win32_svc_dispatch (DWORD, LPTSTR*);
VOID WINAPI win32_svc_ctrl (DWORD);
BOOL win32_report_status (DWORD, DWORD, DWORD);
void win32_log_msg (const char*);
LPTSTR GetLastErrorText (LPTSTR, DWORD);

#endif //__WIN32__

int port =3D 0;
char* logdir =3D 0;
int ignoreport =3D 0;

omni_mutex sleep_m;
omni_condition sleep_c(&sleep_m);

int
main(int argc, char **argv)
{
#ifdef __WIN32__
  BOOL flag_install =3D FALSE;
  BOOL flag_remove  =3D FALSE;
  BOOL flag_start   =3D FALSE;
  BOOL flag_man     =3D FALSE;
#endif
  //
  // If we have a "-start" option, get the given port number, or use
  // the default.
  //

  flag_stop =3D 0;

  while (argc > 1) {
    if (strcmp(argv[1], "-start") =3D=3D 0) {
      if(flag_install || flag_remove)
        usage();
      if (argc < 3 || argv[2][0] =3D=3D '-') {
        port =3D IIOP::DEFAULT_CORBALOC_PORT;
        removeArgs(argc, argv, 1, 1);
      }
      else {
        port =3D atoi(argv[2]);
        removeArgs(argc, argv, 1, 2);
      }
    }
    else if (strcmp(argv[1], "-ignoreport") =3D=3D 0) {
      ignoreport =3D 1;
      removeArgs(argc, argv, 1, 1);
    }
    else if (strcmp(argv[1], "-man") =3D=3D 0) {
      flag_man =3D 1;
      removeArgs(argc, argv, 1, 1);
    }
    else if (strcmp(argv[1], "-logdir") =3D=3D 0) {
      if (argc < 3) usage();
      logdir =3D argv[2];
      removeArgs(argc, argv, 1, 2);
    }
    else if (strcmp(argv[1], "-errlog") =3D=3D 0) {
      if (argc < 3) usage();
#ifdef __WIN32__
      int fd =3D _open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, =
_S_IWRITE);
      if (fd < 0 || _dup2(fd,2)) {
#else
      int fd =3D open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
      if (fd < 0 || dup2(fd,2) < 0) {
#endif
        cerr << "Cannot open error log file: " << argv[2] << endl;
        usage();
      }
      setvbuf(stderr, 0, _IOLBF, 0);
      removeArgs(argc, argv, 1, 2);
    }
#ifdef __WIN32__
    else if (strcmp(argv[1], "-install") =3D=3D 0) {
      if(flag_remove || flag_start)
        usage();
      if (argc < 3 || argv[2][0] =3D=3D '-') {
        port =3D IIOP::DEFAULT_CORBALOC_PORT;
        removeArgs(argc, argv, 1, 1);
      }
      else {
        port =3D atoi(argv[2]);
        removeArgs(argc, argv, 1, 2);
      }
      flag_install =3D TRUE;      //allow for other flags to be =
processed
    }
    else if (strcmp(argv[1], "-remove") =3D=3D 0) {
      if(flag_install || flag_start)
         usage();
      flag_remove =3D TRUE;       //allow for other flags to be =
processed
      removeArgs(argc, argv, 1, 1);
    }
#endif
    else if ((strncmp(argv[1], "-ORB", 4) !=3D 0)) {
      usage();
    }
    else {
      break;
    }
  }

#ifdef __WIN32__
  if (flag_install) {
    TCHAR path[512];

    SC_HANDLE hservice =3D NULL;
    SC_HANDLE hmanager =3D NULL;

    if (GetModuleFileName(NULL, path, sizeof(path)) =3D=3D 0) {
      GetLastErrorText(err_msg, sizeof(err_msg));
      printf("Unable to install %s - %s\n", WIN32_DISP_NAME, err_msg);
      return 2;
    }

    hmanager =3D OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hmanager =3D=3D NULL) {
      GetLastErrorText(err_msg, sizeof(err_msg));
      printf("OpenSCManager failed - %s\n", err_msg);
      return 2;
    }

	DWORD start_type =3D flag_man ? SERVICE_DEMAND_START : =
SERVICE_AUTO_START;

    hservice =3D CreateService(hmanager, WIN32_SVC_NAME, =
WIN32_DISP_NAME,
      SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, start_type,
      SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL);

    if (hservice !=3D NULL) {
      CloseServiceHandle(hservice);
    }

    CloseServiceHandle(hmanager);

    if (hservice =3D=3D NULL) {
      GetLastErrorText(err_msg, sizeof(err_msg));
      printf("CreateService failed - %s\n", err_msg);
      return 2;
    }

    printf("%s installed.\n", WIN32_DISP_NAME);

    if (port =3D=3D 0)              //fake a "-start" by spec a port no.
      port =3D IIOP::DEFAULT_CORBALOC_PORT;
    //fall through to run - but stop immediately; this initializes the
logfile
    flag_stop =3D 1;
  }
  else if (flag_remove) {
    SC_HANDLE hservice =3D NULL;
    SC_HANDLE hmanager =3D NULL;

    hmanager =3D OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hmanager =3D=3D NULL) {
      GetLastErrorText(err_msg, sizeof(err_msg));
      printf("OpenSCManager failed - %s\n", err_msg);
      return 2;
    }

    hservice =3D OpenService(hmanager, WIN32_SVC_NAME, =
SERVICE_ALL_ACCESS);
    if (hservice =3D=3D NULL) {
      GetLastErrorText(err_msg, sizeof(err_msg));
      printf("OpenService failed - %s\n", err_msg);
      CloseServiceHandle(hmanager);
      return 2;
    }

    // try to stop the service
    SERVICE_STATUS status;
    if (ControlService (hservice, SERVICE_CONTROL_STOP, &status)) {
      printf("Stopping %s.", WIN32_DISP_NAME);
      Sleep(1000);

      while (QueryServiceStatus(hservice, &status)) {
        if (status.dwCurrentState !=3D SERVICE_STOP_PENDING)
          break;
        printf(".");
        Sleep(1000);
      }

      if (status.dwCurrentState =3D=3D SERVICE_STOPPED)
        printf("\n%s stopped.\n", WIN32_DISP_NAME);
      else
        printf("\n%s failed to stop.\n", WIN32_DISP_NAME);
    }

    // now remove the service
    if (DeleteService(hservice)) {
      printf("%s removed.\n", WIN32_SVC_NAME);
      win32_log_msg("DeleteService complete");
    }
    else {
      GetLastErrorText(err_msg, sizeof(err_msg));
      printf("DeleteService failed - %s\n", err_msg);
    }

    CloseServiceHandle(hservice);
    CloseServiceHandle(hmanager);
    return 0;
  }
  else {
    SERVICE_TABLE_ENTRY dispatch[] =3D {
      { (LPTSTR)WIN32_SVC_NAME,
(LPSERVICE_MAIN_FUNCTION)win32_svc_dispatch },
      { NULL, NULL }
    };

    //run the service here - call returns when service stopped
    if (StartServiceCtrlDispatcher(dispatch) !=3D 0)
      return 0;
    win32_log_msg("StartServiceCtrlDispatcher failed");
    //service not registered (no prior -install) or error -- run =
normally
  }

  return win32_svc_main(argc, argv);
}

int win32_svc_main(int argc, char **argv)
{
#endif //__WIN32__

  //
  // Set up an instance of class omniNameslog.  This also gives us back
the port
  // number from the log file if "-start" wasn't specified.
  //

  omniNameslog l(port, logdir);

  //
  // Add a fake command line option to tell the POA which port to use.
  //

  if (ignoreport) {
    insertArgs(argc, argv, 1, 2);
  }
  else {
    insertArgs(argc, argv, 1, 4);
    argv[3] =3D strdup("-ORBendPoint");
    argv[4] =3D new char[20];
    sprintf(argv[4], "giop:tcp::%d", port);
  }
  argv[1] =3D strdup("-ORBpoaUniquePersistentSystemIds");
  argv[2] =3D strdup("1");

  //
  // Initialize the ORB and the object adapter.
  //

  CORBA::ORB_ptr orb;

  try {
    orb =3D CORBA::ORB_init(argc, argv);
  }
  catch (CORBA::INITIALIZE& ex) {
    cerr << "Failed to initialise the ORB." << endl;
    return 1;
  }

  try {
    CORBA::Object_var poaref =3D =
orb->resolve_initial_references("RootPOA");
    PortableServer::POA_var poa =3D =
PortableServer::POA::_narrow(poaref);

    PortableServer::POAManager_var pman =3D poa->the_POAManager();

    CORBA::PolicyList pl(1);
    pl.length(1);
    pl[0] =3D poa->create_lifespan_policy(PortableServer::PERSISTENT);

    the_poa =3D poa->create_POA("", pman, pl);
    pman->activate();

    // Get the "magic" interoperable naming service POA
    poaref      =3D orb->resolve_initial_references("omniINSPOA");
    the_ins_poa =3D PortableServer::POA::_narrow(poaref);
    pman        =3D the_ins_poa->the_POAManager();
    pman->activate();
  }
  catch (CORBA::INITIALIZE& ex) {
    cerr << "Failed to initialise the POAs. "
     << "Is omniNames already running?" << endl;
    return 1;
  }

  //
  // Read the log file and set up all the naming contexts described in =
it.
  //

  l.init(orb, the_poa, the_ins_poa);

  //
  // Now this thread has nothing much to do.  Simply take a checkpoint
once
  // every so often.
  //

  int idle_time_btw_chkpt =3D 0;
  char *itbc =3D getenv("OMNINAMES_ITBC");
  if (itbc =3D=3D NULL || sscanf(itbc,"%d",&idle_time_btw_chkpt) !=3D 1)
    idle_time_btw_chkpt =3D DEFAULT_IDLE_TIME_BTW_CHKPT;

  sleep_m.lock();
  while (!flag_stop) {
    l.checkpoint();
	int chkpt_loop_cnt =3D idle_time_btw_chkpt * 20;	//n * 50ms for
c.timed_wait
	while (!flag_stop && chkpt_loop_cnt--) {
      unsigned long s, n;
      omni_thread::get_time(&s, &n, 0, 50000000); //check for stop every
50ms
      sleep_c.timedwait(s,n);
	}
  }
  sleep_m.unlock();

  return 0;
}

#ifdef __WIN32__

class win32_thread : public omni_thread
{
public:
    win32_thread (int _argc, char** _argv) : s(0) { argc =3D _argc; argv =
=3D
_argv; }

    void start () //hides omni_thread::start()
    {
        omni_thread::start_undetached();
    }
    bool wait_for_run ()
    {
        for(int i =3D 0; i < 5000; ++i) {
            if(s.trywait())
                return true;
            omni_thread::sleep(0,1000000);  //sleep 1ms
        }
        return false;
    }
private:
    virtual void* run_undetached (void*)
    {
        s.post();
        win32_svc_main(argc, argv);
        return NULL;
    }

    int     argc;
    char**  argv;
    omni_semaphore s;
};

// inits the service, then runs the naming service code
void WINAPI win32_svc_dispatch (DWORD dargc, LPTSTR *largv)
{
  // register our service control handler:
  h_status =3D RegisterServiceCtrlHandler(WIN32_SVC_NAME, =
win32_svc_ctrl);
  if (h_status !=3D 0) {
    s_status.dwServiceType =3D SERVICE_WIN32_OWN_PROCESS;
    s_status.dwServiceSpecificExitCode =3D 0;

    // report the status to the service control manager.
    if (win32_report_status(SERVICE_START_PENDING, NO_ERROR, 3000)) {
      //dispatch runs in service manager thread, which has no
"omni_thread::self()"
      //since this is needed in omniNameslog::init(), run win32_svc_main
in an omni_thread
      win32_thread wthread((int)dargc, (char**)largv);
      wthread.start();
      if(wthread.wait_for_run()) {
        win32_report_status(SERVICE_RUNNING, NO_ERROR, 0);
        wthread.join(0);
	    err_code =3D NO_ERROR;
	  }
	  win32_report_status(SERVICE_STOPPED, err_code, 0);
    }
  }

  return;
}

// called by the SCM whenever ControlService() is called on this =
service.
VOID WINAPI win32_svc_ctrl (DWORD code)
{
  // Handle the requested control code.
  if(code =3D=3D SERVICE_CONTROL_STOP) {      // stop the service.
    win32_report_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
    flag_stop =3D true;
  } else {
      win32_report_status(s_status.dwCurrentState, NO_ERROR, 0);
  }
}

// sets the current status of the service and reports it to the SCM
BOOL win32_report_status (DWORD state, DWORD exit_code, DWORD wait_hint)
{
  static DWORD checkpt =3D 0;

  BOOL result =3D TRUE;

  if (state =3D=3D SERVICE_START_PENDING || state =3D=3D =
SERVICE_STOPPED)
      s_status.dwControlsAccepted =3D 0;
  else
      s_status.dwControlsAccepted =3D SERVICE_ACCEPT_STOP;

  s_status.dwCurrentState =3D state;
  s_status.dwWin32ExitCode =3D exit_code;
  s_status.dwWaitHint =3D wait_hint;

  if (state =3D=3D SERVICE_RUNNING || state =3D=3D SERVICE_STOPPED)
      s_status.dwCheckPoint =3D 0;
  else
      s_status.dwCheckPoint =3D ++checkpt;

  // report the status of the service to the service control manager.
  result =3D SetServiceStatus(h_status, &s_status);
  if(!result)
    win32_log_msg("SetServiceStatus failed");

  return result;
}

void win32_log_msg (const TCHAR* msg)
{
  HANDLE  hsource =3D NULL;

  hsource =3D RegisterEventSource(NULL, WIN32_SVC_NAME);
  if (hsource !=3D NULL) {
    TCHAR   msg_buf[256];
    LPCTSTR  msg_strings[2] =3D { msg_buf, msg };

    sprintf(msg_buf, "%s error: %d", WIN32_SVC_NAME, GetLastError());

    ReportEvent(hsource, EVENTLOG_ERROR_TYPE, 0, 0, NULL, 2, 0,
msg_strings, NULL);
    DeregisterEventSource(hsource);
  }
}

LPTSTR GetLastErrorText (LPTSTR lpszBuf, DWORD dwSize)
{
    DWORD dwRet;
    LPTSTR lpszTemp =3D NULL;

    dwRet =3D FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
                             FORMAT_MESSAGE_FROM_SYSTEM |
                             FORMAT_MESSAGE_ARGUMENT_ARRAY,
                           NULL,
                           GetLastError(),
                           LANG_NEUTRAL,
                           (LPTSTR)&lpszTemp,
                           0,
                           NULL );

    // supplied buffer is not long enough
    if (!dwRet || ( (long)dwSize < (long)dwRet+14))
        lpszBuf[0] =3D TEXT('\0');
    else
    {
        lpszTemp[lstrlen(lpszTemp)-2] =3D TEXT('\0');  //remove cr and
newline cha
        sprintf(lpszBuf, "%s (0x%x)", lpszTemp, GetLastError());
    }

    if (lpszTemp)
        LocalFree((HLOCAL) lpszTemp);

    return lpszBuf;
}

#endif // __WIN32__




More information about the omniORB-list mailing list