/* C-ARES DNS resolver integration */

/*
 * (C) 2015 by Holger Hans Peter Freyther
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/debug.h>

#include <netdb.h>

extern void *tall_sgsn_ctx;

struct cares_event_fd {
	struct llist_head head;
	struct osmo_fd fd;
};

struct cares_cb_data {
	ares_host_callback cb;
	void *data;
};

static void osmo_ares_reschedule(struct sgsn_instance *sgsn);
static void ares_cb(void *_arg, int status, int timeouts, struct hostent *hostent)
{
	struct cares_cb_data *arg = _arg;

	arg->cb(arg->data, status, timeouts, hostent);
	osmo_ares_reschedule(sgsn);
	talloc_free(arg);
}

static int ares_osmo_fd_cb(struct osmo_fd *fd, unsigned int what)
{
	LOGP(DGPRS, LOGL_DEBUG, "C-ares fd(%d) ready(%d)\n", fd->fd, what);

	ares_process_fd(sgsn->ares_channel,
			(what & OSMO_FD_READ) ? fd->fd : ARES_SOCKET_BAD,
			(what & OSMO_FD_WRITE) ? fd->fd : ARES_SOCKET_BAD);
	osmo_ares_reschedule(sgsn);
	return 0;
}

static void ares_timeout_cb(void *data)
{
	struct sgsn_instance *sgsn = data;

	LOGP(DGPRS, LOGL_DEBUG, "C-ares triggering timeout\n");
	ares_process_fd(sgsn->ares_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
	osmo_ares_reschedule(sgsn);
}

static void osmo_ares_reschedule(struct sgsn_instance *sgsn)
{
	struct timeval *timeout, tv;

	osmo_timer_del(&sgsn->ares_timer);
	timeout = ares_timeout(sgsn->ares_channel, NULL, &tv);
	if (timeout) {
		LOGP(DGPRS, LOGL_DEBUG, "C-ares scheduling timeout %llu.%llu\n",
			(unsigned long long) tv.tv_sec,
			(unsigned long long) tv.tv_usec);
		osmo_timer_setup(&sgsn->ares_timer, ares_timeout_cb, sgsn);
		osmo_timer_schedule(&sgsn->ares_timer, tv.tv_sec, tv.tv_usec);
	}
}

static void setup_ares_osmo_fd(void *data, int fd, int read, int write)
{
	struct cares_event_fd *ufd, *tmp;

	/* delete the entry */
	if (read == 0 && write == 0) {
		llist_for_each_entry_safe(ufd, tmp, &sgsn->ares_fds, head) {
			if (ufd->fd.fd != fd)
				continue;

			LOGP(DGPRS, LOGL_DEBUG,
				"Removing C-ares watched fd (%d)\n", fd);
			osmo_fd_unregister(&ufd->fd);
			llist_del(&ufd->head);
			talloc_free(ufd);
			return;
		}
	}

	/* Search for the fd or create a new one */
	llist_for_each_entry(ufd, &sgsn->ares_fds, head) {
		if (ufd->fd.fd != fd)
			continue;

		LOGP(DGPRS, LOGL_DEBUG, "Updating C-ares fd (%d)\n", fd);
		goto update_fd;
	}

	LOGP(DGPRS, LOGL_DEBUG, "Registering C-ares fd (%d)\n", fd);
	ufd = talloc_zero(tall_sgsn_ctx, struct cares_event_fd);
	ufd->fd.fd = fd;
	ufd->fd.cb = ares_osmo_fd_cb;
	ufd->fd.data = data;
	if (osmo_fd_register(&ufd->fd) != 0)
		LOGP(DGPRS, LOGL_ERROR, "Failed to register C-ares fd (%d)\n", fd);
	llist_add(&ufd->head, &sgsn->ares_fds);

update_fd:
	if (read)
		osmo_fd_read_enable(&ufd->fd);
	else
		osmo_fd_read_disable(&ufd->fd);

	if (write)
		osmo_fd_write_enable(&ufd->fd);
	else
		osmo_fd_write_disable(&ufd->fd);

	osmo_ares_reschedule(sgsn);
}

int sgsn_ares_query(struct sgsn_instance *sgsn, const char *name,
			ares_host_callback cb, void *data)
{
	struct cares_cb_data *cb_data;

	cb_data = talloc_zero(tall_sgsn_ctx, struct cares_cb_data);
	cb_data->cb = cb;
	cb_data->data = data;
	ares_gethostbyname(sgsn->ares_channel, name, AF_INET, ares_cb, cb_data);
	osmo_ares_reschedule(sgsn);
	return 0;
}

int sgsn_ares_init(struct sgsn_instance *sgsn)
{
	struct ares_options options;
	int optmask;
	int rc;

	INIT_LLIST_HEAD(&sgsn->ares_fds);
	memset(&options, 0, sizeof(options));
	options.sock_state_cb = setup_ares_osmo_fd;
	options.sock_state_cb_data = sgsn;

	optmask = ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB | ARES_OPT_DOMAINS;

	if (sgsn->ares_servers)
		optmask |= ARES_OPT_SERVERS;

	ares_library_init(ARES_LIB_INIT_ALL);
	rc = ares_init_options(&sgsn->ares_channel, &options, optmask);
	if (rc != ARES_SUCCESS)
		return rc;

	if (sgsn->ares_servers)
		rc = ares_set_servers(sgsn->ares_channel, sgsn->ares_servers);

	return rc;
}

osmo_static_assert(ARES_SUCCESS == 0, ares_success_zero);
