[SCHEDSVC]
[reactos.git] / reactos / base / services / schedsvc / rpcserver.c
1 /*
2 * ReactOS Services
3 * Copyright (C) 2015 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS Services
22 * FILE: base/services/schedsvc/rpcserver.c
23 * PURPOSE: Scheduler service
24 * PROGRAMMER: Eric Kohl <eric.kohl@reactos.org>
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "precomp.h"
30
31 #include "lmerr.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(schedsvc);
34
35
36 /* FUNCTIONS *****************************************************************/
37
38 DWORD
39 WINAPI
40 RpcThreadRoutine(
41 LPVOID lpParameter)
42 {
43 RPC_STATUS Status;
44
45 Status = RpcServerUseProtseqEpW(L"ncacn_np", 20, L"\\pipe\\atsvc", NULL);
46 if (Status != RPC_S_OK)
47 {
48 ERR("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
49 return 0;
50 }
51
52 Status = RpcServerRegisterIf(atsvc_v1_0_s_ifspec, NULL, NULL);
53 if (Status != RPC_S_OK)
54 {
55 ERR("RpcServerRegisterIf() failed (Status %lx)\n", Status);
56 return 0;
57 }
58
59 Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE);
60 if (Status != RPC_S_OK)
61 {
62 ERR("RpcServerListen() failed (Status %lx)\n", Status);
63 }
64
65 return 0;
66 }
67
68
69 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
70 {
71 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
72 }
73
74
75 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
76 {
77 HeapFree(GetProcessHeap(), 0, ptr);
78 }
79
80
81 /* Function 0 */
82 NET_API_STATUS
83 WINAPI
84 NetrJobAdd(
85 ATSVC_HANDLE ServerName,
86 LPAT_INFO pAtInfo,
87 LPDWORD pJobId)
88 {
89 PJOB pJob;
90
91 TRACE("NetrJobAdd(%S %p %p)\n",
92 ServerName, pAtInfo, pJobId);
93
94 /* Allocate a new job object */
95 pJob = HeapAlloc(GetProcessHeap(),
96 HEAP_ZERO_MEMORY,
97 sizeof(JOB) + wcslen(pAtInfo->Command) * sizeof(WCHAR));
98 if (pJob == NULL)
99 return ERROR_OUTOFMEMORY;
100
101 /* Initialize the job object */
102 pJob->JobTime = pAtInfo->JobTime;
103 pJob->DaysOfMonth = pAtInfo->DaysOfMonth;
104 pJob->DaysOfWeek = pAtInfo->DaysOfWeek;
105 pJob->Flags = pAtInfo->Flags;
106 wcscpy(pJob->Command, pAtInfo->Command);
107
108 /* Acquire the job list lock exclusively */
109 RtlAcquireResourceExclusive(&JobListLock, TRUE);
110
111 /* Assign a new job ID */
112 pJob->JobId = dwNextJobId++;
113 dwJobCount++;
114
115 /* Append the new job to the job list */
116 InsertTailList(&JobListHead, &pJob->JobEntry);
117
118 /* Release the job list lock */
119 RtlReleaseResource(&JobListLock);
120
121 /* Save the job in the registry */
122 SaveJob(pJob);
123
124 /* Calculate the next start time */
125 CalculateNextStartTime(pJob);
126
127 // Insert job into the start list
128
129 // Update the start timer
130
131 /* Return the new job ID */
132 *pJobId = pJob->JobId;
133
134 return ERROR_SUCCESS;
135 }
136
137
138 /* Function 1 */
139 NET_API_STATUS
140 WINAPI
141 NetrJobDel(
142 ATSVC_HANDLE ServerName,
143 DWORD MinJobId,
144 DWORD MaxJobId)
145 {
146 PLIST_ENTRY JobEntry, NextEntry;
147 PJOB CurrentJob;
148
149 TRACE("NetrJobDel(%S %lu %lu)\n",
150 ServerName, MinJobId, MaxJobId);
151
152 /* Check the job IDs */
153 if (MinJobId > MaxJobId)
154 return ERROR_INVALID_PARAMETER;
155
156 /* Acquire the job list lock exclusively */
157 RtlAcquireResourceExclusive(&JobListLock, TRUE);
158
159 JobEntry = JobListHead.Flink;
160 while (JobEntry != &JobListHead)
161 {
162 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, JobEntry);
163
164 if ((CurrentJob->JobId >= MinJobId) && (CurrentJob->JobId <= MaxJobId))
165 {
166 // Remove job from the start list
167
168 // Update the start timer
169
170 /* Remove the job from the registry */
171 DeleteJob(CurrentJob);
172
173 NextEntry = JobEntry->Flink;
174 if (RemoveEntryList(JobEntry))
175 {
176 dwJobCount--;
177 HeapFree(GetProcessHeap(), 0, CurrentJob);
178 JobEntry = NextEntry;
179 continue;
180 }
181 }
182
183 JobEntry = JobEntry->Flink;
184 }
185
186 /* Release the job list lock */
187 RtlReleaseResource(&JobListLock);
188
189 return ERROR_SUCCESS;
190 }
191
192
193 /* Function 2 */
194 NET_API_STATUS
195 __stdcall
196 NetrJobEnum(
197 ATSVC_HANDLE ServerName,
198 LPAT_ENUM_CONTAINER pEnumContainer,
199 DWORD PreferedMaximumLength,
200 LPDWORD pTotalEntries,
201 LPDWORD pResumeHandle)
202 {
203 PLIST_ENTRY JobEntry;
204 PJOB CurrentJob;
205 PAT_ENUM pEnum;
206 DWORD dwStartIndex, dwIndex;
207 DWORD dwEntriesToRead, dwEntriesRead;
208 DWORD dwRequiredSize, dwEntrySize;
209 PWSTR pString;
210 DWORD dwError = ERROR_SUCCESS;
211
212 TRACE("NetrJobEnum(%S %p %lu %p %p)\n",
213 ServerName, pEnumContainer, PreferedMaximumLength, pTotalEntries, pResumeHandle);
214
215 if (pEnumContainer == NULL)
216 {
217 *pTotalEntries = 0;
218 return ERROR_INVALID_PARAMETER;
219 }
220
221 if (*pResumeHandle >= dwJobCount)
222 {
223 *pTotalEntries = 0;
224 return ERROR_SUCCESS;
225 }
226
227 dwStartIndex = *pResumeHandle;
228 TRACE("dwStartIndex: %lu\n", dwStartIndex);
229
230 /* Acquire the job list lock exclusively */
231 RtlAcquireResourceShared(&JobListLock, TRUE);
232
233 dwEntriesToRead = 0;
234 dwRequiredSize = 0;
235 dwIndex = 0;
236 JobEntry = JobListHead.Flink;
237 while (JobEntry != &JobListHead)
238 {
239 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, JobEntry);
240
241 if (dwIndex >= dwStartIndex)
242 {
243 TRACE("dwIndex: %lu\n", dwIndex);
244 dwEntrySize = sizeof(AT_ENUM) +
245 (wcslen(CurrentJob->Command) + 1) * sizeof(WCHAR);
246 TRACE("dwEntrySize: %lu\n", dwEntrySize);
247
248 if ((PreferedMaximumLength != DWORD_MAX) &&
249 (dwRequiredSize + dwEntrySize > PreferedMaximumLength))
250 break;
251
252 dwRequiredSize += dwEntrySize;
253 dwEntriesToRead++;
254 }
255
256 JobEntry = JobEntry->Flink;
257 dwIndex++;
258 }
259 TRACE("dwEntriesToRead: %lu\n", dwEntriesToRead);
260 TRACE("dwRequiredSize: %lu\n", dwRequiredSize);
261
262 if (PreferedMaximumLength != DWORD_MAX)
263 dwRequiredSize = PreferedMaximumLength;
264
265 TRACE("Allocating dwRequiredSize: %lu\n", dwRequiredSize);
266 pEnum = midl_user_allocate(dwRequiredSize);
267 if (pEnum == NULL)
268 {
269 dwError = ERROR_OUTOFMEMORY;
270 goto done;
271 }
272
273 pString = (PWSTR)((ULONG_PTR)pEnum + dwEntriesToRead * sizeof(AT_ENUM));
274
275 dwEntriesRead = 0;
276 dwIndex = 0;
277 JobEntry = JobListHead.Flink;
278 while (JobEntry != &JobListHead)
279 {
280 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, JobEntry);
281
282 if (dwIndex >= dwStartIndex)
283 {
284 pEnum[dwIndex].JobId = CurrentJob->JobId;
285 pEnum[dwIndex].JobTime = CurrentJob->JobTime;
286 pEnum[dwIndex].DaysOfMonth = CurrentJob->DaysOfMonth;
287 pEnum[dwIndex].DaysOfWeek = CurrentJob->DaysOfWeek;
288 pEnum[dwIndex].Flags = CurrentJob->Flags;
289 pEnum[dwIndex].Command = pString;
290 wcscpy(pString, CurrentJob->Command);
291
292 pString = (PWSTR)((ULONG_PTR)pString + (wcslen(CurrentJob->Command) + 1) * sizeof(WCHAR));
293
294 dwEntriesRead++;
295 }
296
297 if (dwEntriesRead == dwEntriesToRead)
298 break;
299
300 /* Next job */
301 JobEntry = JobEntry->Flink;
302 dwIndex++;
303 }
304
305 pEnumContainer->EntriesRead = dwEntriesRead;
306 pEnumContainer->Buffer = pEnum;
307
308 *pTotalEntries = dwJobCount;
309 *pResumeHandle = dwIndex;
310
311 if (dwEntriesRead + dwStartIndex < dwJobCount)
312 dwError = ERROR_MORE_DATA;
313 else
314 dwError = ERROR_SUCCESS;
315
316 done:
317 /* Release the job list lock */
318 RtlReleaseResource(&JobListLock);
319
320 return dwError;
321 }
322
323
324 /* Function 3 */
325 NET_API_STATUS
326 WINAPI
327 NetrJobGetInfo(
328 ATSVC_HANDLE ServerName,
329 DWORD JobId,
330 LPAT_INFO *ppAtInfo)
331 {
332 PLIST_ENTRY JobEntry;
333 PJOB CurrentJob;
334 PAT_INFO pInfo;
335 DWORD dwError = ERROR_FILE_NOT_FOUND;
336
337 TRACE("NetrJobGetInfo(%S %lu %p)\n",
338 ServerName, JobId, ppAtInfo);
339
340 /* Acquire the job list lock exclusively */
341 RtlAcquireResourceShared(&JobListLock, TRUE);
342
343 /* Traverse the job list */
344 JobEntry = JobListHead.Flink;
345 while (JobEntry != &JobListHead)
346 {
347 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, JobEntry);
348
349 /* Do we have the right job? */
350 if (CurrentJob->JobId == JobId)
351 {
352 pInfo = midl_user_allocate(sizeof(AT_INFO));
353 if (pInfo == NULL)
354 {
355 dwError = ERROR_OUTOFMEMORY;
356 goto done;
357 }
358
359 pInfo->Command = midl_user_allocate((wcslen(CurrentJob->Command) + 1) * sizeof(WCHAR));
360 if (pInfo->Command == NULL)
361 {
362 midl_user_free(pInfo);
363 dwError = ERROR_OUTOFMEMORY;
364 goto done;
365 }
366
367 pInfo->JobTime = CurrentJob->JobTime;
368 pInfo->DaysOfMonth = CurrentJob->DaysOfMonth;
369 pInfo->DaysOfWeek = CurrentJob->DaysOfWeek;
370 pInfo->Flags = CurrentJob->Flags;
371 wcscpy(pInfo->Command, CurrentJob->Command);
372
373 *ppAtInfo = pInfo;
374
375 dwError = ERROR_SUCCESS;
376 goto done;
377 }
378
379 /* Next job */
380 JobEntry = JobEntry->Flink;
381 }
382
383 done:
384 /* Release the job list lock */
385 RtlReleaseResource(&JobListLock);
386
387 return dwError;
388 }
389
390 /* EOF */