Coverage Report

Created: 2026-06-27 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/src/records/RecMessage.cc
Line
Count
Source
1
/** @file
2
3
  Record message definitions
4
5
  @section license License
6
7
  Licensed to the Apache Software Foundation (ASF) under one
8
  or more contributor license agreements.  See the NOTICE file
9
  distributed with this work for additional information
10
  regarding copyright ownership.  The ASF licenses this file
11
  to you under the Apache License, Version 2.0 (the
12
  "License"); you may not use this file except in compliance
13
  with the License.  You may obtain a copy of the License at
14
15
      http://www.apache.org/licenses/LICENSE-2.0
16
17
  Unless required by applicable law or agreed to in writing, software
18
  distributed under the License is distributed on an "AS IS" BASIS,
19
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
  See the License for the specific language governing permissions and
21
  limitations under the License.
22
 */
23
24
#include "tscore/ink_platform.h"
25
#include "tscore/ink_memory.h"
26
#include "tscore/ink_align.h"
27
28
#include "P_RecCore.h"
29
#include "P_RecFile.h"
30
#include "P_RecMessage.h"
31
#include "P_RecUtils.h"
32
#include "P_RecCore.h"
33
#include "tscore/Layout.h"
34
#include "swoc/MemSpan.h"
35
36
static RecMessageRecvCb g_recv_cb     = nullptr;
37
static void            *g_recv_cookie = nullptr;
38
39
//-------------------------------------------------------------------------
40
// RecMessageAlloc
41
//-------------------------------------------------------------------------
42
RecMessage *
43
RecMessageAlloc(RecMessageT msg_type, int initial_size)
44
0
{
45
0
  RecMessage *msg;
46
47
0
  msg = static_cast<RecMessage *>(ats_malloc(sizeof(RecMessageHdr) + initial_size));
48
0
  memset(msg, 0, sizeof(RecMessageHdr) + initial_size);
49
0
  msg->msg_type = msg_type;
50
0
  msg->o_start  = sizeof(RecMessageHdr);
51
0
  msg->o_write  = sizeof(RecMessageHdr);
52
0
  msg->o_end    = sizeof(RecMessageHdr) + initial_size;
53
0
  msg->entries  = 0;
54
55
0
  return msg;
56
0
}
57
58
//-------------------------------------------------------------------------
59
// RecMessageFree
60
//-------------------------------------------------------------------------
61
62
int
63
RecMessageFree(RecMessage *msg)
64
0
{
65
0
  ats_free(msg);
66
0
  return REC_ERR_OKAY;
67
0
}
68
69
//-------------------------------------------------------------------------
70
// RecMessageMarshal_Realloc
71
//-------------------------------------------------------------------------
72
RecMessage *
73
RecMessageMarshal_Realloc(RecMessage *msg, const RecRecord *record)
74
0
{
75
0
  int               msg_ele_size;
76
0
  int               rec_name_len         = -1;
77
0
  int               rec_data_str_len     = -1;
78
0
  int               rec_data_def_str_len = -1;
79
0
  int               rec_cfg_chk_len      = -1;
80
0
  RecMessageEleHdr *ele_hdr;
81
0
  RecRecord        *r;
82
0
  char             *p;
83
84
  // find out how much space we need
85
0
  msg_ele_size = sizeof(RecMessageEleHdr) + sizeof(RecRecord);
86
0
  if (record->name) {
87
0
    rec_name_len  = strlen(record->name) + 1;
88
0
    msg_ele_size += rec_name_len;
89
0
  }
90
0
  if (record->data_type == RECD_STRING) {
91
0
    if (record->data.rec_string) {
92
0
      rec_data_str_len  = strlen(record->data.rec_string) + 1;
93
0
      msg_ele_size     += rec_data_str_len;
94
0
    }
95
0
    if (record->data_default.rec_string) {
96
0
      rec_data_def_str_len  = strlen(record->data_default.rec_string) + 1;
97
0
      msg_ele_size         += rec_data_def_str_len;
98
0
    }
99
0
  }
100
0
  if (REC_TYPE_IS_CONFIG(record->rec_type) && (record->config_meta.check_expr)) {
101
0
    rec_cfg_chk_len  = strlen(record->config_meta.check_expr) + 1;
102
0
    msg_ele_size    += rec_cfg_chk_len;
103
0
  }
104
  // XXX: this is NOT 8 byte alignment
105
  // msg_ele_size = 5;
106
  // (msg_ele_size + 7) & ~7 == 5 !!!
107
  // msg_ele_size = (msg_ele_size + 7) & ~7;       // 8 byte alignment
108
109
0
  msg_ele_size = INK_ALIGN_DEFAULT(msg_ele_size); // 8 byte alignment
110
  // get some space in our buffer
111
0
  while (msg->o_end - msg->o_write < msg_ele_size) {
112
0
    int realloc_size = (msg->o_end - msg->o_start) * 2;
113
0
    msg              = static_cast<RecMessage *>(ats_realloc(msg, sizeof(RecMessageHdr) + realloc_size));
114
0
    msg->o_end       = msg->o_start + realloc_size;
115
0
  }
116
0
  ele_hdr = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + msg->o_write);
117
  // The following memset() is pretty CPU intensive, replacing it with something
118
  // like the below would reduce CPU usage a fair amount. /leif.
119
  // *((char*)msg + msg->o_write) = 0;
120
0
  memset(reinterpret_cast<char *>(msg) + msg->o_write, 0, msg->o_end - msg->o_write);
121
0
  msg->o_write += msg_ele_size;
122
123
  // store the record
124
0
  ele_hdr->magic  = REC_MESSAGE_ELE_MAGIC;
125
0
  ele_hdr->o_next = msg->o_write;
126
0
  p               = reinterpret_cast<char *>(ele_hdr) + sizeof(RecMessageEleHdr);
127
0
  memcpy(p, record, sizeof(RecRecord));
128
0
  r  = reinterpret_cast<RecRecord *>(p);
129
0
  p += sizeof(RecRecord);
130
0
  if (rec_name_len != -1) {
131
0
    ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_name_len);
132
0
    memcpy(p, record->name, rec_name_len);
133
0
    r->name  = (char *)((uintptr_t)p - (uintptr_t)r);
134
0
    p       += rec_name_len;
135
0
  }
136
0
  if (rec_data_str_len != -1) {
137
0
    ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_data_str_len);
138
0
    memcpy(p, record->data.rec_string, rec_data_str_len);
139
0
    r->data.rec_string  = (char *)((uintptr_t)p - (uintptr_t)r);
140
0
    p                  += rec_data_str_len;
141
0
  }
142
0
  if (rec_data_def_str_len != -1) {
143
0
    ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_data_def_str_len);
144
0
    memcpy(p, record->data_default.rec_string, rec_data_def_str_len);
145
0
    r->data_default.rec_string  = (char *)((uintptr_t)p - (uintptr_t)r);
146
0
    p                          += rec_data_def_str_len;
147
0
  }
148
0
  if (rec_cfg_chk_len != -1) {
149
0
    ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_cfg_chk_len);
150
0
    memcpy(p, record->config_meta.check_expr, rec_cfg_chk_len);
151
0
    r->config_meta.check_expr = (char *)((uintptr_t)p - (uintptr_t)r);
152
0
  }
153
154
0
  msg->entries += 1;
155
156
0
  return msg;
157
0
}
158
159
//-------------------------------------------------------------------------
160
// RecMessageUnmarshalFirst
161
//-------------------------------------------------------------------------
162
163
int
164
RecMessageUnmarshalFirst(RecMessage *msg, RecMessageItr *itr, RecRecord **record)
165
0
{
166
0
  itr->ele_hdr = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + msg->o_start);
167
0
  itr->next    = 1;
168
169
0
  return RecMessageUnmarshalNext(msg, nullptr, record);
170
0
}
171
172
//-------------------------------------------------------------------------
173
// RecMessageUnmarshalNext
174
//-------------------------------------------------------------------------
175
176
int
177
RecMessageUnmarshalNext(RecMessage *msg, RecMessageItr *itr, RecRecord **record)
178
0
{
179
0
  RecMessageEleHdr *eh;
180
0
  RecRecord        *r;
181
182
0
  if (itr == nullptr) {
183
0
    if (msg->entries == 0) {
184
0
      return REC_ERR_FAIL;
185
0
    } else {
186
0
      eh = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + msg->o_start);
187
0
    }
188
0
  } else {
189
0
    if (itr->next >= msg->entries) {
190
0
      return REC_ERR_FAIL;
191
0
    }
192
0
    itr->ele_hdr  = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + itr->ele_hdr->o_next);
193
0
    itr->next    += 1;
194
0
    eh            = itr->ele_hdr;
195
0
  }
196
197
0
  ink_assert(eh->magic == REC_MESSAGE_ELE_MAGIC);
198
199
  // If the file is corrupt, ignore the rest of the file.
200
0
  if (eh->magic != REC_MESSAGE_ELE_MAGIC) {
201
0
    Warning("Persistent statistics file records.stat is corrupted. Ignoring the rest of the file\n");
202
0
    return REC_ERR_FAIL;
203
0
  }
204
205
0
  r = reinterpret_cast<RecRecord *>(reinterpret_cast<char *>(eh) + sizeof(RecMessageEleHdr));
206
207
0
  if (r->name) {
208
0
    r->name = reinterpret_cast<char *>(r) + (intptr_t)(r->name);
209
0
  }
210
0
  if (r->data_type == RECD_STRING) {
211
0
    if (r->data.rec_string) {
212
0
      r->data.rec_string = reinterpret_cast<char *>(r) + (intptr_t)(r->data.rec_string);
213
0
    }
214
0
    if (r->data_default.rec_string) {
215
0
      r->data_default.rec_string = reinterpret_cast<char *>(r) + (intptr_t)(r->data_default.rec_string);
216
0
    }
217
0
  }
218
0
  if (REC_TYPE_IS_CONFIG(r->rec_type) && (r->config_meta.check_expr)) {
219
0
    r->config_meta.check_expr = reinterpret_cast<char *>(r) + (intptr_t)(r->config_meta.check_expr);
220
0
  }
221
222
0
  *record = r;
223
224
0
  return REC_ERR_OKAY;
225
0
}
226
227
//-------------------------------------------------------------------------
228
// RecMessageRegisterRecvCb
229
//-------------------------------------------------------------------------
230
231
int
232
RecMessageRegisterRecvCb(RecMessageRecvCb recv_cb, void *cookie)
233
0
{
234
0
  if (g_recv_cb) {
235
0
    return REC_ERR_FAIL;
236
0
  }
237
0
  g_recv_cookie = cookie;
238
0
  g_recv_cb     = recv_cb;
239
240
0
  return REC_ERR_OKAY;
241
0
}
242
243
//-------------------------------------------------------------------------
244
// RecMessageReadFromDisk
245
//-------------------------------------------------------------------------
246
247
RecMessage *
248
RecMessageReadFromDisk(const char *fpath)
249
0
{
250
0
  RecMessageHdr msg_hdr;
251
0
  RecMessage   *msg = nullptr;
252
0
  RecHandle     h_file;
253
0
  int           bytes_read;
254
255
0
  if ((h_file = RecFileOpenR(fpath)) == REC_HANDLE_INVALID) {
256
0
    goto Lerror;
257
0
  }
258
0
  if (RecFileRead(h_file, reinterpret_cast<char *>(&msg_hdr), sizeof(RecMessageHdr), &bytes_read) == REC_ERR_FAIL) {
259
0
    goto Lerror;
260
0
  }
261
0
  msg = static_cast<RecMessage *>(ats_malloc((msg_hdr.o_end - msg_hdr.o_start) + sizeof(RecMessageHdr)));
262
0
  memcpy(msg, &msg_hdr, sizeof(RecMessageHdr));
263
0
  if (RecSnapFileRead(h_file, reinterpret_cast<char *>(msg) + msg_hdr.o_start, msg_hdr.o_end - msg_hdr.o_start, &bytes_read) ==
264
0
      REC_ERR_FAIL) {
265
0
    goto Lerror;
266
0
  }
267
268
0
  goto Ldone;
269
270
0
Lerror:
271
0
  ats_free(msg);
272
0
  msg = nullptr;
273
274
0
Ldone:
275
0
  if (h_file != REC_HANDLE_INVALID) {
276
0
    RecFileClose(h_file);
277
0
  }
278
279
0
  return msg;
280
0
}
281
282
//-------------------------------------------------------------------------
283
// RecMessageWriteToDisk
284
//-------------------------------------------------------------------------
285
286
int
287
RecMessageWriteToDisk(RecMessage *msg, const char *fpath)
288
0
{
289
0
  int       msg_size;
290
0
  RecHandle h_file;
291
0
  int       bytes_written;
292
293
  // Cap the message (e.g. when we read it, o_end should reflect the
294
  // size of the new buffer that we write to disk, not the size of the
295
  // buffer in memory).
296
0
  msg->o_end = msg->o_write;
297
298
0
  msg_size = sizeof(RecMessageHdr) + (msg->o_write - msg->o_start);
299
0
  if ((h_file = RecFileOpenW(fpath)) != REC_HANDLE_INVALID) {
300
0
    if (RecSnapFileWrite(h_file, reinterpret_cast<char *>(msg), msg_size, &bytes_written) == REC_ERR_FAIL) {
301
0
      RecFileClose(h_file);
302
0
      return REC_ERR_FAIL;
303
0
    }
304
0
    RecFileClose(h_file);
305
0
  }
306
307
0
  return REC_ERR_OKAY;
308
0
}