pn_socket_t pni_iocp_begin_connect(iocp_t *iocp, pn_socket_t sock, struct addrinfo *addr, pn_error_t *error) { // addr lives for the duration of the async connect. Caller has passed ownership here. // See connect_result_finalize(). // Use of Windows-specific ConnectEx() requires our socket to be "loosely" pre-bound: sockaddr_storage sa; memset(&sa, 0, sizeof(sa)); sa.ss_family = addr->ai_family; if (bind(sock, (SOCKADDR *) &sa, addr->ai_addrlen)) { pni_win32_error(error, "begin async connection", WSAGetLastError()); if (iocp->iocp_trace) iocp_log("%s\n", pn_error_text(error)); closesocket(sock); freeaddrinfo(addr); return INVALID_SOCKET; } iocpdesc_t *iocpd = pni_iocpdesc_create(iocp, sock, false); bind_to_completion_port(iocpd); LPFN_CONNECTEX fn_connect_ex = lookup_connect_ex(iocpd->socket); connect_result_t *result = connect_result(iocpd, addr); DWORD unused; bool success = fn_connect_ex(iocpd->socket, result->addrinfo->ai_addr, result->addrinfo->ai_addrlen, NULL, 0, &unused, (LPOVERLAPPED) result); if (!success && WSAGetLastError() != ERROR_IO_PENDING) { pni_win32_error(error, "ConnectEx failure", WSAGetLastError()); pn_free(result); iocpd->write_closed = true; iocpd->read_closed = true; pni_iocp_begin_close(iocpd); sock = INVALID_SOCKET; if (iocp->iocp_trace) iocp_log("%s\n", pn_error_text(error)); } else { iocpd->ops_in_progress++; } return sock; }
Stream::ConnectEx Stream::connect_ex () const { return (lookup_connect_ex(handle())); }