Hi Everyone, I am experimenting with Semaphores as I am reading the Windows System 10 programming
book, I have this code, when it's run at first it's supposed to spin up the Semaphore Server and that works fine , but when I run another instance of it it's supposed to run the Semaphore Client, but on each attempt it just starts the server and the Client code never executes, I have confirmed with Process explorer that the Semaphore is indeed created. But no matter what I do the Client never runs.
#include <Windows.h>
#include <wininet.h>
#include <stdio.h>
#include <wchar.h>
#include <iostream>
#pragma comment(lib, "wininet.lib") // Link with wininet.lib
#define MAX_DOWNLOAD_COUNT 3
// Define a structure named 'DownloadObj'
struct DownloadObj {
WCHAR url[500];
WCHAR save_to[250];
};
BOOL DownloadHelper(WCHAR* url, WCHAR* save_to) {
BOOL success = FALSE;
DWORD bytesRead = 0;
BYTE buffer[4096];
DWORD bytesWritten = 0;
HINTERNET hInternet = NULL;
HINTERNET hUrl = NULL;
HANDLE fileHandle = INVALID_HANDLE_VALUE;
// Initialize WinINet
hInternet = ::InternetOpenW(L"WinINet Downloader/1.0",
INTERNET_OPEN_TYPE_PRECONFIG,
NULL, NULL, 0);
if (!hInternet) {
printf("InternetOpenW failed: %lu\n", GetLastError());
goto cleanup;
}
// Open URL
hUrl = ::InternetOpenUrlW(hInternet, url, NULL, 0,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0);
if (!hUrl) {
printf("InternetOpenUrlW failed: %lu\n", GetLastError());
goto cleanup;
}
// Create output file
fileHandle = ::CreateFileW(
save_to,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (fileHandle == INVALID_HANDLE_VALUE) {
printf("CreateFileW failed: %lu\n", GetLastError());
goto cleanup;
}
printf("Downloading\n");
// Download loop
do {
if (!::InternetReadFile(hUrl, buffer, sizeof(buffer), &bytesRead)) {
printf("InternetReadFile failed: %lu\n", GetLastError());
goto cleanup;
}
if (bytesRead == 0) {
success = TRUE;
break;
}
if (!::WriteFile(fileHandle, buffer, bytesRead, &bytesWritten, NULL) || bytesWritten != bytesRead) {
printf("WriteFile failed: %lu\n", GetLastError());
goto cleanup;
}
} while (TRUE);
cleanup:
if (fileHandle != INVALID_HANDLE_VALUE) {
::CloseHandle(fileHandle);
}
if (hUrl) {
::InternetCloseHandle(hUrl);
}
if (hInternet) {
::InternetCloseHandle(hInternet);
}
return success;
}
DWORD WINAPI DownloadFile(LPVOID lpParam) {
DownloadObj* params = static_cast<DownloadObj*>(lpParam);
WCHAR* url = params->url;
WCHAR* save_to = params->save_to;
HANDLE hSem = ::OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, TRUE, L"MyDownloadSemaphore");
if (!hSem) {
printf("Client Failed\n");
return 42;
}
// WAIT for a free slot (a permit from the semaphore).
// This call will block if MAX_CONCURRENT_DOWNLOADS are already running.
DWORD dwWaitResult = WaitForSingleObject(hSem, INFINITE);
switch (dwWaitResult) {
case WAIT_OBJECT_0:
wprintf(L"Downloading: %s\n", url);
wprintf(L"To: %s\n", save_to);
// Perform the actual download (this is a blocking call)
if (!DownloadHelper(url, save_to)) {
printf("Download Failed: %u\n", ::GetLastError());
}
// CRITICAL: Release the semaphore permit back to the pool.
// This allows one of the waiting threads to start its download.
if (!ReleaseSemaphore(hSem, 1, NULL)) {
std::cout << "Fatal Error: Failed to release semaphore!" << std::endl;
}
break;
// Handle other cases (like WAIT_TIMEOUT or WAIT_ABANDONED) if needed.
}
::CloseHandle(hSem);
// Do not delete params; it's not heap-allocated
return 42;
}
int main() {
SECURITY_ATTRIBUTES sa = { sizeof(sa) };
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
HANDLE hSemaphore = ::CreateSemaphoreW(&sa, MAX_DOWNLOAD_COUNT, MAX_DOWNLOAD_COUNT, L"MyDownloadSemaphore");
if (hSemaphore) {
printf("Semaphore Server Created ...!!!\n");
getchar();
::CloseHandle(hSemaphore);
} else {
if (::GetLastError() == ERROR_ALREADY_EXISTS) {
printf("Semaphore Client Created ...!!!\n");
struct DownloadObj downloads[5] = {
{L"http://127.0.0.1/a-guide-to-kernel-exploitation.pdf", L"1_.pdf"},
{L"http://127.0.0.1/694705872-Beginners-Guide-to-Exploitation-on-ARM-Vol-1.pdf", L"2_.pdf"},
{L"http://127.0.0.1/ai_m.pdf", L"3_.pdf"},
{L"http://127.0.0.1/ai__eye.pdf", L"4_.pdf"},
{L"http://127.0.0.1/ai_agents.pdf", L"5_.pdf"}
};
std::cout << "\nHello World!\n";
HANDLE hThreads[5];
for (int i = 0; i < 5; i++) {
hThreads[i] = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DownloadFile, &downloads[i], 0, NULL);
printf("Thread: %d\n", i);
if (!hThreads[i]) {
printf("Thread: %d Failed\n", i);
}
}
// Wait for all five threads to finish
::WaitForMultipleObjects(
5, // number of objects in the array
hThreads, // array of object handles
TRUE, // bWaitAll: TRUE to wait for all objects to be signaled
INFINITE // dwMilliseconds: INFINITE to wait indefinitely
);
for (int i = 0; i < 5; i++) {
::CloseHandle(hThreads[i]);
}
} else {
printf("CreateSemaphoreW failed with unexpected error: %lu\n", ::GetLastError());
}
}
return 0;
}