1/* $Id$ */
2
3/***
4  This file is part of avahi.
5
6  avahi is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Lesser General Public License as
8  published by the Free Software Foundation; either version 2.1 of the
9  License, or (at your option) any later version.
10
11  avahi is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14  Public License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with avahi; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  USA.
20***/
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <sys/types.h>
27#include <netinet/in.h>
28#include <sys/socket.h>
29#include <arpa/inet.h>
30#include <string.h>
31#include <assert.h>
32#include <stdio.h>
33
34#include "address.h"
35#include "malloc.h"
36
37static size_t address_get_size(const AvahiAddress *a) {
38    assert(a);
39
40    if (a->proto == AVAHI_PROTO_INET)
41        return 4;
42    else if (a->proto == AVAHI_PROTO_INET6)
43        return 16;
44
45    return 0;
46}
47
48int avahi_address_cmp(const AvahiAddress *a, const AvahiAddress *b) {
49    assert(a);
50    assert(b);
51
52    if (a->proto != b->proto)
53        return -1;
54
55    return memcmp(a->data.data, b->data.data, address_get_size(a));
56}
57
58char *avahi_address_snprint(char *s, size_t length, const AvahiAddress *a) {
59    assert(s);
60    assert(length);
61    assert(a);
62
63    if (!(inet_ntop(avahi_proto_to_af(a->proto), a->data.data, s, length)))
64        return NULL;
65
66    return s;
67}
68
69char* avahi_reverse_lookup_name(const AvahiAddress *a, char *ret_s, size_t length) {
70    assert(ret_s);
71    assert(length > 0);
72    assert(a);
73
74    if (a->proto == AVAHI_PROTO_INET) {
75        uint32_t n = ntohl(a->data.ipv4.address);
76        snprintf(
77            ret_s, length,
78            "%u.%u.%u.%u.in-addr.arpa",
79            n & 0xFF, (n >> 8) & 0xFF, (n >> 16) & 0xFF, n >> 24);
80    } else {
81        assert(a->proto == AVAHI_PROTO_INET6);
82
83        snprintf(
84            ret_s, length,
85            "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
86            a->data.ipv6.address[15] & 0xF, a->data.ipv6.address[15] >> 4,
87            a->data.ipv6.address[14] & 0xF, a->data.ipv6.address[14] >> 4,
88            a->data.ipv6.address[13] & 0xF, a->data.ipv6.address[13] >> 4,
89            a->data.ipv6.address[12] & 0xF, a->data.ipv6.address[12] >> 4,
90            a->data.ipv6.address[11] & 0xF, a->data.ipv6.address[11] >> 4,
91            a->data.ipv6.address[10] & 0xF, a->data.ipv6.address[10] >> 4,
92            a->data.ipv6.address[ 9] & 0xF, a->data.ipv6.address[ 9] >> 4,
93            a->data.ipv6.address[ 8] & 0xF, a->data.ipv6.address[ 8] >> 4,
94            a->data.ipv6.address[ 7] & 0xF, a->data.ipv6.address[ 7] >> 4,
95            a->data.ipv6.address[ 6] & 0xF, a->data.ipv6.address[ 6] >> 4,
96            a->data.ipv6.address[ 5] & 0xF, a->data.ipv6.address[ 5] >> 4,
97            a->data.ipv6.address[ 4] & 0xF, a->data.ipv6.address[ 4] >> 4,
98            a->data.ipv6.address[ 3] & 0xF, a->data.ipv6.address[ 3] >> 4,
99            a->data.ipv6.address[ 2] & 0xF, a->data.ipv6.address[ 2] >> 4,
100            a->data.ipv6.address[ 1] & 0xF, a->data.ipv6.address[ 1] >> 4,
101            a->data.ipv6.address[ 0] & 0xF, a->data.ipv6.address[ 0] >> 4);
102    }
103
104    return ret_s;
105}
106
107AvahiAddress *avahi_address_parse(const char *s, AvahiProtocol proto, AvahiAddress *ret_addr) {
108    assert(ret_addr);
109    assert(s);
110
111    if (proto == AVAHI_PROTO_UNSPEC) {
112        if (inet_pton(AF_INET, s, ret_addr->data.data) <= 0) {
113            if (inet_pton(AF_INET6, s, ret_addr->data.data) <= 0)
114                return NULL;
115            else
116                ret_addr->proto = AVAHI_PROTO_INET6;
117        } else
118            ret_addr->proto = AVAHI_PROTO_INET;
119    } else {
120        if (inet_pton(avahi_proto_to_af(proto), s, ret_addr->data.data) <= 0)
121            return NULL;
122
123        ret_addr->proto = proto;
124    }
125
126    return ret_addr;
127}
128
129int avahi_proto_to_af(AvahiProtocol proto) {
130    if (proto == AVAHI_PROTO_INET)
131        return AF_INET;
132    if (proto == AVAHI_PROTO_INET6)
133        return AF_INET6;
134
135    assert(proto == AVAHI_PROTO_UNSPEC);
136    return AF_UNSPEC;
137}
138
139AvahiProtocol avahi_af_to_proto(int af) {
140    if (af == AF_INET)
141        return AVAHI_PROTO_INET;
142    if (af == AF_INET6)
143        return AVAHI_PROTO_INET6;
144
145    assert(af == AF_UNSPEC);
146    return AVAHI_PROTO_UNSPEC;
147}
148
149const char* avahi_proto_to_string(AvahiProtocol proto) {
150    if (proto == AVAHI_PROTO_INET)
151        return "IPv4";
152    if (proto == AVAHI_PROTO_INET6)
153        return "IPv6";
154
155    assert(proto == AVAHI_PROTO_UNSPEC);
156    return "UNSPEC";
157}
158