GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/notification_client.cc
Date: 2026-09-27 02:40:09
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