Fix multihome server handling and backport cmake support

Related: rhbz#1130328
This commit is contained in:
Tomas Korbar 2023-01-31 15:37:58 +01:00
parent deac8ac8d6
commit e9db6f5bf2
3 changed files with 1423 additions and 28 deletions

1274
libserf-1.3.9-cmake.patch Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
commit 9f03432308609644d633ed79aaa17bcf19b6060e
Author: Tomas Korbar <tkorbar@redhat.com>
Date: Fri Jan 27 14:01:11 2023 +0100
Fix connection to multihome servers
When libserfs connection is rejected, epoll socket receives EPOLLHUP
and its handling has to be suspended if the connection was never
set up, so we can check another address if the target server
is located on more ip addresses.
diff --git a/outgoing.c b/outgoing.c
index 5f5f6b5..313b6c9 100644
--- a/outgoing.c
+++ b/outgoing.c
@@ -153,6 +153,11 @@ apr_status_t serf__conn_update_pollset(serf_connection_t *conn)
/* Now put it back in with the correct read/write values. */
desc.reqevents = APR_POLLHUP | APR_POLLERR;
+
+ if (conn->wait_for_connect) {
+ desc.reqevents |= APR_POLLOUT;
+ }
+
if (conn->requests &&
conn->state != SERF_CONN_INIT) {
/* If there are any outstanding events, then we want to read. */
@@ -391,6 +396,9 @@ apr_status_t serf__open_connections(serf_context_t *ctx)
if (status != APR_SUCCESS) {
if (!APR_STATUS_IS_EINPROGRESS(status))
return status;
+
+ /* Keep track of when we really connect */
+ conn->wait_for_connect = true;
}
/* Flag our pollset as dirty now that we have a new socket. */
@@ -1253,7 +1261,7 @@ apr_status_t serf__process_connection(serf_connection_t *conn,
* the like sitting on the connection, we give the app a chance to read
* it before we trigger a reset condition.
*/
- if ((events & APR_POLLIN) != 0) {
+ if ((events & APR_POLLIN) != 0 && !conn->wait_for_connect) {
if ((status = read_from_connection(conn)) != APR_SUCCESS)
return status;
@@ -1264,7 +1272,13 @@ apr_status_t serf__process_connection(serf_connection_t *conn,
return APR_SUCCESS;
}
}
- if ((events & APR_POLLHUP) != 0) {
+ /*
+ * Since new connection which is refused also creates HUP event,
+ * we need to suppress its handling until we are sure that connection
+ * was established, so we can eventually handle denial of connection
+ * by trying different server
+ */
+ if ((events & APR_POLLHUP) != 0 && !conn->wait_for_connect) {
/* The connection got reset by the server. On Windows this can happen
when all data is read, so just cleanup the connection and open
a new one.
@@ -1292,11 +1306,16 @@ apr_status_t serf__process_connection(serf_connection_t *conn,
{
apr_os_sock_t osskt;
if (!apr_os_sock_get(&osskt, conn->skt)) {
- int error;
+ int error = 0;
+ int rv;
apr_socklen_t l = sizeof(error);
- if (!getsockopt(osskt, SOL_SOCKET, SO_ERROR, (char*)&error,
- &l)) {
+ rv = getsockopt(osskt, SOL_SOCKET, SO_ERROR, (char*)&error, &l);
+ /* The error is placed in errno on Solaris for SO_ERROR */
+ if(rv)
+ error = errno;
+
+ if (error) {
status = APR_FROM_OS_ERROR(error);
/* Handle fallback for multi-homed servers.
@@ -1310,7 +1329,8 @@ apr_status_t serf__process_connection(serf_connection_t *conn,
&& conn->address->next != NULL
&& (APR_STATUS_IS_ECONNREFUSED(status)
|| APR_STATUS_IS_TIMEUP(status)
- || APR_STATUS_IS_ENETUNREACH(status))) {
+ || APR_STATUS_IS_ENETUNREACH(status)
+ || APR_STATUS_IS_EHOSTUNREACH(status))) {
conn->address = conn->address->next;
return reset_connection(conn, 1);
@@ -1324,6 +1344,8 @@ apr_status_t serf__process_connection(serf_connection_t *conn,
return APR_EGENERAL;
}
if ((events & APR_POLLOUT) != 0) {
+ if (conn->wait_for_connect)
+ conn->wait_for_connect = false;
if ((status = write_to_connection(conn)) != APR_SUCCESS)
return status;
}
@@ -1358,6 +1380,7 @@ serf_connection_t *serf_connection_create(
conn->baton.u.conn = conn;
conn->hit_eof = 0;
conn->state = SERF_CONN_INIT;
+ conn->wait_for_connect = false;
conn->latency = -1; /* unknown */
/* Create a subpool for our connection. */
diff --git a/serf_private.h b/serf_private.h
index f906379..b2da7df 100644
--- a/serf_private.h
+++ b/serf_private.h
@@ -21,6 +21,8 @@
#ifndef _SERF_PRIVATE_H_
#define _SERF_PRIVATE_H_
+#include <stdbool.h>
+
/* ### what the hell? why does the APR interface have a "size" ??
### the implication is that, if we bust this limit, we'd need to
### stop, rebuild a pollset, and repopulate it. what suckage. */
@@ -284,6 +286,10 @@ struct serf_connection_t {
/* Calculated connection latency. Negative value if latency is unknown. */
apr_interval_time_t latency;
+ /* Wait for connect: connect() returned APR_EINPROGRESS.
+ Socket not usable yet */
+ bool wait_for_connect;
+
/* Needs to read first before we can write again. */
int stop_writing;
};

View File

@ -1,25 +1,19 @@
%if ! 0%{?fedora}%{?rhel} || 0%{?fedora} > 28 || 0%{?rhel} > 7
%global scons scons-3
%global scons_pkg python3-scons
%else
%global scons scons-2
%global scons_pkg python2-scons
%endif
Name: libserf
Version: 1.3.9
Release: 25%{?dist}
Release: 26%{?dist}
Summary: High-Performance Asynchronous HTTP Client Library
License: ASL 2.0
URL: http://serf.apache.org/
Source0: https://archive.apache.org/dist/serf/serf-%{version}.tar.bz2
BuildRequires: gcc, %{scons_pkg}, pkgconfig
BuildRequires: gcc, pkgconfig
BuildRequires: apr-devel, apr-util-devel, krb5-devel, openssl-devel
BuildRequires: zlib-devel
BuildRequires: zlib-devel, cmake
Patch0: %{name}-norpath.patch
Patch1: %{name}-python3.patch
Patch2: %{name}-1.3.9-bio-ctrl.patch
Patch3: %{name}-1.3.9-errgetfunc.patch
Patch4: %{name}-1.3.9-multihome.patch
Patch5: %{name}-1.3.9-cmake.patch
%description
The serf library is a C-based HTTP client library built upon the Apache
@ -39,29 +33,20 @@ developing applications that use %{name}.
%prep
%autosetup -n serf-%{version} -p1
# Shared library versioning support in scons is worse than awful...
# minimally, here fix the soname to match serf-1.2.x. Minor version
# handling should be fixed too; really requires better upstream support:
# http://scons.tigris.org/issues/show_bug.cgi?id=2869
sed -i '/SHLIBVERSION/s/MAJOR/0/' SConstruct
%build
%{scons} \
CFLAGS="%{optflags}" \
LINKFLAGS="%{__global_ldflags}" \
PREFIX=%{_prefix} \
LIBDIR=%{_libdir} \
GSSAPI=%{_prefix} \
%{?_smp_mflags}
%cmake -DCMAKE_INSTALL_LIBDIR=%{_libdir}
%cmake_build
%install
%{scons} install --install-sandbox=%{buildroot}
%cmake_install
find %{buildroot}%{_libdir} -type f -name '*.*a' -delete -print
mkdir -p %{buildroot}%{_libdir}/pkgconfig
mv %{buildroot}%{_datadir}/pkgconfig/serf.pc %{buildroot}%{_libdir}/pkgconfig/serf.pc
rm -rf %{buildroot}%{_datadir}
%check
export LD_LIBRARY_PATH=%{buildroot}%{_libdir}
%{scons} %{?_smp_mflags} check || true
%ctest || true
%ldconfig_scriptlets
@ -76,6 +61,10 @@ export LD_LIBRARY_PATH=%{buildroot}%{_libdir}
%{_libdir}/pkgconfig/serf*.pc
%changelog
* Tue Jan 31 2023 Tomas Korbar <tkorbar@redhat.com> - 1.3.9-26
- Fix multihome server handling and backport cmake support
- Related: rhbz#1130328
* Thu Jan 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 1.3.9-25
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild