Changed the node code so it also works on systems that have multiple
[handlervirt.git] / offer.c
blobcd9f1b6abbf4ba8af76130f89238d06d079f2dbd
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <errno.h>
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;
21 struct offer {
22 char *name;
23 float cost;
24 unsigned long memory;
25 AvahiEntryGroup *group;
26 short int reservate;
27 OFFER *next;
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) {
40 OFFER * offer_new;
41 char domain[254];
42 if ((offer_new = (OFFER *) malloc(sizeof(OFFER))) == NULL) {
43 return -1;
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;
50 reservate =+ memory;
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);
58 if (!offers_head)
59 offers_head = offer_new;
60 else
61 offers_tail->next = offer_new;
63 offers_tail = offer_new;
66 int offer_tender(const char *name, unsigned long memory, AvahiClient *c) {
67 OFFER * offer_new;
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);
75 if (conn == NULL) {
76 fprintf(stderr, "Failed to connect to hypervisor\n");
77 return -1;
80 free_memory = virNodeGetFreeMemory(conn) - reservate;
81 virConnectClose(conn);
83 if ((offer_new = (OFFER *) malloc(sizeof(OFFER))) == NULL) {
84 return -1;
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);
103 if (!offers_head)
104 offers_head = offer_new;
105 else
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;
115 while (offer_find) {
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);
120 if (!offer_prev)
121 offers_head = offer_find->next;
122 else
123 offer_prev->next = offer_find->next;
125 free(offer_find);
126 return 0;
127 } else {
128 offer_prev = offer_find;
129 offer_find = offer_find->next;
132 return -1;
137 static void resolve_callback(
138 AvahiServiceResolver *r,
139 AVAHI_GCC_UNUSED AvahiIfIndex interface,
140 AVAHI_GCC_UNUSED AvahiProtocol protocol,
141 AvahiResolverEvent event,
142 const char *name,
143 const char *type,
144 const char *domain,
145 const char *host_name,
146 const AvahiAddress *address,
147 uint16_t port,
148 AvahiStringList *txt,
149 AvahiLookupResultFlags flags,
150 AVAHI_GCC_UNUSED void* userdata) {
152 assert(r);
154 /* Called whenever a service has been resolved successfully or timed out */
156 switch (event) {
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))));
159 break;
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);
169 fprintf(stderr,
170 "\t%s:%u (%s)\n"
171 "\tTXT=%s\n"
172 "\tcookie is %u\n"
173 "\tis_local: %i\n"
174 "\tour_own: %i\n"
175 "\twide_area: %i\n"
176 "\tmulticast: %i\n"
177 "\tcached: %i\n",
178 host_name, port, a,
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));
187 avahi_free(t);*/
190 if ((needle = avahi_string_list_find (txt, "memory")) != NULL) {
191 unsigned long int amount;
192 char *memory;
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) {
198 char *winner;
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));
205 avahi_free(winner);
206 } else {
207 offer_tender(name, amount, avahi_service_resolver_get_client(r));
211 avahi_free(memory);
216 avahi_service_resolver_free(r);
219 static void browse_callback(
220 AvahiServiceBrowser *b,
221 AvahiIfIndex interface,
222 AvahiProtocol protocol,
223 AvahiBrowserEvent event,
224 const char *name,
225 const char *type,
226 const char *domain,
227 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
228 AVAHI_GCC_UNUSED void* userdata) {
230 assert(b);
232 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
234 switch (event) {
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);
238 return;
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)));
252 break;
255 case AVAHI_BROWSER_REMOVE:
256 pull_tender(name);
257 fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
258 break;
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");
263 break;
267 static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) {
268 switch (state) {
269 case AVAHI_ENTRY_GROUP_ESTABLISHED :
270 /* The entry group has been established successfully */
271 break;
273 case AVAHI_ENTRY_GROUP_COLLISION : {
274 /* A service name collision with a remote service
275 * happened. */
276 break;
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);
282 break;
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 */
294 switch (state) {
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)));
303 break;
305 case AVAHI_CLIENT_FAILURE: {
306 int error;
307 AvahiClient *client;
309 if (c) {
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);
316 break;
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. */
329 break;
331 case AVAHI_CLIENT_CONNECTING:
337 int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
338 int error;
339 int ret = 1;
341 /* Allocate main loop object */
342 if (!(simple_poll = avahi_simple_poll_new())) {
343 fprintf(stderr, "Failed to create simple poll object.\n");
344 goto fail;
347 client_callback(NULL, AVAHI_CLIENT_FAILURE, NULL);
349 /* Run the main loop */
350 avahi_simple_poll_loop(simple_poll);
352 ret = 0;
354 fail:
356 /* Cleanup things */
358 if (simple_poll)
359 avahi_simple_poll_free(simple_poll);
361 return ret;