Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
153
third_party/FreeRDP/channels/rdpsnd/client/ios/TPCircularBuffer.c
vendored
Normal file
153
third_party/FreeRDP/channels/rdpsnd/client/ios/TPCircularBuffer.c
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// TPCircularBuffer.c
|
||||
// Circular/Ring buffer implementation
|
||||
//
|
||||
// https://github.com/michaeltyson/TPCircularBuffer
|
||||
//
|
||||
// Created by Michael Tyson on 10/12/2011.
|
||||
//
|
||||
// Copyright (C) 2012-2013 A Tasty Pixel
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#include "TPCircularBuffer.h"
|
||||
#include "rdpsnd_main.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define reportResult(result, operation) (_reportResult((result), (operation), __FILE__, __LINE__))
|
||||
static inline bool _reportResult(kern_return_t result, const char* operation, const char* file,
|
||||
int line)
|
||||
{
|
||||
if (result != ERR_SUCCESS)
|
||||
{
|
||||
WLog_DBG(TAG, "%s:%d: %s: %s\n", file, line, operation, mach_error_string(result));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TPCircularBufferInit(TPCircularBuffer* buffer, int length)
|
||||
{
|
||||
|
||||
// Keep trying until we get our buffer, needed to handle race conditions
|
||||
int retries = 3;
|
||||
while (true)
|
||||
{
|
||||
|
||||
buffer->length = round_page(length); // We need whole page sizes
|
||||
|
||||
// Temporarily allocate twice the length, so we have the contiguous address space to
|
||||
// support a second instance of the buffer directly after
|
||||
vm_address_t bufferAddress;
|
||||
kern_return_t result = vm_allocate(mach_task_self(), &bufferAddress, buffer->length * 2,
|
||||
VM_FLAGS_ANYWHERE); // allocate anywhere it'll fit
|
||||
if (result != ERR_SUCCESS)
|
||||
{
|
||||
if (retries-- == 0)
|
||||
{
|
||||
reportResult(result, "Buffer allocation");
|
||||
return false;
|
||||
}
|
||||
// Try again if we fail
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now replace the second half of the allocation with a virtual copy of the first half.
|
||||
// Deallocate the second half...
|
||||
result = vm_deallocate(mach_task_self(), bufferAddress + buffer->length, buffer->length);
|
||||
if (result != ERR_SUCCESS)
|
||||
{
|
||||
if (retries-- == 0)
|
||||
{
|
||||
reportResult(result, "Buffer deallocation");
|
||||
return false;
|
||||
}
|
||||
// If this fails somehow, deallocate the whole region and try again
|
||||
vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Re-map the buffer to the address space immediately after the buffer
|
||||
vm_address_t virtualAddress = bufferAddress + buffer->length;
|
||||
vm_prot_t cur_prot, max_prot;
|
||||
result = vm_remap(mach_task_self(),
|
||||
&virtualAddress, // mirror target
|
||||
buffer->length, // size of mirror
|
||||
0, // auto alignment
|
||||
0, // force remapping to virtualAddress
|
||||
mach_task_self(), // same task
|
||||
bufferAddress, // mirror source
|
||||
0, // MAP READ-WRITE, NOT COPY
|
||||
&cur_prot, // unused protection struct
|
||||
&max_prot, // unused protection struct
|
||||
VM_INHERIT_DEFAULT);
|
||||
if (result != ERR_SUCCESS)
|
||||
{
|
||||
if (retries-- == 0)
|
||||
{
|
||||
reportResult(result, "Remap buffer memory");
|
||||
return false;
|
||||
}
|
||||
// If this remap failed, we hit a race condition, so deallocate and try again
|
||||
vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (virtualAddress != bufferAddress + buffer->length)
|
||||
{
|
||||
// If the memory is not contiguous, clean up both allocated buffers and try again
|
||||
if (retries-- == 0)
|
||||
{
|
||||
WLog_DBG(TAG, "Couldn't map buffer memory to end of buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
vm_deallocate(mach_task_self(), virtualAddress, buffer->length);
|
||||
vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer->buffer = (void*)bufferAddress;
|
||||
buffer->fillCount = 0;
|
||||
buffer->head = buffer->tail = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TPCircularBufferCleanup(TPCircularBuffer* buffer)
|
||||
{
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)buffer->buffer, buffer->length * 2);
|
||||
memset(buffer, 0, sizeof(TPCircularBuffer));
|
||||
}
|
||||
|
||||
void TPCircularBufferClear(TPCircularBuffer* buffer)
|
||||
{
|
||||
int32_t fillCount;
|
||||
if (TPCircularBufferTail(buffer, &fillCount))
|
||||
{
|
||||
TPCircularBufferConsume(buffer, fillCount);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user