Skip to content

fix: setTimeout does not work on Windows #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 3, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions IOSDeviceLib.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
709A6CD21E435D11006F76C7 /* Printing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 709A6CCE1E435D11006F76C7 /* Printing.cpp */; };
709A6CD31E435D11006F76C7 /* windows_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 709A6CD01E435D11006F76C7 /* windows_impl.cpp */; };
70DFE7601E72ACCC000317B3 /* ServerHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70DFE75E1E72ACCC000317B3 /* ServerHelper.cpp */; };
E0F67C12232591AE00D3E0C2 /* SetTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E0F67C11232591AE00D3E0C2 /* SetTimeout.cpp */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand Down Expand Up @@ -335,6 +336,8 @@
70DFE75F1E72ACCC000317B3 /* ServerHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerHelper.h; sourceTree = "<group>"; };
70F5F4281E13EE02005196BF /* configuration.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = configuration.xcconfig; path = IOSDeviceLib/configuration.xcconfig; sourceTree = "<group>"; };
70F6ADAB1DEEB71300DD4722 /* ios-device-lib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "ios-device-lib"; sourceTree = BUILT_PRODUCTS_DIR; };
E0F67C102325919600D3E0C2 /* SetTimeout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SetTimeout.h; sourceTree = "<group>"; };
E0F67C11232591AE00D3E0C2 /* SetTimeout.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SetTimeout.cpp; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -375,6 +378,8 @@
7038C9F31DEEDB4C00A3D335 /* json.hpp */,
7038C9F41DEEDB4C00A3D335 /* PlistCpp */,
7038CB401DEEF31400A3D335 /* Declarations.h */,
E0F67C102325919600D3E0C2 /* SetTimeout.h */,
E0F67C11232591AE00D3E0C2 /* SetTimeout.cpp */,
);
path = IOSDeviceLib;
sourceTree = "<group>";
Expand Down Expand Up @@ -1186,6 +1191,7 @@
7038CB3D1DEEDB4C00A3D335 /* Plist.cpp in Sources */,
709A6CD21E435D11006F76C7 /* Printing.cpp in Sources */,
7024956F1E4080B8009A6EBF /* GDBHelper.cpp in Sources */,
E0F67C12232591AE00D3E0C2 /* SetTimeout.cpp in Sources */,
7038CB3F1DEEDB4C00A3D335 /* pugixml.cpp in Sources */,
7038CB3C1DEEDB4C00A3D335 /* IOSDeviceLib.cpp in Sources */,
702495701E4080B8009A6EBF /* SocketHelper.cpp in Sources */,
Expand Down
11 changes: 10 additions & 1 deletion IOSDeviceLib/Declarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ struct ServiceInfo {
HANDLE socket;
ServiceConnRef connection;
int connection_id;
std::string service_name;
};

struct ConnectionMessageData {
ServiceConnRef conn;
std::string device_identifier;
std::string method_id;
std::string service_name;
int timeout;
};

struct DeviceData {
Expand Down Expand Up @@ -268,7 +277,7 @@ extern HINSTANCE mobile_device_dll;

extern "C"
{
CFSocketNativeHandle AMDServiceConnectionGetSocket(ServiceConnRef con);
CFSocketNativeHandle AMDServiceConnectionGetSocket(ServiceConnRef con);
long AMDServiceConnectionReceive(ServiceConnRef, void *, long);
void AMDServiceConnectionInvalidate(ServiceConnRef);
long AMDServiceConnectionSendMessage(ServiceConnRef serviceConnection, CFDictionaryRef message, CFPropertyListFormat format);
Expand Down
55 changes: 53 additions & 2 deletions IOSDeviceLib/IOSDeviceLib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "Printing.h"
#include "CommonFunctions.h"
#include "ServerHelper.h"
#include "SetTimeout.h"

#ifdef _WIN32
#pragma region Dll_Variable_Definitions
Expand Down Expand Up @@ -444,6 +445,7 @@ ServiceInfo start_secure_service(std::string device_identifier, const char* serv
serviceInfoResult.socket = socket;
serviceInfoResult.connection = connection;
serviceInfoResult.connection_id = nextServiceConnectionId;
serviceInfoResult.service_name = service_name;
serviceConnections[nextServiceConnectionId] = connection;
nextServiceConnectionId++;

Expand Down Expand Up @@ -640,6 +642,53 @@ void perform_detached_operation(void(*operation)(std::string, std::string, std::
std::thread([operation, first_arg, device_identifier, method_id]() { operation(first_arg, device_identifier, method_id); }).detach();
}

std::mutex clean_con_resources_mutex;
void clean_con_resources(void* data)
{
clean_con_resources_mutex.lock();
ConnectionMessageData* connectionMessageData = reinterpret_cast<ConnectionMessageData*>(data);
ServiceConnRef conn = connectionMessageData->conn;
devices[connectionMessageData->device_identifier].services.erase(connectionMessageData->service_name.c_str());
AMDServiceConnectionInvalidate(conn);
clean_con_resources_mutex.unlock();
}

std::mutex receive_con_message_mutex;
std::map<std::string, boost::any> receive_con_message(ConnectionMessageData data)
{
receive_con_message_mutex.lock();

ServiceConnRef conn = data.conn;
TimeoutOutputData timeoutOutputData = setTimeout(data.timeout, &data, clean_con_resources);

std::map<std::string, boost::any> dict;
char *buffer = new char[4];
int bytes_read = AMDServiceConnectionReceive(conn, buffer, 4);
if (bytes_read > 0)
{
unsigned long res = ntohl(*((unsigned long*)buffer));
delete[] buffer;
buffer = new char[res];
bytes_read = AMDServiceConnectionReceive(conn, buffer, res);
if (bytes_read > 0)
{
Plist::readPlist(buffer, res, dict);
clearTimeout(timeoutOutputData);
}
} else {
clearTimeout(timeoutOutputData);
}

delete[] buffer;
receive_con_message_mutex.unlock();
return dict;
}

long send_con_message(ServiceConnRef serviceConnection, CFDictionaryRef message)
{
return AMDServiceConnectionSendMessage(serviceConnection, message, kCFPropertyListXMLFormat_v1_0);
}

void read_dir(AFCConnectionRef afc_conn_p, const char* dir, json &files, std::stringstream &errors, std::string method_id, std::string device_identifier)
{
char *dir_ent;
Expand Down Expand Up @@ -1003,7 +1052,8 @@ void get_application_infos(std::string device_identifier, std::string method_id)
std::vector<json> livesync_app_infos;
while (true)
{
std::map<std::string, boost::any> dict = receive_con_message(serviceInfo.connection, device_identifier, method_id, 0);
ConnectionMessageData connectionMessageData = { serviceInfo.connection, device_identifier, method_id, kInstallationProxy, 10 };
std::map<std::string, boost::any> dict = receive_con_message(connectionMessageData);
PRINT_ERROR_AND_RETURN_IF_FAILED_RESULT(dict.count(kErrorKey), boost::any_cast<std::string>(dict[kErrorKey]).c_str(), device_identifier, method_id);
if (dict.empty() || (dict.count(kStatusKey) && has_complete_status(dict)))
{
Expand Down Expand Up @@ -1177,7 +1227,8 @@ void await_notification_response(std::string device_identifier, AwaitNotificatio
PRINT_ERROR_AND_RETURN_IF_FAILED_RESULT(connection == nullptr, invalid_connection_error_message.c_str(), device_identifier, method_id);

ServiceInfo currentNotificationProxy = devices[device_identifier].services[kNotificationProxy];
std::map<std::string, boost::any> response = receive_con_message(connection, device_identifier, method_id, await_notification_response_info.timeout);
ConnectionMessageData connectionMessageData = { connection, device_identifier, method_id, kNotificationProxy, await_notification_response_info.timeout };
std::map<std::string, boost::any> response = receive_con_message(connectionMessageData);
if (response.size())
{
PRINT_ERROR_AND_RETURN_IF_FAILED_RESULT(response.count(kErrorKey), boost::any_cast<std::string>(response[kErrorKey]).c_str(), device_identifier, method_id);
Expand Down
2 changes: 2 additions & 0 deletions IOSDeviceLib/IOSDeviceLib.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@
<ClCompile Include="PlistCpp\pugixml.cpp" />
<ClCompile Include="Printing.cpp" />
<ClCompile Include="ServerHelper.cpp" />
<ClCompile Include="SetTimeout.cpp" />
<ClCompile Include="SocketHelper.cpp" />
<ClCompile Include="StringHelper.cpp" />
<ClCompile Include="windows_impl.cpp" />
Expand Down Expand Up @@ -454,6 +455,7 @@
<ClInclude Include="PlistCpp\pugixml.hpp" />
<ClInclude Include="Printing.h" />
<ClInclude Include="ServerHelper.h" />
<ClInclude Include="SetTimeout.h" />
<ClInclude Include="SocketHelper.h" />
<ClInclude Include="StringHelper.h" />
</ItemGroup>
Expand Down
69 changes: 69 additions & 0 deletions IOSDeviceLib/SetTimeout.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <mutex>
#include <thread>
#include "SetTimeout.h"
#include "Constants.h"

#ifdef WIN32
DWORD WINAPI TimeoutThreadExecutor(LPVOID lpParam) {
TimeoutData* threadData = (TimeoutData*)lpParam;
std::this_thread::sleep_for(std::chrono::milliseconds(threadData->timeout * 1000));
threadData->operation(threadData->data);
free(threadData);
return 0;
}
#endif

TimeoutOutputData setTimeout(int timeout, void * data, void(*operation)(void*)) {
std::thread::native_handle_type darwinHandle = nullptr;
HANDLE windowsHandle = nullptr;
struct TimeoutData* timeoutData = nullptr;

if (timeout > 0) {
timeoutData = reinterpret_cast<TimeoutData*>(malloc(sizeof(struct TimeoutData)));
timeoutData->timeout = timeout;
timeoutData->data = data;
timeoutData->operation = operation;

#ifdef WIN32
windowsHandle = CreateThread(
NULL, // default security attributes
0, // use default stack size
TimeoutThreadExecutor, // thread function name
timeoutData, // argument to thread function
0, // use default creation flags
nullptr);
#else
std::thread thread = std::thread([=]() {
std::this_thread::sleep_for(std::chrono::milliseconds(timeoutData->timeout * 1000));
timeoutData->operation(timeoutData->data);
});

darwinHandle = thread.native_handle();
thread.detach();
#endif
}

return { darwinHandle, windowsHandle, timeoutData };
}

void clearTimeout(TimeoutOutputData data) {
if (data.timeoutData) {
free(data.timeoutData);
data.timeoutData = nullptr;
}

#ifdef WIN32
if (data.windowsHandle) {
int terminateThreadResult = TerminateThread(data.windowsHandle, 9);
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminatethread#return-value
if (terminateThreadResult == 0)
{
DWORD errorCode = GetLastError();
}
}
#else
if (data.darwinHandle) {
pthread_cancel(data.darwinHandle);
}
#endif
}
40 changes: 40 additions & 0 deletions IOSDeviceLib/SetTimeout.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#include <ws2tcpip.h>
typedef void* CFDictionaryRef;

#pragma comment(lib, "Ws2_32.lib")
#else
typedef void* HANDLE;
typedef unsigned long long SOCKET;
#endif

#ifndef _WIN32

#include <sys/socket.h>
#include <stdlib.h>
#include <CoreFoundation/CoreFoundation.h>
#endif

#include <map>
#include <string>
#include <functional>
#include "PlistCpp/include/boost/any.hpp"

struct TimeoutData {
int timeout;
void * data;
void(*operation)(void *);
};

struct TimeoutOutputData {
std::thread::native_handle_type darwinHandle;
HANDLE windowsHandle;
TimeoutData* timeoutData;
};

TimeoutOutputData setTimeout(int timeout, void * data, void(*operation)(void*));
void clearTimeout(TimeoutOutputData data);
57 changes: 0 additions & 57 deletions IOSDeviceLib/SocketHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,6 @@
#include "PlistCpp/Plist.hpp"
#include "PlistCpp/PlistDate.hpp"

std::thread::native_handle_type setTimeout(std::function<void()> operation, int timeout) {
std::thread thread = std::thread([=]() {
std::this_thread::sleep_for(std::chrono::milliseconds(timeout * 1000));
operation();
});

std::thread::native_handle_type native = thread.native_handle();
thread.detach();

return native;
}

void clearTimeout(std::thread::native_handle_type nativeHandle) {
if (nativeHandle) {
pthread_cancel(nativeHandle);
}
}

std::mutex receive_con_message_mutex;
std::map<std::string, boost::any> receive_con_message(ServiceConnRef con, std::string device_identifier, std::string method_id, int timeout)
{
receive_con_message_mutex.lock();

std::thread::native_handle_type nativeHandle;

if (timeout > 0) {
nativeHandle = setTimeout([=]() {
AMDServiceConnectionInvalidate(con);
}, timeout);
}

std::map<std::string, boost::any> dict;
char *buffer = new char[4];
int bytes_read = AMDServiceConnectionReceive(con, buffer, 4);
if (bytes_read > 0)
{
unsigned long res = ntohl(*((unsigned long*)buffer));
delete[] buffer;
buffer = new char[res];
bytes_read = AMDServiceConnectionReceive(con, buffer, res);
if (bytes_read > 0)
{
Plist::readPlist(buffer, res, dict);
clearTimeout(nativeHandle);
}
}

delete[] buffer;
receive_con_message_mutex.unlock();
return dict;
}

long send_con_message(ServiceConnRef serviceConnection, CFDictionaryRef message)
{
return AMDServiceConnectionSendMessage(serviceConnection, message, kCFPropertyListXMLFormat_v1_0);
}

int send_message(const char* message, SOCKET socket, long long length)
{
LengthEncodedMessage length_encoded_message = get_message_with_encoded_length(message, length);
Expand Down
2 changes: 0 additions & 2 deletions IOSDeviceLib/SocketHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ struct Utf16Message {
LengthEncodedMessage get_message_with_encoded_length(const char* message, long long length = -1);
int send_message(const char* message, SOCKET socket, long long length = -1);
int send_message(std::string message, SOCKET socket, long long length = -1);
long send_con_message(HANDLE* serviceConnection, CFDictionaryRef message);
std::map<std::string, boost::any> receive_con_message(HANDLE* con, std::string device_identifier, std::string method_id, int timeout);
std::map<std::string, boost::any> receive_message(SOCKET socket, int timeout = 5);
std::string receive_message_raw(SOCKET socket, int size = 1000);

Expand Down