libzypp 17.38.15
curl_dl.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
42
43#include <curl/curl.h>
44
45#include <dlfcn.h>
46#include <pthread.h>
47#include <stdarg.h>
48#include <stdio.h>
49#include <stdlib.h>
50
51/* The SONAME to load. Distributions which ship a differently named
52 * libcurl (Debian's libcurl-gnutls.so.4) override it from cmake. */
53#ifndef ZYPP_CURL_SONAME
54#define ZYPP_CURL_SONAME "libcurl.so.4"
55#endif
56
57/* curl.h installs call-site typecheck macros for these */
58#undef curl_easy_setopt
59#undef curl_easy_getinfo
60#undef curl_multi_setopt
61#undef curl_share_setopt
62
63namespace {
64
65void * curl_dl_handle = nullptr;
66char curl_dl_error[512];
67pthread_once_t curl_dl_once = PTHREAD_ONCE_INIT;
68
69extern "C" void curl_dl_open()
70{
71 curl_dl_handle = dlopen( ZYPP_CURL_SONAME, RTLD_LAZY | RTLD_LOCAL );
72 if ( !curl_dl_handle )
73 {
74 // dlerror() is thread local and consumed by reading it, so keep the
75 // message here: a thread which only waited on pthread_once would
76 // otherwise have nothing to report.
77 const char * err = dlerror();
78 snprintf( curl_dl_error, sizeof(curl_dl_error), "%s", err ? err : "cannot load library" );
79 }
80}
81
82/* A libcurl that cannot be loaded, or that lacks a symbol libzypp uses,
83 * is fatal - exactly as it was while libcurl was a DT_NEEDED entry and
84 * the dynamic loader refused to start the process. Reporting it through
85 * a return value instead would push a null check into every call site
86 * (curl_version_info() and curl_easy_init() are dereferenced directly
87 * in several places), and a missed one turns a clear diagnostic into a
88 * SIGSEGV. */
89void * curl_dl_sym( const char * name )
90{
91 pthread_once( &curl_dl_once, curl_dl_open );
92 if ( !curl_dl_handle )
93 {
94 fprintf( stderr, "libzypp: cannot load %s: %s\n", ZYPP_CURL_SONAME, curl_dl_error );
95 abort();
96 }
97 void * sym = dlsym( curl_dl_handle, name );
98 if ( !sym )
99 {
100 const char * err = dlerror();
101 fprintf( stderr, "libzypp: %s lacks %s: %s\n",
102 ZYPP_CURL_SONAME, name, err ? err : "symbol not found" );
103 abort();
104 }
105 return sym;
106}
107
108} // namespace
109
110/* These definitions must never be exported: an exported curl_easy_setopt
111 * would interpose libcurl's own calls to it. -fvisibility=hidden already
112 * does that, but say it here so it does not depend on a build option. */
113#define CURL_DL_HIDDEN __attribute__((visibility("hidden")))
114
115/* Wrapper for a non-variadic function returning a value. */
116#define CURL_DL_FN( ret, name, proto, args ) \
117CURL_DL_HIDDEN ret name proto \
118{ \
119 static ret (*fn) proto; \
120 if ( !fn ) \
121 *(void **)&fn = curl_dl_sym( #name ); \
122 return fn args; \
123}
124
125/* Wrapper for a non-variadic function returning void. */
126#define CURL_DL_FN_VOID( name, proto, args ) \
127CURL_DL_HIDDEN void name proto \
128{ \
129 static void (*fn) proto; \
130 if ( !fn ) \
131 *(void **)&fn = curl_dl_sym( #name ); \
132 fn args; \
133}
134
135CURL_DL_FN( CURLcode, curl_global_init, (long flags), (flags) )
136
137CURL_DL_FN( CURL *, curl_easy_init, (void), () )
138CURL_DL_FN_VOID( curl_easy_cleanup, (CURL *handle), (handle) )
139CURL_DL_FN_VOID( curl_easy_reset, (CURL *handle), (handle) )
140CURL_DL_FN( const char *, curl_easy_strerror, (CURLcode code), (code) )
141
142CURL_DL_FN_VOID( curl_free, (void *p), (p) )
143CURL_DL_FN( char *, curl_unescape, (const char *str, int length), (str, length) )
144CURL_DL_FN( curl_version_info_data *, curl_version_info, (CURLversion age), (age) )
145
146CURL_DL_FN( struct curl_slist *, curl_slist_append, (struct curl_slist *list, const char *str), (list, str) )
147CURL_DL_FN_VOID( curl_slist_free_all, (struct curl_slist *list), (list) )
148
149CURL_DL_FN( CURLM *, curl_multi_init, (void), () )
150CURL_DL_FN( CURLMcode, curl_multi_cleanup, (CURLM *multi), (multi) )
151CURL_DL_FN( CURLMcode, curl_multi_add_handle, (CURLM *multi, CURL *handle), (multi, handle) )
152CURL_DL_FN( CURLMcode, curl_multi_remove_handle, (CURLM *multi, CURL *handle), (multi, handle) )
153CURL_DL_FN( CURLMsg *, curl_multi_info_read, (CURLM *multi, int *msgs_in_queue), (multi, msgs_in_queue) )
155CURL_DL_FN( const char *, curl_multi_strerror, (CURLMcode code), (code) )
156
157/* The variadic trio. Forward through a variadic-typed pointer so the
158 * call uses the variadic ABI (%al on x86-64). */
159
160CURL_DL_HIDDEN CURLcode curl_easy_getinfo( CURL *handle, CURLINFO info, ... )
161{
162 static CURLcode (*fn)( CURL *, CURLINFO, ... );
163 va_list ap;
164 void *arg;
165 if ( !fn )
166 *(void **)&fn = curl_dl_sym( "curl_easy_getinfo" );
168 arg = va_arg( ap, void * ); /* always a pointer out-arg */
170 return fn( handle, info, arg );
171}
172
173CURL_DL_HIDDEN CURLcode curl_easy_setopt( CURL *handle, CURLoption option, ... )
174{
175 static CURLcode (*fn)( CURL *, CURLoption, ... );
176 va_list ap;
177 CURLcode ret;
178 if ( !fn )
179 *(void **)&fn = curl_dl_sym( "curl_easy_setopt" );
180 va_start( ap, option );
181 if ( option < CURLOPTTYPE_OBJECTPOINT ) /* long */
182 ret = fn( handle, option, va_arg( ap, long ) );
183 else if ( option < CURLOPTTYPE_OFF_T ) /* object/function pointer */
184 ret = fn( handle, option, va_arg( ap, void * ) );
185 else if ( option < CURLOPTTYPE_BLOB ) /* curl_off_t */
186 ret = fn( handle, option, va_arg( ap, curl_off_t ) );
187 else /* blob pointer */
188 ret = fn( handle, option, va_arg( ap, void * ) );
189 va_end( ap );
190 return ret;
191}
192
193CURL_DL_HIDDEN CURLMcode curl_multi_setopt( CURLM *multi, CURLMoption option, ... )
194{
195 static CURLMcode (*fn)( CURLM *, CURLMoption, ... );
196 va_list ap;
197 CURLMcode ret;
198 if ( !fn )
199 *(void **)&fn = curl_dl_sym( "curl_multi_setopt" );
200 va_start( ap, option );
201 if ( option < CURLOPTTYPE_OBJECTPOINT )
202 ret = fn( multi, option, va_arg( ap, long ) );
203 else if ( option < CURLOPTTYPE_OFF_T )
204 ret = fn( multi, option, va_arg( ap, void * ) );
205 else if ( option < CURLOPTTYPE_BLOB )
206 ret = fn( multi, option, va_arg( ap, curl_off_t ) );
207 else
208 ret = fn( multi, option, va_arg( ap, void * ) );
209 va_end( ap );
210 return ret;
211}
va_start(ap, info)
CURL handle void p CURLversion age
Definition curl_dl.cc:144
#define CURL_DL_FN(ret, name, proto, args)
Definition curl_dl.cc:116
#define ZYPP_CURL_SONAME
Definition curl_dl.cc:54
CURL handle void p CURLversion age struct curl_slist list curl_multi_cleanup
Definition curl_dl.cc:150
CURL handle void p CURLversion age struct curl_slist list CURLM multi curl_multi_remove_handle
Definition curl_dl.cc:152
CURL handle void p CURLversion age struct curl_slist list CURLM multi CURLM CURL handle CURLM curl_socket_t int ev_bitmask
Definition curl_dl.cc:154
CURL handle void p CURLversion age struct curl_slist list CURLM multi CURLM CURL handle curl_multi_socket_action
Definition curl_dl.cc:154
CURL_DL_HIDDEN CURLMcode curl_multi_setopt(CURLM *multi, CURLMoption option,...)
Definition curl_dl.cc:193
CURL handle void p CURLversion age struct curl_slist list CURLM multi CURLM CURL handle CURLM curl_socket_t int int running_handles CURLINFO va_list ap
Definition curl_dl.cc:163
CURL handle void p curl_version_info
Definition curl_dl.cc:144
CURL handle void * p
Definition curl_dl.cc:142
curl_easy_init
Definition curl_dl.cc:137
CURL * handle
Definition curl_dl.cc:139
CURL_DL_HIDDEN CURLcode curl_easy_setopt(CURL *handle, CURLoption option,...)
Definition curl_dl.cc:173
CURL handle void p CURLversion age struct curl_slist list CURLM multi CURLM CURL handle CURLM curl_socket_t int int running_handles CURLINFO info
Definition curl_dl.cc:160
va_end(ap)
CURL handle void p CURLversion age struct curl_slist list CURLM * multi
Definition curl_dl.cc:150
void * arg
Definition curl_dl.cc:164
#define CURL_DL_FN_VOID(name, proto, args)
Definition curl_dl.cc:126
CURL handle void p CURLversion age struct curl_slist list CURLM multi CURLM CURL handle CURLM curl_socket_t s
Definition curl_dl.cc:154
CURL handle void p CURLversion age struct curl_slist * list
Definition curl_dl.cc:147
CURL handle void p CURLversion age struct curl_slist list CURLM multi CURLM CURL handle CURLM curl_socket_t int int * running_handles
Definition curl_dl.cc:154
return fn(handle, info, arg)
#define CURL_DL_HIDDEN
Definition curl_dl.cc:113
String related utilities and Regular expression matching.