src/lib/resolve.c
author Tero Marttila <terom@fixme.fi>
Thu, 28 May 2009 01:17:36 +0300
branchnew-lib-errors
changeset 219 cefec18b8268
parent 184 src/resolve.c@2ab01ab33cfa
permissions -rw-r--r--
some of the lib/transport stuff compiles
#include "resolve.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>

static const char* _gai_error_msg (const struct error_extra_type *type, const union error_extra *extra)
{
    (void) type;

    return gai_strerror(extra->int_);
}

static const struct error_extra_type _gai_error_type = {
    .name       = "gai",
    .msg_func   = _gai_error_msg
};



const struct error_list resolve_errors = ERROR_LIST("resolve",
    ERROR_TYPE_EXTRA(   ERR_RESOLVE_GETADDRINFO,        "getaddrinfo",              &_gai_error_type),
    ERROR_TYPE_EXTRA(   ERR_RESOLVE_GETADDRINFO_EMPTY,  "getaddrinfo: no results",  &_gai_error_type)

);

err_t resolve_addr (struct resolve_result *res, const char *node, const char *service, int socktype, int ai_flags, error_t *err)
{
    struct addrinfo hints, *ai;
    int ret;

    // build hints
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = ai_flags;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = socktype;

    // resolve (blocking)
    if ((ret = getaddrinfo(node, service, &hints, &ai)))
        return SET_ERROR_EXTRA(err, &resolve_errors, ERR_RESOLVE_GETADDRINFO, &_gai_error_type, ret);

    // no results?
    if (!ai)
        return SET_ERROR(err, &resolve_errors, ERR_RESOLVE_GETADDRINFO_EMPTY);
    
    // store
    res->list = res->item = ai;

    // ok
    return SUCCESS;
}

void resolve_result_init (struct resolve_result *res)
{
    res->list = res->item = NULL;
}

struct addrinfo* resolve_result_next (struct resolve_result *res)
{
    if (!res->item) {
        // no items left
        return NULL;

    } else {
        // ...remember the current item
        struct addrinfo *ai = res->item;

        if (res->item)
            // advance item to the next one
            res->item = res->item->ai_next;

        // return the current one
        return ai;
    }
}

void resolve_result_deinit (struct resolve_result *res)
{
    if (res->list)
        // free them all
        freeaddrinfo(res->list);
    
    // invalidate
    res->list = res->item = NULL;
}

const char * resolve_addr_text (const struct addrinfo *addr)
{
    static char text[1024];
    char host[NI_MAXHOST], service[NI_MAXSERV];
    int ret;

    // lookup the reverse nameinfo
    if ((ret = getnameinfo(
                addr->ai_addr, addr->ai_addrlen, 
                host, sizeof(host), service, sizeof(service), 
                NI_NUMERICHOST | NI_NUMERICSERV
    ))) {
        strcpy(host, "???");
        strcpy(service, "???");
    }

    // format message
    snprintf(text, sizeof(text), "[%s]:%s", host, service);

    // return static pointer
    return text;
}