Initial combination of announce and domudns
[handlervirt.git] / offer.c
blobd5891a03eee72cec338e059ff7985b30e7035847
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));
193 } else {
194 offer_tender(name, amount, avahi_service_resolver_get_client(r));
198 avahi_free(memory);
203 avahi_service_resolver_free(r);
206 static void browse_callback(
207 AvahiServiceBrowser *b,
208 AvahiIfIndex interface,
209 AvahiProtocol protocol,
210 AvahiBrowserEvent event,
211 const char *name,
212 const char *type,
213 const char *domain,
214 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
215 void* userdata) {
217 AvahiClient *c = userdata;
218 assert(b);
220 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
222 switch (event) {
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);
227 return;
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)));
240 break;
242 case AVAHI_BROWSER_REMOVE:
243 pull_tender(name);
244 fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
245 break;
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");
250 break;
254 static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) {
255 switch (state) {
256 case AVAHI_ENTRY_GROUP_ESTABLISHED :
257 /* The entry group has been established successfully */
258 break;
260 case AVAHI_ENTRY_GROUP_COLLISION : {
261 /* A service name collision with a remote service
262 * happened. */
263 break;
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);
269 break;
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) {
278 assert(c);
280 /* Called whenever the client or server state changes */
282 switch (state) {
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 */
286 break;
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);
291 break;
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. */
303 break;
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;
314 int error;
315 int ret = 1;
317 /* NULL means connect to local Xen hypervisor */
318 conn = virConnectOpenReadOnly(NULL);
319 if (conn == NULL) {
320 fprintf(stderr, "Failed to connect to hypervisor\n");
321 goto fail;
324 /* Allocate main loop object */
325 if (!(simple_poll = avahi_simple_poll_new())) {
326 fprintf(stderr, "Failed to create simple poll object.\n");
327 goto fail;
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 */
334 if (!client) {
335 fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
336 goto fail;
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)));
342 goto fail;
346 /* Run the main loop */
347 avahi_simple_poll_loop(simple_poll);
349 ret = 0;
351 fail:
353 /* Cleanup things */
354 if (sb)
355 avahi_service_browser_free(sb);
357 if (client)
358 avahi_client_free(client);
360 if (simple_poll)
361 avahi_simple_poll_free(simple_poll);
363 if (conn)
364 virConnectClose(conn);
366 return ret;