bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / tomcat-connectors-1.2.32-src / native / nt_service / jk_nt_service.c
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 /***************************************************************************
19  * Description: NT System service for Tomcat                       *
20  * Author:      Gal Shachor <shachor@il.ibm.com>                           *
21  *              Dave Oxley <Dave@JungleMoss.com>                           *
22  * Version:     $Revision: 756058 $                                           *
23  ***************************************************************************/
24
25 #include "jk_global.h"
26 #include "jk_util.h"
27 #include "jk_ajp13.h"
28 #include "jk_connect.h"
29 #include <windows.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <process.h>
33
34 #define AJP12_TAG              ("ajp12")
35 #define AJP13_TAG              ("ajp13")
36 #define BASE_REGISTRY_LOCATION ("SYSTEM\\CurrentControlSet\\Services\\")
37 #define IMAGE_NAME             ("ImagePath")
38 #define PARAMS_LOCATION        ("Parameters")
39 #define PRP_LOCATION           ("PropertyFile")
40
41 // internal variables
42 static SERVICE_STATUS          ssStatus;       // current status of the service
43 static SERVICE_STATUS_HANDLE   sshStatusHandle;
44 static DWORD                   dwErr = 0;
45 static char                    szErr[1024] = "";
46 static HANDLE                  hServerStopEvent = NULL;
47 static int                     shutdown_port;
48 static char                    *shutdown_protocol = AJP12_TAG;
49 static char                    *shutdown_secret = NULL;
50 static char                    *shutdown_cmd=NULL;
51
52 typedef enum ActionEnum
53 {   acNoAction  = 0,
54     acInstall   = 1,
55     acRemove    = 2,
56     acStartTC   = 3,
57     acStopTC    = 4
58 }   ActionEnum;
59
60
61 struct jk_tomcat_startup_data {
62     char *cmd_line; /* Start command line */
63     char *stdout_file;
64     char *stderr_file;
65     char *extra_path;
66     char *tomcat_home;
67     char *java_bin;
68
69     char *shutdown_protocol;
70     /* for cmd */
71     char *stop_cmd;
72     /* For ajp13/ajp12/catalina */
73     int  shutdown_port;
74     char *shutdown_secret;
75
76     /* Optional/not needed */
77     char *classpath;
78     char *tomcat_class;
79     char *server_file;
80 };
81
82 typedef struct jk_tomcat_startup_data jk_tomcat_startup_data_t;
83
84 // internal function prototypes
85 static void WINAPI service_ctrl(DWORD dwCtrlCode);
86 static void WINAPI service_main(DWORD dwArgc, 
87                                 char **lpszArgv);
88 static void install_service(char *name,
89                             char *dname,
90                             char *user, 
91                             char *password, 
92                             char *deps, 
93                             BOOL bAutomatic, 
94                             char *rel_prp_file);
95 static void remove_service(char *name);
96 static void start_service(char *name,
97                           char *machine);
98 static void stop_service(char *name,
99                          char *machine);
100 static char *GetLastErrorText(char *lpszBuf, DWORD dwSize);
101 static void AddToMessageLog(char *lpszMsg);
102 static BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
103                                 DWORD dwWin32ExitCode,
104                                 DWORD dwWaitHint);
105 static void start_jk_service(char *name);
106 static void stop_jk_service(void);
107 static int set_registry_values(SC_HANDLE   schService, char *name, 
108                                char *prp_file);
109 static int create_registry_key(const char *tag, 
110                                HKEY *key);
111 static int set_registry_config_parameter(HKEY hkey, 
112                                          const char *tag, 
113                                          char *value);
114 static int get_registry_config_parameter(HKEY hkey, 
115                                          const char *tag,  
116                                          char *b, DWORD sz);
117 static int start_tomcat(const char *name, 
118                         HANDLE *hTomcat);
119 static void stop_tomcat(char *name,
120                         int port, 
121                         const char *protocol,
122                         char *secret,
123                         HANDLE hTomcat);
124 static int read_startup_data(jk_map_t *init_map, 
125                              jk_tomcat_startup_data_t *data, 
126                              jk_pool_t *p);
127 static int exec_cmd(const char *name, HANDLE *hTomcat, char *cmdLine);
128
129 static void usage_message(const char *name)
130 {
131     printf("%s - Usage:\n\n", name);
132     printf("To install the service:\n");
133     printf("%s -i <service name> {optional params} <config properties file>\n", name);
134     printf("    Optional parameters\n");
135     printf("        -u <user name> - In the form DomainName\\UserName (.\\UserName for local)\n");
136     printf("        -n <service display name> - In quotes if contains non-lphanumeric chars\n");
137     printf("        -p <user password>\n");
138     printf("        -a - Set startup type to automatic\n");
139     printf("        -d <service dependency> - Can be entered multiple times\n\n");
140     printf("To remove the service:\n");
141     printf("%s -r <service name>\n\n", name);
142     printf("To start the service:\n");
143     printf("%s -s <service name> {optional params}\n", name);
144     printf("    Optional parameters\n");
145     printf("        -m <machine>\n\n");
146     printf("To stop the service:\n");
147     printf("%s -t <service name> {optional params}\n", name);
148     printf("    Optional parameters\n");
149     printf("        -m <machine>\n");
150 }
151
152 void main(int argc, char **argv)
153 {
154     WORD wVersionRequested;
155     WSADATA wsaData;
156     int i;
157     int err;
158     int count;
159     int iAction = acNoAction;
160     char *pServiceDisplayName = NULL;
161     char *pServiceName = NULL;
162     char *pUserName = NULL;
163     char *pPassword = NULL;
164     char *pMachine = NULL;
165     BOOL bAutomatic = FALSE;
166     char strDependancy[256] = "";
167
168     memset(strDependancy, 0, 255);
169
170     wVersionRequested = MAKEWORD(1, 1); 
171     err = WSAStartup(wVersionRequested, &wsaData);
172     if(0 != err) {
173         fprintf(stderr, "Error connecting to winsock");
174         return;
175     } 
176
177     if(LOBYTE( wsaData.wVersion ) != 1 || 
178        HIBYTE( wsaData.wVersion ) != 1)  {
179         fprintf(stderr, 
180                 "Error winsock version is %d %d \n", 
181                 LOBYTE( wsaData.wVersion ),HIBYTE( wsaData.wVersion ));
182         WSACleanup();
183         return; 
184     } 
185
186     fprintf(stderr, "Asked (and given) winsock %d.%d \n", 
187                     LOBYTE(wsaData.wVersion),
188                     HIBYTE(wsaData.wVersion));
189
190     __try {
191         if(argc > 2) {
192             count=0;
193             for (i=1;i<argc;i++) {
194                 if ((*argv[i] == '-') || (*argv[i] == '/')) {
195                     char *cmd = argv[i];
196                     cmd++;
197                     if(0 == stricmp("i", cmd)) {
198                         iAction = acInstall;
199                         pServiceName = argv[i+1];
200                     } else if(0 == stricmp("r", cmd)) {
201                         iAction = acRemove;
202                         pServiceName = argv[i+1];
203                     } else if(0 == stricmp("s", cmd)) {
204                         iAction = acStartTC;
205                         pServiceName = argv[i+1];
206                     } else if(0 == stricmp("t", cmd)) {
207                         iAction = acStopTC;
208                         pServiceName = argv[i+1];
209                     } else if(0 == stricmp("u", cmd)) {
210                         pUserName = argv[i+1];
211                     } else if(0 == stricmp("p", cmd)) {
212                         pPassword = argv[i+1];
213                     } else if(0 == stricmp("m", cmd)) {
214                         pMachine = argv[i+1];
215                     } else if(0 == stricmp("a", cmd)) {
216                         bAutomatic = TRUE;
217                     } else if(0 == stricmp("n", cmd)) {
218                         pServiceDisplayName = argv[i+1];
219                     } else if(0 == stricmp("d", cmd)) {
220                         memcpy(strDependancy+count, argv[i+1], strlen(argv[i+1]));
221                         count+= strlen(argv[i+1])+1;
222                     }
223                 }
224             }
225             switch (iAction) {
226             case acInstall:
227                 if (pServiceDisplayName == NULL) {
228                     pServiceDisplayName = pServiceName;
229                 }
230                 install_service(pServiceName, pServiceDisplayName, pUserName,
231                                 pPassword, strDependancy, bAutomatic, argv[i-1]);
232                 return;
233             case acRemove:
234                 remove_service(pServiceName);
235                 return;
236             case acStartTC:
237                 start_service(pServiceName, pMachine);
238                 return;
239             case acStopTC:
240                 stop_service(pServiceName, pMachine);
241                 return;
242             }
243         } else if(2  == argc) {
244
245             SERVICE_TABLE_ENTRY dispatchTable[] =
246             {
247                 { argv[1], (LPSERVICE_MAIN_FUNCTION)service_main },
248                 { NULL, NULL }
249             };
250
251             if(!StartServiceCtrlDispatcher(dispatchTable)) {
252                 AddToMessageLog("StartServiceCtrlDispatcher failed.");
253             }
254             return;
255         } 
256
257         usage_message(argv[0]);
258         exit(-1);
259     } __finally {
260         WSACleanup();
261     }
262 }
263
264 void WINAPI service_main(DWORD dwArgc, char **lpszArgv)
265 {
266     // register our service control handler:
267     //
268     //
269     sshStatusHandle = RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
270
271     if(sshStatusHandle) {
272
273         ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
274         ssStatus.dwServiceSpecificExitCode = 0;
275
276         // report the status to the service control manager.
277         //
278         if(ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
279                                 NO_ERROR,              // exit code
280                                 3000)) {                 // wait hint    
281             start_jk_service(lpszArgv[0]);
282         }
283     }
284
285     // try to report the stopped status to the service control manager.
286     //
287     if(sshStatusHandle) {
288         ReportStatusToSCMgr(SERVICE_STOPPED,
289                             dwErr,
290                             0);
291     }
292 }
293
294
295 void WINAPI service_ctrl(DWORD dwCtrlCode)
296 {
297     /*
298      * Handle the requested control code.
299      */
300     switch(dwCtrlCode)
301     {
302         /*
303          * Stop the service.
304          */
305         case SERVICE_CONTROL_SHUTDOWN:
306         case SERVICE_CONTROL_STOP:
307             ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
308             stop_jk_service();
309             break;
310
311         /*
312          * Update the service status.
313          */
314         case SERVICE_CONTROL_INTERROGATE:
315             break;
316
317         /*
318          * Invalid control code, nothing to do.
319          */
320         default:
321             break;
322
323     }
324
325     ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
326
327 }
328
329 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
330                          DWORD dwWin32ExitCode,
331                          DWORD dwWaitHint)
332 {
333     static DWORD dwCheckPoint = 1;
334     BOOL fResult = TRUE;
335
336     if(dwCurrentState == SERVICE_START_PENDING) {
337         ssStatus.dwControlsAccepted = 0;
338     } else {
339         ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
340     }
341
342     ssStatus.dwCurrentState = dwCurrentState;
343     ssStatus.dwWin32ExitCode = dwWin32ExitCode;
344     ssStatus.dwWaitHint = dwWaitHint;
345
346     if((dwCurrentState == SERVICE_RUNNING) ||
347        (dwCurrentState == SERVICE_STOPPED)) {
348         ssStatus.dwCheckPoint = 0;
349     } else {
350         ssStatus.dwCheckPoint = dwCheckPoint++;
351     }
352
353     if(!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus))) {
354         AddToMessageLog(TEXT("SetServiceStatus"));
355     }
356
357     return fResult;
358 }
359
360 typedef WINADVAPI BOOL (WINAPI * pfnChangeServiceConfig2_t)
361                        (SC_HANDLE hService, DWORD dwInfoLevel, LPVOID lpInfo);
362
363
364 void install_service(char *name, 
365                      char *dname, 
366                      char *user, 
367                      char *password, 
368                      char *deps, 
369                      BOOL bAutomatic,
370                      char *rel_prp_file)
371 {
372     SC_HANDLE   schService;
373     SC_HANDLE   schSCManager;
374     char        szExecPath[2048];
375     char        szPropPath[2048];
376     char        szTrueName[256];
377     char        *dummy;
378     char        *src, *dst;
379
380     dst = szTrueName;
381     for (src = name; *src; ++src) {
382         if (dst >= szTrueName + sizeof(szTrueName) - 1) {
383             break;
384         }
385         if (!isspace((int)(*src)) && *src != '/' && *src != '\\') {
386             *(dst++) = *src;
387         }
388     }
389     *dst = '\0';
390
391     if (0 == stricmp("", deps))
392         deps = NULL;
393
394     /* XXX strcat( deps, "Tcpip\0Afd\0" ); */
395     
396     if(!GetFullPathName(rel_prp_file, sizeof(szPropPath) - 1, szPropPath, &dummy)) {
397         printf("Unable to install %s - %s\n", 
398                name, 
399                GetLastErrorText(szErr, sizeof(szErr)));
400         return;
401     }
402
403     if(!jk_file_exists(szPropPath)) {
404         printf("Unable to install %s - File [%s] does not exists\n", 
405                name, 
406                szPropPath);
407         return;
408     }
409
410     szExecPath[0] = '\"';
411     if(GetModuleFileName( NULL, szExecPath + 1, sizeof(szExecPath) - 2) == 0) {
412         /* Was: if(GetModuleFileName( NULL, szExecPath, sizeof(szExecPath) - 1) == 0) { */
413         printf("Unable to install %s - %s\n", 
414                name, 
415                GetLastErrorText(szErr, sizeof(szErr)));
416         return;
417     }
418     strcat(szExecPath, "\" ");
419     strcat(szExecPath, szTrueName);
420
421
422     schSCManager = OpenSCManager(NULL,     // machine (NULL == local)
423                                  NULL,     // database (NULL == default)
424                                  SC_MANAGER_ALL_ACCESS);   // access required                       
425     if(schSCManager) {
426
427         schService = CreateService(schSCManager, // SCManager database
428                                    szTrueName,   // name of service
429                                    dname,         // name to display
430                                    SERVICE_ALL_ACCESS, // desired access
431                                    SERVICE_WIN32_OWN_PROCESS,  // service type
432                                    bAutomatic ? SERVICE_AUTO_START : SERVICE_DEMAND_START,       // start type
433                                    SERVICE_ERROR_NORMAL,       // error control type
434                                    szExecPath,                 // service's binary
435                                    NULL,                       // no load ordering group
436                                    NULL,                       // no tag identifier
437                                    deps,                       // dependencies
438                                    user,                       // account
439                                    password);                  // password
440
441         if(schService) {
442             
443             printf("The service named %s was created. Now adding registry entries\n", name);
444             
445             if(set_registry_values(schService, szTrueName, szPropPath)) {
446                 CloseServiceHandle(schService);
447             } else {
448                 printf("CreateService failed setting the private registry - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
449                 DeleteService(schService);
450                 CloseServiceHandle(schService);
451             }
452         } else {
453             printf("CreateService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
454         }
455
456         CloseServiceHandle(schSCManager);
457     } else { 
458         printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
459     }
460 }
461
462 void remove_service(char *name)
463 {
464     SC_HANDLE   schService;
465     SC_HANDLE   schSCManager;
466     char        szNameBuff[256];
467     DWORD       lenNameBuff = 256;
468     char        *szTrueName = name;
469
470     schSCManager = OpenSCManager(NULL,          // machine (NULL == local)
471                                  NULL,          // database (NULL == default)
472                                  SC_MANAGER_ALL_ACCESS );  // access required
473                         
474     if(schSCManager) {
475         if (GetServiceKeyName(schSCManager, name, szNameBuff, &lenNameBuff)) {
476             szTrueName = szNameBuff;
477         }
478         schService = OpenService(schSCManager, szTrueName, SERVICE_ALL_ACCESS);
479
480         if(schService) {
481             // try to stop the service
482             if(ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus )) {
483                 printf("Stopping %s.", name);
484                 Sleep(1000);
485
486                 while(QueryServiceStatus(schService, &ssStatus )) {
487                     if(ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
488                         printf(".");
489                         Sleep(1000);
490                     } else {
491                         break;
492                     }
493                 }
494
495                 if(ssStatus.dwCurrentState == SERVICE_STOPPED) {
496                     printf("\n%s stopped.\n", name);
497                 } else {
498                     printf("\n%s failed to stop.\n", name);
499                 }
500             }
501
502             // now remove the service
503             if(DeleteService(schService)) {
504                 printf("%s removed.\n", name);
505             } else {
506                 printf("DeleteService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
507             }
508
509             CloseServiceHandle(schService);
510         } else {
511             printf("OpenService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
512         }
513
514         CloseServiceHandle(schSCManager);
515     } else {
516         printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
517     }
518 }
519
520 void start_service(char *name, char *machine)
521 {
522     SC_HANDLE   schService;
523     SC_HANDLE   schSCManager;
524
525     schSCManager = OpenSCManager(machine,  // machine (NULL == local)
526                                  NULL,     // database (NULL == default)
527                                  SC_MANAGER_ALL_ACCESS);   // access required                       
528
529     if(schSCManager) {
530         schService = OpenService(schSCManager, name, SERVICE_ALL_ACCESS);
531  
532        if(schService) {
533             // try to start the service
534             if(StartService(schService, 0, NULL)) {
535                 printf("Starting %s.", name);
536                 Sleep(1000);
537
538                 while(QueryServiceStatus(schService, &ssStatus )) {
539                     if(ssStatus.dwCurrentState == SERVICE_START_PENDING) {
540                         printf(".");
541                         Sleep(1000);
542                     } else {
543                         break;
544                     }
545                 }
546
547                 if(ssStatus.dwCurrentState == SERVICE_RUNNING) {
548                     printf("\n%s started.\n", name);
549                 } else {
550                     printf("\n%s failed to start.\n", name);
551                 }
552             }
553             else
554                 printf("StartService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
555
556             CloseServiceHandle(schService);
557         } else {
558             printf("OpenService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
559         }
560
561         CloseServiceHandle(schSCManager);
562     } else {
563         printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
564     }
565 }
566
567 void stop_service(char *name, char *machine)
568 {
569     SC_HANDLE   schService;
570     SC_HANDLE   schSCManager;
571
572     schSCManager = OpenSCManager(machine,  // machine (NULL == local)
573                                  NULL,     // database (NULL == default)
574                                  SC_MANAGER_ALL_ACCESS);   // access required                       
575
576     if(schSCManager) {
577         schService = OpenService(schSCManager, name, SERVICE_ALL_ACCESS);
578
579         if(schService) {
580             // try to stop the service
581             if(ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus )) {
582                 printf("Stopping %s.", name);
583                 Sleep(1000);
584
585                 while(QueryServiceStatus(schService, &ssStatus )) {
586                     if(ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
587                         printf(".");
588                         Sleep(1000);
589                     } else {
590                         break;
591                     }
592                 }
593
594                 if(ssStatus.dwCurrentState == SERVICE_STOPPED) {
595                     printf("\n%s stopped.\n", name);
596                 } else {
597                     printf("\n%s failed to stop.\n", name);
598                 }
599             }
600             else
601                 printf("StopService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
602
603             CloseServiceHandle(schService);
604         } else {
605             printf("OpenService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
606         }
607
608         CloseServiceHandle(schSCManager);
609     } else {
610         printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
611     }
612 }
613
614 static int set_registry_values(SC_HANDLE   schService, char *name, 
615                                char *prp_file)
616 {
617     char  tag[1024];
618     HKEY  hk;
619     int rc;
620     /* Api based */
621     HANDLE hAdvApi32;
622     char *szDescription = "Tomcat Server";
623     pfnChangeServiceConfig2_t pfnChangeServiceConfig2;
624             
625     if((hAdvApi32 = GetModuleHandle("advapi32.dll"))
626        && ((pfnChangeServiceConfig2 = (pfnChangeServiceConfig2_t)
627             GetProcAddress(hAdvApi32, "ChangeServiceConfig2A")))) {
628         (void) pfnChangeServiceConfig2(schService, // Service Handle
629                                        1,          // SERVICE_CONFIG_DESCRIPTION
630                                        &szDescription);
631     } else {
632         char value[2024];
633
634         rc = JK_FALSE;
635
636         strcpy(tag, BASE_REGISTRY_LOCATION);
637         strcat(tag, name);
638         
639         if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
640                                          tag,
641                                          (DWORD)0,         
642                                          KEY_WRITE | KEY_READ,
643                                          &hk)) {
644             rc = get_registry_config_parameter(hk,
645                                                IMAGE_NAME, 
646                                                value,
647                                                sizeof(value));
648             if(rc) {
649                 strcat(value, " ");
650                 strcat(value, name);
651                 rc = set_registry_config_parameter(hk,
652                                                    IMAGE_NAME, 
653                                                    value);
654                 if(rc) {
655                     printf("Registry values were added\n");
656                     printf("If you have already updated wrapper.properties you may start the %s"
657                            "service by executing \"jk_nt_service -s %s\" from the command prompt\n",
658                            name,
659                            name);                    
660                 }
661             }
662             RegCloseKey(hk);
663         }
664         if(!rc) {
665             printf("Error: Failed to update the service command line - %s\n", 
666                    GetLastErrorText(szErr, sizeof(szErr)));                
667         }
668     }
669     
670     strcpy(tag, BASE_REGISTRY_LOCATION);
671     strcat(tag, name);
672     strcat(tag, "\\");
673     strcat(tag, PARAMS_LOCATION);
674
675     rc = create_registry_key(tag, &hk);
676
677     if(rc) {
678         rc = set_registry_config_parameter(hk, PRP_LOCATION, prp_file);
679         if(!rc) {
680             printf("Error: Can not create value [%s] - %s\n", 
681                     PRP_LOCATION, 
682                     GetLastErrorText(szErr, sizeof(szErr)));                
683         }
684         RegCloseKey(hk);
685     } else {
686         printf("Error: Can not create key [%s] - %s\n", 
687                 tag, 
688                 GetLastErrorText(szErr, sizeof(szErr)));                
689     }
690     return rc;
691 }
692
693 static void start_jk_service(char *name)
694 {
695     /*
696      * report the status to the service control manager.
697      */
698     if(ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
699                            NO_ERROR,              // exit code
700                            3000)) {               // wait hint
701         
702         /* 
703          * create the event object. The control handler function signals
704          * this event when it receives the "stop" control code.
705          */
706         hServerStopEvent = CreateEvent(NULL,    // no security attributes
707                                        TRUE,    // manual reset event
708                                        FALSE,   // not-signalled
709                                        NULL);   // no name
710
711         if(hServerStopEvent) {
712             if(ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
713                                    NO_ERROR,              // exit code
714                                    20000)) {              // wait hint
715                 HANDLE hTomcat = NULL;
716                 char   szNameBuff[256];
717                 DWORD  lenNameBuff = 256;
718                 char   *szTrueName = name;
719                 SC_HANDLE   schSCManager;
720                 int rc;
721
722                 schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS );
723                 if(schSCManager) {
724                     if (GetServiceKeyName(schSCManager, name, szNameBuff, &lenNameBuff)) {
725                         szTrueName = szNameBuff;
726                     }
727                     CloseServiceHandle(schSCManager);
728                 }
729
730                 rc = start_tomcat(szTrueName, &hTomcat);
731
732                 if(rc && ReportStatusToSCMgr(SERVICE_RUNNING, // service state
733                                              NO_ERROR,        // exit code
734                                              0)) {            // wait hint       
735                     HANDLE waitfor[] = { hServerStopEvent, hTomcat};
736                     DWORD dwIndex = WaitForMultipleObjects(2, waitfor, FALSE, INFINITE);
737
738                     switch(dwIndex) {
739                     case WAIT_OBJECT_0:
740                         /* 
741                          * Stop order arrived 
742                          */ 
743                         ResetEvent(hServerStopEvent);
744                         stop_tomcat(name, shutdown_port, shutdown_protocol,
745                                     shutdown_secret, hTomcat);
746                         break;
747                     case (WAIT_OBJECT_0 + 1):
748                         /* 
749                          * Tomcat died !!!
750                          */ 
751                         CloseHandle(hServerStopEvent);
752                         CloseHandle(hTomcat);
753                         exit(0); // exit ungracefully so
754                                  // Service Control Manager 
755                                  // will attempt a restart.
756                         break;
757                     default:
758                         /* 
759                          * some error... 
760                          * close the servlet container and exit 
761                          */ 
762                         stop_tomcat(name, shutdown_port, shutdown_protocol,
763                                     shutdown_secret, hTomcat);
764                     }
765                     CloseHandle(hServerStopEvent);
766                     CloseHandle(hTomcat);
767                 }                
768             }
769         }
770     }
771
772     if(hServerStopEvent) {
773         CloseHandle(hServerStopEvent);
774     }
775 }
776
777
778 static void stop_jk_service(void)
779 {
780     if(hServerStopEvent) {
781         SetEvent(hServerStopEvent);
782     }
783 }
784
785 static void AddToMessageLog(char *lpszMsg)
786 {   
787     char    szMsg[2048];
788     HANDLE  hEventSource;
789     char *  lpszStrings[2];
790
791     printf("Error: %s\n", lpszMsg);
792
793     dwErr = GetLastError();
794
795     hEventSource = RegisterEventSource(NULL, "Tomcat");
796
797     sprintf(szMsg, "%s error: %d", "Tomcat", dwErr);
798     lpszStrings[0] = szMsg;
799     lpszStrings[1] = lpszMsg;
800
801     if(hEventSource != NULL) {
802         ReportEvent(hEventSource, // handle of event source
803             EVENTLOG_ERROR_TYPE,  // event type
804             0,                    // event category
805             0,                    // event ID
806             NULL,                 // current user's SID
807             2,                    // strings in lpszStrings
808             0,                    // no bytes of raw data
809             lpszStrings,          // array of error strings
810             NULL);                // no raw data
811
812         DeregisterEventSource(hEventSource);
813     }
814     
815 }
816
817 //
818 //  FUNCTION: GetLastErrorText
819 //
820 //  PURPOSE: copies error message text to string
821 //
822 //  PARAMETERS:
823 //    lpszBuf - destination buffer
824 //    dwSize - size of buffer
825 //
826 //  RETURN VALUE:
827 //    destination buffer
828 //
829 //  COMMENTS:
830 //
831 char *GetLastErrorText( char *lpszBuf, DWORD dwSize )
832 {
833     DWORD dwRet;
834     char *lpszTemp = NULL;
835
836     dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
837                           NULL,
838                           GetLastError(),
839                           LANG_NEUTRAL,
840                           (char *)&lpszTemp,
841                           0,
842                           NULL);
843
844     // supplied buffer is not long enough
845     if(!dwRet || ((long)dwSize < (long)dwRet+14)) {
846         lpszBuf[0] = '\0';
847     } else {
848         lpszTemp[lstrlen(lpszTemp)-2] = '\0';  //remove cr and newline character
849         sprintf(lpszBuf, "%s (0x%x)", lpszTemp, GetLastError());
850     }
851
852     if(lpszTemp) {
853         LocalFree((HLOCAL) lpszTemp );
854     }
855
856     return lpszBuf;
857 }
858
859 static void stop_tomcat(char *name,
860                         int port, 
861                         const char *protocol,
862                         char *secret,
863                         HANDLE hTomcat)
864 {
865     struct sockaddr_in in;
866
867     if(strcasecmp(protocol, "cmd") == 0 ) {
868         exec_cmd( name, hTomcat, shutdown_cmd);
869         /* XXX sleep 100 */
870         TerminateProcess(hTomcat, 0);
871         return;
872     } 
873     
874     if(jk_resolve("localhost", port, &in, NULL)) {
875         int sd = jk_open_socket(&in, JK_TRUE, 0, 0, NULL);
876         if(sd >0) {
877             int rc = JK_FALSE;
878
879             if(strcasecmp(protocol, "catalina") == 0 ) {
880                 char len;
881                 
882                 if( secret==NULL )
883                     secret="SHUTDOWN";
884                 len=strlen( secret );
885                 
886                 rc = send(sd, secret, len , 0);
887                 if(len == rc) {
888                     rc = JK_TRUE;
889                 }
890             } else if(!strcasecmp(protocol, "ajp13")) {
891                 jk_pool_t pool;
892                 jk_msg_buf_t *msg = NULL;
893                 jk_pool_atom_t buf[TINY_POOL_SIZE];
894
895                 jk_open_pool(&pool, buf, sizeof(buf));
896
897                 msg = jk_b_new(&pool);
898                 jk_b_set_buffer_size(msg, 512); 
899
900                 rc = ajp13_marshal_shutdown_into_msgb(msg, 
901                                                       &pool,
902                                                       NULL);
903                 if( secret!=NULL ) {
904                     /** will work with old clients, as well as new
905                      */
906                     rc = jk_b_append_string(msg, secret);
907                 }
908                 if(rc) {
909                     jk_b_end(msg, AJP13_PROTO);
910     
911                     if(0 > jk_tcp_socket_sendfull(sd, 
912                                                   msg->buf,
913                                                   msg->len,
914                                                   NULL)) {
915                         rc = JK_FALSE;
916                     }
917                 }                                                    
918             } else {
919                 char b[] = {(char)254, (char)15};
920                 rc = send(sd, b, 2, 0);
921                 if(2 == rc) {
922                     rc = JK_TRUE;
923                 }
924             }
925             jk_close_socket(sd, NULL);
926             if(JK_TRUE == rc) {
927                 if(WAIT_OBJECT_0 == WaitForSingleObject(hTomcat, 30*1000)) {
928                     return;
929                 }
930             }            
931         }
932     }
933
934     TerminateProcess(hTomcat, 0);    
935 }
936
937 static int exec_cmd(const char *name, HANDLE *hTomcat, char *cmdLine)
938 {
939     char  tag[1024];
940     HKEY  hk;
941
942     strcpy(tag, BASE_REGISTRY_LOCATION);
943     strcat(tag, name);
944     strcat(tag, "\\");
945     strcat(tag, PARAMS_LOCATION);
946
947     if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
948                                      tag,
949                                      (DWORD)0,         
950                                      KEY_READ,
951                                      &hk)) {
952         char prp_file[2048];
953         if(get_registry_config_parameter(hk,
954                                          PRP_LOCATION, 
955                                          prp_file,
956                                          sizeof(prp_file))) {
957             jk_map_t *init_map;
958             
959             if(jk_map_alloc(&init_map)) {
960                 if(jk_map_read_properties(init_map, NULL, prp_file, NULL,
961                                           JK_MAP_HANDLE_DUPLICATES, NULL)) {
962                     jk_tomcat_startup_data_t data;
963                     jk_pool_t p;
964                     jk_pool_atom_t buf[HUGE_POOL_SIZE];
965                     jk_open_pool(&p, buf, sizeof(buf));
966             
967                     if(read_startup_data(init_map, &data, &p)) {
968                         STARTUPINFO startupInfo;
969                         PROCESS_INFORMATION processInformation;
970                         SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
971
972                         if(data.extra_path) {
973                             jk_append_libpath(&p, data.extra_path);
974                         }
975
976                         memset(&startupInfo, 0, sizeof(startupInfo));
977                         startupInfo.cb = sizeof(startupInfo);
978                         startupInfo.lpTitle = "Tomcat";
979                         startupInfo.dwFlags = STARTF_USESTDHANDLES;
980                         startupInfo.hStdInput = NULL;
981                         startupInfo.hStdOutput = CreateFile(data.stdout_file,
982                                                             GENERIC_WRITE,
983                                                             FILE_SHARE_READ,
984                                                             &sa,
985                                                             OPEN_ALWAYS,
986                                                             FILE_ATTRIBUTE_NORMAL,
987                                                             NULL);
988                         SetFilePointer(startupInfo.hStdOutput,
989                                        0,
990                                        NULL,
991                                        FILE_END);
992                         startupInfo.hStdError = CreateFile(data.stderr_file,
993                                                            GENERIC_WRITE,
994                                                            FILE_SHARE_READ,
995                                                            &sa,
996                                                            OPEN_ALWAYS,
997                                                            FILE_ATTRIBUTE_NORMAL,
998                                                            NULL);
999                         SetFilePointer(startupInfo.hStdError,
1000                                        0,
1001                                        NULL,
1002                                        FILE_END);
1003
1004                         memset(&processInformation, 0, sizeof(processInformation));
1005                         
1006                         if( cmdLine==NULL ) 
1007                             cmdLine=data.cmd_line;
1008
1009                         printf(cmdLine);
1010                         if(CreateProcess(data.java_bin,
1011                                         cmdLine,
1012                                         NULL,
1013                                         NULL,
1014                                         TRUE,
1015                                         CREATE_NEW_CONSOLE,
1016                                         NULL,
1017                                         data.tomcat_home,
1018                                         &startupInfo,
1019                                         &processInformation)){
1020
1021                             *hTomcat = processInformation.hProcess;
1022                             CloseHandle(processInformation.hThread);
1023                             CloseHandle(startupInfo.hStdOutput);
1024                             CloseHandle(startupInfo.hStdError);
1025
1026                             shutdown_port = data.shutdown_port;
1027                             shutdown_secret = data.shutdown_secret;
1028                             shutdown_protocol = strdup(data.shutdown_protocol);
1029                             shutdown_cmd = strdup(data.stop_cmd);
1030
1031                             return JK_TRUE;
1032                         } else {
1033                             printf("Error: Can not create new process - %s\n", 
1034                                     GetLastErrorText(szErr, sizeof(szErr)));                
1035                         }
1036
1037                     }                    
1038                 }
1039             }
1040             jk_map_free(&init_map);
1041         }
1042         RegCloseKey(hk);
1043     } 
1044
1045     return JK_FALSE;
1046 }
1047
1048 static int start_tomcat(const char *name, HANDLE *hTomcat)
1049 {
1050     return exec_cmd( name, hTomcat, NULL );
1051 }
1052
1053 static int create_registry_key(const char *tag,
1054                                HKEY *key)
1055 {
1056     LONG  lrc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
1057                                tag,
1058                                0,
1059                                NULL,
1060                                REG_OPTION_NON_VOLATILE,
1061                                KEY_WRITE,
1062                                NULL,
1063                                key,
1064                                NULL);
1065     if(ERROR_SUCCESS != lrc) {
1066         return JK_FALSE;        
1067     }
1068
1069     return JK_TRUE;
1070 }
1071
1072 static int set_registry_config_parameter(HKEY hkey,
1073                                          const char *tag, 
1074                                          char *value)
1075 {       
1076     LONG  lrc;
1077
1078     lrc = RegSetValueEx(hkey, 
1079                         tag,            
1080                         0,              
1081                         REG_SZ,  
1082                         value, 
1083                         strlen(value));
1084
1085     if(ERROR_SUCCESS != lrc) {
1086         return JK_FALSE;        
1087     }
1088
1089     return JK_TRUE;     
1090 }
1091
1092
1093
1094 static int get_registry_config_parameter(HKEY hkey,
1095                                          const char *tag, 
1096                                          char *b,
1097                                          DWORD sz)
1098 {   
1099     DWORD type = 0;
1100     LONG  lrc;
1101
1102     lrc = RegQueryValueEx(hkey,     
1103                           tag,      
1104                           (LPDWORD)0,
1105                           &type,    
1106                           (LPBYTE)b,
1107                           &sz); 
1108     if(ERROR_SUCCESS != lrc) {
1109         return JK_FALSE;        
1110     }
1111     
1112     b[sz] = '\0';
1113
1114     return JK_TRUE;     
1115 }
1116
1117 static int read_startup_data(jk_map_t *init_map, 
1118                              jk_tomcat_startup_data_t *data, 
1119                              jk_pool_t *p)
1120 {
1121     
1122     data->classpath = NULL;
1123     data->tomcat_home = NULL;
1124     data->stdout_file = NULL;
1125     data->stderr_file = NULL;
1126     data->java_bin = NULL;
1127     data->extra_path = NULL;
1128     data->tomcat_class = NULL;
1129     data->server_file = NULL;
1130
1131     /* All this is wrong - you just need to configure cmd_line */
1132     /* Optional - you may have cmd_line defined */
1133     data->server_file = jk_map_get_string(init_map, 
1134                                           "wrapper.server_xml", 
1135                                           NULL);
1136     data->classpath = jk_map_get_string(init_map, 
1137                                         "wrapper.class_path", 
1138                                         NULL);
1139     data->tomcat_home = jk_map_get_string(init_map, 
1140                                           "wrapper.tomcat_home", 
1141                                           NULL);
1142     data->java_bin = jk_map_get_string(init_map, 
1143                                        "wrapper.javabin", 
1144                                        NULL);
1145     data->tomcat_class = jk_map_get_string(init_map,
1146                                            "wrapper.startup_class",
1147                                            "org.apache.tomcat.startup.Tomcat");
1148
1149     data->cmd_line = jk_map_get_string(init_map,
1150                                        "wrapper.cmd_line",
1151                                        NULL);
1152
1153     data->stop_cmd = jk_map_get_string(init_map,
1154                                        "wrapper.stop_cmd",
1155                                        NULL);
1156
1157     if(NULL == data->cmd_line &&
1158        ( (NULL == data->tomcat_class) ||
1159          (NULL == data->server_file) ||
1160          (NULL == data->tomcat_home) ||
1161          (NULL == data->java_bin) )) {
1162        return JK_FALSE;
1163     }
1164
1165     if(NULL == data->cmd_line) {
1166         data->cmd_line = (char *)jk_pool_alloc(p, (20 + 
1167                                                    strlen(data->java_bin) +
1168                                                    strlen(" -classpath ") +
1169                                                    strlen(data->classpath) +
1170                                                    strlen(data->tomcat_class) +
1171                                                    strlen(" -home ") +
1172                                                    strlen(data->tomcat_home) +
1173                                                    strlen(" -config ") +
1174                                                    strlen(data->server_file)
1175                                                    ) * sizeof(char));
1176         if(NULL == data->cmd_line) {
1177             return JK_FALSE;
1178         }
1179
1180         strcpy(data->cmd_line, data->java_bin);
1181         strcat(data->cmd_line, " -classpath ");
1182         strcat(data->cmd_line, data->classpath);
1183         strcat(data->cmd_line, " ");
1184         strcat(data->cmd_line, data->tomcat_class);
1185         strcat(data->cmd_line, " -home ");
1186         strcat(data->cmd_line, data->tomcat_home);
1187         strcat(data->cmd_line, " -config ");
1188         strcat(data->cmd_line, data->server_file);
1189     }
1190
1191     data->shutdown_port = jk_map_get_int(init_map,
1192                                          "wrapper.shutdown_port",
1193                                          8007);
1194
1195     data->shutdown_secret = jk_map_get_string(init_map,
1196                                               "wrapper.shutdown_secret", 
1197                                               NULL);
1198     
1199     data->shutdown_protocol = jk_map_get_string(init_map,
1200                                                 "wrapper.shutdown_protocol",
1201                                                 AJP12_TAG);
1202
1203     data->extra_path = jk_map_get_string(init_map,
1204                                          "wrapper.ld_path",
1205                                          NULL);
1206
1207     data->stdout_file = jk_map_get_string(init_map,
1208                                           "wrapper.stdout",
1209                                           NULL);
1210
1211     if(NULL == data->stdout_file && NULL == data->tomcat_home ) {
1212         return JK_FALSE;
1213     }
1214     
1215     if(NULL == data->stdout_file) {
1216         data->stdout_file = jk_pool_alloc(p, strlen(data->tomcat_home) + 2 + strlen("\\stdout.log"));
1217         strcpy(data->stdout_file, data->tomcat_home);
1218         strcat(data->stdout_file, "\\stdout.log");        
1219     }
1220
1221     data->stderr_file = jk_map_get_string(init_map,
1222                                           "wrapper.stderr",
1223                                           NULL);
1224
1225     if(NULL == data->stderr_file) {
1226         data->stderr_file = jk_pool_alloc(p, strlen(data->tomcat_home) + 2 + strlen("\\stderr.log"));
1227         strcpy(data->stderr_file, data->tomcat_home);
1228         strcat(data->stderr_file, "\\stderr.log");        
1229     }
1230
1231     return JK_TRUE;
1232 }
1233