First offer engine.
[handlervirt.git] / offer.c
blob546dc144d58fc5a1204ae5462b35eb7a3b0947ba
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 unsigned long memory;
24 AvahiEntryGroup *group;
25 OFFER *next;
28 OFFER *offers_head = NULL;
29 OFFER *offers_tail = NULL;
31 virConnectPtr conn = NULL; /* the hypervisor connection */
32 static AvahiSimplePoll *simple_poll = NULL;
34 static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata);
38 int offer_tender(const char *name, unsigned long memory, AvahiClient *c) {
39 OFFER * offer_new;
40 unsigned long long free_memory = virNodeGetFreeMemory(conn);
41 char domain[254], txt[254];
43 if ((offer_new = (OFFER *) malloc(sizeof(OFFER))) == NULL) {
44 return -1;
47 snprintf(domain, 254, "%s.%s", name, avahi_client_get_domain_name(c));
48 snprintf(txt, 254, "cost=%f", (float)memory / (float)free_memory);
50 printf("%s\n", txt);
52 /* Here we assume that Avahi will guarantee uniqueness */
53 offer_new->name = strdup(name);
54 offer_new->memory = memory;
55 offer_new->group = avahi_entry_group_new(c, entry_group_callback, NULL);
56 offer_new->next = NULL;
57 avahi_entry_group_add_service(offer_new->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, domain, "_tender._tcp", NULL, NULL, 651, txt, NULL, NULL);
58 avahi_entry_group_commit(offer_new->group);
61 if (!offers_head)
62 offers_head = offer_new;
63 else
64 offers_tail->next = offer_new;
66 offers_tail = offer_new;
69 int pull_tender(const char *name) {
70 OFFER *offer_prev = NULL;
71 OFFER *offer_find = offers_head;
73 while (offer_find) {
74 if (strcmp(offer_find->name, name) == 0) {
75 free(offer_find->name);
76 avahi_entry_group_free(offer_find->group);
77 if (!offer_prev)
78 offers_head = offer_find->next;
79 else
80 offer_prev->next = offer_find->next;
82 free(offer_find);
83 return 0;
84 } else {
85 offer_prev = offer_find;
86 offer_find = offer_find->next;
89 return -1;
94 static void resolve_callback(
95 AvahiServiceResolver *r,
96 AVAHI_GCC_UNUSED AvahiIfIndex interface,
97 AVAHI_GCC_UNUSED AvahiProtocol protocol,
98 AvahiResolverEvent event,
99 const char *name,
100 const char *type,
101 const char *domain,
102 const char *host_name,
103 const AvahiAddress *address,
104 uint16_t port,
105 AvahiStringList *txt,
106 AvahiLookupResultFlags flags,
107 AVAHI_GCC_UNUSED void* userdata) {
109 assert(r);
111 /* Called whenever a service has been resolved successfully or timed out */
113 switch (event) {
114 case AVAHI_RESOLVER_FAILURE:
115 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))));
116 break;
118 case AVAHI_RESOLVER_FOUND: {
119 char a[AVAHI_ADDRESS_STR_MAX], *t;
120 AvahiStringList *needle;
122 fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
124 avahi_address_snprint(a, sizeof(a), address);
125 t = avahi_string_list_to_string(txt);
126 fprintf(stderr,
127 "\t%s:%u (%s)\n"
128 "\tTXT=%s\n"
129 "\tcookie is %u\n"
130 "\tis_local: %i\n"
131 "\tour_own: %i\n"
132 "\twide_area: %i\n"
133 "\tmulticast: %i\n"
134 "\tcached: %i\n",
135 host_name, port, a,
137 avahi_string_list_get_service_cookie(txt),
138 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
139 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
140 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
141 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
142 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
144 avahi_free(t);
146 if ((needle = avahi_string_list_find (txt, "memory")) != NULL) {
147 unsigned long int amount;
148 char *memory;
149 avahi_string_list_get_pair (needle, NULL, &memory, NULL);
150 amount = strtoul(memory, NULL, 10);
152 if (errno != ERANGE && amount > 0)
153 offer_tender(name, amount, avahi_service_resolver_get_client(r));
155 avahi_free(memory);
160 avahi_service_resolver_free(r);
163 static void browse_callback(
164 AvahiServiceBrowser *b,
165 AvahiIfIndex interface,
166 AvahiProtocol protocol,
167 AvahiBrowserEvent event,
168 const char *name,
169 const char *type,
170 const char *domain,
171 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
172 void* userdata) {
174 AvahiClient *c = userdata;
175 assert(b);
177 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
179 switch (event) {
180 case AVAHI_BROWSER_FAILURE:
182 fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
183 avahi_simple_poll_quit(simple_poll);
184 return;
186 case AVAHI_BROWSER_NEW:
187 fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
189 /* We ignore the returned resolver object. In the callback
190 function we free it. If the server is terminated before
191 the callback function is called the server will free
192 the resolver for us. */
194 if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, c)))
195 fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
197 break;
199 case AVAHI_BROWSER_REMOVE:
200 pull_tender(name);
201 fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
202 break;
204 case AVAHI_BROWSER_ALL_FOR_NOW:
205 case AVAHI_BROWSER_CACHE_EXHAUSTED:
206 fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
207 break;
211 static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) {
212 switch (state) {
213 case AVAHI_ENTRY_GROUP_ESTABLISHED :
214 /* The entry group has been established successfully */
215 break;
217 case AVAHI_ENTRY_GROUP_COLLISION : {
218 /* A service name collision with a remote service
219 * happened. */
220 break;
223 case AVAHI_ENTRY_GROUP_FAILURE :
224 /* Some kind of failure happened while we were registering our services */
225 avahi_simple_poll_quit(simple_poll);
226 break;
228 case AVAHI_ENTRY_GROUP_UNCOMMITED:
229 case AVAHI_ENTRY_GROUP_REGISTERING:
234 static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
235 assert(c);
237 /* Called whenever the client or server state changes */
239 switch (state) {
240 case AVAHI_CLIENT_S_RUNNING:
241 /* The server has startup successfully and registered its host
242 * name on the network, so it's time to create our services */
243 break;
245 case AVAHI_CLIENT_FAILURE:
246 fprintf(stderr, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c)));
247 avahi_simple_poll_quit(simple_poll);
248 break;
250 case AVAHI_CLIENT_S_COLLISION:
251 /* Let's drop our registered services. When the server is back
252 * in AVAHI_SERVER_RUNNING state we will register them
253 * again with the new host name. */
255 case AVAHI_CLIENT_S_REGISTERING:
256 /* The server records are now being established. This
257 * might be caused by a host name change. We need to wait
258 * for our own records to register until the host name is
259 * properly esatblished. */
260 break;
262 case AVAHI_CLIENT_CONNECTING:
268 int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
269 AvahiClient *client = NULL;
270 AvahiServiceBrowser *sb = NULL;
271 int error;
272 int ret = 1;
274 /* NULL means connect to local Xen hypervisor */
275 conn = virConnectOpenReadOnly(NULL);
276 if (conn == NULL) {
277 fprintf(stderr, "Failed to connect to hypervisor\n");
278 goto fail;
281 /* Allocate main loop object */
282 if (!(simple_poll = avahi_simple_poll_new())) {
283 fprintf(stderr, "Failed to create simple poll object.\n");
284 goto fail;
287 /* Allocate a new client */
288 client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error);
290 /* Check wether creating the client object succeeded */
291 if (!client) {
292 fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
293 goto fail;
296 /* Create the service browser */
297 if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_offer._tcp", NULL, 0, browse_callback, client))) {
298 fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
299 goto fail;
303 /* Run the main loop */
304 avahi_simple_poll_loop(simple_poll);
306 ret = 0;
308 fail:
310 /* Cleanup things */
311 if (sb)
312 avahi_service_browser_free(sb);
314 if (client)
315 avahi_client_free(client);
317 if (simple_poll)
318 avahi_simple_poll_free(simple_poll);
320 if (conn)
321 virConnectClose(conn);
323 return ret;