[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