1/***
2  This file is part of avahi.
3
4  avahi is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Lesser General Public License as
6  published by the Free Software Foundation; either version 2.1 of the
7  License, or (at your option) any later version.
8
9  avahi is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12  Public License for more details.
13
14  You should have received a copy of the GNU Lesser General Public
15  License along with avahi; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  USA.
18***/
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <stdlib.h>
25#include <assert.h>
26
27#include <avahi-common/llist.h>
28#include <avahi-common/malloc.h>
29
30#include "rrlist.h"
31#include "log.h"
32
33typedef struct AvahiRecordListItem AvahiRecordListItem;
34
35struct AvahiRecordListItem {
36    int read;
37    AvahiRecord *record;
38    int unicast_response;
39    int flush_cache;
40    int auxiliary;
41    AVAHI_LLIST_FIELDS(AvahiRecordListItem, items);
42};
43
44struct AvahiRecordList {
45    AVAHI_LLIST_HEAD(AvahiRecordListItem, read);
46    AVAHI_LLIST_HEAD(AvahiRecordListItem, unread);
47
48    int all_flush_cache;
49};
50
51AvahiRecordList *avahi_record_list_new(void) {
52    AvahiRecordList *l;
53
54    if (!(l = avahi_new(AvahiRecordList, 1))) {
55        avahi_log_error("avahi_new() failed.");
56        return NULL;
57    }
58
59    AVAHI_LLIST_HEAD_INIT(AvahiRecordListItem, l->read);
60    AVAHI_LLIST_HEAD_INIT(AvahiRecordListItem, l->unread);
61
62    l->all_flush_cache = 1;
63    return l;
64}
65
66void avahi_record_list_free(AvahiRecordList *l) {
67    assert(l);
68
69    avahi_record_list_flush(l);
70    avahi_free(l);
71}
72
73static void item_free(AvahiRecordList *l, AvahiRecordListItem *i) {
74    assert(l);
75    assert(i);
76
77    if (i->read)
78        AVAHI_LLIST_REMOVE(AvahiRecordListItem, items, l->read, i);
79    else
80        AVAHI_LLIST_REMOVE(AvahiRecordListItem, items, l->unread, i);
81
82    avahi_record_unref(i->record);
83    avahi_free(i);
84}
85
86void avahi_record_list_flush(AvahiRecordList *l) {
87    assert(l);
88
89    while (l->read)
90        item_free(l, l->read);
91    while (l->unread)
92        item_free(l, l->unread);
93
94    l->all_flush_cache = 1;
95}
96
97AvahiRecord* avahi_record_list_next(AvahiRecordList *l, int *ret_flush_cache, int *ret_unicast_response, int *ret_auxiliary) {
98    AvahiRecord *r;
99    AvahiRecordListItem *i;
100
101    if (!(i = l->unread))
102        return NULL;
103
104    assert(!i->read);
105
106    r = avahi_record_ref(i->record);
107    if (ret_unicast_response)
108        *ret_unicast_response = i->unicast_response;
109    if (ret_flush_cache)
110        *ret_flush_cache = i->flush_cache;
111    if (ret_auxiliary)
112        *ret_auxiliary = i->auxiliary;
113
114    AVAHI_LLIST_REMOVE(AvahiRecordListItem, items, l->unread, i);
115    AVAHI_LLIST_PREPEND(AvahiRecordListItem, items, l->read, i);
116
117    i->read = 1;
118
119    return r;
120}
121
122static AvahiRecordListItem *get(AvahiRecordList *l, AvahiRecord *r) {
123    AvahiRecordListItem *i;
124
125    assert(l);
126    assert(r);
127
128    for (i = l->read; i; i = i->items_next)
129        if (avahi_record_equal_no_ttl(i->record, r))
130            return i;
131
132    for (i = l->unread; i; i = i->items_next)
133        if (avahi_record_equal_no_ttl(i->record, r))
134            return i;
135
136    return NULL;
137}
138
139void avahi_record_list_push(AvahiRecordList *l, AvahiRecord *r, int flush_cache, int unicast_response, int auxiliary) {
140    AvahiRecordListItem *i;
141
142    assert(l);
143    assert(r);
144
145    if (get(l, r))
146        return;
147
148    if (!(i = avahi_new(AvahiRecordListItem, 1))) {
149        avahi_log_error("avahi_new() failed.");
150        return;
151    }
152
153    i->unicast_response = unicast_response;
154    i->flush_cache = flush_cache;
155    i->auxiliary = auxiliary;
156    i->record = avahi_record_ref(r);
157    i->read = 0;
158
159    l->all_flush_cache = l->all_flush_cache && flush_cache;
160
161    AVAHI_LLIST_PREPEND(AvahiRecordListItem, items, l->unread, i);
162}
163
164void avahi_record_list_drop(AvahiRecordList *l, AvahiRecord *r) {
165    AvahiRecordListItem *i;
166
167    assert(l);
168    assert(r);
169
170    if (!(i = get(l, r)))
171        return;
172
173    item_free(l, i);
174}
175
176int avahi_record_list_is_empty(AvahiRecordList *l) {
177    assert(l);
178
179    return !l->unread && !l->read;
180}
181
182int avahi_record_list_all_flush_cache(AvahiRecordList *l) {
183    assert(l);
184
185    /* Return TRUE if all entries in this list have flush_cache set */
186
187    return l->all_flush_cache;
188}
189