summaryrefslogtreecommitdiffstats
blob: 07966afcac99045a002ab55990597292f3b82e69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright (c) 2010 Remko Tronçon
 * Licensed under the GNU General Public License v3.
 * See Documentation/Licenses/GPLv3.txt for more information.
 */

#pragma once

#include <avahi-client/publish.h>

#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h"
#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h"
#include "Swiften/Base/ByteArray.h"
#include "Swiften/EventLoop/EventLoop.h"

namespace Swift {
	class AvahiQuerier;

	class AvahiRegisterQuery : public DNSSDRegisterQuery, public AvahiQuery {
		public:	
			AvahiRegisterQuery(const std::string& name, int port, const ByteArray& txtRecord, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), name(name), port(port), txtRecord(txtRecord), group(0) {
			}

			void registerService() {
				std::cout << "Registering service " << name << ":" << port << std::endl;
				avahi_threaded_poll_lock(querier->getThreadedPoll());
				if (!group) {
					std::cout << "Creating entry group" << std::endl;
					group = avahi_entry_group_new(querier->getClient(), handleEntryGroupChange, this);
					if (!group) {
						std::cout << "Error ceating entry group" << std::endl;
						eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
					}
				}

				doRegisterService();
				avahi_threaded_poll_unlock(querier->getThreadedPoll());
			}

			void unregisterService() {
				if (group) {
					avahi_entry_group_free(group);
					group = NULL;
				}
			}

			void updateServiceInfo(const ByteArray& txtRecord) {
				this->txtRecord = txtRecord;
				avahi_threaded_poll_lock(querier->getThreadedPoll());
				assert(group);
				avahi_entry_group_reset(group);
				doRegisterService();
				avahi_threaded_poll_unlock(querier->getThreadedPoll());
			}

		private:
			void doRegisterService() {
				AvahiStringList* txtList;
				avahi_string_list_parse(txtRecord.getData(), txtRecord.getSize(), &txtList);

				int result = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), name.c_str(), "_presence._tcp", NULL, NULL, port, txtList);
				if (result < 0) {
					std::cout << "Error registering service: " << avahi_strerror(result) << std::endl;
					eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
				}
				result = avahi_entry_group_commit(group);
				if (result < 0) {
					std::cout << "Error registering service: " << avahi_strerror(result) << std::endl;
				}
			}

			static void handleEntryGroupChange(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) {
				static_cast<AvahiRegisterQuery*>(userdata)->handleEntryGroupChange(g, state);
			}

			void handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state) {
				std::cout << "ENtry group callback: " << state << std::endl;
				switch (state) {
					case AVAHI_ENTRY_GROUP_ESTABLISHED :
						// Domain is a hack!
						eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, "local", "_presence._tcp", 0))), shared_from_this());
						std::cout << "Entry group established" << std::endl;
						break;
				case AVAHI_ENTRY_GROUP_COLLISION : {
						std::cout << "Entry group collision" << std::endl;
						/*char *n;
						n = avahi_alternative_service_name(name);
						avahi_free(name);
						name = n;*/
						break;
				}

				case AVAHI_ENTRY_GROUP_FAILURE :
						std::cout << "Entry group failure " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << std::endl;
						break;

				case AVAHI_ENTRY_GROUP_UNCOMMITED:
				case AVAHI_ENTRY_GROUP_REGISTERING:
						;

				/*
				DNSServiceErrorType result = DNSServiceRegister(
						&sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, port, 
						txtRecord.getSize(), txtRecord.getData(), 
						&AvahiRegisterQuery::handleServiceRegisteredStatic, this);
				if (result != kDNSServiceErr_NoError) {
					sdRef = NULL;
				}*/
				//eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
			}
		}

/*
			static void handleServiceRegisteredStatic(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) {
				static_cast<AvahiRegisterQuery*>(context)->handleServiceRegistered(errorCode, name, regtype, domain);
			}

			void handleServiceRegistered(DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain) {
				if (errorCode != kDNSServiceErr_NoError) {
					eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
				}
				else {
				}
			}
			*/

		private:
			std::string name;
			int port;
			ByteArray txtRecord;
			AvahiEntryGroup* group;
	};
}