summaryrefslogtreecommitdiff
path: root/ace/NT_Service.cpp
blob: 9229ed2e21905389054c543adb1b1f6a47dab11c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// $Id$

// NT_Service.cpp

#include "ace/inc_user_config.h"
#if defined (ACE_HAS_WINNT4) && ACE_HAS_WINNT4 != 0

#define ACE_BUILD_DLL
#include "ace/NT_Service.h"
#include "ace/Service_Object.h"

#if !defined (__ACE_INLINE__)
#include "ace/NT_Service.i"
#endif /* __ACE_INLINE__ */

ACE_ALLOC_HOOK_DEFINE(ACE_NT_Service)

// This default implementation of ACE_NT_Service::open sets the service's
// status to START_PENDING with the estimated time until STARTED set to the
// value given when this object was constructed.  Then the svc function is
// called, which implements the guts of the service.  Note that this function
// is running in a thread created by the OS, not by ACE_Thread_Manager.
// The thread manager does not know anything about this thread.  The service
// can, however, use ACE_Thread_Manager to start more threads if desired.
// When the svc function returns, the service status is set to STOPPED, and
// exit codes set based on errno/GetLastError if the svc function returns -1.
//
// The svc function is expected to set the service status to SERVICE_RUNNING
// after it initializes.
//
// The handle_control function will be called for each time there is a request
// for the service.  It is up to that function and svc to cooperate to both
// respond appropriately to the request (by at least updating the service's
// status) and to fulfill the request.

int
ACE_NT_Service::open (void *args)
{

int svc_return;

  report_status(SERVICE_START_PENDING, 0);

  if ((svc_return = this->svc()) == 0) {
    this->svc_status_.dwWin32ExitCode = NO_ERROR;
    this->svc_status_.dwServiceSpecificExitCode = 0;
  }
  else {
    if (errno == 0) {
      this->svc_status_.dwWin32ExitCode = GetLastError();
    }
    else {
      this->svc_status_.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
      this->svc_status_.dwServiceSpecificExitCode = errno;
    }
  }

  report_status(SERVICE_STOPPED, 0);

  return svc_return;

}

void
ACE_NT_Service::handle_control (DWORD control_code)
{

  switch(control_code) {
  case SERVICE_CONTROL_SHUTDOWN:
  case SERVICE_CONTROL_STOP:
    report_status(SERVICE_STOP_PENDING);
    /* how to cancel? */
    break;

  case SERVICE_CONTROL_PAUSE:
    report_status(SERVICE_PAUSE_PENDING);
    this->suspend();
    report_status(SERVICE_PAUSED);
    break;

  case SERVICE_CONTROL_CONTINUE:
    report_status(SERVICE_CONTINUE_PENDING);
    this->resume();
    report_status(SERVICE_RUNNING);
    break;

  case SERVICE_CONTROL_INTERROGATE:
    report_status(0);
    break;
  }

  return;

}



// report_status
//
// Reports the current status.  If new_status is not 0, it sets the 
// status to the new value before reporting.  NOTE - this assumes that
// no actual service status values have the value 0.  This is true in
// WinNT 4.
// If the status is a 'pending' type, the supplied time hint is used
// unless it's 0, in which case the existing hint is used.  The dwWaitHint
// is not updated by this function.  The checkpoint is incremented
// by one after a pending report.
// 
int
ACE_NT_Service::report_status (DWORD new_status, DWORD time_hint)
{

int   bump_checkpoint = 0,
      retval = 0;
DWORD save_controls = 0;


  if (new_status != 0)
    this->svc_status_.dwCurrentState = new_status;
  switch(this->svc_status_.dwCurrentState) {
  case SERVICE_START_PENDING:
    save_controls = this->svc_status_.dwControlsAccepted;
    this->svc_status_.dwControlsAccepted = 0;
    /* Fall through */
  case SERVICE_STOP_PENDING:
  case SERVICE_CONTINUE_PENDING:
  case SERVICE_PAUSE_PENDING:
    this->svc_status_.dwWaitHint = time_hint ? time_hint : this->start_time_;
    bump_checkpoint = 1;
    break;

  default:
    this->svc_status_.dwCheckPoint = 0;
  }

  retval = SetServiceStatus(this->svc_handle_, &this->svc_status_) ? 0 : -1;

  if (save_controls != 0)
    this->svc_status_.dwControlsAccepted = save_controls;

  if (bump_checkpoint)
    ++this->svc_status_.dwCheckPoint;

  return retval;

}

#endif /* ACE_HAS_WINNT4 */