aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-service.c
diff options
context:
space:
mode:
authorNot Zed <NotZed@Ximian.com>2001-03-30 08:31:20 +0800
committerMichael Zucci <zucchi@src.gnome.org>2001-03-30 08:31:20 +0800
commit554de99b229180451331f81adc3f6195bf525878 (patch)
treebf56d161d8c74305a793c95bf483ba28c7caa4f8 /camel/camel-service.c
parent424506262d215dfe306aea0d0fe86833d08b82a4 (diff)
downloadgsoc2013-evolution-554de99b229180451331f81adc3f6195bf525878.tar
gsoc2013-evolution-554de99b229180451331f81adc3f6195bf525878.tar.gz
gsoc2013-evolution-554de99b229180451331f81adc3f6195bf525878.tar.bz2
gsoc2013-evolution-554de99b229180451331f81adc3f6195bf525878.tar.lz
gsoc2013-evolution-554de99b229180451331f81adc3f6195bf525878.tar.xz
gsoc2013-evolution-554de99b229180451331f81adc3f6195bf525878.tar.zst
gsoc2013-evolution-554de99b229180451331f81adc3f6195bf525878.zip
Not quite finished but checking in for some local frobbing.
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. svn path=/trunk/; revision=9033
Diffstat (limited to 'camel/camel-service.c')
-rw-r--r--camel/camel-service.c146
1 files changed, 132 insertions, 14 deletions
diff --git a/camel/camel-service.c b/camel/camel-service.c
index 20bb00e808..5f6d983435 100644
--- a/camel/camel-service.c
+++ b/camel/camel-service.c
@@ -30,10 +30,18 @@
#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);
}