react-native-tcp-windows 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +145 -0
  3. package/lib/commonjs/ReactNativeTcpWindows.js +9 -0
  4. package/lib/commonjs/ReactNativeTcpWindows.js.map +1 -0
  5. package/lib/commonjs/index.js +124 -0
  6. package/lib/commonjs/index.js.map +1 -0
  7. package/lib/commonjs/package.json +1 -0
  8. package/lib/module/ReactNativeTcpWindows.js +5 -0
  9. package/lib/module/ReactNativeTcpWindows.js.map +1 -0
  10. package/lib/module/index.js +104 -0
  11. package/lib/module/index.js.map +1 -0
  12. package/lib/module/package.json +1 -0
  13. package/lib/typescript/commonjs/package.json +1 -0
  14. package/lib/typescript/commonjs/src/ReactNativeTcpWindows.d.ts +13 -0
  15. package/lib/typescript/commonjs/src/ReactNativeTcpWindows.d.ts.map +1 -0
  16. package/lib/typescript/commonjs/src/__tests__/index.test.d.ts +1 -0
  17. package/lib/typescript/commonjs/src/__tests__/index.test.d.ts.map +1 -0
  18. package/lib/typescript/commonjs/src/index.d.ts +80 -0
  19. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  20. package/lib/typescript/module/package.json +1 -0
  21. package/lib/typescript/module/src/ReactNativeTcpWindows.d.ts +13 -0
  22. package/lib/typescript/module/src/ReactNativeTcpWindows.d.ts.map +1 -0
  23. package/lib/typescript/module/src/__tests__/index.test.d.ts +1 -0
  24. package/lib/typescript/module/src/__tests__/index.test.d.ts.map +1 -0
  25. package/lib/typescript/module/src/index.d.ts +80 -0
  26. package/lib/typescript/module/src/index.d.ts.map +1 -0
  27. package/package.json +204 -0
  28. package/react-native.config.js +12 -0
  29. package/src/ReactNativeTcpWindows.ts +14 -0
  30. package/src/__tests__/index.test.tsx +1 -0
  31. package/src/index.tsx +124 -0
  32. package/windows/ExperimentalFeatures.props +33 -0
  33. package/windows/ReactNativeTcpWindows/ReactNativeTcpWindows.cpp +206 -0
  34. package/windows/ReactNativeTcpWindows/ReactNativeTcpWindows.def +3 -0
  35. package/windows/ReactNativeTcpWindows/ReactNativeTcpWindows.h +83 -0
  36. package/windows/ReactNativeTcpWindows/ReactNativeTcpWindows.rc +0 -0
  37. package/windows/ReactNativeTcpWindows/ReactNativeTcpWindows.vcxproj +146 -0
  38. package/windows/ReactNativeTcpWindows/ReactNativeTcpWindows.vcxproj.filters +44 -0
  39. package/windows/ReactNativeTcpWindows/ReactPackageProvider.cpp +20 -0
  40. package/windows/ReactNativeTcpWindows/ReactPackageProvider.h +24 -0
  41. package/windows/ReactNativeTcpWindows/ReactPackageProvider.idl +9 -0
  42. package/windows/ReactNativeTcpWindows/TcpSocket.cpp +565 -0
  43. package/windows/ReactNativeTcpWindows/TcpSocket.h +69 -0
  44. package/windows/ReactNativeTcpWindows/codegen/.clang-format +2 -0
  45. package/windows/ReactNativeTcpWindows/codegen/NativeReactNativeTcpWindowsSpec.g.h +71 -0
  46. package/windows/ReactNativeTcpWindows/packages.lock.json +60 -0
  47. package/windows/ReactNativeTcpWindows/pch.cpp +1 -0
  48. package/windows/ReactNativeTcpWindows/pch.h +30 -0
  49. package/windows/ReactNativeTcpWindows/resource.h +5 -0
  50. package/windows/ReactNativeTcpWindows/targetver.h +8 -0
  51. package/windows/ReactNativeTcpWindows.sln +43 -0
@@ -0,0 +1,565 @@
1
+ #include "pch.h"
2
+ #include "TcpSocket.h"
3
+ #include <sstream>
4
+
5
+ bool TcpSocket::s_wsaInitialized = false;
6
+ int TcpSocket::s_wsaRefCount = 0;
7
+ std::mutex TcpSocket::s_wsaMutex;
8
+
9
+ TcpSocket::TcpSocket(const std::string &address, int port, ConnectionType type)
10
+ : m_address(address), m_port(port), m_type(type), m_socket(INVALID_SOCKET), m_serverSocket(INVALID_SOCKET), m_isRunning(false), m_isConnected(false), m_isServerRunning(false)
11
+ {
12
+
13
+ std::lock_guard<std::mutex> lock(s_wsaMutex);
14
+ if (!s_wsaInitialized)
15
+ {
16
+ WSADATA wsaData;
17
+ if (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0)
18
+ {
19
+ s_wsaInitialized = true;
20
+ }
21
+ }
22
+ s_wsaRefCount++;
23
+ }
24
+
25
+ TcpSocket::~TcpSocket()
26
+ {
27
+ close();
28
+
29
+ std::lock_guard<std::mutex> lock(s_wsaMutex);
30
+ s_wsaRefCount--;
31
+ if (s_wsaRefCount == 0 && s_wsaInitialized)
32
+ {
33
+ WSACleanup();
34
+ s_wsaInitialized = false;
35
+ }
36
+ }
37
+
38
+ bool TcpSocket::connect()
39
+ {
40
+ if (m_type != ConnectionType::Client)
41
+ {
42
+ return false;
43
+ }
44
+
45
+ if (m_isConnected)
46
+ {
47
+ close();
48
+ }
49
+
50
+ m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
51
+ if (m_socket == INVALID_SOCKET)
52
+ {
53
+ if (m_connectionStatusCallback)
54
+ {
55
+ m_connectionStatusCallback(false, "Failed to create socket");
56
+ }
57
+ return false;
58
+ }
59
+
60
+ sockaddr_in serverAddr = {};
61
+ serverAddr.sin_family = AF_INET;
62
+ serverAddr.sin_port = htons(m_port);
63
+
64
+ if (inet_pton(AF_INET, m_address.c_str(), &serverAddr.sin_addr) <= 0)
65
+ {
66
+ closesocket(m_socket);
67
+ m_socket = INVALID_SOCKET;
68
+ if (m_connectionStatusCallback)
69
+ {
70
+ m_connectionStatusCallback(false, "Invalid address format");
71
+ }
72
+ return false;
73
+ }
74
+
75
+ if (::connect(m_socket, (sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
76
+ {
77
+ int error = WSAGetLastError();
78
+ closesocket(m_socket);
79
+ m_socket = INVALID_SOCKET;
80
+ if (m_connectionStatusCallback)
81
+ {
82
+ m_connectionStatusCallback(false, "Connection failed. Error: " + std::to_string(error));
83
+ }
84
+ return false;
85
+ }
86
+
87
+ m_isConnected = true;
88
+ m_isRunning = true;
89
+ startReading();
90
+
91
+ if (m_connectionStatusCallback)
92
+ {
93
+ m_connectionStatusCallback(true, "Connected successfully");
94
+ }
95
+
96
+ return true;
97
+ }
98
+
99
+ bool TcpSocket::startServer()
100
+ {
101
+ if (m_type != ConnectionType::Server)
102
+ {
103
+ return false;
104
+ }
105
+
106
+ if (m_isServerRunning)
107
+ {
108
+ close();
109
+ }
110
+
111
+ m_serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
112
+ if (m_serverSocket == INVALID_SOCKET)
113
+ {
114
+ if (m_connectionStatusCallback)
115
+ {
116
+ m_connectionStatusCallback(false, "Failed to create server socket");
117
+ }
118
+ return false;
119
+ }
120
+
121
+ // Allow socket reuse
122
+ BOOL reuseAddr = TRUE;
123
+ setsockopt(m_serverSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseAddr, sizeof(reuseAddr));
124
+
125
+ sockaddr_in serverAddr = {};
126
+ serverAddr.sin_family = AF_INET;
127
+ serverAddr.sin_port = htons(m_port);
128
+ serverAddr.sin_addr.s_addr = INADDR_ANY;
129
+
130
+ if (bind(m_serverSocket, (sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
131
+ {
132
+ int error = WSAGetLastError();
133
+ closesocket(m_serverSocket);
134
+ m_serverSocket = INVALID_SOCKET;
135
+ if (m_connectionStatusCallback)
136
+ {
137
+ m_connectionStatusCallback(false, "Bind failed. Error: " + std::to_string(error));
138
+ }
139
+ return false;
140
+ }
141
+
142
+ if (listen(m_serverSocket, SOMAXCONN) == SOCKET_ERROR)
143
+ {
144
+ int error = WSAGetLastError();
145
+ closesocket(m_serverSocket);
146
+ m_serverSocket = INVALID_SOCKET;
147
+ if (m_connectionStatusCallback)
148
+ {
149
+ m_connectionStatusCallback(false, "Listen failed. Error: " + std::to_string(error));
150
+ }
151
+ return false;
152
+ }
153
+
154
+ m_isServerRunning = true;
155
+ m_isRunning = true;
156
+
157
+ // Start accepting connections
158
+ m_acceptThread = std::thread(&TcpSocket::serverAcceptThread, this);
159
+
160
+ if (m_connectionStatusCallback)
161
+ {
162
+ m_connectionStatusCallback(true, "Server started on port " + std::to_string(m_port));
163
+ }
164
+
165
+ return true;
166
+ }
167
+
168
+ void TcpSocket::close()
169
+ {
170
+ // STEP 1: Shutdown sockets FIRST to wake up any blocking operations
171
+ if (m_socket != INVALID_SOCKET) {
172
+ shutdown(m_socket, SD_BOTH); // This wakes up recv() calls
173
+ }
174
+
175
+ if (m_serverSocket != INVALID_SOCKET) {
176
+ shutdown(m_serverSocket, SD_BOTH); // This wakes up accept() calls
177
+ }
178
+
179
+ // Shutdown all client connections
180
+ {
181
+ std::lock_guard<std::mutex> lock(m_clientsMutex);
182
+ for (SOCKET clientSocket : m_clientSockets) {
183
+ if (clientSocket != INVALID_SOCKET) {
184
+ shutdown(clientSocket, SD_BOTH);
185
+ }
186
+ }
187
+ }
188
+
189
+ // STEP 2: Now stopReading should complete quickly since sockets are shutdown
190
+ stopReading();
191
+
192
+ // STEP 3: Close the sockets
193
+ if (m_socket != INVALID_SOCKET)
194
+ {
195
+ closesocket(m_socket);
196
+ m_socket = INVALID_SOCKET;
197
+ }
198
+
199
+ if (m_serverSocket != INVALID_SOCKET)
200
+ {
201
+ closesocket(m_serverSocket);
202
+ m_serverSocket = INVALID_SOCKET;
203
+ }
204
+
205
+ // Close all client connections
206
+ {
207
+ std::lock_guard<std::mutex> lock(m_clientsMutex);
208
+ for (SOCKET clientSocket : m_clientSockets)
209
+ {
210
+ closesocket(clientSocket);
211
+ }
212
+ m_clientSockets.clear();
213
+ }
214
+
215
+ m_isConnected = false;
216
+ m_isServerRunning = false;
217
+ }
218
+
219
+ bool TcpSocket::write(const std::vector<uint8_t> &data)
220
+ {
221
+ if (data.empty())
222
+ {
223
+ return false;
224
+ }
225
+
226
+ if (m_type == ConnectionType::Client && m_isConnected)
227
+ {
228
+ int result = send(m_socket, (char *)data.data(), static_cast<int>(data.size()), 0);
229
+ return result != SOCKET_ERROR;
230
+ }
231
+ else if (m_type == ConnectionType::Server && m_isServerRunning)
232
+ {
233
+ // Send to all connected clients
234
+ std::lock_guard<std::mutex> lock(m_clientsMutex);
235
+ bool success = true;
236
+ for (SOCKET clientSocket : m_clientSockets)
237
+ {
238
+ int result = send(clientSocket, (char *)data.data(), static_cast<int>(data.size()), 0);
239
+ if (result == SOCKET_ERROR)
240
+ {
241
+ success = false;
242
+ }
243
+ }
244
+ return success;
245
+ }
246
+
247
+ return false;
248
+ }
249
+
250
+ void TcpSocket::setDataReceivedCallback(DataReceivedCallback callback)
251
+ {
252
+ m_dataCallback = std::move(callback);
253
+ }
254
+
255
+ void TcpSocket::setClientConnectedCallback(ClientConnectedCallback callback)
256
+ {
257
+ m_clientConnectedCallback = std::move(callback);
258
+ }
259
+
260
+ void TcpSocket::setClientDisconnectedCallback(ClientDisconnectedCallback callback)
261
+ {
262
+ m_clientDisconnectedCallback = std::move(callback);
263
+ }
264
+
265
+ void TcpSocket::setConnectionStatusCallback(ConnectionStatusCallback callback)
266
+ {
267
+ m_connectionStatusCallback = std::move(callback);
268
+ }
269
+
270
+ void TcpSocket::startReading()
271
+ {
272
+ if (m_type == ConnectionType::Client)
273
+ {
274
+ m_readThread = std::thread(&TcpSocket::clientReadThread, this);
275
+ }
276
+ }
277
+
278
+ // CHANGE 1: Update clientReadThread() - Add socket timeout
279
+ void TcpSocket::clientReadThread()
280
+ {
281
+ std::vector<uint8_t> buffer(1024);
282
+
283
+ // Set socket timeout to prevent infinite blocking
284
+ DWORD timeout = 1000; // 1 second
285
+ setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
286
+
287
+ while (m_isRunning && m_isConnected)
288
+ {
289
+ int bytesReceived = recv(m_socket, (char *)buffer.data(), buffer.size(), 0);
290
+
291
+ if (bytesReceived > 0)
292
+ {
293
+ if (m_dataCallback)
294
+ {
295
+ OutputDebugStringA(("TCP Client received " + std::to_string(bytesReceived) + " bytes\n").c_str());
296
+ m_dataCallback(std::vector<uint8_t>(buffer.begin(), buffer.begin() + bytesReceived));
297
+ }
298
+ }
299
+ else if (bytesReceived == 0)
300
+ {
301
+ // Connection closed by peer
302
+ m_isConnected = false;
303
+ if (m_connectionStatusCallback)
304
+ {
305
+ m_connectionStatusCallback(false, "Connection closed by peer");
306
+ }
307
+ break;
308
+ }
309
+ else
310
+ {
311
+ // Error occurred
312
+ int error = WSAGetLastError();
313
+ if (error == WSAETIMEDOUT)
314
+ {
315
+ // Timeout - continue loop to check m_isRunning
316
+ continue;
317
+ }
318
+ else if (error == WSAECONNRESET || error == WSAESHUTDOWN || error == WSAENOTCONN)
319
+ {
320
+ // Connection closed/shutdown - exit gracefully
321
+ m_isConnected = false;
322
+ OutputDebugStringA("Connection closed during recv\n");
323
+ break;
324
+ }
325
+ else if (error != WSAEWOULDBLOCK)
326
+ {
327
+ m_isConnected = false;
328
+ if (m_connectionStatusCallback)
329
+ {
330
+ m_connectionStatusCallback(false, "Receive error: " + std::to_string(error));
331
+ }
332
+ break;
333
+ }
334
+ }
335
+ }
336
+ OutputDebugStringA("Client read thread exiting\n");
337
+ }
338
+
339
+ // CHANGE 2: Update serverAcceptThread() - Add socket timeout
340
+ void TcpSocket::serverAcceptThread()
341
+ {
342
+ // Set socket timeout for accept() to prevent infinite blocking
343
+ DWORD timeout = 1000; // 1 second
344
+ setsockopt(m_serverSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
345
+
346
+ while (m_isRunning && m_isServerRunning)
347
+ {
348
+ sockaddr_in clientAddr = {};
349
+ int clientAddrLen = sizeof(clientAddr);
350
+
351
+ SOCKET clientSocket = accept(m_serverSocket, (sockaddr *)&clientAddr, &clientAddrLen);
352
+
353
+ if (clientSocket != INVALID_SOCKET)
354
+ {
355
+ std::string clientAddress = getSocketAddress(clientSocket);
356
+
357
+ {
358
+ std::lock_guard<std::mutex> lock(m_clientsMutex);
359
+ m_clientSockets.push_back(clientSocket);
360
+ m_clientThreads.emplace_back(&TcpSocket::serverClientReadThread, this, clientSocket, clientAddress);
361
+ }
362
+
363
+ if (m_clientConnectedCallback)
364
+ {
365
+ m_clientConnectedCallback(clientAddress);
366
+ }
367
+
368
+ OutputDebugStringA(("Client connected from: " + clientAddress + "\n").c_str());
369
+ }
370
+ else if (m_isRunning && m_isServerRunning)
371
+ {
372
+ int error = WSAGetLastError();
373
+ if (error == WSAETIMEDOUT)
374
+ {
375
+ // Timeout - continue loop to check m_isRunning
376
+ continue;
377
+ }
378
+ else if (error == WSAECONNRESET || error == WSAESHUTDOWN || error == WSAENOTCONN)
379
+ {
380
+ // Server socket closed/shutdown - exit gracefully
381
+ OutputDebugStringA("Server socket closed during accept\n");
382
+ break;
383
+ }
384
+ else if (error != WSAEINTR)
385
+ {
386
+ OutputDebugStringA(("Accept error: " + std::to_string(error) + "\n").c_str());
387
+ }
388
+ }
389
+ }
390
+ OutputDebugStringA("Server accept thread exiting\n");
391
+ }
392
+
393
+ // CHANGE 3: Update serverClientReadThread() - Add socket timeout
394
+ void TcpSocket::serverClientReadThread(SOCKET clientSocket, std::string clientAddress)
395
+ {
396
+ std::vector<uint8_t> buffer(1024);
397
+
398
+ // Set socket timeout to prevent infinite blocking
399
+ DWORD timeout = 1000; // 1 second
400
+ setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
401
+
402
+ while (m_isRunning && m_isServerRunning)
403
+ {
404
+ int bytesReceived = recv(clientSocket, (char *)buffer.data(), buffer.size(), 0);
405
+
406
+ if (bytesReceived > 0)
407
+ {
408
+ if (m_dataCallback)
409
+ {
410
+ OutputDebugStringA(("TCP Server received " + std::to_string(bytesReceived) + " bytes from " + clientAddress + "\n").c_str());
411
+ m_dataCallback(std::vector<uint8_t>(buffer.begin(), buffer.begin() + bytesReceived));
412
+ }
413
+ }
414
+ else if (bytesReceived == 0)
415
+ {
416
+ // Client disconnected
417
+ OutputDebugStringA(("Client disconnected normally: " + clientAddress + "\n").c_str());
418
+ break;
419
+ }
420
+ else
421
+ {
422
+ // Error occurred
423
+ int error = WSAGetLastError();
424
+ if (error == WSAETIMEDOUT)
425
+ {
426
+ // Timeout - continue loop to check m_isRunning
427
+ continue;
428
+ }
429
+ else if (error == WSAECONNRESET || error == WSAESHUTDOWN || error == WSAENOTCONN)
430
+ {
431
+ // Client connection closed/shutdown - exit gracefully
432
+ OutputDebugStringA(("Client connection closed during recv: " + clientAddress + "\n").c_str());
433
+ break;
434
+ }
435
+ else if (error != WSAEWOULDBLOCK)
436
+ {
437
+ OutputDebugStringA(("Client receive error: " + std::to_string(error) + " for " + clientAddress + "\n").c_str());
438
+ break;
439
+ }
440
+ }
441
+ }
442
+
443
+ // Remove client from list and close socket
444
+ {
445
+ std::lock_guard<std::mutex> lock(m_clientsMutex);
446
+ auto it = std::find(m_clientSockets.begin(), m_clientSockets.end(), clientSocket);
447
+ if (it != m_clientSockets.end())
448
+ {
449
+ m_clientSockets.erase(it);
450
+ }
451
+ }
452
+
453
+ closesocket(clientSocket);
454
+
455
+ if (m_clientDisconnectedCallback)
456
+ {
457
+ m_clientDisconnectedCallback(clientAddress);
458
+ }
459
+
460
+ OutputDebugStringA(("Client thread exiting: " + clientAddress + "\n").c_str());
461
+ }
462
+
463
+ // CHANGE 4: Simplify stopReading() - Remove async timeout logic (it's causing issues)
464
+ void TcpSocket::stopReading()
465
+ {
466
+ OutputDebugStringA("stopReading() called\n");
467
+
468
+ // 1. Set the stop flag
469
+ m_isRunning = false;
470
+ OutputDebugStringA("Set m_isRunning = false\n");
471
+
472
+ // 2. WAKE UP blocked threads by shutting down sockets
473
+ if (m_socket != INVALID_SOCKET)
474
+ {
475
+ OutputDebugStringA("Shutting down main socket...\n");
476
+ shutdown(m_socket, SD_BOTH);
477
+ }
478
+
479
+ if (m_serverSocket != INVALID_SOCKET)
480
+ {
481
+ OutputDebugStringA("Shutting down server socket...\n");
482
+ shutdown(m_serverSocket, SD_BOTH);
483
+ }
484
+
485
+ // Wake up client sockets
486
+ {
487
+ std::lock_guard<std::mutex> lock(m_clientsMutex);
488
+ OutputDebugStringA(("Shutting down " + std::to_string(m_clientSockets.size()) + " client sockets...\n").c_str());
489
+ for (SOCKET clientSocket : m_clientSockets)
490
+ {
491
+ shutdown(clientSocket, SD_BOTH);
492
+ }
493
+ }
494
+
495
+ // 3. Join threads with simple timeout
496
+ OutputDebugStringA("Joining read thread...\n");
497
+ if (m_readThread.joinable())
498
+ {
499
+ try
500
+ {
501
+ m_readThread.join();
502
+ OutputDebugStringA("Read thread joined successfully\n");
503
+ }
504
+ catch (...)
505
+ {
506
+ OutputDebugStringA("Read thread join failed - detaching\n");
507
+ m_readThread.detach();
508
+ }
509
+ }
510
+
511
+ OutputDebugStringA("Joining accept thread...\n");
512
+ if (m_acceptThread.joinable())
513
+ {
514
+ try
515
+ {
516
+ m_acceptThread.join();
517
+ OutputDebugStringA("Accept thread joined successfully\n");
518
+ }
519
+ catch (...)
520
+ {
521
+ OutputDebugStringA("Accept thread join failed - detaching\n");
522
+ m_acceptThread.detach();
523
+ }
524
+ }
525
+
526
+ // Join client threads
527
+ OutputDebugStringA(("Joining " + std::to_string(m_clientThreads.size()) + " client threads...\n").c_str());
528
+ for (size_t i = 0; i < m_clientThreads.size(); ++i)
529
+ {
530
+ auto &thread = m_clientThreads[i];
531
+ if (thread.joinable())
532
+ {
533
+ try
534
+ {
535
+ thread.join();
536
+ OutputDebugStringA(("Client thread " + std::to_string(i) + " joined successfully\n").c_str());
537
+ }
538
+ catch (...)
539
+ {
540
+ OutputDebugStringA(("Client thread " + std::to_string(i) + " join failed - detaching\n").c_str());
541
+ thread.detach();
542
+ }
543
+ }
544
+ }
545
+ m_clientThreads.clear();
546
+
547
+ OutputDebugStringA("stopReading() completed successfully\n");
548
+ }
549
+
550
+ std::string TcpSocket::getSocketAddress(SOCKET socket)
551
+ {
552
+ sockaddr_in addr = {};
553
+ int addrLen = sizeof(addr);
554
+
555
+ if (getpeername(socket, (sockaddr *)&addr, &addrLen) == 0)
556
+ {
557
+ char ipStr[INET_ADDRSTRLEN];
558
+ if (inet_ntop(AF_INET, &addr.sin_addr, ipStr, INET_ADDRSTRLEN))
559
+ {
560
+ return std::string(ipStr) + ":" + std::to_string(ntohs(addr.sin_port));
561
+ }
562
+ }
563
+
564
+ return "unknown";
565
+ }
@@ -0,0 +1,69 @@
1
+ #pragma once
2
+ #include "pch.h"
3
+ #include <string>
4
+ #include <WinSock2.h>
5
+ #include <WS2tcpip.h>
6
+ #include <functional>
7
+ #include <thread>
8
+ #include <atomic>
9
+ #include <mutex>
10
+
11
+ #pragma comment(lib, "ws2_32.lib")
12
+
13
+ class TcpSocket {
14
+ public:
15
+ enum class ConnectionType { Client = 0, Server = 1 };
16
+
17
+ using DataReceivedCallback = std::function<void(const std::vector<uint8_t>&)>;
18
+ using ClientConnectedCallback = std::function<void(const std::string&)>;
19
+ using ClientDisconnectedCallback = std::function<void(const std::string&)>;
20
+ using ConnectionStatusCallback = std::function<void(bool, const std::string&)>;
21
+
22
+ TcpSocket(const std::string& address, int port, ConnectionType type);
23
+ //TcpSocket::TcpSocket(const std::string&, int, TcpSocket::ConnectionType)
24
+
25
+ ~TcpSocket();
26
+
27
+ bool connect();
28
+ bool startServer();
29
+ void close();
30
+ bool write(const std::vector<uint8_t>& data);
31
+ void setDataReceivedCallback(DataReceivedCallback callback);
32
+ void setClientConnectedCallback(ClientConnectedCallback callback);
33
+ void setClientDisconnectedCallback(ClientDisconnectedCallback callback);
34
+ void setConnectionStatusCallback(ConnectionStatusCallback callback);
35
+ bool isConnected() const { return m_isConnected; }
36
+ bool isServerRunning() const { return m_isServerRunning; }
37
+
38
+ private:
39
+ void startReading();
40
+ void clientReadThread();
41
+ void serverAcceptThread();
42
+ void serverClientReadThread(SOCKET clientSocket, std::string clientAddress);
43
+ void stopReading();
44
+ void cleanup();
45
+ std::string getSocketAddress(SOCKET socket);
46
+
47
+ std::string m_address;
48
+ int m_port;
49
+ ConnectionType m_type;
50
+ SOCKET m_socket;
51
+ SOCKET m_serverSocket;
52
+ std::atomic<bool> m_isRunning;
53
+ std::atomic<bool> m_isConnected;
54
+ std::atomic<bool> m_isServerRunning;
55
+ std::thread m_readThread;
56
+ std::thread m_acceptThread;
57
+ std::vector<std::thread> m_clientThreads;
58
+ std::vector<SOCKET> m_clientSockets;
59
+ std::mutex m_clientsMutex;
60
+
61
+ DataReceivedCallback m_dataCallback;
62
+ ClientConnectedCallback m_clientConnectedCallback;
63
+ ClientDisconnectedCallback m_clientDisconnectedCallback;
64
+ ConnectionStatusCallback m_connectionStatusCallback;
65
+
66
+ static bool s_wsaInitialized;
67
+ static int s_wsaRefCount;
68
+ static std::mutex s_wsaMutex;
69
+ };
@@ -0,0 +1,2 @@
1
+ DisableFormat: true
2
+ SortIncludes: false
@@ -0,0 +1,71 @@
1
+
2
+ /*
3
+ * This file is auto-generated from a NativeModule spec file in js.
4
+ *
5
+ * This is a C++ Spec class that should be used with MakeTurboModuleProvider to register native modules
6
+ * in a way that also verifies at compile time that the native module matches the interface required
7
+ * by the TurboModule JS spec.
8
+ */
9
+ #pragma once
10
+ // clang-format off
11
+
12
+ #include <NativeModules.h>
13
+ #include <tuple>
14
+
15
+ namespace ReactNativeTcpWindowsCodegen {
16
+
17
+
18
+ struct ReactNativeTcpWindowsSpec : winrt::Microsoft::ReactNative::TurboModuleSpec {
19
+ static constexpr auto methods = std::tuple{
20
+ Method<void(std::string, double, Promise<std::string>) noexcept>{0, L"connectToServer"},
21
+ Method<void(double, Promise<std::string>) noexcept>{1, L"startServer"},
22
+ Method<void(Promise<std::string>) noexcept>{2, L"closeConnection"},
23
+ Method<void(std::vector<double>, Promise<bool>) noexcept>{3, L"write"},
24
+ Method<void(Promise<bool>) noexcept>{4, L"getConnectionStatus"},
25
+ Method<void(std::string) noexcept>{5, L"addListener"},
26
+ Method<void(double) noexcept>{6, L"removeListeners"},
27
+ };
28
+
29
+ template <class TModule>
30
+ static constexpr void ValidateModule() noexcept {
31
+ constexpr auto methodCheckResults = CheckMethods<TModule, ReactNativeTcpWindowsSpec>();
32
+
33
+ REACT_SHOW_METHOD_SPEC_ERRORS(
34
+ 0,
35
+ "connectToServer",
36
+ " REACT_METHOD(connectToServer) void connectToServer(std::string address, double port, ::React::ReactPromise<std::string> &&result) noexcept { /* implementation */ }\n"
37
+ " REACT_METHOD(connectToServer) static void connectToServer(std::string address, double port, ::React::ReactPromise<std::string> &&result) noexcept { /* implementation */ }\n");
38
+ REACT_SHOW_METHOD_SPEC_ERRORS(
39
+ 1,
40
+ "startServer",
41
+ " REACT_METHOD(startServer) void startServer(double port, ::React::ReactPromise<std::string> &&result) noexcept { /* implementation */ }\n"
42
+ " REACT_METHOD(startServer) static void startServer(double port, ::React::ReactPromise<std::string> &&result) noexcept { /* implementation */ }\n");
43
+ REACT_SHOW_METHOD_SPEC_ERRORS(
44
+ 2,
45
+ "closeConnection",
46
+ " REACT_METHOD(closeConnection) void closeConnection(::React::ReactPromise<std::string> &&result) noexcept { /* implementation */ }\n"
47
+ " REACT_METHOD(closeConnection) static void closeConnection(::React::ReactPromise<std::string> &&result) noexcept { /* implementation */ }\n");
48
+ REACT_SHOW_METHOD_SPEC_ERRORS(
49
+ 3,
50
+ "write",
51
+ " REACT_METHOD(write) void write(std::vector<double> const & data, ::React::ReactPromise<bool> &&result) noexcept { /* implementation */ }\n"
52
+ " REACT_METHOD(write) static void write(std::vector<double> const & data, ::React::ReactPromise<bool> &&result) noexcept { /* implementation */ }\n");
53
+ REACT_SHOW_METHOD_SPEC_ERRORS(
54
+ 4,
55
+ "getConnectionStatus",
56
+ " REACT_METHOD(getConnectionStatus) void getConnectionStatus(::React::ReactPromise<bool> &&result) noexcept { /* implementation */ }\n"
57
+ " REACT_METHOD(getConnectionStatus) static void getConnectionStatus(::React::ReactPromise<bool> &&result) noexcept { /* implementation */ }\n");
58
+ REACT_SHOW_METHOD_SPEC_ERRORS(
59
+ 5,
60
+ "addListener",
61
+ " REACT_METHOD(addListener) void addListener(std::string eventType) noexcept { /* implementation */ }\n"
62
+ " REACT_METHOD(addListener) static void addListener(std::string eventType) noexcept { /* implementation */ }\n");
63
+ REACT_SHOW_METHOD_SPEC_ERRORS(
64
+ 6,
65
+ "removeListeners",
66
+ " REACT_METHOD(removeListeners) void removeListeners(double count) noexcept { /* implementation */ }\n"
67
+ " REACT_METHOD(removeListeners) static void removeListeners(double count) noexcept { /* implementation */ }\n");
68
+ }
69
+ };
70
+
71
+ } // namespace ReactNativeTcpWindowsCodegen