home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 August / PCWorld_2001-08_cd.bin / Komunikace / sambar / _setup.1 / Ntmain.c < prev    next >
C/C++ Source or Header  |  2001-05-13  |  14KB  |  637 lines

  1. /*
  2. ** NTMAIN
  3. **
  4. **      This is the main driver for the Windows NT Service driver of 
  5. **        the Sambar Server. 
  6. **
  7. **        Confidential Property of Tod Sambar
  8. **        (c) Copyright Tod Sambar 1997-2001
  9. **        All rights reserved.
  10. **
  11. **
  12. ** Syntax:
  13. **
  14. **      ntserver [-i] [-u] [-d] [-s service-name] [-c config-dir ]
  15. **
  16. **            -i        Install the Sambar Server as an NT Service
  17. **             -u        Uninstall the Sambar Server NT Service
  18. **            -d         Start the Sambar Server in debug mode
  19. **            -s        Optional service name argument (for installing multiple)
  20. **            -c         Optional path to the config directory to use.
  21. **
  22. **
  23. ** History:
  24. ** Chg#    Date    Description                                                Resp
  25. ** ----    -------    -------------------------------------------------------    ----
  26. **        26JUL97    Created                                                    sambar
  27. */
  28.  
  29. #include     <windows.h>
  30. #include    <stdio.h>
  31. #include    <stdlib.h>
  32. #include     <direct.h>
  33. #include     <process.h>
  34. #include    <sambar.h>
  35.  
  36. /*
  37. ** Local Defines
  38. */
  39. #define SERVICE_NAME        "Sambar Server"
  40. #define SERVICE_TITLE        "Sambar Server"
  41. #define NTSERVER_DEBUG        (SA_INT)0x0001
  42. #define NTSERVER_INSTALL    (SA_INT)0x0002
  43. #define NTSERVER_UNINSTALL    (SA_INT)0x0004
  44.  
  45. #define CK_PIPE                1
  46.  
  47.  
  48. /*
  49. ** Local Prototypes
  50. */
  51. static SA_RETCODE     get_args(int argc, char **argv, SA_INT *flagsp);
  52. static void         syntax_error(char *name, char *argv);
  53. static SA_RETCODE    install_service(void);
  54. static SA_RETCODE    uninstall_service(void);
  55. VOID                 service_main(DWORD argc, LPTSTR *argv);
  56. VOID                  service_ctrl(DWORD dwCtrlCode);
  57. static SA_RETCODE    service_cd(void);
  58. static void         service_status(int state, int exitCode, int waitHint);
  59. static void            HTTPLog(SA_CTX *ctx, SA_HTTPLOG *httplog);
  60. static void         create_pipe(void);
  61. static void         close_pipe(void);
  62.  
  63.  
  64. /*
  65. ** Global Handles
  66. */
  67. static SERVICE_STATUS_HANDLE    hServiceStatus;
  68. static int                        sState;
  69. static boolean                    bConnected = FALSE;
  70. static HANDLE                    hIOCP = NULL;
  71. static HANDLE                    hPipe = NULL;
  72. static OVERLAPPED                o;
  73. static SA_INIT                    SaInit;
  74. static char                        ConfigDir[256];
  75. static char                        ServiceName[256];
  76. static char                        ServiceTitle[256];
  77.  
  78.  
  79.  
  80. int    
  81. main(int argc, char *argv[])
  82. {
  83.     SA_INT        flags;
  84.  
  85.     /* Initialization                                                    */
  86.     memset(&SaInit, 0, sizeof(SA_INIT));
  87.     strcpy(ServiceName, SERVICE_NAME);
  88.     strcpy(ServiceTitle, SERVICE_TITLE);
  89.     ConfigDir[0] = '\0';
  90.     SaInit.i_logfunc = HTTPLog;
  91.     SaInit.i_servicename = ServiceName;
  92.  
  93.     /*
  94.     ** Read the command line arguments.
  95.     */
  96.     if (get_args(argc, argv, &flags) != SA_SUCCEED)
  97.         return (0);
  98.  
  99.     if (flags & NTSERVER_INSTALL)
  100.     {
  101.         if (install_service() != SA_SUCCEED)
  102.             return (-1);
  103.  
  104.         fprintf(stdout, 
  105.             "The %s NT Service can be started from the Service Panel.\n", 
  106.             ServiceName);
  107.  
  108.         return (0);
  109.     }
  110.  
  111.     if (flags & NTSERVER_UNINSTALL)
  112.     {
  113.         if (uninstall_service() != SA_SUCCEED)
  114.             return (-1);
  115.  
  116.         return (0);
  117.     }
  118.  
  119.     /* Change to the appropriate working directory for execution        */ 
  120.     if (service_cd() != SA_SUCCEED)
  121.         return (-1);
  122.  
  123.     if (flags & NTSERVER_DEBUG)
  124.     {
  125.         create_pipe();
  126.  
  127.         /* Execute the Sambar Server Shell                                */
  128.         if (sa_server2((SA_VOID *)&SaInit) != SA_SUCCEED)
  129.         {
  130.             close_pipe();
  131.             return (-1);
  132.         }
  133.  
  134.         close_pipe();
  135.     }
  136.     else
  137.     {
  138.         SERVICE_TABLE_ENTRY        ste[] =
  139.         {
  140.             { ServiceName,        (LPSERVICE_MAIN_FUNCTION)service_main },
  141.             { NULL,                NULL }
  142.         };
  143.  
  144.         if (StartServiceCtrlDispatcher(ste) != TRUE)
  145.         {
  146.             fprintf(stderr, "Failed to start %s NT Service (%d)\n",
  147.                 ServiceName, GetLastError());
  148.             return (-1);
  149.         }
  150.     }
  151.  
  152.     return (0);
  153. }
  154.  
  155. /*
  156. **  GET_ARGS
  157. **
  158. **     This routine parses the command line arguments passed to the
  159. **     NT Server application.
  160. **
  161. */
  162. static SA_RETCODE
  163. get_args(int argc, char **argv, SA_INT *flagsp)
  164. {
  165.     int        j;
  166.     SA_INT    flags;
  167.  
  168.     /* Initialization                                                    */
  169.     flags = 0;
  170.  
  171.     /*
  172.     ** Are there any arguments to parse?
  173.     */
  174.     if (argc <= 1)
  175.     {
  176.         /*
  177.         ** We don't have any arguments.
  178.         */
  179.         *flagsp = 0;
  180.         return (SA_SUCCEED);
  181.     }
  182.  
  183.     /* Loop through the arguments                                        */
  184.     j = 1;
  185.  
  186.     while (j < argc)
  187.     {
  188.         if (strcmp(argv[j], "-i") == 0)
  189.         {
  190.             flags |= NTSERVER_INSTALL;
  191.         }
  192.         else if (strcmp(argv[j], "-u") == 0)
  193.         {
  194.             flags |= NTSERVER_UNINSTALL;
  195.         }
  196.         else if (strcmp(argv[j], "-d") == 0)
  197.         {
  198.             flags |= NTSERVER_DEBUG;
  199.         }
  200.         else if (strcmp(argv[j], "-s") == 0)
  201.         {
  202.             j++;
  203.             if (j == argc)
  204.             {
  205.                 syntax_error(argv[0], argv[j]);
  206.                 return (SA_FAIL);
  207.             }
  208.  
  209.             strcpy(ServiceName, argv[j]);
  210.             strcpy(ServiceTitle, argv[j]);
  211.         }
  212.         else if (strcmp(argv[j], "-c") == 0)
  213.         {
  214.             j++;
  215.             if (j == argc)
  216.             {
  217.                 syntax_error(argv[0], argv[j]);
  218.                 return (SA_FAIL);
  219.             }
  220.  
  221.             strcpy(ConfigDir, argv[j]);
  222.             SaInit.i_configdir = ConfigDir;
  223.         }
  224.         else
  225.         {
  226.             syntax_error(argv[0], argv[j]);
  227.             return (SA_FAIL);
  228.         }
  229.  
  230.         j++;
  231.     }
  232.  
  233.     *flagsp = flags;
  234.  
  235.     /*
  236.     ** All done.
  237.     */
  238.     return (SA_SUCCEED);
  239. }
  240.  
  241. /*
  242. ** SYNTAX_ERROR
  243. **
  244. **     This routine is used to inform the user that a command-line
  245. **     syntax error occurred.
  246. */
  247. static void
  248. syntax_error(char *name, char *argv)
  249. {
  250.     /*
  251.     ** Print the error string.
  252.     */
  253.     if (argv != NULL)
  254.         fprintf(stderr, "\nUnexpected flag: %s\n", argv);
  255.  
  256.     fprintf(stderr, "\nCorrect syntax is: %s\n", name);
  257.  
  258.     fprintf(stderr, 
  259.         "  [-i]               # Install the NT Service\n");
  260.     fprintf(stderr, 
  261.         "  [-u]               # Unistall the NT Service\n");
  262.     fprintf(stderr, 
  263.         "  [-d]               # Start the Sambar Server in debug mode\n");
  264.     fprintf(stderr, 
  265.         "  [-s servicename]   # Optional NT Service name (default: Sambar Server)\n");
  266.     fprintf(stderr, 
  267.         "  [-c configdir]     # Optional config directory (default: Sambar install dir)\n");
  268.  
  269.     return;
  270. }
  271.  
  272. static SA_RETCODE
  273. install_service(void)
  274. {
  275.     SC_HANDLE    schService;
  276.     SC_HANDLE    schSCManager;
  277.     TCHAR         szPath[256];
  278.     TCHAR         szCmd[512];
  279.  
  280.     if (GetModuleFileName(NULL, szPath, 256) == 0)
  281.     {
  282.         fprintf(stderr, "Failed to get exe for service %s (%d)\n", 
  283.             ServiceName, GetLastError());
  284.         return (SA_FAIL);
  285.     }
  286.  
  287.     schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  288.  
  289.     if (schSCManager == NULL)
  290.     {
  291.         fprintf(stderr, "Failed to open the service manager.\n");
  292.         return (SA_FAIL);
  293.     }
  294.  
  295.     if (ConfigDir[0] != '\0')
  296.     {
  297.         sprintf(szCmd, "\"%s\" -c \"%s\" -s \"%s\"", szPath, ConfigDir,
  298.             ServiceName);
  299.     }
  300.     else if (strcmp(ServiceName, SERVICE_NAME) != 0)
  301.     {
  302.         sprintf(szCmd, "\"%s\" -s \"%s\"", szPath, ServiceName);
  303.     }
  304.     else
  305.     {
  306.         strcpy(szCmd, szPath);
  307.     }
  308.  
  309.     schService = CreateService(schSCManager, ServiceName, ServiceTitle,
  310.                     SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
  311.                     SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
  312.                     szCmd, NULL, NULL, "Tcpip\0", NULL, NULL);
  313.  
  314.  
  315.     if (schService == NULL)
  316.     {
  317.         fprintf(stderr, "Failed to create service %s (%d)\n", 
  318.             ServiceName, GetLastError());
  319.         CloseServiceHandle(schSCManager);
  320.         return (SA_FAIL);
  321.     }
  322.  
  323.     fprintf(stdout, "Installed service %s.\n", ServiceName);
  324.  
  325.     CloseServiceHandle(schService);
  326.     CloseServiceHandle(schSCManager);
  327.  
  328.     return (SA_SUCCEED);
  329. }
  330.  
  331. static SA_RETCODE
  332. uninstall_service(void)
  333. {
  334.     SC_HANDLE        schService;
  335.     SC_HANDLE        schSCManager;
  336.     SERVICE_STATUS    status;
  337.  
  338.     schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  339.  
  340.     if (schSCManager == NULL)
  341.     {
  342.         fprintf(stderr, "Failed to open the service manager.\n");
  343.         return (SA_FAIL);
  344.     }
  345.  
  346.     schService = OpenService(schSCManager, ServiceName, SERVICE_ALL_ACCESS);
  347.  
  348.     if (schService == NULL)
  349.     {
  350.         fprintf(stderr, "Failed to open service %s (%d).\n", 
  351.             ServiceName, GetLastError());
  352.         CloseServiceHandle(schSCManager);
  353.         return (SA_FAIL);
  354.     }
  355.  
  356.     /* Try to stop the service                                             */
  357.     if (ControlService(schService, SERVICE_CONTROL_STOP, &status))
  358.     {
  359.         Sleep(1000);
  360.         while (QueryServiceStatus(schService, &status))
  361.         {
  362.             if (status.dwCurrentState == SERVICE_STOP_PENDING)
  363.                 Sleep(1000);
  364.             else
  365.                 break;
  366.         }
  367.     }
  368.  
  369.     /* Delete the service                                                */
  370.     if (DeleteService(schService) != TRUE)
  371.     {
  372.         fprintf(stderr, "Failed in attempt to delete service %s (%d).\n", 
  373.             ServiceName, GetLastError());
  374.         CloseServiceHandle(schService);
  375.         CloseServiceHandle(schSCManager);
  376.         return (SA_FAIL);
  377.     }
  378.  
  379.     fprintf(stdout, "Deleted service %s.\n", ServiceName);
  380.     CloseServiceHandle(schService);
  381.     CloseServiceHandle(schSCManager);
  382.  
  383.     return (SA_SUCCEED);
  384. }
  385.  
  386. VOID
  387. service_main(DWORD argc, LPTSTR *argv)
  388. {
  389.     SA_INT        flags;
  390.  
  391.     /* Get an configuration arguments                                    */
  392.     (void)get_args(argc, argv, &flags);
  393.  
  394.     hServiceStatus = RegisterServiceCtrlHandler(ServiceName, 
  395.                         (LPHANDLER_FUNCTION)service_ctrl);
  396.     if (!hServiceStatus)
  397.     {
  398.         fprintf(stderr, "Failed to register %s service control handler (%d).\n",
  399.             ServiceName, GetLastError());
  400.         return;
  401.     }
  402.  
  403.     service_status(SERVICE_START_PENDING, NO_ERROR, 5000);
  404.     service_status(SERVICE_RUNNING, NO_ERROR, 0);
  405.  
  406.     /* Start the Sambar Server                                            */
  407.     create_pipe();
  408.     sa_server2((SA_VOID *)&SaInit);
  409.     close_pipe();
  410.  
  411.     service_status(SERVICE_STOPPED, NO_ERROR, 0);
  412.  
  413.     return;
  414. }
  415.  
  416. VOID
  417. service_ctrl(DWORD dwCtrlCode)
  418. {
  419.     int     state;
  420.  
  421.     state = sState;
  422.  
  423.     switch(dwCtrlCode)
  424.     {
  425.     // Stop the service.
  426.     //
  427.     case SERVICE_CONTROL_STOP:
  428.     case SERVICE_CONTROL_SHUTDOWN:
  429.           service_status(SERVICE_STOP_PENDING, NO_ERROR, 8000);
  430.  
  431.         (SA_VOID)sa_shutdown(0);
  432.         return;
  433.  
  434.     // Update the service status.
  435.     //
  436.     case SERVICE_CONTROL_INTERROGATE:
  437.         break;
  438.  
  439.     // invalid control code
  440.     //
  441.     default:
  442.         break;
  443.     }
  444.  
  445.     service_status(state, NO_ERROR, 0);
  446. }
  447.  
  448.  
  449. static void
  450. service_status(int state, int exitCode, int waitHint)
  451. {
  452.     SERVICE_STATUS    status;
  453.     
  454.     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  455.     status.dwServiceSpecificExitCode = 0;
  456.     status.dwCheckPoint = 0;
  457.  
  458.     if (state == SERVICE_START_PENDING)
  459.     {
  460.         status.dwControlsAccepted = 0;
  461.     }
  462.     else
  463.     {
  464.         status.dwControlsAccepted =    SERVICE_ACCEPT_STOP | 
  465.                                     SERVICE_ACCEPT_SHUTDOWN;
  466.     }
  467.  
  468.     sState = state;
  469.     status.dwCurrentState = state;
  470.     status.dwWin32ExitCode = exitCode;
  471.     status.dwWaitHint = waitHint;
  472.  
  473.     (VOID)SetServiceStatus(hServiceStatus, &status);
  474.  
  475.     return;
  476. }
  477.  
  478. static SA_RETCODE
  479. service_cd(void)
  480. {
  481.     int            count;
  482.     DWORD        len;
  483.     TCHAR         szPath[512];
  484.  
  485.     len = GetModuleFileName(NULL, szPath, 512);
  486.     if (len == 0)
  487.     {
  488.         fprintf(stderr, "Failed to get exe for service %s (%d)\n", 
  489.             ServiceName, GetLastError());
  490.         return (SA_FAIL);
  491.     }
  492.  
  493.     /* 
  494.     ** Change to the directory above the executable.                    
  495.     **
  496.     ** The working directory for the Sambar Server application must
  497.     ** be the installation directory.
  498.     */
  499.     count = 0;
  500.     while ((len > 0) && (count < 2))
  501.     {
  502.         len--;
  503.         if (szPath[len] == '\\')
  504.         {
  505.             count++;
  506.             szPath[len] = '\0';
  507.         }
  508.     }
  509.  
  510.     if (count != 2)
  511.     {
  512.         fprintf(stderr, 
  513.             "Unable to change to the Sambar Server installation directory.\n");
  514.         return (SA_FAIL);
  515.     }
  516.  
  517.     if (chdir(szPath) != 0)
  518.     {
  519.         fprintf(stderr, 
  520.             "Unable to change to the Sambar Server installation directory.\n");
  521.         return (SA_FAIL);
  522.     }
  523.  
  524.     return (SA_SUCCEED);
  525. }
  526.  
  527. static void
  528. create_pipe()
  529. {
  530.     /* Create the completion port for named-pipe client connection    */
  531.     hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, CK_PIPE, 0);
  532.     if (hIOCP == INVALID_HANDLE_VALUE)
  533.     {
  534.         fprintf(stderr, "Failure creating I/O completion port [%d]",
  535.             GetLastError());
  536.         return;
  537.     }
  538.  
  539.     /* Create a pipe that clients can connect to.                    */
  540.     hPipe = CreateNamedPipe("\\\\.\\pipe\\SambarServer",
  541.         PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE, 
  542.         1, 0, 1024, 1000, (LPSECURITY_ATTRIBUTES)NULL);
  543.     if (hPipe == INVALID_HANDLE_VALUE)
  544.     {
  545.         fprintf(stderr,
  546.             "Failure creating named pipe for interactive display [%d]",
  547.             GetLastError());
  548.         CloseHandle(hIOCP);
  549.         hIOCP = NULL;
  550.     }
  551.  
  552.     /* Associate the pipe                                                */
  553.     CreateIoCompletionPort(hPipe, hIOCP, CK_PIPE, 0);
  554.  
  555.     /* Pend an asynchronous connect against the pipe.                    */
  556.     memset(&o, 0, sizeof(o));
  557.     ConnectNamedPipe(hPipe, &o);
  558. }
  559.  
  560. static void
  561. close_pipe()
  562. {
  563.     if ((hIOCP != NULL) && (hIOCP != INVALID_HANDLE_VALUE))
  564.     {
  565.         CloseHandle(hIOCP);
  566.         hIOCP = NULL;
  567.     }
  568.  
  569.     if ((hPipe != NULL) && (hPipe != INVALID_HANDLE_VALUE))
  570.     {
  571.         CloseHandle(hPipe);
  572.         hPipe = NULL;
  573.     }
  574. }
  575.  
  576. static void
  577. HTTPLog(SA_CTX *ctx, SA_HTTPLOG    *httplog)
  578. {
  579.     int            i;
  580.     int            n;
  581.     DWORD        dwComp;
  582.     DWORD        dwBytes;
  583.     OVERLAPPED    *po;
  584.     char        timestr[32];
  585.     char        str[2048];
  586.  
  587.     if ((!bConnected) && (hPipe != NULL) && (hPipe != INVALID_HANDLE_VALUE))
  588.     {
  589.         while (GetQueuedCompletionStatus(hIOCP, &dwBytes, &dwComp, &po, 0))
  590.         {
  591.             if (dwComp == CK_PIPE)
  592.             {
  593.                 bConnected = TRUE;
  594.             }
  595.         }
  596.     }
  597.  
  598.     if (!bConnected)
  599.         return;
  600.  
  601.     i = 0;
  602.     while ((httplog->timestamp[i] != '\0') && (httplog->timestamp[i] != ':'))
  603.         i++;
  604.  
  605.     n = 0;
  606.     while ((httplog->timestamp[i] != '\0') && 
  607.         (httplog->timestamp[i] != ' ') &&
  608.         (n < 16))
  609.     {
  610.         timestr[n] = httplog->timestamp[i];
  611.         n++;
  612.         i++;
  613.     }
  614.  
  615.     timestr[0] = '[';
  616.     timestr[n] = ']';
  617.     timestr[n+1] = '\0';
  618.  
  619.     sprintf(str, "[%s]  %s  %s  %ld  %s  %s    %ld", 
  620.         httplog->vhost, timestr, httplog->user, httplog->status, 
  621.         httplog->method, httplog->request, httplog->size);
  622.     if (!WriteFile(hPipe, str, strlen(str), &n, NULL))
  623.     {
  624.         /* Error occurred writing on pipe, client disconnected. */
  625.         bConnected = FALSE;
  626.         DisconnectNamedPipe(hPipe);
  627.         memset(&o, 0, sizeof(o));
  628.         ConnectNamedPipe(hPipe, &o);
  629.     }
  630.     else
  631.     {
  632.         FlushFileBuffers(hPipe);
  633.     }
  634.  
  635.     return;
  636. }
  637.