6 #include <avahi-client/client.h>
7 #include <avahi-client/publish.h>
8 #include <avahi-client/lookup.h>
10 #include <avahi-common/alternative.h>
11 #include <avahi-common/simple-watch.h>
12 #include <avahi-common/malloc.h>
13 #include <avahi-common/error.h>
14 #include <avahi-common/timeval.h>
16 #include <libvirt/libvirt.h>
19 typedef struct offer OFFER
;
24 AvahiEntryGroup
*group
;
28 OFFER
*offers_head
= NULL
;
29 OFFER
*offers_tail
= NULL
;
31 virConnectPtr conn
= NULL
; /* the hypervisor connection */
32 static AvahiSimplePoll
*simple_poll
= NULL
;
34 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
);
38 int offer_tender(const char *name
, unsigned long memory
, AvahiClient
*c
) {
40 unsigned long long free_memory
= virNodeGetFreeMemory(conn
);
41 char domain
[254], txt
[254];
43 if ((offer_new
= (OFFER
*) malloc(sizeof(OFFER
))) == NULL
) {
47 snprintf(domain
, 254, "%s.%s", name
, avahi_client_get_domain_name(c
));
48 snprintf(txt
, 254, "cost=%f", (float)memory
/ (float)free_memory
);
52 /* Here we assume that Avahi will guarantee uniqueness */
53 offer_new
->name
= strdup(name
);
54 offer_new
->memory
= memory
;
55 offer_new
->group
= avahi_entry_group_new(c
, entry_group_callback
, NULL
);
56 offer_new
->next
= NULL
;
57 avahi_entry_group_add_service(offer_new
->group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, 0, domain
, "_tender._tcp", NULL
, NULL
, 651, txt
, NULL
, NULL
);
58 avahi_entry_group_commit(offer_new
->group
);
62 offers_head
= offer_new
;
64 offers_tail
->next
= offer_new
;
66 offers_tail
= offer_new
;
69 int pull_tender(const char *name
) {
70 OFFER
*offer_prev
= NULL
;
71 OFFER
*offer_find
= offers_head
;
74 if (strcmp(offer_find
->name
, name
) == 0) {
75 free(offer_find
->name
);
76 avahi_entry_group_free(offer_find
->group
);
78 offers_head
= offer_find
->next
;
80 offer_prev
->next
= offer_find
->next
;
85 offer_prev
= offer_find
;
86 offer_find
= offer_find
->next
;
94 static void resolve_callback(
95 AvahiServiceResolver
*r
,
96 AVAHI_GCC_UNUSED AvahiIfIndex interface
,
97 AVAHI_GCC_UNUSED AvahiProtocol protocol
,
98 AvahiResolverEvent event
,
102 const char *host_name
,
103 const AvahiAddress
*address
,
105 AvahiStringList
*txt
,
106 AvahiLookupResultFlags flags
,
107 AVAHI_GCC_UNUSED
void* userdata
) {
111 /* Called whenever a service has been resolved successfully or timed out */
114 case AVAHI_RESOLVER_FAILURE
:
115 fprintf(stderr
, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name
, type
, domain
, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r
))));
118 case AVAHI_RESOLVER_FOUND
: {
119 char a
[AVAHI_ADDRESS_STR_MAX
], *t
;
120 AvahiStringList
*needle
;
122 fprintf(stderr
, "Service '%s' of type '%s' in domain '%s':\n", name
, type
, domain
);
124 avahi_address_snprint(a
, sizeof(a
), address
);
125 t
= avahi_string_list_to_string(txt
);
137 avahi_string_list_get_service_cookie(txt
),
138 !!(flags
& AVAHI_LOOKUP_RESULT_LOCAL
),
139 !!(flags
& AVAHI_LOOKUP_RESULT_OUR_OWN
),
140 !!(flags
& AVAHI_LOOKUP_RESULT_WIDE_AREA
),
141 !!(flags
& AVAHI_LOOKUP_RESULT_MULTICAST
),
142 !!(flags
& AVAHI_LOOKUP_RESULT_CACHED
));
146 if ((needle
= avahi_string_list_find (txt
, "memory")) != NULL
) {
147 unsigned long int amount
;
149 avahi_string_list_get_pair (needle
, NULL
, &memory
, NULL
);
150 amount
= strtoul(memory
, NULL
, 10);
152 if (errno
!= ERANGE
&& amount
> 0)
153 offer_tender(name
, amount
, avahi_service_resolver_get_client(r
));
160 avahi_service_resolver_free(r
);
163 static void browse_callback(
164 AvahiServiceBrowser
*b
,
165 AvahiIfIndex interface
,
166 AvahiProtocol protocol
,
167 AvahiBrowserEvent event
,
171 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
174 AvahiClient
*c
= userdata
;
177 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
180 case AVAHI_BROWSER_FAILURE
:
182 fprintf(stderr
, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))));
183 avahi_simple_poll_quit(simple_poll
);
186 case AVAHI_BROWSER_NEW
:
187 fprintf(stderr
, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
189 /* We ignore the returned resolver object. In the callback
190 function we free it. If the server is terminated before
191 the callback function is called the server will free
192 the resolver for us. */
194 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
, AVAHI_PROTO_UNSPEC
, 0, resolve_callback
, c
)))
195 fprintf(stderr
, "Failed to resolve service '%s': %s\n", name
, avahi_strerror(avahi_client_errno(c
)));
199 case AVAHI_BROWSER_REMOVE
:
201 fprintf(stderr
, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
204 case AVAHI_BROWSER_ALL_FOR_NOW
:
205 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
206 fprintf(stderr
, "(Browser) %s\n", event
== AVAHI_BROWSER_CACHE_EXHAUSTED
? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
211 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
) {
213 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
214 /* The entry group has been established successfully */
217 case AVAHI_ENTRY_GROUP_COLLISION
: {
218 /* A service name collision with a remote service
223 case AVAHI_ENTRY_GROUP_FAILURE
:
224 /* Some kind of failure happened while we were registering our services */
225 avahi_simple_poll_quit(simple_poll
);
228 case AVAHI_ENTRY_GROUP_UNCOMMITED
:
229 case AVAHI_ENTRY_GROUP_REGISTERING
:
234 static void client_callback(AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
) {
237 /* Called whenever the client or server state changes */
240 case AVAHI_CLIENT_S_RUNNING
:
241 /* The server has startup successfully and registered its host
242 * name on the network, so it's time to create our services */
245 case AVAHI_CLIENT_FAILURE
:
246 fprintf(stderr
, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c
)));
247 avahi_simple_poll_quit(simple_poll
);
250 case AVAHI_CLIENT_S_COLLISION
:
251 /* Let's drop our registered services. When the server is back
252 * in AVAHI_SERVER_RUNNING state we will register them
253 * again with the new host name. */
255 case AVAHI_CLIENT_S_REGISTERING
:
256 /* The server records are now being established. This
257 * might be caused by a host name change. We need to wait
258 * for our own records to register until the host name is
259 * properly esatblished. */
262 case AVAHI_CLIENT_CONNECTING
:
268 int main(AVAHI_GCC_UNUSED
int argc
, AVAHI_GCC_UNUSED
char*argv
[]) {
269 AvahiClient
*client
= NULL
;
270 AvahiServiceBrowser
*sb
= NULL
;
274 /* NULL means connect to local Xen hypervisor */
275 conn
= virConnectOpenReadOnly(NULL
);
277 fprintf(stderr
, "Failed to connect to hypervisor\n");
281 /* Allocate main loop object */
282 if (!(simple_poll
= avahi_simple_poll_new())) {
283 fprintf(stderr
, "Failed to create simple poll object.\n");
287 /* Allocate a new client */
288 client
= avahi_client_new(avahi_simple_poll_get(simple_poll
), 0, client_callback
, NULL
, &error
);
290 /* Check wether creating the client object succeeded */
292 fprintf(stderr
, "Failed to create client: %s\n", avahi_strerror(error
));
296 /* Create the service browser */
297 if (!(sb
= avahi_service_browser_new(client
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, "_offer._tcp", NULL
, 0, browse_callback
, client
))) {
298 fprintf(stderr
, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client
)));
303 /* Run the main loop */
304 avahi_simple_poll_loop(simple_poll
);
312 avahi_service_browser_free(sb
);
315 avahi_client_free(client
);
318 avahi_simple_poll_free(simple_poll
);
321 virConnectClose(conn
);