diff options
author | Not Zed <NotZed@Ximian.com> | 2004-09-24 10:50:45 +0800 |
---|---|---|
committer | Michael Zucci <zucchi@src.gnome.org> | 2004-09-24 10:50:45 +0800 |
commit | 2223bc36fa7b6b16ff7ea83e39e64e9375e3ebc1 (patch) | |
tree | 47094ce1777a4c6fe98bfc81e70a07a6f9f5414a | |
parent | 6883c5737127983d776b7071c258ae74c9bfb4c1 (diff) | |
download | gsoc2013-evolution-2223bc36fa7b6b16ff7ea83e39e64e9375e3ebc1.tar gsoc2013-evolution-2223bc36fa7b6b16ff7ea83e39e64e9375e3ebc1.tar.gz gsoc2013-evolution-2223bc36fa7b6b16ff7ea83e39e64e9375e3ebc1.tar.bz2 gsoc2013-evolution-2223bc36fa7b6b16ff7ea83e39e64e9375e3ebc1.tar.lz gsoc2013-evolution-2223bc36fa7b6b16ff7ea83e39e64e9375e3ebc1.tar.xz gsoc2013-evolution-2223bc36fa7b6b16ff7ea83e39e64e9375e3ebc1.tar.zst gsoc2013-evolution-2223bc36fa7b6b16ff7ea83e39e64e9375e3ebc1.zip |
** See bug #47821.
2004-09-13 Not Zed <NotZed@Ximian.com>
** See bug #47821.
* camel-service.c: removed the old hostent based hostname interfaces.
* camel-sasl-kerberos4.c (krb4_challenge): new hostname interfaces.
* camel-sasl-gssapi.c (gssapi_challenge): new hostname interfaces.
* camel-sasl-digest-md5.c (digest_md5_challenge): use new hostname
interfaces.
(generate_response): just take hostname directly, not hostent.
* camel-mime-utils.c (camel_header_msgid_generate): use new
hostname interfaces.
* providers/smtp/camel-smtp-transport.c (connect_to_server): fixed
to use new addrinfo apis.
* providers/pop3/camel-pop3-store.c (connect_to_server): fixed to
use new addrinfo apis.
* camel-tcp-stream-ssl.c (stream_connect): try all addresses
supplied.
* camel-tcp-stream.c (camel_tcp_stream_get_remote_address)
(camel_tcp_stream_get_local_address): return a sockaddr now, and
also the address length. Fixed all implementations and callers.
(camel_tcp_stream_connect): use addrinfo rather than hostent for
host AND port info. Fixed all implementations and callers.
svn path=/trunk/; revision=27352
-rw-r--r-- | camel/ChangeLog | 32 | ||||
-rw-r--r-- | camel/camel-http-stream.c | 29 | ||||
-rw-r--r-- | camel/camel-mime-utils.c | 26 | ||||
-rw-r--r-- | camel/camel-sasl-digest-md5.c | 22 | ||||
-rw-r--r-- | camel/camel-sasl-gssapi.c | 14 | ||||
-rw-r--r-- | camel/camel-sasl-kerberos4.c | 14 | ||||
-rw-r--r-- | camel/camel-service.c | 582 | ||||
-rw-r--r-- | camel/camel-service.h | 61 | ||||
-rw-r--r-- | camel/camel-tcp-stream-raw.c | 147 | ||||
-rw-r--r-- | camel/camel-tcp-stream-ssl.c | 160 | ||||
-rw-r--r-- | camel/camel-tcp-stream.c | 89 | ||||
-rw-r--r-- | camel/camel-tcp-stream.h | 29 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.c | 47 | ||||
-rw-r--r-- | camel/providers/nntp/camel-nntp-store.c | 34 | ||||
-rw-r--r-- | camel/providers/pop3/camel-pop3-store.c | 51 | ||||
-rw-r--r-- | camel/providers/smtp/camel-smtp-transport.c | 94 | ||||
-rw-r--r-- | camel/providers/smtp/camel-smtp-transport.h | 13 |
17 files changed, 792 insertions, 652 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index cd755a5659..f68d97d54f 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,35 @@ +2004-09-13 Not Zed <NotZed@Ximian.com> + + ** See bug #47821. + + * camel-service.c: removed the old hostent based hostname interfaces. + + * camel-sasl-kerberos4.c (krb4_challenge): new hostname interfaces. + + * camel-sasl-gssapi.c (gssapi_challenge): new hostname interfaces. + + * camel-sasl-digest-md5.c (digest_md5_challenge): use new hostname + interfaces. + (generate_response): just take hostname directly, not hostent. + + * camel-mime-utils.c (camel_header_msgid_generate): use new + hostname interfaces. + + * providers/smtp/camel-smtp-transport.c (connect_to_server): fixed + to use new addrinfo apis. + + * providers/pop3/camel-pop3-store.c (connect_to_server): fixed to + use new addrinfo apis. + + * camel-tcp-stream-ssl.c (stream_connect): try all addresses + supplied. + + * camel-tcp-stream.c (camel_tcp_stream_get_remote_address) + (camel_tcp_stream_get_local_address): return a sockaddr now, and + also the address length. Fixed all implementations and callers. + (camel_tcp_stream_connect): use addrinfo rather than hostent for + host AND port info. Fixed all implementations and callers. + 2004-09-22 Not Zed <NotZed@Ximian.com> * camel-folder-summary.c (camel_folder_summary_decode_token): diff --git a/camel/camel-http-stream.c b/camel/camel-http-stream.c index 5937c23f79..53c0241a2b 100644 --- a/camel/camel-http-stream.c +++ b/camel/camel-http-stream.c @@ -172,9 +172,12 @@ static CamelStream * http_connect (CamelHttpStream *http, CamelURL *url) { CamelStream *stream = NULL; - struct hostent *host; + struct addrinfo *ai, hints = { 0 }; int errsave; - + char *serv; + + d(printf("connecting to http stream @ '%s'\n", url->host)); + if (!strcasecmp (url->protocol, "https")) { #ifdef HAVE_SSL stream = camel_tcp_stream_ssl_new (http->session, url->host, SSL_FLAGS); @@ -187,24 +190,30 @@ http_connect (CamelHttpStream *http, CamelURL *url) errno = EINVAL; return NULL; } - - printf("connecting to http stream @ '%s'\n", url->host); - host = camel_gethostbyname (url->host, NULL); - if (!host) { - errno = EHOSTUNREACH; + if (url->port) { + serv = g_alloca(16); + sprintf(serv, "%d", url->port); + } else { + serv = url->protocol; + } + hints.ai_socktype = SOCK_STREAM; + + ai = camel_getaddrinfo(url->host, serv, &hints, NULL); + if (ai == NULL) { + camel_object_unref (stream); return NULL; } - if (camel_tcp_stream_connect (CAMEL_TCP_STREAM (stream), host, url->port ? url->port : 80) == -1) { + if (camel_tcp_stream_connect (CAMEL_TCP_STREAM (stream), ai) == -1) { errsave = errno; camel_object_unref (stream); - camel_free_host (host); + camel_freeaddrinfo(ai); errno = errsave; return NULL; } - camel_free_host (host); + camel_freeaddrinfo(ai); http->raw = stream; http->read = camel_stream_buffer_new (stream, CAMEL_STREAM_BUFFER_READ); diff --git a/camel/camel-mime-utils.c b/camel/camel-mime-utils.c index 8ce61e0b4e..3c1d4baf1c 100644 --- a/camel/camel-mime-utils.c +++ b/camel/camel-mime-utils.c @@ -3761,25 +3761,29 @@ camel_header_msgid_generate (void) #define COUNT_LOCK() pthread_mutex_lock (&count_lock) #define COUNT_UNLOCK() pthread_mutex_unlock (&count_lock) char host[MAXHOSTNAMELEN]; - struct hostent *h = NULL; + char *name; static int count = 0; char *msgid; int retval; - + struct addrinfo *ai = NULL, hints = { 0 }; + retval = gethostname (host, sizeof (host)); - - if (retval == 0 && *host) - h = camel_gethostbyname (host, NULL); - else - host[0] = '\0'; + if (retval == 0 && *host) { + hints.ai_flags = AI_CANONNAME; + ai = camel_getaddrinfo(host, NULL, &hints, NULL); + if (ai && ai->ai_canonname) + name = ai->ai_canonname; + else + name = host; + } else + name = "localhost.localdomain"; COUNT_LOCK (); - msgid = g_strdup_printf ("%d.%d.%d.camel@%s", (int) time (NULL), getpid (), count++, - h ? h->h_name : (*host ? host : "localhost.localdomain")); + msgid = g_strdup_printf ("%d.%d.%d.camel@%s", (int) time (NULL), getpid (), count++, name); COUNT_UNLOCK (); - if (h) - camel_free_host (h); + if (ai) + camel_freeaddrinfo(ai); return msgid; } diff --git a/camel/camel-sasl-digest-md5.c b/camel/camel-sasl-digest-md5.c index 36fd2f5808..b526ff47e7 100644 --- a/camel/camel-sasl-digest-md5.c +++ b/camel/camel-sasl-digest-md5.c @@ -624,7 +624,7 @@ compute_response (struct _DigestResponse *resp, const char *passwd, gboolean cli } static struct _DigestResponse * -generate_response (struct _DigestChallenge *challenge, struct hostent *host, +generate_response (struct _DigestChallenge *challenge, const char *host, const char *protocol, const char *user, const char *passwd) { struct _DigestResponse *resp; @@ -660,7 +660,7 @@ generate_response (struct _DigestChallenge *challenge, struct hostent *host, /* create the URI */ uri = g_new0 (struct _DigestURI, 1); uri->type = g_strdup (protocol); - uri->host = g_strdup (host->h_name); + uri->host = g_strdup (host); uri->name = NULL; resp->uri = uri; @@ -796,10 +796,10 @@ digest_md5_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex) struct _param *rspauth; GByteArray *ret = NULL; gboolean abort = FALSE; - struct hostent *h; const char *ptr; guchar out[33]; char *tokens; + struct addrinfo *ai, hints; /* Need to wait for the server */ if (!token) @@ -830,12 +830,20 @@ digest_md5_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex) "\"Quality of Protection\" token\n")); return NULL; } - - h = camel_service_gethost (sasl->service, ex); - priv->response = generate_response (priv->challenge, h, sasl->service_name, + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, NULL); + if (ai && ai->ai_canonname) + ptr = ai->ai_canonname; + else + ptr = "localhost.localdomain"; + + priv->response = generate_response (priv->challenge, ptr, sasl->service_name, sasl->service->url->user, sasl->service->url->passwd); - camel_free_host(h); + if (ai) + camel_freeaddrinfo(ai); ret = digest_response (priv->response); break; diff --git a/camel/camel-sasl-gssapi.c b/camel/camel-sasl-gssapi.c index 60619e7fec..1efbefee16 100644 --- a/camel/camel-sasl-gssapi.c +++ b/camel/camel-sasl-gssapi.c @@ -209,18 +209,18 @@ gssapi_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex) gss_qop_t qop; gss_OID mech; char *str; + struct addrinfo *ai, hints; switch (priv->state) { case GSSAPI_STATE_INIT: - if (!(h = camel_service_gethost (sasl->service, ex))) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to resolve host `%s': %s"), - sasl->service->url->host, g_strerror (errno)); + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, ex); + if (ai == NULL) return NULL; - } - str = g_strdup_printf ("%s@%s", sasl->service_name, h->h_name); - camel_free_host (h); + str = g_strdup_printf("%s@%s", sasl->service_name, ai->ai_canonname); + camel_freeaddrinfo(ai); inbuf.value = str; inbuf.length = strlen (str); diff --git a/camel/camel-sasl-kerberos4.c b/camel/camel-sasl-kerberos4.c index e225c1a26c..fd366e61db 100644 --- a/camel/camel-sasl-kerberos4.c +++ b/camel/camel-sasl-kerberos4.c @@ -129,6 +129,7 @@ krb4_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex) KTEXT_ST authenticator; CREDENTIALS credentials; guint32 plus1; + struct addrinfo *ai, hints; /* Need to wait for the server */ if (!token) @@ -142,12 +143,17 @@ krb4_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex) memcpy (&priv->nonce_n, token->data, 4); priv->nonce_h = ntohl (priv->nonce_n); + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, ex); + if (ai == NULL) + goto lose; + /* Our response is an authenticator including that number. */ - h = camel_service_gethost (sasl->service, ex); - inst = g_strndup (h->h_name, strcspn (h->h_name, ".")); + inst = g_strndup (ai->ai_canonname, strcspn (ai->ai_canonname, ".")); camel_strdown (inst); - realm = g_strdup (krb_realmofhost (h->h_name)); - camel_free_host(h); + realm = g_strdup (krb_realmofhost (ai->ai_canonname)); + camel_freeaddrinfo(ai); 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); diff --git a/camel/camel-service.c b/camel/camel-service.c index 11f97cd2a6..171bfe6061 100644 --- a/camel/camel-service.c +++ b/camel/camel-service.c @@ -34,6 +34,8 @@ #include <pthread.h> #include <errno.h> +#include <sys/poll.h> + #include "e-util/e-msgport.h" #include "e-util/e-host-utils.h" @@ -642,67 +644,226 @@ camel_service_query_auth_types (CamelService *service, CamelException *ex) return ret; } -/* URL utility routines */ - -/** - * camel_service_gethost: - * @service: a CamelService - * @ex: a CamelException - * - * This is a convenience function to do a gethostbyname on the host - * for the service's URL. - * - * Return value: a (statically-allocated) hostent. - **/ -struct hostent * -camel_service_gethost (CamelService *service, CamelException *ex) -{ - char *hostname; - - if (service->url->host) - hostname = service->url->host; - else - hostname = "localhost"; - - return camel_gethostbyname (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 { +/* ********************************************************************** */ +struct _addrinfo_msg { EMsg msg; unsigned int cancelled:1; + + /* for host lookup */ const char *name; - int len; - int type; + const char *service; int result; - int herr; + const struct addrinfo *hints; + struct addrinfo **res; + + /* for host lookup emulation */ +#ifdef NEED_ADDRINFO struct hostent hostbuf; int hostbuflen; char *hostbufmem; +#endif + + /* for name lookup */ + const struct sockaddr *addr; + socklen_t addrlen; + char *host; + int hostlen; + char *serv; + int servlen; + int flags; }; +static void +cs_freeinfo(struct _addrinfo_msg *msg) +{ + g_free(msg->host); + g_free(msg->serv); +#ifdef NEED_ADDRINFO + g_free(msg->hostbufmem); +#endif + g_free(msg); +} + +/* returns -1 if cancelled */ +static int +cs_waitinfo(void *(worker)(void *), struct _addrinfo_msg *msg, const char *error, CamelException *ex) +{ + EMsgPort *reply_port; + pthread_t id; + int err, cancel_fd, cancel = 0, fd; + + cancel_fd = camel_operation_cancel_fd(NULL); + if (cancel_fd == -1) { + worker(msg); + return 0; + } + + reply_port = msg->msg.reply_port = e_msgport_new(); + fd = e_msgport_fd(msg->msg.reply_port); + if ((err = pthread_create(&id, NULL, worker, msg)) == 0) { + struct pollfd polls[2]; + int status; + + polls[0].fd = fd; + polls[0].events = POLLIN; + polls[1].fd = cancel_fd; + polls[1].events = POLLIN; + + d(printf("waiting for name return/cancellation in main process\n")); + do { + polls[0].revents = 0; + polls[1].revents = 0; + status = poll(polls, 2, -1); + } while (status == -1 && errno == EINTR); + + if (status == -1 || (polls[1].revents & POLLIN)) { + if (status == -1) + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s", error, g_strerror(errno)); + else + camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled")); + + /* We cancel so if the thread impl is decent it causes immediate exit. + We detach so we dont need to wait for it to exit if it isn't. + We check the reply port incase we had a reply in the mean time, which we free later */ + d(printf("Cancelling lookup thread and leaving it\n")); + msg->cancelled = 1; + pthread_detach(id); + pthread_cancel(id); + cancel = 1; + } else { + struct _addrinfo_msg *reply = (struct _addrinfo_msg *)e_msgport_get(reply_port); + + g_assert(reply == msg); + d(printf("waiting for child to exit\n")); + pthread_join(id, NULL); + d(printf("child done\n")); + } + } else { + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s: %s", _("cannot create thread"), g_strerror(err)); + } + e_msgport_destroy(reply_port); + + return cancel; +} + +#ifdef NEED_ADDRINFO static void * -get_hostbyname(void *data) +cs_getaddrinfo(void *data) { - struct _lookup_msg *info = data; + struct _addrinfo_msg *msg = data; + int herr; + struct hostent h; + struct addrinfo *res, *last = NULL; + struct sockaddr_in *sin; + in_port_t port = 0; + int i; + + /* This is a pretty simplistic emulation of getaddrinfo */ - while ((info->result = e_gethostbyname_r(info->name, &info->hostbuf, info->hostbufmem, info->hostbuflen, &info->herr)) == ERANGE) { - d(printf("gethostbyname fialed?\n")); + while ((msg->result = e_gethostbyname_r(msg->name, &h, msg->hostbufmem, msg->hostbuflen, &herr)) == ERANGE) { pthread_testcancel(); - info->hostbuflen *= 2; - info->hostbufmem = g_realloc(info->hostbufmem, info->hostbuflen); + msg->hostbuflen *= 2; + msg->hostbufmem = g_realloc(msg->hostbufmem, msg->hostbuflen); } - - d(printf("gethostbyname ok?\n")); /* If we got cancelled, dont reply, just free it */ + if (msg->cancelled) + goto cancel; + + /* FIXME: map error numbers across */ + if (msg->result != 0) + goto reply; + + /* check hints matched */ + if (msg->hints && msg->hints->ai_family && msg->hints->ai_family != h.h_addrtype) { + msg->result = EAI_FAMILY; + goto reply; + } + + /* we only support ipv4 for this interface, even if it could supply ipv6 */ + if (h.h_addrtype != AF_INET) { + msg->result = EAI_FAMILY; + goto reply; + } + + /* check service mapping */ + if (msg->service) { + const char *p = msg->service; + + while (*p) { + if (*p < '0' || *p > '9') + break; + p++; + } + + if (*p) { + const char *socktype = NULL; + struct servent *serv; + + if (msg->hints && msg->hints->ai_socktype) { + if (msg->hints->ai_socktype == SOCK_STREAM) + socktype = "tcp"; + else if (msg->hints->ai_socktype == SOCK_DGRAM) + socktype = "udp"; + } + + serv = getservbyname(msg->service, socktype); + if (serv == NULL) { + msg->result = EAI_NONAME; + goto reply; + } + port = serv->s_port; + } else { + port = htons(strtoul(msg->service, NULL, 10)); + } + } + + for (i=0;h.h_addr_list[i];i++) { + res = g_malloc0(sizeof(*res)); + if (msg->hints) { + res->ai_flags = msg->hints->ai_flags; + if (msg->hints->ai_flags & AI_CANONNAME) + res->ai_canonname = g_strdup(h.h_name); + res->ai_socktype = msg->hints->ai_socktype; + res->ai_protocol = msg->hints->ai_protocol; + } else { + res->ai_flags = 0; + res->ai_socktype = SOCK_STREAM; /* fudge */ + res->ai_protocol = 0; /* fudge */ + } + res->ai_family = AF_INET; + res->ai_addrlen = sizeof(*sin); + res->ai_addr = g_malloc(sizeof(*sin)); + sin = (struct sockaddr_in *)res->ai_addr; + sin->sin_family = AF_INET; + sin->sin_port = port; + memcpy(&sin->sin_addr, h.h_addr_list[i], sizeof(sin->sin_addr)); + + if (last == NULL) { + *msg->res = last = res; + } else { + last->ai_next = res; + last = res; + } + } +reply: + e_msgport_reply((EMsg *)msg); + return NULL; +cancel: + cs_freeinfo(msg); + return NULL; +} +#else +static void * +cs_getaddrinfo(void *data) +{ + struct _addrinfo_msg *info = data; + + do { + info->result = getaddrinfo(info->name, info->service, info->hints, info->res); + } while (info->result == EAI_AGAIN); + if (info->cancelled) { - g_free(info->hostbufmem); g_free(info); } else { e_msgport_reply((EMsg *)info); @@ -710,239 +871,186 @@ get_hostbyname(void *data) return NULL; } +#endif /* NEED_ADDRINFO */ -struct hostent * -camel_gethostbyname (const char *name, CamelException *exout) +struct addrinfo * +camel_getaddrinfo(const char *name, const char *service, const struct addrinfo *hints, CamelException *ex) { - int fdmax, status, fd, cancel_fd; - struct _lookup_msg *msg; - CamelException ex; - + struct _addrinfo_msg *msg; + struct addrinfo *res = NULL; +#ifndef ENABLE_IPv6 + struct addrinfo *myhints; +#endif g_return_val_if_fail(name != NULL, NULL); if (camel_operation_cancel_check(NULL)) { - camel_exception_set (exout, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled")); + camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled")); return NULL; } - camel_exception_init(&ex); camel_operation_start_transient(NULL, _("Resolving: %s"), name); - msg = g_malloc0(sizeof(*msg)); - msg->hostbuflen = 1024; - msg->hostbufmem = g_malloc(msg->hostbuflen); - msg->name = name; - msg->result = -1; - - cancel_fd = camel_operation_cancel_fd(NULL); - if (cancel_fd == -1) { - get_hostbyname(msg); - } else { - EMsgPort *reply_port; - pthread_t id; - fd_set rdset; - int err; - - reply_port = msg->msg.reply_port = e_msgport_new(); - fd = e_msgport_fd(msg->msg.reply_port); - if ((err = pthread_create(&id, NULL, get_hostbyname, msg)) == 0) { - d(printf("waiting for name return/cancellation in main process\n")); - do { - FD_ZERO(&rdset); - FD_SET(cancel_fd, &rdset); - FD_SET(fd, &rdset); - fdmax = MAX(fd, cancel_fd) + 1; - status = select(fdmax, &rdset, NULL, 0, NULL); - } while (status == -1 && errno == EINTR); - - if (status == -1 || FD_ISSET(cancel_fd, &rdset)) { - if (status == -1) - camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Failure in name lookup: %s"), g_strerror(errno)); - else - camel_exception_setv(&ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled")); - - /* We cancel so if the thread impl is decent it causes immediate exit. - We detach so we dont need to wait for it to exit if it isn't. - We check the reply port incase we had a reply in the mean time, which we free later */ - d(printf("Cancelling lookup thread and leaving it\n")); - msg->cancelled = 1; - pthread_detach(id); - pthread_cancel(id); - msg = (struct _lookup_msg *)e_msgport_get(reply_port); - } else { - struct _lookup_msg *reply = (struct _lookup_msg *)e_msgport_get(reply_port); - - g_assert(reply == msg); - d(printf("waiting for child to exit\n")); - pthread_join(id, NULL); - d(printf("child done\n")); - } - } else { - camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Host lookup failed: cannot create thread: %s"), g_strerror(err)); - } - e_msgport_destroy(reply_port); + /* force ipv4 addresses only */ +#ifndef ENABLE_IPv6 + if (hints == NULL) { + memset(&myhints, 0, sizeof(myhints)); + hints = &myhints; } - - camel_operation_end(NULL); - - if (!camel_exception_is_set(&ex)) { - if (msg->result == 0) - return &msg->hostbuf; - if (msg->herr == HOST_NOT_FOUND || msg->herr == NO_DATA) - camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM, - _("Host lookup failed: %s: host not found"), name); - else - camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM, - _("Host lookup failed: %s: unknown reason"), name); - } + hints->ai_family = AF_INET; +#endif - if (msg) { - g_free(msg->hostbufmem); - g_free(msg); - } + msg = g_malloc0(sizeof(*msg)); + msg->name = name; + msg->service = service; + msg->hints = hints; + msg->res = &res; +#ifdef NEED_ADDRINFO + msg->hostbuflen = 1024; + msg->hostbufmem = g_malloc(msg->hostbuflen); +#endif + if (cs_waitinfo(cs_getaddrinfo, msg, _("Host lookup failed"), ex) == 0) + cs_freeinfo(msg); + else + res = NULL; - camel_exception_xfer(exout, &ex); + camel_operation_end(NULL); - return NULL; + return res; } -static void * -get_hostbyaddr (void *data) +void +camel_freeaddrinfo(struct addrinfo *host) { - struct _lookup_msg *info = data; - - while ((info->result = e_gethostbyaddr_r (info->name, info->len, info->type, &info->hostbuf, - info->hostbufmem, info->hostbuflen, &info->herr)) == ERANGE) { - d(printf ("gethostbyaddr fialed?\n")); - pthread_testcancel (); - info->hostbuflen *= 2; - info->hostbufmem = g_realloc (info->hostbufmem, info->hostbuflen); +#ifdef NEED_ADDRINFO + while (host) { + struct addrinfo *next = host->ai_next; + + g_free(host->ai_canonname); + g_free(host->ai_addr); + g_free(host); + host = next; } - - d(printf ("gethostbyaddr ok?\n")); - - if (info->cancelled) { - g_free(info->hostbufmem); - g_free(info); - } else { - e_msgport_reply((EMsg *)info); - } - - return NULL; +#else + freeaddrinfo(host); +#endif } - -struct hostent * -camel_gethostbyaddr (const char *addr, int len, int type, CamelException *exout) +#ifdef NEED_ADDRINFO +static void * +cs_getnameinfo(void *data) { - int fdmax, status, fd, cancel_fd; - struct _lookup_msg *msg; - CamelException ex; + struct _addrinfo_msg *msg = data; + int herr; + struct hostent h; + struct sockaddr_in *sin = (struct sockaddr_in *)msg->addr; - g_return_val_if_fail (addr != NULL, NULL); - - if (camel_operation_cancel_check (NULL)) { - camel_exception_set (exout, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled")); + /* FIXME: error code */ + if (msg->addr->sa_family != AF_INET) { + msg->result = -1; return NULL; } - camel_exception_init(&ex); - camel_operation_start_transient (NULL, _("Resolving address")); - - msg = g_malloc0 (sizeof (struct _lookup_msg)); - msg->hostbuflen = 1024; - msg->hostbufmem = g_malloc (msg->hostbuflen); - msg->name = addr; - msg->len = len; - msg->type = type; - msg->result = -1; - - cancel_fd = camel_operation_cancel_fd (NULL); - if (cancel_fd == -1) { - get_hostbyaddr (msg); - } else { - EMsgPort *reply_port; - pthread_t id; - fd_set rdset; - int err; - - reply_port = msg->msg.reply_port = e_msgport_new (); - fd = e_msgport_fd (msg->msg.reply_port); - if ((err = pthread_create (&id, NULL, get_hostbyaddr, msg)) == 0) { - d(printf("waiting for name return/cancellation in main process\n")); - do { - FD_ZERO(&rdset); - FD_SET(cancel_fd, &rdset); - FD_SET(fd, &rdset); - fdmax = MAX(fd, cancel_fd) + 1; - status = select (fdmax, &rdset, NULL, 0, NULL); - } while (status == -1 && errno == EINTR); - - if (status == -1 || FD_ISSET(cancel_fd, &rdset)) { - if (status == -1) - camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Failure in name lookup: %s"), g_strerror(errno)); - else - camel_exception_setv(&ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled")); - - /* We cancel so if the thread impl is decent it causes immediate exit. - We detach so we dont need to wait for it to exit if it isn't. - We check the reply port incase we had a reply in the mean time, which we free later */ - d(printf("Cancelling lookup thread and leaving it\n")); - msg->cancelled = 1; - pthread_detach(id); - pthread_cancel(id); - msg = (struct _lookup_msg *)e_msgport_get(reply_port); - } else { - struct _lookup_msg *reply = (struct _lookup_msg *)e_msgport_get(reply_port); - - g_assert(reply == msg); - d(printf("waiting for child to exit\n")); - pthread_join(id, NULL); - d(printf("child done\n")); - } - } else { - camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Host lookup failed: cannot create thread: %s"), g_strerror(err)); - } + /* FIXME: honour getnameinfo flags: do we care, not really */ - - e_msgport_destroy (reply_port); + while ((msg->result = e_gethostbyaddr_r((const char *)&sin->sin_addr, sizeof(sin->sin_addr), AF_INET, &h, + msg->hostbufmem, msg->hostbuflen, &herr)) == ERANGE) { + pthread_testcancel (); + msg->hostbuflen *= 2; + msg->hostbufmem = g_realloc(msg->hostbufmem, msg->hostbuflen); } - camel_operation_end (NULL); - - if (!camel_exception_is_set(&ex)) { - if (msg->result == 0) - return &msg->hostbuf; + if (msg->cancelled) + goto cancel; - if (msg->herr == HOST_NOT_FOUND || msg->herr == NO_DATA) - camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM, - _("Host lookup failed: host not found")); - else - camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM, - _("Host lookup failed: unknown reason")); + if (msg->host) { + g_free(msg->host); + if (msg->result == 0 && h.h_name && h.h_name[0]) { + msg->host = g_strdup(h.h_name); + } else { + unsigned char *in = (unsigned char *)&sin->sin_addr; + + /* sin_addr is always network order which is big-endian */ + msg->host = g_strdup_printf("%u.%u.%u.%u", in[0], in[1], in[2], in[3]); + } } - if (msg) { - g_free(msg->hostbufmem); - g_free(msg); - } + /* we never actually use this anyway */ + if (msg->serv) + sprintf(msg->serv, "%d", sin->sin_port); + + e_msgport_reply((EMsg *)msg); + return NULL; +cancel: + cs_freeinfo(msg); + return NULL; +} +#else +static void * +cs_getnameinfo(void *data) +{ + struct _addrinfo_msg *msg = data; - camel_exception_xfer(exout, &ex); + /* there doens't appear to be a return code which says host or serv buffers are too short, lengthen them */ + do { + msg->result = getnameinfo(msg->addr, msg->addrlen, msg->host, msg->hostlen, msg->serv, msg->servlen, msg->flags); + } while (msg->result == EAI_AGAIN); + + if (msg->cancelled) + cs_freeinfo(msg); + else + e_msgport_reply((EMsg *)msg); return NULL; } +#endif -void camel_free_host(struct hostent *h) +int +camel_getnameinfo(const struct sockaddr *sa, socklen_t salen, char **host, char **serv, int flags, CamelException *ex) { - struct _lookup_msg *msg; + struct _addrinfo_msg *msg; + int result; - g_return_if_fail(h != NULL); + if (camel_operation_cancel_check(NULL)) { + camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled")); + return -1; + } - /* 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)); + camel_operation_start_transient(NULL, _("Resolving address")); - g_free(msg->hostbufmem); + msg = g_malloc0(sizeof(*msg)); + msg->addr = sa; + msg->addrlen = salen; + if (host) { + msg->hostlen = NI_MAXHOST; + msg->host = g_malloc(msg->hostlen); + msg->host[0] = 0; + } + if (serv) { + msg->servlen = NI_MAXSERV; + msg->serv = g_malloc(msg->servlen); + msg->serv[0] = 0; + } + msg->flags = flags; +#ifdef NEED_ADDRINFO + msg->hostbuflen = 1024; + msg->hostbufmem = g_malloc(msg->hostbuflen); +#endif + cs_waitinfo(cs_getnameinfo, msg, _("Name lookup failed"), ex); + + result = msg->result; + + if (host) + *host = g_strdup(msg->host); + if (serv) + *serv = g_strdup(msg->serv); + + g_free(msg->host); + g_free(msg->serv); g_free(msg); + + camel_operation_end(NULL); + + return result; } + diff --git a/camel/camel-service.h b/camel/camel-service.h index 587749e242..f49472cc5a 100644 --- a/camel/camel-service.h +++ b/camel/camel-service.h @@ -135,14 +135,61 @@ CamelProvider * camel_service_get_provider (CamelService *service); GList * camel_service_query_auth_types (CamelService *service, CamelException *ex); -/* convenience functions */ -struct hostent * camel_service_gethost (CamelService *service, - CamelException *ex); +#ifdef NEED_ADDRINFO +/* Some of this is copied from GNU's netdb.h + + Copyright (C) 1996-2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. +*/ +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; -/* cancellable dns lookup */ -struct hostent * camel_gethostbyname (const char *name, CamelException *ex); -struct hostent * camel_gethostbyaddr (const char *addr, int len, int type, CamelException *ex); -void camel_free_host (struct hostent *h); +#define AI_CANONNAME 0x0002 /* Request for canonical name. */ +#define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */ + +/* Error values for `getaddrinfo' function. */ +#define EAI_BADFLAGS -1 /* Invalid value for `ai_flags' field. */ +#define EAI_NONAME -2 /* NAME or SERVICE is unknown. */ +#define EAI_AGAIN -3 /* Temporary failure in name resolution. */ +#define EAI_FAIL -4 /* Non-recoverable failure in name res. */ +#define EAI_NODATA -5 /* No address associated with NAME. */ +#define EAI_FAMILY -6 /* `ai_family' not supported. */ +#define EAI_SOCKTYPE -7 /* `ai_socktype' not supported. */ +#define EAI_SERVICE -8 /* SERVICE not supported for `ai_socktype'. */ +#define EAI_ADDRFAMILY -9 /* Address family for NAME not supported. */ +#define EAI_MEMORY -10 /* Memory allocation failure. */ +#define EAI_SYSTEM -11 /* System error returned in `errno'. */ +#define EAI_OVERFLOW -12 /* Argument buffer overflow. */ + +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +#define NI_NUMERICHOST 1 /* Don't try to look up hostname. */ +#define NI_NUMERICSERV 2 /* Don't convert port number to name. */ +#define NI_NOFQDN 4 /* Only return nodename portion. */ +#define NI_NAMEREQD 8 /* Don't return numeric addresses. */ +#define NI_DGRAM 16 /* Look up UDP service rather than TCP. */ +#endif + +/* new hostname interfaces */ +struct addrinfo *camel_getaddrinfo(const char *name, const char *service, + const struct addrinfo *hints, CamelException *ex); +void camel_freeaddrinfo(struct addrinfo *host); +int camel_getnameinfo(const struct sockaddr *sa, socklen_t salen, char **host, char **serv, + int flags, CamelException *ex); /* Standard Camel function */ CamelType camel_service_get_type (void); diff --git a/camel/camel-tcp-stream-raw.c b/camel/camel-tcp-stream-raw.c index 04e47ac64b..93f3fbdbab 100644 --- a/camel/camel-tcp-stream-raw.c +++ b/camel/camel-tcp-stream-raw.c @@ -20,7 +20,6 @@ * */ - #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -48,11 +47,11 @@ static ssize_t stream_write (CamelStream *stream, const char *buffer, size_t n); static int stream_flush (CamelStream *stream); static int stream_close (CamelStream *stream); -static int stream_connect (CamelTcpStream *stream, struct hostent *host, int port); +static int stream_connect (CamelTcpStream *stream, struct addrinfo *host); static int stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data); static int stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data); -static CamelTcpAddress *stream_get_local_address (CamelTcpStream *stream); -static CamelTcpAddress *stream_get_remote_address (CamelTcpStream *stream); +static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len); +static struct sockaddr *stream_get_remote_address (CamelTcpStream *stream, socklen_t *len); static void camel_tcp_stream_raw_class_init (CamelTcpStreamRawClass *camel_tcp_stream_raw_class) @@ -267,13 +266,8 @@ stream_close (CamelStream *stream) /* this is a 'cancellable' connect, cancellable from camel_operation_cancel etc */ /* returns -1 & errno == EINTR if the connection was cancelled */ static int -socket_connect (struct hostent *h, int port) +socket_connect(struct addrinfo *h) { -#ifdef ENABLE_IPv6 - struct sockaddr_in6 sin6; -#endif - struct sockaddr_in sin; - struct sockaddr *saddr; struct timeval tv; socklen_t len; int cancel_fd; @@ -286,31 +280,17 @@ socket_connect (struct hostent *h, int port) return -1; } - /* setup connect, we do it using a nonblocking socket so we can poll it */ -#ifdef ENABLE_IPv6 - if (h->h_addrtype == AF_INET6) { - sin6.sin6_port = htons (port); - sin6.sin6_family = h->h_addrtype; - memcpy (&sin6.sin6_addr, h->h_addr, sizeof (sin6.sin6_addr)); - saddr = (struct sockaddr *) &sin6; - len = sizeof (sin6); - } else { -#endif - sin.sin_port = htons (port); - sin.sin_family = h->h_addrtype; - memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr)); - saddr = (struct sockaddr *) &sin; - len = sizeof (sin); -#ifdef ENABLE_IPv6 + if (h->ai_socktype != SOCK_STREAM) { + errno = EINVAL; + return -1; } -#endif - - if ((fd = socket (h->h_addrtype, SOCK_STREAM, 0)) == -1) + + if ((fd = socket (h->ai_family, SOCK_STREAM, 0)) == -1) return -1; cancel_fd = camel_operation_cancel_fd (NULL); if (cancel_fd == -1) { - if (connect (fd, saddr, len) == -1) { + if (connect (fd, h->ai_addr, h->ai_addrlen) == -1) { errnosav = errno; close (fd); errno = errnosav; @@ -325,7 +305,7 @@ socket_connect (struct hostent *h, int port) flags = fcntl (fd, F_GETFL); fcntl (fd, F_SETFL, flags | O_NONBLOCK); - if (connect (fd, saddr, len) == 0) { + if (connect (fd, h->ai_addr, h->ai_addrlen) == 0) { fcntl (fd, F_SETFL, flags); return fd; } @@ -383,21 +363,22 @@ socket_connect (struct hostent *h, int port) } static int -stream_connect (CamelTcpStream *stream, struct hostent *host, int port) +stream_connect (CamelTcpStream *stream, struct addrinfo *host) { CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream); - int fd; g_return_val_if_fail (host != NULL, -1); - - if ((fd = socket_connect (host, port)) == -1) - return -1; - - raw->sockfd = fd; - - return 0; -} + while (host) { + raw->sockfd = socket_connect(host); + if (raw->sockfd != -1) + return 0; + + host = host->ai_next; + } + + return -1; +} static int get_sockopt_level (const CamelSockOptData *data) @@ -496,72 +477,42 @@ stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data) sizeof (data->value)); } +static struct sockaddr * +stream_get_local_address (CamelTcpStream *stream, socklen_t *len) +{ #ifdef ENABLE_IPv6 -#define MIN_SOCKADDR_BUFLEN (sizeof (struct sockaddr_in6)) + struct sockaddr_in6 sin; #else -#define MIN_SOCKADDR_BUFLEN (sizeof (struct sockaddr_in)) + struct sockaddr_in sin; #endif + struct sockaddr *saddr = (struct sockaddr *)&sin; -static CamelTcpAddress * -stream_get_local_address (CamelTcpStream *stream) -{ - unsigned char buf[MIN_SOCKADDR_BUFLEN]; -#ifdef ENABLE_IPv6 - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) buf; -#endif - struct sockaddr_in *sin = (struct sockaddr_in *) buf; - struct sockaddr *saddr = (struct sockaddr *) buf; - gpointer address; - socklen_t len; - int family; - - len = MIN_SOCKADDR_BUFLEN; - - if (getsockname (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, &len) == -1) + *len = sizeof(sin); + if (getsockname (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, len) == -1) return NULL; - - if (saddr->sa_family == AF_INET) { - family = CAMEL_TCP_ADDRESS_IPv4; - address = &sin->sin_addr; -#ifdef ENABLE_IPv6 - } else if (saddr->sa_family == AF_INET6) { - family = CAMEL_TCP_ADDRESS_IPv6; - address = &sin6->sin6_addr; -#endif - } else - return NULL; - - return camel_tcp_address_new (family, sin->sin_port, len, address); + + saddr = g_malloc(*len); + memcpy(saddr, &sin, *len); + + return saddr; } -static CamelTcpAddress * -stream_get_remote_address (CamelTcpStream *stream) +static struct sockaddr * +stream_get_remote_address (CamelTcpStream *stream, socklen_t *len) { - unsigned char buf[MIN_SOCKADDR_BUFLEN]; #ifdef ENABLE_IPv6 - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) buf; -#endif - struct sockaddr_in *sin = (struct sockaddr_in *) buf; - struct sockaddr *saddr = (struct sockaddr *) buf; - gpointer address; - socklen_t len; - int family; - - len = MIN_SOCKADDR_BUFLEN; - - if (getpeername (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, &len) == -1) - return NULL; - - if (saddr->sa_family == AF_INET) { - family = CAMEL_TCP_ADDRESS_IPv4; - address = &sin->sin_addr; -#ifdef ENABLE_IPv6 - } else if (saddr->sa_family == AF_INET6) { - family = CAMEL_TCP_ADDRESS_IPv6; - address = &sin6->sin6_addr; + struct sockaddr_in6 sin; +#else + struct sockaddr_in sin; #endif - } else + struct sockaddr *saddr = (struct sockaddr *)&sin; + + *len = sizeof(sin); + if (getpeername (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, len) == -1) return NULL; - - return camel_tcp_address_new (family, sin->sin_port, len, address); + + saddr = g_malloc(*len); + memcpy(saddr, &sin, *len); + + return saddr; } diff --git a/camel/camel-tcp-stream-ssl.c b/camel/camel-tcp-stream-ssl.c index ef89d8c88e..19c534beff 100644 --- a/camel/camel-tcp-stream-ssl.c +++ b/camel/camel-tcp-stream-ssl.c @@ -81,11 +81,11 @@ static int stream_close (CamelStream *stream); static PRFileDesc *enable_ssl (CamelTcpStreamSSL *ssl, PRFileDesc *fd); -static int stream_connect (CamelTcpStream *stream, struct hostent *host, int port); +static int stream_connect (CamelTcpStream *stream, struct addrinfo *host); static int stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data); static int stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data); -static CamelTcpAddress *stream_get_local_address (CamelTcpStream *stream); -static CamelTcpAddress *stream_get_remote_address (CamelTcpStream *stream); +static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len); +static struct sockaddr *stream_get_remote_address (CamelTcpStream *stream, socklen_t *len); struct _CamelTcpStreamSSLPrivate { PRFileDesc *sockfd; @@ -1025,30 +1025,58 @@ enable_ssl (CamelTcpStreamSSL *ssl, PRFileDesc *fd) } static int -stream_connect (CamelTcpStream *stream, struct hostent *host, int port) +sockaddr_to_praddr(struct sockaddr *s, int len, PRNetAddr *addr) +{ + /* We assume the ip addresses are the same size - they have to be anyway. + We could probably just use memcpy *shrug* */ + + memset(addr, 0, sizeof(*addr)); + + if (s->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)s; + + if (len < sizeof(*sin)) + return -1; + + addr->inet.family = PR_AF_INET; + addr->inet.port = sin->sin_port; + memcpy(&addr->inet.ip, &sin->sin_addr, sizeof(addr->inet.ip)); + + return 0; + } +#ifdef ENABLE_IPv6 + else if (s->sa_family == PR_AF_INET6) { + struct sockaddr_in6 *sin = (struct sockaddr_in6 *)s; + + if (len < sizeof(*sin)) + return -1; + + addr->ipv6.family = PR_AF_INET6; + addr->ipv6.port = sin->sin6_port; + addr->ipv6.flowinfo = sin->sin6_flowinfo; + memcpy(&addr->ipv6.ip, &sin->sin6_addr, sizeof(addr->ipv6.ip)); + addr->ipv6.scope_id = sin->sin6_scope_id; + + return 0; + } +#endif + + return -1; +} + +static int +socket_connect(CamelTcpStream *stream, struct addrinfo *host) { CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream); PRNetAddr netaddr; PRFileDesc *fd, *cancel_fd; - - g_return_val_if_fail (host != NULL, -1); - - memset ((void *) &netaddr, 0, sizeof (PRNetAddr)); -#ifdef ENABLE_IPv6 - if (host->h_addrtype == AF_INET6) - memcpy (&netaddr.ipv6.ip, host->h_addr, sizeof (netaddr.ipv6.ip)); - else - memcpy (&netaddr.inet.ip, host->h_addr, sizeof (netaddr.inet.ip)); -#else - memcpy (&netaddr.inet.ip, host->h_addr, sizeof (netaddr.inet.ip)); -#endif - - if (PR_InitializeNetAddr (PR_IpAddrNull, port, &netaddr) == PR_FAILURE) { - set_errno (PR_GetError ()); + + if (sockaddr_to_praddr(host->ai_addr, host->ai_addrlen, &netaddr) != 0) { + errno = EINVAL; return -1; } - fd = PR_OpenTCPSocket (host->h_addrtype); + fd = PR_OpenTCPSocket(netaddr.raw.family); if (fd == NULL) { set_errno (PR_GetError ()); return -1; @@ -1127,6 +1155,17 @@ stream_connect (CamelTcpStream *stream, struct hostent *host, int port) return 0; } +static int +stream_connect(CamelTcpStream *stream, struct addrinfo *host) +{ + while (host) { + if (socket_connect(stream, host) == 0) + return 0; + host = host->ai_next; + } + + return -1; +} static int stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data) @@ -1158,56 +1197,61 @@ stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data) return 0; } -static CamelTcpAddress * -stream_get_local_address (CamelTcpStream *stream) +static struct sockaddr * +sockaddr_from_praddr(PRNetAddr *addr, socklen_t *len) +{ + /* We assume the ip addresses are the same size - they have to be anyway */ + + if (addr->raw.family == PR_AF_INET) { + struct sockaddr_in *sin = g_malloc0(sizeof(*sin)); + + sin->sin_family = AF_INET; + sin->sin_port = addr->inet.port; + memcpy(&sin->sin_addr, &addr->inet.ip, sizeof(sin->sin_addr)); + *len = sizeof(*sin); + + return (struct sockaddr *)sin; + } +#ifdef ENABLE_IPv6 + else if (addr->raw.family == PR_AF_INET6) { + struct sockaddr_in6 *sin = g_malloc0(sizeof(*sin)); + + sin->sin6_family = AF_INET6; + sin->sin6_port = addr->ipv6.port; + sin->sin6_flowinfo = addr->ipv6.flowinfo; + memcpy(&sin->sin6_addr, &addr->ipv6.ip, sizeof(sin->sin6_addr)); + sin->sin6_scope_id = addr->ipv6.scope_id; + *len = sizeof(*sin); + + return (struct sockaddr *)sin; + } +#endif + + return NULL; +} + +static struct sockaddr * +stream_get_local_address(CamelTcpStream *stream, socklen_t *len) { PRFileDesc *sockfd = CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd; - int family, length; - gpointer address; PRNetAddr addr; - PR_GetSockName (sockfd, &addr); - - if (addr.inet.family == PR_AF_INET) { - family = CAMEL_TCP_ADDRESS_IPv4; - address = &addr.inet.ip; - length = 4; -#ifdef ENABLE_IPv6 - } else if (addr.inet.family == PR_AF_INET6) { - family = CAMEL_TCP_ADDRESS_IPv6; - address = &addr.ipv6.ip; - length = 16; -#endif - } else + if (PR_GetSockName(sockfd, &addr) != PR_SUCCESS) return NULL; - - return camel_tcp_address_new (family, addr.inet.port, length, address); + + return sockaddr_from_praddr(&addr, len); } -static CamelTcpAddress * -stream_get_remote_address (CamelTcpStream *stream) +static struct sockaddr * +stream_get_remote_address (CamelTcpStream *stream, socklen_t *len) { PRFileDesc *sockfd = CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd; - int family, length; - gpointer address; PRNetAddr addr; - PR_GetPeerName (sockfd, &addr); - - if (addr.inet.family == PR_AF_INET) { - family = CAMEL_TCP_ADDRESS_IPv4; - address = &addr.inet.ip; - length = sizeof (addr.inet.ip); -#ifdef ENABLE_IPv6 - } else if (addr.inet.family == PR_AF_INET6) { - family = CAMEL_TCP_ADDRESS_IPv6; - address = &addr.ipv6.ip; - length = sizeof (addr.ipv6.ip); -#endif - } else + if (PR_GetPeerName(sockfd, &addr) != PR_SUCCESS) return NULL; - - return camel_tcp_address_new (family, addr.inet.port, length, address); + + return sockaddr_from_praddr(&addr, len); } #endif /* HAVE_NSS */ diff --git a/camel/camel-tcp-stream.c b/camel/camel-tcp-stream.c index fbbcbec451..3aa2d0d368 100644 --- a/camel/camel-tcp-stream.c +++ b/camel/camel-tcp-stream.c @@ -35,12 +35,11 @@ static CamelStreamClass *parent_class = NULL; /* Returns the class for a CamelTcpStream */ #define CTS_CLASS(so) CAMEL_TCP_STREAM_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -static int tcp_connect (CamelTcpStream *stream, struct hostent *host, int port); +static int tcp_connect (CamelTcpStream *stream, struct addrinfo *host); static int tcp_getsockopt (CamelTcpStream *stream, CamelSockOptData *data); static int tcp_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data); -static CamelTcpAddress *tcp_get_local_address (CamelTcpStream *stream); -static CamelTcpAddress *tcp_get_remote_address (CamelTcpStream *stream); - +static struct sockaddr *tcp_get_local_address (CamelTcpStream *stream, socklen_t *len); +static struct sockaddr *tcp_get_remote_address (CamelTcpStream *stream, socklen_t *len); static void camel_tcp_stream_class_init (CamelTcpStreamClass *camel_tcp_stream_class) @@ -84,7 +83,7 @@ camel_tcp_stream_get_type (void) static int -tcp_connect (CamelTcpStream *stream, struct hostent *host, int port) +tcp_connect (CamelTcpStream *stream, struct addrinfo *host) { w(g_warning ("CamelTcpStream::connect called on default implementation")); return -1; @@ -93,22 +92,21 @@ tcp_connect (CamelTcpStream *stream, struct hostent *host, int port) /** * camel_tcp_stream_connect: * @stream: a CamelTcpStream object. - * @host: a hostent value - * @port: port + * @host: A linked list of addrinfo structures to try to connect, in + * the order of most likely to least likely to work. * * Create a socket and connect based upon the data provided. * * Return value: zero on success or -1 on fail. **/ int -camel_tcp_stream_connect (CamelTcpStream *stream, struct hostent *host, int port) +camel_tcp_stream_connect (CamelTcpStream *stream, struct addrinfo *host) { g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), -1); - return CTS_CLASS (stream)->connect (stream, host, port); + return CTS_CLASS (stream)->connect (stream, host); } - static int tcp_getsockopt (CamelTcpStream *stream, CamelSockOptData *data) { @@ -116,7 +114,6 @@ tcp_getsockopt (CamelTcpStream *stream, CamelSockOptData *data) return -1; } - /** * camel_tcp_stream_getsockopt: * @stream: tcp stream object @@ -134,7 +131,6 @@ camel_tcp_stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data) return CTS_CLASS (stream)->getsockopt (stream, data); } - static int tcp_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data) { @@ -142,7 +138,6 @@ tcp_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data) return -1; } - /** * camel_tcp_stream_setsockopt: * @stream: tcp stream object @@ -160,9 +155,8 @@ camel_tcp_stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *dat return CTS_CLASS (stream)->setsockopt (stream, data); } - -static CamelTcpAddress * -tcp_get_local_address (CamelTcpStream *stream) +static struct sockaddr * +tcp_get_local_address (CamelTcpStream *stream, socklen_t *len) { w(g_warning ("CamelTcpStream::get_local_address called on default implementation")); return NULL; @@ -171,23 +165,24 @@ tcp_get_local_address (CamelTcpStream *stream) /** * camel_tcp_stream_get_local_address: * @stream: tcp stream object + * @len: Pointer to address length which must be supplied. * * Get the local address of @stream. * * Return value: the stream's local address (which must be freed with - * camel_tcp_address_free()) if the stream is connected, or %NULL if not. + * g_free()) if the stream is connected, or %NULL if not. **/ -CamelTcpAddress * -camel_tcp_stream_get_local_address (CamelTcpStream *stream) +struct sockaddr * +camel_tcp_stream_get_local_address (CamelTcpStream *stream, socklen_t *len) { g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), NULL); + g_return_val_if_fail(len != NULL, NULL); - return CTS_CLASS (stream)->get_local_address (stream); + return CTS_CLASS (stream)->get_local_address (stream, len); } - -static CamelTcpAddress * -tcp_get_remote_address (CamelTcpStream *stream) +static struct sockaddr * +tcp_get_remote_address (CamelTcpStream *stream, socklen_t *len) { w(g_warning ("CamelTcpStream::get_remote_address called on default implementation")); return NULL; @@ -196,54 +191,18 @@ tcp_get_remote_address (CamelTcpStream *stream) /** * camel_tcp_stream_get_remote_address: * @stream: tcp stream object + * @len: Pointer to address length, which must be supplied. * * Get the remote address of @stream. * * Return value: the stream's remote address (which must be freed with - * camel_tcp_address_free()) if the stream is connected, or %NULL if not. + * g_free()) if the stream is connected, or %NULL if not. **/ -CamelTcpAddress * -camel_tcp_stream_get_remote_address (CamelTcpStream *stream) +struct sockaddr * +camel_tcp_stream_get_remote_address (CamelTcpStream *stream, socklen_t *len) { g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), NULL); - - return CTS_CLASS (stream)->get_remote_address (stream); -} + g_return_val_if_fail(len != NULL, NULL); - -/** - * camel_tcp_address_new: - * @family: the address family - * @port: the port number (in network byte order) - * @length: the length of @address - * @address: the address data (family dependent, in network byte order) - * - * Return value: a new CamelTcpAddress. - **/ -CamelTcpAddress * -camel_tcp_address_new (CamelTcpAddressFamily family, gushort port, - gushort length, gpointer address) -{ - CamelTcpAddress *addr; - - addr = g_malloc (sizeof (CamelTcpAddress) + length - 1); - addr->family = family; - addr->port = port; - addr->length = length; - memcpy (&addr->address, address, length); - - return addr; -} - - -/** - * camel_tcp_address_free: - * @address: the address - * - * Frees @address. - **/ -void -camel_tcp_address_free (CamelTcpAddress *address) -{ - g_free (address); + return CTS_CLASS (stream)->get_remote_address (stream, len); } diff --git a/camel/camel-tcp-stream.h b/camel/camel-tcp-stream.h index 9472da10ee..b7be61dbec 100644 --- a/camel/camel-tcp-stream.h +++ b/camel/camel-tcp-stream.h @@ -88,18 +88,6 @@ typedef struct _CamelSockOptData { } value; } CamelSockOptData; -typedef enum { - CAMEL_TCP_ADDRESS_IPv4, - CAMEL_TCP_ADDRESS_IPv6 -} CamelTcpAddressFamily; - -typedef struct { - CamelTcpAddressFamily family; - gushort port, length; - guint8 address[1]; -} CamelTcpAddress; - - struct _CamelTcpStream { CamelStream parent_object; @@ -109,29 +97,24 @@ typedef struct { CamelStreamClass parent_class; /* Virtual methods */ - int (*connect) (CamelTcpStream *stream, struct hostent *host, int port); + int (*connect) (CamelTcpStream *stream, struct addrinfo *host); int (*getsockopt) (CamelTcpStream *stream, CamelSockOptData *data); int (*setsockopt) (CamelTcpStream *stream, const CamelSockOptData *data); - CamelTcpAddress * (*get_local_address) (CamelTcpStream *stream); - CamelTcpAddress * (*get_remote_address) (CamelTcpStream *stream); + struct sockaddr * (*get_local_address) (CamelTcpStream *stream, socklen_t *len); + struct sockaddr * (*get_remote_address) (CamelTcpStream *stream, socklen_t *len); } CamelTcpStreamClass; /* Standard Camel function */ CamelType camel_tcp_stream_get_type (void); /* public methods */ -int camel_tcp_stream_connect (CamelTcpStream *stream, struct hostent *host, int port); +int camel_tcp_stream_connect (CamelTcpStream *stream, struct addrinfo *host); int camel_tcp_stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data); int camel_tcp_stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data); -CamelTcpAddress *camel_tcp_stream_get_local_address (CamelTcpStream *stream); -CamelTcpAddress *camel_tcp_stream_get_remote_address (CamelTcpStream *stream); - -CamelTcpAddress *camel_tcp_address_new (CamelTcpAddressFamily family, - gushort port, gushort length, - gpointer address); -void camel_tcp_address_free (CamelTcpAddress *address); +struct sockaddr *camel_tcp_stream_get_local_address (CamelTcpStream *stream, socklen_t *len); +struct sockaddr *camel_tcp_stream_get_remote_address (CamelTcpStream *stream, socklen_t *len); #ifdef __cplusplus } diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 85e8b8fc04..54340ca783 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -519,51 +519,60 @@ connect_to_server (CamelService *service, int ssl_mode, int try_starttls, CamelE CamelStream *tcp_stream; CamelSockOptData sockopt; gboolean force_imap4 = FALSE; - struct hostent *h; int clean_quit; - int port, ret; + int ret; char *buf; - - if (!(h = camel_service_gethost (service, ex))) - return FALSE; - - port = service->url->port ? service->url->port : 143; + struct addrinfo *ai, hints = { 0 }; + char *serv; + + /* FIXME: this connect stuff is duplicated everywhere */ + + if (service->url->port) { + serv = g_alloca(16); + sprintf(serv, "%d", service->url->port); + } else + serv = "imap"; if (ssl_mode != USE_SSL_NEVER) { #ifdef HAVE_SSL if (try_starttls) { tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); } else { - port = service->url->port ? service->url->port : 993; + if (service->url->port == 0) + serv = "imaps"; tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); } #else - if (!try_starttls) - port = service->url->port ? service->url->port : 993; + if (!try_starttls && service->url->port == 0) + serv = "imaps"; camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, _("SSL unavailable")); - - camel_free_host (h); - return FALSE; #endif /* HAVE_SSL */ } else { tcp_stream = camel_tcp_stream_raw_new (); } + + hints.ai_socktype = SOCK_STREAM; + ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); + if (ai == NULL) { + camel_object_unref(tcp_stream); + return FALSE; + } - ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port); - camel_free_host (h); + ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai); + camel_freeaddrinfo(ai); if (ret == -1) { if (errno == EINTR) camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled")); else camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, g_strerror (errno)); + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, g_strerror (errno)); camel_object_unref (tcp_stream); diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c index 6d8490d453..e1473f1de1 100644 --- a/camel/providers/nntp/camel-nntp-store.c +++ b/camel/providers/nntp/camel-nntp-store.c @@ -162,9 +162,10 @@ connect_to_server (CamelService *service, int ssl_mode, CamelException *ex) gboolean retval = FALSE; unsigned char *buf; unsigned int len; - struct hostent *h; - int port, ret; + int ret; char *path; + struct addrinfo *ai, hints = { 0 }; + char *serv; CAMEL_NNTP_STORE_LOCK(store, command_lock); @@ -181,15 +182,17 @@ connect_to_server (CamelService *service, int ssl_mode, CamelException *ex) camel_data_cache_set_expire_age (store->cache, 60*60*24*14); camel_data_cache_set_expire_access (store->cache, 60*60*24*5); } - - if (!(h = camel_service_gethost (service, ex))) - goto fail; - - port = service->url->port ? service->url->port : NNTP_PORT; + + if (service->url->port) { + serv = g_alloca(16); + sprintf(serv, "%d", service->url->port); + } else + serv = "nntp"; #ifdef HAVE_SSL if (ssl_mode != USE_SSL_NEVER) { - port = service->url->port ? service->url->port : NNTPS_PORT; + if (service->url->port == 0) + serv = "nntps"; tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3); } else { tcp_stream = camel_tcp_stream_raw_new (); @@ -197,17 +200,24 @@ connect_to_server (CamelService *service, int ssl_mode, CamelException *ex) #else tcp_stream = camel_tcp_stream_raw_new (); #endif /* HAVE_SSL */ + + hints.ai_socktype = SOCK_STREAM; + ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); + if (ai == NULL) { + camel_object_unref(tcp_stream); + goto fail; + } - ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port); - camel_free_host (h); + ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai); + camel_freeaddrinfo(ai); if (ret == -1) { if (errno == EINTR) camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled")); else camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, g_strerror (errno)); + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, g_strerror (errno)); camel_object_unref (tcp_stream); diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c index a63aa137e1..4e5c2baace 100644 --- a/camel/providers/pop3/camel-pop3-store.c +++ b/camel/providers/pop3/camel-pop3-store.c @@ -149,52 +149,59 @@ connect_to_server (CamelService *service, int ssl_mode, int try_starttls, CamelE CamelPOP3Store *store = CAMEL_POP3_STORE (service); CamelStream *tcp_stream; CamelPOP3Command *pc; - struct hostent *h; guint32 flags = 0; int clean_quit; - int ret, port; - - h = camel_service_gethost (service, ex); - if (!h) - return FALSE; - - port = service->url->port ? service->url->port : 110; - + int ret; + struct addrinfo *ai, hints = { 0 }; + char *serv; + + if (service->url->port) { + serv = g_alloca(16); + sprintf(serv, "%d", service->url->port); + } else + serv = "pop3"; + if (ssl_mode != USE_SSL_NEVER) { #ifdef HAVE_SSL if (try_starttls) { tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); } else { - port = service->url->port ? service->url->port : 995; + if (service->url->port == 0) + serv = "pop3s"; tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); } #else - if (!try_starttls) - port = service->url->port ? service->url->port : 995; + if (!try_starttls && service->url->port == 0) + serv = "pop3s"; camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, _("SSL unavailable")); - camel_free_host (h); - return FALSE; #endif /* HAVE_SSL */ } else { tcp_stream = camel_tcp_stream_raw_new (); } + + hints.ai_socktype = SOCK_STREAM; + ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); + if (ai == NULL) { + camel_object_unref(tcp_stream); + return FALSE; + } - ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port); - camel_free_host (h); + ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai); + camel_freeaddrinfo(ai); if (ret == -1) { if (errno == EINTR) camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled")); else camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to POP server %s (port %d): %s"), - service->url->host, port, g_strerror (errno)); + _("Could not connect to POP server %s (port %s): %s"), + service->url->host, serv, g_strerror (errno)); camel_object_unref (tcp_stream); @@ -212,8 +219,8 @@ connect_to_server (CamelService *service, int ssl_mode, int try_starttls, CamelE if (!(store->engine = camel_pop3_engine_new (tcp_stream, flags))) { camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to read a valid greeting from POP server %s (port %d)"), - service->url->host, port); + _("Failed to read a valid greeting from POP server %s (port %s)"), + service->url->host, serv); return FALSE; } diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c index 53a2d2cb68..c3a9e9ed15 100644 --- a/camel/providers/smtp/camel-smtp-transport.c +++ b/camel/providers/smtp/camel-smtp-transport.c @@ -237,53 +237,60 @@ connect_to_server (CamelService *service, int try_starttls, CamelException *ex) CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service); CamelStream *tcp_stream; char *respbuf = NULL; - struct hostent *h; - int port, ret; + int ret; + struct addrinfo *ai, hints = { 0 }; + char *serv; if (!CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex)) return FALSE; - h = camel_service_gethost (service, ex); - if (!h) - return FALSE; - /* set some smtp transport defaults */ transport->flags &= CAMEL_SMTP_TRANSPORT_USE_SSL; /* reset all but ssl flags */ transport->authtypes = NULL; - - port = service->url->port ? service->url->port : SMTP_PORT; + + if (service->url->port) { + serv = g_alloca(16); + sprintf(serv, "%d", service->url->port); + } else + serv = "smtp"; if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL) { #ifdef HAVE_SSL if (try_starttls) { tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); } else { - port = service->url->port ? service->url->port : 465; + if (service->url->port == 0) + serv = "smtps"; tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); } #else - if (!try_starttls) - port = service->url->port ? service->url->port : 465; + if (!try_starttls && service->url->port == 0) + serv = "smtps"; camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, _("SSL unavailable")); - - camel_free_host (h); - + return FALSE; #endif /* HAVE_SSL */ } else { tcp_stream = camel_tcp_stream_raw_new (); } + + hints.ai_socktype = SOCK_STREAM; + ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); + if (ai == NULL) { + camel_object_unref(tcp_stream); + return FALSE; + } - ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port); - camel_free_host (h); + ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai); + camel_freeaddrinfo(ai); if (ret == -1) { camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s (port %d): %s"), - service->url->host, port, + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, g_strerror (errno)); camel_object_unref (tcp_stream); @@ -294,7 +301,7 @@ connect_to_server (CamelService *service, int try_starttls, CamelException *ex) transport->connected = TRUE; /* get the localaddr - needed later by smtp_helo */ - transport->localaddr = camel_tcp_stream_get_local_address (CAMEL_TCP_STREAM (tcp_stream)); + transport->localaddr = camel_tcp_stream_get_local_address (CAMEL_TCP_STREAM (tcp_stream), &transport->localaddrlen); transport->ostream = tcp_stream; transport->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ); @@ -580,7 +587,7 @@ smtp_disconnect (CamelService *service, gboolean clean, CamelException *ex) transport->ostream = NULL; } - camel_tcp_address_free (transport->localaddr); + g_free(transport->localaddr); transport->localaddr = NULL; transport->connected = FALSE; @@ -865,10 +872,7 @@ smtp_helo (CamelSmtpTransport *transport, CamelException *ex) { /* say hello to the server */ char *name = NULL, *cmdbuf = NULL, *respbuf = NULL; - struct hostent *host; - CamelException err; const char *token; - int af; /* these are flags that we set, so unset them in case we are being called a second time (ie, after a STARTTLS) */ @@ -883,42 +887,10 @@ smtp_helo (CamelSmtpTransport *transport, CamelException *ex) } camel_operation_start_transient (NULL, _("SMTP Greeting")); - - /* get the local host name */ - camel_exception_init (&err); -#ifdef ENABLE_IPv6 - af = transport->localaddr->family == CAMEL_TCP_ADDRESS_IPv6 ? AF_INET6 : AF_INET; -#else - af = AF_INET; -#endif - host = camel_gethostbyaddr ((char *) &transport->localaddr->address, - transport->localaddr->length, af, &err); - - camel_exception_clear (&err); - - if (host && host->h_name && *host->h_name) { - name = g_strdup (host->h_name); - } else { -#ifdef ENABLE_IPv6 - char ip[MAXHOSTNAMELEN + 1]; - const char *proto; - - proto = transport->localaddr->family == CAMEL_TCP_ADDRESS_IPv6 ? "IPv6:" : ""; - name = g_strdup_printf ("[%s%s]", proto, inet_ntop (af, transport->localaddr->address, ip, MAXHOSTNAMELEN)); -#else - /* We *could* use inet_ntoa() here, but it's probably - not worth it since we would have to worry about - some systems not having inet_ntoa() */ - name = g_strdup_printf ("[%d.%d.%d.%d]", - transport->localaddr->address[0], - transport->localaddr->address[1], - transport->localaddr->address[2], - transport->localaddr->address[3]); -#endif - } - - if (host) - camel_free_host (host); + + /* this can't really fail with the flags we're using, it should fallback to numerical */ + if (camel_getnameinfo(transport->localaddr, transport->localaddrlen, &name, NULL, 0, NULL) != 0) + name = g_strdup("localhost.localdomain"); /* hiya server! how are you today? */ if (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) diff --git a/camel/providers/smtp/camel-smtp-transport.h b/camel/providers/smtp/camel-smtp-transport.h index ef15f2b07d..87fcafb58b 100644 --- a/camel/providers/smtp/camel-smtp-transport.h +++ b/camel/providers/smtp/camel-smtp-transport.h @@ -22,17 +22,14 @@ * USA */ - #ifndef CAMEL_SMTP_TRANSPORT_H #define CAMEL_SMTP_TRANSPORT_H 1 - #ifdef __cplusplus extern "C" { #pragma } #endif /* __cplusplus */ - #include "camel-transport.h" #include "camel-tcp-stream.h" @@ -41,7 +38,6 @@ extern "C" { #define CAMEL_SMTP_TRANSPORT_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SMTP_TRANSPORT_TYPE, CamelSmtpTransportClass)) #define CAMEL_IS_SMTP_TRANSPORT(o) (CAMEL_CHECK_TYPE((o), CAMEL_SMTP_TRANSPORT_TYPE)) - #define CAMEL_SMTP_TRANSPORT_IS_ESMTP (1 << 0) #define CAMEL_SMTP_TRANSPORT_8BITMIME (1 << 1) #define CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES (1 << 2) @@ -63,20 +59,17 @@ typedef struct { guint32 flags; gboolean connected; - CamelTcpAddress *localaddr; + struct sockaddr *localaddr; + socklen_t localaddrlen; GHashTable *authtypes; - } CamelSmtpTransport; - - typedef struct { CamelTransportClass parent_class; } CamelSmtpTransportClass; - /* Standard Camel function */ CamelType camel_smtp_transport_get_type (void); @@ -85,5 +78,3 @@ CamelType camel_smtp_transport_get_type (void); #endif /* __cplusplus */ #endif /* CAMEL_SMTP_TRANSPORT_H */ - - |