~vinchen13/mysql-proxy/fix_some_bugs

« back to all changes in this revision

Viewing changes to src/chassis-win32-service.c

  • Committer: vin
  • Date: 2012-02-15 02:47:30 UTC
  • Revision ID: vinchen13@gmail.com-20120215024730-6xtv6nhn83ina0sc
origin source code from mysql-proxy-0.8.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $%BEGINLICENSE%$
 
2
 Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 
3
 
 
4
 This program is free software; you can redistribute it and/or
 
5
 modify it under the terms of the GNU General Public License as
 
6
 published by the Free Software Foundation; version 2 of the
 
7
 License.
 
8
 
 
9
 This program is distributed in the hope that it will be useful,
 
10
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
12
 GNU General Public License for more details.
 
13
 
 
14
 You should have received a copy of the GNU General Public License
 
15
 along with this program; if not, write to the Free Software
 
16
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
17
 02110-1301  USA
 
18
 
 
19
 $%ENDLICENSE%$ */
 
20
 
 
21
#include "chassis-win32-service.h"
 
22
#include "chassis-mainloop.h" /* for chassis_set_shutdown */
 
23
 
 
24
#ifdef _WIN32
 
25
/**
 
26
 * win32 service functions
 
27
 *
 
28
 */
 
29
 
 
30
#include <windows.h>
 
31
#include <winsock2.h>
 
32
 
 
33
static char **shell_argv;
 
34
static int shell_argc;
 
35
static int (*shell_main)(int, char **);
 
36
static int chassis_win32_running_as_service = 0;
 
37
static SERVICE_STATUS chassis_win32_service_status;
 
38
static SERVICE_STATUS_HANDLE chassis_win32_service_status_handle = 0;
 
39
 
 
40
gboolean chassis_win32_is_service(void) {
 
41
        return chassis_win32_running_as_service;
 
42
}
 
43
 
 
44
void chassis_win32_service_set_state(DWORD new_state, int wait_msec) {
 
45
        DWORD status;
 
46
        
 
47
        /* safeguard against a missing if(chassis_win32_running_as_service) in other code */
 
48
        if (!chassis_win32_running_as_service) return;
 
49
 
 
50
        g_assert(chassis_win32_service_status_handle);
 
51
        
 
52
        switch(new_state) {
 
53
        case SERVICE_START_PENDING:
 
54
        case SERVICE_STOP_PENDING:
 
55
                chassis_win32_service_status.dwWaitHint = wait_msec;
 
56
                
 
57
                if (chassis_win32_service_status.dwCurrentState == new_state) {
 
58
                        chassis_win32_service_status.dwCheckPoint++;
 
59
                } else {
 
60
                        chassis_win32_service_status.dwCheckPoint = 0;
 
61
                }
 
62
                
 
63
                break;
 
64
        default:
 
65
                chassis_win32_service_status.dwWaitHint = 0;
 
66
                break;
 
67
        }
 
68
        
 
69
        chassis_win32_service_status.dwCurrentState = new_state;
 
70
        
 
71
        if (!SetServiceStatus (chassis_win32_service_status_handle, &chassis_win32_service_status)) {
 
72
                status = GetLastError();
 
73
        }
 
74
}
 
75
 
 
76
/**
 
77
 * the event-handler for the service
 
78
 * 
 
79
 * the SCM will send us events from time to time which we acknoledge
 
80
 */
 
81
 
 
82
static DWORD WINAPI chassis_win32_service_ctrl(DWORD Opcode, DWORD EventType, LPVOID EventData, LPVOID _udata) {
 
83
        switch(Opcode) {
 
84
        case SERVICE_CONTROL_SHUTDOWN:
 
85
        case SERVICE_CONTROL_STOP:
 
86
                chassis_win32_service_set_state(SERVICE_STOP_PENDING, 0);
 
87
                
 
88
                chassis_set_shutdown(); /* exit the main-loop */
 
89
                
 
90
                return NO_ERROR;
 
91
        case SERVICE_CONTROL_INTERROGATE:
 
92
                /* even if we don't implement it, we should return NO_ERROR here */
 
93
                return NO_ERROR;
 
94
        default:
 
95
                chassis_win32_service_set_state(Opcode, 0); /* forward the state changes */
 
96
                return ERROR_CALL_NOT_IMPLEMENTED;
 
97
        }
 
98
}
 
99
 
 
100
/**
 
101
 * trampoline us into the real main_cmdline
 
102
 */
 
103
static void WINAPI chassis_win32_service_start(DWORD argc, LPTSTR *argv) {
 
104
        const char *service_name = "MerlinAgent";
 
105
        int ret;
 
106
        
 
107
        /* tell the service controller that we are alive */
 
108
        chassis_win32_service_status.dwCurrentState       = SERVICE_START_PENDING;
 
109
        chassis_win32_service_status.dwCheckPoint         = 0;
 
110
        chassis_win32_service_status.dwServiceType        = SERVICE_WIN32_OWN_PROCESS;
 
111
        chassis_win32_service_status.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
 
112
        chassis_win32_service_status.dwWin32ExitCode      = NO_ERROR;
 
113
        chassis_win32_service_status.dwServiceSpecificExitCode = 0;
 
114
        
 
115
        chassis_win32_service_status_handle = RegisterServiceCtrlHandlerEx(service_name, chassis_win32_service_ctrl, NULL); 
 
116
        
 
117
        if (chassis_win32_service_status_handle == (SERVICE_STATUS_HANDLE)0) {
 
118
                int err = GetLastError();
 
119
 
 
120
                g_critical("%s: RegisterServiceCtrlHandler(%s, ...) failed: %s (%d)",
 
121
                                G_STRLOC,
 
122
                                service_name,
 
123
                                g_strerror(err),
 
124
                                err);
 
125
 
 
126
                return; 
 
127
        }
 
128
        
 
129
        chassis_win32_service_set_state(SERVICE_START_PENDING, 1000); /* wait max 1sec before we get the to the next step */
 
130
 
 
131
        g_assert(shell_main);
 
132
        
 
133
        /* jump into the actual main */
 
134
        ret = shell_main(shell_argc, shell_argv);
 
135
        
 
136
        /* FIXME: should we log if we fail to start ? */
 
137
}
 
138
 
 
139
/**
 
140
 * Determine whether we are called as a service and set that up.
 
141
 * Then call main_cmdline to do the real work.
 
142
 */
 
143
int main_win32(int argc, char **argv, int (*_main_cmdline)(int, char **)) {
 
144
        WSADATA wsaData;
 
145
 
 
146
        SERVICE_TABLE_ENTRY dispatch_tab[] = {
 
147
                { "", chassis_win32_service_start }, /* we use SERVICE_WIN32_OWN_PROCESS, so the name can be "" */
 
148
                { NULL, NULL } 
 
149
        };
 
150
 
 
151
        if (0 != WSAStartup(MAKEWORD( 2, 2 ), &wsaData)) {
 
152
                g_critical("WSAStartup failed to initialize the socket library.\n");
 
153
 
 
154
                return -1;
 
155
        }
 
156
 
 
157
        /* save the arguments because the service controller will clobber them */
 
158
        shell_main = _main_cmdline;
 
159
        shell_argc = argc;
 
160
        shell_argv = argv;
 
161
 
 
162
        /* speculate that we are running as a service, reset to 0 on error */
 
163
        chassis_win32_running_as_service = TRUE;
 
164
        
 
165
        if (!StartServiceCtrlDispatcher(dispatch_tab)) {
 
166
                int err = GetLastError();
 
167
                
 
168
                switch(err) {
 
169
                case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
 
170
                        /* we weren't called as a service, carry on with the cmdline handling */
 
171
                        chassis_win32_running_as_service = FALSE;
 
172
                        return shell_main(shell_argc, shell_argv);
 
173
                case ERROR_SERVICE_ALREADY_RUNNING:
 
174
                        g_critical("service is already running, shutting down");
 
175
                        return 0;
 
176
                default:
 
177
                        g_critical("unhandled error-code (%d) for StartServiceCtrlDispatcher(), shutting down", err);
 
178
                        return -1;
 
179
                }
 
180
        } else {
 
181
                /* the service-thread is started, return to the shell */
 
182
        }
 
183
        return 0;
 
184
}
 
185
#else
 
186
/**
 
187
 * just a stub in case we aren't on win32
 
188
 */
 
189
int main_win32(int G_GNUC_UNUSED argc, char G_GNUC_UNUSED **argv, int G_GNUC_UNUSED (*_main_cmdline)(int, char **)) {
 
190
        return -1;
 
191
}
 
192
#endif