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 static AvahiSimplePoll
*simple_poll
= NULL
;
37 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
);
39 int accept_tender(const char *name
, unsigned long memory
, AvahiClient
*c
) {
42 if ((offer_new
= (OFFER
*) malloc(sizeof(OFFER
))) == NULL
) {
45 snprintf(domain
, 254, "%s.%s", name
, avahi_client_get_host_name_fqdn(c
));
46 offer_new
->name
= strdup(name
);
47 offer_new
->memory
= memory
;
48 offer_new
->reservate
= 1;
49 offer_new
->cost
= 0.0f
;
51 offer_new
->group
= avahi_entry_group_new(c
, entry_group_callback
, NULL
);
52 offer_new
->next
= NULL
;
54 /* TODO: enable givemetake only after domains are migrated! */
55 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
);
56 avahi_entry_group_commit(offer_new
->group
);
59 offers_head
= offer_new
;
61 offers_tail
->next
= offer_new
;
63 offers_tail
= offer_new
;
66 int offer_tender(const char *name
, unsigned long memory
, AvahiClient
*c
) {
68 virConnectPtr conn
= NULL
; /* the hypervisor connection */
70 unsigned long long free_memory
;
71 char domain
[254], txt
[254];
73 /* NULL means connect to local Xen hypervisor */
74 conn
= virConnectOpenReadOnly(NULL
);
76 fprintf(stderr
, "Failed to connect to hypervisor\n");
80 free_memory
= virNodeGetFreeMemory(conn
) - reservate
;
81 virConnectClose(conn
);
83 if ((offer_new
= (OFFER
*) malloc(sizeof(OFFER
))) == NULL
) {
87 offer_new
->cost
= (float)memory
/ (float)free_memory
;
88 snprintf(domain
, 254, "%s.%s", name
, avahi_client_get_host_name_fqdn(c
));
89 snprintf(txt
, 254, "cost=%f", offer_new
->cost
);
91 printf("Puts hand up: %f\n", offer_new
->cost
);
93 /* Here we assume that Avahi will guarantee uniqueness */
94 offer_new
->name
= strdup(name
);
95 offer_new
->memory
= memory
;
96 offer_new
->reservate
= 0;
97 offer_new
->group
= avahi_entry_group_new(c
, entry_group_callback
, NULL
);
98 offer_new
->next
= NULL
;
99 avahi_entry_group_add_service(offer_new
->group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, 0, domain
, "_tender._tcp", NULL
, NULL
, 651, txt
, NULL
, NULL
);
100 avahi_entry_group_commit(offer_new
->group
);
104 offers_head
= offer_new
;
106 offers_tail
->next
= offer_new
;
108 offers_tail
= offer_new
;
111 int pull_tender(const char *name
) {
112 OFFER
*offer_prev
= NULL
;
113 OFFER
*offer_find
= offers_head
;
116 if (strcmp(offer_find
->name
, name
) == 0) {
117 if (offer_find
->reservate
== 1) reservate
=- offer_find
->memory
;
118 free(offer_find
->name
);
119 avahi_entry_group_free(offer_find
->group
);
121 offers_head
= offer_find
->next
;
123 offer_prev
->next
= offer_find
->next
;
128 offer_prev
= offer_find
;
129 offer_find
= offer_find
->next
;
137 static void resolve_callback(
138 AvahiServiceResolver
*r
,
139 AVAHI_GCC_UNUSED AvahiIfIndex interface
,
140 AVAHI_GCC_UNUSED AvahiProtocol protocol
,
141 AvahiResolverEvent event
,
145 const char *host_name
,
146 const AvahiAddress
*address
,
148 AvahiStringList
*txt
,
149 AvahiLookupResultFlags flags
,
150 AVAHI_GCC_UNUSED
void* userdata
) {
154 /* Called whenever a service has been resolved successfully or timed out */
157 case AVAHI_RESOLVER_FAILURE
:
158 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
))));
161 case AVAHI_RESOLVER_FOUND
: {
162 AvahiStringList
*needle
;
163 /* char a[AVAHI_ADDRESS_STR_MAX], *t;
165 fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
167 avahi_address_snprint(a, sizeof(a), address);
168 t = avahi_string_list_to_string(txt);
180 avahi_string_list_get_service_cookie(txt),
181 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
182 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
183 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
184 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
185 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
190 if ((needle
= avahi_string_list_find (txt
, "memory")) != NULL
) {
191 unsigned long int amount
;
193 avahi_string_list_get_pair (needle
, NULL
, &memory
, NULL
);
194 amount
= strtoul(memory
, NULL
, 10);
196 if (errno
!= ERANGE
&& amount
> 0) {
197 if ((needle
= avahi_string_list_find (txt
, "domain")) != NULL
) {
199 avahi_string_list_get_pair (needle
, NULL
, &winner
, NULL
);
201 if (strcmp(winner
, avahi_client_get_host_name_fqdn(avahi_service_resolver_get_client(r
))) == 0) {
202 accept_tender(name
, amount
, avahi_service_resolver_get_client(r
));
207 offer_tender(name
, amount
, avahi_service_resolver_get_client(r
));
216 avahi_service_resolver_free(r
);
219 static void browse_callback(
220 AvahiServiceBrowser
*b
,
221 AvahiIfIndex interface
,
222 AvahiProtocol protocol
,
223 AvahiBrowserEvent event
,
227 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
228 AVAHI_GCC_UNUSED
void* userdata
) {
232 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
235 case AVAHI_BROWSER_FAILURE
:
236 fprintf(stderr
, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))));
237 avahi_service_browser_free(b
);
240 case AVAHI_BROWSER_NEW
: {
241 AvahiClient
*c
= avahi_service_browser_get_client(b
);
242 fprintf(stderr
, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
244 /* We ignore the returned resolver object. In the callback
245 function we free it. If the server is terminated before
246 the callback function is called the server will free
247 the resolver for us. */
249 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
, AVAHI_PROTO_UNSPEC
, 0, resolve_callback
, NULL
)))
250 fprintf(stderr
, "Failed to resolve service '%s': %s\n", name
, avahi_strerror(avahi_client_errno(c
)));
255 case AVAHI_BROWSER_REMOVE
:
257 fprintf(stderr
, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
260 case AVAHI_BROWSER_ALL_FOR_NOW
:
261 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
262 fprintf(stderr
, "(Browser) %s\n", event
== AVAHI_BROWSER_CACHE_EXHAUSTED
? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
267 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
) {
269 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
270 /* The entry group has been established successfully */
273 case AVAHI_ENTRY_GROUP_COLLISION
: {
274 /* A service name collision with a remote service
279 case AVAHI_ENTRY_GROUP_FAILURE
:
280 /* Some kind of failure happened while we were registering our services */
281 // avahi_simple_poll_quit(simple_poll);
284 case AVAHI_ENTRY_GROUP_UNCOMMITED
:
285 case AVAHI_ENTRY_GROUP_REGISTERING
:
290 static void client_callback(AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
) {
292 /* Called whenever the client or server state changes */
295 case AVAHI_CLIENT_S_RUNNING
:
296 /* The server has startup successfully and registered its host
297 * name on the network, so it's time to create our services */
299 if (!avahi_service_browser_new(c
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, "_offer._tcp", NULL
, 0, browse_callback
, NULL
)) {
300 fprintf(stderr
, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(c
)));
305 case AVAHI_CLIENT_FAILURE
: {
310 fprintf(stderr
, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c
)));
311 avahi_client_free(c
);
314 /* Allocate a new client */
315 client
= avahi_client_new(avahi_simple_poll_get(simple_poll
), AVAHI_CLIENT_NO_FAIL
, client_callback
, NULL
, &error
);
319 case AVAHI_CLIENT_S_COLLISION
:
320 /* Let's drop our registered services. When the server is back
321 * in AVAHI_SERVER_RUNNING state we will register them
322 * again with the new host name. */
324 case AVAHI_CLIENT_S_REGISTERING
:
325 /* The server records are now being established. This
326 * might be caused by a host name change. We need to wait
327 * for our own records to register until the host name is
328 * properly esatblished. */
331 case AVAHI_CLIENT_CONNECTING
:
337 int main(AVAHI_GCC_UNUSED
int argc
, AVAHI_GCC_UNUSED
char*argv
[]) {
341 /* Allocate main loop object */
342 if (!(simple_poll
= avahi_simple_poll_new())) {
343 fprintf(stderr
, "Failed to create simple poll object.\n");
347 client_callback(NULL
, AVAHI_CLIENT_FAILURE
, NULL
);
349 /* Run the main loop */
350 avahi_simple_poll_loop(simple_poll
);
359 avahi_simple_poll_free(simple_poll
);