[omniORB] Making omniNames a service on Windows NT
Jan Lessner
jan@c-lab.de
Mon, 07 Sep 1998 18:15:57 +0200
This is a multi-part message in MIME format.
--------------5D9E120A2824
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi Folks
It took me quite a while to find an easy way for making omniNames a
"real" Windows service, which you can register in the Control Panel and
keep running beyond login sessions. I could image that this is of
interest for others here too, so I attached the modified omniNames.cc to
this email.
As I didn't find a way to register services on Windows including
particular command line options, the modified version *by default* tries
to connect to the service control manager and complains if it can't. For
the old standard initialization, omniNames must be started with option
-appl, meaning it should behave like an ordinary application rather than
a service. In "service mode" any standard error output is redirected to
a log file for error analysis. For UNIX this redirection is the only
difference between normal and service mode.
Would be a nice extension for omniORB 2.6 I think (after a little code
clean-up, of course).
Regards,
Jan Lessner, C-LAB
--------------5D9E120A2824
Content-Type: text/plain; charset=us-ascii; name="omniNames.cc"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="omniNames.cc"
// -*- Mode: C++; -*-
// Package : omniNames
// omniNames.cc Author : Tristan Richardson (tjr)
//
// Copyright (C) 1997 Olivetti & Oracle Research Laboratory
//
// 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 <string.h>
#include <iostream.h>
#include <omnithread.h>
#include <NamingContext_i.h>
// Minimum idle period before we take a checkpoint (15 mins)
#define DEFAULT_IDLE_TIME_BTW_CHKPT (15*60)
void
usage()
{
cerr << "\nusage: omniNames [-start <port>] [<omniORB2-options>...]" << endl;
cerr << "\nUse -start option to start omniNames for the first time."
<< endl;
cerr << "\nYou can set the environment variable " << LOGDIR_ENV_VAR
<< " to specify the\ndirectory where the log 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 = idx+nargs; i < argc; i++) {
argv[i-nargs] = argv[i];
}
argc -= nargs;
}
static void
insertArgs(int& argc, char**& argv, int idx, int nargs)
{
char** newArgv = new char*[argc+nargs];
int i;
for (i = 0; i < idx; i++) {
newArgv[i] = argv[i];
}
for (i = idx; i < argc; i++) {
newArgv[i+nargs] = argv[i];
}
argv = newArgv;
argc += nargs;
}
//
// main loop
//
static log *serverlog = NULL;
static CORBA::BOA_ptr boa;
void mainloop()
{
boa->impl_is_ready(0,1);
//
// Now this thread has nothing much to do. Simply take a checkpoint once
// every so often.
//
int idle_time_btw_chkpt;
char *itbc = getenv("OMNINAMES_ITBC");
if (itbc == NULL || sscanf(itbc,"%d",&idle_time_btw_chkpt) != 1)
idle_time_btw_chkpt = DEFAULT_IDLE_TIME_BTW_CHKPT;
omni_mutex m;
omni_condition c(&m);
m.lock();
while (1) {
serverlog->checkpoint();
unsigned long s, n;
omni_thread::get_time(&s, &n, idle_time_btw_chkpt);
c.timedwait(s,n);
}
m.unlock();
}
#include <time.h>
#include <stdarg.h>
/* Convenience function for standard error output preceeded
* by the current date and time. This is especially of interest
* for Windows service applications
*/
void syslog(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
char buf[1024];
time_t t;
time(&t);
vsprintf(buf, fmt, ap);
cerr << ctime(&t) << buf << flush;
va_end(ap);
}
#ifdef __WIN32__
//
// Windows service management stuff
//
static SERVICE_STATUS ssStatus;
static SERVICE_STATUS_HANDLE sshStatusHandle;
static BOOL was_stopped = FALSE;
/*
* Service control function, accepting only STOP messages
*/
void service_ctrl(DWORD dwCtrlCode)
{
if (dwCtrlCode == SERVICE_CONTROL_STOP) {
ssStatus.dwCurrentState = SERVICE_STOPPED;
was_stopped = TRUE;
}
else {
// ignore any other control message but STOP
ssStatus.dwCurrentState = SERVICE_RUNNING;
}
ssStatus.dwWin32ExitCode = NO_ERROR;
if (!SetServiceStatus(sshStatusHandle, &ssStatus)) {
syslog("SetServiceStatus failed: %d\n", GetLastError());
}
}
void service_main(int argc, char *argv[])
{
/* register our service control handler */
if (!(sshStatusHandle = RegisterServiceCtrlHandler
("omniNames", (LPHANDLER_FUNCTION)service_ctrl))) {
syslog("RegisterServiceCtrlHandler failed: %d\n", GetLastError());
return;
}
/* report running status to Service Control Manager */
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwCurrentState = SERVICE_RUNNING;
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ssStatus.dwWin32ExitCode = NO_ERROR;
ssStatus.dwServiceSpecificExitCode = 0;
ssStatus.dwCheckPoint = 1;
ssStatus.dwWaitHint = 5000;
if (!SetServiceStatus(sshStatusHandle, &ssStatus)) {
syslog("SetServiceStatus failed: %d\n", GetLastError());
ssStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(sshStatusHandle, &ssStatus);
return;
}
/* enter the main loop */
mainloop();
}
#endif
//
// main
//
int main(int argc, char **argv)
{
//
// If we have a "-start" option, get the given port number.
//
int port = 0;
unsigned char service_init = 1;
if (argc > 1) {
if (strcmp(argv[1], "-start") == 0) {
if (argc < 3) usage();
port = atoi(argv[2]);
removeArgs(argc, argv, 1, 2);
} else if (strcmp(argv[1], "-appl") == 0) {
service_init = 0;
removeArgs(argc, argv, 1, 1);
} else if ((strncmp(argv[1], "-BOA", 4) != 0) &&
(strncmp(argv[1], "-ORB", 4) != 0)) {
usage();
}
}
/* In case omniNames runs as a real service application, redirect
* any standard error output to a log file.
*/
if (service_init) {
cerr = *new ofstream("omniNames.log");
syslog("Name service initializing\n");
}
//
// Set up an instance of class log. This also gives us back the port
// number from the log file if "-start" wasn't specified.
//
log l(port);
serverlog = &l;
//
// Add a fake command line option to tell the BOA which port to use.
//
insertArgs(argc, argv, 1, 2);
argv[1] = strdup("-BOAiiop_port");
argv[2] = new char[16];
sprintf(argv[2], "%d", port);
//
// Initialize the ORB and the object adaptor.
//
CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
boa = orb->BOA_init(argc,argv,"omniORB2_BOA");
//
// Read the log file and set up all the naming contexts described in it.
//
l.init(orb, boa);
#ifdef __WIN32__
if (service_init) {
/* register at the service control manager */
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ "omniNames", (LPSERVICE_MAIN_FUNCTION)service_main },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcher(DispatchTable))
{
if (was_stopped) {
syslog("Name service stopped\n");
}
else {
syslog("StartServiceCtrlDispatcher failed: %d\n", GetLastError());
}
}
}
else
#endif
mainloop();
return 0;
}
--------------5D9E120A2824--