blob: 0cccf2877c64ed8d7496e39dd907e8c91622406d [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***************************************************************************
* Description: NT System service for Jakarta/Tomcat *
* Author: Gal Shachor <shachor@il.ibm.com> *
* Dave Oxley <Dave@JungleMoss.com> *
* Version: $Revision$ *
***************************************************************************/
#include "jk_global.h"
#include "jk_util.h"
#include "jk_ajp13.h"
#include "jk_connect.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#define AJP12_TAG ("ajp12")
#define AJP13_TAG ("ajp13")
#define BASE_REGISTRY_LOCATION ("SYSTEM\\CurrentControlSet\\Services\\")
#define IMAGE_NAME ("ImagePath")
#define PARAMS_LOCATION ("Parameters")
#define PRP_LOCATION ("PropertyFile")
// internal variables
static SERVICE_STATUS ssStatus; // current status of the service
static SERVICE_STATUS_HANDLE sshStatusHandle;
static DWORD dwErr = 0;
static char szErr[1024] = "";
static HANDLE hServerStopEvent = NULL;
static int shutdown_port;
static char *shutdown_protocol = AJP12_TAG;
static char *shutdown_secret = NULL;
static char *shutdown_cmd=NULL;
typedef enum ActionEnum
{ acNoAction = 0,
acInstall = 1,
acRemove = 2,
acStartTC = 3,
acStopTC = 4
} ActionEnum;
struct jk_tomcat_startup_data {
char *cmd_line; /* Start command line */
char *stdout_file;
char *stderr_file;
char *extra_path;
char *tomcat_home;
char *java_bin;
char *shutdown_protocol;
/* for cmd */
char *stop_cmd;
/* For ajp13/ajp12/catalina */
int shutdown_port;
char *shutdown_secret;
/* Optional/not needed */
char *classpath;
char *tomcat_class;
char *server_file;
};
typedef struct jk_tomcat_startup_data jk_tomcat_startup_data_t;
// internal function prototypes
static void WINAPI service_ctrl(DWORD dwCtrlCode);
static void WINAPI service_main(DWORD dwArgc,
char **lpszArgv);
static void install_service(char *name,
char *dname,
char *user,
char *password,
char *deps,
BOOL bAutomatic,
char *rel_prp_file);
static void remove_service(char *name);
static void start_service(char *name,
char *machine);
static void stop_service(char *name,
char *machine);
static char *GetLastErrorText(char *lpszBuf, DWORD dwSize);
static void AddToMessageLog(char *lpszMsg);
static BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint);
static void start_jk_service(char *name);
static void stop_jk_service(void);
static int set_registry_values(SC_HANDLE schService, char *name,
char *prp_file);
static int create_registry_key(const char *tag,
HKEY *key);
static int set_registry_config_parameter(HKEY hkey,
const char *tag,
char *value);
static int get_registry_config_parameter(HKEY hkey,
const char *tag,
char *b, DWORD sz);
static int start_tomcat(const char *name,
HANDLE *hTomcat);
static void stop_tomcat(char *name,
int port,
const char *protocol,
char *secret,
HANDLE hTomcat);
static int read_startup_data(jk_map_t *init_map,
jk_tomcat_startup_data_t *data,
jk_pool_t *p);
static int exec_cmd(const char *name, HANDLE *hTomcat, char *cmdLine);
static void usage_message(const char *name)
{
printf("%s - Usage:\n\n", name);
printf("To install the service:\n");
printf("%s -i <service name> {optional params} <config properties file>\n", name);
printf(" Optional parameters\n");
printf(" -u <user name> - In the form DomainName\\UserName (.\\UserName for local)\n");
printf(" -n <service display name> - In quotes if contains non-lphanumeric chars\n");
printf(" -p <user password>\n");
printf(" -a - Set startup type to automatic\n");
printf(" -d <service dependency> - Can be entered multiple times\n\n");
printf("To remove the service:\n");
printf("%s -r <service name>\n\n", name);
printf("To start the service:\n");
printf("%s -s <service name> {optional params}\n", name);
printf(" Optional parameters\n");
printf(" -m <machine>\n\n");
printf("To stop the service:\n");
printf("%s -t <service name> {optional params}\n", name);
printf(" Optional parameters\n");
printf(" -m <machine>\n");
}
void main(int argc, char **argv)
{
WORD wVersionRequested;
WSADATA wsaData;
int i;
int err;
int count;
int iAction = acNoAction;
char *pServiceDisplayName = NULL;
char *pServiceName = NULL;
char *pUserName = NULL;
char *pPassword = NULL;
char *pMachine = NULL;
BOOL bAutomatic = FALSE;
char strDependancy[256] = "";
memset(strDependancy, 0, 255);
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
if(0 != err) {
fprintf(stderr, "Error connecting to winsock");
return;
}
if(LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1) {
fprintf(stderr,
"Error winsock version is %d %d \n",
LOBYTE( wsaData.wVersion ),HIBYTE( wsaData.wVersion ));
WSACleanup();
return;
}
fprintf(stderr, "Asked (and given) winsock %d.%d \n",
LOBYTE(wsaData.wVersion),
HIBYTE(wsaData.wVersion));
__try {
if(argc > 2) {
count=0;
for (i=1;i<argc;i++) {
if ((*argv[i] == '-') || (*argv[i] == '/')) {
char *cmd = argv[i];
cmd++;
if(0 == stricmp("i", cmd)) {
iAction = acInstall;
pServiceName = argv[i+1];
} else if(0 == stricmp("r", cmd)) {
iAction = acRemove;
pServiceName = argv[i+1];
} else if(0 == stricmp("s", cmd)) {
iAction = acStartTC;
pServiceName = argv[i+1];
} else if(0 == stricmp("t", cmd)) {
iAction = acStopTC;
pServiceName = argv[i+1];
} else if(0 == stricmp("u", cmd)) {
pUserName = argv[i+1];
} else if(0 == stricmp("p", cmd)) {
pPassword = argv[i+1];
} else if(0 == stricmp("m", cmd)) {
pMachine = argv[i+1];
} else if(0 == stricmp("a", cmd)) {
bAutomatic = TRUE;
} else if(0 == stricmp("n", cmd)) {
pServiceDisplayName = argv[i+1];
} else if(0 == stricmp("d", cmd)) {
memcpy(strDependancy+count, argv[i+1], strlen(argv[i+1]));
count+= strlen(argv[i+1])+1;
}
}
}
switch (iAction) {
case acInstall:
if (pServiceDisplayName == NULL) {
pServiceDisplayName = pServiceName;
}
install_service(pServiceName, pServiceDisplayName, pUserName,
pPassword, strDependancy, bAutomatic, argv[i-1]);
return;
case acRemove:
remove_service(pServiceName);
return;
case acStartTC:
start_service(pServiceName, pMachine);
return;
case acStopTC:
stop_service(pServiceName, pMachine);
return;
}
} else if(2 == argc) {
SERVICE_TABLE_ENTRY dispatchTable[] =
{
{ argv[1], (LPSERVICE_MAIN_FUNCTION)service_main },
{ NULL, NULL }
};
if(!StartServiceCtrlDispatcher(dispatchTable)) {
AddToMessageLog("StartServiceCtrlDispatcher failed.");
}
return;
}
usage_message(argv[0]);
exit(-1);
} __finally {
WSACleanup();
}
}
void WINAPI service_main(DWORD dwArgc, char **lpszArgv)
{
// register our service control handler:
//
//
sshStatusHandle = RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
if(sshStatusHandle) {
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwServiceSpecificExitCode = 0;
// report the status to the service control manager.
//
if(ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) { // wait hint
start_jk_service(lpszArgv[0]);
}
}
// try to report the stopped status to the service control manager.
//
if(sshStatusHandle) {
ReportStatusToSCMgr(SERVICE_STOPPED,
dwErr,
0);
}
}
void WINAPI service_ctrl(DWORD dwCtrlCode)
{
/*
* Handle the requested control code.
*/
switch(dwCtrlCode)
{
/*
* Stop the service.
*/
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
stop_jk_service();
break;
/*
* Update the service status.
*/
case SERVICE_CONTROL_INTERROGATE:
break;
/*
* Invalid control code, nothing to do.
*/
default:
break;
}
ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
}
BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
BOOL fResult = TRUE;
if(dwCurrentState == SERVICE_START_PENDING) {
ssStatus.dwControlsAccepted = 0;
} else {
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
}
ssStatus.dwCurrentState = dwCurrentState;
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
ssStatus.dwWaitHint = dwWaitHint;
if((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED)) {
ssStatus.dwCheckPoint = 0;
} else {
ssStatus.dwCheckPoint = dwCheckPoint++;
}
if(!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus))) {
AddToMessageLog(TEXT("SetServiceStatus"));
}
return fResult;
}
typedef WINADVAPI BOOL (WINAPI * pfnChangeServiceConfig2_t)
(SC_HANDLE hService, DWORD dwInfoLevel, LPVOID lpInfo);
void install_service(char *name,
char *dname,
char *user,
char *password,
char *deps,
BOOL bAutomatic,
char *rel_prp_file)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
char szExecPath[2048];
char szPropPath[2048];
char szTrueName[256];
char *dummy;
char *src, *dst;
dst = szTrueName;
for (src = name; *src; ++src) {
if (dst >= szTrueName + sizeof(szTrueName) - 1) {
break;
}
if (!isspace(*src) && *src != '/' && *src != '\\') {
*(dst++) = *src;
}
}
*dst = '\0';
if (0 == stricmp("", deps))
deps = NULL;
/* XXX strcat( deps, "Tcpip\0Afd\0" ); */
if(!GetFullPathName(rel_prp_file, sizeof(szPropPath) - 1, szPropPath, &dummy)) {
printf("Unable to install %s - %s\n",
name,
GetLastErrorText(szErr, sizeof(szErr)));
return;
}
if(!jk_file_exists(szPropPath)) {
printf("Unable to install %s - File [%s] does not exists\n",
name,
szPropPath);
return;
}
szExecPath[0] = '\"';
if(GetModuleFileName( NULL, szExecPath + 1, sizeof(szExecPath) - 2) == 0) {
/* Was: if(GetModuleFileName( NULL, szExecPath, sizeof(szExecPath) - 1) == 0) { */
printf("Unable to install %s - %s\n",
name,
GetLastErrorText(szErr, sizeof(szErr)));
return;
}
strcat(szExecPath, "\" ");
strcat(szExecPath, szTrueName);
schSCManager = OpenSCManager(NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS); // access required
if(schSCManager) {
schService = CreateService(schSCManager, // SCManager database
szTrueName, // name of service
dname, // name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
bAutomatic ? SERVICE_AUTO_START : SERVICE_DEMAND_START, // start type
SERVICE_ERROR_NORMAL, // error control type
szExecPath, // service's binary
NULL, // no load ordering group
NULL, // no tag identifier
deps, // dependencies
user, // account
password); // password
if(schService) {
printf("The service named %s was created. Now adding registry entries\n", name);
if(set_registry_values(schService, szTrueName, szPropPath)) {
CloseServiceHandle(schService);
} else {
printf("CreateService failed setting the private registry - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
DeleteService(schService);
CloseServiceHandle(schService);
}
} else {
printf("CreateService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
}
CloseServiceHandle(schSCManager);
} else {
printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
}
}
void remove_service(char *name)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
char szNameBuff[256];
DWORD lenNameBuff = 256;
char *szTrueName = name;
schSCManager = OpenSCManager(NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS ); // access required
if(schSCManager) {
if (GetServiceKeyName(schSCManager, name, szNameBuff, &lenNameBuff)) {
szTrueName = szNameBuff;
}
schService = OpenService(schSCManager, szTrueName, SERVICE_ALL_ACCESS);
if(schService) {
// try to stop the service
if(ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus )) {
printf("Stopping %s.", name);
Sleep(1000);
while(QueryServiceStatus(schService, &ssStatus )) {
if(ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
printf(".");
Sleep(1000);
} else {
break;
}
}
if(ssStatus.dwCurrentState == SERVICE_STOPPED) {
printf("\n%s stopped.\n", name);
} else {
printf("\n%s failed to stop.\n", name);
}
}
// now remove the service
if(DeleteService(schService)) {
printf("%s removed.\n", name);
} else {
printf("DeleteService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
}
CloseServiceHandle(schService);
} else {
printf("OpenService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
}
CloseServiceHandle(schSCManager);
} else {
printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
}
}
void start_service(char *name, char *machine)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
schSCManager = OpenSCManager(machine, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS); // access required
if(schSCManager) {
schService = OpenService(schSCManager, name, SERVICE_ALL_ACCESS);
if(schService) {
// try to start the service
if(StartService(schService, 0, NULL)) {
printf("Starting %s.", name);
Sleep(1000);
while(QueryServiceStatus(schService, &ssStatus )) {
if(ssStatus.dwCurrentState == SERVICE_START_PENDING) {
printf(".");
Sleep(1000);
} else {
break;
}
}
if(ssStatus.dwCurrentState == SERVICE_RUNNING) {
printf("\n%s started.\n", name);
} else {
printf("\n%s failed to start.\n", name);
}
}
else
printf("StartService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
CloseServiceHandle(schService);
} else {
printf("OpenService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
}
CloseServiceHandle(schSCManager);
} else {
printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
}
}
void stop_service(char *name, char *machine)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
schSCManager = OpenSCManager(machine, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS); // access required
if(schSCManager) {
schService = OpenService(schSCManager, name, SERVICE_ALL_ACCESS);
if(schService) {
// try to stop the service
if(ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus )) {
printf("Stopping %s.", name);
Sleep(1000);
while(QueryServiceStatus(schService, &ssStatus )) {
if(ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
printf(".");
Sleep(1000);
} else {
break;
}
}
if(ssStatus.dwCurrentState == SERVICE_STOPPED) {
printf("\n%s stopped.\n", name);
} else {
printf("\n%s failed to stop.\n", name);
}
}
else
printf("StopService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
CloseServiceHandle(schService);
} else {
printf("OpenService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
}
CloseServiceHandle(schSCManager);
} else {
printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
}
}
static int set_registry_values(SC_HANDLE schService, char *name,
char *prp_file)
{
char tag[1024];
HKEY hk;
int rc;
/* Api based */
HANDLE hAdvApi32;
char *szDescription = "Jakarta Tomcat Server";
pfnChangeServiceConfig2_t pfnChangeServiceConfig2;
if((hAdvApi32 = GetModuleHandle("advapi32.dll"))
&& ((pfnChangeServiceConfig2 = (pfnChangeServiceConfig2_t)
GetProcAddress(hAdvApi32, "ChangeServiceConfig2A")))) {
(void) pfnChangeServiceConfig2(schService, // Service Handle
1, // SERVICE_CONFIG_DESCRIPTION
&szDescription);
} else {
char value[2024];
rc = JK_FALSE;
strcpy(tag, BASE_REGISTRY_LOCATION);
strcat(tag, name);
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
tag,
(DWORD)0,
KEY_WRITE | KEY_READ,
&hk)) {
rc = get_registry_config_parameter(hk,
IMAGE_NAME,
value,
sizeof(value));
if(rc) {
strcat(value, " ");
strcat(value, name);
rc = set_registry_config_parameter(hk,
IMAGE_NAME,
value);
if(rc) {
printf("Registry values were added\n");
printf("If you have already updated wrapper.properties you may start the %s"
"service by executing \"jk_nt_service -s %s\" from the command prompt\n",
name,
name);
}
}
RegCloseKey(hk);
}
if(!rc) {
printf("Error: Failed to update the service command line - %s\n",
GetLastErrorText(szErr, sizeof(szErr)));
}
}
strcpy(tag, BASE_REGISTRY_LOCATION);
strcat(tag, name);
strcat(tag, "\\");
strcat(tag, PARAMS_LOCATION);
rc = create_registry_key(tag, &hk);
if(rc) {
rc = set_registry_config_parameter(hk, PRP_LOCATION, prp_file);
if(!rc) {
printf("Error: Can not create value [%s] - %s\n",
PRP_LOCATION,
GetLastErrorText(szErr, sizeof(szErr)));
}
RegCloseKey(hk);
} else {
printf("Error: Can not create key [%s] - %s\n",
tag,
GetLastErrorText(szErr, sizeof(szErr)));
}
return rc;
}
static void start_jk_service(char *name)
{
/*
* report the status to the service control manager.
*/
if(ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) { // wait hint
/*
* create the event object. The control handler function signals
* this event when it receives the "stop" control code.
*/
hServerStopEvent = CreateEvent(NULL, // no security attributes
TRUE, // manual reset event
FALSE, // not-signalled
NULL); // no name
if(hServerStopEvent) {
if(ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
20000)) { // wait hint
HANDLE hTomcat = NULL;
char szNameBuff[256];
DWORD lenNameBuff = 256;
char *szTrueName = name;
SC_HANDLE schSCManager;
int rc;
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS );
if(schSCManager) {
if (GetServiceKeyName(schSCManager, name, szNameBuff, &lenNameBuff)) {
szTrueName = szNameBuff;
}
CloseServiceHandle(schSCManager);
}
rc = start_tomcat(szTrueName, &hTomcat);
if(rc && ReportStatusToSCMgr(SERVICE_RUNNING, // service state
NO_ERROR, // exit code
0)) { // wait hint
HANDLE waitfor[] = { hServerStopEvent, hTomcat};
DWORD dwIndex = WaitForMultipleObjects(2, waitfor, FALSE, INFINITE);
switch(dwIndex) {
case WAIT_OBJECT_0:
/*
* Stop order arrived
*/
ResetEvent(hServerStopEvent);
stop_tomcat(name, shutdown_port, shutdown_protocol,
shutdown_secret, hTomcat);
break;
case (WAIT_OBJECT_0 + 1):
/*
* Tomcat died !!!
*/
CloseHandle(hServerStopEvent);
CloseHandle(hTomcat);
exit(0); // exit ungracefully so
// Service Control Manager
// will attempt a restart.
break;
default:
/*
* some error...
* close the servlet container and exit
*/
stop_tomcat(name, shutdown_port, shutdown_protocol,
shutdown_secret, hTomcat);
}
CloseHandle(hServerStopEvent);
CloseHandle(hTomcat);
}
}
}
}
if(hServerStopEvent) {
CloseHandle(hServerStopEvent);
}
}
static void stop_jk_service(void)
{
if(hServerStopEvent) {
SetEvent(hServerStopEvent);
}
}
static void AddToMessageLog(char *lpszMsg)
{
char szMsg[2048];
HANDLE hEventSource;
char * lpszStrings[2];
printf("Error: %s\n", lpszMsg);
dwErr = GetLastError();
hEventSource = RegisterEventSource(NULL, "Jakrta - Tomcat");
sprintf(szMsg, "%s error: %d", "Jakrta - Tomcat", dwErr);
lpszStrings[0] = szMsg;
lpszStrings[1] = lpszMsg;
if(hEventSource != NULL) {
ReportEvent(hEventSource, // handle of event source
EVENTLOG_ERROR_TYPE, // event type
0, // event category
0, // event ID
NULL, // current user's SID
2, // strings in lpszStrings
0, // no bytes of raw data
lpszStrings, // array of error strings
NULL); // no raw data
DeregisterEventSource(hEventSource);
}
}
//
// FUNCTION: GetLastErrorText
//
// PURPOSE: copies error message text to string
//
// PARAMETERS:
// lpszBuf - destination buffer
// dwSize - size of buffer
//
// RETURN VALUE:
// destination buffer
//
// COMMENTS:
//
char *GetLastErrorText( char *lpszBuf, DWORD dwSize )
{
DWORD dwRet;
char *lpszTemp = NULL;
dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
GetLastError(),
LANG_NEUTRAL,
(char *)&lpszTemp,
0,
NULL);
// supplied buffer is not long enough
if(!dwRet || ((long)dwSize < (long)dwRet+14)) {
lpszBuf[0] = '\0';
} else {
lpszTemp[lstrlen(lpszTemp)-2] = '\0'; //remove cr and newline character
sprintf(lpszBuf, "%s (0x%x)", lpszTemp, GetLastError());
}
if(lpszTemp) {
LocalFree((HLOCAL) lpszTemp );
}
return lpszBuf;
}
static void stop_tomcat(char *name,
int port,
const char *protocol,
char *secret,
HANDLE hTomcat)
{
struct sockaddr_in in;
if(strcasecmp(protocol, "cmd") == 0 ) {
exec_cmd( name, hTomcat, shutdown_cmd);
/* XXX sleep 100 */
TerminateProcess(hTomcat, 0);
return;
}
if(jk_resolve("localhost", port, &in)) {
int sd = jk_open_socket(&in, JK_TRUE, 0, NULL);
if(sd >0) {
int rc = JK_FALSE;
if(strcasecmp(protocol, "catalina") == 0 ) {
char len;
if( secret==NULL )
secret="SHUTDOWN";
len=strlen( secret );
rc = send(sd, secret, len , 0);
if(len == rc) {
rc = JK_TRUE;
}
} else if(!strcasecmp(protocol, "ajp13")) {
jk_pool_t pool;
jk_msg_buf_t *msg = NULL;
jk_pool_atom_t buf[TINY_POOL_SIZE];
jk_open_pool(&pool, buf, sizeof(buf));
msg = jk_b_new(&pool);
jk_b_set_buffer_size(msg, 512);
rc = ajp13_marshal_shutdown_into_msgb(msg,
&pool,
NULL);
if( secret!=NULL ) {
/** will work with old clients, as well as new
*/
rc = jk_b_append_string(msg, secret);
}
if(rc) {
jk_b_end(msg, AJP13_PROTO);
if(0 > jk_tcp_socket_sendfull(sd,
jk_b_get_buff(msg),
jk_b_get_len(msg))) {
rc = JK_FALSE;
}
}
} else {
char b[] = {(char)254, (char)15};
rc = send(sd, b, 2, 0);
if(2 == rc) {
rc = JK_TRUE;
}
}
jk_close_socket(sd);
if(JK_TRUE == rc) {
if(WAIT_OBJECT_0 == WaitForSingleObject(hTomcat, 30*1000)) {
return;
}
}
}
}
TerminateProcess(hTomcat, 0);
}
static int exec_cmd(const char *name, HANDLE *hTomcat, char *cmdLine)
{
char tag[1024];
HKEY hk;
strcpy(tag, BASE_REGISTRY_LOCATION);
strcat(tag, name);
strcat(tag, "\\");
strcat(tag, PARAMS_LOCATION);
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
tag,
(DWORD)0,
KEY_READ,
&hk)) {
char prp_file[2048];
if(get_registry_config_parameter(hk,
PRP_LOCATION,
prp_file,
sizeof(prp_file))) {
jk_map_t *init_map;
if(map_alloc(&init_map)) {
if(map_read_properties(init_map, prp_file)) {
jk_tomcat_startup_data_t data;
jk_pool_t p;
jk_pool_atom_t buf[HUGE_POOL_SIZE];
jk_open_pool(&p, buf, sizeof(buf));
if(read_startup_data(init_map, &data, &p)) {
STARTUPINFO startupInfo;
PROCESS_INFORMATION processInformation;
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
if(data.extra_path) {
jk_append_libpath(&p, data.extra_path);
}
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
startupInfo.lpTitle = "Jakarta Tomcat";
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdInput = NULL;
startupInfo.hStdOutput = CreateFile(data.stdout_file,
GENERIC_WRITE,
FILE_SHARE_READ,
&sa,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
SetFilePointer(startupInfo.hStdOutput,
0,
NULL,
FILE_END);
startupInfo.hStdError = CreateFile(data.stderr_file,
GENERIC_WRITE,
FILE_SHARE_READ,
&sa,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
SetFilePointer(startupInfo.hStdError,
0,
NULL,
FILE_END);
memset(&processInformation, 0, sizeof(processInformation));
if( cmdLine==NULL )
cmdLine=data.cmd_line;
printf(cmdLine);
if(CreateProcess(data.java_bin,
cmdLine,
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE,
NULL,
data.tomcat_home,
&startupInfo,
&processInformation)){
*hTomcat = processInformation.hProcess;
CloseHandle(processInformation.hThread);
CloseHandle(startupInfo.hStdOutput);
CloseHandle(startupInfo.hStdError);
shutdown_port = data.shutdown_port;
shutdown_secret = data.shutdown_secret;
shutdown_protocol = strdup(data.shutdown_protocol);
shutdown_cmd = strdup(data.stop_cmd);
return JK_TRUE;
} else {
printf("Error: Can not create new process - %s\n",
GetLastErrorText(szErr, sizeof(szErr)));
}
}
}
}
map_free(&init_map);
}
RegCloseKey(hk);
}
return JK_FALSE;
}
static int start_tomcat(const char *name, HANDLE *hTomcat)
{
return exec_cmd( name, hTomcat, NULL );
}
static int create_registry_key(const char *tag,
HKEY *key)
{
LONG lrc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
tag,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
key,
NULL);
if(ERROR_SUCCESS != lrc) {
return JK_FALSE;
}
return JK_TRUE;
}
static int set_registry_config_parameter(HKEY hkey,
const char *tag,
char *value)
{
LONG lrc;
lrc = RegSetValueEx(hkey,
tag,
0,
REG_SZ,
value,
strlen(value));
if(ERROR_SUCCESS != lrc) {
return JK_FALSE;
}
return JK_TRUE;
}
static int get_registry_config_parameter(HKEY hkey,
const char *tag,
char *b,
DWORD sz)
{
DWORD type = 0;
LONG lrc;
lrc = RegQueryValueEx(hkey,
tag,
(LPDWORD)0,
&type,
(LPBYTE)b,
&sz);
if(ERROR_SUCCESS != lrc) {
return JK_FALSE;
}
b[sz] = '\0';
return JK_TRUE;
}
static int read_startup_data(jk_map_t *init_map,
jk_tomcat_startup_data_t *data,
jk_pool_t *p)
{
data->classpath = NULL;
data->tomcat_home = NULL;
data->stdout_file = NULL;
data->stderr_file = NULL;
data->java_bin = NULL;
data->extra_path = NULL;
data->tomcat_class = NULL;
data->server_file = NULL;
/* All this is wrong - you just need to configure cmd_line */
/* Optional - you may have cmd_line defined */
data->server_file = map_get_string(init_map,
"wrapper.server_xml",
NULL);
data->classpath = map_get_string(init_map,
"wrapper.class_path",
NULL);
data->tomcat_home = map_get_string(init_map,
"wrapper.tomcat_home",
NULL);
data->java_bin = map_get_string(init_map,
"wrapper.javabin",
NULL);
data->tomcat_class = map_get_string(init_map,
"wrapper.startup_class",
"org.apache.tomcat.startup.Tomcat");
data->cmd_line = map_get_string(init_map,
"wrapper.cmd_line",
NULL);
data->stop_cmd = map_get_string(init_map,
"wrapper.stop_cmd",
NULL);
if(NULL == data->cmd_line &&
( (NULL == data->tomcat_class) ||
(NULL == data->server_file) ||
(NULL == data->tomcat_home) ||
(NULL == data->java_bin) )) {
return JK_FALSE;
}
if(NULL == data->cmd_line) {
data->cmd_line = (char *)jk_pool_alloc(p, (20 +
strlen(data->java_bin) +
strlen(" -classpath ") +
strlen(data->classpath) +
strlen(data->tomcat_class) +
strlen(" -home ") +
strlen(data->tomcat_home) +
strlen(" -config ") +
strlen(data->server_file)
) * sizeof(char));
if(NULL == data->cmd_line) {
return JK_FALSE;
}
strcpy(data->cmd_line, data->java_bin);
strcat(data->cmd_line, " -classpath ");
strcat(data->cmd_line, data->classpath);
strcat(data->cmd_line, " ");
strcat(data->cmd_line, data->tomcat_class);
strcat(data->cmd_line, " -home ");
strcat(data->cmd_line, data->tomcat_home);
strcat(data->cmd_line, " -config ");
strcat(data->cmd_line, data->server_file);
}
data->shutdown_port = map_get_int(init_map,
"wrapper.shutdown_port",
8007);
data->shutdown_secret = map_get_string(init_map,
"wrapper.shutdown_secret", NULL );
data->shutdown_protocol = map_get_string(init_map,
"wrapper.shutdown_protocol",
AJP12_TAG);
data->extra_path = map_get_string(init_map,
"wrapper.ld_path",
NULL);
data->stdout_file = map_get_string(init_map,
"wrapper.stdout",
NULL);
if(NULL == data->stdout_file && NULL == data->tomcat_home ) {
return JK_FALSE;
}
if(NULL == data->stdout_file) {
data->stdout_file = jk_pool_alloc(p, strlen(data->tomcat_home) + 2 + strlen("\\stdout.log"));
strcpy(data->stdout_file, data->tomcat_home);
strcat(data->stdout_file, "\\stdout.log");
}
data->stderr_file = map_get_string(init_map,
"wrapper.stderr",
NULL);
if(NULL == data->stderr_file) {
data->stderr_file = jk_pool_alloc(p, strlen(data->tomcat_home) + 2 + strlen("\\stderr.log"));
strcpy(data->stderr_file, data->tomcat_home);
strcat(data->stderr_file, "\\stderr.log");
}
return JK_TRUE;
}