[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 #define DWORD_MAX 0xffffffffUL
36
37 typedef struct _JOB
38 {
39 LIST_ENTRY Entry;
40 DWORD JobId;
41
42 DWORD_PTR JobTime;
43 DWORD DaysOfMonth;
44 UCHAR DaysOfWeek;
45 UCHAR Flags;
46 WCHAR Command[1];
47 } JOB, *PJOB;
48
49 DWORD dwNextJobId = 0;
50 DWORD dwJobCount = 0;
51 LIST_ENTRY JobListHead;
52 RTL_RESOURCE JobListLock;
53
54
55 /* FUNCTIONS *****************************************************************/
56
57 DWORD
58 WINAPI
59 RpcThreadRoutine(
60 LPVOID lpParameter)
61 {
62 RPC_STATUS Status;
63
64 Status = RpcServerUseProtseqEpW(L"ncacn_np", 20, L"\\pipe\\atsvc", NULL);
65 if (Status != RPC_S_OK)
66 {
67 ERR("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
68 return 0;
69 }
70
71 Status = RpcServerRegisterIf(atsvc_v1_0_s_ifspec, NULL, NULL);
72 if (Status != RPC_S_OK)
73 {
74 ERR("RpcServerRegisterIf() failed (Status %lx)\n", Status);
75 return 0;
76 }
77
78 Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE);
79 if (Status != RPC_S_OK)
80 {
81 ERR("RpcServerListen() failed (Status %lx)\n", Status);
82 }
83
84 return 0;
85 }
86
87
88 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
89 {
90 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
91 }
92
93
94 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
95 {
96 HeapFree(GetProcessHeap(), 0, ptr);
97 }
98
99
100 /* Function 0 */
101 NET_API_STATUS
102 WINAPI
103 NetrJobAdd(
104 ATSVC_HANDLE ServerName,
105 LPAT_INFO pAtInfo,
106 LPDWORD pJobId)
107 {
108 PJOB pJob;
109
110 TRACE("NetrJobAdd(%S %p %p)\n",
111 ServerName, pAtInfo, pJobId);
112
113 /* Allocate a new job object */
114 pJob = HeapAlloc(GetProcessHeap(),
115 HEAP_ZERO_MEMORY,
116 sizeof(JOB) + wcslen(pAtInfo->Command) * sizeof(WCHAR));
117 if (pJob == NULL)
118 return ERROR_OUTOFMEMORY;
119
120 /* Initialize the job object */
121 pJob->JobTime = pAtInfo->JobTime;
122 pJob->DaysOfMonth = pAtInfo->DaysOfMonth;
123 pJob->DaysOfWeek = pAtInfo->DaysOfWeek;
124 pJob->Flags = pAtInfo->Flags;
125 wcscpy(pJob->Command, pAtInfo->Command);
126
127 /* Acquire the job list lock exclusively */
128 RtlAcquireResourceExclusive(&JobListLock, TRUE);
129
130 /* Assign a new job ID */
131 pJob->JobId = dwNextJobId++;
132 dwJobCount++;
133
134 /* Append the new job to the job list */
135 InsertTailList(&JobListHead, &pJob->Entry);
136
137 /* Release the job list lock */
138 RtlReleaseResource(&JobListLock);
139
140 /* Return the new job ID */
141 *pJobId = pJob->JobId;
142
143 return ERROR_SUCCESS;
144 }
145
146
147 /* Function 1 */
148 NET_API_STATUS
149 WINAPI
150 NetrJobDel(
151 ATSVC_HANDLE ServerName,
152 DWORD MinJobId,
153 DWORD MaxJobId)
154 {
155 PLIST_ENTRY JobEntry, NextEntry;
156 PJOB CurrentJob;
157
158 TRACE("NetrJobDel(%S %lu %lu)\n",
159 ServerName, MinJobId, MaxJobId);
160
161 /* Acquire the job list lock exclusively */
162 RtlAcquireResourceExclusive(&JobListLock, TRUE);
163
164 JobEntry = JobListHead.Flink;
165 while (JobEntry != &JobListHead)
166 {
167 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, Entry);
168
169 if ((CurrentJob->JobId >= MinJobId) && (CurrentJob->JobId <= MaxJobId))
170 {
171 NextEntry = JobEntry->Flink;
172 if (RemoveEntryList(JobEntry))
173 {
174 dwJobCount--;
175 HeapFree(GetProcessHeap(), 0, CurrentJob);
176 JobEntry = NextEntry;
177 continue;
178 }
179 }
180
181 JobEntry = JobEntry->Flink;
182 }
183
184 /* Release the job list lock */
185 RtlReleaseResource(&JobListLock);
186
187 return ERROR_SUCCESS;
188 }
189
190
191 /* Function 2 */
192 NET_API_STATUS
193 __stdcall
194 NetrJobEnum(
195 ATSVC_HANDLE ServerName,
196 LPAT_ENUM_CONTAINER pEnumContainer,
197 DWORD PreferedMaximumLength,
198 LPDWORD pTotalEntries,
199 LPDWORD pResumeHandle)
200 {
201 PLIST_ENTRY JobEntry;
202 PJOB CurrentJob;
203 PAT_ENUM pEnum;
204 DWORD dwStartIndex, dwIndex;
205 DWORD dwEntriesToRead, dwEntriesRead;
206 DWORD dwRequiredSize, dwEntrySize;
207 PWSTR pString;
208 DWORD dwError = ERROR_SUCCESS;
209
210 TRACE("NetrJobEnum(%S %p %lu %p %p)\n",
211 ServerName, pEnumContainer, PreferedMaximumLength, pTotalEntries, pResumeHandle);
212
213 if (pEnumContainer == NULL)
214 {
215 *pTotalEntries = 0;
216 return ERROR_INVALID_PARAMETER;
217 }
218
219 if (*pResumeHandle >= dwJobCount)
220 {
221 *pTotalEntries = 0;
222 return ERROR_SUCCESS;
223 }
224
225 dwStartIndex = *pResumeHandle;
226 TRACE("dwStartIndex: %lu\n", dwStartIndex);
227
228 /* Acquire the job list lock exclusively */
229 RtlAcquireResourceShared(&JobListLock, TRUE);
230
231 dwEntriesToRead = 0;
232 dwRequiredSize = 0;
233 dwIndex = 0;
234 JobEntry = JobListHead.Flink;
235 while (JobEntry != &JobListHead)
236 {
237 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, Entry);
238
239 if (dwIndex >= dwStartIndex)
240 {
241 TRACE("dwIndex: %lu\n", dwIndex);
242 dwEntrySize = sizeof(AT_ENUM) +
243 (wcslen(CurrentJob->Command) + 1) * sizeof(WCHAR);
244 TRACE("dwEntrySize: %lu\n", dwEntrySize);
245
246 if ((PreferedMaximumLength != DWORD_MAX) &&
247 (dwRequiredSize + dwEntrySize > PreferedMaximumLength))
248 break;
249
250 dwRequiredSize += dwEntrySize;
251 dwEntriesToRead++;
252 }
253
254 JobEntry = JobEntry->Flink;
255 dwIndex++;
256 }
257 TRACE("dwEntriesToRead: %lu\n", dwEntriesToRead);
258 TRACE("dwRequiredSize: %lu\n", dwRequiredSize);
259
260 if (PreferedMaximumLength != DWORD_MAX)
261 dwRequiredSize = PreferedMaximumLength;
262
263 TRACE("Allocating dwRequiredSize: %lu\n", dwRequiredSize);
264 pEnum = midl_user_allocate(dwRequiredSize);
265 if (pEnum == NULL)
266 {
267 dwError = ERROR_OUTOFMEMORY;
268 goto done;
269 }
270
271 pString = (PWSTR)((ULONG_PTR)pEnum + dwEntriesToRead * sizeof(AT_ENUM));
272
273 dwEntriesRead = 0;
274 dwIndex = 0;
275 JobEntry = JobListHead.Flink;
276 while (JobEntry != &JobListHead)
277 {
278 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, Entry);
279
280 if (dwIndex >= dwStartIndex)
281 {
282 pEnum[dwIndex].JobId = CurrentJob->JobId;
283 pEnum[dwIndex].JobTime = CurrentJob->JobTime;
284 pEnum[dwIndex].DaysOfMonth = CurrentJob->DaysOfMonth;
285 pEnum[dwIndex].DaysOfWeek = CurrentJob->DaysOfWeek;
286 pEnum[dwIndex].Flags = CurrentJob->Flags;
287 pEnum[dwIndex].Command = pString;
288 wcscpy(pString, CurrentJob->Command);
289
290 pString = (PWSTR)((ULONG_PTR)pString + (wcslen(CurrentJob->Command) + 1) * sizeof(WCHAR));
291
292 dwEntriesRead++;
293 }
294
295 if (dwEntriesRead == dwEntriesToRead)
296 break;
297
298 /* Next job */
299 JobEntry = JobEntry->Flink;
300 dwIndex++;
301 }
302
303 pEnumContainer->EntriesRead = dwEntriesRead;
304 pEnumContainer->Buffer = pEnum;
305
306 *pTotalEntries = dwJobCount;
307 *pResumeHandle = dwIndex;
308
309 if (dwEntriesRead + dwStartIndex < dwJobCount)
310 dwError = ERROR_MORE_DATA;
311 else
312 dwError = ERROR_SUCCESS;
313
314 done:
315 /* Release the job list lock */
316 RtlReleaseResource(&JobListLock);
317
318 return dwError;
319 }
320
321
322 /* Function 3 */
323 NET_API_STATUS
324 WINAPI
325 NetrJobGetInfo(
326 ATSVC_HANDLE ServerName,
327 DWORD JobId,
328 LPAT_INFO *ppAtInfo)
329 {
330 PLIST_ENTRY JobEntry;
331 PJOB CurrentJob;
332 PAT_INFO pInfo;
333 DWORD dwError = ERROR_FILE_NOT_FOUND;
334
335 TRACE("NetrJobGetInfo(%S %lu %p)\n",
336 ServerName, JobId, ppAtInfo);
337
338 /* Acquire the job list lock exclusively */
339 RtlAcquireResourceShared(&JobListLock, TRUE);
340
341 /* Traverse the job list */
342 JobEntry = JobListHead.Flink;
343 while (JobEntry != &JobListHead)
344 {
345 CurrentJob = CONTAINING_RECORD(JobEntry, JOB, Entry);
346
347 /* Do we have the right job? */
348 if (CurrentJob->JobId == JobId)
349 {
350 pInfo = midl_user_allocate(sizeof(AT_INFO));
351 if (pInfo == NULL)
352 {
353 dwError = ERROR_OUTOFMEMORY;
354 goto done;
355 }
356
357 pInfo->Command = midl_user_allocate((wcslen(CurrentJob->Command) + 1) * sizeof(WCHAR));
358 if (pInfo->Command == NULL)
359 {
360 midl_user_free(pInfo);
361 dwError = ERROR_OUTOFMEMORY;
362 goto done;
363 }
364
365 pInfo->JobTime = CurrentJob->JobTime;
366 pInfo->DaysOfMonth = CurrentJob->DaysOfMonth;
367 pInfo->DaysOfWeek = CurrentJob->DaysOfWeek;
368 pInfo->Flags = CurrentJob->Flags;
369 wcscpy(pInfo->Command, CurrentJob->Command);
370
371 *ppAtInfo = pInfo;
372
373 dwError = ERROR_SUCCESS;
374 goto done;
375 }
376
377 /* Next job */
378 JobEntry = JobEntry->Flink;
379 }
380
381 done:
382 /* Release the job list lock */
383 RtlReleaseResource(&JobListLock);
384
385 return dwError;
386 }
387
388 /* EOF */