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