1 /*
2  * Copyright (C) 2013 Andreas Degert
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  * ---------------------------------------------------------------------------
18  */
19 
20 #include <avahi-common/error.h>
21 #include <avahi-common/alternative.h>
22 #include <avahi-common/malloc.h>
23 #include "avahi_register.h"
24 #include "gx_logging.h"
25 
26 /****************************************************************
27  ** class AvahiService
28  */
29 
AvahiService()30 AvahiService::AvahiService()
31     : client(0), group(0), current_name(), registered_port(-1) {
32     client = ga_client_new(GaClientFlags(0));
33     GError *error = 0;
34     if (!ga_client_start(client, &error)) {
35 	gx_print_error("avahi registration", error->message);
36 	return;
37     }
38     group = ga_entry_group_new();
39     g_signal_connect(group, "state-changed", G_CALLBACK(state_changed), this);
40     error = 0;
41     ga_entry_group_attach(group, client, &error);
42 }
43 
~AvahiService()44 AvahiService::~AvahiService() {
45     if (client) {
46 	g_clear_object(&client);
47     }
48     if (group) {
49 	g_clear_object(&group);
50     }
51 }
52 
53 //static
state_changed(GaEntryGroup * group,GaEntryGroupState state,void * data)54 void AvahiService::state_changed(GaEntryGroup *group, GaEntryGroupState state, void *data) {
55     AvahiService& self = *static_cast<AvahiService*>(data);
56     switch (state) {
57     case GA_ENTRY_GROUP_STATE_UNCOMMITED: break;
58     case GA_ENTRY_GROUP_STATE_REGISTERING: break;
59     case GA_ENTRY_GROUP_STATE_ESTABLISHED:
60 	gx_print_info("avahi registration", "established");
61 	break;
62     case GA_ENTRY_GROUP_STATE_COLLISTION: { // typo in header??
63 	gx_print_info("avahi registration", "collision");
64 	char *n = avahi_alternative_service_name(self.current_name.c_str());
65 	std::string name = n;
66 	avahi_free(n);
67 	self.register_service(name, self.registered_port);
68 	break;
69     }
70     case GA_ENTRY_GROUP_STATE_FAILURE:
71 	gx_print_error("avahi registration", "failure");
72 	break;
73     }
74 }
75 
register_service(std::string name,int port)76 bool AvahiService::register_service(std::string name, int port) {
77     if (!group) {
78 	return false;
79     }
80     for (int i = 0; i < 10; ++i) {
81 	GError *error = 0;
82 	ga_entry_group_add_service(group, name.c_str(), "_guitarix._tcp", port, &error, 0);
83 	if (!error) {
84 	    break;
85 	}
86 	if (error->code != AVAHI_ERR_COLLISION) {
87 	    gx_print_error("avahi registration", error->message);
88 	    return false;
89 	}
90 	char *n = avahi_alternative_service_name(name.c_str());
91 	name = n;
92 	avahi_free(n);
93     }
94     ga_entry_group_commit(group, 0);
95     current_name = name;
96     registered_port = port;
97     return true;
98 }
99