summaryrefslogtreecommitdiffstats
path: root/xbmc/network/Zeroconf.h
blob: bed66c936b61291c701e2537f14d9b11e4d832fb (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
134
135
136
137
138
/*
 *  Copyright (C) 2005-2018 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#pragma once

#include "utils/Job.h"

#include <map>
#include <string>
#include <utility>
#include <vector>

class CCriticalSection;
/// this class provides support for zeroconf
/// while the different zeroconf implementations have asynchronous APIs
/// this class hides it and provides only few ways to interact
/// with the services. If more control is needed, feel
/// free to add it. The main purpose currently is to provide an easy
/// way to publish services in the different StartXXX/StopXXX methods
/// in CApplication
//! @todo Make me safe for use in static initialization. CritSec is a static member :/
//!       use e.g. loki's singleton implementation to make do it properly
class CZeroconf
{
public:

  //tries to publish this service via zeroconf
  //fcr_identifier can be used to stop or reannounce this service later
  //fcr_type is the zeroconf service type to publish (e.g. _http._tcp for webserver)
  //fcr_name is the name of the service to publish. The hostname is currently automatically appended
  //         and used for name collisions. e.g. XBMC would get published as fcr_name@Martn or, after collision fcr_name@Martn-2
  //f_port port of the service to publish
  // returns false if fcr_identifier was already present
  bool PublishService(const std::string& fcr_identifier,
                      const std::string& fcr_type,
                      const std::string& fcr_name,
                      unsigned int f_port,
                      std::vector<std::pair<std::string, std::string> > txt /*= std::vector<std::pair<std::string, std::string> >()*/);

  //tries to rebroadcast that service on the network without removing/readding
  //this can be achieved by changing a fake txt record. Implementations should
  //implement it by doing so.
  //
  //fcr_identifier - the identifier of the already published service which should be reannounced
  // returns true on successful reannonuce - false if this service isn't published yet
  bool ForceReAnnounceService(const std::string& fcr_identifier);

  ///removes the specified service
  ///returns false if fcr_identifier does not exist
  bool RemoveService(const std::string& fcr_identifier);

  ///returns true if fcr_identifier exists
  bool HasService(const std::string& fcr_identifier) const;

  //starts publishing
  //services that were added with PublishService(...) while Zeroconf wasn't
  //started, get published now.
  bool Start();

  // unpublishes all services (but keeps them stored in this class)
  // a call to Start() will republish them
  void Stop();

  // class methods
  // access to singleton; singleton gets created on call if not existent
  // if zeroconf is disabled (!HAS_ZEROCONF), this will return a dummy implementation that
  // just does nothings, otherwise the platform specific one
  static CZeroconf* GetInstance();
  // release the singleton; (save to call multiple times)
  static void   ReleaseInstance();
  // returns false if ReleaseInstance() was called before
  static bool   IsInstantiated() { return  smp_instance != 0; }
  // win32: process results from the bonjour daemon
  virtual void  ProcessResults() {}
  // returns if the service is started and services are announced
  bool IsStarted() { return m_started; }

protected:
  //methods to implement for concrete implementations
  //publishs this service
  virtual bool doPublishService(const std::string& fcr_identifier,
                                const std::string& fcr_type,
                                const std::string& fcr_name,
                                unsigned int f_port,
                                const std::vector<std::pair<std::string, std::string> >& txt) = 0;

  //methods to implement for concrete implementations
  //update this service
  virtual bool doForceReAnnounceService(const std::string& fcr_identifier) = 0;

  //removes the service if published
  virtual bool doRemoveService(const std::string& fcr_ident) = 0;

  //removes all services (short hand for "for i in m_service_map doRemoveService(i)")
  virtual void doStop() = 0;

  // return true if the zeroconf daemon is running
  virtual bool IsZCdaemonRunning() { return  true; }

protected:
  //singleton: we don't want to get instantiated nor copied or deleted from outside
  CZeroconf();
  CZeroconf(const CZeroconf&);
  virtual ~CZeroconf();

private:
  struct PublishInfo{
    std::string type;
    std::string name;
    unsigned int port;
    std::vector<std::pair<std::string, std::string> > txt;
  };

  //protects data
  CCriticalSection* mp_crit_sec;
  typedef std::map<std::string, PublishInfo> tServiceMap;
  tServiceMap m_service_map;
  bool m_started = false;

  static CZeroconf* smp_instance;

  class CPublish : public CJob
  {
  public:
    CPublish(const std::string& fcr_identifier, const PublishInfo& pubinfo);
    explicit CPublish(const tServiceMap& servmap);

    bool DoWork() override;

  private:
    tServiceMap m_servmap;
  };
};