Not quite finished but checking in for some local frobbing.
authorNot Zed <NotZed@Ximian.com>
Fri, 30 Mar 2001 00:31:20 +0000 (00:31 +0000)
committerMichael Zucci <zucchi@src.gnome.org>
Fri, 30 Mar 2001 00:31:20 +0000 (00:31 +0000)
2001-03-29  Not Zed  <NotZed@Ximian.com>

        * providers/smtp/camel-smtp-transport.c (smtp_connect): Free host
        name info when done ... blah blah.

        * camel-sasl-kerberos4.c (krb4_challenge): Free host name info
        after we're done with it.

        * camel-sasl-digest-md5.c (digest_md5_challenge): Free host name
        info after we're done with it.

        * camel-remote-store.c (remote_connect): Free the host name info
        from get_host after we're finished with it.

        * camel-service.c (camel_get_host_byname): New function to
        lookup a name, and still be cancellable.
        (camel_free_host): And a function to free the structure
        returned.
        (camel_service_gethost): Call get_host_byname for this.

camel/ChangeLog
camel/camel-remote-store.c
camel/camel-sasl-digest-md5.c
camel/camel-sasl-kerberos4.c
camel/camel-service.c
camel/camel-service.h
camel/camel-vee-folder.c
camel/providers/pop3/camel-pop3-store.c
camel/providers/smtp/camel-smtp-transport.c

index 0106940..9ab05a1 100644 (file)
@@ -1,3 +1,23 @@
+2001-03-29  Not Zed  <NotZed@Ximian.com>
+
+       * providers/smtp/camel-smtp-transport.c (smtp_connect): Free host
+       name info when done ... blah blah.
+
+       * camel-sasl-kerberos4.c (krb4_challenge): Free host name info
+       after we're done with it.
+
+       * camel-sasl-digest-md5.c (digest_md5_challenge): Free host name
+       info after we're done with it.
+
+       * camel-remote-store.c (remote_connect): Free the host name info
+       from get_host after we're finished with it.
+
+       * camel-service.c (camel_get_host_byname): New function to
+       lookup a name, and still be cancellable.
+       (camel_free_host): And a function to free the structure
+       returned.
+       (camel_service_gethost): Call get_host_byname for this.
+
 2001-03-29  Jon Trowbridge  <trow@ximian.com>
 
        * camel-filter-driver.c (camel_filter_driver_filter_message): Save
        (camel_vee_folder_hash_folder): Made public (renamed from
        hash_folder), simply for subclasses (probably not needed).
        (vee_expunge): Oops, call the class sync, not superclass sync.
+       (vee_sync): Remove some accidental debug.
 
 2001-03-27  Jeffrey Stedfast  <fejj@ximian.com>
 
index 286cd62..21bd252 100644 (file)
@@ -236,6 +236,7 @@ remote_connect (CamelService *service, CamelException *ex)
 #endif /* HAVE_NSS */
        
        ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port);
+       camel_free_host(h);
        if (ret == -1) {
                if (errno == EINTR)
                        camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
index 2200c49..fa0d9a8 100644 (file)
@@ -823,7 +823,7 @@ digest_md5_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
                priv->response = generate_response (priv->challenge, h, sasl->service_name,
                                                    sasl->service->url->user,
                                                    sasl->service->url->passwd);
-               
+               camel_free_host(h);
                ret = digest_response (priv->response);
                
                break;
index 2f92f1d..1698ffe 100644 (file)
@@ -146,6 +146,7 @@ krb4_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
                inst = g_strndup (h->h_name, strcspn (h->h_name, "."));
                g_strdown (inst);
                realm = g_strdup (krb_realmofhost (h->h_name));
+               camel_free_host(h);
                status = krb_mk_req (&authenticator, sasl->service_name, inst, realm, priv->nonce_h);
                if (status == KSUCCESS) {
                        status = krb_get_cred (sasl->service_name, inst, realm, &credentials);
index 20bb00e..5f6d983 100644 (file)
 
 #include <ctype.h>
 #include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef ENABLE_THREADS
+#include <pthread.h>
+#include "e-util/e-msgport.h"
+#endif
 
 #include "camel-service.h"
 #include "camel-session.h"
 #include "camel-exception.h"
+#include "camel-operation.h"
 #include "camel-private.h"
 
 static CamelObjectClass *parent_class = NULL;
@@ -469,29 +477,139 @@ camel_service_query_auth_types (CamelService *service, CamelException *ex)
 struct hostent *
 camel_service_gethost (CamelService *service, CamelException *ex)
 {
-       struct hostent *h;
        char *hostname;
-
-#warning "This needs to use gethostbyname_r()"
+       struct hostent *h;
 
        if (service->url->host)
                hostname = service->url->host;
        else
                hostname = "localhost";
-       h = gethostbyname (hostname);
-       if (!h) {
-               extern int h_errno;
 
-               if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA) {
-                       camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID,
-                                             _("No such host %s."), hostname);
-               } else {
-                       camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-                                             _("Temporarily unable to look "
-                                               "up hostname %s."), hostname);
+       return camel_get_host_byname(hostname, ex);
+}
+
+#ifdef offsetof
+#define STRUCT_OFFSET(type, field)        ((gint) offsetof (type, field))
+#else
+#define STRUCT_OFFSET(type, field)        ((gint) ((gchar*) &((type *) 0)->field))
+#endif
+
+struct _lookup_msg {
+#ifdef ENABLE_THREADS
+       EMsg msg;
+#endif
+       const char *name;
+       int result;
+       int herr;
+       struct hostent hostbuf;
+       struct hostent *hp;
+       int hostbuflen;
+       char *hostbufmem;
+};
+
+static void *
+get_host(void *data)
+{
+       struct _lookup_msg *info = data;
+
+       while ((info->result = gethostbyname_r(info->name, &info->hostbuf, info->hostbufmem, info->hostbuflen, &info->hp, &info->herr)) == ERANGE) {
+               printf("gethostbyname fialed?\n");
+#ifdef ENABLE_THREADS
+               pthread_testcancel();
+#endif
+                info->hostbuflen *= 2;
+                info->hostbufmem = g_realloc(info->hostbufmem, info->hostbuflen);
+       }
+
+       printf("gethostbyname ok?\n");
+
+#ifdef ENABLE_THREADS
+       e_msgport_reply((EMsg *)info);
+#endif
+       return NULL;
+}
+
+struct hostent *camel_get_host_byname(const char *name, CamelException *ex)
+{
+#ifdef ENABLE_THREADS
+       int fdmax, fd, cancel_fd;
+#endif
+       struct _lookup_msg *msg;
+
+       g_return_val_if_fail(name != NULL, NULL);
+
+       if (camel_operation_cancel_check(NULL)) {
+               camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+               return NULL;
+       }
+
+       msg = g_malloc0(sizeof(*msg));
+       msg->hostbuflen = 1024;
+       msg->hostbufmem = g_malloc(msg->hostbuflen);
+       msg->name = name;
+
+#ifdef ENABLE_THREADS
+       cancel_fd = camel_operation_cancel_fd(NULL);
+       if (cancel_fd == -1) {
+#endif
+               get_host(msg);
+#ifdef ENABLE_THREADS
+       } else {
+               EMsgPort *reply_port;
+               pthread_t id;
+               fd_set rdset;
+
+               reply_port = msg->msg.reply_port = e_msgport_new();
+               fd = e_msgport_fd(msg->msg.reply_port);
+               if (pthread_create(&id, NULL, get_host, msg) == 0) {
+                       FD_ZERO(&rdset);
+                       FD_SET(cancel_fd, &rdset);
+                       FD_SET(fd, &rdset);
+                       fdmax = MAX(fd, cancel_fd) + 1;
+                       printf("waiting for name return/cancellation in main process\n");
+                       if (select(fdmax, &rdset, NULL, 0, NULL) == -1) {
+                               camel_exception_setv(ex, 1, _("Failure in name lookup: %s"), strerror(errno));
+                               printf("Cancelling lookup thread\n");
+                               pthread_cancel(id);
+                       } else if (FD_ISSET(cancel_fd, &rdset)) {
+                               printf("Cancelling lookup thread\n");
+                               camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+                               pthread_cancel(id);
+                       } else {
+                               struct _lookup_msg *reply = (struct _lookup_msg *)e_msgport_get(reply_port);
+
+                               g_assert(reply == msg);
+                       }
+                       printf("waiting for child to exit\n");
+                       pthread_join(id, NULL);
                }
+               e_msgport_destroy(reply_port);
+       }
+#endif
+
+       if (msg->hp == NULL) {
+               if (msg->herr == HOST_NOT_FOUND || msg->herr == NO_DATA)
+                       camel_exception_setv(ex, 1, _("Host lookup failed: %s: host not found"), name);
+               else
+                       camel_exception_setv(ex, 1, _("Host lookup failed: %s: unknown reason"), name);
+               g_free(msg->hostbufmem);
+               g_free(msg);
                return NULL;
+       } else {
+               return &msg->hostbuf;
        }
+}
+
+void camel_free_host(struct hostent *h)
+{
+       struct _lookup_msg *msg;
+
+       g_return_if_fail(h != NULL);
+
+       /* yeah this looks ugly but it is safe.  we passed out a reference to inside our structure, this maps it
+          to the base structure, so we can free everything right without having to keep track of it separately */
+       msg = (struct _lookup_msg *)(((char *)h) - STRUCT_OFFSET(struct _lookup_msg, hostbuf));
 
-       return h;
+       g_free(msg->hostbufmem);
+       g_free(msg);
 }
index ed02f98..7850aca 100644 (file)
@@ -112,6 +112,9 @@ GList *             camel_service_query_auth_types   (CamelService *service,
 struct hostent *    camel_service_gethost            (CamelService *service,
                                                      CamelException *ex);
 
+/* cancellable dns lookup */
+struct hostent *    camel_get_host_byname           (const char *name, CamelException *ex);
+void               camel_free_host                  (struct hostent *h);
 
 /* Standard Camel function */
 CamelType camel_service_get_type (void);
index ba1cdb5..04a06ec 100644 (file)
@@ -411,8 +411,6 @@ vee_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
        struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
        GList *node;
 
-       printf("vee-sync\n");
-
        CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
 
        node = p->folders;
index 17b2fdf..4ebb92d 100644 (file)
@@ -169,9 +169,12 @@ connect_to_server (CamelService *service, CamelException *ex)
                /* Need to copy hostname, because krb_realmofhost will
                 * call gethostbyname as well, and gethostbyname uses
                 * static storage.
+                * This isn't really necessary since gethost() returns a copy anyway,
+                * but for simplicity leave the old code here - NZ
                 */
                h = camel_service_gethost (service, ex);
                hostname = g_strdup (h->h_name);
+               camel_free_host(h);
 
                fd = CAMEL_STREAM_FS (CAMEL_REMOTE_STORE (service)->ostream)->fd;
 
index a6572d4..f2c344e 100644 (file)
@@ -255,6 +255,7 @@ smtp_connect (CamelService *service, CamelException *ex)
 #endif /* HAVE_NSS */
        
        ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port);
+       camel_free_host(h);
        if (ret == -1) {
                camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
                                      _("Could not connect to %s (port %d): %s"),