root/branches/windows-client/src/client/windows/client-service/service-main.c @ 8839

Revision 8839, 15.6 KB (checked in by sampson, 2 years ago)

Windows certificate support

  • Property svn:executable set to *
Line 
1/* Copyright (C) 2010 Omnibond, Inc. */
2
3/* Client Service - service control functions */
4
5#include <Windows.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include <string.h>
9
10#include "gen-locks.h"
11
12#include "client-service.h"
13#include "config.h"
14#include "fs.h"
15#include "cert.h"
16#include "user-cache.h"
17
18#define WIN32ServiceName           "orangefs-client"
19#define WIN32ServiceDisplayName    "OrangeFS Client"
20
21/* globals */
22SERVICE_STATUS_HANDLE hstatus;
23SERVICE_STATUS service_status;
24
25#ifdef _DEBUG
26BOOL debug = TRUE;
27#else
28BOOL debug = FALSE;
29#endif
30
31int is_running = 0;
32int run_service = 0; 
33
34HANDLE hthread, hcache_thread;
35
36DWORD thread_start(PORANGEFS_OPTIONS options);
37DWORD thread_stop();
38
39DWORD cache_thread_start();
40DWORD cache_thread_stop();
41
42DWORD WINAPI main_loop(LPVOID poptions);
43
44FILE *debug_log = NULL;
45
46extern struct qhash_table *user_cache;
47
48extern gen_mutex_t user_cache_mutex;
49
50PORANGEFS_OPTIONS goptions;
51
52/* externs */
53extern int __cdecl dokan_loop(PORANGEFS_OPTIONS options);
54
55void init_service_log()
56{
57    char exe_path[MAX_PATH], *p;
58    int ret;
59
60    if (!debug || !run_service)
61        return;
62
63    /* create log file in exe directory */
64    ret = GetModuleFileName(NULL, exe_path, MAX_PATH);
65    if (ret != 0)
66    {
67        /* get directory */
68        p = strrchr(exe_path, '\\');
69        if (p)
70            *p = '\0';
71
72        strcat(exe_path, "\\service.log");
73
74        debug_log = fopen(exe_path, "a");
75    }
76}
77
78void service_debug(char *format, ...)
79{
80    char buffer[512];
81    va_list argp;
82
83    if (!debug || !run_service)
84        return;
85
86    va_start(argp, format);
87    vsprintf_s(buffer, sizeof(buffer), format, argp);
88    va_end(argp);
89
90    fprintf(debug_log, buffer);
91    fflush(debug_log);
92
93}
94
95void close_service_log()
96{
97    if (!debug || !run_service)
98        return;
99
100    if (debug_log)
101    {
102        fprintf(debug_log, "\n");
103        fclose(debug_log);
104    }
105}
106
107BOOL check_mount_point(const char *mount_point)
108{
109    const char *slash;
110    char drive;
111    DWORD mask;
112
113    /* first check if a directory rather than drive is mapped */
114    slash = strchr(mount_point, '\\');
115    if (slash && slash[1] != '\0')
116        /* Dokan will exit if directory is invalid */
117        return TRUE;
118
119    drive = toupper(mount_point[0]);
120    drive -= 'A';
121    if (drive < 0 || drive > 25)
122        return FALSE;
123
124    mask = GetLogicalDrives();
125    if (mask == 0)
126    {
127        fprintf(stderr, "GetLogicalDrives failed: %u\n", GetLastError());
128        return FALSE;
129    }
130
131    return !(mask & (1 << drive));
132}
133
134DWORD service_install()
135{
136    SC_HANDLE sch_service;
137    SC_HANDLE sch_manager;
138    char *exe_path, *command;
139    size_t size;
140    int err;
141
142    /* Get location of executable */
143    size = 512;
144    do {
145        exe_path = (char *) malloc(size);
146        if (!exe_path)
147        {
148            fprintf(stderr, "Insufficient memory\n");
149            return -1;
150        }
151
152        GetModuleFileName(NULL, exe_path, size);
153        err = GetLastError();
154
155        if (err == ERROR_INSUFFICIENT_BUFFER)
156        {
157            free(exe_path);
158            size *= 2;
159        }
160        else if (err != ERROR_SUCCESS)
161        {
162            free(exe_path);
163            fprintf(stderr, "Error: GetModuleFileName (%u)\n", err);
164            return -1;
165        }
166
167    } while (err == ERROR_INSUFFICIENT_BUFFER);
168
169    /* append -service option to command */
170    command = (char *) malloc(strlen(exe_path) + 16);
171    if (!command)
172    {
173        fprintf(stderr, "Insufficient memory\n");
174        return -1;
175    }
176    strcpy(command, exe_path);
177    strcat(command, " -service");
178
179    /* open the service manager */
180    sch_manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
181    if (sch_manager != NULL)
182    {
183        /* create the service */
184        sch_service = CreateService(
185            sch_manager,
186            WIN32ServiceName,
187            WIN32ServiceDisplayName,
188            SERVICE_ALL_ACCESS,
189            SERVICE_WIN32_OWN_PROCESS,
190            SERVICE_AUTO_START,
191            SERVICE_ERROR_NORMAL,
192            command,
193            NULL,
194            NULL,
195            TEXT("\0\0"),
196            NULL,
197            NULL);
198
199        if (sch_service != NULL)
200        {
201            printf("%s installed\n", WIN32ServiceDisplayName);
202            CloseServiceHandle(sch_service);
203        }
204        else
205        {
206            fprintf(stderr, "Error: CreateService (%u)\n", GetLastError());
207            return -1;
208        }
209
210        CloseServiceHandle(sch_manager);
211    }
212    else
213    {
214        fprintf(stderr, "Error: OpenSCManager (%u)\n", GetLastError());
215        return -1;
216    }
217
218    free(exe_path);
219    free(command);
220
221    return 0;
222}
223
224DWORD service_remove()
225{
226    SC_HANDLE sch_service;
227    SC_HANDLE sch_manager;
228
229    /* open service manager */
230    sch_manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
231
232    if (sch_manager != NULL)
233    {
234        /* open service */
235        sch_service = OpenService(sch_manager, WIN32ServiceName,
236                        SERVICE_ALL_ACCESS | DELETE);
237        if (sch_service != NULL)
238        {
239            /* attempt to stop service */
240            if (ControlService(sch_service, SERVICE_CONTROL_STOP,
241                  &service_status))
242            {
243                Sleep(1000);
244
245                while (QueryServiceStatus(sch_service, &service_status))
246                {
247                    if (service_status.dwCurrentState == SERVICE_STOP_PENDING)                   
248                        Sleep(1000);
249                    else
250                        break;
251                }
252
253            }
254           
255            if (DeleteService(sch_service))               
256                printf("%s removed\n", WIN32ServiceDisplayName);
257            else
258                fprintf(stderr, "Error: DeleteService (%u)\n", GetLastError());
259
260            CloseServiceHandle(sch_service);
261
262        }
263        else
264        {
265            fprintf(stderr, "Error: OpenService (%u)\n", GetLastError());
266            return -1;
267        }
268
269        CloseServiceHandle(sch_manager);
270    }
271    else
272    {
273        fprintf(stderr, "Error: OpenSCManager (%u)\n", GetLastError());
274        return -1;
275    }
276
277    return 0;
278
279}
280
281/* service control handler */
282void WINAPI service_ctrl(DWORD ctrl_code)
283{
284    switch (ctrl_code)
285    {
286    case SERVICE_CONTROL_STOP:
287    case SERVICE_CONTROL_SHUTDOWN:
288        service_debug("service_ctrl: shutdown received\n");
289       
290        service_status.dwCurrentState = SERVICE_STOP_PENDING;
291        Sleep(1000);
292        SetServiceStatus(hstatus, &service_status);
293       
294        is_running = 0;
295        thread_stop();
296    }
297}
298
299void WINAPI service_main(DWORD argc, char *argv[])
300{
301    PORANGEFS_OPTIONS options;
302    int ret;
303
304    /* allocate options */
305    options = (PORANGEFS_OPTIONS) calloc(1, sizeof(ORANGEFS_OPTIONS));
306
307    /* init user cache */
308    user_cache = qhash_init(user_compare, quickhash_string_hash, 257);
309   
310    gen_mutex_init(&user_cache_mutex);
311
312    /* default mount point */
313    strcpy(options->mount_point, "Z:");
314
315    /* read from config file */
316    ret = get_config(options);
317
318    /* point global options */
319    goptions = options;   
320       
321#ifndef _DEBUG
322    debug = options->debug;
323#endif
324
325    init_service_log();
326
327    service_debug("Entered service_main\n");
328
329    if (ret != 0)
330    {
331        service_debug("Could not parse config file: check user options\n");
332        close_service_log();
333        return;
334    }
335
336    if (!check_mount_point(options->mount_point))
337        return;
338
339    /* register our control handler routine */
340    if ((hstatus = RegisterServiceCtrlHandler(WIN32ServiceName, service_ctrl))
341           != NULL)
342    {
343        service_debug("Service registered\n");
344
345        /* run the user cache thread */
346        ret = cache_thread_start();
347        if (ret != 0)
348        {
349            service_debug("Could not start cache thread: %u\n", ret);
350            close_service_log();
351            free(options);
352           
353            return;
354        }
355
356        /* run the service */
357        service_status.dwCurrentState = SERVICE_RUNNING;
358        service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
359        service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
360        service_status.dwWin32ExitCode = NO_ERROR;
361        service_status.dwServiceSpecificExitCode = 0;
362
363        /* execute service main loop */
364        if (SetServiceStatus(hstatus, &service_status))
365        {
366            is_running = 1;
367            service_debug("Starting thread\n");
368            thread_start(options);
369        }
370
371        /* stop cache thread */
372        cache_thread_stop();
373
374        /* cleanup OpenSSL */
375        openssl_cleanup();
376       
377        /* shut down service */       
378        service_status.dwCurrentState = SERVICE_STOPPED;
379        SetServiceStatus(hstatus, &service_status);       
380    }
381    else
382    {
383        service_debug("RegisterServiceCtrlHandler failed: %u\n", GetLastError());
384        /* TODO: error reporting */
385    }
386
387    qhash_destroy_and_finalize(user_cache, struct user_entry, hash_link, free);
388   
389    close_service_log();
390
391    free(options);
392}
393
394DWORD thread_start(PORANGEFS_OPTIONS options)
395{
396    DWORD err = 0;
397
398    service_debug("thread_start enter\n");
399
400    /* create and run the new thread */
401    hthread = CreateThread(NULL,
402                           0,
403                           main_loop,
404                           options,
405                           0,
406                           NULL);
407    if (hthread)
408    { 
409        WaitForSingleObject(hthread, INFINITE);
410    }
411    else
412    {
413        err = GetLastError();
414        service_debug("CreateThread failed: %u\n", err);
415    }
416
417    service_debug("thread_start exit\n");
418
419    return err;                           
420}
421
422DWORD thread_stop()
423{
424    DWORD err = 0;
425
426    service_debug("thread_stop enter\n");
427   
428    /* stop the thread */
429    if (!TerminateThread(hthread, 0))
430    {
431        err = GetLastError();
432        service_debug("TerminateThread failed: %u\n", err);
433    }
434
435    service_debug("thread_stop exit\n");
436
437    return err;
438}
439
440DWORD cache_thread_start()
441{
442    DWORD err = 0;
443
444    /* create and run the user cache thread */
445    hcache_thread = CreateThread(NULL,
446                                 0,
447                                 (LPTHREAD_START_ROUTINE) user_cache_thread,
448                                 NULL,
449                                 0,
450                                 NULL);
451   
452    if (hcache_thread == NULL)
453        err = GetLastError();
454
455    return err;
456}
457
458DWORD cache_thread_stop()
459{
460    DWORD err = 0;
461
462    if (hcache_thread != NULL)
463        if (!TerminateThread(hcache_thread, 0))
464            err = GetLastError();
465
466    return err;
467}
468
469DWORD WINAPI main_loop(LPVOID poptions)
470{
471    PORANGEFS_OPTIONS options = (PORANGEFS_OPTIONS) poptions;
472    char *tabfile, exe_path[MAX_PATH], *p;
473    FILE *f;
474    int ret, malloc_flag = 0;
475
476    /* locate tabfile -- env. variable overrides */
477    if (!(tabfile = getenv("PVFS2TAB_FILE")))
478    {
479        ret = GetModuleFileName(NULL, exe_path, MAX_PATH);
480        if (ret)
481        {
482            /* get directory */
483            p = strrchr(exe_path, '\\');
484            if (p)
485                *p = '\0';
486
487            tabfile = (char *) malloc(MAX_PATH);
488            malloc_flag = TRUE;
489
490            strcpy(tabfile, exe_path);
491            strcat(tabfile, "\\orangefstab");
492
493            /* attempt to open file */
494            f = fopen(tabfile, "r");
495            if (f)
496                fclose(f);
497            else
498            {
499                /* switch to pvfs2tab -- fs_initialize will fail if not valid */
500                strcpy(tabfile, exe_path);
501                strcat(tabfile, "\\pvfs2tab");
502            }
503        }
504        else
505        {
506           fprintf(stderr, "GetModuleFileName failed: %u\n", GetLastError());
507        }
508    }
509
510    /* init file systems */
511    if (tabfile)
512    {
513        service_debug("Using tabfile: %s\n", tabfile);
514        ret = fs_initialize(tabfile);
515    }
516    else
517        ret = ERROR_FILE_NOT_FOUND;
518
519    /* run dokan operations */
520    if (ret == 0)
521    {
522        dokan_loop(options);
523
524        /* close file systems */
525        fs_finalize();
526    }
527    else
528    {
529        service_debug("fs_initialize returned %d\n", ret);
530        fprintf(stderr, "fs_initialize returned %d\n", ret);
531    }
532
533    if (malloc_flag)
534        free(tabfile);
535
536    return (DWORD) ret;
537}
538
539int main(int argc, char **argv, char **envp)
540{
541  int i = 0;
542  PORANGEFS_OPTIONS options;
543  DWORD err = 0;
544  char mount_point[256];
545
546  SERVICE_TABLE_ENTRY dispatch_table[2] =
547  {
548      {WIN32ServiceName, (LPSERVICE_MAIN_FUNCTION) service_main},
549      {NULL, NULL}
550  };
551
552  mount_point[0] = '\0';
553
554  /* command line arguments */
555  for (i = 1; i < argc; i++)
556  {
557      if (!stricmp(argv[i], "-installService") ||
558          !stricmp(argv[i], "-w") || !stricmp(argv[i], "/w"))
559      {
560          return service_install();
561      }
562      else if (!stricmp(argv[i], "-removeService") ||
563               !stricmp(argv[i], "-u") || !stricmp(argv[i], "/u"))
564      {
565          return service_remove();
566      }
567      else if (!strcmp(argv[i], "-service"))
568      {
569          run_service = 1;
570      }
571      else if (!strcmp(argv[i], "-mount") || !strcmp(argv[i], "-m") ||
572               !strcmp(argv[i], "/m"))
573      {
574          if (i < (argc - 1))
575              strncpy(mount_point, argv[++i], MAX_PATH);
576          else
577              fprintf(stderr, "Invalid argument -mount. Using mount point Z:\n");
578      }
579      else if (!strcmp(argv[i], "-debug") || !strcmp(argv[i], "-d") ||
580               !strcmp(argv[i], "/d"))
581      {
582          debug = TRUE;
583      }
584  }
585
586  /* initialize OpenSSL */
587  openssl_init();
588
589  if (run_service)
590  {
591      /* dispatch the main service thread */
592      StartServiceCtrlDispatcher(dispatch_table);
593  }
594  else
595  {   
596      options = (PORANGEFS_OPTIONS) calloc(1, sizeof(ORANGEFS_OPTIONS));
597
598      /* init user list */
599      user_cache = qhash_init(user_compare, quickhash_string_hash, 257);
600     
601      gen_mutex_init(&user_cache_mutex);
602
603      /* get options from config file */
604      if (get_config(options) != 0)
605          return 1;
606
607      /* point goptions */
608      goptions = options;
609
610      /* override with mount point from command line */
611      if (strlen(mount_point) > 0)
612          strcpy(options->mount_point, mount_point);
613
614      /* use default mount point */
615      if (strlen(options->mount_point) == 0)
616          strcpy(options->mount_point, "Z:");
617
618      /* turn debug on if specified on command line */
619      if (debug)
620          options->debug = TRUE;
621
622      if (!check_mount_point(options->mount_point))
623      {
624          fprintf(stderr, "Drive already in use\n");
625          return -1;
626      }
627
628      /* start user cache thread  */
629      err = cache_thread_start();
630      if (err != 0)
631      {
632          fprintf(stderr, "User cache thread did not start: %u\n", err);
633          free(options);
634          return err;
635      }
636
637      is_running = 1;
638
639      /* process requests */
640      err = main_loop(options);
641     
642      printf("main_loop exited: %d\n", err);
643
644      gen_mutex_destroy(&user_cache_mutex);
645
646      cache_thread_stop();
647
648      qhash_destroy_and_finalize(user_cache, struct user_entry, hash_link, free);
649
650      openssl_cleanup();
651
652      free(options);
653  }
654
655  return err;
656}
Note: See TracBrowser for help on using the browser.