/* 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 & BSC_FD_READ) ? fd->fd : ARES_SOCKET_BAD,
			(what & BSC_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)
		ufd->fd.when |= BSC_FD_READ;
	else
		ufd->fd.when &= ~BSC_FD_READ;

	if (write)
		ufd->fd.when |= BSC_FD_WRITE;
	else
		ufd->fd.when &= ~BSC_FD_WRITE;

	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);
