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 <stdlib.h>
27#include <assert.h>
28
29#include <avahi-common/llist.h>
30#include <avahi-common/malloc.h>
31
32#include "rrlist.h"
33#include "log.h"
34
35typedef struct AvahiRecordListItem AvahiRecordListItem;
36
37struct AvahiRecordListItem {
38    int read;
39    AvahiRecord *record;
40    int unicast_response;
41    int flush_cache;
42    int auxiliary;
43    AVAHI_LLIST_FIELDS(AvahiRecordListItem, items);
44};
45
46struct AvahiRecordList {
47    AVAHI_LLIST_HEAD(AvahiRecordListItem, read);
48    AVAHI_LLIST_HEAD(AvahiRecordListItem, unread);
49
50    int all_flush_cache;
51};
52
53AvahiRecordList *avahi_record_list_new(void) {
54    AvahiRecordList *l;
55
56    if (!(l = avahi_new(AvahiRecordList, 1))) {
57        avahi_log_error("avahi_new() failed.");
58        return NULL;
59    }
60
61    AVAHI_LLIST_HEAD_INIT(AvahiRecordListItem, l->read);
62    AVAHI_LLIST_HEAD_INIT(AvahiRecordListItem, l->unread);
63
64    l->all_flush_cache = 1;
65    return l;
66}
67
68void avahi_record_list_free(AvahiRecordList *l) {
69    assert(l);
70
71    avahi_record_list_flush(l);
72    avahi_free(l);
73}
74
75static void item_free(AvahiRecordList *l, AvahiRecordListItem *i) {
76    assert(l);
77    assert(i);
78
79    if (i->read)
80        AVAHI_LLIST_REMOVE(AvahiRecordListItem, items, l->read, i);
81    else
82        AVAHI_LLIST_REMOVE(AvahiRecordListItem, items, l->unread, i);
83
84    avahi_record_unref(i->record);
85    avahi_free(i);
86}
87
88void avahi_record_list_flush(AvahiRecordList *l) {
89    assert(l);
90
91    while (l->read)
92        item_free(l, l->read);
93    while (l->unread)
94        item_free(l, l->unread);
95
96    l->all_flush_cache = 1;
97}
98
99AvahiRecord* avahi_record_list_next(AvahiRecordList *l, int *ret_flush_cache, int *ret_unicast_response, int *ret_auxiliary) {
100    AvahiRecord *r;
101    AvahiRecordListItem *i;
102
103    if (!(i = l->unread))
104        return NULL;
105
106    assert(!i->read);
107
108    r = avahi_record_ref(i->record);
109    if (ret_unicast_response)
110        *ret_unicast_response = i->unicast_response;
111    if (ret_flush_cache)
112        *ret_flush_cache = i->flush_cache;
113    if (ret_auxiliary)
114        *ret_auxiliary = i->auxiliary;
115
116    AVAHI_LLIST_REMOVE(AvahiRecordListItem, items, l->unread, i);
117    AVAHI_LLIST_PREPEND(AvahiRecordListItem, items, l->read, i);
118
119    i->read = 1;
120
121    return r;
122}
123
124static AvahiRecordListItem *get(AvahiRecordList *l, AvahiRecord *r) {
125    AvahiRecordListItem *i;
126
127    assert(l);
128    assert(r);
129
130    for (i = l->read; i; i = i->items_next)
131        if (avahi_record_equal_no_ttl(i->record, r))
132            return i;
133
134    for (i = l->unread; i; i = i->items_next)
135        if (avahi_record_equal_no_ttl(i->record, r))
136            return i;
137
138    return NULL;
139}
140
141void avahi_record_list_push(AvahiRecordList *l, AvahiRecord *r, int flush_cache, int unicast_response, int auxiliary) {
142    AvahiRecordListItem *i;
143
144    assert(l);
145    assert(r);
146
147    if (get(l, r))
148        return;
149
150    if (!(i = avahi_new(AvahiRecordListItem, 1))) {
151        avahi_log_error("avahi_new() failed.");
152        return;
153    }
154
155    i->unicast_response = unicast_response;
156    i->flush_cache = flush_cache;
157    i->auxiliary = auxiliary;
158    i->record = avahi_record_ref(r);
159    i->read = 0;
160
161    l->all_flush_cache = l->all_flush_cache && flush_cache;
162
163    AVAHI_LLIST_PREPEND(AvahiRecordListItem, items, l->unread, i);
164}
165
166void avahi_record_list_drop(AvahiRecordList *l, AvahiRecord *r) {
167    AvahiRecordListItem *i;
168
169    assert(l);
170    assert(r);
171
172    if (!(i = get(l, r)))
173        return;
174
175    item_free(l, i);
176}
177
178int avahi_record_list_is_empty(AvahiRecordList *l) {
179    assert(l);
180
181    return !l->unread && !l->read;
182}
183
184int avahi_record_list_all_flush_cache(AvahiRecordList *l) {
185    assert(l);
186
187    /* Return TRUE if all entries in this list have flush_cache set */
188
189    return l->all_flush_cache;
190}
191