1ca2b353ee219a21f43cbf6192c46ce1236acf8b
[reactos.git] / 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 // Cancel the start timer
116
117 /* Append the new job to the job list */
118 InsertTailList(&JobListHead, &pJob->JobEntry);
119
120 /* Save the job in the registry */
121 SaveJob(pJob);
122
123 /* Calculate the next start time */
124 CalculateNextStartTime(pJob);
125
126 /* Insert the job into the start list */
127 InsertJobIntoStartList(&StartListHead, pJob);
128 #if 0
129 DumpStartList(&StartListHead);
130 #endif
131
132 // Update the start timer
133
134 /* Release the job list lock */
135 RtlReleaseResource(&JobListLock);
136
137 /* Return the new job ID */
138 *pJobId = pJob->JobId;
139
140 return ERROR_SUCCESS;
141 }
142
143
144 /* Function 1 */
145 NET_API_STATUS
146 WINAPI
147 NetrJobDel(
148 ATSVC_HANDLE ServerName,
149 DWORD MinJobId,
150 DWORD MaxJobId)
151 {
152 PLIST_ENTRY JobEntry, NextEntry;
153 PJOB CurrentJob;
154
155 TRACE("NetrJobDel(%S %lu %lu)\n",
156 ServerName, MinJobId, MaxJobId);
157
158 /* Check the job IDs */
159 if (MinJobId > MaxJobId)
160 return ERROR_INVALID_PARAMETER;
161
162 /* Acquire the job list lock exclusively */
163 RtlAcquireResourceExclusive(&JobListLock, TRUE);
164
165 // Cancel the start timer
166
167 JobEntry = JobListHead.Flink;
168 while (JobEntry != &JobListHead)
169 {
170 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, JobEntry);
171
172 if ((CurrentJob->JobId >= MinJobId) && (CurrentJob->JobId <= MaxJobId))
173 {
174 /* Remove the job from the start list */
175 RemoveEntryList(&CurrentJob->StartEntry);
176 #if 0
177 DumpStartList(&StartListHead);
178 #endif
179
180 /* Remove the job from the registry */
181 DeleteJob(CurrentJob);
182
183 NextEntry = JobEntry->Flink;
184 if (RemoveEntryList(JobEntry))
185 {
186 dwJobCount--;
187 HeapFree(GetProcessHeap(), 0, CurrentJob);
188 JobEntry = NextEntry;
189 continue;
190 }
191 }
192
193 JobEntry = JobEntry->Flink;
194 }
195
196 // Update the start timer
197
198 /* Release the job list lock */
199 RtlReleaseResource(&JobListLock);
200
201 return ERROR_SUCCESS;
202 }
203
204
205 /* Function 2 */
206 NET_API_STATUS
207 __stdcall
208 NetrJobEnum(
209 ATSVC_HANDLE ServerName,
210 LPAT_ENUM_CONTAINER pEnumContainer,
211 DWORD PreferedMaximumLength,
212 LPDWORD pTotalEntries,
213 LPDWORD pResumeHandle)
214 {
215 PLIST_ENTRY JobEntry;
216 PJOB CurrentJob;
217 PAT_ENUM pEnum;
218 DWORD dwStartIndex, dwIndex;
219 DWORD dwEntriesToRead, dwEntriesRead;
220 DWORD dwRequiredSize, dwEntrySize;
221 PWSTR pString;
222 DWORD dwError = ERROR_SUCCESS;
223
224 TRACE("NetrJobEnum(%S %p %lu %p %p)\n",
225 ServerName, pEnumContainer, PreferedMaximumLength, pTotalEntries, pResumeHandle);
226
227 if (pEnumContainer == NULL)
228 {
229 *pTotalEntries = 0;
230 return ERROR_INVALID_PARAMETER;
231 }
232
233 if (*pResumeHandle >= dwJobCount)
234 {
235 *pTotalEntries = 0;
236 return ERROR_SUCCESS;
237 }
238
239 dwStartIndex = *pResumeHandle;
240 TRACE("dwStartIndex: %lu\n", dwStartIndex);
241
242 /* Acquire the job list lock exclusively */
243 RtlAcquireResourceShared(&JobListLock, TRUE);
244
245 dwEntriesToRead = 0;
246 dwRequiredSize = 0;
247 dwIndex = 0;
248 JobEntry = JobListHead.Flink;
249 while (JobEntry != &JobListHead)
250 {
251 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, JobEntry);
252
253 if (dwIndex >= dwStartIndex)
254 {
255 TRACE("dwIndex: %lu\n", dwIndex);
256 dwEntrySize = sizeof(AT_ENUM) +
257 (wcslen(CurrentJob->Command) + 1) * sizeof(WCHAR);
258 TRACE("dwEntrySize: %lu\n", dwEntrySize);
259
260 if ((PreferedMaximumLength != ULONG_MAX) &&
261 (dwRequiredSize + dwEntrySize > PreferedMaximumLength))
262 break;
263
264 dwRequiredSize += dwEntrySize;
265 dwEntriesToRead++;
266 }
267
268 JobEntry = JobEntry->Flink;
269 dwIndex++;
270 }
271 TRACE("dwEntriesToRead: %lu\n", dwEntriesToRead);
272 TRACE("dwRequiredSize: %lu\n", dwRequiredSize);
273
274 if (PreferedMaximumLength != ULONG_MAX)
275 dwRequiredSize = PreferedMaximumLength;
276
277 TRACE("Allocating dwRequiredSize: %lu\n", dwRequiredSize);
278 pEnum = midl_user_allocate(dwRequiredSize);
279 if (pEnum == NULL)
280 {
281 dwError = ERROR_OUTOFMEMORY;
282 goto done;
283 }
284
285 pString = (PWSTR)((ULONG_PTR)pEnum + dwEntriesToRead * sizeof(AT_ENUM));
286
287 dwEntriesRead = 0;
288 dwIndex = 0;
289 JobEntry = JobListHead.Flink;
290 while (JobEntry != &JobListHead)
291 {
292 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, JobEntry);
293
294 if (dwIndex >= dwStartIndex)
295 {
296 pEnum[dwIndex].JobId = CurrentJob->JobId;
297 pEnum[dwIndex].JobTime = CurrentJob->JobTime;
298 pEnum[dwIndex].DaysOfMonth = CurrentJob->DaysOfMonth;
299 pEnum[dwIndex].DaysOfWeek = CurrentJob->DaysOfWeek;
300 pEnum[dwIndex].Flags = CurrentJob->Flags;
301 pEnum[dwIndex].Command = pString;
302 wcscpy(pString, CurrentJob->Command);
303
304 pString = (PWSTR)((ULONG_PTR)pString + (wcslen(CurrentJob->Command) + 1) * sizeof(WCHAR));
305
306 dwEntriesRead++;
307 }
308
309 if (dwEntriesRead == dwEntriesToRead)
310 break;
311
312 /* Next job */
313 JobEntry = JobEntry->Flink;
314 dwIndex++;
315 }
316
317 pEnumContainer->EntriesRead = dwEntriesRead;
318 pEnumContainer->Buffer = pEnum;
319
320 *pTotalEntries = dwJobCount;
321 *pResumeHandle = dwIndex;
322
323 if (dwEntriesRead + dwStartIndex < dwJobCount)
324 dwError = ERROR_MORE_DATA;
325 else
326 dwError = ERROR_SUCCESS;
327
328 done:
329 /* Release the job list lock */
330 RtlReleaseResource(&JobListLock);
331
332 return dwError;
333 }
334
335
336 /* Function 3 */
337 NET_API_STATUS
338 WINAPI
339 NetrJobGetInfo(
340 ATSVC_HANDLE ServerName,
341 DWORD JobId,
342 LPAT_INFO *ppAtInfo)
343 {
344 PLIST_ENTRY JobEntry;
345 PJOB CurrentJob;
346 PAT_INFO pInfo;
347 DWORD dwError = ERROR_FILE_NOT_FOUND;
348
349 TRACE("NetrJobGetInfo(%S %lu %p)\n",
350 ServerName, JobId, ppAtInfo);
351
352 /* Acquire the job list lock exclusively */
353 RtlAcquireResourceShared(&JobListLock, TRUE);
354
355 /* Traverse the job list */
356 JobEntry = JobListHead.Flink;
357 while (JobEntry != &JobListHead)
358 {
359 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, JobEntry);
360
361 /* Do we have the right job? */
362 if (CurrentJob->JobId == JobId)
363 {
364 pInfo = midl_user_allocate(sizeof(AT_INFO));
365 if (pInfo == NULL)
366 {
367 dwError = ERROR_OUTOFMEMORY;
368 goto done;
369 }
370
371 pInfo->Command = midl_user_allocate((wcslen(CurrentJob->Command) + 1) * sizeof(WCHAR));
372 if (pInfo->Command == NULL)
373 {
374 midl_user_free(pInfo);
375 dwError = ERROR_OUTOFMEMORY;
376 goto done;
377 }
378
379 pInfo->JobTime = CurrentJob->JobTime;
380 pInfo->DaysOfMonth = CurrentJob->DaysOfMonth;
381 pInfo->DaysOfWeek = CurrentJob->DaysOfWeek;
382 pInfo->Flags = CurrentJob->Flags;
383 wcscpy(pInfo->Command, CurrentJob->Command);
384
385 *ppAtInfo = pInfo;
386
387 dwError = ERROR_SUCCESS;
388 goto done;
389 }
390
391 /* Next job */
392 JobEntry = JobEntry->Flink;
393 }
394
395 done:
396 /* Release the job list lock */
397 RtlReleaseResource(&JobListLock);
398
399 return dwError;
400 }
401
402 /* EOF */