4 This file is part of avahi.
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.
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.
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
26 #include "probe-sched.h"
29 #define AVAHI_PROBE_DEFER_MSEC 70
31 typedef struct AvahiProbeJob AvahiProbeJob;
33 struct AvahiProbeJob {
34 AvahiProbeScheduler *scheduler;
35 AvahiTimeEvent *time_event;
37 gboolean chosen; /* Use for packet assembling */
42 AVAHI_LLIST_FIELDS(AvahiProbeJob, jobs);
45 struct AvahiProbeScheduler {
46 AvahiInterface *interface;
47 AvahiTimeEventQueue *time_event_queue;
49 AVAHI_LLIST_HEAD(AvahiProbeJob, jobs);
52 static AvahiProbeJob* job_new(AvahiProbeScheduler *s, AvahiRecord *record) {
58 pj = g_new(AvahiProbeJob, 1);
60 pj->record = avahi_record_ref(record);
61 pj->time_event = NULL;
64 AVAHI_LLIST_PREPEND(AvahiProbeJob, jobs, s->jobs, pj);
69 static void job_free(AvahiProbeScheduler *s, AvahiProbeJob *pj) {
73 avahi_time_event_queue_remove(s->time_event_queue, pj->time_event);
75 AVAHI_LLIST_REMOVE(AvahiProbeJob, jobs, s->jobs, pj);
77 avahi_record_unref(pj->record);
82 AvahiProbeScheduler *avahi_probe_scheduler_new(AvahiInterface *i) {
83 AvahiProbeScheduler *s;
87 s = g_new(AvahiProbeScheduler, 1);
89 s->time_event_queue = i->monitor->server->time_event_queue;
91 AVAHI_LLIST_HEAD_INIT(AvahiProbeJob, s->jobs);
96 void avahi_probe_scheduler_free(AvahiProbeScheduler *s) {
99 avahi_probe_scheduler_clear(s);
103 void avahi_probe_scheduler_clear(AvahiProbeScheduler *s) {
107 job_free(s, s->jobs);
110 static gboolean packet_add_probe_query(AvahiProbeScheduler *s, AvahiDnsPacket *p, AvahiProbeJob *pj) {
119 g_assert(!pj->chosen);
121 /* Estimate the size for this record */
123 avahi_key_get_estimate_size(pj->record->key) +
124 avahi_record_get_estimate_size(pj->record);
127 if (size > avahi_dns_packet_space(p))
130 /* Create the probe query */
131 k = avahi_key_new(pj->record->key->name, pj->record->key->class, AVAHI_DNS_TYPE_ANY);
132 b = !!avahi_dns_packet_append_key(p, k, FALSE);
135 /* Mark this job for addition to the packet */
138 /* Scan for more jobs whith matching key pattern */
139 for (pj = s->jobs; pj; pj = pj->jobs_next) {
143 /* Does the record match the probe? */
144 if (k->class != pj->record->key->class || !avahi_domain_equal(k->name, pj->record->key->name))
147 /* This job wouldn't fit in */
148 if (avahi_record_get_estimate_size(pj->record) > avahi_dns_packet_space(p))
151 /* Mark this job for addition to the packet */
160 static void elapse_callback(AvahiTimeEvent *e, gpointer data) {
161 AvahiProbeJob *pj = data, *next;
162 AvahiProbeScheduler *s;
169 p = avahi_dns_packet_new_query(s->interface->hardware->mtu);
172 /* Add the import probe */
173 if (!packet_add_probe_query(s, p, pj)) {
178 avahi_dns_packet_free(p);
180 /* The probe didn't fit in the package, so let's allocate a larger one */
183 avahi_key_get_estimate_size(pj->record->key) +
184 avahi_record_get_estimate_size(pj->record) +
185 AVAHI_DNS_PACKET_HEADER_SIZE;
187 if (size > AVAHI_DNS_PACKET_MAX_SIZE)
188 size = AVAHI_DNS_PACKET_MAX_SIZE;
190 p = avahi_dns_packet_new_query(size);
192 k = avahi_key_new(pj->record->key->name, pj->record->key->class, AVAHI_DNS_TYPE_ANY);
193 b = avahi_dns_packet_append_key(p, k, FALSE) && avahi_dns_packet_append_record(p, pj->record, FALSE, 0);
197 avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_NSCOUNT, 1);
198 avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_QDCOUNT, 1);
199 avahi_interface_send_packet(s->interface, p);
201 g_warning("Probe record too large, cannot send");
203 avahi_dns_packet_free(p);
209 /* Try to fill up packet with more probes, if available */
210 for (pj = s->jobs; pj; pj = pj->jobs_next) {
215 if (!packet_add_probe_query(s, p, pj))
221 avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_QDCOUNT, n);
225 /* Now add the chosen records to the authorative section */
226 for (pj = s->jobs; pj; pj = next) {
228 next = pj->jobs_next;
233 if (!avahi_dns_packet_append_record(p, pj->record, FALSE, 0)) {
234 g_warning("Bad probe size estimate!");
236 /* Unmark all following jobs */
237 for (; pj; pj = pj->jobs_next)
248 avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_NSCOUNT, n);
251 avahi_interface_send_packet(s->interface, p);
252 avahi_dns_packet_free(p);
255 gboolean avahi_probe_scheduler_post(AvahiProbeScheduler *s, AvahiRecord *record, gboolean immediately) {
261 g_assert(!avahi_key_is_pattern(record->key));
263 avahi_elapse_time(&tv, immediately ? 0 : AVAHI_PROBE_DEFER_MSEC, 0);
265 /* Create a new job and schedule it */
266 pj = job_new(s, record);
268 pj->time_event = avahi_time_event_queue_add(s->time_event_queue, &pj->delivery, elapse_callback, pj);
270 /* g_message("Accepted new probe job."); */