aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog32
-rw-r--r--camel/camel-http-stream.c29
-rw-r--r--camel/camel-mime-utils.c26
-rw-r--r--camel/camel-sasl-digest-md5.c22
-rw-r--r--camel/camel-sasl-gssapi.c14
-rw-r--r--camel/camel-sasl-kerberos4.c14
-rw-r--r--camel/camel-service.c582
-rw-r--r--camel/camel-service.h61
-rw-r--r--camel/camel-tcp-stream-raw.c147
-rw-r--r--camel/camel-tcp-stream-ssl.c160
-rw-r--r--camel/camel-tcp-stream.c89
-rw-r--r--camel/camel-tcp-stream.h29
-rw-r--r--camel/providers/imap/camel-imap-store.c47
-rw-r--r--camel/providers/nntp/camel-nntp-store.c34
-rw-r--r--camel/providers/pop3/camel-pop3-store.c51
-rw-r--r--camel/providers/smtp/camel-smtp-transport.c94
-rw-r--r--camel/providers/smtp/camel-smtp-transport.h13
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 */
-
-