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>
20 unsigned int domainid
;
21 AvahiEntryGroup
*group
;
25 typedef struct list_el domu
;
27 domu
* domus
= NULL
; /* list of domains */
28 unsigned int domu_count
= 0;
29 static AvahiSimplePoll
*simple_poll
= NULL
;
31 static AvahiStringList
* domainProperties(virDomainPtr thisDomain
) {
32 AvahiStringList
*new = avahi_string_list_new(NULL
);
34 virDomainInterfaceStatsStruct stats
;
35 virDomainGetInfo(thisDomain
, &info
);
36 new = avahi_string_list_add_printf(new, "maxMem=%lu", info
.maxMem
);
37 new = avahi_string_list_add_printf(new, "memory=%lu", info
.memory
);
38 new = avahi_string_list_add_printf(new, "cpuTime=%llu", info
.cpuTime
);
40 /* TODO: multiple network interfaces :( */
42 snprintf(vifname
, 14, "vif%d.0", virDomainGetID(thisDomain
));
46 virDomainInterfaceStats(thisDomain
, vifname
, &stats
, sizeof(stats
));
48 new = avahi_string_list_add_printf(new, "interfaces=eth%d", no
);
49 new = avahi_string_list_add_printf(new, "interface_eth%d_rxbytes=%lld", no
, stats
.rx_bytes
);
50 new = avahi_string_list_add_printf(new, "interface_eth%d_rxpackets=%lld", no
, stats
.rx_packets
);
51 // new = avahi_string_list_add_printf(new, "interface_eth%d_rxerrs=%lld", no, stats.rx_errs);
52 // new = avahi_string_list_add_printf(new, "interface_eth%d_rxdrop=%lld", no, stats.rx_drop);
53 new = avahi_string_list_add_printf(new, "interface_eth%d_txbytes=%lld", no
, stats
.tx_bytes
);
54 new = avahi_string_list_add_printf(new, "interface_eth%d_txpackets=%lld", no
, stats
.tx_packets
);
55 // new = avahi_string_list_add_printf(new, "interface_eth%d_txerrs=%lld", no, stats.tx_errs);
56 // new = avahi_string_list_add_printf(new, "interface_eth%d_txdrop=%lld", no, stats.tx_drop);
61 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
) {
62 /* Called whenever the entry group state changes */
65 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
66 /* The entry group has been established successfully */
67 //fprintf(stderr, "Service '%s' successfully established.\n", name);
70 case AVAHI_ENTRY_GROUP_COLLISION
: {
73 /* A service name collision with a remote service
74 * happened. Let's pick a new name */
75 //n = avahi_alternative_service_name(name);
79 // fprintf(stderr, "Service name collision, renaming service to '%s'\n", name);
81 /* And recreate the services */
82 //create_services(avahi_entry_group_get_client(g));
86 case AVAHI_ENTRY_GROUP_FAILURE
:
88 fprintf(stderr
, "Entry group failure: %s\n", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g
))));
90 /* Some kind of failure happened while we were registering our services */
91 avahi_simple_poll_quit(simple_poll
);
94 case AVAHI_ENTRY_GROUP_UNCOMMITED
:
95 case AVAHI_ENTRY_GROUP_REGISTERING
:
100 void create_services(AvahiClient
*c
) {
101 virConnectPtr conn
= virConnectOpenReadOnly(NULL
);
104 int maxid
= virConnectNumOfDomains(conn
);
105 if (maxid
> 1) { /* ignore dom0 */
106 int *ids
= (int *) malloc(sizeof(int) * maxid
);
107 if ((maxid
= virConnectListDomains(conn
, &ids
[0], maxid
)) < 0) {
111 unsigned int domu_count_new
= (maxid
- 1);
112 domu
* domus_old
= domus
;
113 domus
= (domu
*) malloc(sizeof(domu
) * domu_count_new
);
114 const char *type
= "_domu._tcp";
115 for (i
= 0; i
< domu_count_new
; i
++) {
117 domus
[i
].group
= NULL
;
118 domus
[i
].domainid
= ids
[i
+1];
121 //fprintf(stderr, "Looking for %d\n", domus[i].domainid);
123 for (j
= 0; j
< domu_count
; j
++) {
124 //fprintf(stderr, "--> %d\n", domus_old[j].domainid);
125 if (ids
[i
+1] == domus_old
[j
].domainid
) {
126 //fprintf(stderr, "got it\n");
127 virDomainPtr thisDomain
= virDomainLookupByID(conn
, domus
[i
].domainid
);
128 domus
[i
].group
= domus_old
[j
].group
;
130 const char *name
= virDomainGetName(thisDomain
);
132 AvahiStringList
*domainProps
;
133 domainProps
= domainProperties(thisDomain
);
134 domus_old
[j
].keep
= 1;
135 avahi_entry_group_update_service_txt_strlst(domus
[i
].group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, 0, name
, type
, NULL
, domainProps
);
136 avahi_string_list_free(domainProps
);
138 // domus_old[j].keep = 0;
141 // domus_old[j].keep = 0;
143 virDomainFree(thisDomain
);
146 if (i
> domu_count
|| domus
[i
].group
== NULL
) {
148 AvahiStringList
*domainProps
;
149 virDomainPtr thisDomain
= virDomainLookupByID(conn
, ids
[i
+1]);
150 domus
[i
].group
= avahi_entry_group_new(c
, entry_group_callback
, NULL
);
151 domainProps
= domainProperties(thisDomain
);
152 name
= virDomainGetName(thisDomain
);
155 avahi_entry_group_add_service_strlst(domus
[i
].group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, 0, name
, type
, NULL
, NULL
, 651, domainProps
);
156 avahi_entry_group_commit(domus
[i
].group
);
161 avahi_string_list_free(domainProps
);
162 virDomainFree(thisDomain
);
167 for (i
= 0; i
< domu_count
; i
++) {
168 // fprintf(stderr, "id: %d, keep: %d\n", domus_old[i].domainid, domus_old[i].keep);
169 if (domus_old
[i
].keep
== 0 && domus_old
[i
].group
!= NULL
) {
170 avahi_entry_group_free(domus_old
[i
].group
);
175 domu_count
= domu_count_new
;
179 virConnectClose(conn
);
180 //fprintf(stderr, "exit: %s\n", __func__);
183 static void modify_callback(AvahiTimeout
*e
, void *userdata
) {
185 AvahiClient
*client
= userdata
;
187 /* If the server is currently running, we need to remove our
188 * service and create it anew */
189 if (avahi_client_get_state(client
) == AVAHI_CLIENT_S_RUNNING
) {
190 /* And create them again with the new name */
191 create_services(client
);
193 avahi_simple_poll_get(simple_poll
)->timeout_update(e
, avahi_elapse_time(&tv
, 1000*POLL
, 0));
197 static void client_callback(AvahiClient
*c
, AvahiClientState state
, AVAHI_GCC_UNUSED
void * userdata
) {
199 /* Called whenever the client or server state changes */
202 case AVAHI_CLIENT_S_RUNNING
: {
203 /* The server has startup successfully and registered its host
204 * name on the network, so it's time to create our services */
207 /* After 10s do some weird modification to the service */
208 avahi_simple_poll_get(simple_poll
)->timeout_new(
209 avahi_simple_poll_get(simple_poll
),
210 avahi_elapse_time(&tv
, 1000*POLL
, 0),
217 case AVAHI_CLIENT_FAILURE
: {
219 AvahiClient
*client
= NULL
;
222 avahi_client_free(c
);
224 /* Allocate a new client */
225 client
= avahi_client_new(avahi_simple_poll_get(simple_poll
), AVAHI_CLIENT_NO_FAIL
, client_callback
, NULL
, &error
);
227 /* Check wether creating the client object succeeded */
229 /* If you look at the above argument, this should NEVER
231 fprintf(stderr
, "Failed to create client: %s\n", avahi_strerror(error
));
232 avahi_simple_poll_quit(simple_poll
);
238 case AVAHI_CLIENT_S_COLLISION
:
240 /* Let's drop our registered services. When the server is back
241 * in AVAHI_SERVER_RUNNING state we will register them
242 * again with the new host name. */
244 case AVAHI_CLIENT_S_REGISTERING
:
246 /* The server records are now being established. This
247 * might be caused by a host name change. We need to wait
248 * for our own records to register until the host name is
249 * properly esatblished. */
253 case AVAHI_CLIENT_CONNECTING
:
260 int main(AVAHI_GCC_UNUSED
int argc
, AVAHI_GCC_UNUSED
char*argv
[]) {
262 /* Allocate main loop object */
263 if (!(simple_poll
= avahi_simple_poll_new())) {
264 fprintf(stderr
, "Failed to create simple poll object.\n");
268 client_callback(NULL
, AVAHI_CLIENT_FAILURE
, NULL
);
270 /* Run the main loop */
271 avahi_simple_poll_loop(simple_poll
);
278 avahi_simple_poll_quit(simple_poll
);
281 avahi_simple_poll_free(simple_poll
);