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