Skip to content

Commit aef3881

Browse files
authored
Merge pull request #60 from telerik/vladimirov/settimeout-windows
fix: setTimeout does not work on Windows
2 parents ab37d3e + ff56761 commit aef3881

File tree

9 files changed

+181
-63
lines changed

9 files changed

+181
-63
lines changed

IOSDeviceLib.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
709A6CD21E435D11006F76C7 /* Printing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 709A6CCE1E435D11006F76C7 /* Printing.cpp */; };
2222
709A6CD31E435D11006F76C7 /* windows_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 709A6CD01E435D11006F76C7 /* windows_impl.cpp */; };
2323
70DFE7601E72ACCC000317B3 /* ServerHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70DFE75E1E72ACCC000317B3 /* ServerHelper.cpp */; };
24+
E0F67C12232591AE00D3E0C2 /* SetTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E0F67C11232591AE00D3E0C2 /* SetTimeout.cpp */; };
2425
/* End PBXBuildFile section */
2526

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

340343
/* Begin PBXFrameworksBuildPhase section */
@@ -375,6 +378,8 @@
375378
7038C9F31DEEDB4C00A3D335 /* json.hpp */,
376379
7038C9F41DEEDB4C00A3D335 /* PlistCpp */,
377380
7038CB401DEEF31400A3D335 /* Declarations.h */,
381+
E0F67C102325919600D3E0C2 /* SetTimeout.h */,
382+
E0F67C11232591AE00D3E0C2 /* SetTimeout.cpp */,
378383
);
379384
path = IOSDeviceLib;
380385
sourceTree = "<group>";
@@ -1186,6 +1191,7 @@
11861191
7038CB3D1DEEDB4C00A3D335 /* Plist.cpp in Sources */,
11871192
709A6CD21E435D11006F76C7 /* Printing.cpp in Sources */,
11881193
7024956F1E4080B8009A6EBF /* GDBHelper.cpp in Sources */,
1194+
E0F67C12232591AE00D3E0C2 /* SetTimeout.cpp in Sources */,
11891195
7038CB3F1DEEDB4C00A3D335 /* pugixml.cpp in Sources */,
11901196
7038CB3C1DEEDB4C00A3D335 /* IOSDeviceLib.cpp in Sources */,
11911197
702495701E4080B8009A6EBF /* SocketHelper.cpp in Sources */,

IOSDeviceLib/Declarations.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,15 @@ struct ServiceInfo {
105105
HANDLE socket;
106106
ServiceConnRef connection;
107107
int connection_id;
108+
std::string service_name;
109+
};
110+
111+
struct ConnectionMessageData {
112+
ServiceConnRef conn;
113+
std::string device_identifier;
114+
std::string method_id;
115+
std::string service_name;
116+
int timeout;
108117
};
109118

110119
struct DeviceData {
@@ -268,7 +277,7 @@ extern HINSTANCE mobile_device_dll;
268277

269278
extern "C"
270279
{
271-
CFSocketNativeHandle AMDServiceConnectionGetSocket(ServiceConnRef con);
280+
CFSocketNativeHandle AMDServiceConnectionGetSocket(ServiceConnRef con);
272281
long AMDServiceConnectionReceive(ServiceConnRef, void *, long);
273282
void AMDServiceConnectionInvalidate(ServiceConnRef);
274283
long AMDServiceConnectionSendMessage(ServiceConnRef serviceConnection, CFDictionaryRef message, CFPropertyListFormat format);

IOSDeviceLib/IOSDeviceLib.cpp

+53-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "Printing.h"
2222
#include "CommonFunctions.h"
2323
#include "ServerHelper.h"
24+
#include "SetTimeout.h"
2425

2526
#ifdef _WIN32
2627
#pragma region Dll_Variable_Definitions
@@ -444,6 +445,7 @@ ServiceInfo start_secure_service(std::string device_identifier, const char* serv
444445
serviceInfoResult.socket = socket;
445446
serviceInfoResult.connection = connection;
446447
serviceInfoResult.connection_id = nextServiceConnectionId;
448+
serviceInfoResult.service_name = service_name;
447449
serviceConnections[nextServiceConnectionId] = connection;
448450
nextServiceConnectionId++;
449451

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

645+
std::mutex clean_con_resources_mutex;
646+
void clean_con_resources(void* data)
647+
{
648+
clean_con_resources_mutex.lock();
649+
ConnectionMessageData* connectionMessageData = reinterpret_cast<ConnectionMessageData*>(data);
650+
ServiceConnRef conn = connectionMessageData->conn;
651+
devices[connectionMessageData->device_identifier].services.erase(connectionMessageData->service_name.c_str());
652+
AMDServiceConnectionInvalidate(conn);
653+
clean_con_resources_mutex.unlock();
654+
}
655+
656+
std::mutex receive_con_message_mutex;
657+
std::map<std::string, boost::any> receive_con_message(ConnectionMessageData data)
658+
{
659+
receive_con_message_mutex.lock();
660+
661+
ServiceConnRef conn = data.conn;
662+
TimeoutOutputData timeoutOutputData = setTimeout(data.timeout, &data, clean_con_resources);
663+
664+
std::map<std::string, boost::any> dict;
665+
char *buffer = new char[4];
666+
int bytes_read = AMDServiceConnectionReceive(conn, buffer, 4);
667+
if (bytes_read > 0)
668+
{
669+
unsigned long res = ntohl(*((unsigned long*)buffer));
670+
delete[] buffer;
671+
buffer = new char[res];
672+
bytes_read = AMDServiceConnectionReceive(conn, buffer, res);
673+
if (bytes_read > 0)
674+
{
675+
Plist::readPlist(buffer, res, dict);
676+
clearTimeout(timeoutOutputData);
677+
}
678+
} else {
679+
clearTimeout(timeoutOutputData);
680+
}
681+
682+
delete[] buffer;
683+
receive_con_message_mutex.unlock();
684+
return dict;
685+
}
686+
687+
long send_con_message(ServiceConnRef serviceConnection, CFDictionaryRef message)
688+
{
689+
return AMDServiceConnectionSendMessage(serviceConnection, message, kCFPropertyListXMLFormat_v1_0);
690+
}
691+
643692
void read_dir(AFCConnectionRef afc_conn_p, const char* dir, json &files, std::stringstream &errors, std::string method_id, std::string device_identifier)
644693
{
645694
char *dir_ent;
@@ -1003,7 +1052,8 @@ void get_application_infos(std::string device_identifier, std::string method_id)
10031052
std::vector<json> livesync_app_infos;
10041053
while (true)
10051054
{
1006-
std::map<std::string, boost::any> dict = receive_con_message(serviceInfo.connection, device_identifier, method_id, 0);
1055+
ConnectionMessageData connectionMessageData = { serviceInfo.connection, device_identifier, method_id, kInstallationProxy, 10 };
1056+
std::map<std::string, boost::any> dict = receive_con_message(connectionMessageData);
10071057
PRINT_ERROR_AND_RETURN_IF_FAILED_RESULT(dict.count(kErrorKey), boost::any_cast<std::string>(dict[kErrorKey]).c_str(), device_identifier, method_id);
10081058
if (dict.empty() || (dict.count(kStatusKey) && has_complete_status(dict)))
10091059
{
@@ -1177,7 +1227,8 @@ void await_notification_response(std::string device_identifier, AwaitNotificatio
11771227
PRINT_ERROR_AND_RETURN_IF_FAILED_RESULT(connection == nullptr, invalid_connection_error_message.c_str(), device_identifier, method_id);
11781228

11791229
ServiceInfo currentNotificationProxy = devices[device_identifier].services[kNotificationProxy];
1180-
std::map<std::string, boost::any> response = receive_con_message(connection, device_identifier, method_id, await_notification_response_info.timeout);
1230+
ConnectionMessageData connectionMessageData = { connection, device_identifier, method_id, kNotificationProxy, await_notification_response_info.timeout };
1231+
std::map<std::string, boost::any> response = receive_con_message(connectionMessageData);
11811232
if (response.size())
11821233
{
11831234
PRINT_ERROR_AND_RETURN_IF_FAILED_RESULT(response.count(kErrorKey), boost::any_cast<std::string>(response[kErrorKey]).c_str(), device_identifier, method_id);

IOSDeviceLib/IOSDeviceLib.vcxproj

+2
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173
<ClCompile Include="PlistCpp\pugixml.cpp" />
174174
<ClCompile Include="Printing.cpp" />
175175
<ClCompile Include="ServerHelper.cpp" />
176+
<ClCompile Include="SetTimeout.cpp" />
176177
<ClCompile Include="SocketHelper.cpp" />
177178
<ClCompile Include="StringHelper.cpp" />
178179
<ClCompile Include="windows_impl.cpp" />
@@ -454,6 +455,7 @@
454455
<ClInclude Include="PlistCpp\pugixml.hpp" />
455456
<ClInclude Include="Printing.h" />
456457
<ClInclude Include="ServerHelper.h" />
458+
<ClInclude Include="SetTimeout.h" />
457459
<ClInclude Include="SocketHelper.h" />
458460
<ClInclude Include="StringHelper.h" />
459461
</ItemGroup>

IOSDeviceLib/SetTimeout.cpp

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include <mutex>
2+
#include <thread>
3+
#include "SetTimeout.h"
4+
#include "Constants.h"
5+
6+
#ifdef WIN32
7+
DWORD WINAPI TimeoutThreadExecutor(LPVOID lpParam) {
8+
TimeoutData* threadData = (TimeoutData*)lpParam;
9+
std::this_thread::sleep_for(std::chrono::milliseconds(threadData->timeout * 1000));
10+
threadData->operation(threadData->data);
11+
free(threadData);
12+
return 0;
13+
}
14+
#endif
15+
16+
TimeoutOutputData setTimeout(int timeout, void * data, void(*operation)(void*)) {
17+
std::thread::native_handle_type darwinHandle = nullptr;
18+
HANDLE windowsHandle = nullptr;
19+
struct TimeoutData* timeoutData = nullptr;
20+
21+
if (timeout > 0) {
22+
timeoutData = reinterpret_cast<TimeoutData*>(malloc(sizeof(struct TimeoutData)));
23+
timeoutData->timeout = timeout;
24+
timeoutData->data = data;
25+
timeoutData->operation = operation;
26+
27+
#ifdef WIN32
28+
windowsHandle = CreateThread(
29+
NULL, // default security attributes
30+
0, // use default stack size
31+
TimeoutThreadExecutor, // thread function name
32+
timeoutData, // argument to thread function
33+
0, // use default creation flags
34+
nullptr);
35+
#else
36+
std::thread thread = std::thread([=]() {
37+
std::this_thread::sleep_for(std::chrono::milliseconds(timeoutData->timeout * 1000));
38+
timeoutData->operation(timeoutData->data);
39+
});
40+
41+
darwinHandle = thread.native_handle();
42+
thread.detach();
43+
#endif
44+
}
45+
46+
return { darwinHandle, windowsHandle, timeoutData };
47+
}
48+
49+
void clearTimeout(TimeoutOutputData data) {
50+
if (data.timeoutData) {
51+
free(data.timeoutData);
52+
data.timeoutData = nullptr;
53+
}
54+
55+
#ifdef WIN32
56+
if (data.windowsHandle) {
57+
int terminateThreadResult = TerminateThread(data.windowsHandle, 9);
58+
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminatethread#return-value
59+
if (terminateThreadResult == 0)
60+
{
61+
DWORD errorCode = GetLastError();
62+
}
63+
}
64+
#else
65+
if (data.darwinHandle) {
66+
pthread_cancel(data.darwinHandle);
67+
}
68+
#endif
69+
}

IOSDeviceLib/SetTimeout.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
3+
#ifdef _WIN32
4+
#include <io.h>
5+
#include <fcntl.h>
6+
#include <ws2tcpip.h>
7+
typedef void* CFDictionaryRef;
8+
9+
#pragma comment(lib, "Ws2_32.lib")
10+
#else
11+
typedef void* HANDLE;
12+
typedef unsigned long long SOCKET;
13+
#endif
14+
15+
#ifndef _WIN32
16+
17+
#include <sys/socket.h>
18+
#include <stdlib.h>
19+
#include <CoreFoundation/CoreFoundation.h>
20+
#endif
21+
22+
#include <map>
23+
#include <string>
24+
#include <functional>
25+
#include "PlistCpp/include/boost/any.hpp"
26+
27+
struct TimeoutData {
28+
int timeout;
29+
void * data;
30+
void(*operation)(void *);
31+
};
32+
33+
struct TimeoutOutputData {
34+
std::thread::native_handle_type darwinHandle;
35+
HANDLE windowsHandle;
36+
TimeoutData* timeoutData;
37+
};
38+
39+
TimeoutOutputData setTimeout(int timeout, void * data, void(*operation)(void*));
40+
void clearTimeout(TimeoutOutputData data);

IOSDeviceLib/SocketHelper.cpp

-57
Original file line numberDiff line numberDiff line change
@@ -7,63 +7,6 @@
77
#include "PlistCpp/Plist.hpp"
88
#include "PlistCpp/PlistDate.hpp"
99

10-
std::thread::native_handle_type setTimeout(std::function<void()> operation, int timeout) {
11-
std::thread thread = std::thread([=]() {
12-
std::this_thread::sleep_for(std::chrono::milliseconds(timeout * 1000));
13-
operation();
14-
});
15-
16-
std::thread::native_handle_type native = thread.native_handle();
17-
thread.detach();
18-
19-
return native;
20-
}
21-
22-
void clearTimeout(std::thread::native_handle_type nativeHandle) {
23-
if (nativeHandle) {
24-
pthread_cancel(nativeHandle);
25-
}
26-
}
27-
28-
std::mutex receive_con_message_mutex;
29-
std::map<std::string, boost::any> receive_con_message(ServiceConnRef con, std::string device_identifier, std::string method_id, int timeout)
30-
{
31-
receive_con_message_mutex.lock();
32-
33-
std::thread::native_handle_type nativeHandle;
34-
35-
if (timeout > 0) {
36-
nativeHandle = setTimeout([=]() {
37-
AMDServiceConnectionInvalidate(con);
38-
}, timeout);
39-
}
40-
41-
std::map<std::string, boost::any> dict;
42-
char *buffer = new char[4];
43-
int bytes_read = AMDServiceConnectionReceive(con, buffer, 4);
44-
if (bytes_read > 0)
45-
{
46-
unsigned long res = ntohl(*((unsigned long*)buffer));
47-
delete[] buffer;
48-
buffer = new char[res];
49-
bytes_read = AMDServiceConnectionReceive(con, buffer, res);
50-
if (bytes_read > 0)
51-
{
52-
Plist::readPlist(buffer, res, dict);
53-
clearTimeout(nativeHandle);
54-
}
55-
}
56-
57-
delete[] buffer;
58-
receive_con_message_mutex.unlock();
59-
return dict;
60-
}
61-
62-
long send_con_message(ServiceConnRef serviceConnection, CFDictionaryRef message)
63-
{
64-
return AMDServiceConnectionSendMessage(serviceConnection, message, kCFPropertyListXMLFormat_v1_0);
65-
}
66-
6710
int send_message(const char* message, SOCKET socket, long long length)
6811
{
6912
LengthEncodedMessage length_encoded_message = get_message_with_encoded_length(message, length);

IOSDeviceLib/SocketHelper.h

-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ struct Utf16Message {
4040
LengthEncodedMessage get_message_with_encoded_length(const char* message, long long length = -1);
4141
int send_message(const char* message, SOCKET socket, long long length = -1);
4242
int send_message(std::string message, SOCKET socket, long long length = -1);
43-
long send_con_message(HANDLE* serviceConnection, CFDictionaryRef message);
44-
std::map<std::string, boost::any> receive_con_message(HANDLE* con, std::string device_identifier, std::string method_id, int timeout);
4543
std::map<std::string, boost::any> receive_message(SOCKET socket, int timeout = 5);
4644
std::string receive_message_raw(SOCKET socket, int size = 1000);
4745

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ios-device-lib",
3-
"version": "0.7.3",
3+
"version": "0.7.4",
44
"description": "",
55
"types": "./typings/ios-device-lib.d.ts",
66
"main": "index.js",

0 commit comments

Comments
 (0)