public inbox for hail-devel@vger.kernel.org
 help / color / mirror / Atom feed
From: Jeff Garzik <jeff@garzik.org>
To: Pete Zaitcev <zaitcev@redhat.com>
Cc: Project Hail List <hail-devel@vger.kernel.org>
Subject: Re: [Patch 1/1] CLD: Introduce the "New CLD" API
Date: Tue, 09 Feb 2010 01:03:58 -0500	[thread overview]
Message-ID: <4B70FACE.7050304@garzik.org> (raw)
In-Reply-To: <20100208223517.2404ba3f@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 1212 bytes --]

On 02/09/2010 12:35 AM, Pete Zaitcev wrote:
> On Mon, 08 Feb 2010 23:55:03 -0500
> Jeff Garzik<jeff@garzik.org>  wrote:
>
>>>>> -	if (cldc_getaddr(&host_list, hostb, NULL))
>>>>> +	if (cldc_getaddr(&host_list, hostb,&ncld_log))
>>>>>     		return 1001;
>>>
>>>> Logging pointer should be supplied by the caller...  that is the larger
>>>> bug.  Needing a no-op log function is just an indication of that.
>>>
>>> I did it before, but then every client, without exception, needed
>>> to include<stdarg.h>   and provide the log. And what for? This is
>>> STUPID and proof is in the pudding: your getsrvinfo does not do
>>> anything of the sort.
>>
>> Possibly true -- but it is worse to introduce internal inconsistencies.
>>    It is far better to remove debugging statements completely than to
>> create inconsistent usage.
>
> Hmm, you may be right about that.
>
>>> Might as well replace cldc_getadd with getsrvinfo
>>> and then everyone becomes happy.
>>
>> Seems a good fit :)
>
> How far along were you with getsrvinfo? I only have the header
> that you sent to the list just before Christmas.

Coding complete, but needed testing.  Probably works, since it came from 
working code.  See attached.

	Jeff



[-- Attachment #2: getsrvinfo.h --]
[-- Type: text/plain, Size: 1233 bytes --]

#ifndef __GETSRVINFO_H__
#define __GETSRVINFO_H__

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

struct srvinfo;

enum srvinfo_error_codes {
	ESI_NONE		= 0,	/* no error */
	ESI_CORRUPT		= 1,	/* server returned bad data */
	ESI_FAIL		= 2,	/* server returned permanent failure */
	ESI_AGAIN		= 3,	/* server returned temporary failure;
					 * try again later.*/
	ESI_OOM			= 4,	/* internal memory alloc failed */
	ESI_INVAL		= 5,	/* invalid argument(s) */
};

enum srvinfo_flags {
	FSI_NO_ADDR		= (1U << 0),  /* skip host->addrs lookup */
};

struct srvinfo {
	unsigned int		si_prio;    /* SRV priority */
	unsigned int		si_weight;  /* SRV weight */
	char			*si_target; /* SRV target domainname */
	unsigned short		si_port;    /* SRV port */

	struct addrinfo		*si_addr;   /* addresses returned
					     * from getaddrinfo(3) lookup
					     * on si_target */
	struct srvinfo		*si_next;   /* next srvinfo in result list */
};

extern int getsrvinfo(const char *service_name, const char *domain_name,
		      const struct addrinfo *hints,
		      unsigned int flags, struct srvinfo **res);
extern void freesrvinfo(struct srvinfo *res);
extern const char *gsi_strerror(int errcode);

#endif /* __GETSRVINFO_H__ */

[-- Attachment #3: getsrvinfo.c --]
[-- Type: text/plain, Size: 5530 bytes --]


/*
 * Copyright 2009 Red Hat, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include "getsrvinfo.h"

#define __must_be_array(a) \
	(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))

enum {
	gsi_max_dom_name_sz		= 64,
	gsi_dns_buf_sz			= 1024,
};

static int fill_srvinfo(struct srvinfo *si,
			const struct addrinfo *hints,
			unsigned int gsi_flags,
			unsigned int priority,
			unsigned int weight, unsigned int port,
			unsigned int nlen, const char *name)
{
	char portstr[11];
	char *hostname;
	struct addrinfo *res0 = NULL;
	int rc = 0;

	sprintf(portstr, "%u", port);

	hostname = malloc(nlen + 1);
	if (!hostname)
		return -ENOMEM;

	memcpy(hostname, name, nlen);
	hostname[nlen] = 0;

	if (!(gsi_flags & FSI_NO_ADDR)) {
		rc = getaddrinfo(hostname, portstr, hints, &res0);

		/* because we do not wish failure of one lookup
		 * to cause failure of the entire operation,
		 * we simply record the lack of an address (NULL)
		 * and move on.
		 */
		if (rc)
			res0 = NULL;
	}

	si->si_prio = priority;
	si->si_weight = weight;
	si->si_target = hostname;
	si->si_port = port;

	si->si_addr = res0;
	si->si_next = NULL;

	return 0;
}

void freesrvinfo(struct srvinfo *res)
{
	while (res) {
		struct srvinfo *tmp;
		
		tmp = res;
		res = res->si_next;

		if (tmp->si_addr)
			freeaddrinfo(tmp->si_addr);
		free(tmp->si_target);
		free(tmp);
	}
}

int getsrvinfo(const char *service_name, const char *domain_name,
	       const struct addrinfo *hints, unsigned int gsi_flags,
	       struct srvinfo **res_out)
{
	unsigned char resp[gsi_dns_buf_sz];
	int rlen;
	ns_msg nsb;
	ns_rr rrb;
	int rrlen;
	char hostb[gsi_max_dom_name_sz];
	struct srvinfo *si, *res = NULL, *res_last = NULL;
	const unsigned char *p;
	int rc, gsi_rc, i;

	if (!domain_name || !res_out)
		return ESI_INVAL;

	*res_out = NULL;

	/* we concatencate service_name and domain_name as a helpful
	 * service for the caller, because it is very common
	 * that service_name is either completely static, or at least
	 * stored in a separate variable from domain_name.
	 */
	if (service_name) {
		char *name;
		size_t name_len;
		int has_dot;

		has_dot = (service_name[strlen(service_name) - 1] == '.');
		name_len = strlen(service_name) + strlen(domain_name) +
			   (has_dot ? 0 : 1) + 1;

		name = malloc(name_len);
		if (!name)
			return ESI_OOM;

		snprintf(name, name_len, "%s%s%s", service_name,
			     has_dot ? "" : ".",
			     domain_name);
			
		rc = res_search(name, ns_c_in, ns_t_srv, resp, sizeof(resp));

		free(name);
	} else {
		rc = res_search(domain_name, ns_c_in, ns_t_srv,
				resp, sizeof(resp));
	}

	/* parse resolver return value */
	if (rc < 0) {
		switch (h_errno) {
		case TRY_AGAIN:
			return ESI_AGAIN;
		case HOST_NOT_FOUND:
		case NO_DATA:
		case NO_RECOVERY:
		default:
			return ESI_FAIL;
		}
	}
	rlen = rc;

	if (rlen == 0)
		return ESI_FAIL;

	/* set up DNS result parse */
	if (ns_initparse(resp, rlen, &nsb) < 0)
		return ESI_CORRUPT;

	/* iterate through each answer.  Because DNS packets may
	 * be truncated, we do not signal an error on
	 * short-length faults found during packet parsing
	 */
	for (i = 0; i < ns_msg_count(nsb, ns_s_an); i++) {
		rc = ns_parserr(&nsb, ns_s_an, i, &rrb);
		if (rc < 0)
			continue;

		if (ns_rr_class(rrb) != ns_c_in)
			continue;

		switch (ns_rr_type(rrb)) {
		case ns_t_srv:
			rrlen = ns_rr_rdlen(rrb);
			if (rrlen < 8) {	/* 2+2+2 and 2 for host */
				break;
			}
			p = ns_rr_rdata(rrb);
			rc = dn_expand(resp, resp+rlen, p+6,
				       hostb, gsi_max_dom_name_sz);
			if (rc < 0) {
				break;
			}
			if (rc < 2) {
				break;
			}

			si = malloc(sizeof(*si));
			if (!si) {
				gsi_rc = ESI_OOM;
				goto err_out;
			}

			if (fill_srvinfo(si, hints, gsi_flags,
					 ns_get16(p+0),
					 ns_get16(p+2),
					 ns_get16(p+4),
					 rc, hostb)) {
				free(si);
				gsi_rc = ESI_OOM;
				goto err_out;
			}

			/* if first item, set BOL-ptr */
			if (!res)
				res = si;

			/* append to EOL */
			if (res_last)
				res_last->si_next = si;
			res_last = si;

			break;

		case ns_t_cname:	/* impossible, but ... ? */
		default:
			break;
		}
	}

	*res_out = res;
	return ESI_NONE;

err_out:
	freesrvinfo(res);
	return gsi_rc;
}

static const char *gsi_error_str[] = {
	[ESI_NONE]		= "no error",
	[ESI_CORRUPT]		= "server returned bad data",
	[ESI_FAIL]		= "server returned permanent failure",
	[ESI_AGAIN]		= "server returned temporary failure",
	[ESI_OOM]		= "internal memory alloc failed",
	[ESI_INVAL]		= "invalid argument(s)",
};

const char *gsi_strerror(int errcode)
{
	if (errcode < 0 || errcode >= ARRAY_SIZE(gsi_error_str))
		return NULL;
	
	return gsi_error_str[errcode];
}


  reply	other threads:[~2010-02-09  6:03 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-02-07 19:15 [Patch 1/1] CLD: Introduce the "New CLD" API Pete Zaitcev
2010-02-07 22:26 ` Jeff Garzik
2010-02-08 12:32 ` Jeff Garzik
2010-02-09  0:30   ` Pete Zaitcev
2010-02-09  6:25     ` Jeff Garzik
2010-02-09  1:46   ` Pete Zaitcev
2010-02-09  2:06     ` Jeff Garzik
2010-02-09  2:17       ` Pete Zaitcev
2010-02-09  4:55         ` Jeff Garzik
2010-02-09  5:35           ` Pete Zaitcev
2010-02-09  6:03             ` Jeff Garzik [this message]
2010-02-14  0:52 ` Jeff Garzik
2010-02-18  0:05   ` Pete Zaitcev
2010-02-18  1:18     ` Jeff Garzik
2010-02-19  1:35       ` Pete Zaitcev
2010-02-19  2:41         ` Jeff Garzik
2010-02-19 22:23           ` Pete Zaitcev

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B70FACE.7050304@garzik.org \
    --to=jeff@garzik.org \
    --cc=hail-devel@vger.kernel.org \
    --cc=zaitcev@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox