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