resolved-dns-stream.c revision b914e211f3a40f507b3cdc572838ec7f3fd5e4cf
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2014 Lennart Poettering
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.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "missing.h"
#include "resolved-dns-stream.h"
#define DNS_STREAMS_MAX 128
static void dns_stream_stop(DnsStream *s) {
assert(s);
}
static int dns_stream_update_io(DnsStream *s) {
int f = 0;
assert(s);
f |= EPOLLOUT;
f |= EPOLLIN;
return sd_event_source_set_io_events(s->io_event_source, f);
}
assert(s);
dns_stream_stop(s);
if (s->complete)
else
dns_stream_free(s);
return 0;
}
static int dns_stream_identify(DnsStream *s) {
union {
+ EXTRA_CMSG_SPACE /* kernel appears to require extra space */];
} control;
int r;
assert(s);
if (s->identified)
return 0;
/* Query the local side */
s->local_salen = sizeof(s->local);
if (r < 0)
return -errno;
/* Query the remote side */
s->peer_salen = sizeof(s->peer);
if (r < 0)
return -errno;
/* Check consistency */
/* Query connection meta information */
if (r < 0)
return -errno;
if (r < 0)
return -errno;
} else
return -EAFNOSUPPORT;
case IPV6_PKTINFO: {
if (s->ifindex <= 0)
s->ifindex = i->ipi6_ifindex;
break;
}
case IPV6_HOPLIMIT:
break;
}
case IP_PKTINFO: {
if (s->ifindex <= 0)
s->ifindex = i->ipi_ifindex;
break;
}
case IP_TTL:
break;
}
}
}
/* The Linux kernel sets the interface index to the loopback
* device if the connection came from the local host since it
* avoids the routing table in such a case. Let's unset the
* interface index in such a case. */
s->ifindex = 0;
/* If we don't know the interface index still, we look for the
* first local interface with a matching address. Yuck! */
if (s->ifindex <= 0)
s->ifindex = manager_find_ifindex(s->manager, s->local.sa.sa_family, s->local.sa.sa_family == AF_INET ? (union in_addr_union*) &s->local.in.sin_addr : (union in_addr_union*) &s->local.in6.sin6_addr);
/* Make sure all packets for this connection are sent on the same interface */
if (r < 0)
return -errno;
if (r < 0)
return -errno;
}
}
s->identified = true;
return 0;
}
assert(s);
return dns_stream_complete(s, ETIMEDOUT);
}
int r;
assert(s);
r = dns_stream_identify(s);
if (r < 0)
return dns_stream_complete(s, -r);
s->write_packet &&
if (ss < 0) {
return dns_stream_complete(s, errno);
} else
/* Are we done? If so, disable the event source for EPOLLOUT */
r = dns_stream_update_io(s);
if (r < 0)
return dns_stream_complete(s, -r);
}
}
(!s->read_packet ||
if (ss < 0) {
return dns_stream_complete(s, errno);
} else if (ss == 0)
return dns_stream_complete(s, ECONNRESET);
else
}
return dns_stream_complete(s, EBADMSG);
if (!s->read_packet) {
if (r < 0)
return dns_stream_complete(s, -r);
} else {
if (s->read_packet->ifindex == 0)
if (s->read_packet->ifindex == 0)
}
}
if (ss < 0) {
return dns_stream_complete(s, errno);
} else if (ss == 0)
return dns_stream_complete(s, ECONNRESET);
else
}
/* Are we done? If so, disable the event source for EPOLLIN */
r = dns_stream_update_io(s);
if (r < 0)
return dns_stream_complete(s, -r);
/* If there's a packet handler
* installed, call that. Note that
* this is optional... */
if (s->on_packet)
return s->on_packet(s);
}
}
}
return dns_stream_complete(s, 0);
return 0;
}
if (!s)
return NULL;
dns_stream_stop(s);
if (s->manager) {
s->manager->n_dns_streams--;
}
free(s);
return 0;
}
static const int one = 1;
int r;
assert(m);
if (m->n_dns_streams > DNS_STREAMS_MAX)
return -EBUSY;
if (!s)
return -ENOMEM;
s->fd = -1;
if (r < 0)
return -errno;
if (r < 0)
return r;
r = sd_event_add_time(m->event, &s->timeout_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + DNS_STREAM_TIMEOUT_USEC, 0, on_stream_timeout, s);
if (r < 0)
return r;
s->manager = m;
m->n_dns_streams++;
*ret = s;
s = NULL;
return 0;
}
assert(s);
if (s->write_packet)
return -EBUSY;
s->write_packet = dns_packet_ref(p);
s->n_written = 0;
return dns_stream_update_io(s);
}