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
));
194 offer_tender(name
, amount
, avahi_service_resolver_get_client(r
));
203 avahi_service_resolver_free(r
);
206 static void browse_callback(
207 AvahiServiceBrowser
*b
,
208 AvahiIfIndex interface
,
209 AvahiProtocol protocol
,
210 AvahiBrowserEvent event
,
214 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
217 AvahiClient
*c
= userdata
;
220 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
223 case AVAHI_BROWSER_FAILURE
:
225 fprintf(stderr
, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))));
226 avahi_simple_poll_quit(simple_poll
);
229 case AVAHI_BROWSER_NEW
:
230 fprintf(stderr
, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
232 /* We ignore the returned resolver object. In the callback
233 function we free it. If the server is terminated before
234 the callback function is called the server will free
235 the resolver for us. */
237 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
, AVAHI_PROTO_UNSPEC
, 0, resolve_callback
, c
)))
238 fprintf(stderr
, "Failed to resolve service '%s': %s\n", name
, avahi_strerror(avahi_client_errno(c
)));
242 case AVAHI_BROWSER_REMOVE
:
244 fprintf(stderr
, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
247 case AVAHI_BROWSER_ALL_FOR_NOW
:
248 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
249 fprintf(stderr
, "(Browser) %s\n", event
== AVAHI_BROWSER_CACHE_EXHAUSTED
? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
254 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
) {
256 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
257 /* The entry group has been established successfully */
260 case AVAHI_ENTRY_GROUP_COLLISION
: {
261 /* A service name collision with a remote service
266 case AVAHI_ENTRY_GROUP_FAILURE
:
267 /* Some kind of failure happened while we were registering our services */
268 avahi_simple_poll_quit(simple_poll
);
271 case AVAHI_ENTRY_GROUP_UNCOMMITED
:
272 case AVAHI_ENTRY_GROUP_REGISTERING
:
277 static void client_callback(AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
) {
280 /* Called whenever the client or server state changes */
283 case AVAHI_CLIENT_S_RUNNING
:
284 /* The server has startup successfully and registered its host
285 * name on the network, so it's time to create our services */
288 case AVAHI_CLIENT_FAILURE
:
289 fprintf(stderr
, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c
)));
290 avahi_simple_poll_quit(simple_poll
);
293 case AVAHI_CLIENT_S_COLLISION
:
294 /* Let's drop our registered services. When the server is back
295 * in AVAHI_SERVER_RUNNING state we will register them
296 * again with the new host name. */
298 case AVAHI_CLIENT_S_REGISTERING
:
299 /* The server records are now being established. This
300 * might be caused by a host name change. We need to wait
301 * for our own records to register until the host name is
302 * properly esatblished. */
305 case AVAHI_CLIENT_CONNECTING
:
311 int main(AVAHI_GCC_UNUSED
int argc
, AVAHI_GCC_UNUSED
char*argv
[]) {
312 AvahiClient
*client
= NULL
;
313 AvahiServiceBrowser
*sb
= NULL
;
317 /* NULL means connect to local Xen hypervisor */
318 conn
= virConnectOpenReadOnly(NULL
);
320 fprintf(stderr
, "Failed to connect to hypervisor\n");
324 /* Allocate main loop object */
325 if (!(simple_poll
= avahi_simple_poll_new())) {
326 fprintf(stderr
, "Failed to create simple poll object.\n");
330 /* Allocate a new client */
331 client
= avahi_client_new(avahi_simple_poll_get(simple_poll
), 0, client_callback
, NULL
, &error
);
333 /* Check wether creating the client object succeeded */
335 fprintf(stderr
, "Failed to create client: %s\n", avahi_strerror(error
));
339 /* Create the service browser */
340 if (!(sb
= avahi_service_browser_new(client
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, "_offer._tcp", NULL
, 0, browse_callback
, client
))) {
341 fprintf(stderr
, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client
)));
346 /* Run the main loop */
347 avahi_simple_poll_loop(simple_poll
);
355 avahi_service_browser_free(sb
);
358 avahi_client_free(client
);
361 avahi_simple_poll_free(simple_poll
);
364 virConnectClose(conn
);