xref: /reactos/base/services/schedsvc/rpcserver.c (revision 44323e61)
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     /* Insert the job into the start list */
125     InsertJobIntoStartList(&StartListHead, pJob);
126 #if 0
127     DumpStartList(&StartListHead);
128 #endif
129 
130     /* Release the job list lock */
131     RtlReleaseResource(&JobListLock);
132 
133     /* Set the update event */
134     if (Events[1] != NULL)
135         SetEvent(Events[1]);
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     JobEntry = JobListHead.Flink;
166     while (JobEntry != &JobListHead)
167     {
168         CurrentJob = CONTAINING_RECORD(JobEntry, JOB, JobEntry);
169 
170         if ((CurrentJob->JobId >= MinJobId) && (CurrentJob->JobId <= MaxJobId))
171         {
172             /* Remove the job from the start list */
173             RemoveEntryList(&CurrentJob->StartEntry);
174 #if 0
175             DumpStartList(&StartListHead);
176 #endif
177 
178             /* Remove the job from the registry */
179             DeleteJob(CurrentJob);
180 
181             NextEntry = JobEntry->Flink;
182             if (RemoveEntryList(JobEntry))
183             {
184                 dwJobCount--;
185                 HeapFree(GetProcessHeap(), 0, CurrentJob);
186                 JobEntry = NextEntry;
187                 continue;
188             }
189         }
190 
191         JobEntry = JobEntry->Flink;
192     }
193 
194     /* Release the job list lock */
195     RtlReleaseResource(&JobListLock);
196 
197     /* Set the update event */
198     if (Events[1] != NULL)
199         SetEvent(Events[1]);
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 */
403