6 #include <avahi-client/client.h>
7 #include <avahi-client/publish.h>
9 #include <avahi-common/alternative.h>
10 #include <avahi-common/simple-watch.h>
11 #include <avahi-common/malloc.h>
12 #include <avahi-common/error.h>
13 #include <avahi-common/timeval.h>
15 #include <libvirt/libvirt.h>
21 unsigned int domainid
;
24 virDomainPtr thisDomain
;
25 AvahiEntryGroup
*group
;
28 virConnectPtr conn
= NULL
;
29 typedef struct list_el domu
;
31 domu
* domus
= NULL
; /* list of domains */
32 unsigned int domu_count
= 0;
33 static AvahiSimplePoll
*simple_poll
= NULL
;
35 static void resolve_callback(
36 AvahiServiceResolver
*r
,
37 AVAHI_GCC_UNUSED AvahiIfIndex interface
,
38 AVAHI_GCC_UNUSED AvahiProtocol protocol
,
39 AvahiResolverEvent event
,
43 const char *host_name
,
44 const AvahiAddress
*address
,
47 AvahiLookupResultFlags flags
,
52 /* Called whenever a service has been resolved successfully or timed out */
55 case AVAHI_RESOLVER_FAILURE
:
56 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
))));
59 case AVAHI_RESOLVER_FOUND
: {
60 char a
[AVAHI_ADDRESS_STR_MAX
], *t
;
61 AvahiStringList
*needle
;
63 fprintf(stderr
, "Service '%s' of type '%s' in domain '%s':\n", name
, type
, domain
);
65 avahi_address_snprint(a
, sizeof(a
), address
);
66 t
= avahi_string_list_to_string(txt
);
78 avahi_string_list_get_service_cookie(txt
),
79 !!(flags
& AVAHI_LOOKUP_RESULT_LOCAL
),
80 !!(flags
& AVAHI_LOOKUP_RESULT_OUR_OWN
),
81 !!(flags
& AVAHI_LOOKUP_RESULT_WIDE_AREA
),
82 !!(flags
& AVAHI_LOOKUP_RESULT_MULTICAST
),
83 !!(flags
& AVAHI_LOOKUP_RESULT_CACHED
));
87 for (i
= 0; i
< domu_count
; i
++) {
88 const char *thisName
= virDomainGetName(domu
[i
].thisDomain
);
89 unsigned int len
= strlen(thisName
);
91 if (strlen(name
) > len
&& name
[len
] == '.' && strncmp(thisName
, name
, len
) == 0) {
92 if ((needle
= avahi_string_list_find (txt
, "cost")) != NULL
) {
96 avahi_string_list_get_pair (needle
, NULL
, &cost
, NULL
);
99 printf("%s: I'll run the VM for the competing cost of L$W %f\n", host_name
, amount
);
100 if (errno
!= ERANGE
&& amount
< domu
[i
]->cost
) {
101 domu
[i
]->cost
= amount
;
102 free(domu
[i
]->domain
);
103 domu
[i
]->domain
= strdup(&name
[++len
]);
114 avahi_service_resolver_free(r
);
117 static void browse_callback(
118 AvahiServiceBrowser
*b
,
119 AvahiIfIndex interface
,
120 AvahiProtocol protocol
,
121 AvahiBrowserEvent event
,
125 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
129 AvahiClient
*c
= avahi_service_browser_get_client(b
);
131 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
134 case AVAHI_BROWSER_FAILURE
:
136 fprintf(stderr
, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))));
137 avahi_simple_poll_quit(simple_poll
);
140 case AVAHI_BROWSER_NEW
:
141 fprintf(stderr
, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
143 /* We ignore the returned resolver object. In the callback
144 function we free it. If the server is terminated before
145 the callback function is called the server will free
146 the resolver for us. */
148 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
, AVAHI_PROTO_UNSPEC
, 0, resolve_callback
, userdata
)))
149 fprintf(stderr
, "Failed to resolve service '%s': %s\n", name
, avahi_strerror(avahi_client_errno(c
)));
153 case AVAHI_BROWSER_REMOVE
:
154 fprintf(stderr
, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
157 case AVAHI_BROWSER_ALL_FOR_NOW
:
158 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
159 fprintf(stderr
, "(Browser) %s\n", event
== AVAHI_BROWSER_CACHE_EXHAUSTED
? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
165 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
) {
167 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
168 /* The entry group has been established successfully */
171 case AVAHI_ENTRY_GROUP_COLLISION
: {
172 /* A service name collision with a remote service
177 case AVAHI_ENTRY_GROUP_FAILURE
:
178 /* Some kind of failure happened while we were registering our services */
179 avahi_simple_poll_quit(simple_poll
);
182 case AVAHI_ENTRY_GROUP_UNCOMMITED
:
183 case AVAHI_ENTRY_GROUP_REGISTERING
:
188 void create_services(AvahiClient
*c
) {
189 conn
= virConnectOpenReadOnly(NULL
);
192 int maxid
= virConnectNumOfDomains(conn
);
193 if (maxid
> 1) { /* ignore dom0 */
194 int *ids
= (int *) malloc(sizeof(int) * maxid
);
195 if ((maxid
= virConnectListDomains(conn
, &ids
[0], maxid
)) < 0) {
199 unsigned int domu_count_new
= (maxid
- 1);
200 domu
* domus_old
= domus
;
201 domus
= (domu
*) malloc(sizeof(domu
) * domu_count_new
);
202 for (i
= 0; i
< domu_count_new
; i
++) {
204 domus
[i
].group
= NULL
;
205 domus
[i
].domainid
= ids
[i
+1];
208 for (j
= 0; j
< domu_count
; j
++) {
209 if (ids
[i
+1] == domus_old
[j
].domainid
) {
210 domus
[i
].group
= domus_old
[j
].group
;
211 domus_old
[j
].keep
= 1;
214 if (i
> domu_count
|| domus
[i
].group
== NULL
) {
216 domus
[i
].thisDomain
= virDomainLookupByID(conn
, ids
[i
+1]);
217 snprintf(txt
, 254, "memory=%lu", virDomainGetMaxMemory(domus
[i
].thisDomain
));
220 domus
[i
].domain
= NULL
;
221 domus
[i
].cost
= 100000.0f
;
222 domus
[i
].group
= avahi_entry_group_new(c
, entry_group_callback
, NULL
);
223 avahi_entry_group_add_service(domus
[i
].group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, 0,
224 virDomainGetName(domus
[i
].thisDomain
), "_offer._tcp", NULL
, NULL
, 651, txt
, NULL
, NULL
);
225 avahi_entry_group_commit(domus
[i
].group
);
229 for (i
= 0; i
< domu_count
; i
++) {
230 if (domus_old
[i
].keep
== 0) {
231 if (domus_old
[i
].group
)
232 avahi_entry_group_free(domus_old
[i
].group
);
233 if (domus_old
[i
].domain
)
234 free(domus_old
[i
].domain
);
235 virDomainFree(domus
[i
].thisDomain
);
236 } else if (domus_old
[i
].cost
< 100000.0f
) {
237 avahi_entry_group_free(domus_old
[i
].group
);
238 domus_old
[i
].group
= NULL
;
239 printf("Migrate %s to %s\n", virDomainGetName(domus
[i
].thisDomain
), domus
[i
].domain
);
244 domu_count
= domu_count_new
;
248 virConnectClose(conn
);
252 static void client_callback(AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
) {
255 /* Called whenever the client or server state changes */
258 case AVAHI_CLIENT_S_RUNNING
:
260 /* The server has startup successfully and registered its host
261 * name on the network, so it's time to create our services */
265 case AVAHI_CLIENT_FAILURE
:
267 fprintf(stderr
, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c
)));
268 avahi_simple_poll_quit(simple_poll
);
272 case AVAHI_CLIENT_S_COLLISION
:
274 /* Let's drop our registered services. When the server is back
275 * in AVAHI_SERVER_RUNNING state we will register them
276 * again with the new host name. */
278 case AVAHI_CLIENT_S_REGISTERING
:
280 /* The server records are now being established. This
281 * might be caused by a host name change. We need to wait
282 * for our own records to register until the host name is
283 * properly esatblished. */
286 avahi_entry_group_reset(group);*/
290 case AVAHI_CLIENT_CONNECTING
:
297 static void modify_callback(AvahiTimeout
*e
, void *userdata
) {
299 AvahiClient
*client
= userdata
;
301 // fprintf(stderr, "Doing some weird modification\n");
303 /* If the server is currently running, we need to remove our
304 * service and create it anew */
305 if (avahi_client_get_state(client
) == AVAHI_CLIENT_S_RUNNING
) {
306 /* And create them again with the new name */
307 create_services(client
);
309 avahi_simple_poll_get(simple_poll
)->timeout_update(e
, avahi_elapse_time(&tv
, 1000*POLL
, 0));
314 int main(AVAHI_GCC_UNUSED
int argc
, AVAHI_GCC_UNUSED
char*argv
[]) {
315 AvahiClient
*client
= NULL
;
316 AvahiServiceBrowser
*sb
= NULL
;
320 /* Allocate main loop object */
321 if (!(simple_poll
= avahi_simple_poll_new())) {
322 fprintf(stderr
, "Failed to create simple poll object.\n");
326 /* Allocate a new client */
327 client
= avahi_client_new(avahi_simple_poll_get(simple_poll
), 0, client_callback
, NULL
, &error
);
329 /* Check wether creating the client object succeeded */
331 fprintf(stderr
, "Failed to create client: %s\n", avahi_strerror(error
));
335 /* Create the service browser */
336 if (!(sb
= avahi_service_browser_new(client
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, "_tender._tcp", NULL
, 0, browse_callback
, this))) {
337 fprintf(stderr
, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client
)));
341 /* After POLL seconds we will update the list of VMs and hope we have some domains to migrate off to */
342 avahi_simple_poll_get(simple_poll
)->timeout_new(
343 avahi_simple_poll_get(simple_poll
),
344 avahi_elapse_time(&tv
, 1000*POLL
, 0),
348 /* Run the main loop */
349 avahi_simple_poll_loop(simple_poll
);
358 avahi_client_free(client
);
361 avahi_simple_poll_free(simple_poll
);