GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/notification_client.cc
Date: 2026-09-06 02:40:30
Exec Total Coverage
Lines: 0 74 0.0%
Branches: 0 69 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "notification_client.h"
6
7 #include <inttypes.h>
8
9 #include <string>
10
11 #include "crypto/signature.h"
12 #include "manifest.h"
13 #include "manifest_fetch.h"
14 #include "notify/messages.h"
15 #include "notify/subscriber_sse.h"
16 #include "notify/subscriber_supervisor.h"
17 #include "util/logging.h"
18 #include "util/posix.h" // IWYU pragma: keep
19
20 namespace {
21
22 class ActivitySubscriber : public notify::SubscriberSSE {
23 public:
24 ActivitySubscriber(const std::string &server_url, FuseRemounter *remounter,
25 download::DownloadManager *dl_mgr,
26 signature::SignatureManager *sig_mgr)
27 : SubscriberSSE(server_url)
28 , remounter_(remounter)
29 , dl_mgr_(dl_mgr)
30 , sig_mgr_(sig_mgr) { }
31
32 virtual ~ActivitySubscriber() { }
33
34 virtual notify::Subscriber::Status Consume(const std::string &repo_name,
35 const std::string &msg_text) {
36 notify::msg::Activity msg;
37 if (!msg.FromJSONString(msg_text)) {
38 LogCvmfs(kLogCvmfs, kLogSyslogErr,
39 "NotificationClient - could not decode message.");
40 return notify::Subscriber::kError;
41 }
42
43 manifest::ManifestEnsemble ensemble;
44 const manifest::Failures res = manifest::Verify(
45 reinterpret_cast<unsigned char *>(&(msg.manifest_[0])),
46 msg.manifest_.size(), "", repo_name, 0, NULL, sig_mgr_, dl_mgr_,
47 &ensemble);
48
49 if (res != manifest::kFailOk) {
50 LogCvmfs(kLogCvmfs, kLogSyslogErr,
51 "NotificationClient - manifest has invalid signature.");
52 return notify::Subscriber::kError;
53 }
54
55 const std::unique_ptr<manifest::Manifest> manifest(
56 manifest::Manifest::LoadMem(
57 reinterpret_cast<const unsigned char *>(msg.manifest_.data()),
58 msg.manifest_.size()));
59
60 if (manifest.get() == nullptr) {
61 LogCvmfs(kLogCvmfs, kLogSyslogErr,
62 "NotificationClient - could not parse manifest.");
63 return notify::Subscriber::kError;
64 }
65
66 const uint64_t new_revision = manifest->revision();
67 LogCvmfs(kLogCvmfs, kLogSyslog,
68 "NotificationClient - repository %s is now at revision %" PRIu64
69 ", root hash: %s",
70 repo_name.c_str(), new_revision,
71 manifest->catalog_hash().ToString().c_str());
72
73 const FuseRemounter::Status status = remounter_->CheckSynchronously();
74 switch (status) {
75 case FuseRemounter::kStatusFailGeneral:
76 LogCvmfs(kLogCvmfs, kLogSyslog, "NotificationClient - remount failed");
77 break;
78 case FuseRemounter::kStatusFailNoSpace:
79 LogCvmfs(kLogCvmfs, kLogSyslog,
80 "NotificationClient - remount failed (no space)");
81 break;
82 case FuseRemounter::kStatusUp2Date:
83 LogCvmfs(kLogCvmfs, kLogSyslog,
84 "NotificationClient - catalog up to date");
85 break;
86 case FuseRemounter::kStatusMaintenance:
87 LogCvmfs(kLogCvmfs, kLogSyslog,
88 "NotificationClient - in maintenance mode");
89 break;
90 default:
91 LogCvmfs(kLogCvmfs, kLogSyslog, "NotificationClient - internal error");
92 }
93 return notify::Subscriber::kContinue;
94 }
95
96 private:
97 FuseRemounter *remounter_;
98 download::DownloadManager *dl_mgr_;
99 signature::SignatureManager *sig_mgr_;
100 };
101
102 } // namespace
103
104 NotificationClient::NotificationClient(const std::string &config,
105 const std::string &repo_name,
106 FuseRemounter *remounter,
107 download::DownloadManager *dl_mgr,
108 signature::SignatureManager *sig_mgr)
109 : config_(config)
110 , repo_name_(repo_name)
111 , remounter_(remounter)
112 , dl_mgr_(dl_mgr)
113 , sig_mgr_(sig_mgr)
114 , subscriber_()
115 , thread_()
116 , spawned_(false) { }
117
118 NotificationClient::~NotificationClient() {
119 if (subscriber_.get() != nullptr) {
120 subscriber_->Unsubscribe();
121 }
122 if (spawned_) {
123 pthread_join(thread_, NULL);
124 spawned_ = false;
125 }
126 }
127
128 void NotificationClient::Spawn() {
129 if (!spawned_) {
130 if (pthread_create(&thread_, NULL, NotificationClient::Run, this)) {
131 LogCvmfs(kLogCvmfs, kLogSyslogErr,
132 "NotificationClient - Could not start background thread");
133 }
134 spawned_ = true;
135 }
136 }
137
138 void *NotificationClient::Run(void *data) {
139 NotificationClient *cl = static_cast<NotificationClient *>(data);
140
141 cl->subscriber_.reset(new ActivitySubscriber(cl->config_, cl->remounter_,
142 cl->dl_mgr_, cl->sig_mgr_));
143
144 LogCvmfs(
145 kLogCvmfs, kLogSyslog,
146 "NotificationClient - Entering subscription loop for repository: %s.",
147 cl->repo_name_.c_str());
148
149 // Retry settings: accept no more than 10 failures in the last minute
150 const int num_retries = 10;
151 const uint64_t interval = 60;
152 notify::SubscriberSupervisor supervisor(cl->subscriber_.get(), cl->repo_name_,
153 num_retries, interval);
154 supervisor.Run();
155
156 return NULL;
157 }
158