? docs/libcurl/libcurl-client.3
? docs/libcurl/curl_client_init.3
? docs/libcurl/curl_client_cleanup.3
? docs/libcurl/curl_easy_init_c.3
? include/curl/client.h
? lib/client.c
? lib/clientif.h
Index: curl-config.in
===================================================================
RCS file: /cvsroot/curl/curl/curl-config.in,v
retrieving revision 1.23
diff --unified -r1.23 curl-config.in
--- curl-config.in	4 Sep 2005 18:15:24 -0000	1.23
+++ curl-config.in	4 Dec 2005 03:17:18 -0000
@@ -60,9 +60,11 @@
     --feature|--features)
 	if test "@USE_SSLEAY@" = "1"; then
           echo "SSL"
+          echo "OpenSSL"
           NTLM=1 # OpenSSL implies NTLM
         elif test -n "@USE_GNUTLS@"; then
           echo "SSL"
+          echo "GnuTLS"
         fi
 	if test "@KRB4_ENABLED@" = "1"; then
           echo "KRB4"
Index: docs/libcurl/libcurl.3
===================================================================
RCS file: /cvsroot/curl/curl/docs/libcurl/libcurl.3,v
retrieving revision 1.11
diff --unified -r1.11 libcurl.3
--- docs/libcurl/libcurl.3	21 Jun 2004 08:28:10 -0000	1.11
+++ docs/libcurl/libcurl.3	4 Dec 2005 03:17:19 -0000
@@ -13,10 +13,12 @@
 There are more than a twenty custom bindings available that bring libcurl
 access to your favourite language. Look elsewhere for documentation on those.
 
-All applications that use libcurl should call \fIcurl_global_init(3)\fP
-exactly once before any libcurl function can be used. After all usage of
-libcurl is complete, it \fBmust\fP call \fIcurl_global_cleanup(3)\fP. In
-between those two calls, you can use libcurl as described below.
+You must generally set up some global environment before you can use
+any libcurl functions.  The easiest way to do that is to call
+\fIcurl_global_init()\fP at the beginning of your program and
+\fIcurl_global_cleanup()\fP at the end.  But see the ENVIRONMENT
+section below for details on what this does and why you might not want
+to do it.
 
 To transfer files, you always set up an "easy handle" using
 \fIcurl_easy_init(3)\fP, but when you want the file(s) transferred you have
@@ -55,6 +57,94 @@
 frees a whole curl_slist
 .RE
 
+.SH "ENVIRONMENT"
+
+Depending on your environment, there is some setup of your program
+environment that you have to do before using any libcurl function.
+
+You can do all of that by calling \fIcurl_global_init(3)\fP before
+calling any other libcurl functions.  However, because the setup is
+global for the program, it could affect parts of the program other
+than the part you're writing, and even unrelated to libcurl, so read
+on to be sure you do the setup that is right for your program.
+
+The setup that has to happen is:
+
+.IN 4
+
+On a Windows system, you must initialize the Windows socket facility
+by calling the Windows function \fIWSAStartup()\fP.
+
+On an Amiga system, you must initialize the AmigaOS socket facility
+by calling opening the AmigaOS library "bsdsocket.library".
+
+If you are using IDNA, set the CHARSET environment variable appropriately.
+Typically, that means you set its value to "cpNNN", where NNN is the
+return value of \fIGetACP()\fP.
+
+If you are using the OpenSSL library (i.e. libcurl was built to use
+the OpenSSL libary and you plan to make secure connections that
+exploit it), you must set up global state for that library by calling
+its \fISSL_load_error_strings()\fP and SSL_library_init() function
+and, if your version of OpenSSL has it,
+\fIENGINE_load_builtin_engines()\fP.
+
+If you are using the GNU Transport Layer Security Library
+(i.e. libcurl was built to use the gtls library and you plan to make
+secure connections that exploit it), you must set up global state for
+that library by calling its \fIgnutls_global_init()\fP function.  This sets
+up defaults, and if you want libcurl to use non-default global
+options, you must also set up those before using an libcurl functions.
+
+.IN -4
+
+\fIcurl_global_init(3)\fP does all these things.  But bear in mind that
+these settings are global to your program and will affect not only libcurl,
+but anything else in your program that is using, for example, Windows
+sockets or GNU TLS.  In particular, if two different parts of your program
+are using libcurl, a single \fIcurl_global_init(3)\fP affects both.
+
+Pay particular attention if you are distributing a subroutine library that
+uses libcurl -- the user of your library probably won't appreciate you
+modifying global things under the covers.
+
+You may also want to undo the setup after you have finished using
+libcurl.  To do this:
+
+  call WSACleanup()
+  close the bsdsocket.library
+  restore the CHARSET environment variable
+  call ERR_free_strings()
+  call EVP_cleanup()
+  call ENGINE_cleanup()
+  call gnutls_global_cleanup()
+
+\fIcurl_global_cleanup(3)\fP will do all this for you.  But remember
+that this environment is global to your program.  Anything else in
+your program that is currently using, for example, Windows sockets or
+GNU TLS will break if you do a \fIcurl_global_cleanup(3)\fP.
+
+Because this environment is not specific to libcurl, it may be cleaner
+in your program to manage it explicitly with e.g. \fIWSAStartup()\fPs
+and \fIWSACleanup()\fP than with \fIcurl_global_init(3)\fP and
+\fIcurl_global_cleanup(3)\fP.
+
+Also note that \fIcurl_global_init(3)\fP has flags to allow you to do only
+particular parts of the global setup.
+
+There is another way to use libcurl that more cleanly separates the global
+setup from libcurl, and in the future will provide a way to eliminate the
+need for some of the global setup:  create a libcurl "client" and create
+your libcurl easy handles with \fIcurl_easy_init_c()\fP instead of with
+\fIcurl_easy_init()\fP.  See the \fIlibcurl-client(3)\fP man page.
+
+One final consideration: \fIcurl_easy_init(3)\fP has a failsafe built
+into it that calls \fIcurl_global_init(3)\fP, with default options, if
+you haven't previously called it.  But it's better for your code to
+call it explicitly, so it is more obvious that program global
+environment is being manipulated.
+
+
 .SH "LINKING WITH LIBCURL"
 On unix-like machines, there's a tool named curl-config that gets installed
 with the rest of the curl stuff when 'make install' is performed.
Index: include/curl/curl.h
===================================================================
RCS file: /cvsroot/curl/curl/include/curl/curl.h,v
retrieving revision 1.287
diff --unified -r1.287 curl.h
--- include/curl/curl.h	28 Nov 2005 23:06:00 -0000	1.287
+++ include/curl/curl.h	4 Dec 2005 03:17:20 -0000
@@ -316,6 +316,7 @@
   CURLE_TFTP_UNKNOWNID,          /* 72 - Unknown transfer ID */
   CURLE_TFTP_EXISTS,             /* 73 - File already exists */
   CURLE_TFTP_NOSUCHUSER,         /* 74 - No such user */
+  CURLE_NO_SOCKETS,              /* 75 - User didn't provide socket facility */
   CURL_LAST /* never use! */
 } CURLcode;
 
@@ -1198,6 +1199,12 @@
   struct curl_slist *next;
 };
 
+CURL_EXTERN void curl_global_set_mem(curl_malloc_callback m,
+                                     curl_free_callback f,
+                                     curl_realloc_callback r,
+                                     curl_strdup_callback s,
+                                     curl_calloc_callback c);
+    
 /*
  * NAME curl_slist_append()
  *
Index: include/curl/easy.h
===================================================================
RCS file: /cvsroot/curl/curl/include/curl/easy.h,v
retrieving revision 1.13
diff --unified -r1.13 easy.h
--- include/curl/easy.h	9 Nov 2004 14:02:58 -0000	1.13
+++ include/curl/easy.h	4 Dec 2005 03:17:20 -0000
@@ -22,11 +22,15 @@
  *
  * $Id: easy.h,v 1.13 2004/11/09 14:02:58 giva Exp $
  ***************************************************************************/
+
+#include "client.h"
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
 CURL_EXTERN CURL *curl_easy_init(void);
+CURL_EXTERN CURL *curl_easy_init_c(CURLC *curlc);
 CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
 CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
 CURL_EXTERN void curl_easy_cleanup(CURL *curl);
Index: lib/Makefile.am
===================================================================
RCS file: /cvsroot/curl/curl/lib/Makefile.inc,v
retrieving revision 1.9
diff --unified -r1.9 Makefile.inc
--- lib/Makefile.inc	11 Nov 2005 22:04:11 -0000	1.9
+++ lib/Makefile.inc	4 Dec 2005 03:17:20 -0000
@@ -8,7 +8,7 @@
   content_encoding.c share.c http_digest.c md5.c http_negotiate.c	\
   http_ntlm.c inet_pton.c strtoofft.c strerror.c hostares.c hostasyn.c	\
   hostip4.c hostip6.c hostsyn.c hostthre.c inet_ntop.c parsedate.c	\
-  select.c gtls.c sslgen.c tftp.c
+  select.c gtls.c sslgen.c tftp.c client.c
 
 HHEADERS = arpa_telnet.h netrc.h file.h timeval.h base64.h hostip.h	\
   progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h	\
@@ -18,6 +18,6 @@
   share.h md5.h http_digest.h http_negotiate.h http_ntlm.h ca-bundle.h	\
   inet_pton.h strtoofft.h strerror.h inet_ntop.h curlx.h memory.h	\
   setup.h transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h   \
-  gtls.h tftp.h sockaddr.h
+  gtls.h tftp.h sockaddr.h client.h
 
 
Index: lib/easy.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/easy.c,v
retrieving revision 1.73
diff --unified -r1.73 easy.c
--- lib/easy.c	17 Jul 2005 12:44:11 -0000	1.73
+++ lib/easy.c	4 Dec 2005 03:17:21 -0000
@@ -169,6 +169,12 @@
 static unsigned int  initialized;
 static long          init_flags;
 
+/* This is the Curl Client that a user of curl_global_init() uses.  A
+   non-curl_global_init() user, in contrast, creates his own
+   Curl Client and passes its handle to any libcurl function that
+   needs one.  */
+CURLC * curl_global_client;
+
 /*
  * If a memory-using function (like curl_getenv) is used before
  * curl_global_init() is called, we need to have these pointers set already.
@@ -193,12 +199,16 @@
   if (initialized)
     return CURLE_OK;
 
-  /* Setup the default memory functions here (again) */
-  Curl_cmalloc = (curl_malloc_callback)malloc;
-  Curl_cfree = (curl_free_callback)free;
-  Curl_crealloc = (curl_realloc_callback)realloc;
-  Curl_cstrdup = (curl_strdup_callback)strdup;
-  Curl_ccalloc = (curl_calloc_callback)calloc;
+  /* Where we didn't initialize some global facility because the user
+     told us not to, we assume that he initialized it.  So tell the client
+     to go ahead and use all the global facilities.
+  */
+  curl_global_client = curl_client_init(
+      CURL_CLIENT_GLOBAL_OPENSSL |
+      CURL_CLIENT_GLOBAL_GNUTLS |
+      CURL_CLIENT_GLOBAL_WINSOCK |
+      CURL_CLIENT_GLOBAL_AMIGASOCK |
+      CURL_CLIENT_GLOBAL_CHARSET);
 
   if (flags & CURL_GLOBAL_SSL)
     if (!Curl_ssl_init())
@@ -243,13 +253,8 @@
 
   /* Call the actual init function first */
   code = curl_global_init(flags);
-  if (code == CURLE_OK) {
-    Curl_cmalloc = m;
-    Curl_cfree = f;
-    Curl_cstrdup = s;
-    Curl_crealloc = r;
-    Curl_ccalloc = c;
-  }
+  if (code == CURLE_OK)
+    curl_global_set_mem(m, f, r, s, c);
 
   return code;
 }
@@ -265,6 +270,10 @@
 
   Curl_global_host_cache_dtor();
 
+  curl_client_cleanup(curl_global_client);
+
+  curl_global_client = NULL;
+
   if (init_flags & CURL_GLOBAL_SSL)
     Curl_ssl_cleanup();
 
@@ -279,6 +288,17 @@
   init_flags  = 0;
 }
 
+void curl_global_set_mem(curl_malloc_callback m,
+                         curl_free_callback f, curl_realloc_callback r,
+                         curl_strdup_callback s, curl_calloc_callback c)
+{
+  Curl_cmalloc = m;
+  Curl_cfree = f;
+  Curl_cstrdup = s;
+  Curl_crealloc = r;
+  Curl_ccalloc = c;
+}
+
 /*
  * curl_easy_init() is the external interface to alloc, setup and init an
  * easy handle that is returned. If anything goes wrong, NULL is returned.
@@ -297,7 +317,20 @@
   }
 
   /* We use curl_open() with undefined URL so far */
-  res = Curl_open(&data);
+  res = Curl_open(&data, curl_global_client);
+  if(res != CURLE_OK)
+    return NULL;
+
+  return data;
+}
+
+CURL *curl_easy_init_c(CURLC *curlc)
+{
+  CURLcode res;
+  struct SessionHandle *data;
+
+  /* We use curl_open() with undefined URL so far */
+  res = Curl_open(&data, curlc);
   if(res != CURLE_OK)
     return NULL;
 
Index: lib/sslgen.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/sslgen.c,v
retrieving revision 1.6
diff --unified -r1.6 sslgen.c
--- lib/sslgen.c	11 Aug 2005 21:41:11 -0000	1.6
+++ lib/sslgen.c	4 Dec 2005 03:17:21 -0000
@@ -56,6 +56,7 @@
 #include "strequal.h"
 #include "url.h"
 #include "memory.h"
+#include "easyif.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -196,14 +197,24 @@
 Curl_ssl_connect(struct connectdata *conn, int sockindex)
 {
 #ifdef USE_SSL
-  /* mark this is being ssl enabled from here on. */
-  conn->ssl[sockindex].use = TRUE;
+  /* We don't know how to use any SSL library without involving the library's
+     global state, so if the client hasn't set that up (or just won't
+     allow us to use it), we don't enable the connection for SSL.  But
+     otherwise we do (conn->ssl[sockindex].use). */
 
 #ifdef USE_SSLEAY
-  return Curl_ossl_connect(conn, sockindex);
+  if(Curl_client_global_openssl_ok(conn->data->client)) {
+    conn->ssl[sockindex].use = TRUE;
+    return Curl_ossl_connect(conn, sockindex);
+  } else
+    return CURLE_OK;
 #else
 #ifdef USE_GNUTLS
-  return Curl_gtls_connect(conn, sockindex);
+  if(Curl_client_global_gnutls_ok(conn->data->client)) {
+    conn->ssl[sockindex].use = TRUE;
+    return Curl_gtls_connect(conn, sockindex);
+  } else
+    return CURLE_OK
 #endif /* USE_GNUTLS */
 #endif /* USE_SSLEAY */
 
Index: lib/ssluse.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/ssluse.c,v
retrieving revision 1.136
diff --unified -r1.136 ssluse.c
--- lib/ssluse.c	13 Nov 2005 23:53:14 -0000	1.136
+++ lib/ssluse.c	4 Dec 2005 03:17:22 -0000
@@ -53,6 +53,7 @@
 #include "strequal.h"
 #include "select.h"
 #include "sslgen.h"
+#include "clientif.h"
 
 #define _MPRINTF_REPLACE /* use the internal *printf() functions */
 #include <curl/mprintf.h>
@@ -585,7 +586,14 @@
 CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
 {
 #if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
-  ENGINE *e = ENGINE_by_id(engine);
+  ENGINE *e;
+  if (!Curl_client_global_openssl_ok(data->client)) {
+    failf(data, "To set an SSL engine, you must initialise the OpenSSL "
+          "crypto engine facility and use the CURL_CLIENT_GLOBAL_OPENSSL "
+          "flag on curl_client_init().");
+    return (CURLE_SSL_ENGINE_NOTFOUND);
+  }
+  e = ENGINE_by_id(engine);
 
   if (!e) {
     failf(data, "SSL Engine '%s' not found", engine);
@@ -644,8 +652,9 @@
 #if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
   ENGINE *e;
 
-  for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
-    list = curl_slist_append(list, ENGINE_get_id(e));
+  if (Curl_client_global_openssl_ok(data->client))
+    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
+      list = curl_slist_append(list, ENGINE_get_id(e));
 #endif
   (void) data;
   return (list);
Index: lib/url.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/url.c,v
retrieving revision 1.483
diff --unified -r1.483 url.c
--- lib/url.c	30 Nov 2005 13:09:48 -0000	1.483
+++ lib/url.c	4 Dec 2005 03:17:25 -0000
@@ -116,6 +116,7 @@
 #include "http_negotiate.h"
 #include "select.h"
 #include "multiif.h"
+#include "clientif.h"
 
 /* And now for the protocols */
 #include "ftp.h"
@@ -278,10 +279,13 @@
  *
  * @param curl is a pointer to a sessionhandle pointer that gets set by this
  * function.
+ * @param curlc is a handle for the Curl client to which this session will
+ * belong.
  * @return CURLcode
  */
 
-CURLcode Curl_open(struct SessionHandle **curl)
+CURLcode Curl_open(struct SessionHandle **curl,
+                   CURLC *curlc)
 {
   CURLcode res = CURLE_OK;
   struct SessionHandle *data;
@@ -291,6 +295,14 @@
     /* this is a very serious error */
     return CURLE_OUT_OF_MEMORY;
 
+  /* Today, we don't know any way to access socket functions except
+     through a process-global socket facility, and a Curl session is
+     useless without sockets, so if the Curl client doesn't want us to
+     use the global socket facility, we just have to fail.
+  */
+  if(!Curl_client_global_sock_ok(curlc))
+    return CURLE_NO_SOCKETS;
+
 #ifdef USE_ARES
   if(ARES_SUCCESS != ares_init(&data->state.areschannel)) {
     free(data);
@@ -302,6 +314,8 @@
 
   /* We do some initial setup here, all those fields that can't be just 0 */
 
+  data->client = curlc;
+
   data->state.headerbuff=(char*)malloc(HEADERSIZE);
   if(!data->state.headerbuff)
     res = CURLE_OUT_OF_MEMORY;
@@ -2238,18 +2252,24 @@
       stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
     char *ace_hostname = NULL;
     struct SessionHandle *data = conn->data;
-    int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
-    infof (data, "Input domain encoded as `%s'\n",
-           stringprep_locale_charset ());
-    if (rc != IDNA_SUCCESS)
-      infof(data, "Failed to convert %s to ACE; %s\n",
-            host->name, Curl_idn_strerror(conn,rc));
+    if (!curl_client_charset_ok(conn->data->client))
+      infof(data, "Cannot convert %s to ACE; you must set CHARSET "
+            "environment variable and "
+            "call curl_client_use_charset().\n");
     else {
-      tld_check_name(data, ace_hostname);
-
-      host->encalloc = ace_hostname;
-      /* change the name pointer to point to the encoded hostname */
-      host->name = host->encalloc;
+      int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
+      infof (data, "Input domain encoded as `%s'\n",
+             stringprep_locale_charset ());
+      if (rc != IDNA_SUCCESS)
+        infof(data, "Failed to convert %s to ACE; %s\n",
+              host->name, Curl_idn_strerror(conn,rc));
+      else {
+        tld_check_name(data, ace_hostname);
+  
+        host->encalloc = ace_hostname;
+        /* change the name pointer to point to the encoded hostname */
+        host->name = host->encalloc;
+      }
     }
   }
 #else
Index: lib/url.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/url.h,v
retrieving revision 1.23
diff --unified -r1.23 url.h
--- lib/url.h	17 Jul 2005 12:44:11 -0000	1.23
+++ lib/url.h	4 Dec 2005 03:17:25 -0000
@@ -29,7 +29,7 @@
  * Prototypes for library-wide functions provided by url.c
  */
 
-CURLcode Curl_open(struct SessionHandle **curl);
+CURLcode Curl_open(struct SessionHandle **curl, CURLC *curlc);
 CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
                      va_list arg);
 CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
Index: lib/urldata.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/urldata.h,v
retrieving revision 1.275
diff --unified -r1.275 urldata.h
--- lib/urldata.h	28 Nov 2005 23:06:00 -0000	1.275
+++ lib/urldata.h	4 Dec 2005 03:17:27 -0000
@@ -1099,6 +1099,8 @@
  * 'struct urlstate' instead.  */
 
 struct SessionHandle {
+  CURLC *client;               /* The Curl client to which this session
+                                  belongs */
   struct curl_hash *hostcache;
   void *multi;                 /* if non-NULL, points to the multi handle
                                   struct of which this "belongs" */
