xueliu
2/29/2020 - 9:48 PM

avahi-publisher


#ifndef _PUBLISHER_H
#define _PUBLISHER_H

#include <iostream>
#include <string>
#include <vector>

#include <avahi-client/client.h>
#include <avahi-client/publish.h>

#include <avahi-common/alternative.h>
#include <avahi-common/simple-watch.h>
#include <avahi-common/malloc.h>
#include <avahi-common/error.h>
#include <avahi-common/timeval.h>

namespace libpublisher
{
	class	publisher
	{
		private:
			static void entry_group_callback(AvahiEntryGroup *_group, AvahiEntryGroupState _state, void *userdata);
			static void create_services(AvahiClient *_client);
			static void client_callback(AvahiClient *_client, AvahiClientState _state, void *userdata);
			void treat_collision(AvahiClient *_client);

		public:
			void publish_avahi_service(const char *_service_name, const int _port_number, const char *_service_type);
			publisher(const std::string &service_name, const int &port_number, const std::string &service_type, std::vector<std::string> & message);
			~publisher();
	};
}

#endif //_PUBLISHER_H
#include <iostream>
#include <iostream>
#include <string>
#include <cstring>

#include <avahi-client/client.h>
#include <avahi-client/publish.h>

#include <avahi-common/alternative.h>
#include <avahi-common/simple-watch.h>
#include <avahi-common/malloc.h>
#include <avahi-common/error.h>
#include <avahi-common/timeval.h>

#include "publisher.h"

namespace libpublisher
{
	static AvahiEntryGroup *group;
	static AvahiSimplePoll *poll_;
	static const char *name;
	std::string service_type, message;
	AvahiStringList *dns_message;
	int  port_number;

	void publisher::entry_group_callback(AvahiEntryGroup * _group, AvahiEntryGroupState _state, void * userdata)
	{
		group = _group;
		switch(_state)
		{
			case AVAHI_ENTRY_GROUP_FAILURE:
				std::cerr << "ENTRY GROUP FAILURE: " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(_group))) << std::endl;
				avahi_simple_poll_quit(poll_);
			break;

			case AVAHI_ENTRY_GROUP_COLLISION :
			case AVAHI_ENTRY_GROUP_ESTABLISHED :
			case AVAHI_ENTRY_GROUP_UNCOMMITED:
			case AVAHI_ENTRY_GROUP_REGISTERING:
				;
			break;
		}
	}
		void publisher::create_services(AvahiClient * _client)
		{
			if ((!group)&&(!(group = avahi_entry_group_new(_client, entry_group_callback, NULL))))
			{
				std::cout << "avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(_client)) << std::endl;
				avahi_simple_poll_quit(poll_);
			}

			if (avahi_entry_group_is_empty(group))
			{
				auto ret = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), name, service_type.c_str() , NULL, NULL, port_number, dns_message);
				if (ret < 0)
				{
					if (ret == AVAHI_ERR_COLLISION){
						create_services(_client);
					}
					std::cerr << "Failed to add _ipp._tcp service:" << avahi_strerror(ret) << std::endl;
					avahi_simple_poll_quit(poll_);
				}
				if ((ret = avahi_entry_group_commit(group)) < 0) {
					std::cerr << "Failed to commit entry group: " << avahi_strerror(ret) << std::endl;
					avahi_simple_poll_quit(poll_);
				}
			}
			return;
		}

		void publisher::client_callback(AvahiClient *_client, AvahiClientState _state, void *userdata)
		{
			switch (_state)
			{
				case AVAHI_CLIENT_S_RUNNING:
					create_services(_client);
				break;

				case AVAHI_CLIENT_FAILURE:
					std::cerr << 	"Client failure: " <<  avahi_strerror(avahi_client_errno(_client)) << std::endl;
					avahi_simple_poll_quit(poll_);
				break;

				case AVAHI_CLIENT_S_COLLISION:
				case AVAHI_CLIENT_S_REGISTERING:
					if (group) avahi_entry_group_reset(group);
				break;

				case AVAHI_CLIENT_CONNECTING:
					;
				break;
			}
		}

		void publisher::treat_collision(AvahiClient * _client)
		{
			char *n;
			n = avahi_alternative_service_name(name);
			avahi_free((void *)name);
			name = n;

			fprintf(stderr, "Service name collision, renaming service to '%s'\n", name);

			avahi_entry_group_reset(group);

			create_services(_client);
			return;
		}

		void publisher::publish_avahi_service(const char *_service_name, const int _port_number, const char *_service_type)
		{
			name = _service_name;
			port_number = _port_number;
			service_type = _service_type;

			poll_ = avahi_simple_poll_new();
			if(poll_){
				int error;
				AvahiClient *client = avahi_client_new(avahi_simple_poll_get(poll_), static_cast<AvahiClientFlags>(0), client_callback, NULL,  &error);
				if(client){
					avahi_simple_poll_loop(poll_);
					avahi_client_free(client);
				} else {
					std::cout << "FAILED TO CREATE AVAHI CLIENT OBJECT: " << avahi_strerror(error) << std::endl;
					avahi_simple_poll_free(poll_);
				}
			} else {
				std::cout << "FAILED TO CREATE AVAHI SIMPLE POLL OBJECT: " << std::endl;
			}
		}

		publisher::publisher(const std::string &service_name, const int &port_number, const std::string &service_type, std::vector<std::string> &message)
		{
			dns_message = avahi_string_list_new("version = V1.13", NULL);
			for(auto i = 0; i < message.size(); i++)
				dns_message = avahi_string_list_add(dns_message,std::string("message"+std::to_string(i)+"="+message.at(i)).c_str());
			publish_avahi_service(service_name.c_str(), port_number, service_type.c_str());
		}

		publisher::~publisher()
		{
			avahi_simple_poll_free(poll_);
		}
}
#include <iostream>
#include <vector>

#include "publisher.h"

int main(const int argc, const char **argv)
{
	std::vector<std::string> message;
	for(auto i = 0; i < 10; i++)
	{
		message.push_back("test message " + std::to_string(i));
	}
									  
	libpublisher::publisher new_publish("test service", 8080, "_http._tcp", message);
}
#!/bin/bash

g++ -std=c++14 main.cpp publisher.cpp -o app -lavahi-core -lavahi-common -lavahi-client