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