@@ -403,33 +403,38 @@ win_tcp_socket_internal::connect(
403403
404404 svc_.work_started ();
405405
406- // Ephemeral bind — must match the socket's family, not the endpoint's
407- sockaddr_storage bind_storage{};
408- socklen_t bind_len;
409- if (family_ == AF_INET6)
406+ // ConnectEx requires the socket to be bound. Skip if already bound
407+ // (e.g. the caller used tcp_socket::bind() before connect).
408+ if (local_endpoint_ == endpoint{})
410409 {
411- sockaddr_in6 sa6{};
412- sa6.sin6_family = AF_INET6;
413- sa6.sin6_port = 0 ;
414- sa6.sin6_addr = in6addr_any;
415- std::memcpy (&bind_storage, &sa6, sizeof (sa6));
416- bind_len = sizeof (sa6);
417- }
418- else
419- {
420- sockaddr_in sa4{};
421- sa4.sin_family = AF_INET;
422- sa4.sin_addr .s_addr = INADDR_ANY;
423- sa4.sin_port = 0 ;
424- std::memcpy (&bind_storage, &sa4, sizeof (sa4));
425- bind_len = sizeof (sa4);
426- }
410+ sockaddr_storage bind_storage{};
411+ socklen_t bind_len;
412+ if (family_ == AF_INET6)
413+ {
414+ sockaddr_in6 sa6{};
415+ sa6.sin6_family = AF_INET6;
416+ sa6.sin6_port = 0 ;
417+ sa6.sin6_addr = in6addr_any;
418+ std::memcpy (&bind_storage, &sa6, sizeof (sa6));
419+ bind_len = sizeof (sa6);
420+ }
421+ else
422+ {
423+ sockaddr_in sa4{};
424+ sa4.sin_family = AF_INET;
425+ sa4.sin_addr .s_addr = INADDR_ANY;
426+ sa4.sin_port = 0 ;
427+ std::memcpy (&bind_storage, &sa4, sizeof (sa4));
428+ bind_len = sizeof (sa4);
429+ }
427430
428- if (::bind (socket_, reinterpret_cast <sockaddr*>(&bind_storage), bind_len) ==
429- SOCKET_ERROR)
430- {
431- svc_.on_completion (&op, ::WSAGetLastError (), 0 );
432- return std::noop_coroutine ();
431+ if (::bind (
432+ socket_, reinterpret_cast <sockaddr*>(&bind_storage),
433+ bind_len) == SOCKET_ERROR)
434+ {
435+ svc_.on_completion (&op, ::WSAGetLastError (), 0 );
436+ return std::noop_coroutine ();
437+ }
433438 }
434439
435440 auto connect_ex = svc_.connect_ex ();
@@ -884,6 +889,28 @@ win_tcp_service::open_socket(
884889 return {};
885890}
886891
892+ inline std::error_code
893+ win_tcp_service::bind_socket (win_tcp_socket_internal& impl, endpoint ep)
894+ {
895+ SOCKET sock = impl.socket_ ;
896+
897+ sockaddr_storage storage{};
898+ socklen_t addrlen = detail::to_sockaddr (ep, storage);
899+ if (::bind (
900+ sock, reinterpret_cast <sockaddr*>(&storage),
901+ static_cast <int >(addrlen)) == SOCKET_ERROR)
902+ return make_err (::WSAGetLastError ());
903+
904+ // Cache local endpoint (resolves ephemeral port)
905+ sockaddr_storage local_storage{};
906+ int local_len = sizeof (local_storage);
907+ if (::getsockname (
908+ sock, reinterpret_cast <sockaddr*>(&local_storage), &local_len) == 0 )
909+ impl.local_endpoint_ = detail::from_sockaddr (local_storage);
910+
911+ return {};
912+ }
913+
887914inline void *
888915win_tcp_service::native_handle () const noexcept
889916{
0 commit comments