Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.v4.util.LongSparseArray;
import androidx.collection.LongSparseArray;
import android.util.Log;

import com.freerdp.freerdpcore.application.GlobalApp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatActivity;

import com.freerdp.freerdpcore.domain.ConnectionReference;
import com.freerdp.freerdpcore.presentation.BookmarkActivity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.annotation.LayoutRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
Expand Down
2 changes: 2 additions & 0 deletions client/Android/Studio/gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
org.gradle.jvmargs=-Xmx4096M
android.useAndroidX = true
android.enableJetifier = true
6 changes: 3 additions & 3 deletions client/Android/android_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ static void android_event_disconnect_free(ANDROID_EVENT* event)
free(event);
}

ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(void* data, int data_length)
ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(const void* data, size_t data_length)
{
ANDROID_EVENT_CLIPBOARD* event;
event = (ANDROID_EVENT_CLIPBOARD*)calloc(1, sizeof(ANDROID_EVENT_CLIPBOARD));
Expand All @@ -261,7 +261,7 @@ ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(void* data, int data_length

if (data)
{
event->data = malloc(data_length);
event->data = calloc(data_length + 1, sizeof(char));

if (!event->data)
{
Expand All @@ -270,7 +270,7 @@ ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(void* data, int data_length
}

memcpy(event->data, data, data_length);
event->data_length = data_length;
event->data_length = data_length + 1;
}

return event;
Expand Down
2 changes: 1 addition & 1 deletion client/Android/android_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ FREERDP_LOCAL ANDROID_EVENT_KEY* android_event_key_new(int flags, UINT16 scancod
FREERDP_LOCAL ANDROID_EVENT_KEY* android_event_unicodekey_new(UINT16 flags, UINT16 key);
FREERDP_LOCAL ANDROID_EVENT_CURSOR* android_event_cursor_new(UINT16 flags, UINT16 x, UINT16 y);
FREERDP_LOCAL ANDROID_EVENT* android_event_disconnect_new(void);
FREERDP_LOCAL ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(void* data, int data_length);
FREERDP_LOCAL ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(const void* data, size_t data_length);

FREERDP_LOCAL void android_event_free(ANDROID_EVENT* event);

Expand Down
4 changes: 2 additions & 2 deletions client/Android/android_freerdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
#define TAG CLIENT_TAG("android")

/* Defines the JNI version supported by this library. */
#define FREERDP_JNI_VERSION "2.3.2"
#define FREERDP_JNI_VERSION "2.4.0"

static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e)
{
Expand Down Expand Up @@ -996,7 +996,7 @@ static jboolean JNICALL jni_freerdp_send_clipboard_data(JNIEnv* env, jclass cls,
ANDROID_EVENT* event;
freerdp* inst = (freerdp*)instance;
const jbyte* data = jdata != NULL ? (*env)->GetStringUTFChars(env, jdata, NULL) : NULL;
int data_length = data ? strlen(data) : 0;
const size_t data_length = data ? (*env)->GetStringUTFLength(env, data) : 0;
jboolean ret = JNI_FALSE;
event = (ANDROID_EVENT*)android_event_clipboard_new((void*)data, data_length);

Expand Down
4 changes: 4 additions & 0 deletions client/Windows/wf_cliprdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2360,6 +2360,8 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext* context,
{
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
{
if (clipboard->nFiles <= fileContentsRequest->listIndex)
goto error;
*((UINT32*)&pData[0]) =
clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeLow;
*((UINT32*)&pData[4]) =
Expand All @@ -2369,6 +2371,8 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext* context,
else if (fileContentsRequest->dwFlags == FILECONTENTS_RANGE)
{
BOOL bRet;
if (clipboard->nFiles <= fileContentsRequest->listIndex)
goto error;
bRet = wf_cliprdr_get_file_contents(
clipboard->file_names[fileContentsRequest->listIndex], pData,
fileContentsRequest->nPositionLow, fileContentsRequest->nPositionHigh, cbRequested,
Expand Down
11 changes: 8 additions & 3 deletions client/X11/xf_cliprdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,8 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard,

if (!delayRespond)
{
union {
union
{
XEvent* ev;
XSelectionEvent* sev;
} conv;
Expand Down Expand Up @@ -1423,7 +1424,10 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
}

ret = xf_cliprdr_send_client_format_list_response(clipboard, TRUE);
xf_cliprdr_prepare_to_set_selection_owner(xfc, clipboard);
if (xfc->remote_app)
xf_cliprdr_set_selection_owner(xfc, clipboard, CurrentTime);
else
xf_cliprdr_prepare_to_set_selection_owner(xfc, clipboard);
return ret;
}

Expand Down Expand Up @@ -1611,7 +1615,8 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context,

xf_cliprdr_provide_data(clipboard, clipboard->respond, pDstData, DstSize);
{
union {
union
{
XEvent* ev;
XSelectionEvent* sev;
} conv;
Expand Down
2 changes: 1 addition & 1 deletion client/X11/xf_keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ static BOOL xf_keyboard_action_script_init(xfContext* xfc)
char* keyCombination;
char buffer[1024] = { 0 };
char command[1024] = { 0 };
xfc->actionScriptExists = PathFileExistsA(xfc->context.settings->ActionScript);
xfc->actionScriptExists = winpr_PathFileExists(xfc->context.settings->ActionScript);

if (!xfc->actionScriptExists)
return FALSE;
Expand Down
6 changes: 3 additions & 3 deletions client/common/cmdline.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ static BOOL freerdp_path_valid(const char* path, BOOL* special)
? TRUE
: FALSE;
if (!isSpecial)
isPath = PathFileExistsA(path);
isPath = winpr_PathFileExists(path);

if (special)
*special = isSpecial;
Expand Down Expand Up @@ -151,9 +151,9 @@ static BOOL freerdp_client_add_drive(rdpSettings* settings, const char* path, co
if (name)
{
/* Path was entered as secondary argument, swap */
if (PathFileExistsA(name))
if (winpr_PathFileExists(name))
{
if (!PathFileExistsA(path) || (!PathIsRelativeA(name) && PathIsRelativeA(path)))
if (!winpr_PathFileExists(path) || (!PathIsRelativeA(name) && PathIsRelativeA(path)))
{
const char* tmp = path;
path = name;
Expand Down
6 changes: 4 additions & 2 deletions client/common/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <errno.h>
#include <ctype.h>

#include <winpr/file.h>

#include <freerdp/client/file.h>
#include <freerdp/client/cmdline.h>

Expand Down Expand Up @@ -791,7 +793,7 @@ BOOL freerdp_client_parse_rdp_file_ex(rdpFile* file, const char* name, rdp_file_
FILE* fp = NULL;
size_t read_size;
INT64 file_size;
fp = fopen(name, "r");
fp = winpr_fopen(name, "r");

if (!fp)
{
Expand Down Expand Up @@ -944,7 +946,7 @@ BOOL freerdp_client_write_rdp_file(const rdpFile* file, const char* name, BOOL u
return FALSE;
}

fp = fopen(name, "w+b");
fp = winpr_fopen(name, "w+b");

if (fp)
{
Expand Down
6 changes: 3 additions & 3 deletions client/common/test/TestClientRdpFile.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,11 +420,11 @@ int TestClientRdpFile(int argc, char* argv[])
rc = 0;
fail:
if (utfname)
DeleteFileA(utfname);
winpr_DeleteFile(utfname);
if (uniname)
DeleteFileA(uniname);
winpr_DeleteFile(uniname);
if (base)
RemoveDirectoryA(base);
winpr_RemoveDirectory(base);
free(utfname);
free(uniname);
free(base);
Expand Down
3 changes: 3 additions & 0 deletions libfreerdp/codec/h264_ffmpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,10 @@ static BOOL libavcodec_init(H264_CONTEXT* h264)
}

h264->pSystemData = (void*)sys;

#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 137, 100)
avcodec_register_all();
#endif

if (!h264->Compressor)
{
Expand Down
6 changes: 4 additions & 2 deletions libfreerdp/codec/planar.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

#define TAG FREERDP_TAG("codec")

#define ALIGN(val, align) ((val) % (align) == 0) ? (val) : ((val) + (align) - (val) % (align))

static INLINE UINT32 planar_invert_format(BITMAP_PLANAR_CONTEXT* planar, BOOL alpha,
UINT32 DstFormat)
{
Expand Down Expand Up @@ -1482,8 +1484,8 @@ BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context, UINT32
return FALSE;

context->bgr = FALSE;
context->maxWidth = width;
context->maxHeight = height;
context->maxWidth = ALIGN(width, 4);
context->maxHeight = ALIGN(height, 4);
context->maxPlaneSize = context->maxWidth * context->maxHeight;
context->nTempStep = context->maxWidth * 4;
free(context->planesBuffer);
Expand Down
105 changes: 93 additions & 12 deletions libfreerdp/codec/progressive.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "rfx_quantization.h"
#include "rfx_dwt.h"
#include "rfx_rlgr.h"
#include "rfx_types.h"
#include "progressive.h"

#define TAG FREERDP_TAG("codec.progressive")
Expand Down Expand Up @@ -454,6 +455,8 @@ static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfa

if (!surface->tiles || !surface->updatedTileIndices)
{
free(surface->updatedTileIndices);
free(surface->tiles);
free(surface);
return NULL;
}
Expand Down Expand Up @@ -1619,18 +1622,55 @@ static INLINE BOOL progressive_tile_read(PROGRESSIVE_CONTEXT* progressive, BOOL
return progressive_surface_tile_replace(surface, region, &tile, FALSE);
}

struct _PROGRESSIVE_TILE_PROCESS_WORK_PARAM
{
PROGRESSIVE_CONTEXT* progressive;
PROGRESSIVE_BLOCK_REGION* region;
PROGRESSIVE_BLOCK_CONTEXT* context;
RFX_PROGRESSIVE_TILE* tile;
};
typedef struct _PROGRESSIVE_TILE_PROCESS_WORK_PARAM PROGRESSIVE_TILE_PROCESS_WORK_PARAM;

static void CALLBACK progressive_process_tiles_tile_work_callback(PTP_CALLBACK_INSTANCE instance,
void* context, PTP_WORK work)
{
PROGRESSIVE_TILE_PROCESS_WORK_PARAM* param = (PROGRESSIVE_TILE_PROCESS_WORK_PARAM*)context;

switch (param->tile->blockType)
{
case PROGRESSIVE_WBT_TILE_SIMPLE:
case PROGRESSIVE_WBT_TILE_FIRST:
progressive_decompress_tile_first(param->progressive, param->tile, param->region,
param->context);
break;

case PROGRESSIVE_WBT_TILE_UPGRADE:
progressive_decompress_tile_upgrade(param->progressive, param->tile, param->region,
param->context);
break;
default:
WLog_Print(param->progressive->log, WLOG_ERROR, "Invalid block type %04 (%s)" PRIx16,
param->tile->blockType,
progressive_get_block_type_string(param->tile->blockType));
break;
}
}

static INLINE int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, wStream* s,
PROGRESSIVE_BLOCK_REGION* region,
PROGRESSIVE_SURFACE_CONTEXT* surface,
const PROGRESSIVE_BLOCK_CONTEXT* context)
{
int status = -1;
int status = 0;
size_t end;
const size_t start = Stream_GetPosition(s);
UINT16 index;
UINT16 blockType;
UINT32 blockLen;
UINT32 count = 0;
PTP_WORK* work_objects = NULL;
PROGRESSIVE_TILE_PROCESS_WORK_PARAM* params = NULL;
UINT16 close_cnt = 0;

if (Stream_GetRemainingLength(s) < region->tileDataSize)
{
Expand Down Expand Up @@ -1712,24 +1752,46 @@ static INLINE int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, wS
return -1044;
}

if (progressive->rfx_context->priv->UseThreads)
{
work_objects = (PTP_WORK*)calloc(region->numTiles, sizeof(PTP_WORK));
if (!work_objects)
return -1;

params = (PROGRESSIVE_TILE_PROCESS_WORK_PARAM*)calloc(
region->numTiles, sizeof(PROGRESSIVE_TILE_PROCESS_WORK_PARAM));
if (!params)
{
free(work_objects);
return -1;
}
}

for (index = 0; index < region->numTiles; index++)
{
RFX_PROGRESSIVE_TILE* tile = region->tiles[index];
params[index].progressive = progressive;
params[index].region = region;
params[index].context = context;
params[index].tile = tile;

switch (tile->blockType)
if (progressive->rfx_context->priv->UseThreads)
{
case PROGRESSIVE_WBT_TILE_SIMPLE:
case PROGRESSIVE_WBT_TILE_FIRST:
status = progressive_decompress_tile_first(progressive, tile, region, context);
if (!(work_objects[index] = CreateThreadpoolWork(
progressive_process_tiles_tile_work_callback, (void*)&params[index],
&progressive->rfx_context->priv->ThreadPoolEnv)))
{
WLog_ERR(TAG, "CreateThreadpoolWork failed.");
status = -1;
break;
}

case PROGRESSIVE_WBT_TILE_UPGRADE:
status = progressive_decompress_tile_upgrade(progressive, tile, region, context);
break;
default:
WLog_Print(progressive->log, WLOG_ERROR, "Invalid block type %04 (%s)" PRIx16,
tile->blockType, progressive_get_block_type_string(tile->blockType));
return -42;
SubmitThreadpoolWork(work_objects[index]);
close_cnt = index + 1;
}
else
{
progressive_process_tiles_tile_work_callback(0, &params[index], 0);
}

if (status < 0)
Expand All @@ -1740,6 +1802,25 @@ static INLINE int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, wS
}
}

if (status < 0)
WLog_Print(progressive->log, WLOG_ERROR,
"Failed to create ThreadpoolWork for tile %" PRIu16, index);

if (progressive->rfx_context->priv->UseThreads)
{
for (index = 0; index < close_cnt; index++)
{
WaitForThreadpoolWorkCallbacks(work_objects[index], FALSE);
CloseThreadpoolWork(work_objects[index]);
}
}

free(work_objects);
free(params);

if (status < 0)
return -1;

return (int)(end - start);
}

Expand Down
5 changes: 3 additions & 2 deletions libfreerdp/codec/test/TestFreeRDPCodecProgressive.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <winpr/wlog.h>
#include <winpr/image.h>
#include <winpr/sysinfo.h>
#include <winpr/file.h>

#include <freerdp/codec/region.h>

Expand Down Expand Up @@ -278,7 +279,7 @@ static BYTE* test_progressive_load_file(const char* path, const char* file, size
if (!filename)
return NULL;

fp = fopen(filename, "r");
fp = winpr_fopen(filename, "r");
free(filename);

if (!fp)
Expand Down Expand Up @@ -1142,7 +1143,7 @@ int TestFreeRDPCodecProgressive(int argc, char* argv[])
goto fail;
}

if (PathFileExistsA(ms_sample_path))
if (winpr_PathFileExists(ms_sample_path))
{
/*
if (test_progressive_ms_sample(ms_sample_path) < 0)
Expand Down
3 changes: 2 additions & 1 deletion libfreerdp/common/assistance.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <winpr/print.h>
#include <winpr/windows.h>
#include <winpr/ssl.h>
#include <winpr/file.h>

#include <freerdp/log.h>
#include <freerdp/client/file.h>
Expand Down Expand Up @@ -1177,7 +1178,7 @@ int freerdp_assistance_parse_file(rdpAssistanceFile* file, const char* name, con

free(file->filename);
file->filename = _strdup(name);
fp = fopen(name, "r");
fp = winpr_fopen(name, "r");

if (!fp)
{
Expand Down
3 changes: 2 additions & 1 deletion libfreerdp/core/certificate.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <winpr/wtypes.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/crypto.h>

#include <openssl/pem.h>
Expand Down Expand Up @@ -789,7 +790,7 @@ rdpRsaKey* key_new(const char* keyfile)
INT64 length;
char* buffer = NULL;
rdpRsaKey* key = NULL;
fp = fopen(keyfile, "rb");
fp = winpr_fopen(keyfile, "rb");

if (!fp)
{
Expand Down
21 changes: 15 additions & 6 deletions libfreerdp/core/gateway/rdg.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,18 +308,27 @@ static BOOL rdg_read_http_unicode_string(wStream* s, const WCHAR** string, UINT1
{
WCHAR* str;
UINT16 strLenBytes;
size_t rem = Stream_GetRemainingLength(s);

/* Read length of the string */
if (Stream_GetRemainingLength(s) < 4)
if (rem < 4)
{
WLog_ERR(TAG, "[%s]: Could not read stream length, only have % " PRIuz " bytes", rem);
return FALSE;
}
Stream_Read_UINT16(s, strLenBytes);

/* Remember position of our string */
str = (WCHAR*)Stream_Pointer(s);

/* seek past the string - if this fails something is wrong */
if (!Stream_SafeSeek(s, strLenBytes))
{
WLog_ERR(TAG,
"[%s]: Could not read stream data, only have % " PRIuz " bytes, expected %" PRIu16,
rem - 4, strLenBytes);
return FALSE;
}

/* return the string data (if wanted) */
if (string)
Expand Down Expand Up @@ -1295,7 +1304,7 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
/* Seek over tunnelId (4 bytes) */
if (!Stream_SafeSeek(s, 4))
{
WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 4", __FUNCTION__,
WLog_ERR(TAG, "[%s] Short tunnelId, got %" PRIuz ", expected 4", __FUNCTION__,
Stream_GetRemainingLength(s));
return FALSE;
}
Expand All @@ -1306,7 +1315,7 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
UINT32 caps;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 4", __FUNCTION__,
WLog_ERR(TAG, "[%s] Short capsFlags, got %" PRIuz ", expected 4", __FUNCTION__,
Stream_GetRemainingLength(s));
return FALSE;
}
Expand All @@ -1320,15 +1329,15 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
/* Seek over nonce (20 bytes) */
if (!Stream_SafeSeek(s, 20))
{
WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 20", __FUNCTION__,
WLog_ERR(TAG, "[%s] Short nonce, got %" PRIuz ", expected 20", __FUNCTION__,
Stream_GetRemainingLength(s));
return FALSE;
}

/* Read serverCert */
if (!rdg_read_http_unicode_string(s, NULL, NULL))
{
WLog_ERR(TAG, "[%s] Failed to read string", __FUNCTION__);
WLog_ERR(TAG, "[%s] Failed to read server certificate", __FUNCTION__);
return FALSE;
}
}
Expand All @@ -1345,7 +1354,7 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
/* Read message string and invoke callback */
if (!rdg_read_http_unicode_string(s, &msg, &msgLenBytes))
{
WLog_ERR(TAG, "[%s] Failed to read string", __FUNCTION__);
WLog_ERR(TAG, "[%s] Failed to read consent message", __FUNCTION__);
return FALSE;
}

Expand Down
45 changes: 30 additions & 15 deletions libfreerdp/core/license.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <winpr/crypto.h>
#include <winpr/shell.h>
#include <winpr/path.h>
#include <winpr/file.h>

#include <freerdp/log.h>

Expand Down Expand Up @@ -188,19 +189,21 @@ static BOOL computeCalHash(const char* hostname, char* hashStr)
return ret;
}

static BOOL saveCal(rdpSettings* settings, const BYTE* data, int length, char* hostname)
static BOOL saveCal(rdpSettings* settings, const BYTE* data, size_t length, const char* hostname)
{
char hash[41];
FILE* fp;
char* licenseStorePath = NULL;
char filename[MAX_PATH], filenameNew[MAX_PATH];
char *filepath = NULL, *filepathNew = NULL;
WCHAR* wFilepathNew = NULL;
WCHAR* wFilepath = NULL;
size_t written;
BOOL ret = FALSE;

if (!PathFileExistsA(settings->ConfigPath))
if (!winpr_PathFileExists(settings->ConfigPath))
{
if (!PathMakePathA(settings->ConfigPath, 0))
if (!winpr_PathMakePath(settings->ConfigPath, 0))
{
WLog_ERR(TAG, "error creating directory '%s'", settings->ConfigPath);
goto out;
Expand All @@ -211,9 +214,9 @@ static BOOL saveCal(rdpSettings* settings, const BYTE* data, int length, char* h
if (!(licenseStorePath = GetCombinedPath(settings->ConfigPath, licenseStore)))
goto out;

if (!PathFileExistsA(licenseStorePath))
if (!winpr_PathFileExists(licenseStorePath))
{
if (!PathMakePathA(licenseStorePath, 0))
if (!winpr_PathMakePath(licenseStorePath, 0))
{
WLog_ERR(TAG, "error creating directory '%s'", licenseStorePath);
goto out;
Expand All @@ -231,8 +234,12 @@ static BOOL saveCal(rdpSettings* settings, const BYTE* data, int length, char* h

if (!(filepathNew = GetCombinedPath(licenseStorePath, filenameNew)))
goto out;
if (ConvertToUnicode(CP_UTF8, 0, filepathNew, -1, &wFilepathNew, 0) <= 0)
goto out;
if (ConvertToUnicode(CP_UTF8, 0, filepath, -1, &wFilepath, 0) <= 0)
goto out;

fp = fopen(filepathNew, "wb");
fp = winpr_fopen(filepathNew, "wb");
if (!fp)
goto out;

Expand All @@ -241,25 +248,28 @@ static BOOL saveCal(rdpSettings* settings, const BYTE* data, int length, char* h

if (written != 1)
{
DeleteFile(filepathNew);
DeleteFileW(wFilepathNew);
goto out;
}

ret = MoveFileEx(filepathNew, filepath, MOVEFILE_REPLACE_EXISTING);
ret = MoveFileExW(wFilepathNew, wFilepath, MOVEFILE_REPLACE_EXISTING);

out:
free(wFilepathNew);
free(filepathNew);
free(wFilepath);
free(filepath);
free(licenseStorePath);
return ret;
}

static BYTE* loadCalFile(rdpSettings* settings, const char* hostname, int* dataLen)
static BYTE* loadCalFile(rdpSettings* settings, const char* hostname, size_t* dataLen)
{
char *licenseStorePath = NULL, *calPath = NULL;
char calFilename[MAX_PATH];
char hash[41];
int length, status;
size_t length;
int status;
FILE* fp;
BYTE* ret = NULL;

Expand All @@ -277,7 +287,7 @@ static BYTE* loadCalFile(rdpSettings* settings, const char* hostname, int* dataL
if (!(calPath = GetCombinedPath(licenseStorePath, calFilename)))
goto error_path;

fp = fopen(calPath, "rb");
fp = winpr_fopen(calPath, "rb");
if (!fp)
goto error_open;

Expand Down Expand Up @@ -683,9 +693,14 @@ BOOL license_encrypt_premaster_secret(rdpLicense* license)
license->EncryptedPremasterSecret->type = BB_RANDOM_BLOB;
license->EncryptedPremasterSecret->length = PREMASTER_SECRET_LENGTH;
#ifndef LICENSE_NULL_PREMASTER_SECRET
license->EncryptedPremasterSecret->length = crypto_rsa_public_encrypt(
license->PremasterSecret, PREMASTER_SECRET_LENGTH, license->ModulusLength, license->Modulus,
license->Exponent, EncryptedPremasterSecret);
{
SSIZE_T length = crypto_rsa_public_encrypt(
license->PremasterSecret, PREMASTER_SECRET_LENGTH, license->ModulusLength,
license->Modulus, license->Exponent, EncryptedPremasterSecret);
if ((length < 0) || (length > UINT16_MAX))
return FALSE;
license->EncryptedPremasterSecret->length = (UINT16)length;
}
#endif
license->EncryptedPremasterSecret->data = EncryptedPremasterSecret;
return TRUE;
Expand Down Expand Up @@ -1417,7 +1432,7 @@ BOOL license_answer_license_request(rdpLicense* license)
{
wStream* s;
BYTE* license_data = NULL;
int license_size = 0;
size_t license_size = 0;
BOOL status;
char* username;

Expand Down
2 changes: 1 addition & 1 deletion libfreerdp/core/test/TestConnect.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ static int testSuccess(int port)
printf("Sample Server: %s\n", exe);
printf("Workspace: %s\n", wpath);

if (!PathFileExistsA(exe))
if (!winpr_PathFileExists(exe))
goto fail;

// Start sample server locally.
Expand Down
4 changes: 1 addition & 3 deletions libfreerdp/crypto/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -846,9 +846,7 @@ BOOL x509_verify_certificate(CryptoCert cert, const char* certificate_store_path
NULL);
#endif

lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());

if (lookup == NULL)
if (X509_STORE_set_default_paths(cert_ctx) != 1)
goto end;

lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
Expand Down
3 changes: 1 addition & 2 deletions libfreerdp/crypto/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ include_directories(${OPENSSL_INCLUDE_DIR})

add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})

file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} TEST_PATH)
string(REGEX REPLACE "\\\\" "\\\\\\\\" TEST_PATH ${TEST_PATH})
set(TEST_PATH ${CMAKE_CURRENT_SOURCE_DIR})

add_definitions(-DTEST_SOURCE_DIR="${TEST_PATH}")
target_link_libraries(${MODULE_NAME} freerdp winpr ${OPENSSL_LIBRARIES})
Expand Down
6 changes: 3 additions & 3 deletions libfreerdp/crypto/test/TestKnownHosts.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ static int prepare(const char* currentFileV2, const char* legacyFileV2, const ch
FILE* fl = NULL;
FILE* fc = NULL;
size_t i;
fc = fopen(currentFileV2, "w+");
fc = winpr_fopen(currentFileV2, "w+");

if (!fc)
goto finish;

fl = fopen(legacyFileV2, "w+");
fl = winpr_fopen(legacyFileV2, "w+");

if (!fl)
goto finish;
Expand All @@ -55,7 +55,7 @@ static int prepare(const char* currentFileV2, const char* legacyFileV2, const ch
fc = NULL;
fclose(fl);
fl = NULL;
fl = fopen(legacyFile, "w+");
fl = winpr_fopen(legacyFile, "w+");

if (!fl)
goto finish;
Expand Down
7 changes: 2 additions & 5 deletions libfreerdp/crypto/test/Test_x509_cert_info.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <winpr/file.h>
#include <freerdp/crypto/crypto.h>

typedef char* (*get_field_pr)(X509*);
Expand Down Expand Up @@ -27,11 +28,7 @@ static char* certificate_path(void)
where the tests are run. (ie. no chdir occurs between compilation and test running, or __FILE__
is an absolute path).
*/
#if defined(_WIN32)
static const char dirsep = '\\';
#else
static const char dirsep = '/';
#endif
static const char filename[] = "Test_x509_cert_info.pem";
#ifdef TEST_SOURCE_DIR
const char* file = TEST_SOURCE_DIR;
Expand Down Expand Up @@ -91,7 +88,7 @@ static int TestCertificateFile(const char* certificate_path,
const certificate_test_t* certificate_tests, int count)
{
X509* certificate;
FILE* certificate_file = fopen(certificate_path, "r");
FILE* certificate_file = winpr_fopen(certificate_path, "r");
int success = 0;
int i;

Expand Down
3 changes: 2 additions & 1 deletion libfreerdp/utils/pcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <string.h>

#include <winpr/wtypes.h>
#include <winpr/file.h>
#include <winpr/crt.h>
#include <freerdp/log.h>

Expand Down Expand Up @@ -177,7 +178,7 @@ rdpPcap* pcap_open(char* name, BOOL write)
pcap->name = name;
pcap->write = write;
pcap->record_count = 0;
pcap->fp = fopen(name, write ? "w+b" : "rb");
pcap->fp = winpr_fopen(name, write ? "w+b" : "rb");

if (pcap->fp == NULL)
goto fail;
Expand Down
7 changes: 4 additions & 3 deletions rdtk/librdtk/rdtk_font.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <winpr/wtypes.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/file.h>
#include <winpr/print.h>

#include "rdtk_engine.h"
Expand Down Expand Up @@ -154,7 +155,7 @@ static char* rdtk_font_load_descriptor_file(const char* filename, int* pSize)
FILE* fp = NULL;
size_t readSize;
size_t fileSize;
fp = fopen(filename, "r");
fp = winpr_fopen(filename, "r");

if (!fp)
return NULL;
Expand Down Expand Up @@ -611,10 +612,10 @@ rdtkFont* rdtk_font_new(rdtkEngine* engine, const char* path, const char* file)

sprintf_s(fontDescriptorFile, length + 8, "%s.xml", fontBaseFile);

if (!PathFileExistsA(fontImageFile))
if (!winpr_PathFileExists(fontImageFile))
goto cleanup;

if (!PathFileExistsA(fontDescriptorFile))
if (!winpr_PathFileExists(fontDescriptorFile))
goto cleanup;

font = (rdtkFont*)calloc(1, sizeof(rdtkFont));
Expand Down
3 changes: 2 additions & 1 deletion server/Sample/sfreerdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <winpr/crt.h>
#include <winpr/ssl.h>
#include <winpr/synch.h>
#include <winpr/file.h>
#include <winpr/string.h>
#include <winpr/path.h>
#include <winpr/winsock.h>
Expand Down Expand Up @@ -254,7 +255,7 @@ static BOOL test_peer_load_icon(freerdp_peer* client)
return FALSE;
}

if ((fp = fopen("test_icon.ppm", "r")) == NULL)
if ((fp = winpr_fopen("test_icon.ppm", "r")) == NULL)
{
WLog_ERR(TAG, "Unable to open test icon");
return FALSE;
Expand Down
2 changes: 1 addition & 1 deletion server/shadow/X11/x11_shadow.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ static BOOL x11_shadow_pam_get_service_name(SHADOW_PAM_AUTH_INFO* info)
const char* hint = hints[x];

_snprintf(path, sizeof(path), "%s/%s", base, hint);
if (PathFileExistsA(path))
if (winpr_PathFileExists(path))
{

info->service_name = _strdup(hint);
Expand Down
19 changes: 10 additions & 9 deletions server/shadow/shadow_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ static int shadow_server_init_config_path(rdpShadowServer* server)

if (userLibraryPath)
{
if (!PathFileExistsA(userLibraryPath) && !PathMakePathA(userLibraryPath, 0))
if (!winpr_PathFileExists(userLibraryPath) && !winpr_PathMakePath(userLibraryPath, 0))
{
WLog_ERR(TAG, "Failed to create directory '%s'", userLibraryPath);
free(userLibraryPath);
Expand All @@ -691,8 +691,8 @@ static int shadow_server_init_config_path(rdpShadowServer* server)

if (userApplicationSupportPath)
{
if (!PathFileExistsA(userApplicationSupportPath) &&
!PathMakePathA(userApplicationSupportPath, 0))
if (!winpr_PathFileExists(userApplicationSupportPath) &&
!winpr_PathMakePath(userApplicationSupportPath, 0))
{
WLog_ERR(TAG, "Failed to create directory '%s'", userApplicationSupportPath);
free(userLibraryPath);
Expand All @@ -717,7 +717,7 @@ static int shadow_server_init_config_path(rdpShadowServer* server)

if (configHome)
{
if (!PathFileExistsA(configHome) && !PathMakePathA(configHome, 0))
if (!winpr_PathFileExists(configHome) && !winpr_PathMakePath(configHome, 0))
{
WLog_ERR(TAG, "Failed to create directory '%s'", configHome);
free(configHome);
Expand All @@ -743,7 +743,7 @@ static BOOL shadow_server_init_certificate(rdpShadowServer* server)
const char* makecert_argv[6] = { "makecert", "-rdp", "-live", "-silent", "-y", "5" };
int makecert_argc = (sizeof(makecert_argv) / sizeof(char*));

if (!PathFileExistsA(server->ConfigPath) && !PathMakePathA(server->ConfigPath, 0))
if (!winpr_PathFileExists(server->ConfigPath) && !winpr_PathMakePath(server->ConfigPath, 0))
{
WLog_ERR(TAG, "Failed to create directory '%s'", server->ConfigPath);
return FALSE;
Expand All @@ -752,7 +752,7 @@ static BOOL shadow_server_init_certificate(rdpShadowServer* server)
if (!(filepath = GetCombinedPath(server->ConfigPath, "shadow")))
return FALSE;

if (!PathFileExistsA(filepath) && !PathMakePathA(filepath, 0))
if (!winpr_PathFileExists(filepath) && !winpr_PathMakePath(filepath, 0))
{
if (!CreateDirectoryA(filepath, 0))
{
Expand All @@ -767,7 +767,8 @@ static BOOL shadow_server_init_certificate(rdpShadowServer* server)
if (!server->CertificateFile || !server->PrivateKeyFile)
goto out_fail;

if ((!PathFileExistsA(server->CertificateFile)) || (!PathFileExistsA(server->PrivateKeyFile)))
if ((!winpr_PathFileExists(server->CertificateFile)) ||
(!winpr_PathFileExists(server->PrivateKeyFile)))
{
makecert = makecert_context_new();

Expand All @@ -780,13 +781,13 @@ static BOOL shadow_server_init_certificate(rdpShadowServer* server)
if (makecert_context_set_output_file_name(makecert, "shadow") != 1)
goto out_fail;

if (!PathFileExistsA(server->CertificateFile))
if (!winpr_PathFileExists(server->CertificateFile))
{
if (makecert_context_output_certificate_file(makecert, filepath) != 1)
goto out_fail;
}

if (!PathFileExistsA(server->PrivateKeyFile))
if (!winpr_PathFileExists(server->PrivateKeyFile))
{
if (makecert_context_output_private_key_file(makecert, filepath) != 1)
goto out_fail;
Expand Down
2 changes: 1 addition & 1 deletion winpr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ if (NOT WIN32)
endif()

# Soname versioning
set(RAW_VERSION_STRING "2.3.2")
set(RAW_VERSION_STRING "2.4.0")
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
elseif(USE_VERSION_FROM_GIT_TAG)
Expand Down
2 changes: 2 additions & 0 deletions winpr/include/winpr/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,8 @@ extern "C"
WINPR_API int GetNamePipeFileDescriptor(HANDLE hNamedPipe);
WINPR_API HANDLE GetFileHandleForFileDescriptor(int fd);

WINPR_API FILE* winpr_fopen(const char* path, const char* mode);

#ifdef __cplusplus
}
#endif
Expand Down
6 changes: 6 additions & 0 deletions winpr/include/winpr/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,12 @@ extern "C"

#endif

WINPR_API BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName);
WINPR_API BOOL winpr_DeleteFile(const char* lpFileName);
WINPR_API BOOL winpr_RemoveDirectory(LPCSTR lpPathName);
WINPR_API BOOL winpr_PathFileExists(const char* pszPath);
WINPR_API BOOL winpr_PathMakePath(const char* path, LPSECURITY_ATTRIBUTES lpAttributes);

#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 3 additions & 1 deletion winpr/include/winpr/synch.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ extern "C"

#define WAIT_OBJECT_0 0x00000000L
#define WAIT_ABANDONED 0x00000080L
#define WAIT_IO_COMPLETION 0x000000C0L

#ifndef WAIT_TIMEOUT
#define WAIT_TIMEOUT 0x00000102L
Expand Down Expand Up @@ -202,7 +203,8 @@ extern "C"
ULONG Version;
DWORD Flags;

union {
union
{
struct
{
HMODULE LocalizedReasonModule;
Expand Down
3 changes: 3 additions & 0 deletions winpr/include/winpr/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ extern "C"
WINPR_API HANDLE _GetCurrentThread(void);
WINPR_API DWORD GetCurrentThreadId(void);

typedef void (*PAPCFUNC)(ULONG_PTR Parameter);
WINPR_API DWORD QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);

WINPR_API DWORD ResumeThread(HANDLE hThread);
WINPR_API DWORD SuspendThread(HANDLE hThread);
WINPR_API BOOL SwitchToThread(void);
Expand Down
23 changes: 8 additions & 15 deletions winpr/libwinpr/clipboard/posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ static struct posix_file* make_posix_file(const char* local_name, const WCHAR* r
free(file);
return NULL;
}
static UINT posix_file_read_close(struct posix_file* file, BOOL force);

static void free_posix_file(void* the_file)
{
Expand All @@ -102,14 +103,7 @@ static void free_posix_file(void* the_file)
if (!file)
return;

if (file->fd >= 0)
{
if (close(file->fd) < 0)
{
int err = errno;
WLog_WARN(TAG, "failed to close fd %d: %s", file->fd, strerror(err));
}
}
posix_file_read_close(file, TRUE);

free(file->local_name);
free(file->remote_name);
Expand Down Expand Up @@ -836,12 +830,14 @@ static UINT posix_file_read_perform(struct posix_file* file, UINT32 size, BYTE**
return ERROR_READ_FAULT;
}

static UINT posix_file_read_close(struct posix_file* file)
UINT posix_file_read_close(struct posix_file* file, BOOL force)
{
if (file->fd < 0)
return NO_ERROR;

if (file->offset == file->size)
/* Always force close the file. Clipboard might open hundreds of files
* so avoid caching to prevent running out of available file descriptors */
if ((file->offset >= file->size) || force || TRUE)
{
WLog_VRB(TAG, "close file %d", file->fd);

Expand Down Expand Up @@ -876,12 +872,9 @@ static UINT posix_file_get_range(struct posix_file* file, UINT64 offset, UINT32
if (error)
goto out;

error = posix_file_read_close(file);

if (error)
goto out;

out:

posix_file_read_close(file, (error != NO_ERROR) && (size > 0));
return error;
}

Expand Down
2 changes: 1 addition & 1 deletion winpr/libwinpr/error/error.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ DWORD GetLastError(VOID)
PTEB pt = NtCurrentTeb();
if (pt)
{
return NtCurrentTeb()->LastErrorValue;
return pt->LastErrorValue;
}
return ERROR_OUTOFMEMORY;
}
Expand Down
31 changes: 29 additions & 2 deletions winpr/libwinpr/file/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ static HANDLE FileCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dw
}
}

fp = fopen(pFile->lpFileName, "ab");
fp = winpr_fopen(pFile->lpFileName, "ab");
if (!fp)
{
SetLastError(map_posix_err(errno));
Expand Down Expand Up @@ -800,7 +800,7 @@ static HANDLE FileCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dw
}

if (NULL == fp)
fp = fopen(pFile->lpFileName, mode);
fp = winpr_fopen(pFile->lpFileName, mode);

pFile->fp = fp;
if (!pFile->fp)
Expand Down Expand Up @@ -1358,3 +1358,30 @@ HANDLE GetFileHandleForFileDescriptor(int fd)
return (HANDLE)pFile;
#endif /* _WIN32 */
}

FILE* winpr_fopen(const char* path, const char* mode)
{
#ifndef _WIN32
return fopen(path, mode);
#else
LPWSTR lpPathW = NULL;
LPWSTR lpModeW = NULL;
FILE* result = NULL;

if (!path || !mode)
return NULL;

if (ConvertToUnicode(CP_UTF8, 0, path, -1, &lpPathW, 0) < 1)
goto cleanup;

if (ConvertToUnicode(CP_UTF8, 0, mode, -1, &lpModeW, 0) < 1)
goto cleanup;

result = _wfopen(lpPathW, lpModeW);

cleanup:
free(lpPathW);
free(lpModeW);
return result;
#endif
}
6 changes: 3 additions & 3 deletions winpr/libwinpr/file/test/TestFileCreateFile.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ int TestFileCreateFile(int argc, char* argv[])
return -1;
}

if (!PathFileExistsA(name))
if (!winpr_PathFileExists(name))
rc = -1;

if (!WriteFile(handle, buffer, sizeof(buffer), &written, NULL))
Expand Down Expand Up @@ -81,10 +81,10 @@ int TestFileCreateFile(int argc, char* argv[])
if (!CloseHandle(handle))
rc = -1;

if (!DeleteFileA(name))
if (!winpr_DeleteFile(name))
rc = -1;

if (PathFileExistsA(name))
if (winpr_PathFileExists(name))
rc = -1;

free(name);
Expand Down
4 changes: 2 additions & 2 deletions winpr/libwinpr/io/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ NTSTATUS _IoCreateDeviceEx(PDRIVER_OBJECT_EX DriverObject, ULONG DeviceExtension
if (!DeviceBasePath)
return STATUS_NO_MEMORY;

if (!PathFileExistsA(DeviceBasePath))
if (!winpr_PathFileExists(DeviceBasePath))
{
if (mkdir(DeviceBasePath, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
{
Expand Down Expand Up @@ -169,7 +169,7 @@ NTSTATUS _IoCreateDeviceEx(PDRIVER_OBJECT_EX DriverObject, ULONG DeviceExtension
return STATUS_NO_MEMORY;
}

if (PathFileExistsA(pDeviceObjectEx->DeviceFileName))
if (winpr_PathFileExists(pDeviceObjectEx->DeviceFileName))
{
if (unlink(pDeviceObjectEx->DeviceFileName) == -1)
{
Expand Down
111 changes: 109 additions & 2 deletions winpr/libwinpr/path/shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ static char* GetPath_XDG_CACHE_HOME(void)
{
path = GetCombinedPath(home, "cache");

if (!PathFileExistsA(path))
if (!winpr_PathFileExists(path))
if (!CreateDirectoryA(path, NULL))
path = NULL;
}
Expand Down Expand Up @@ -567,7 +567,7 @@ BOOL PathFileExistsW(LPCWSTR pszPath)
if (ConvertFromUnicode(CP_UTF8, 0, pszPath, -1, &lpFileNameA, 0, NULL, NULL) < 1)
return FALSE;

ret = PathFileExistsA(lpFileNameA);
ret = winpr_PathFileExists(lpFileNameA);
free(lpFileNameA);
return ret;
}
Expand Down Expand Up @@ -614,3 +614,110 @@ BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
#endif

#endif

BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
{
#ifndef _WIN32
return MoveFileA(lpExistingFileName, lpNewFileName);
#else
BOOL result = FALSE;
LPWSTR lpExistingFileNameW = NULL;
LPWSTR lpNewFileNameW = NULL;

if (!lpExistingFileName || !lpNewFileName)
return FALSE;

if (ConvertToUnicode(CP_UTF8, 0, lpExistingFileName, -1, &lpExistingFileNameW, 0) < 1)
goto cleanup;

if (ConvertToUnicode(CP_UTF8, 0, lpNewFileName, -1, &lpNewFileNameW, 0) < 1)
goto cleanup;

result = MoveFileW(lpExistingFileNameW, lpNewFileNameW);

cleanup:
free(lpExistingFileNameW);
free(lpNewFileNameW);
return result;
#endif
}

BOOL winpr_DeleteFile(const char* lpFileName)
{
#ifndef _WIN32
return DeleteFileA(lpFileName);
#else
LPWSTR lpFileNameW = NULL;
BOOL result = FALSE;

if (lpFileName)
{
if (ConvertToUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameW, 0) < 1)
goto cleanup;
}

result = DeleteFileW(lpFileNameW);

cleanup:
free(lpFileNameW);
return result;
#endif
}

BOOL winpr_RemoveDirectory(LPCSTR lpPathName)
{
#ifndef _WIN32
return RemoveDirectoryA(lpPathName);
#else
LPWSTR lpPathNameW = NULL;
BOOL result = FALSE;

if (lpPathName)
{
if (ConvertToUnicode(CP_UTF8, 0, lpPathName, -1, &lpPathNameW, 0) < 1)
goto cleanup;
}

result = RemoveDirectoryW(lpPathNameW);

cleanup:
free(lpPathNameW);
return result;
#endif
}

BOOL winpr_PathFileExists(const char* pszPath)
{
#ifndef _WIN32
return PathFileExistsA(pszPath);
#else
WCHAR* pszPathW = NULL;
BOOL result = FALSE;

if (ConvertToUnicode(CP_UTF8, 0, pszPath, -1, &pszPathW, 0) < 1)
return FALSE;

result = PathFileExistsW(pszPathW);
free(pszPathW);

return result;
#endif
}

BOOL winpr_PathMakePath(const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
{
#ifndef _WIN32
return PathMakePathA(path, lpAttributes);
#else
WCHAR* pathW = NULL;
BOOL result = FALSE;

if (ConvertToUnicode(CP_UTF8, 0, path, -1, &pathW, 0) < 1)
return FALSE;

result = SHCreateDirectoryExW(NULL, pathW, lpAttributes) == ERROR_SUCCESS;
free(pathW);

return result;
#endif
}
8 changes: 4 additions & 4 deletions winpr/libwinpr/path/test/TestPathMakePath.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ int TestPathMakePath(int argc, char* argv[])
}

printf("Creating path %s\n", path);
success = PathMakePathA(path, NULL);
success = winpr_PathMakePath(path, NULL);

if (!success)
{
Expand All @@ -51,7 +51,7 @@ int TestPathMakePath(int argc, char* argv[])
return -1;
}

success = PathFileExistsA(path);
success = winpr_PathFileExists(path);

if (!success)
{
Expand All @@ -62,9 +62,9 @@ int TestPathMakePath(int argc, char* argv[])

while (strlen(path) > baseLen)
{
if (!RemoveDirectoryA(path))
if (!winpr_RemoveDirectory(path))
{
fprintf(stderr, "RemoveDirectoryA %s failed!\n", path);
fprintf(stderr, "winpr_RemoveDirectory %s failed!\n", path);
free(path);
return -1;
}
Expand Down
8 changes: 4 additions & 4 deletions winpr/libwinpr/pipe/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD
if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
goto out;

if (!PathFileExistsA(lpPipePath))
if (!winpr_PathFileExists(lpPipePath))
{
if (!CreateDirectoryA(lpPipePath, 0))
{
Expand All @@ -643,8 +643,8 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD

free(lpPipePath);

if (PathFileExistsA(pNamedPipe->lpFilePath))
DeleteFileA(pNamedPipe->lpFilePath);
if (winpr_PathFileExists(pNamedPipe->lpFilePath))
winpr_DeleteFile(pNamedPipe->lpFilePath);

if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
Expand Down Expand Up @@ -836,7 +836,7 @@ BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
status = TRUE;
dwSleepInterval = 10;

while (!PathFileExistsA(lpFilePath))
while (!winpr_PathFileExists(lpFilePath))
{
Sleep(dwSleepInterval);
nWaitTime += dwSleepInterval;
Expand Down
7 changes: 4 additions & 3 deletions winpr/libwinpr/registry/registry_reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include <winpr/wtypes.h>
#include <winpr/crt.h>
#include <winpr/file.h>

#include "registry_reg.h"

Expand Down Expand Up @@ -414,14 +415,14 @@ Reg* reg_open(BOOL read_only)

if (reg->read_only)
{
reg->fp = fopen(reg->filename, "r");
reg->fp = winpr_fopen(reg->filename, "r");
}
else
{
reg->fp = fopen(reg->filename, "r+");
reg->fp = winpr_fopen(reg->filename, "r+");

if (!reg->fp)
reg->fp = fopen(reg->filename, "w+");
reg->fp = winpr_fopen(reg->filename, "w+");
}

if (!reg->fp)
Expand Down
2 changes: 1 addition & 1 deletion winpr/libwinpr/sspi/NTLM/ntlm_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -1037,7 +1037,7 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
#endif
context->state = NTLM_STATE_FINAL;
Stream_Free(s, FALSE);
return SEC_I_COMPLETE_NEEDED;
return SEC_E_OK;
}

SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context)
Expand Down
4 changes: 2 additions & 2 deletions winpr/libwinpr/sspi/test/TestSchannel.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ static int dump_test_certificate_files(void)
if (!fullpath)
return -1;

fp = fopen(fullpath, "w+");
fp = winpr_fopen(fullpath, "w+");
if (fp)
{
if (fwrite((void*)test_localhost_crt, sizeof(test_localhost_crt), 1, fp) != 1)
Expand All @@ -578,7 +578,7 @@ static int dump_test_certificate_files(void)
fullpath = GetCombinedPath("/tmp", "localhost.key");
if (!fullpath)
return -1;
fp = fopen(fullpath, "w+");
fp = winpr_fopen(fullpath, "w+");
if (fp && fwrite((void*)test_localhost_key, sizeof(test_localhost_key), 1, fp) != 1)
goto out_fail;

Expand Down
2 changes: 2 additions & 0 deletions winpr/libwinpr/synch/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ winpr_module_add(
event.c
init.c
mutex.c
pollset.c
pollset.h
semaphore.c
sleep.c
synch.h
Expand Down
197 changes: 107 additions & 90 deletions winpr/libwinpr/synch/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,112 @@
#include <sys/eventfd.h>
#endif

#include <fcntl.h>
#include <errno.h>

#include "../handle/handle.h"
#include "../pipe/pipe.h"

#include "../log.h"
#include "event.h"
#define TAG WINPR_TAG("synch.event")

#ifdef HAVE_SYS_EVENTFD_H
#if !defined(WITH_EVENTFD_READ_WRITE)
static int eventfd_read(int fd, eventfd_t* value)
{
return (read(fd, value, sizeof(*value)) == sizeof(*value)) ? 0 : -1;
}

static int eventfd_write(int fd, eventfd_t value)
{
return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1;
}
#endif
#endif

BOOL winpr_event_init(WINPR_EVENT_IMPL* event)
{
#ifdef HAVE_SYS_EVENTFD_H
event->fds[1] = -1;
event->fds[0] = eventfd(0, EFD_NONBLOCK);

return event->fds[0] >= 0;
#else
int flags;

if (pipe(event->fds) < 0)
return FALSE;

flags = fcntl(event->fds[0], F_GETFL);
if (flags < 0)
goto out_error;

if (fcntl(event->fds[0], F_SETFL, flags | O_NONBLOCK) < 0)
goto out_error;

return TRUE;

out_error:
winpr_event_uninit(event);
return FALSE;
#endif
}

void winpr_event_init_from_fd(WINPR_EVENT_IMPL* event, int fd)
{
event->fds[0] = fd;
#ifndef HAVE_SYS_EVENTFD_H
event->fds[1] = fd;
#endif
}

BOOL winpr_event_set(WINPR_EVENT_IMPL* event)
{
int ret;
do
{
#ifdef HAVE_SYS_EVENTFD_H
eventfd_t value = 1;
ret = eventfd_write(event->fds[0], value);
#else
ret = write(event->fds[1], "-", 1);
#endif
} while (ret < 0 && errno == EINTR);

return ret >= 0;
}

BOOL winpr_event_reset(WINPR_EVENT_IMPL* event)
{
int ret;
do
{
do
{
#ifdef HAVE_SYS_EVENTFD_H
eventfd_t value = 1;
ret = eventfd_read(event->fds[0], &value);
#else
char value;
ret = read(event->fds[0], &value, 1);
#endif
} while (ret < 0 && errno == EINTR);
} while (ret >= 0);

return (errno == EAGAIN);
}

void winpr_event_uninit(WINPR_EVENT_IMPL* event)
{
if (event->fds[0] != -1)
close(event->fds[0]);
#ifndef HAVE_SYS_EVENTFD_H
if (event->fds[1] != -1)
close(event->fds[1]);
#endif
}

static BOOL EventCloseHandle(HANDLE handle);

static BOOL EventIsHandled(HANDLE handle)
Expand All @@ -71,7 +169,7 @@ static int EventGetFd(HANDLE handle)
if (!EventIsHandled(handle))
return -1;

return event->pipe_fd[0];
return event->impl.fds[0];
}

static BOOL EventCloseHandle_(WINPR_EVENT* event)
Expand All @@ -80,19 +178,7 @@ static BOOL EventCloseHandle_(WINPR_EVENT* event)
return FALSE;

if (!event->bAttached)
{
if (event->pipe_fd[0] != -1)
{
close(event->pipe_fd[0]);
event->pipe_fd[0] = -1;
}

if (event->pipe_fd[1] != -1)
{
close(event->pipe_fd[1]);
event->pipe_fd[1] = -1;
}
}
winpr_event_uninit(&event->impl);

free(event->name);
free(event);
Expand Down Expand Up @@ -161,21 +247,9 @@ HANDLE CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
if (!event->bManualReset)
WLog_ERR(TAG, "auto-reset events not yet implemented");

event->pipe_fd[0] = -1;
event->pipe_fd[1] = -1;
#ifdef HAVE_SYS_EVENTFD_H
event->pipe_fd[0] = eventfd(0, EFD_NONBLOCK);

if (event->pipe_fd[0] < 0)
goto fail;

#else

if (pipe(event->pipe_fd) < 0)
if (!winpr_event_init(&event->impl))
goto fail;

#endif

if (bInitialState)
{
if (!SetEvent(event))
Expand Down Expand Up @@ -246,25 +320,10 @@ HANDLE OpenEventA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
return NULL;
}

#ifdef HAVE_SYS_EVENTFD_H
#if !defined(WITH_EVENTFD_READ_WRITE)
static int eventfd_read(int fd, eventfd_t* value)
{
return (read(fd, value, sizeof(*value)) == sizeof(*value)) ? 0 : -1;
}

static int eventfd_write(int fd, eventfd_t value)
{
return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1;
}
#endif
#endif

BOOL SetEvent(HANDLE hEvent)
{
ULONG Type;
WINPR_HANDLE* Object;
int length;
BOOL status;
WINPR_EVENT* event;
status = FALSE;
Expand All @@ -273,30 +332,7 @@ BOOL SetEvent(HANDLE hEvent)
{
event = (WINPR_EVENT*)Object;

#ifdef HAVE_SYS_EVENTFD_H
eventfd_t val = 1;

do
{
length = eventfd_write(event->pipe_fd[0], val);
} while ((length < 0) && (errno == EINTR));

status = (length == 0) ? TRUE : FALSE;
#else

if (WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0)
{
length = write(event->pipe_fd[1], "-", 1);

if (length == 1)
status = TRUE;
}
else
{
status = TRUE;
}

#endif
status = winpr_event_set(&event->impl);
}

return status;
Expand All @@ -306,32 +342,14 @@ BOOL ResetEvent(HANDLE hEvent)
{
ULONG Type;
WINPR_HANDLE* Object;
int length;
BOOL status = TRUE;
WINPR_EVENT* event;

if (!winpr_Handle_GetInfo(hEvent, &Type, &Object))
return FALSE;

event = (WINPR_EVENT*)Object;

while (status && WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
{
do
{
#ifdef HAVE_SYS_EVENTFD_H
eventfd_t value;
length = eventfd_read(event->pipe_fd[0], &value);
#else
length = read(event->pipe_fd[0], &length, 1);
#endif
} while ((length < 0) && (errno == EINTR));

if (length < 0)
status = FALSE;
}

return status;
return winpr_event_reset(&event->impl);
}

#endif
Expand All @@ -348,8 +366,7 @@ HANDLE CreateFileDescriptorEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL
{
event->bAttached = TRUE;
event->bManualReset = bManualReset;
event->pipe_fd[0] = FileDescriptor;
event->pipe_fd[1] = -1;
winpr_event_init_from_fd(&event->impl, FileDescriptor);
event->ops = &ops;
WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, mode);
handle = (HANDLE)event;
Expand Down Expand Up @@ -416,12 +433,12 @@ int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor, ULONG mode)

event = (WINPR_EVENT*)Object;

if (!event->bAttached && event->pipe_fd[0] >= 0 && event->pipe_fd[0] != FileDescriptor)
close(event->pipe_fd[0]);
if (!event->bAttached && event->impl.fds[0] >= 0 && event->impl.fds[0] != FileDescriptor)
close(event->impl.fds[0]);

event->bAttached = TRUE;
event->Mode = mode;
event->pipe_fd[0] = FileDescriptor;
event->impl.fds[0] = FileDescriptor;
return 0;
#else
return -1;
Expand Down
56 changes: 56 additions & 0 deletions winpr/libwinpr/synch/event.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* event implementation
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_LIBWINPR_SYNCH_EVENT_H_
#define WINPR_LIBWINPR_SYNCH_EVENT_H_

#include "../handle/handle.h"

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_SYS_EVENTFD_H
#include <sys/eventfd.h>
#endif

struct winpr_event_impl
{
int fds[2];
};

typedef struct winpr_event_impl WINPR_EVENT_IMPL;

struct winpr_event
{
WINPR_HANDLE_DEF();

WINPR_EVENT_IMPL impl;
BOOL bAttached;
BOOL bManualReset;
char* name;
};
typedef struct winpr_event WINPR_EVENT;

BOOL winpr_event_init(WINPR_EVENT_IMPL* event);
void winpr_event_init_from_fd(WINPR_EVENT_IMPL* event, int fd);
BOOL winpr_event_set(WINPR_EVENT_IMPL* event);
BOOL winpr_event_reset(WINPR_EVENT_IMPL* event);
void winpr_event_uninit(WINPR_EVENT_IMPL* event);

#endif /* WINPR_LIBWINPR_SYNCH_EVENT_H_ */
223 changes: 223 additions & 0 deletions winpr/libwinpr/synch/pollset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
#ifndef _WIN32
#include <errno.h>

#include "pollset.h"
#include <winpr/handle.h>
#include <winpr/sysinfo.h>
#include "../log.h"

#define TAG WINPR_TAG("sync.pollset")

#ifdef HAVE_POLL_H
static DWORD handle_mode_to_pollevent(ULONG mode)
{
DWORD event = 0;

if (mode & WINPR_FD_READ)
event |= POLLIN;

if (mode & WINPR_FD_WRITE)
event |= POLLOUT;

return event;
}
#endif

BOOL pollset_init(WINPR_POLL_SET* set, size_t nhandles)
{
#ifdef HAVE_POLL_H
if (nhandles > MAXIMUM_WAIT_OBJECTS)
{
set->isStatic = FALSE;
set->pollset = calloc(nhandles, sizeof(*set->pollset));
if (!set->pollset)
return FALSE;
}
else
{
set->pollset = set->staticSet;
set->isStatic = TRUE;
}
#else
set->fdIndex = calloc(nhandles, sizeof(*set->fdIndex));
if (!set->fdIndex)
return FALSE;

FD_ZERO(&set->rset_base);
FD_ZERO(&set->rset);
FD_ZERO(&set->wset_base);
FD_ZERO(&set->wset);
set->maxFd = 0;
set->nread = set->nwrite = 0;
#endif

set->size = nhandles;
set->fillIndex = 0;
return TRUE;
}

void pollset_uninit(WINPR_POLL_SET* set)
{
#ifdef HAVE_POLL_H
if (!set->isStatic)
free(set->pollset);
#else
free(set->fdIndex);
#endif
}

void pollset_reset(WINPR_POLL_SET* set)
{
#ifndef HAVE_POLL_H
FD_ZERO(&set->rset_base);
FD_ZERO(&set->wset_base);
set->maxFd = 0;
set->nread = set->nwrite = 0;
#endif
set->fillIndex = 0;
}

BOOL pollset_add(WINPR_POLL_SET* set, int fd, ULONG mode)
{
#ifdef HAVE_POLL_H
struct pollfd* item;
if (set->fillIndex == set->size)
return FALSE;

item = &set->pollset[set->fillIndex];
item->fd = fd;
item->revents = 0;
item->events = handle_mode_to_pollevent(mode);
#else
FdIndex* fdIndex = &set->fdIndex[set->fillIndex];
if (mode & WINPR_FD_READ)
{
FD_SET(fd, &set->rset_base);
set->nread++;
}

if (mode & WINPR_FD_WRITE)
{
FD_SET(fd, &set->wset_base);
set->nwrite++;
}

if (fd > set->maxFd)
set->maxFd = fd;

fdIndex->fd = fd;
fdIndex->mode = mode;
#endif
set->fillIndex++;
return TRUE;
}

int pollset_poll(WINPR_POLL_SET* set, DWORD dwMilliseconds)
{
int ret = 0;
UINT64 dueTime, now;

now = GetTickCount64();
if (dwMilliseconds == INFINITE)
dueTime = 0xFFFFFFFFFFFFFFFF;
else
dueTime = now + dwMilliseconds;

#ifdef HAVE_POLL_H
int timeout;

do
{
if (dwMilliseconds == INFINITE)
timeout = -1;
else
timeout = (int)(dueTime - now);

ret = poll(set->pollset, set->fillIndex, timeout);
if (ret >= 0)
return ret;

if (errno != EINTR)
return -1;

now = GetTickCount64();
} while (now < dueTime);

#else
do
{
struct timeval staticTimeout;
struct timeval* timeout;

fd_set* rset = NULL;
fd_set* wset = NULL;

if (dwMilliseconds == INFINITE)
{
timeout = NULL;
}
else
{
long waitTime = (long)(dueTime - now);

timeout = &staticTimeout;
timeout->tv_sec = waitTime / 1000;
timeout->tv_usec = (waitTime % 1000) * 1000;
}

if (set->nread)
{
rset = &set->rset;
memcpy(rset, &set->rset_base, sizeof(*rset));
}

if (set->nwrite)
{
wset = &set->wset;
memcpy(wset, &set->wset_base, sizeof(*wset));
}

ret = select(set->maxFd + 1, rset, wset, NULL, timeout);
if (ret >= 0)
return ret;

if (errno != EINTR)
return -1;

now = GetTickCount64();

} while (now < dueTime);

FD_ZERO(&set->rset);
FD_ZERO(&set->wset);
#endif

return 0; /* timeout */
}

BOOL pollset_isSignaled(WINPR_POLL_SET* set, size_t idx)
{
if (idx > set->fillIndex)
{
WLog_ERR(TAG, "%s: index=%d out of pollset(fillIndex=%d)", __FUNCTION__, idx,
set->fillIndex);
return FALSE;
}

#ifdef HAVE_POLL_H
return !!(set->pollset[idx].revents & set->pollset[idx].events);
#else
FdIndex* fdIndex = &set->fdIndex[idx];
if (fdIndex->fd < 0)
return FALSE;

if ((fdIndex->mode & WINPR_FD_READ) && FD_ISSET(fdIndex->fd, &set->rset))
return TRUE;

if ((fdIndex->mode & WINPR_FD_WRITE) && FD_ISSET(fdIndex->fd, &set->wset))
return TRUE;

return FALSE;
#endif
}
#endif
73 changes: 73 additions & 0 deletions winpr/libwinpr/synch/pollset.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* pollset
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_LIBWINPR_SYNCH_POLLSET_H_
#define WINPR_LIBWINPR_SYNCH_POLLSET_H_

#include <winpr/wtypes.h>
#include <winpr/synch.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef _WIN32

#ifdef HAVE_POLL_H
#include <poll.h>
#else
#include <sys/select.h>

typedef struct
{
int fd;
ULONG mode;
} FdIndex;
#endif

struct winpr_poll_set
{
#ifdef HAVE_POLL_H
struct pollfd* pollset;
struct pollfd staticSet[MAXIMUM_WAIT_OBJECTS];
BOOL isStatic;
#else
FdIndex* fdIndex;
fd_set rset_base;
fd_set rset;
fd_set wset_base;
fd_set wset;
int nread, nwrite;
int maxFd;
#endif
size_t fillIndex;
size_t size;
};

typedef struct winpr_poll_set WINPR_POLL_SET;

BOOL pollset_init(WINPR_POLL_SET* set, size_t nhandles);
void pollset_uninit(WINPR_POLL_SET* set);
void pollset_reset(WINPR_POLL_SET* set);
BOOL pollset_add(WINPR_POLL_SET* set, int fd, ULONG mode);
int pollset_poll(WINPR_POLL_SET* set, DWORD dwMilliseconds);
BOOL pollset_isSignaled(WINPR_POLL_SET* set, size_t idx);

#endif

#endif /* WINPR_LIBWINPR_SYNCH_POLLSET_H_ */
66 changes: 61 additions & 5 deletions winpr/libwinpr/synch/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#include <winpr/synch.h>

#include "../log.h"
#include "../thread/apc.h"
#include "../thread/thread.h"
#include "../synch/pollset.h"

#define TAG WINPR_TAG("synch.sleep")

Expand All @@ -47,11 +50,64 @@ VOID Sleep(DWORD dwMilliseconds)

DWORD SleepEx(DWORD dwMilliseconds, BOOL bAlertable)
{
/* TODO: Implement bAlertable support */
if (bAlertable)
WLog_WARN(TAG, "%s does not support bAlertable", __FUNCTION__);
Sleep(dwMilliseconds);
return 0;
WINPR_THREAD* thread = winpr_GetCurrentThread();
WINPR_POLL_SET pollset;
int status;
DWORD ret = WAIT_FAILED;
BOOL autoSignalled;

if (!thread)
{
WLog_ERR(TAG, "unable to retrieve currentThread");
return WAIT_FAILED;
}

/* treat re-entrancy if a completion is calling us */
if (thread->apc.treatingCompletions)
bAlertable = FALSE;

if (!bAlertable || !thread->apc.length)
{
usleep(dwMilliseconds * 1000);
return 0;
}

if (!pollset_init(&pollset, thread->apc.length))
{
WLog_ERR(TAG, "unable to initialize pollset");
return WAIT_FAILED;
}

if (!apc_collectFds(thread, &pollset, &autoSignalled))
{
WLog_ERR(TAG, "unable to APC file descriptors");
goto out;
}

if (!autoSignalled)
{
/* we poll and wait only if no APC member is ready */
status = pollset_poll(&pollset, dwMilliseconds);
if (status < 0)
{
WLog_ERR(TAG, "polling of apc fds failed");
goto out;
}
}

if (apc_executeCompletions(thread, &pollset, 0))
{
ret = WAIT_IO_COMPLETION;
}
else
{
/* according to the spec return value is 0 see
* https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepex*/
ret = 0;
}
out:
pollset_uninit(&pollset);
return ret;
}

#endif
Expand Down
38 changes: 22 additions & 16 deletions winpr/libwinpr/synch/synch.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <winpr/synch.h>

#include "../handle/handle.h"
#include "../thread/apc.h"
#include "event.h"

#ifndef _WIN32

Expand Down Expand Up @@ -65,26 +67,22 @@ struct winpr_semaphore
};
typedef struct winpr_semaphore WINPR_SEMAPHORE;

struct winpr_event
{
WINPR_HANDLE_DEF();

int pipe_fd[2];
BOOL bAttached;
BOOL bManualReset;
char* name;
};
typedef struct winpr_event WINPR_EVENT;

#ifdef HAVE_SYS_TIMERFD_H
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/timerfd.h>
#endif
#define TIMER_IMPL_TIMERFD

#if defined(__APPLE__)
#elif defined(WITH_POSIX_TIMER)
#include <fcntl.h>
#define TIMER_IMPL_POSIX

#elif defined(__APPLE__)
#define TIMER_IMPL_DISPATCH
#include <dispatch/dispatch.h>
#else
#error missing timer implementation
#endif

struct winpr_timer
Expand All @@ -98,17 +96,25 @@ struct winpr_timer
PTIMERAPCROUTINE pfnCompletionRoutine;
LPVOID lpArgToCompletionRoutine;

#ifdef WITH_POSIX_TIMER
#ifdef TIMER_IMPL_TIMERFD
struct itimerspec timeout;
#endif

#ifdef TIMER_IMPL_POSIX
WINPR_EVENT_IMPL event;
timer_t tid;
struct itimerspec timeout;
#endif
#if defined(__APPLE__)

#ifdef TIMER_IMPL_DISPATCH
WINPR_EVENT_IMPL event;
dispatch_queue_t queue;
dispatch_source_t source;
int pipe[2];
BOOL running;
#endif
char* name;

WINPR_APC_ITEM apcItem;
};
typedef struct winpr_timer WINPR_TIMER;

Expand Down
3 changes: 2 additions & 1 deletion winpr/libwinpr/synch/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ set(${MODULE_PREFIX}_TESTS
TestSynchMultipleThreads.c
TestSynchTimerQueue.c
TestSynchWaitableTimer.c
TestSynchWaitableTimerAPC.c)
TestSynchWaitableTimerAPC.c
TestSynchAPC.c)

create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}
Expand Down
174 changes: 174 additions & 0 deletions winpr/libwinpr/synch/test/TestSynchAPC.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* TestSyncAPC
*
* Copyright 2021 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/wtypes.h>
#include <winpr/thread.h>
#include <winpr/synch.h>

typedef struct
{
BOOL error;
BOOL called;
} UserApcArg;

void CALLBACK userApc(ULONG_PTR arg)
{
UserApcArg* userArg = (UserApcArg*)arg;
userArg->called = TRUE;
}

static DWORD WINAPI uncleanThread(LPVOID lpThreadParameter)
{
/* this thread post an APC that will never get executed */
UserApcArg* userArg = (UserApcArg*)lpThreadParameter;
if (!QueueUserAPC((PAPCFUNC)userApc, _GetCurrentThread(), (ULONG_PTR)lpThreadParameter))
{
userArg->error = TRUE;
return 1;
}

return 0;
}

static DWORD WINAPI cleanThread(LPVOID lpThreadParameter)
{
Sleep(500);

SleepEx(500, TRUE);
return 0;
}

typedef struct
{
HANDLE timer1;
DWORD timer1Calls;
HANDLE timer2;
DWORD timer2Calls;
BOOL endTest;
} UncleanCloseData;

static VOID CALLBACK Timer1APCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
{
UncleanCloseData* data = (UncleanCloseData*)lpArg;
data->timer1Calls++;
CloseHandle(data->timer2);
data->endTest = TRUE;
}

static VOID CALLBACK Timer2APCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
{
UncleanCloseData* data = (UncleanCloseData*)lpArg;
data->timer2Calls++;
}

static DWORD /*WINAPI*/ closeHandleTest(LPVOID lpThreadParameter)
{
LARGE_INTEGER dueTime;
UncleanCloseData* data = (UncleanCloseData*)lpThreadParameter;
data->endTest = FALSE;

dueTime.QuadPart = -500;
if (!SetWaitableTimer(data->timer1, &dueTime, 0, Timer1APCProc, lpThreadParameter, FALSE))
return 1;

dueTime.QuadPart = -900;
if (!SetWaitableTimer(data->timer2, &dueTime, 0, Timer2APCProc, lpThreadParameter, FALSE))
return 1;

while (!data->endTest)
{
SleepEx(100, TRUE);
}
return 0;
}

int TestSynchAPC(int argc, char* argv[])
{
HANDLE thread = NULL;
UserApcArg userApcArg;
UncleanCloseData uncleanCloseData;

userApcArg.error = FALSE;
userApcArg.called = FALSE;

WINPR_UNUSED(argc);
WINPR_UNUSED(argv);

/* first post an APC and check it is executed during a SleepEx */
if (!QueueUserAPC((PAPCFUNC)userApc, _GetCurrentThread(), (ULONG_PTR)&userApcArg))
return 1;

if (SleepEx(100, FALSE) != 0)
return 2;

if (SleepEx(100, TRUE) != WAIT_IO_COMPLETION)
return 3;

if (!userApcArg.called)
return 4;

userApcArg.called = FALSE;

/* test that the APC is cleaned up even when not called */
thread = CreateThread(NULL, 0, uncleanThread, &userApcArg, 0, NULL);
if (!thread)
return 10;
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);

if (userApcArg.called || userApcArg.error)
return 11;

/* test a remote APC queuing */
thread = CreateThread(NULL, 0, cleanThread, &userApcArg, 0, NULL);
if (!thread)
return 20;

if (!QueueUserAPC((PAPCFUNC)userApc, thread, (ULONG_PTR)&userApcArg))
return 21;

WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);

if (!userApcArg.called)
return 22;

#if 0
/* test cleanup of timer completions */
memset(&uncleanCloseData, 0, sizeof(uncleanCloseData));
uncleanCloseData.timer1 = CreateWaitableTimerA(NULL, FALSE, NULL);
if (!uncleanCloseData.timer1)
return 31;

uncleanCloseData.timer2 = CreateWaitableTimerA(NULL, FALSE, NULL);
if (!uncleanCloseData.timer2)
return 32;

thread = CreateThread(NULL, 0, closeHandleTest, &uncleanCloseData, 0, NULL);
if (!thread)
return 33;

WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);

if (uncleanCloseData.timer1Calls != 1 || uncleanCloseData.timer2Calls != 0)
return 34;
CloseHandle(uncleanCloseData.timer1);
#endif
return 0;
}
190 changes: 137 additions & 53 deletions winpr/libwinpr/synch/test/TestSynchMultipleThreads.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
#include <winpr/synch.h>
#include <winpr/thread.h>

#define THREADS 24

static DWORD WINAPI test_thread(LPVOID arg)
{
long timeout = rand();
timeout %= 1000;
timeout += 100;
long timeout = 100 + (rand() % 1000);
WINPR_UNUSED(arg);
Sleep(timeout);
ExitThread(0);
return 0;
Expand All @@ -25,7 +26,7 @@ static int start_threads(DWORD count, HANDLE* threads)

if (!threads[i])
{
printf("CreateThread [%" PRIu32 "] failure\n", i);
fprintf(stderr, "%s: CreateThread [%" PRIu32 "] failure\n", __FUNCTION__, i);
return -1;
}
}
Expand All @@ -41,119 +42,202 @@ static int close_threads(DWORD count, HANDLE* threads)
{
if (!CloseHandle(threads[i]))
{
printf("CloseHandle [%" PRIu32 "] failure\n", i);
fprintf(stderr, "%s: CloseHandle [%" PRIu32 "] failure\n", __FUNCTION__, i);
return -1;
}
}

return 0;
}

int TestSynchMultipleThreads(int argc, char* argv[])
static BOOL TestWaitForAll(void)
{
#define THREADS 24
DWORD rc = 0, ev, i;
BOOL rc = FALSE;
DWORD ret;
HANDLE threads[THREADS];

/* WaitForAll, timeout */
if (start_threads(THREADS, threads))
return 1;
{
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
return FALSE;
}

if (WaitForMultipleObjects(THREADS, threads, TRUE, 50) != WAIT_TIMEOUT)
ret = WaitForMultipleObjects(THREADS, threads, TRUE, 50);
if (ret != WAIT_TIMEOUT)
{
printf("WaitForMultipleObjects bWaitAll, timeout 50 failed\n");
rc = 2;
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, timeout 50 failed, ret=%d\n",
__FUNCTION__, ret);
goto fail;
}

if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0)
{
printf("WaitForMultipleObjects bWaitAll, INFINITE failed\n");
rc = 3;
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__);
goto fail;
}

if (close_threads(THREADS, threads))
return 4;
{
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
return FALSE;
}

/* WaitOne, infinite */
if (rc)
return rc;
rc = TRUE;
fail:
return rc;
}

static BOOL TestWaitOne(void)
{
BOOL rc = FALSE;
DWORD ret;
HANDLE threads[THREADS];
/* WaitForAll, timeout */
if (start_threads(THREADS, threads))
return 5;

ev = WaitForMultipleObjects(THREADS, threads, FALSE, INFINITE);
{
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
return FALSE;
}

if (ev > (WAIT_OBJECT_0 + THREADS))
ret = WaitForMultipleObjects(THREADS, threads, FALSE, INFINITE);
if (ret > (WAIT_OBJECT_0 + THREADS))
{
printf("WaitForMultipleObjects INFINITE failed\n");
rc = 6;
fprintf(stderr, "%s: WaitForMultipleObjects INFINITE failed\n", __FUNCTION__);
goto fail;
}

if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0)
{
printf("WaitForMultipleObjects bWaitAll, INFINITE failed\n");
rc = 7;
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__);
goto fail;
}

if (close_threads(THREADS, threads))
return 8;
{
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
return FALSE;
}

if (rc)
return rc;
rc = TRUE;
fail:
return rc;
}

/* WaitOne, timeout */
static BOOL TestWaitOneTimeout(void)
{
BOOL rc = FALSE;
DWORD ret;
HANDLE threads[THREADS];
/* WaitForAll, timeout */
if (start_threads(THREADS, threads))
return 9;
{
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
return FALSE;
}

if (WaitForMultipleObjects(THREADS, threads, FALSE, 50) != WAIT_TIMEOUT)
ret = WaitForMultipleObjects(THREADS, threads, FALSE, 50);
if (ret != WAIT_TIMEOUT)
{
printf("WaitForMultipleObjects timeout 50 failed\n");
rc = 10;
fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__,
ret);
goto fail;
}

if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0)
{
printf("WaitForMultipleObjects bWaitAll, INFINITE failed\n");
rc = 11;
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__);
goto fail;
}

if (close_threads(THREADS, threads))
return 12;
{
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
return FALSE;
}

if (rc)
return 13;
rc = TRUE;
fail:
return rc;
}

/* WaitOne, timeout, multiple joins */
static BOOL TestWaitOneTimeoutMultijoin(void)
{
BOOL rc = FALSE;
DWORD ret, i;
HANDLE threads[THREADS];
/* WaitForAll, timeout */
if (start_threads(THREADS, threads))
return 14;
{
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
return FALSE;
}

for (i = 0; i < THREADS; i++)
{
if (WaitForMultipleObjects(THREADS, threads, FALSE, 0) != WAIT_TIMEOUT)
ret = WaitForMultipleObjects(THREADS, threads, FALSE, 0);
if (ret != WAIT_TIMEOUT)
{
printf("WaitForMultipleObjects timeout 50 failed\n");
rc = 15;
fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__,
ret);
goto fail;
}
}

if (WaitForMultipleObjects(THREADS, threads, TRUE, INFINITE) != WAIT_OBJECT_0)
{
printf("WaitForMultipleObjects bWaitAll, INFINITE failed\n");
rc = 16;
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__);
goto fail;
}

if (close_threads(THREADS, threads))
rc = 17;
{
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
return FALSE;
}

if (rc)
return rc;
rc = TRUE;
fail:
return rc;
}

/* Thread detach test */
static BOOL TestDetach(void)
{
HANDLE threads[THREADS];
/* WaitForAll, timeout */
if (start_threads(THREADS, threads))
return 18;
{
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
return FALSE;
}

if (close_threads(THREADS, threads))
return 19;
{
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
return FALSE;
}

return TRUE;
}

int TestSynchMultipleThreads(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);

if (!TestWaitForAll())
return -1;

if (!TestWaitOne())
return -2;

if (!TestWaitOneTimeout())
return -3;

if (!TestWaitOneTimeoutMultijoin())
return -4;

if (!TestDetach())
return -5;

return 0;
}
31 changes: 8 additions & 23 deletions winpr/libwinpr/synch/test/TestSynchWaitableTimerAPC.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static VOID CALLBACK TimerAPCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwT
int TestSynchWaitableTimerAPC(int argc, char* argv[])
{
int status = -1;
DWORD rc;
HANDLE hTimer = NULL;
BOOL bSuccess;
LARGE_INTEGER due;
Expand All @@ -50,44 +51,28 @@ int TestSynchWaitableTimerAPC(int argc, char* argv[])
}

hTimer = CreateWaitableTimer(NULL, FALSE, NULL);

if (!hTimer)
goto cleanup;

due.QuadPart = -15000000LL; /* 1.5 seconds */
due.QuadPart = -1000 * 1000LL; /* 1 seconds */
apcData.StartTime = GetTickCount();
bSuccess = SetWaitableTimer(hTimer, &due, 2000, TimerAPCProc, &apcData, FALSE);
bSuccess = SetWaitableTimer(hTimer, &due, 100, TimerAPCProc, &apcData, FALSE);

if (!bSuccess)
goto cleanup;

/**
* See Remarks at
* https://msdn.microsoft.com/en-us/library/windows/desktop/ms686786(v=vs.85).aspx The
* SetWaitableTimer completion routine is executed by the thread that activates the timer using
* SetWaitableTimer. However, the thread must be in an ALERTABLE state.
*/

/**
* Note: On WIN32 we need to use WaitForSingleObjectEx with parameter bAlertable = TRUE
* However, WinPR currently (May 2016) does not have a working WaitForSingleObjectEx
*implementation but its non-WIN32 WaitForSingleObject implementations seem to be alertable by
*WinPR's timer implementations.
**/
/* nothing shall happen after 1.2 second, because thread is not in alertable state */
rc = WaitForSingleObject(g_Event, 1200);
if (rc != WAIT_TIMEOUT)
goto cleanup;

for (;;)
{
DWORD rc;
#ifdef _WIN32
rc = WaitForSingleObjectEx(g_Event, INFINITE, TRUE);
#else
rc = WaitForSingleObject(g_Event, INFINITE);
#endif

if (rc == WAIT_OBJECT_0)
break;

if (rc == 0x000000C0L) /* WAIT_IO_COMPLETION */
if (rc == WAIT_IO_COMPLETION)
continue;

printf("Failed to wait for completion event (%" PRIu32 ")\n", GetLastError());
Expand Down
Loading