summaryrefslogtreecommitdiff
path: root/libmailutils/stream/tcp.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-03-30 00:49:43 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-03-30 15:51:47 +0300
commitadca074d616ac562095a92e01f2b181e6d3593c8 (patch)
treef4c11a1c11fcb137cfada7643e6f284465a75c16 /libmailutils/stream/tcp.c
parent827cb66a4c639139c3f11c7af26aa5149f25a7e0 (diff)
downloadmailutils-adca074d616ac562095a92e01f2b181e6d3593c8.tar.gz
mailutils-adca074d616ac562095a92e01f2b181e6d3593c8.tar.bz2
Implement IPv6 support.
* am/ipv6.m4: New file. * examples/sa.c: New file. * include/mailutils/cidr.h: New file. * include/mailutils/sockaddr.h: New file. * libmailutils/cidr/Makefile.am: New file. * libmailutils/cidr/fromsa.c: New file. * libmailutils/cidr/fromstr.c: New file. * libmailutils/cidr/match.c: New file. * libmailutils/cidr/tosa.c: New file. * libmailutils/cidr/tostr.c: New file. * libmailutils/sockaddr/Makefile.am: New file. * libmailutils/sockaddr/copy.c: New file. * libmailutils/sockaddr/create.c: New file. * libmailutils/sockaddr/free.c: New file. * libmailutils/sockaddr/fromnode.c: New file. * libmailutils/sockaddr/insert.c: New file. * libmailutils/sockaddr/ipaddr.c: New file. * libmailutils/sockaddr/str.c: New file. * libmailutils/sockaddr/unlink.c: New file. * libmailutils/sockaddr/url.c: New file. * libmailutils/tests/cidr.c: New file. * configure.ac: Call MU_ENABLE_IPV6. Build libmailutils/sockaddr and libmailutils/cidr. * examples/.gitignore: Add mblconv and sa * examples/Makefile.am: (noinst_PROGRAMS): Add sa. * examples/aclck.c: Use new ACL API. * examples/echosrv.c: Use new mserv API. * include/mailutils/Makefile.am (pkginclude_HEADERS): Add cidr.h and sockaddr.h * include/mailutils/acl.h (mu_acl_append, mu_acl_prepend) (mu_acl_insert): Change signatures. * include/mailutils/debug.h (mu_sockaddr_to_str): Remove proto. * include/mailutils/mailutils.h: Include cidr.h and sockaddr.h * include/mailutils/server.h (mu_ip_server_create): Change signature. (mu_ip_server_get_sockaddr): Likewise. (mu_m_server_set_default_address) (mu_m_server_get_default_address): Remove. * include/mailutils/stream.h (mu_tcp_stream_create_from_sa): New proto. * include/mailutils/types.hin (mu_cidr, mu_sockaddr): New structs. * include/mailutils/url.h (MU_URL_IPV6): New flag. (MU_URL_PARSE_DSLASH_OPTIONAL): New parse flag. * libmailutils/Makefile.am: Descend into cidr and sockaddr. Link in libcidr and libsockaddr. * libmailutils/diag/debug.c (mu_debug_log_begin): Flush mu_strerr. * libmailutils/diag/errors (MU_ERR_NONAME) (MU_ERR_BADFLAGS,MU_ERR_SOCKTYPE) (MU_ERR_FAMILY,MU_ERR_SERVICE): New errors. * libmailutils/server/acl.c: Rewrite API using mu_cidr. * libmailutils/server/ipsrv.c: Rewrite AI using mu_sockaddr. * libmailutils/server/msrv.c: Likewise. * libmailutils/stream/tcp.c: Likewise. * libmailutils/tests/.gitignore: Add cidr. * libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add cidr. * libmailutils/tests/url-parse.c: Support command line options to tune the parsing. * libmailutils/tests/url.at: Pass options to url-parse. * libmailutils/url/create.c (getkn): Return meaningful error code. (_mu_url_ctx_parse_host): Accept IPv6 addresses. Set the MU_URL_IPV6 flag if one is given. (_mu_url_ctx_parse): Unless MU_URL_PARSE_DSLASH_OPTIONAL flag is given, request :// after scheme part. (mu_url_create): Add MU_URL_PARSE_DSLASH_OPTIONAL flag. * libmu_cfg/acl.c: Use new ACL API. * mu/acl.c: Likewise. * libproto/mailer/smtp.c (smtp_open): Use mu_tcp_stream_create_from_sa * libproto/pop/mbox.c (pop_open): Likewise. * mu/imap.c (com_connect): Likewise. * mu/pop.c (com_connect): Likewise. * testsuite/smtpsend.c (main): Likewise.
Diffstat (limited to 'libmailutils/stream/tcp.c')
-rw-r--r--libmailutils/stream/tcp.c178
1 files changed, 96 insertions, 82 deletions
diff --git a/libmailutils/stream/tcp.c b/libmailutils/stream/tcp.c
index 40b37124d..f383f1b5a 100644
--- a/libmailutils/stream/tcp.c
+++ b/libmailutils/stream/tcp.c
@@ -39,7 +39,7 @@
#include <mailutils/errno.h>
#include <mailutils/stream.h>
#include <mailutils/util.h>
-
+#include <mailutils/sockaddr.h>
#include <mailutils/sys/stream.h>
#define TCP_STATE_INIT 1
@@ -52,18 +52,11 @@ struct _tcp_instance
{
struct _mu_stream stream;
int fd;
- char *host;
- unsigned short port;
int state;
- unsigned long address;
- unsigned long source_addr;
+ struct mu_sockaddr *remote_addr;
+ struct mu_sockaddr *source_addr;
};
-/* On solaris inet_addr() return -1. */
-#ifndef INADDR_NONE
-# define INADDR_NONE (unsigned long)-1
-#endif
-
static int
_tcp_close (mu_stream_t stream)
{
@@ -83,28 +76,12 @@ _tcp_close (mu_stream_t stream)
}
static int
-resolve_hostname (const char *host, unsigned long *ip)
-{
- unsigned long address = inet_addr (host);
- if (address == INADDR_NONE)
- {
- struct hostent *phe = gethostbyname (host);
- if (!phe)
- return MU_ERR_GETHOSTBYNAME;
- address = *(((unsigned long **) phe->h_addr_list)[0]);
- }
- *ip = address;
- return 0;
-}
-
-static int
_tcp_open (mu_stream_t stream)
{
struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
int flgs, ret;
socklen_t namelen;
struct sockaddr_in peer_addr;
- struct sockaddr_in soc_addr;
int flags;
mu_stream_get_flags (stream, &flags);
@@ -114,7 +91,8 @@ _tcp_open (mu_stream_t stream)
case TCP_STATE_INIT:
if (tcp->fd == -1)
{
- if ((tcp->fd = socket (PF_INET, SOCK_STREAM, 0)) == -1)
+ tcp->fd = socket (tcp->remote_addr->addr->sa_family, SOCK_STREAM, 0);
+ if (tcp->fd == -1)
return errno;
}
if (flags & MU_STREAM_NONBLOCK)
@@ -124,13 +102,10 @@ _tcp_open (mu_stream_t stream)
fcntl (tcp->fd, F_SETFL, flgs);
mu_stream_set_flags (stream, MU_STREAM_NONBLOCK);
}
- if (tcp->source_addr != INADDR_ANY)
+ if (tcp->source_addr)
{
- struct sockaddr_in s;
- s.sin_family = AF_INET;
- s.sin_addr.s_addr = tcp->source_addr;
- s.sin_port = 0;
- if (bind (tcp->fd, (struct sockaddr*) &s, sizeof(s)) < 0)
+ if (bind (tcp->fd, tcp->source_addr->addr,
+ tcp->source_addr->addrlen) < 0)
{
int e = errno;
close (tcp->fd);
@@ -142,27 +117,11 @@ _tcp_open (mu_stream_t stream)
tcp->state = TCP_STATE_RESOLVING;
case TCP_STATE_RESOLVING:
- if (!(tcp->host != NULL && tcp->port > 0))
- {
- _tcp_close (stream);
- return EINVAL;
- }
-
- if ((ret = resolve_hostname (tcp->host, &tcp->address)))
- {
- _tcp_close (stream);
- return ret;
- }
tcp->state = TCP_STATE_RESOLVE;
case TCP_STATE_RESOLVE:
- memset (&soc_addr, 0, sizeof (soc_addr));
- soc_addr.sin_family = AF_INET;
- soc_addr.sin_port = htons (tcp->port);
- soc_addr.sin_addr.s_addr = tcp->address;
-
- if ((connect (tcp->fd,
- (struct sockaddr *) &soc_addr, sizeof (soc_addr))) == -1)
+ if (connect (tcp->fd, tcp->remote_addr->addr,
+ tcp->remote_addr->addrlen) == -1)
{
ret = errno;
if (ret == EINPROGRESS || ret == EAGAIN)
@@ -254,10 +213,8 @@ _tcp_done (mu_stream_t stream)
{
struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
- if (tcp->host)
- free (tcp->host);
- if (tcp->fd != -1)
- close (tcp->fd);
+ mu_sockaddr_free (tcp->remote_addr);
+ mu_sockaddr_free (tcp->source_addr);
}
int
@@ -315,33 +272,21 @@ _create_tcp_stream (int flags)
}
int
-mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
- const char *host, unsigned port,
- unsigned long source_ip,
- int flags)
+mu_tcp_stream_create_from_sa (mu_stream_t *pstream,
+ struct mu_sockaddr *remote_addr,
+ struct mu_sockaddr *source_addr, int flags)
{
int rc;
mu_stream_t stream;
struct _tcp_instance *tcp;
- if (host == NULL)
- return MU_ERR_TCP_NO_HOST;
-
- if (port > USHRT_MAX)
- return MU_ERR_TCP_NO_PORT;
-
tcp = _create_tcp_stream (flags | MU_STREAM_RDWR);
if (!tcp)
return ENOMEM;
- tcp->host = strdup (host);
- if (!tcp->host)
- {
- free (tcp);
- return ENOMEM;
- }
- tcp->port = port;
- tcp->state = TCP_STATE_INIT;
- tcp->source_addr = source_ip;
+
+ tcp->remote_addr = remote_addr;
+ tcp->source_addr = source_addr;
+
stream = (mu_stream_t) tcp;
rc = mu_stream_open (stream);
if (rc == 0 || rc == EAGAIN || rc == EINPROGRESS)
@@ -351,24 +296,93 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
return rc;
}
+
+int
+mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
+ const char *host, unsigned port,
+ unsigned long source_ip,
+ int flags)
+{
+ int rc;
+ struct mu_sockaddr *remote_addr, *source_addr = NULL;
+ struct mu_sockaddr_hints hints;
+
+ memset (&hints, 0, sizeof hints);
+ hints.family = AF_INET;
+ hints.socktype = SOCK_STREAM;
+ hints.protocol = IPPROTO_TCP;
+ hints.port = port;
+ rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
+ if (rc)
+ return rc;
+
+ if (source_ip)
+ {
+ struct sockaddr_in s;
+ s.sin_family = AF_INET;
+ s.sin_addr.s_addr = source_ip;
+ s.sin_port = 0;
+ rc = mu_sockaddr_create (&source_addr, (struct sockaddr*)&s,
+ sizeof (s));
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ return 0;
+ }
+ }
+
+ rc = mu_tcp_stream_create_from_sa (pstream, remote_addr, source_addr, flags);
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ mu_sockaddr_free (source_addr);
+ }
+ return rc;
+}
+
int
mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
const char *host, unsigned port,
const char *source_host,
int flags)
{
- unsigned long source_addr;
- int ret = resolve_hostname (source_host, &source_addr);
- if (ret == 0)
- ret = mu_tcp_stream_create_with_source_ip (stream, host, port,
- source_addr, flags);
- return ret;
+ int rc;
+ struct mu_sockaddr *remote_addr, *source_addr = NULL;
+ struct mu_sockaddr_hints hints;
+
+ memset (&hints, 0, sizeof hints);
+ hints.family = AF_INET;
+ hints.socktype = SOCK_STREAM;
+ hints.port = port;
+ rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
+ if (rc)
+ return rc;
+
+ if (source_host)
+ {
+ hints.flags = MU_AH_PASSIVE;
+ hints.port = 0;
+ rc = mu_sockaddr_from_node (&source_addr, source_host, NULL, &hints);
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ return 0;
+ }
+ }
+
+ rc = mu_tcp_stream_create_from_sa (stream, remote_addr, source_addr, flags);
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ mu_sockaddr_free (source_addr);
+ }
+ return rc;
}
int
mu_tcp_stream_create (mu_stream_t *stream, const char *host, unsigned port,
int flags)
{
- return mu_tcp_stream_create_with_source_ip (stream, host, port,
- INADDR_ANY, flags);
+ return mu_tcp_stream_create_with_source_host (stream, host, port,
+ NULL, flags);
}

Return to:

Send suggestions and report system problems to the System administrator.