GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/notification_client.cc
Date: 2026-05-10 02:36:07
Exec Total Coverage
Lines: 0 73 0.0%
Branches: 0 75 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 UniquePtr<manifest::Manifest> manifest(manifest::Manifest::LoadMem(
56 reinterpret_cast<const unsigned char *>(msg.manifest_.data()),
57 msg.manifest_.size()));
58
59 if (!manifest.IsValid()) {
60 LogCvmfs(kLogCvmfs, kLogSyslogErr,
61 "NotificationClient - could not parse manifest.");
62 return notify::Subscriber::kError;
63 }
64
65 const uint64_t new_revision = manifest->revision();
66 LogCvmfs(kLogCvmfs, kLogSyslog,
67 "NotificationClient - repository %s is now at revision %" PRIu64
68 ", root hash: %s",
69 repo_name.c_str(), new_revision,
70 manifest->catalog_hash().ToString().c_str());
71
72 const FuseRemounter::Status status = remounter_->CheckSynchronously();
73 switch (status) {
74 case FuseRemounter::kStatusFailGeneral:
75 LogCvmfs(kLogCvmfs, kLogSyslog, "NotificationClient - remount failed");
76 break;
77 case FuseRemounter::kStatusFailNoSpace:
78 LogCvmfs(kLogCvmfs, kLogSyslog,
79 "NotificationClient - remount failed (no space)");
80 break;
81 case FuseRemounter::kStatusUp2Date:
82 LogCvmfs(kLogCvmfs, kLogSyslog,
83 "NotificationClient - catalog up to date");
84 break;
85 case FuseRemounter::kStatusMaintenance:
86 LogCvmfs(kLogCvmfs, kLogSyslog,
87 "NotificationClient - in maintenance mode");
88 break;
89 default:
90 LogCvmfs(kLogCvmfs, kLogSyslog, "NotificationClient - internal error");
91 }
92 return notify::Subscriber::kContinue;
93 }
94
95 private:
96 FuseRemounter *remounter_;
97 download::DownloadManager *dl_mgr_;
98 signature::SignatureManager *sig_mgr_;
99 };
100
101 } // namespace
102
103 NotificationClient::NotificationClient(const std::string &config,
104 const std::string &repo_name,
105 FuseRemounter *remounter,
106 download::DownloadManager *dl_mgr,
107 signature::SignatureManager *sig_mgr)
108 : config_(config)
109 , repo_name_(repo_name)
110 , remounter_(remounter)
111 , dl_mgr_(dl_mgr)
112 , sig_mgr_(sig_mgr)
113 , subscriber_()
114 , thread_()
115 , spawned_(false) { }
116
117 NotificationClient::~NotificationClient() {
118 if (subscriber_.IsValid()) {
119 subscriber_->Unsubscribe();
120 }
121 if (spawned_) {
122 pthread_join(thread_, NULL);
123 spawned_ = false;
124 }
125 }
126
127 void NotificationClient::Spawn() {
128 if (!spawned_) {
129 if (pthread_create(&thread_, NULL, NotificationClient::Run, this)) {
130 LogCvmfs(kLogCvmfs, kLogSyslogErr,
131 "NotificationClient - Could not start background thread");
132 }
133 spawned_ = true;
134 }
135 }
136
137 void *NotificationClient::Run(void *data) {
138 NotificationClient *cl = static_cast<NotificationClient *>(data);
139
140 cl->subscriber_ = new ActivitySubscriber(cl->config_, cl->remounter_,
141 cl->dl_mgr_, cl->sig_mgr_);
142
143 LogCvmfs(
144 kLogCvmfs, kLogSyslog,
145 "NotificationClient - Entering subscription loop for repository: %s.",
146 cl->repo_name_.c_str());
147
148 // Retry settings: accept no more than 10 failures in the last minute
149 const int num_retries = 10;
150 const uint64_t interval = 60;
151 notify::SubscriberSupervisor supervisor(
152 cl->subscriber_.weak_ref(), cl->repo_name_, num_retries, interval);
153 supervisor.Run();
154
155 return NULL;
156 }
157