Skip to content

Commit 2ca2763

Browse files
committed
Use correct descriptor on windows.
1 parent ff3a07b commit 2ca2763

2 files changed

Lines changed: 83 additions & 76 deletions

File tree

libs/networking/include/launchdarkly/network/curl_multi_manager.hpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44

55
#include <curl/curl.h>
66
#include <boost/asio/any_io_executor.hpp>
7+
#ifdef _WIN32
8+
#include <boost/asio/windows/stream_handle.hpp>
9+
#else
710
#include <boost/asio/posix/stream_descriptor.hpp>
11+
#endif
812
#include <boost/asio/steady_timer.hpp>
913

1014
#include <functional>
@@ -13,6 +17,14 @@
1317
#include <mutex>
1418

1519
namespace launchdarkly::network {
20+
21+
// Platform-specific socket handle type
22+
#ifdef _WIN32
23+
using SocketHandle = boost::asio::windows::stream_handle;
24+
#else
25+
using SocketHandle = boost::asio::posix::stream_descriptor;
26+
#endif
27+
1628
/**
1729
* Manages CURL multi interface integrated with ASIO event loop.
1830
*
@@ -23,7 +35,7 @@ namespace launchdarkly::network {
2335
*
2436
* Key features:
2537
* - Non-blocking I/O using curl_multi_socket_action
26-
* - Socket monitoring via ASIO stream_descriptor
38+
* - Socket monitoring via ASIO (posix::stream_descriptor on POSIX, windows::stream_handle on Windows)
2739
* - Timer integration with ASIO steady_timer
2840
* - Thread-safe operation on ASIO executor
2941
*/
@@ -91,7 +103,7 @@ class CurlMultiManager : public std::enable_shared_from_this<CurlMultiManager> {
91103
// Per-socket data
92104
struct SocketInfo {
93105
curl_socket_t sockfd;
94-
std::shared_ptr<boost::asio::posix::stream_descriptor> descriptor;
106+
std::shared_ptr<SocketHandle> handle;
95107
int action{0}; // CURL_POLL_IN, CURL_POLL_OUT, etc.
96108
// Keep handlers alive - we own them and they only capture weak_ptr to avoid circular refs
97109
std::shared_ptr<std::function<void()>> read_handler;

libs/networking/src/curl_multi_manager.cpp

Lines changed: 69 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,16 @@ void CurlMultiManager::check_multi_info() {
216216

217217
void CurlMultiManager::start_socket_monitor(SocketInfo* socket_info,
218218
const int action) {
219-
if (!socket_info->descriptor) {
220-
// Create descriptor for this socket
221-
socket_info->descriptor = std::make_shared<
222-
boost::asio::posix::stream_descriptor>(executor_);
223-
socket_info->descriptor->assign(socket_info->sockfd);
219+
if (!socket_info->handle) {
220+
// Create handle for this socket
221+
socket_info->handle = std::make_shared<SocketHandle>(executor_);
222+
#ifdef _WIN32
223+
// On Windows, we need to cast the socket to HANDLE for stream_handle
224+
socket_info->handle->assign(reinterpret_cast<HANDLE>(socket_info->sockfd));
225+
#else
226+
// On POSIX, we can assign the socket descriptor directly
227+
socket_info->handle->assign(socket_info->sockfd);
228+
#endif
224229
}
225230

226231
// Check if action has changed
@@ -234,46 +239,41 @@ void CurlMultiManager::start_socket_monitor(SocketInfo* socket_info,
234239
if (action & CURL_POLL_IN) {
235240
// Only create new handler if we don't have one or if action changed
236241
if (!socket_info->read_handler || action_changed) {
237-
// Use weak_ptr to safely detect when descriptor is deleted
238-
std::weak_ptr<boost::asio::posix::stream_descriptor> weak_descriptor
239-
= socket_info->descriptor;
242+
// Use weak_ptr to safely detect when handle is deleted
243+
std::weak_ptr<SocketHandle> weak_handle = socket_info->handle;
240244

241245
// Create and store handler in SocketInfo to keep it alive
242246
// Use weak_ptr in capture to avoid circular reference
243-
socket_info->read_handler = std::make_shared<std::function<void
244-
()>>();
245-
std::weak_ptr<std::function<void()>> weak_read_handler = socket_info
246-
->read_handler;
247-
*socket_info->read_handler = [weak_self, sockfd, weak_descriptor,
248-
weak_read_handler]() {
249-
// Check if manager and descriptor are still valid
250-
const auto self = weak_self.lock();
251-
const auto descriptor = weak_descriptor.lock();
252-
if (!self || !descriptor) {
253-
return;
254-
}
247+
socket_info->read_handler = std::make_shared<std::function<void()>>();
248+
std::weak_ptr<std::function<void()>> weak_read_handler = socket_info->read_handler;
249+
*socket_info->read_handler = [weak_self, sockfd, weak_handle, weak_read_handler]() {
250+
// Check if manager and handle are still valid
251+
const auto self = weak_self.lock();
252+
const auto handle = weak_handle.lock();
253+
if (!self || !handle) {
254+
return;
255+
}
255256

256-
descriptor->async_wait(
257-
boost::asio::posix::stream_descriptor::wait_read,
258-
[weak_self, sockfd, weak_descriptor, weak_read_handler](
257+
handle->async_wait(
258+
SocketHandle::wait_read,
259+
[weak_self, sockfd, weak_handle, weak_read_handler](
259260
const boost::system::error_code& ec) {
260-
// If operation was canceled or had an error, don't re-register
261-
if (ec) {
262-
return;
263-
}
264-
265-
if (const auto self = weak_self.lock()) {
266-
self->handle_socket_action(
267-
sockfd, CURL_CSELECT_IN);
268-
269-
// Always try to re-register for continuous monitoring
270-
// The validity check at the top of read_handler will stop it if needed
271-
if (const auto handler = weak_read_handler.lock()) {
272-
(*handler)(); // Recursive call
273-
}
261+
// If operation was canceled or had an error, don't re-register
262+
if (ec) {
263+
return;
264+
}
265+
266+
if (const auto self = weak_self.lock()) {
267+
self->handle_socket_action(sockfd, CURL_CSELECT_IN);
268+
269+
// Always try to re-register for continuous monitoring
270+
// The validity check at the top of read_handler will stop it if needed
271+
if (const auto handler = weak_read_handler.lock()) {
272+
(*handler)(); // Recursive call
274273
}
275-
});
276-
};
274+
}
275+
});
276+
};
277277
(*socket_info->read_handler)(); // Initial call
278278
}
279279
}
@@ -282,46 +282,41 @@ void CurlMultiManager::start_socket_monitor(SocketInfo* socket_info,
282282
if (action & CURL_POLL_OUT) {
283283
// Only create new handler if we don't have one or if action changed
284284
if (!socket_info->write_handler || action_changed) {
285-
// Use weak_ptr to safely detect when descriptor is deleted
286-
std::weak_ptr<boost::asio::posix::stream_descriptor> weak_descriptor
287-
= socket_info->descriptor;
285+
// Use weak_ptr to safely detect when handle is deleted
286+
std::weak_ptr<SocketHandle> weak_handle = socket_info->handle;
288287

289288
// Create and store handler in SocketInfo to keep it alive
290289
// Use weak_ptr in capture to avoid circular reference
291-
socket_info->write_handler = std::make_shared<std::function<void
292-
()>>();
293-
std::weak_ptr<std::function<void()>> weak_write_handler =
294-
socket_info->write_handler;
295-
*socket_info->write_handler = [weak_self, sockfd, weak_descriptor,
296-
weak_write_handler]() {
297-
// Check if manager and descriptor are still valid
298-
const auto self = weak_self.lock();
299-
const auto descriptor = weak_descriptor.lock();
300-
if (!self || !descriptor) {
301-
return;
302-
}
303-
304-
descriptor->async_wait(
305-
boost::asio::posix::stream_descriptor::wait_write,
306-
[weak_self, sockfd, weak_descriptor, weak_write_handler
307-
](const boost::system::error_code& ec) {
308-
// If operation was canceled or had an error, don't re-register
309-
if (ec) {
310-
return;
311-
}
312-
313-
if (const auto self = weak_self.lock()) {
314-
self->handle_socket_action(
315-
sockfd, CURL_CSELECT_OUT);
290+
socket_info->write_handler = std::make_shared<std::function<void()>>();
291+
std::weak_ptr<std::function<void()>> weak_write_handler = socket_info->write_handler;
292+
*socket_info->write_handler = [weak_self, sockfd, weak_handle, weak_write_handler]() {
293+
// Check if manager and handle are still valid
294+
const auto self = weak_self.lock();
295+
const auto handle = weak_handle.lock();
296+
if (!self || !handle) {
297+
return;
298+
}
316299

317-
// Always try to re-register for continuous monitoring
318-
// The validity check at the top of write_handler will stop it if needed
319-
if (const auto handler = weak_write_handler.lock()) {
320-
(*handler)(); // Recursive call
321-
}
300+
handle->async_wait(
301+
SocketHandle::wait_write,
302+
[weak_self, sockfd, weak_handle, weak_write_handler](
303+
const boost::system::error_code& ec) {
304+
// If operation was canceled or had an error, don't re-register
305+
if (ec) {
306+
return;
307+
}
308+
309+
if (const auto self = weak_self.lock()) {
310+
self->handle_socket_action(sockfd, CURL_CSELECT_OUT);
311+
312+
// Always try to re-register for continuous monitoring
313+
// The validity check at the top of write_handler will stop it if needed
314+
if (const auto handler = weak_write_handler.lock()) {
315+
(*handler)(); // Recursive call
322316
}
323-
});
324-
};
317+
}
318+
});
319+
};
325320
(*socket_info->write_handler)(); // Initial call
326321
}
327322
}

0 commit comments

Comments
 (0)