Commit 0eab7f8a authored by Pekka Pessi's avatar Pekka Pessi

Added tpac_address field to the stack interface.

The function tpac_address is called whenever tport detects that its
addresses has changed.

darcs-hash:20060223201957-65a35-614c717f4fb1da1dd6329b517f522c68d0e19ece.gz
parent 148eb5bf
......@@ -102,6 +102,9 @@ typedef struct {
/** Ask stack to accept/reject early SigComp message */
int (*tpac_sigcomp_accept)(tp_stack_t *, tport_t *, msg_t *);
/** Indicate stack that address has changed */
void (*tpac_address)(tp_stack_t *, tport_t *);
} tport_stack_class_t;
/* Compatibility */
......@@ -119,16 +122,19 @@ enum {
/* AI extension flags - these must not overlap with existing AI flags. */
/** Message is to be sent/received compressed */
#define TP_AI_COMPRESSED 0x1000
#define TP_AI_COMPRESSED 0x01000
/** Message is to be sent/received on secure connection */
#define TP_AI_SECURE 0x02000
/** Halfclose (shutdown(c, 1)) connection after sending message */
#define TP_AI_SHUTDOWN 0x2000
#define TP_AI_SHUTDOWN 0x04000
/** Close connection (shutdown(c, 2)) after sending message */
#define TP_AI_CLOSE 0x4000
#define TP_AI_CLOSE 0x08000
/** Address was inaddr_any */
#define TP_AI_ANY 0x8000
#define TP_AI_ANY 0x80000
#define TP_AI_MASK 0xf000
#define TP_AI_MASK 0xff000
/** Maximum size of a @e host:port string, including final NUL. */
#define TPORT_HOSTPORTSIZE (55)
......
......@@ -630,11 +630,14 @@ static int init_test(tp_test_t *tt)
for (tp = tport_primaries(tt->tt_srv_tports); tp; tp = tport_next(tp)) {
TEST_1(tpn = tport_name(tp));
if (1 || tt->tt_flags & tst_verbatim)
printf("bound transport to %s/%s:%s;maddr=%s%s%s\n",
tpn->tpn_proto, tpn->tpn_canon, tpn->tpn_port, tpn->tpn_host,
if (1 || tt->tt_flags & tst_verbatim) {
char const *host = tpn->tpn_host != tpn->tpn_canon ? tpn->tpn_host : "";
printf("bound transport to %s/%s:%s%s%s%s%s\n",
tpn->tpn_proto, tpn->tpn_canon, tpn->tpn_port,
host[0] ? ";maddr=" : "", host,
tpn->tpn_comp ? ";comp=" : "",
tpn->tpn_comp ? tpn->tpn_comp : "");
}
/* Ignore server2 tports for now */
if (strcmp(tpn->tpn_ident, "server"))
......
......@@ -136,6 +136,9 @@ typedef struct _tls_t tls_t; /* dummy */
#define MSG_NOSIGNAL (0)
#endif
/* Number of supported transports */
#define TPORT_N (8)
#if HAVE_SOFIA_STUN
#include "sofia-sip/stun.h"
#include "sofia-sip/stun_tag.h"
......@@ -264,8 +267,10 @@ struct tport_s {
su_socket_t tp_socket; /**< Socket of this tport*/
int tp_index; /**< Root registration index */
int tp_events; /**< Subscribed events */
int tp_addrlen; /**< Size fo tp_addr */
su_sockaddr_t tp_addr[1]; /**< Peer address */
su_addrinfo_t tp_addrinfo[1]; /**< Peer/own address info */
su_sockaddr_t tp_addr[1]; /**< Peer/own address */
#define tp_addrlen tp_addrinfo->ai_addrlen
#if HAVE_TLS
tls_t *tp_tls;
......@@ -333,12 +338,8 @@ struct tport_primary {
tport_threadpool_t *pri_threadpool; /**< Worker threads */
unsigned pri_thrpsize;
unsigned pri_family : 8; /**< Network family (INET/INET6) */
unsigned pri_socktype : 8; /**< Socket type */
unsigned pri_protocol : 8; /**< IP protocol number */
unsigned pri_natted:1; /**< Using natted address */
unsigned:0;
tport_params_t pri_params[1]; /**< Transport parameters */
......@@ -544,7 +545,7 @@ static inline int tp_cmp(tport_t const *a, tport_t const *b)
if (a->tp_addrlen != b->tp_addrlen)
return a->tp_addrlen - b->tp_addrlen;
return memcmp(a->tp_addr, b->tp_addr, sizeof(a->tp_addr));
return memcmp(a->tp_addr, b->tp_addr, a->tp_addrlen);
}
static inline int tprb_is_inserted(tport_t const *a)
......@@ -606,25 +607,25 @@ static inline int tport_is_registered(tport_t const *self)
/** Test if transport is stream. */
inline int tport_is_stream(tport_t const *self)
{
return self->tp_pri->pri_socktype == SOCK_STREAM;
return self->tp_addrinfo->ai_socktype == SOCK_STREAM;
}
/** Test if transport is dgram. */
static inline int tport_is_dgram(tport_t const *self)
{
return self->tp_pri->pri_socktype == SOCK_DGRAM;
return self->tp_addrinfo->ai_socktype == SOCK_DGRAM;
}
/** Test if transport is udp. */
inline int tport_is_udp(tport_t const *self)
{
return self->tp_pri->pri_protocol == IPPROTO_UDP;
return self->tp_addrinfo->ai_protocol == IPPROTO_UDP;
}
/** Test if transport is tcp. */
inline int tport_is_tcp(tport_t const *self)
{
return self->tp_pri->pri_protocol == IPPROTO_TCP;
return self->tp_addrinfo->ai_protocol == IPPROTO_TCP;
}
/** Test if transport is needs connect() before sending. */
......@@ -646,8 +647,8 @@ static inline int tport_is_connected(tport_t const *self)
int tport_is_reliable(tport_t const *self)
{
return self != NULL &&
(self->tp_pri->pri_socktype == SOCK_STREAM ||
self->tp_pri->pri_socktype == SOCK_SEQPACKET);
(self->tp_addrinfo->ai_socktype == SOCK_STREAM ||
self->tp_addrinfo->ai_socktype == SOCK_SEQPACKET);
}
......@@ -655,9 +656,8 @@ int tport_is_reliable(tport_t const *self)
int tport_has_ip4(tport_t const *self)
{
return self &&
(self->tp_pri->pri_family == 0 ||
self->tp_pri->pri_family == AF_INET
/* || self->tp_pri->pri_family2 == AF_INET */);
(self->tp_addrinfo->ai_family == 0 ||
self->tp_addrinfo->ai_family == AF_INET);
}
......@@ -666,7 +666,8 @@ int tport_has_ip4(tport_t const *self)
int tport_has_ip6(tport_t const *self)
{
return self &&
(self->tp_pri->pri_family == 0 || self->tp_pri->pri_family == AF_INET6);
(self->tp_addrinfo->ai_family == 0 ||
self->tp_addrinfo->ai_family == AF_INET6);
}
#endif
......@@ -778,21 +779,32 @@ int tport_nat_set_canon(tport_t *self, struct tport_nat_s *nat);
static
int tport_nat_finish(tport_primary_t *self);
#define PASSIVE PASSIVE
#define ACTIVE ACTIVE
enum socket_open { PASSIVE = 0, ACTIVE = 1 };
static
tport_t *tport_connect(tport_primary_t *pri, su_addrinfo_t *ai,
tp_name_t const *tpn);
static int bind6only_check(void);
static
int tport_server_addrinfo(tport_master_t *mr,
char const *canon,
int family,
char const *host,
char const *service,
char const *protocol,
char const * const transports[],
su_addrinfo_t **res);
static int tport_get_local_addrinfo(tport_master_t *mr,
su_localinfo_t *li,
char const *port,
su_addrinfo_t const *hints,
su_addrinfo_t **return_ai);
static void tport_freeaddrinfo(tport_master_t *mr, su_addrinfo_t *ai);
int tport_getaddrinfo(char const *node, char const *service,
su_addrinfo_t const *hints,
su_addrinfo_t **res);
static void tport_freeaddrinfo(su_addrinfo_t *ai);
#if HAVE_TLS
static tls_t *tport_init_tls(tagi_t *tags);
......@@ -807,7 +819,7 @@ static int
tport_init_compression(tport_primary_t *self, char const *compression,
tagi_t *tl),
tport_setname(tport_t *, char const *, su_sockaddr_t const *, char const *),
tport_setname(tport_t *, char const *, su_addrinfo_t const *, char const *),
tport_recv(su_root_magic_t *m, su_wait_t *w, tport_t *self),
tport_accept(su_root_magic_t *m, su_wait_t *w, tport_t *self),
tport_connected(su_root_magic_t *m, su_wait_t *w, tport_t *self),
......@@ -1100,6 +1112,8 @@ tport_primary_t *tport_alloc_primary(tport_master_t *mr)
memcpy(tp->tp_params, mr->mr_params, sizeof (*tp->tp_params));
tp->tp_reusable = mr->mr_master->tp_reusable;
tp->tp_addrinfo->ai_addr = &tp->tp_addr->su_sa;
SU_DEBUG_5(("%s(%p): new primary tport %p\n", __func__, mr, pri));
}
......@@ -1114,12 +1128,13 @@ tport_primary_t *tport_alloc_primary(tport_master_t *mr)
* registers the socket with suitable events to the root.
*
* @param dad parent (master or primary) transport object
* @param ai pointer to addrinfo structure
* @param ainfo pointer to addrinfo structure
* @param canon canonical name of node
* @param protoname name of the protocol
*/
static
tport_primary_t *tport_listen(tport_master_t *mr, su_addrinfo_t const *ai,
tport_primary_t *tport_listen(tport_master_t *mr,
su_addrinfo_t const *ainfo,
char const *canon, char const *protoname,
int port,
tagi_t *tags)
......@@ -1131,8 +1146,8 @@ tport_primary_t *tport_listen(tport_master_t *mr, su_addrinfo_t const *ai,
su_wakeup_f wakeup = NULL;
su_wait_t wait[1] = { SU_WAIT_INIT };
su_addrinfo_t ai[1];
su_sockaddr_t su[1];
socklen_t sulen = ai->ai_addrlen;
int err;
int errlevel = 3;
......@@ -1152,9 +1167,22 @@ tport_primary_t *tport_listen(tport_master_t *mr, su_addrinfo_t const *ai,
su_seterrno(err)), \
(void *)NULL)
if (sulen > sizeof(su))
if (ainfo->ai_addrlen > sizeof(su))
return NULL;
if (!(ainfo->ai_socktype == SOCK_STREAM ||
ainfo->ai_socktype == SOCK_SEQPACKET ||
ainfo->ai_socktype == SOCK_DGRAM)) {
assert(ainfo->ai_socktype == SOCK_STREAM ||
ainfo->ai_socktype == SOCK_SEQPACKET ||
ainfo->ai_socktype == SOCK_DGRAM);
return NULL;
memcpy(su, ai->ai_addr, sulen);
}
memcpy(ai, ainfo, sizeof ai);
ai->ai_addr = memcpy(su, ai->ai_addr, ai->ai_addrlen);
ai->ai_next = NULL;
if (port > 0)
su->su_port = htons(port);
......@@ -1163,9 +1191,6 @@ tport_primary_t *tport_listen(tport_master_t *mr, su_addrinfo_t const *ai,
pri = tport_alloc_primary(mr);
if (pri == NULL)
return TPORT_LISTEN_ERROR(errno, tport_alloc_primary);
pri->pri_family = ai->ai_family;
pri->pri_socktype = ai->ai_socktype;
pri->pri_protocol = ai->ai_protocol;
if (tport_set_params(pri->pri_primary, TAG_NEXT(tags)) < 0)
return TPORT_LISTEN_ERROR(su_errno(), tport_set_params);
......@@ -1198,21 +1223,33 @@ tport_primary_t *tport_listen(tport_master_t *mr, su_addrinfo_t const *ai,
if (!nat_bound /* || !mr->mr_nat->stun_enabled */) {
/* STUN has a problem or is not enabled */
if (bind(s, &su->su_sa, sulen) == SOCKET_ERROR) {
if (bind(s, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR) {
if (su_errno() == EADDRINUSE) errlevel = 7;
return TPORT_LISTEN_ERROR(su_errno(), bind);
}
if (getsockname(s, &su->su_sa, &sulen) == SOCKET_ERROR)
if (getsockname(s, ai->ai_addr, &ai->ai_addrlen) == SOCKET_ERROR)
return TPORT_LISTEN_ERROR(su_errno(), getsockname);
#if defined (__linux__) && defined (SU_HAVE_IN6)
if (ai->ai_family == AF_INET6) {
if (SU_SOCKADDR_INADDR_ANY(su))
/* pri->pri_family2 = AF_INET */ ;
else if (IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr) ||
IN6_IS_ADDR_V4COMPAT(&su->su_sin6.sin6_addr))
pri->pri_family = AF_INET;
if (!SU_SOCKADDR_INADDR_ANY(su) &&
(IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr) ||
IN6_IS_ADDR_V4COMPAT(&su->su_sin6.sin6_addr))) {
su_sockaddr_t su0[1];
memcpy(su0, su, sizeof su0);
memset(su, 0, ai->ai_addrlen = sizeof su->su_sin);
su->su_family = ai->ai_family = AF_INET;
su->su_port = su0->su_port;
#ifndef IN6_V4MAPPED_TO_INADDR
#define IN6_V4MAPPED_TO_INADDR(in6, in4) \
memcpy((in4), 12 + (uint8_t *)(in6), sizeof(struct in_addr))
#endif
IN6_V4MAPPED_TO_INADDR(&su0->su_sin6.sin6_addr, &su->su_sin.sin_addr);
}
}
#endif
}
......@@ -1234,7 +1271,8 @@ tport_primary_t *tport_listen(tport_master_t *mr, su_addrinfo_t const *ai,
*/
su_setreuseaddr(s, 1);
#endif
} else {
}
else /* if (ai->ai_socktype == SOCK_DGRAM) */ {
/* Connectionless protocols sendto() and recvfrom() messages */
wakeup = tport_recv; /* receiving function will be registered */
events = SU_WAIT_IN;
......@@ -1286,10 +1324,11 @@ tport_primary_t *tport_listen(tport_master_t *mr, su_addrinfo_t const *ai,
return TPORT_LISTEN_ERROR(su_errno(), su_wait_create);
/* Register receiving or accepting function with events specified above */
index = su_root_register(mr->mr_root, wait, wakeup, pri->pri_primary, 0);
index = su_root_register(mr->mr_root, wait, wakeup, pri->pri_primary, 0);
if (index == -1)
return TPORT_LISTEN_ERROR(su_errno(), su_root_register);
if (tport_setname(pri->pri_primary, protoname, su, canon) == -1)
if (tport_setname(pri->pri_primary, protoname, ai, canon) == -1)
return TPORT_LISTEN_ERROR(su_errno(), tport_setname);
pri->pri_primary->tp_socket = s;
......@@ -1297,8 +1336,6 @@ tport_primary_t *tport_listen(tport_master_t *mr, su_addrinfo_t const *ai,
pri->pri_primary->tp_events = events;
pri->pri_primary->tp_connected = 0;
pri->pri_primary->tp_conn_orient = ai->ai_socktype != SOCK_DGRAM;
pri->pri_primary->tp_addr[0] = su[0];
pri->pri_primary->tp_addrlen = sulen;
if (nat_bound) {
/* XXX - should set also the IP address in tp_addr? */
......@@ -1376,6 +1413,8 @@ tport_t *tport_alloc_secondary(tport_primary_t *pri)
self->tp_reusable = pri->pri_primary->tp_reusable;
self->tp_magic = pri->pri_primary->tp_magic;
self->tp_addrinfo->ai_addr = (void *)self->tp_addr;
}
return self;
......@@ -1484,9 +1523,8 @@ tport_t *tport_connect(tport_primary_t *pri,
if ((index = su_root_register(mr->mr_root, wait, wakeup, self, 0)) == -1)
TPORT_CONNECT_ERROR(su_errno(), su_root_register);
/* */
if (tport_setname(self, tpn->tpn_proto,
(void *)ai->ai_addr, tpn->tpn_canon) == -1)
/* Set sockname for the tport */
if (tport_setname(self, tpn->tpn_proto, ai, tpn->tpn_canon) == -1)
TPORT_CONNECT_ERROR(su_errno(), tport_setname);
self->tp_socket = s;
......@@ -1510,8 +1548,6 @@ tport_t *tport_connect(tport_primary_t *pri,
}
#endif
memcpy(self->tp_addr, ai->ai_addr, self->tp_addrlen = ai->ai_addrlen);
SU_DEBUG_5(("%s(%p): %s " TPN_FORMAT "\n",
__func__, self, "connecting to",
TPN_ARGS(self->tp_name)));
......@@ -1808,7 +1844,7 @@ int tport_bind_client(tport_master_t *mr,
;
for (i = 0; transports[i]; i++) {
su_addrinfo_t hints[1];
su_addrinfo_t *tpai, hints[1];
char const *proto = transports[i];
if (strcmp(proto, tpn->tpn_proto) != 0 &&
......@@ -1831,10 +1867,12 @@ int tport_bind_client(tport_master_t *mr,
break;
}
#endif
tpai = tp->tp_addrinfo;
pri->pri_family = hints->ai_family;
pri->pri_socktype = hints->ai_socktype;
pri->pri_protocol = hints->ai_protocol;
tpai->ai_flags = TP_AI_MASK & hints->ai_flags;
tpai->ai_family = hints->ai_family;
tpai->ai_socktype = hints->ai_socktype;
tpai->ai_protocol = hints->ai_protocol;
tp->tp_name->tpn_proto = proto;
tp->tp_name->tpn_host = "*";
......@@ -1842,6 +1880,8 @@ int tport_bind_client(tport_master_t *mr,
tp->tp_name->tpn_canon = "*";
tp->tp_name->tpn_ident = su_strdup(tp->tp_home, tpn->tpn_ident);
tpai->ai_canonname = "*";
tport_init_compression(pri, tpn->tpn_comp, tags);
}
......@@ -1858,52 +1898,23 @@ int tport_bind_server(tport_master_t *mr,
tagi_t *tags)
{
char hostname[256];
char const *proto, *canon = NULL, *host, *port;
char port0[16];
int ephemeral_port;
int i, error = 0, not_supported, family = 0;
char const *canon = NULL, *host, *service;
int error = 0, not_supported, family = 0;
tport_primary_t *pri = NULL, **tbf;
su_localinfo_t *li = NULL;
unsigned p;
su_addrinfo_t *ai, *res = NULL;
unsigned port, port0, port1, old;
unsigned short step = 0;
struct tport_nat_s *nat;
#if SU_HAVE_IN6
if (!mr->mr_boundserver) {
/* Check if we can bind to IPv6 separately */
su_sockaddr_t su[1], su4[1];
socklen_t sulen, su4len;
int s6, s4;
s4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
s6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
memset(su, 0, sizeof *su);
su->su_len = sulen = (sizeof su->su_sin6);
su->su_family = AF_INET6;
memset(su4, 0, sizeof *su4);
su4->su_len = su4len = (sizeof su->su_sin);
su4->su_family = AF_INET;
if (bind(s6, &su->su_sa, sulen) < 0)
;
else if (getsockname(s6, &su->su_sa, &sulen) < 0)
;
else if ((su4->su_port = su->su_port) != 0 &&
bind(s4, &su4->su_sa, su4len) == 0)
mr->mr_bindv6only = 1;
su_close(s6), su_close(s4);
mr->mr_boundserver = 1;
/* Check if we can bind to IPv6 separately */
mr->mr_bindv6only = bind6only_check();
}
#endif
for (tbf = &mr->mr_primaries; *tbf; tbf = &(*tbf)->pri_next)
;
SU_DEBUG_5(("%s(%p) to " TPN_FORMAT "\n", __func__, mr, TPN_ARGS(tpn)));
nat = tport_nat_initialize_nat_traversal(mr, tpn, &transports, tags);
......@@ -1926,9 +1937,9 @@ int tport_bind_server(tport_master_t *mr,
if (tpn->tpn_port != NULL && strlen(tpn->tpn_port) > 0 &&
strcmp(tpn->tpn_port, tpn_any) != 0)
port = tpn->tpn_port, ephemeral_port = 0;
service = tpn->tpn_port;
else
port = "", ephemeral_port = -1; /* XXX */
service = "";
if (host && (strcmp(host, "0.0.0.0") == 0 || strcmp(host, "0") == 0))
host = NULL, family = AF_INET;
......@@ -1945,175 +1956,93 @@ int tport_bind_server(tport_master_t *mr,
canon = tport_nat_get_external_ip_address(nat);
}
if (host == NULL) {
su_localinfo_t hints[1] = {{ 0 }};
hints->li_flags = 0;
hints->li_family = family;
hints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE | LI_SCOPE_HOST;
if (tport_server_addrinfo(mr, canon, family,
host, service, tpn->tpn_proto,
transports, &res) < 0)
return -1;
error = su_getlocalinfo(hints, &li);
if (error) {
#if SU_HAVE_IN6
SU_DEBUG_3(("%s(%p): su_getlocalinfo() for %s address: %s\n",
__func__, mr,
family == AF_INET6 ? "ip6"
: family == AF_INET ? "ip4" : "ip",
su_gli_strerror(error)));
#else
SU_DEBUG_3(("%s(%p): su_getlocalinfo() for %s address: %s\n",
__func__, mr,
family == AF_INET ? "ip4" : "ip",
su_gli_strerror(error)));
#endif
su_seterrno(ENOENT);
return -1;
}
}
for (tbf = &mr->mr_primaries; *tbf; tbf = &(*tbf)->pri_next)
;
port = port0 = port1 = ntohs(((su_sockaddr_t *)res->ai_addr)->su_port);
error = ENOENT, not_supported = 1;
/*
* Loop until we can bind all the transports requested by the protocol to
* the same port.
*/
do {
not_supported = 1; /* Make sure we don't loop for ever */
pri = NULL;
for (i = 0; transports[i]; i++) {
su_addrinfo_t *ai, *res, hints[1];
int tried = 0;
proto = transports[i];
error = EPROTONOSUPPORT;
if (strcasecmp(proto, tpn->tpn_proto) != 0 &&
strcmp(tpn->tpn_proto, tpn_any) != 0)
continue;
/* Resolve protocol, skip unknown transport protocols. */
if (getprotohints(hints, proto, AI_PASSIVE) < 0)
continue;
hints->ai_family = family;
if (host == NULL)
hints->ai_flags |= AI_NUMERICHOST;
for (;;) {
for (ai = res; ai; ai = ai->ai_next) {
SU_DEBUG_9(("%s(%p): calling tport_listen\n", __func__, mr));
pri = NULL;
((su_sockaddr_t *)ai->ai_addr)->su_port = htons(port);
if (host)
error = su_getaddrinfo(host, port, hints, &res);
else
error = tport_get_local_addrinfo(mr, li, port, hints, &res);
if (error || !res) {
if (error == EAI_SOCKTYPE)
SU_DEBUG_7(("%s(%p): su_getaddrinfo(%s, %s) for %s: %s\n",
__func__, mr, host ? host : "\"\"", port, proto,
su_gai_strerror(error)));
else
SU_DEBUG_3(("%s(%p): su_getaddrinfo(%s, %s) for %s: %s\n",
__func__, mr, host ? host : "\"\"", port, proto,
su_gai_strerror(error)));
error = ENOENT;
continue;
pri = tport_listen(mr, ai, canon, ai->ai_canonname, port, tags);
if (!pri) {
switch (error = su_errno()) {
case EADDRNOTAVAIL: /* Not our address */
case ENOPROTOOPT: /* Protocol not supported */
case ESOCKTNOSUPPORT: /* Socket type not supported */
continue;
default:
break;
}
break;
}
p = ntohs(((su_sockaddr_t *)res->ai_addr)->su_port);
pri->pri_primary->tp_ident = su_strdup(pri->pri_home, tpn->tpn_ident);
tport_init_compression(pri, tpn->tpn_comp, tags);
not_supported = 0;
for (ai = res; ai; ai = ai->ai_next) {
/* Skip non-internet (AF_LOCAL) addresses */
#if SU_HAVE_IN6
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
#else
if (ai->ai_family != AF_INET)
continue;
#if HAVE_TLS
if (strcasecmp(tpn->tpn_proto, "tls") == 0) {
pri->pri_primary->tp_tls = tport_init_tls(tags);
if (!pri->pri_primary->tp_tls) {
error = su_errno();
break;
}
}
#endif
SU_DEBUG_9(("%s(%p): calling tport_socket\n", __func__, mr));
ai->ai_socktype = hints->ai_socktype;
ai->ai_protocol = hints->ai_protocol;
if (port0 == 0 && port == 0) {
port = port1 = ntohs(pri->pri_primary->tp_addr->su_port);
assert(port != 0);
}
}
tried = 1;
if (ai == NULL)
break;
pri = tport_listen(mr, ai, canon, proto, p, tags);
while (*tbf)
tport_zap_primary(*tbf);
if (pri) {
pri->pri_primary->tp_ident = su_strdup(pri->pri_home, tpn->tpn_ident);
tport_init_compression(pri, tpn->tpn_comp, tags);
if (error != EADDRINUSE || port0 != 0 || port == 0)
break;
#if HAVE_TLS
if (strcasecmp(tpn->tpn_proto, "tls") == 0) {
pri->pri_primary->tp_tls = tport_init_tls(tags);
if (!pri->pri_primary->tp_tls)
goto error;
}
#endif
not_supported = 0;
if (ephemeral_port)
port = strcpy(port0, pri->pri_primary->tp_port);
if (ephemeral_port == -1) {
ephemeral_port = ntohs(pri->pri_primary->tp_addr->su_port);
assert(ephemeral_port != 0);
if (p == 0)
p = ephemeral_port;
}
}
else {
error = su_errno();
if (error == EADDRINUSE)
not_supported = 0;
}
}
while (step == 0) {
/* step should be relative prime to 65536 - 1024 */
/* 65536 - 1024 = 7 * 3 * 3 * 1024 */
step = (random() | 1) % (65535 - 1024);
if (step % 3 == 0)
step = (step + 2) % (65536 - 1024);
if (step % 7 == 0)
step = (step + 2) % (65536 - 1024);
}
old = port; port += step; if (port >= 65536) port -= (65536 - 1024);
if (host)
su_freeaddrinfo(res);
else
tport_freeaddrinfo(mr, res);
if (port == port1) /* All ports in use! */
break;
if (!pri) {
while (*tbf)
tport_zap_primary(*tbf);
if (!tried)
not_supported = 1;
if (ephemeral_port != 0 && ephemeral_port != -1) {
while (step == 0) {
/* step should be relative prime to 65536 - 1024 */
/* 65536 - 1024 = 7 * 3 * 3 * 1024 */
step = (random() | 1) % (65535 - 1024);
if (step % 3 == 0)
step = (step + 2) % (65536 - 1024);
if (step % 7 == 0)
step = (step + 2) % (65536 - 1024);
}
p += step;
if (p >= 65536) p -= (65536 - 1024);
if (p == ephemeral_port)
ephemeral_port = 0;
SU_DEBUG_3(("%s(%p): cannot bind all transports to port %s, "
"trying %u\n",
__func__, mr, port, p));
snprintf(port0, sizeof(port0), "%u", p);
port = port0;
}
break;
}
}
SU_DEBUG_3(("%s(%p): cannot bind all transports to port %u, trying %u\n",
__func__, mr, old, port));
}
while (!pri && ephemeral_port && !not_supported);
if (li)
su_freelocalinfo(li);
tport_freeaddrinfo(res);
if (not_supported)
if (res && not_supported)
error = EPROTONOSUPPORT;
if (!pri) {
if (!*tbf) {
su_seterrno(error);
return -1;
}
......@@ -2123,65 +2052,308 @@ int tport_bind_server(tport_master_t *mr,