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
;
25 AvahiEntryGroup
*group
;
30 OFFER
*offers_head
= NULL
;
31 OFFER
*offers_tail
= NULL
;
33 unsigned long reservate
= 0;
35 virConnectPtr conn
= NULL
; /* the hypervisor connection */
36 static AvahiSimplePoll
*simple_poll
= NULL
;
38 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
);
40 int accept_tender(const char *name
, unsigned long memory
, AvahiClient
*c
) {
43 if ((offer_new
= (OFFER
*) malloc(sizeof(OFFER
))) == NULL
) {
46 snprintf(domain
, 254, "%s.%s", name
, avahi_client_get_host_name_fqdn(c
));
47 offer_new
->name
= strdup(name
);
48 offer_new
->memory
= memory
;
49 offer_new
->reservate
= 1;
50 offer_new
->cost
= 0.0f
;
52 offer_new
->group
= avahi_entry_group_new(c
, entry_group_callback
, NULL
);
53 offer_new
->next
= NULL
;
55 /* TODO: enable givemetake only after domains are migrated! */
56 avahi_entry_group_add_service(offer_new
->group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, 0, domain
, "_tender._tcp", NULL
, NULL
, 651, "givemetake=1", NULL
, NULL
);
57 avahi_entry_group_commit(offer_new
->group
);
60 offers_head
= offer_new
;
62 offers_tail
->next
= offer_new
;
64 offers_tail
= offer_new
;
67 int offer_tender(const char *name
, unsigned long memory
, AvahiClient
*c
) {
69 unsigned long long free_memory
= virNodeGetFreeMemory(conn
) - reservate
;
70 char domain
[254], txt
[254];
72 if ((offer_new
= (OFFER
*) malloc(sizeof(OFFER
))) == NULL
) {
76 offer_new
->cost
= (float)memory
/ (float)free_memory
;
77 snprintf(domain
, 254, "%s.%s", name
, avahi_client_get_host_name_fqdn(c
));
78 snprintf(txt
, 254, "cost=%f", offer_new
->cost
);
80 printf("Puts hand up: %f\n", offer_new
->cost
);
82 /* Here we assume that Avahi will guarantee uniqueness */
83 offer_new
->name
= strdup(name
);
84 offer_new
->memory
= memory
;
85 offer_new
->reservate
= 0;
86 offer_new
->group
= avahi_entry_group_new(c
, entry_group_callback
, NULL
);
87 offer_new
->next
= NULL
;
88 avahi_entry_group_add_service(offer_new
->group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, 0, domain
, "_tender._tcp", NULL
, NULL
, 651, txt
, NULL
, NULL
);
89 avahi_entry_group_commit(offer_new
->group
);
93 offers_head
= offer_new
;
95 offers_tail
->next
= offer_new
;
97 offers_tail
= offer_new
;
100 int pull_tender(const char *name
) {
101 OFFER
*offer_prev
= NULL
;
102 OFFER
*offer_find
= offers_head
;
105 if (strcmp(offer_find
->name
, name
) == 0) {
106 if (offer_find
->reservate
== 1) reservate
=- offer_find
->memory
;
107 free(offer_find
->name
);
108 avahi_entry_group_free(offer_find
->group
);
110 offers_head
= offer_find
->next
;
112 offer_prev
->next
= offer_find
->next
;
117 offer_prev
= offer_find
;
118 offer_find
= offer_find
->next
;
126 static void resolve_callback(
127 AvahiServiceResolver
*r
,
128 AVAHI_GCC_UNUSED AvahiIfIndex interface
,
129 AVAHI_GCC_UNUSED AvahiProtocol protocol
,
130 AvahiResolverEvent event
,
134 const char *host_name
,
135 const AvahiAddress
*address
,
137 AvahiStringList
*txt
,
138 AvahiLookupResultFlags flags
,
139 AVAHI_GCC_UNUSED
void* userdata
) {
143 /* Called whenever a service has been resolved successfully or timed out */
146 case AVAHI_RESOLVER_FAILURE
:
147 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
))));
150 case AVAHI_RESOLVER_FOUND
: {
151 char a
[AVAHI_ADDRESS_STR_MAX
], *t
;
152 AvahiStringList
*needle
;
154 fprintf(stderr
, "Service '%s' of type '%s' in domain '%s':\n", name
, type
, domain
);
156 avahi_address_snprint(a
, sizeof(a
), address
);
157 t
= avahi_string_list_to_string(txt
);
169 avahi_string_list_get_service_cookie(txt
),
170 !!(flags
& AVAHI_LOOKUP_RESULT_LOCAL
),
171 !!(flags
& AVAHI_LOOKUP_RESULT_OUR_OWN
),
172 !!(flags
& AVAHI_LOOKUP_RESULT_WIDE_AREA
),
173 !!(flags
& AVAHI_LOOKUP_RESULT_MULTICAST
),
174 !!(flags
& AVAHI_LOOKUP_RESULT_CACHED
));
179 if ((needle
= avahi_string_list_find (txt
, "memory")) != NULL
) {
180 unsigned long int amount
;
182 avahi_string_list_get_pair (needle
, NULL
, &memory
, NULL
);
183 amount
= strtoul(memory
, NULL
, 10);
185 if (errno
!= ERANGE
&& amount
> 0) {
186 if ((needle
= avahi_string_list_find (txt
, "domain")) != NULL
) {
188 avahi_string_list_get_pair (needle
, NULL
, &winner
, NULL
);
190 if (strcmp(winner
, avahi_client_get_host_name_fqdn(avahi_service_resolver_get_client(r
))) == 0) {
191 accept_tender(name
, amount
, avahi_service_resolver_get_client(r
));
196 offer_tender(name
, amount
, avahi_service_resolver_get_client(r
));
205 avahi_service_resolver_free(r
);
208 static void browse_callback(
209 AvahiServiceBrowser
*b
,
210 AvahiIfIndex interface
,
211 AvahiProtocol protocol
,
212 AvahiBrowserEvent event
,
216 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
219 AvahiClient
*c
= userdata
;
222 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
225 case AVAHI_BROWSER_FAILURE
:
227 fprintf(stderr
, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))));
228 avahi_simple_poll_quit(simple_poll
);
231 case AVAHI_BROWSER_NEW
:
232 fprintf(stderr
, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
234 /* We ignore the returned resolver object. In the callback
235 function we free it. If the server is terminated before
236 the callback function is called the server will free
237 the resolver for us. */
239 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
, AVAHI_PROTO_UNSPEC
, 0, resolve_callback
, c
)))
240 fprintf(stderr
, "Failed to resolve service '%s': %s\n", name
, avahi_strerror(avahi_client_errno(c
)));
244 case AVAHI_BROWSER_REMOVE
:
246 fprintf(stderr
, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
249 case AVAHI_BROWSER_ALL_FOR_NOW
:
250 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
251 fprintf(stderr
, "(Browser) %s\n", event
== AVAHI_BROWSER_CACHE_EXHAUSTED
? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
256 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
) {
258 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
259 /* The entry group has been established successfully */
262 case AVAHI_ENTRY_GROUP_COLLISION
: {
263 /* A service name collision with a remote service
268 case AVAHI_ENTRY_GROUP_FAILURE
:
269 /* Some kind of failure happened while we were registering our services */
270 avahi_simple_poll_quit(simple_poll
);
273 case AVAHI_ENTRY_GROUP_UNCOMMITED
:
274 case AVAHI_ENTRY_GROUP_REGISTERING
:
279 static void client_callback(AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
) {
282 /* Called whenever the client or server state changes */
285 case AVAHI_CLIENT_S_RUNNING
:
286 /* The server has startup successfully and registered its host
287 * name on the network, so it's time to create our services */
290 case AVAHI_CLIENT_FAILURE
:
291 fprintf(stderr
, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c
)));
292 avahi_simple_poll_quit(simple_poll
);
295 case AVAHI_CLIENT_S_COLLISION
:
296 /* Let's drop our registered services. When the server is back
297 * in AVAHI_SERVER_RUNNING state we will register them
298 * again with the new host name. */
300 case AVAHI_CLIENT_S_REGISTERING
:
301 /* The server records are now being established. This
302 * might be caused by a host name change. We need to wait
303 * for our own records to register until the host name is
304 * properly esatblished. */
307 case AVAHI_CLIENT_CONNECTING
:
313 int main(AVAHI_GCC_UNUSED
int argc
, AVAHI_GCC_UNUSED
char*argv
[]) {
314 AvahiClient
*client
= NULL
;
315 AvahiServiceBrowser
*sb
= NULL
;
319 /* NULL means connect to local Xen hypervisor */
320 conn
= virConnectOpenReadOnly(NULL
);
322 fprintf(stderr
, "Failed to connect to hypervisor\n");
326 /* Allocate main loop object */
327 if (!(simple_poll
= avahi_simple_poll_new())) {
328 fprintf(stderr
, "Failed to create simple poll object.\n");
332 /* Allocate a new client */
333 client
= avahi_client_new(avahi_simple_poll_get(simple_poll
), 0, client_callback
, NULL
, &error
);
335 /* Check wether creating the client object succeeded */
337 fprintf(stderr
, "Failed to create client: %s\n", avahi_strerror(error
));
341 /* Create the service browser */
342 if (!(sb
= avahi_service_browser_new(client
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, "_offer._tcp", NULL
, 0, browse_callback
, client
))) {
343 fprintf(stderr
, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client
)));
348 /* Run the main loop */
349 avahi_simple_poll_loop(simple_poll
);
357 avahi_service_browser_free(sb
);
360 avahi_client_free(client
);
363 avahi_simple_poll_free(simple_poll
);
366 virConnectClose(conn
);