GCC Code Coverage Report


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