Commit 8af92ee5 authored by Marek Vavrusa's avatar Marek Vavrusa

AXFRIN packet handling now works, but not implemented.

Packet handling code should be implemented in ns_process_axfrin() (name-server.c)
Function should return codes to the caller, so it can tell when the
transfer is finished.

Commit refs #788, #800, #858.
parent 118687f3
......@@ -9,9 +9,8 @@
int sockaddr_init(sockaddr_t *addr, int af)
{
/* Reset pointer. */
memset(addr, 0, sizeof(sockaddr_t));
addr->family = -1;
addr->ptr = 0;
addr->len = 0;
/* Initialize address size. */
switch(af) {
......
......@@ -1775,13 +1775,13 @@ static int ns_axfr_send_and_clear(ns_xfr_t *xfr)
assert(xfr != NULL);
assert(xfr->query != NULL);
assert(xfr->response != NULL);
assert(xfr->response_wire != NULL);
assert(xfr->wire != NULL);
assert(xfr->send != NULL);
// Transform the packet into wire format
debug_ns("Converting response to wire format..\n");
size_t real_size;
if (ns_response_to_wire(xfr->response, xfr->response_wire, &real_size)
if (ns_response_to_wire(xfr->response, xfr->wire, &real_size)
!= 0) {
return NS_ERR_SERVFAIL;
// // send back SERVFAIL (as this is our problem)
......@@ -1793,8 +1793,8 @@ static int ns_axfr_send_and_clear(ns_xfr_t *xfr)
// Send the response
debug_ns("Sending response (size %zu)..\n", real_size);
debug_ns_hex((const char *)xfr->response_wire, real_size);
int res = xfr->send(xfr->session, xfr->response_wire, real_size);
debug_ns_hex((const char *)xfr->wire, real_size);
int res = xfr->send(xfr->session, xfr->wire, real_size);
if (res < 0) {
debug_ns("Send returned %d\n", res);
return res;
......@@ -1921,7 +1921,7 @@ static int ns_axfr_from_zone(dnslib_zone_t *zone, ns_xfr_t *xfr)
assert(xfr != NULL);
assert(xfr->query != NULL);
assert(xfr->response != NULL);
assert(xfr->response_wire != NULL);
assert(xfr->wire != NULL);
assert(xfr->send != NULL);
ns_axfr_params_t params;
......@@ -2413,19 +2413,19 @@ int ns_answer_axfr(ns_nameserver_t *nameserver, ns_xfr_t *xfr)
if (response == NULL) {
log_server_warning("Failed to create packet structure.\n");
ns_error_response(nameserver, xfr->query->header.id,
DNSLIB_RCODE_SERVFAIL, xfr->response_wire,
&xfr->rsize);
DNSLIB_RCODE_SERVFAIL, xfr->wire,
&xfr->wire_size);
rcu_read_unlock();
return KNOT_EOK;
}
int ret = dnslib_packet_set_max_size(response, xfr->rsize);
int ret = dnslib_packet_set_max_size(response, xfr->wire_size);
if (ret != DNSLIB_EOK) {
log_server_warning("Failed to init response structure.\n");
ns_error_response(nameserver, xfr->query->header.id,
DNSLIB_RCODE_SERVFAIL, xfr->response_wire,
&xfr->rsize);
DNSLIB_RCODE_SERVFAIL, xfr->wire,
&xfr->wire_size);
rcu_read_unlock();
dnslib_packet_free(&response);
return KNOT_EOK;
......@@ -2436,8 +2436,8 @@ int ns_answer_axfr(ns_nameserver_t *nameserver, ns_xfr_t *xfr)
if (ret != DNSLIB_EOK) {
log_server_warning("Failed to init response structure.\n");
ns_error_response(nameserver, xfr->query->header.id,
DNSLIB_RCODE_SERVFAIL, xfr->response_wire,
&xfr->rsize);
DNSLIB_RCODE_SERVFAIL, xfr->wire,
&xfr->wire_size);
rcu_read_unlock();
dnslib_packet_free(&response);
return KNOT_EOK;
......@@ -2467,9 +2467,9 @@ int ns_answer_axfr(ns_nameserver_t *nameserver, ns_xfr_t *xfr)
// now only one type of error (SERVFAIL), later maybe more
size_t real_size;
ns_error_response(nameserver, xfr->query->header.id,
DNSLIB_RCODE_SERVFAIL, xfr->response_wire,
DNSLIB_RCODE_SERVFAIL, xfr->wire,
&real_size);
ret = xfr->send(xfr->session, xfr->response_wire, real_size);
ret = xfr->send(xfr->session, xfr->wire, real_size);
}
rcu_read_unlock();
......@@ -2576,6 +2576,20 @@ int ns_process_response(ns_nameserver_t *nameserver, sockaddr_t *from,
/*----------------------------------------------------------------------------*/
int ns_process_axfrin(ns_nameserver_t *nameserver, ns_xfr_t *xfr)
{
/*! \todo Implement me.
* - xfr contains partially-built zone or NULL (xfr->data)
* - incoming packet is in xfr->wire
* - incoming packet size is in xfr->wire_size
* - signalize caller, that transfer is finished/error (ret. code?)
*/
debug_net("ns_process_axfrin: incoming packet\n");
return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
void ns_destroy(ns_nameserver_t **nameserver)
{
synchronize_rcu();
......
......@@ -139,8 +139,8 @@ typedef struct ns_xfr {
dnslib_packet_t *response;
axfr_callback_t send;
int session;
uint8_t *response_wire;
size_t rsize;
uint8_t *wire;
size_t wire_size;
void *data;
} ns_xfr_t;
......@@ -201,6 +201,16 @@ int ns_process_response(ns_nameserver_t *nameserver, sockaddr_t *from,
dnslib_packet_t *packet, uint8_t *response_wire,
size_t *rsize);
/*!
* \brief Processes an AXFR-IN packet.
*
* \param nameserver Name server structure to provide the data for answering.
* \param xfr
*
* \todo Document me.
*/
int ns_process_axfrin(ns_nameserver_t *nameserver, ns_xfr_t *xfr);
/*!
* \brief Properly destroys the name server structure.
*
......
......@@ -11,6 +11,7 @@
#include <stdlib.h>
#include "common/sockaddr.h"
#include "common/skip-list.h"
#include "knot/common.h"
#include "knot/server/tcp-handler.h"
#include "knot/server/xfr-handler.h"
......@@ -25,16 +26,35 @@ typedef struct tcp_pool_t {
int evcount; /*!< Epoll events counter */
struct epoll_event *events; /*!< Epoll events backing store. */
int ebs_size; /*!< Epoll events backing store size. */
skip_list_t *ev_data; /*!< User data for polled sockets. */
pthread_mutex_t mx; /*!< Pool synchronisation lock. */
server_t *server; /*!< Server instance. */
tcp_event_f on_event; /* TCP event handler. */
iohandler_t *io_h; /* master I/O handler */
tcp_handle_t handle; /* TCP event handler. */
stat_t *stat; /* statistics gatherer */
} tcp_pool_t;
/*
* Forward decls.
*/
/*!
* \brief Compare function for skip-list.
*/
static int tcp_pool_compare(void *k1, void *k2)
{
/* Key = socket filedescriptor. */
ssize_t diff = (ssize_t)k1 - (ssize_t)k2;
if (diff < 0) {
return -1;
}
if (diff > 0) {
return 1;
}
return 0;
}
/*! \brief Lock TCP pool. */
static inline int tcp_pool_lock(tcp_pool_t *pool)
{
......@@ -54,10 +74,11 @@ static inline int tcp_pool_unlock(tcp_pool_t *pool)
*
* \param pool Associated connection pool.
* \param fd Associated socket.
* \param data Associated data.
* \param qbuf Buffer for a query wireformat.
* \param qbuf_maxlen Buffer maximum size.
*/
static inline int tcp_handle(tcp_pool_t *pool, int fd,
static inline int tcp_handle(tcp_pool_t *pool, int fd, void *data,
uint8_t *qbuf, size_t qbuf_maxlen)
{
sockaddr_t addr;
......@@ -124,12 +145,13 @@ static inline int tcp_handle(tcp_pool_t *pool, int fd,
qbuf, &resp_len);
break;
case DNSLIB_QUERY_AXFR:
memset(&xfr, 0, sizeof(ns_xfr_t));
xfr.type = XFR_OUT_REQUEST;
xfr.query = packet;
xfr.send = tcp_send;
xfr.session = fd;
xfr.response_wire = 0;
xfr.rsize = 0;
xfr.wire = 0;
xfr.wire_size = 0;
memcpy(&xfr.addr, &addr, sizeof(sockaddr_t));
xfr_request(pool->server->xfr_h, &xfr);
debug_net("tcp: enqueued AXFR request size %zd.\n",
......@@ -222,7 +244,7 @@ int tcp_disconnect(tcp_pool_t *pool, int fd)
* Public APIs.
*/
tcp_pool_t *tcp_pool_new(server_t *server, tcp_handle_t hfunc)
tcp_pool_t *tcp_pool_new(server_t *server, tcp_event_f hfunc)
{
// Alloc
tcp_pool_t *pool = malloc(sizeof(tcp_pool_t));
......@@ -236,7 +258,7 @@ tcp_pool_t *tcp_pool_new(server_t *server, tcp_handle_t hfunc)
pool->evcount = 0;
pool->ebs_size = 0;
pool->server = server;
pool->handle = hfunc;
pool->on_event = hfunc;
// Create epoll fd
pool->epfd = epoll_create(1);
......@@ -260,6 +282,15 @@ tcp_pool_t *tcp_pool_new(server_t *server, tcp_handle_t hfunc)
return 0;
}
/* Create skip-list for TCP session data. */
pool->ev_data = skip_create_list(tcp_pool_compare);
if (!pool->ev_data) {
pthread_mutex_destroy(&pool->mx);
close(pool->epfd);
free(pool->events);
free(pool);
}
// Create stat gatherer
STAT_INIT(pool->stat);
stat_set_protocol(pool->stat, stat_TCP);
......@@ -288,12 +319,15 @@ void tcp_pool_del(tcp_pool_t **pool)
// Delete stat
stat_free((*pool)->stat);
// Delete session data
skip_destroy_list(&(*pool)->ev_data, 0, free);
// Free
free((*pool));
*pool = 0;
}
int tcp_pool_add(tcp_pool_t* pool, int newsock, uint32_t events)
int tcp_pool_add(tcp_pool_t* pool, int sock, void *data)
{
if (!pool) {
return -1;
......@@ -303,17 +337,17 @@ int tcp_pool_add(tcp_pool_t* pool, int newsock, uint32_t events)
memset(&ev, 0, sizeof(struct epoll_event));
// All polled events should use non-blocking mode.
int old_flag = fcntl(newsock, F_GETFL, 0);
if (fcntl(newsock, F_SETFL, old_flag | O_NONBLOCK) == -1) {
int old_flag = fcntl(sock, F_GETFL, 0);
if (fcntl(sock, F_SETFL, old_flag | O_NONBLOCK) == -1) {
log_server_error("Error setting non-blocking mode "
"on the socket.\n");
return -1;
}
// Register to epoll
ev.data.fd = newsock;
ev.events = events;
if (epoll_ctl(pool->epfd, EPOLL_CTL_ADD, newsock, &ev) != 0) {
ev.data.fd = sock;
ev.events = EPOLLIN;
if (epoll_ctl(pool->epfd, EPOLL_CTL_ADD, sock, &ev) != 0) {
debug_net("Failed to add socket to "
"event set (%d).\n",
errno);
......@@ -323,10 +357,13 @@ int tcp_pool_add(tcp_pool_t* pool, int newsock, uint32_t events)
// Increase event count
++pool->evcount;
/* Append data. */
skip_insert(pool->ev_data, (void*)((ssize_t)sock), data, 0);
return 0;
}
int tcp_pool_remove(tcp_pool_t* pool, int socket)
int tcp_pool_remove(tcp_pool_t* pool, int sock)
{
if (!pool) {
return -1;
......@@ -335,16 +372,24 @@ int tcp_pool_remove(tcp_pool_t* pool, int socket)
// Compatibility with kernels < 2.6.9, require non-0 ptr.
struct epoll_event ev;
if (epoll_ctl(pool->epfd, EPOLL_CTL_DEL, socket, &ev) != 0) {
if (epoll_ctl(pool->epfd, EPOLL_CTL_DEL, sock, &ev) != 0) {
debug_net("Failed to remove socket from "
"event set (%d).\n",
errno);
return -1;
}
/* Remove data if exist, data will be freed. */
skip_remove(pool->ev_data, (void*)((ssize_t)sock), 0, free);
return 0;
}
server_t* tcp_pool_server(tcp_pool_t *pool)
{
return pool->server;
}
int tcp_pool(dthread_t *thread)
{
tcp_pool_t *pool = (tcp_pool_t *)thread->data;
......@@ -385,7 +430,11 @@ int tcp_pool(dthread_t *thread)
if (pool->events[i].events & EPOLLERR) {
tcp_disconnect(pool, fd);
} else {
ret = pool->handle(pool, fd, qbuf, sizeof(qbuf));
/* Lookup associated data. */
void *d = skip_find(pool->ev_data,
(void*)((size_t)fd));
ret = pool->on_event(pool, fd, d,
qbuf, sizeof(qbuf));
if (ret != KNOT_EOK) {
tcp_disconnect(pool, fd);
}
......@@ -545,7 +594,7 @@ int tcp_master(dthread_t *thread)
"to pool #%d\n",
incoming, pool_id);
tcp_pool_add(pool, incoming, EPOLLIN);
tcp_pool_add(pool, incoming, 0);
// Activate pool
dt_activate(t);
......
......@@ -9,6 +9,8 @@
* the worker threads ("buckets"). Each threads processes it's own
* set of sockets, and eliminates mutual exclusion problem by doing so.
*
* \todo Improve documentation of TCP pool API and use proper error codes.
*
* \addtogroup server
* @{
*/
......@@ -32,10 +34,11 @@ struct tcp_pool_t;
*
* \param pool Associated connection pool.
* \param fd Associated socket.
* \param data Associated data.
* \param qbuf Buffer for a query wireformat.
* \param qbuf_maxlen Buffer maximum size.
*/
typedef int (*tcp_handle_t)(struct tcp_pool_t *pool, int fd,
typedef int (*tcp_event_f)(struct tcp_pool_t *pool, int fd, void *data,
uint8_t *qbuf, size_t qbuf_maxlen);
/*!
......@@ -49,7 +52,7 @@ typedef int (*tcp_handle_t)(struct tcp_pool_t *pool, int fd,
* \retval New instance on success.
* \retval NULL on errors.
*/
struct tcp_pool_t *tcp_pool_new(server_t *server, tcp_handle_t hfunc);
struct tcp_pool_t *tcp_pool_new(server_t *server, tcp_event_f hfunc);
/*!
* \brief Delete TCP pool instance.
......@@ -62,17 +65,33 @@ void tcp_pool_del(struct tcp_pool_t **pool);
* \brief Add socket to the TCP pool.
*
* \param pool Given TCP pool.
* \param newsock Socket to be added to the TCP pool.
* \param events Events to be registered (usually just EPOLLIN).
* \param sock Socket to be added to the TCP pool.
* \param data Data associated with TCP session.
*
* \retval 0 on success.
* \retval <0 on error.
*/
int tcp_pool_add(struct tcp_pool_t* pool, int newsock, uint32_t events);
int tcp_pool_add(struct tcp_pool_t *pool, int sock, void *data);
/*!
* \brief Remove socket from a TCP pool.
*
* \param pool Given TCP pool.
* \param sock Socket to be removed from the TCP pool.
*
* \retval 0 on success.
* \retval <0 on error.
*/
int tcp_pool_remove(struct tcp_pool_t *pool, int sock);
/*!
* \brief Return associated server instance.
*
* \param pool Given TCP pool.
*
* \return Associated server instance.
*/
int tcp_pool_remove(struct tcp_pool_t* pool, int socket);
server_t* tcp_pool_server(struct tcp_pool_t *pool);
/*!
* \brief TCP pool main function.
......
......@@ -26,20 +26,38 @@
*
* \param pool Associated connection pool.
* \param fd Associated socket.
* \param data Associated data.
* \param qbuf Buffer for a query wireformat.
* \param qbuf_maxlen Buffer maximum size.
*/
static inline int xfr_client_ev(struct tcp_pool_t *pool, int fd,
static inline int xfr_client_ev(struct tcp_pool_t *pool, int fd, void *data,
uint8_t *qbuf, size_t qbuf_maxlen)
{
/* Check data. */
ns_xfr_t *request = (ns_xfr_t *)data;
if (!request) {
close(fd);
return KNOT_EINVAL;
}
/* Read DNS/TCP packet. */
int ret = tcp_recv(fd, qbuf, qbuf_maxlen, 0);
if (ret <= 0) {
close(fd);
return KNOT_ERROR;
}
fprintf(stderr, "xfr-in event received %d bytes\n", ret);
/* Update xfer state. */
request->wire = qbuf;
request->wire_size = ret;
return KNOT_EOK;
/* Process incoming packet. */
server_t *server = tcp_pool_server(pool);
ret = ns_process_axfrin(server->nameserver, request);
/*! \todo Evaluate, function should respond properly
* to handle finished transfer. */
return ret;
}
/*
......@@ -63,8 +81,8 @@ xfrhandler_t *xfr_create(size_t thrcount, ns_nameserver_t *ns)
}
/* Create TCP pool. */
data->xfers = tcp_pool_new(ns->server, xfr_client_ev);
if (!data->xfers) {
data->xfer_pool = tcp_pool_new(ns->server, xfr_client_ev);
if (!data->xfer_pool) {
evqueue_free(&data->q);
free(data);
return 0;
......@@ -74,13 +92,13 @@ xfrhandler_t *xfr_create(size_t thrcount, ns_nameserver_t *ns)
dt_unit_t *unit = 0;
unit = dt_create_coherent(thrcount, &xfr_master, (void*)data);
if (!unit) {
tcp_pool_del(&data->xfers);
tcp_pool_del(&data->xfer_pool);
evqueue_free(&data->q);
free(data);
return 0;
}
data->unit = unit;
dt_repurpose(unit->threads[0], &xfr_client, data->xfers);
dt_repurpose(unit->threads[0], &xfr_client, data->xfer_pool);
return data;
}
......@@ -95,7 +113,7 @@ int xfr_free(xfrhandler_t *handler)
evqueue_free(&handler->q);
/* Delete TCP pool. */
tcp_pool_del(&handler->xfers);
tcp_pool_del(&handler->xfer_pool);
/* Delete unit. */
dt_delete(&handler->unit);
......@@ -137,15 +155,15 @@ int xfr_client_start(xfrhandler_t *handler, ns_xfr_t *req)
const dnslib_node_t *apex = dnslib_zone_apex(zone);
const dnslib_dname_t *dname = dnslib_node_owner(apex);
size_t bufsize = req->rsize;
ret = axfrin_create_axfr_query(dname, req->response_wire, &bufsize);
size_t bufsize = req->wire_size;
ret = axfrin_create_axfr_query(dname, req->wire, &bufsize);
if (ret != KNOT_EOK) {
return ret;
}
/* Send AXFR query. */
fprintf(stderr, "sending %zu bytes AXFR query\n", bufsize);
ret = tcp_send(fd, req->response_wire, bufsize);
debug_net("axfrin: sending AXFR query (%zu bytes)\n", bufsize);
ret = tcp_send(fd, req->wire, bufsize);
if (ret != bufsize) {
return KNOT_ERROR;
}
......@@ -153,11 +171,21 @@ int xfr_client_start(xfrhandler_t *handler, ns_xfr_t *req)
/* Update XFR request. */
req->send = tcp_send;
req->session = fd;
req->wire = 0; /* Disable shared buffer. */
req->wire_size = 0;
req->data = 0; /* New zone will be built. */
/* Store XFR request for further processing. */
void *data = malloc(sizeof(ns_xfr_t));
if (!data) {
close(fd);
return KNOT_ENOMEM;
}
/*! \todo Store XFR request for further processing. */
memcpy(data, req, sizeof(ns_xfr_t));
/* Add to pending transfers. */
tcp_pool_add(handler->xfers, fd, EPOLLIN);
tcp_pool_add(handler->xfer_pool, fd, data);
dt_activate(handler->unit->threads[0]);
return KNOT_EOK;
......@@ -206,8 +234,8 @@ int xfr_master(dthread_t *thread)
/* Update request. */
sockaddr_update(&xfr.addr);
xfr.response_wire = buf;
xfr.rsize = sizeof(buf);
xfr.wire = buf;
xfr.wire_size = sizeof(buf);
/* Handle request. */
const char *req_type = "";
......
......@@ -32,7 +32,7 @@ typedef struct xfrhandler_t
dt_unit_t *unit; /*!< \brief Threading unit. */
ns_nameserver_t *ns; /*!< \brief Pointer to nameserver.*/
evqueue_t *q; /*!< \brief Shared XFR requests queue.*/
struct tcp_pool_t *xfers; /*! \brief TCP client transfers. */
struct tcp_pool_t *xfer_pool; /*! \brief TCP client transfers. */
} xfrhandler_t;
/*!
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment