Kernelcmdline, end for rrd
[handlervirt.git] / offer.c
blob23f7934a0f490fb714b964d213651091e7ea6925
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 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) {
41 OFFER * offer_new;
42 char domain[254];
43 if ((offer_new = (OFFER *) malloc(sizeof(OFFER))) == NULL) {
44 return -1;
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;
51 reservate =+ memory;
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);
59 if (!offers_head)
60 offers_head = offer_new;
61 else
62 offers_tail->next = offer_new;
64 offers_tail = offer_new;
67 int offer_tender(const char *name, unsigned long memory, AvahiClient *c) {
68 OFFER * offer_new;
69 unsigned long long free_memory = virNodeGetFreeMemory(conn) - reservate;
70 char domain[254], txt[254];
72 if ((offer_new = (OFFER *) malloc(sizeof(OFFER))) == NULL) {
73 return -1;
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);
92 if (!offers_head)
93 offers_head = offer_new;
94 else
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;
104 while (offer_find) {
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);
109 if (!offer_prev)
110 offers_head = offer_find->next;
111 else
112 offer_prev->next = offer_find->next;
114 free(offer_find);
115 return 0;
116 } else {
117 offer_prev = offer_find;
118 offer_find = offer_find->next;
121 return -1;
126 static void resolve_callback(
127 AvahiServiceResolver *r,
128 AVAHI_GCC_UNUSED AvahiIfIndex interface,
129 AVAHI_GCC_UNUSED AvahiProtocol protocol,
130 AvahiResolverEvent event,
131 const char *name,
132 const char *type,
133 const char *domain,
134 const char *host_name,
135 const AvahiAddress *address,
136 uint16_t port,
137 AvahiStringList *txt,
138 AvahiLookupResultFlags flags,
139 AVAHI_GCC_UNUSED void* userdata) {
141 assert(r);
143 /* Called whenever a service has been resolved successfully or timed out */
145 switch (event) {
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))));
148 break;
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);
158 fprintf(stderr,
159 "\t%s:%u (%s)\n"
160 "\tTXT=%s\n"
161 "\tcookie is %u\n"
162 "\tis_local: %i\n"
163 "\tour_own: %i\n"
164 "\twide_area: %i\n"
165 "\tmulticast: %i\n"
166 "\tcached: %i\n",
167 host_name, port, a,
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));
176 avahi_free(t);
179 if ((needle = avahi_string_list_find (txt, "memory")) != NULL) {
180 unsigned long int amount;
181 char *memory;
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) {
187 char *winner;
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 avahi_free(winner);
195 } else {
196 offer_tender(name, amount, avahi_service_resolver_get_client(r));
200 avahi_free(memory);
205 avahi_service_resolver_free(r);
208 static void browse_callback(
209 AvahiServiceBrowser *b,
210 AvahiIfIndex interface,
211 AvahiProtocol protocol,
212 AvahiBrowserEvent event,
213 const char *name,
214 const char *type,
215 const char *domain,
216 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
217 void* userdata) {
219 AvahiClient *c = userdata;
220 assert(b);
222 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
224 switch (event) {
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);
229 return;
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)));
242 break;
244 case AVAHI_BROWSER_REMOVE:
245 pull_tender(name);
246 fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
247 break;
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");
252 break;
256 static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) {
257 switch (state) {
258 case AVAHI_ENTRY_GROUP_ESTABLISHED :
259 /* The entry group has been established successfully */
260 break;
262 case AVAHI_ENTRY_GROUP_COLLISION : {
263 /* A service name collision with a remote service
264 * happened. */
265 break;
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);
271 break;
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) {
280 assert(c);
282 /* Called whenever the client or server state changes */
284 switch (state) {
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 */
288 break;
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);
293 break;
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. */
305 break;
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;
316 int error;
317 int ret = 1;
319 /* NULL means connect to local Xen hypervisor */
320 conn = virConnectOpenReadOnly(NULL);
321 if (conn == NULL) {
322 fprintf(stderr, "Failed to connect to hypervisor\n");
323 goto fail;
326 /* Allocate main loop object */
327 if (!(simple_poll = avahi_simple_poll_new())) {
328 fprintf(stderr, "Failed to create simple poll object.\n");
329 goto fail;
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 */
336 if (!client) {
337 fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
338 goto fail;
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)));
344 goto fail;
348 /* Run the main loop */
349 avahi_simple_poll_loop(simple_poll);
351 ret = 0;
353 fail:
355 /* Cleanup things */
356 if (sb)
357 avahi_service_browser_free(sb);
359 if (client)
360 avahi_client_free(client);
362 if (simple_poll)
363 avahi_simple_poll_free(simple_poll);
365 if (conn)
366 virConnectClose(conn);
368 return ret;