cURL / Mailing Lists / curl-library / Single Mail

curl-library

living without global variables

From: Bryan Henderson <bryanh_at_giraffe-data.com>
Date: Sun, 27 Nov 2005 22:45:39 +0100

I have written the code we discussed a while back to make it easier to
write a program in which libcurl doesn't mess with global state.

A reminder of the strategy: A libcurl user uses one of two paradigms:

  - traditional and easy: Call curl_global_init() before using libcurl
    and curl_global_cleanup() afterward. Make sure nothing else in your
    program is using libcurl or OpenSSL, Winsock, etc. Create session
    objects with curl_easy_init().

  - private client object: Call (new) curl_client_init() to create a client
    object. Create session objects with (new) curl_easy_init_c() with
    the client handle as argument. By default, nothing that requires
    libcurl to mess with global state works. If user wants it to work,
    he initializes the particular global facility in his own code and
    calls e.g. curl_use_global_openssl() to give libcurl permission to
    use it with a particular client object.

There is still the middle ground where you call curl_global_init()
with flags that cause it to omit certain initialization, but I see
that as useful only for backward compatibility. A user would be
better off using a private client object if he wants to manage global
state explicitly.

The goal of the private client object paradigm is twofold:

  - Put global state manipulation in global code, where it is less
    covert and easier to manage for the use of multiple parties
    (e.g. where two modules that use libcurl and one that uses OpenSSL
    independently are all linked into the same program).

  - Allow for the global state to be removed completely in the future,
    assuming OpenSSL, etc. get fixed to be modular. (And I intend to
    work on at least OpenSSL in this respect). The libcurl private
    client object is where the openssl private client handle will be
    kept.

I gave up on making the memory allocator stuff non-global. It is too
much work and I think too rare that someone actually sets one of those
global variables. So all I did for that is create a new function
curl_global_set_mem() to set those for a program that avoids
curl_global_init().

The implementation is pretty simple:

  - A client handle (type CURLC) is analogous to an easy or multi
    handle. There is a new client.c, client.h, and libcurl-client.3
    to implement it

  - A field added to struct SessionHandle: handle of client to which
    session belongs.

  - curl_global_init() creates a client handle and puts its handle in
    a global variable. This is the "global client."

  - curl_easy_init() makes the session belong to the global client.

  - (new) curl_easy_init_c() is same as curl_easy_init() but sets the
    session handle to the private client handle indicated by its
    argument instead of to the global client.

  - The client descriptor has a flag for each of the 5 global
    facilities: Windows socket library, Amiga socket library, OpenSSL,
    GNU TLS, and CHARSET environment variable. There is a new external
    function to set each, and an internal one to query it.

  - At various places (6 of them) where one of the global facilities
    is necessary, code check whether it's OK to use it and fails
    whatever it's doing if not. In the SSL cases, it does the same as
    it would if there were no SSL library bound: continues the
    operation, but without SSL enabled.

I have attached the 3 new files and a patch for the rest. I also
included a diff file that is the same as the patch, but with mere
indentation changes (because something moved inside an "if") ignored
so you can see better what changed.

The patch includes the man file changes that explain in greater detail
than this email the whole global state issue.

-- 
Bryan Henderson                                    Phone 408-621-2000
San Jose, California





  • application/octet-stream attachment: client.h
Received on 2005-11-27