Coverage Report

Created: 2026-02-14 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/SipLayer.cpp
Line
Count
Source
1
5.82k
#define LOG_MODULE PacketLogModuleSipLayer
2
3
#include "SipLayer.h"
4
#include "SdpLayer.h"
5
#include "PayloadLayer.h"
6
#include "Logger.h"
7
#include "GeneralUtils.h"
8
#include <array>
9
#include <string>
10
#include <algorithm>
11
#include <exception>
12
#include <utility>
13
#include <unordered_map>
14
15
namespace pcpp
16
{
17
  namespace
18
  {
19
    constexpr uint32_t pack4(const char* data, size_t len)
20
124k
    {
21
124k
      return ((len > 0 ? static_cast<uint32_t>(data[0]) << 24 : 0) |
22
124k
              (len > 1 ? static_cast<uint32_t>(data[1]) << 16 : 0) |
23
124k
              (len > 2 ? static_cast<uint32_t>(data[2]) << 8 : 0) |
24
124k
              (len > 3 ? static_cast<uint32_t>(data[3]) : 0));
25
124k
    }
26
27
    constexpr uint32_t operator""_packed4(const char* str, size_t len)
28
3.65k
    {
29
3.65k
      return pack4(str, len);
30
3.65k
    }
31
32
    const std::array<std::string, 14> SipMethodEnumToString = {  //
33
      "INVITE",    "ACK",    "BYE",     "CANCEL", "REGISTER", "PRACK",   "OPTIONS",
34
      "SUBSCRIBE", "NOTIFY", "PUBLISH", "INFO",   "REFER",    "MESSAGE", "UPDATE"
35
    };
36
37
    const std::unordered_map<std::string, SipRequestLayer::SipMethod> SipMethodStringToEnum{
38
      { "INVITE",    SipRequestLayer::SipMethod::SipINVITE    },
39
      { "ACK",       SipRequestLayer::SipMethod::SipACK       },
40
      { "BYE",       SipRequestLayer::SipMethod::SipBYE       },
41
      { "CANCEL",    SipRequestLayer::SipMethod::SipCANCEL    },
42
      { "REGISTER",  SipRequestLayer::SipMethod::SipREGISTER  },
43
      { "PRACK",     SipRequestLayer::SipMethod::SipPRACK     },
44
      { "OPTIONS",   SipRequestLayer::SipMethod::SipOPTIONS   },
45
      { "SUBSCRIBE", SipRequestLayer::SipMethod::SipSUBSCRIBE },
46
      { "NOTIFY",    SipRequestLayer::SipMethod::SipNOTIFY    },
47
      { "PUBLISH",   SipRequestLayer::SipMethod::SipPUBLISH   },
48
      { "INFO",      SipRequestLayer::SipMethod::SipINFO      },
49
      { "REFER",     SipRequestLayer::SipMethod::SipREFER     },
50
      { "MESSAGE",   SipRequestLayer::SipMethod::SipMESSAGE   },
51
      { "UPDATE",    SipRequestLayer::SipMethod::SipUPDATE    },
52
    };
53
  }  // namespace
54
55
  // -------- Class SipLayer -----------------
56
57
  int SipLayer::getContentLength() const
58
12.3k
  {
59
12.3k
    std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD);
60
12.3k
    std::transform(contentLengthFieldName.begin(), contentLengthFieldName.end(), contentLengthFieldName.begin(),
61
12.3k
                   ::tolower);
62
12.3k
    HeaderField* contentLengthField = getFieldByName(contentLengthFieldName);
63
12.3k
    if (contentLengthField != nullptr)
64
8.68k
      return atoi(contentLengthField->getFieldValue().c_str());
65
3.69k
    return 0;
66
12.3k
  }
67
68
  HeaderField* SipLayer::setContentLength(int contentLength, const std::string& prevFieldName)
69
832
  {
70
832
    std::ostringstream contentLengthAsString;
71
832
    contentLengthAsString << contentLength;
72
832
    std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD);
73
832
    HeaderField* contentLengthField = getFieldByName(contentLengthFieldName);
74
832
    if (contentLengthField == nullptr)
75
0
    {
76
0
      HeaderField* prevField = getFieldByName(prevFieldName);
77
0
      contentLengthField = insertField(prevField, PCPP_SIP_CONTENT_LENGTH_FIELD, contentLengthAsString.str());
78
0
    }
79
832
    else
80
832
      contentLengthField->setFieldValue(contentLengthAsString.str());
81
82
832
    return contentLengthField;
83
832
  }
84
85
  void SipLayer::parseNextLayer()
86
24.9k
  {
87
24.9k
    if (getLayerPayloadSize() == 0)
88
13.6k
      return;
89
90
11.2k
    size_t headerLen = getHeaderLen();
91
11.2k
    std::string contentType;
92
11.2k
    if (getContentLength() > 0)
93
7.20k
    {
94
7.20k
      HeaderField* contentTypeField = getFieldByName(PCPP_SIP_CONTENT_TYPE_FIELD);
95
7.20k
      if (contentTypeField != nullptr)
96
6.25k
        contentType = contentTypeField->getFieldValue();
97
7.20k
    }
98
99
11.2k
    auto payload = m_Data + headerLen;
100
11.2k
    auto payloadLen = m_DataLen - headerLen;
101
102
11.2k
    if (contentType.find("application/sdp") != std::string::npos)
103
5.43k
    {
104
5.43k
      constructNextLayer<SdpLayer>(payload, payloadLen);
105
5.43k
    }
106
5.86k
    else
107
5.86k
    {
108
5.86k
      constructNextLayer<PayloadLayer>(payload, payloadLen);
109
5.86k
    }
110
11.2k
  }
111
112
  void SipLayer::computeCalculateFields()
113
3.92k
  {
114
3.92k
    HeaderField* contentLengthField = getFieldByName(PCPP_SIP_CONTENT_LENGTH_FIELD);
115
3.92k
    if (contentLengthField == nullptr)
116
1.65k
      return;
117
118
2.27k
    size_t headerLen = getHeaderLen();
119
2.27k
    if (m_DataLen > headerLen)
120
1.08k
    {
121
1.08k
      int currentContentLength = getContentLength();
122
1.08k
      if (currentContentLength != static_cast<int>(m_DataLen - headerLen))
123
832
        setContentLength(m_DataLen - headerLen);
124
1.08k
    }
125
2.27k
  }
126
127
  SipLayer::SipParseResult SipLayer::detectSipMessageType(const uint8_t* data, size_t dataLen)
128
117k
  {
129
117k
    if (!data || dataLen < 3)
130
204
    {
131
204
      return SipLayer::SipParseResult::Unknown;
132
204
    }
133
134
117k
    uint32_t key = pack4(reinterpret_cast<const char*>(data), dataLen);
135
136
117k
    switch (key)
137
117k
    {
138
1.15k
    case "INVI"_packed4:  // INVITE
139
1.68k
    case "ACK "_packed4:  // ACK
140
1.68k
    case "BYE "_packed4:  // BYE
141
1.72k
    case "CANC"_packed4:  // CANCEL
142
1.81k
    case "REGI"_packed4:  // REGISTER
143
1.81k
    case "PRAC"_packed4:  // PRACK
144
1.82k
    case "OPTI"_packed4:  // OPTIONS
145
1.85k
    case "SUBS"_packed4:  // SUBSCRIBE
146
2.42k
    case "NOTI"_packed4:  // NOTIFY
147
2.43k
    case "PUBL"_packed4:  // PUBLISH
148
2.43k
    case "INFO"_packed4:  // INFO
149
2.44k
    case "REFE"_packed4:  // REFER
150
2.44k
    case "MESS"_packed4:  // MESSAGE
151
2.47k
    case "UPDA"_packed4:  // UPDATE
152
2.47k
      return SipLayer::SipParseResult::Request;
153
154
3.65k
    case "SIP/"_packed4:
155
3.65k
      return SipLayer::SipParseResult::Response;
156
157
110k
    default:
158
110k
      return SipLayer::SipParseResult::Unknown;
159
117k
    }
160
117k
  }
161
162
  SipLayer* SipLayer::parseSipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, uint16_t srcPort,
163
                                    uint16_t dstPort)
164
30.8k
  {
165
30.8k
    if (!(SipLayer::isSipPort(srcPort) || SipLayer::isSipPort(dstPort)))
166
0
    {
167
0
      return nullptr;
168
0
    }
169
170
30.8k
    if (SipRequestFirstLine::parseMethod(reinterpret_cast<char*>(data), dataLen) !=
171
30.8k
        SipRequestLayer::SipMethodUnknown)
172
7.82k
    {
173
7.82k
      return new SipRequestLayer(data, dataLen, prevLayer, packet);
174
7.82k
    }
175
176
23.0k
    if (SipResponseFirstLine::parseStatusCode(reinterpret_cast<char*>(data), dataLen) !=
177
23.0k
            SipResponseLayer::SipStatusCodeUnknown &&
178
16.7k
        !SipResponseFirstLine::parseVersion(reinterpret_cast<char*>(data), dataLen).empty())
179
12.6k
    {
180
12.6k
      return new SipResponseLayer(data, dataLen, prevLayer, packet);
181
12.6k
    }
182
183
10.3k
    return nullptr;
184
23.0k
  }
185
186
  SipLayer* SipLayer::parseSipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
187
117k
  {
188
117k
    SipLayer::SipParseResult sipParseResult = detectSipMessageType(data, dataLen);
189
190
117k
    if (sipParseResult == SipLayer::SipParseResult::Unknown)
191
111k
    {
192
111k
      return nullptr;
193
111k
    }
194
195
6.13k
    if (sipParseResult == SipLayer::SipParseResult::Request)
196
2.47k
    {
197
2.47k
      if (SipRequestFirstLine::parseFirstLine(reinterpret_cast<char*>(data), dataLen).first)
198
1.13k
      {
199
1.13k
        return new SipRequestLayer(data, dataLen, prevLayer, packet);
200
1.13k
      }
201
1.34k
      return nullptr;
202
2.47k
    }
203
204
3.65k
    if (SipResponseFirstLine::parseFirstLine(reinterpret_cast<char*>(data), dataLen).first)
205
3.30k
    {
206
3.30k
      return new SipResponseLayer(data, dataLen, prevLayer, packet);
207
3.30k
    }
208
358
    return nullptr;
209
3.65k
  }
210
211
  // -------- Class SipRequestFirstLine -----------------
212
213
8.95k
  SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest) : m_SipRequest(sipRequest)
214
8.95k
  {
215
8.95k
    m_Method = parseMethod(reinterpret_cast<char*>(m_SipRequest->m_Data), m_SipRequest->getDataLen());
216
8.95k
    if (m_Method == SipRequestLayer::SipMethodUnknown)
217
0
    {
218
0
      m_UriOffset = -1;
219
0
      PCPP_LOG_DEBUG("Couldn't resolve SIP request method");
220
0
    }
221
8.95k
    else
222
8.95k
      m_UriOffset = SipMethodEnumToString[m_Method].length() + 1;
223
224
8.95k
    parseVersion();
225
226
8.95k
    char* endOfFirstLine;
227
8.95k
    if ((endOfFirstLine =
228
8.95k
             static_cast<char*>(memchr(reinterpret_cast<char*>(m_SipRequest->m_Data + m_VersionOffset), '\n',
229
8.95k
                                       m_SipRequest->m_DataLen - static_cast<size_t>(m_VersionOffset)))) != nullptr)
230
8.22k
    {
231
8.22k
      m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipRequest->m_Data) + 1;
232
8.22k
      m_IsComplete = true;
233
8.22k
    }
234
724
    else
235
724
    {
236
724
      m_FirstLineEndOffset = m_SipRequest->getDataLen();
237
724
      m_IsComplete = false;
238
724
    }
239
240
8.95k
    if (Logger::getInstance().isDebugEnabled(PacketLogModuleSipLayer))
241
0
    {
242
0
      std::string method =
243
0
          (m_Method == SipRequestLayer::SipMethodUnknown ? "Unknown" : SipMethodEnumToString[m_Method]);
244
0
      PCPP_LOG_DEBUG("Method='" << method << "'; SIP version='" << m_Version << "'; URI='" << getUri() << "'");
245
0
    }
246
8.95k
  }
247
248
  SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest, SipRequestLayer::SipMethod method,
249
                                           const std::string& version, const std::string& uri)
250
0
  try  // throw(SipRequestFirstLineException)
251
0
  {
252
0
    if (method == SipRequestLayer::SipMethodUnknown)
253
0
    {
254
0
      m_Exception.setMessage("Method supplied was SipMethodUnknown");
255
0
      throw m_Exception;
256
0
    }
257
258
0
    if (version == "")
259
0
    {
260
0
      m_Exception.setMessage("Version supplied was empty string");
261
0
      throw m_Exception;
262
0
    }
263
264
0
    m_SipRequest = sipRequest;
265
266
0
    m_Method = method;
267
0
    m_Version = version;
268
269
0
    std::string firstLine = SipMethodEnumToString[m_Method] + " " + uri + " " + version + "\r\n";
270
271
0
    m_UriOffset = SipMethodEnumToString[m_Method].length() + 1;
272
0
    m_FirstLineEndOffset = firstLine.length();
273
0
    m_VersionOffset = m_UriOffset + uri.length() + 6;
274
275
0
    m_SipRequest->m_DataLen = firstLine.length();
276
0
    m_SipRequest->m_Data = new uint8_t[m_SipRequest->m_DataLen];
277
0
    memcpy(m_SipRequest->m_Data, firstLine.c_str(), m_SipRequest->m_DataLen);
278
279
0
    m_IsComplete = true;
280
0
  }
281
0
  catch (const SipRequestFirstLineException&)
282
0
  {
283
0
    throw;
284
0
  }
285
0
  catch (...)
286
0
  {
287
0
    std::terminate();
288
0
  }
289
290
  SipRequestLayer::SipMethod SipRequestFirstLine::parseMethod(const char* data, size_t dataLen)
291
40.5k
  {
292
40.5k
    if (!data || dataLen < 4)
293
218
    {
294
218
      return SipRequestLayer::SipMethodUnknown;
295
218
    }
296
297
40.3k
    size_t spaceIndex = 0;
298
704k
    while (spaceIndex < dataLen && data[spaceIndex] != ' ')
299
664k
    {
300
664k
      spaceIndex++;
301
664k
    }
302
303
40.3k
    if (spaceIndex == 0 || spaceIndex == dataLen)
304
3.62k
    {
305
3.62k
      return SipRequestLayer::SipMethodUnknown;
306
3.62k
    }
307
308
36.7k
    auto methodAdEnum = SipMethodStringToEnum.find(std::string(data, data + spaceIndex));
309
36.7k
    if (methodAdEnum == SipMethodStringToEnum.end())
310
19.9k
    {
311
19.9k
      return SipRequestLayer::SipMethodUnknown;
312
19.9k
    }
313
16.7k
    return methodAdEnum->second;
314
36.7k
  }
315
316
  std::pair<bool, SipRequestFirstLine::SipFirstLineData> SipRequestFirstLine::parseFirstLine(const char* data,
317
                                                                                             size_t dataLen)
318
2.47k
  {
319
2.47k
    SipFirstLineData result = { "", "", "" };
320
321
2.47k
    if (data == nullptr || dataLen == 0)
322
0
    {
323
0
      PCPP_LOG_DEBUG("Empty data in SIP request line");
324
0
      return { false, result };
325
0
    }
326
327
    // Find first space (end of METHOD)
328
2.47k
    size_t firstSpaceIndex = 0;
329
41.0k
    while (firstSpaceIndex < dataLen && data[firstSpaceIndex] != ' ')
330
38.5k
    {
331
38.5k
      firstSpaceIndex++;
332
38.5k
    }
333
334
2.47k
    if (firstSpaceIndex == 0 || firstSpaceIndex == dataLen)
335
42
    {
336
42
      PCPP_LOG_DEBUG("Invalid METHOD in SIP request line");
337
42
      return { false, result };
338
42
    }
339
340
    // Validate method exists in SipMethodStringToEnum
341
2.43k
    std::string methodStr{ data, firstSpaceIndex };
342
2.43k
    if (SipMethodStringToEnum.find(methodStr) == SipMethodStringToEnum.end())
343
186
    {
344
186
      PCPP_LOG_DEBUG("Unknown SIP method");
345
186
      return { false, result };
346
186
    }
347
348
    // Find second space (end of URI)
349
2.24k
    size_t secondSpaceIndex = firstSpaceIndex + 1;
350
131k
    while (secondSpaceIndex < dataLen && data[secondSpaceIndex] != ' ')
351
128k
      secondSpaceIndex++;
352
353
2.24k
    if (secondSpaceIndex == dataLen)
354
107
    {
355
107
      PCPP_LOG_DEBUG("No space before version");
356
107
      return { false, result };
357
107
    }
358
359
2.14k
    size_t uriLen = secondSpaceIndex - firstSpaceIndex - 1;
360
2.14k
    if (uriLen == 0)
361
13
    {
362
13
      PCPP_LOG_DEBUG("Empty URI");
363
13
      return { false, result };
364
13
    }
365
366
    // Find end of line
367
2.12k
    size_t lineEnd = secondSpaceIndex + 1;
368
67.8k
    while (lineEnd < dataLen && data[lineEnd] != '\r' && data[lineEnd] != '\n')
369
65.6k
      lineEnd++;
370
371
    // Minimum length for "SIP/x.y"
372
2.12k
    size_t versionLen = lineEnd - secondSpaceIndex - 1;
373
2.12k
    if (versionLen < 7)
374
131
    {
375
131
      PCPP_LOG_DEBUG("Version too short");
376
131
      return { false, result };
377
131
    }
378
379
1.99k
    const char* versionStart = data + secondSpaceIndex + 1;
380
1.99k
    if (versionStart[0] != 'S' || versionStart[1] != 'I' || versionStart[2] != 'P' || versionStart[3] != '/')
381
865
    {
382
865
      PCPP_LOG_DEBUG("Invalid SIP version format");
383
865
      return { false, result };
384
865
    }
385
386
    // All validations passed
387
1.13k
    result.method = std::move(methodStr);
388
1.13k
    result.uri = std::string{ data + firstSpaceIndex + 1, uriLen };
389
1.13k
    result.version = std::string{ versionStart, versionLen };
390
391
1.13k
    return { true, result };
392
1.99k
  }
393
394
  void SipRequestFirstLine::parseVersion()
395
8.95k
  {
396
8.95k
    if (m_SipRequest->getDataLen() < static_cast<size_t>(m_UriOffset))
397
0
    {
398
0
      m_Version = "";
399
0
      m_VersionOffset = -1;
400
0
      return;
401
0
    }
402
403
8.95k
    char* data = reinterpret_cast<char*>(m_SipRequest->m_Data + m_UriOffset);
404
8.95k
    char* verPos = cross_platform_memmem(data, m_SipRequest->getDataLen() - m_UriOffset, " SIP/", 5);
405
8.95k
    if (verPos == nullptr)
406
1.09k
    {
407
1.09k
      m_Version = "";
408
1.09k
      m_VersionOffset = -1;
409
1.09k
      return;
410
1.09k
    }
411
412
    // verify packet doesn't end before the version, meaning still left place for " SIP/x.y" (7 chars)
413
7.86k
    if (static_cast<uint16_t>(verPos + 7 - reinterpret_cast<char*>(m_SipRequest->m_Data)) >
414
7.86k
        m_SipRequest->getDataLen())
415
20
    {
416
20
      m_Version = "";
417
20
      m_VersionOffset = -1;
418
20
      return;
419
20
    }
420
421
    // skip the space char
422
7.84k
    verPos++;
423
424
7.84k
    int endOfVerPos = 0;
425
120k
    while (((verPos + endOfVerPos) < reinterpret_cast<char*>(m_SipRequest->m_Data + m_SipRequest->m_DataLen)) &&
426
120k
           ((verPos + endOfVerPos)[0] != '\r') && ((verPos + endOfVerPos)[0] != '\n'))
427
112k
      endOfVerPos++;
428
429
7.84k
    m_Version = std::string(verPos, endOfVerPos);
430
431
7.84k
    m_VersionOffset = verPos - reinterpret_cast<char*>(m_SipRequest->m_Data);
432
7.84k
  }
433
434
  bool SipRequestFirstLine::setMethod(SipRequestLayer::SipMethod newMethod)
435
0
  {
436
0
    if (newMethod == SipRequestLayer::SipMethodUnknown)
437
0
    {
438
0
      PCPP_LOG_ERROR("Requested method is SipMethodUnknown");
439
0
      return false;
440
0
    }
441
442
    // extend or shorten layer
443
0
    int lengthDifference = SipMethodEnumToString[newMethod].length() - SipMethodEnumToString[m_Method].length();
444
0
    if (lengthDifference > 0)
445
0
    {
446
0
      if (!m_SipRequest->extendLayer(0, lengthDifference))
447
0
      {
448
0
        PCPP_LOG_ERROR("Cannot change layer size");
449
0
        return false;
450
0
      }
451
0
    }
452
0
    else if (lengthDifference < 0)
453
0
    {
454
0
      if (!m_SipRequest->shortenLayer(0, 0 - lengthDifference))
455
0
      {
456
0
        PCPP_LOG_ERROR("Cannot change layer size");
457
0
        return false;
458
0
      }
459
0
    }
460
461
0
    if (lengthDifference != 0)
462
0
    {
463
0
      m_SipRequest->shiftFieldsOffset(m_SipRequest->getFirstField(), lengthDifference);
464
0
      m_SipRequest->m_FieldsOffset += lengthDifference;
465
0
    }
466
467
0
    memcpy(m_SipRequest->m_Data, SipMethodEnumToString[newMethod].c_str(),
468
0
           SipMethodEnumToString[newMethod].length());
469
470
0
    m_UriOffset += lengthDifference;
471
0
    m_VersionOffset += lengthDifference;
472
0
    m_FirstLineEndOffset += lengthDifference;
473
474
0
    m_Method = newMethod;
475
476
0
    return true;
477
0
  }
478
479
  std::string SipRequestFirstLine::getUri() const
480
0
  {
481
0
    std::string result;
482
0
    if (m_UriOffset != -1 && m_VersionOffset != -1)
483
0
      result.assign(reinterpret_cast<char*>(m_SipRequest->m_Data + m_UriOffset),
484
0
                    m_VersionOffset - 1 - m_UriOffset);
485
486
    // else first line is illegal, return empty string
487
488
0
    return result;
489
0
  }
490
491
  bool SipRequestFirstLine::setUri(const std::string& newUri)
492
0
  {
493
0
    if (newUri == "")
494
0
    {
495
0
      PCPP_LOG_ERROR("URI cannot be empty");
496
0
      return false;
497
0
    }
498
499
    // extend or shorten layer
500
0
    std::string currentUri = getUri();
501
0
    int lengthDifference = newUri.length() - currentUri.length();
502
0
    if (lengthDifference > 0)
503
0
    {
504
0
      if (!m_SipRequest->extendLayer(m_UriOffset, lengthDifference))
505
0
      {
506
0
        PCPP_LOG_ERROR("Cannot change layer size");
507
0
        return false;
508
0
      }
509
0
    }
510
0
    else if (lengthDifference < 0)
511
0
    {
512
0
      if (!m_SipRequest->shortenLayer(m_UriOffset, 0 - lengthDifference))
513
0
      {
514
0
        PCPP_LOG_ERROR("Cannot change layer size");
515
0
        return false;
516
0
      }
517
0
    }
518
519
0
    if (lengthDifference != 0)
520
0
    {
521
0
      m_SipRequest->shiftFieldsOffset(m_SipRequest->getFirstField(), lengthDifference);
522
0
      m_SipRequest->m_FieldsOffset += lengthDifference;
523
0
    }
524
525
0
    memcpy(m_SipRequest->m_Data + m_UriOffset, newUri.c_str(), newUri.length());
526
527
0
    m_VersionOffset += lengthDifference;
528
0
    m_FirstLineEndOffset += lengthDifference;
529
530
0
    return true;
531
0
  }
532
533
  // -------- Class SipRequestLayer -----------------
534
535
  SipRequestLayer::SipRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
536
8.95k
      : SipLayer(data, dataLen, prevLayer, packet, SIPRequest)
537
8.95k
  {
538
8.95k
    m_FirstLine = new SipRequestFirstLine(this);
539
8.95k
    m_FieldsOffset = m_FirstLine->getSize();
540
8.95k
    parseFields();
541
8.95k
  }
542
543
  SipRequestLayer::SipRequestLayer(SipMethod method, const std::string& requestUri, const std::string& version)
544
0
  {
545
0
    m_Protocol = SIPRequest;
546
0
    m_FirstLine = new SipRequestFirstLine(this, method, version, requestUri);
547
0
    m_FieldsOffset = m_FirstLine->getSize();
548
0
  }
549
550
0
  SipRequestLayer::SipRequestLayer(const SipRequestLayer& other) : SipLayer(other)
551
0
  {
552
0
    m_FirstLine = new SipRequestFirstLine(this);
553
0
  }
554
555
  SipRequestLayer& SipRequestLayer::operator=(const SipRequestLayer& other)
556
0
  {
557
0
    SipLayer::operator=(other);
558
559
0
    if (m_FirstLine != nullptr)
560
0
      delete m_FirstLine;
561
562
0
    m_FirstLine = new SipRequestFirstLine(this);
563
564
0
    return *this;
565
0
  }
566
567
  SipRequestLayer::~SipRequestLayer()
568
8.95k
  {
569
8.95k
    delete m_FirstLine;
570
8.95k
  }
571
572
  std::string SipRequestLayer::toString() const
573
3.30k
  {
574
3.30k
    static const int maxLengthToPrint = 120;
575
3.30k
    std::string result = "SIP request, ";
576
3.30k
    int size = m_FirstLine->getSize() - 2;  // the -2 is to remove \r\n at the end of the first line
577
3.30k
    if (size <= 0)
578
4
    {
579
4
      result += std::string("CORRUPT DATA");
580
4
      return result;
581
4
    }
582
3.30k
    if (size <= maxLengthToPrint)
583
2.82k
    {
584
2.82k
      char* firstLine = new char[size + 1];
585
2.82k
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), size);
586
2.82k
      firstLine[size] = 0;
587
2.82k
      result += std::string(firstLine);
588
2.82k
      delete[] firstLine;
589
2.82k
    }
590
482
    else
591
482
    {
592
482
      char firstLine[maxLengthToPrint + 1];
593
482
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3);
594
482
      firstLine[maxLengthToPrint - 3] = '.';
595
482
      firstLine[maxLengthToPrint - 2] = '.';
596
482
      firstLine[maxLengthToPrint - 1] = '.';
597
482
      firstLine[maxLengthToPrint] = 0;
598
482
      result += std::string(firstLine);
599
482
    }
600
601
3.30k
    return result;
602
3.30k
  }
603
604
  // -------- Class SipResponseLayer -----------------
605
606
  namespace
607
  {
608
    const std::array<std::string, 77> StatusCodeEnumToString = {  // format override comment
609
      "Trying",
610
      "Ringing",
611
      "Call is Being Forwarded",
612
      "Queued",
613
      "Session in Progress",
614
      "Early Dialog Terminated",
615
      "OK",
616
      "Accepted",
617
      "No Notification",
618
      "Multiple Choices",
619
      "Moved Permanently",
620
      "Moved Temporarily",
621
      "Use Proxy",
622
      "Alternative Service",
623
      "Bad Request",
624
      "Unauthorized",
625
      "Payment Required",
626
      "Forbidden",
627
      "Not Found",
628
      "Method Not Allowed",
629
      "Not Acceptable",
630
      "Proxy Authentication Required",
631
      "Request Timeout",
632
      "Conflict",
633
      "Gone",
634
      "Length Required",
635
      "Conditional Request Failed",
636
      "Request Entity Too Large",
637
      "Request-URI Too Long",
638
      "Unsupported Media Type",
639
      "Unsupported URI Scheme",
640
      "Unknown Resource-Priority",
641
      "Bad Extension",
642
      "Extension Required",
643
      "Session Interval Too Small",
644
      "Interval Too Brief",
645
      "Bad Location Information",
646
      "Bad Alert Message",
647
      "Use Identity Header",
648
      "Provide Referrer Identity",
649
      "Flow Failed",
650
      "Anonymity Disallowed",
651
      "Bad Identity-Info",
652
      "Unsupported Certificate",
653
      "Invalid Identity Header",
654
      "First Hop Lacks Outbound Support",
655
      "Max-Breadth Exceeded",
656
      "Bad Info Package",
657
      "Consent Needed",
658
      "Temporarily Unavailable",
659
      "Call_Transaction Does Not Exist",
660
      "Loop Detected",
661
      "Too Many Hops",
662
      "Address Incomplete",
663
      "Ambiguous",
664
      "Busy Here",
665
      "Request Terminated",
666
      "Not Acceptable Here",
667
      "Bad Event",
668
      "Request Pending",
669
      "Undecipherable",
670
      "Security Agreement Required",
671
      "Server Internal Error",
672
      "Not Implemented",
673
      "Bad Gateway",
674
      "Service Unavailable",
675
      "Server Timeout",
676
      "Version Not Supported",
677
      "Message Too Large",
678
      "Push Notification Service Not Supported",
679
      "Precondition Failure",
680
      "Busy Everywhere",
681
      "Decline",
682
      "Does Not Exist Anywhere",
683
      "Not Acceptable",
684
      "Unwanted",
685
      "Rejected"
686
    };
687
688
    const std::array<int, 77> StatusCodeEnumToInt = {
689
      100, 180, 181, 182, 183, 199, 200, 202, 204, 300, 301, 302, 305, 380, 400, 401, 402, 403, 404, 405,
690
      406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 420, 421, 422, 425, 423, 424, 428, 429,
691
      430, 433, 436, 437, 438, 439, 440, 469, 470, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 491,
692
      493, 494, 500, 501, 502, 503, 504, 505, 513, 555, 580, 600, 603, 604, 606, 607, 608
693
    };
694
695
    // Parses the SIP status code from raw data. The data must point to the beginning of the status code.
696
    SipResponseLayer::SipResponseStatusCode parseStatusCodePure(const char* data, size_t dataLen)
697
35.1k
    {
698
35.1k
      if (data == nullptr || dataLen < 3)
699
0
      {
700
0
        return SipResponseLayer::SipStatusCodeUnknown;
701
0
      }
702
703
35.1k
      uint16_t code = 0;
704
35.1k
      code += (static_cast<uint16_t>(data[0]) - '0') * 100;
705
35.1k
      code += (static_cast<uint16_t>(data[1]) - '0') * 10;
706
35.1k
      code += (static_cast<uint16_t>(data[2]) - '0');
707
708
35.1k
      switch (code)
709
35.1k
      {
710
      // 1xx: Informational
711
4.51k
      case 100:
712
4.51k
        return SipResponseLayer::SipResponseStatusCode::Sip100Trying;
713
704
      case 180:
714
704
        return SipResponseLayer::SipResponseStatusCode::Sip180Ringing;
715
82
      case 181:
716
82
        return SipResponseLayer::SipResponseStatusCode::Sip181CallisBeingForwarded;
717
107
      case 182:
718
107
        return SipResponseLayer::SipResponseStatusCode::Sip182Queued;
719
114
      case 183:
720
114
        return SipResponseLayer::SipResponseStatusCode::Sip183SessioninProgress;
721
816
      case 199:
722
816
        return SipResponseLayer::SipResponseStatusCode::Sip199EarlyDialogTerminated;
723
      // 2xx: Success
724
14.0k
      case 200:
725
14.0k
        return SipResponseLayer::SipResponseStatusCode::Sip200OK;
726
379
      case 202:
727
379
        return SipResponseLayer::SipResponseStatusCode::Sip202Accepted;
728
759
      case 204:
729
759
        return SipResponseLayer::SipResponseStatusCode::Sip204NoNotification;
730
      // 3xx: Redirection
731
1.18k
      case 300:
732
1.18k
        return SipResponseLayer::SipResponseStatusCode::Sip300MultipleChoices;
733
89
      case 301:
734
89
        return SipResponseLayer::SipResponseStatusCode::Sip301MovedPermanently;
735
46
      case 302:
736
46
        return SipResponseLayer::SipResponseStatusCode::Sip302MovedTemporarily;
737
62
      case 305:
738
62
        return SipResponseLayer::SipResponseStatusCode::Sip305UseProxy;
739
74
      case 380:
740
74
        return SipResponseLayer::SipResponseStatusCode::Sip380AlternativeService;
741
      // 4xx: Client Failure
742
171
      case 400:
743
171
        return SipResponseLayer::SipResponseStatusCode::Sip400BadRequest;
744
3.70k
      case 401:
745
3.70k
        return SipResponseLayer::SipResponseStatusCode::Sip401Unauthorized;
746
513
      case 402:
747
513
        return SipResponseLayer::SipResponseStatusCode::Sip402PaymentRequired;
748
822
      case 403:
749
822
        return SipResponseLayer::SipResponseStatusCode::Sip403Forbidden;
750
81
      case 404:
751
81
        return SipResponseLayer::SipResponseStatusCode::Sip404NotFound;
752
81
      case 405:
753
81
        return SipResponseLayer::SipResponseStatusCode::Sip405MethodNotAllowed;
754
73
      case 406:
755
73
        return SipResponseLayer::SipResponseStatusCode::Sip406NotAcceptable;
756
517
      case 407:
757
517
        return SipResponseLayer::SipResponseStatusCode::Sip407ProxyAuthenticationRequired;
758
723
      case 408:
759
723
        return SipResponseLayer::SipResponseStatusCode::Sip408RequestTimeout;
760
207
      case 409:
761
207
        return SipResponseLayer::SipResponseStatusCode::Sip409Conflict;
762
81
      case 410:
763
81
        return SipResponseLayer::SipResponseStatusCode::Sip410Gone;
764
82
      case 411:
765
82
        return SipResponseLayer::SipResponseStatusCode::Sip411LengthRequired;
766
82
      case 412:
767
82
        return SipResponseLayer::SipResponseStatusCode::Sip412ConditionalRequestFailed;
768
84
      case 413:
769
84
        return SipResponseLayer::SipResponseStatusCode::Sip413RequestEntityTooLarge;
770
107
      case 414:
771
107
        return SipResponseLayer::SipResponseStatusCode::Sip414RequestURITooLong;
772
105
      case 415:
773
105
        return SipResponseLayer::SipResponseStatusCode::Sip415UnsupportedMediaType;
774
79
      case 416:
775
79
        return SipResponseLayer::SipResponseStatusCode::Sip416UnsupportedURIScheme;
776
85
      case 417:
777
85
        return SipResponseLayer::SipResponseStatusCode::Sip417UnknownResourcePriority;
778
68
      case 420:
779
68
        return SipResponseLayer::SipResponseStatusCode::Sip420BadExtension;
780
85
      case 421:
781
85
        return SipResponseLayer::SipResponseStatusCode::Sip421ExtensionRequired;
782
81
      case 422:
783
81
        return SipResponseLayer::SipResponseStatusCode::Sip422SessionIntervalTooSmall;
784
83
      case 423:
785
83
        return SipResponseLayer::SipResponseStatusCode::Sip423IntervalTooBrief;
786
99
      case 424:
787
99
        return SipResponseLayer::SipResponseStatusCode::Sip424BadLocationInformation;
788
74
      case 425:
789
74
        return SipResponseLayer::SipResponseStatusCode::Sip425BadAlertMessage;
790
72
      case 428:
791
72
        return SipResponseLayer::SipResponseStatusCode::Sip428UseIdentityHeader;
792
78
      case 429:
793
78
        return SipResponseLayer::SipResponseStatusCode::Sip429ProvideReferrerIdentity;
794
84
      case 430:
795
84
        return SipResponseLayer::SipResponseStatusCode::Sip430FlowFailed;
796
80
      case 433:
797
80
        return SipResponseLayer::SipResponseStatusCode::Sip433AnonymityDisallowed;
798
50
      case 436:
799
50
        return SipResponseLayer::SipResponseStatusCode::Sip436BadIdentityInfo;
800
85
      case 437:
801
85
        return SipResponseLayer::SipResponseStatusCode::Sip437UnsupportedCertificate;
802
81
      case 438:
803
81
        return SipResponseLayer::SipResponseStatusCode::Sip438InvalidIdentityHeader;
804
86
      case 439:
805
86
        return SipResponseLayer::SipResponseStatusCode::Sip439FirstHopLacksOutboundSupport;
806
124
      case 440:
807
124
        return SipResponseLayer::SipResponseStatusCode::Sip440MaxBreadthExceeded;
808
34
      case 469:
809
34
        return SipResponseLayer::SipResponseStatusCode::Sip469BadInfoPackage;
810
31
      case 470:
811
31
        return SipResponseLayer::SipResponseStatusCode::Sip470ConsentNeeded;
812
109
      case 480:
813
109
        return SipResponseLayer::SipResponseStatusCode::Sip480TemporarilyUnavailable;
814
76
      case 481:
815
76
        return SipResponseLayer::SipResponseStatusCode::Sip481Call_TransactionDoesNotExist;
816
77
      case 482:
817
77
        return SipResponseLayer::SipResponseStatusCode::Sip482LoopDetected;
818
81
      case 483:
819
81
        return SipResponseLayer::SipResponseStatusCode::Sip483TooManyHops;
820
107
      case 484:
821
107
        return SipResponseLayer::SipResponseStatusCode::Sip484AddressIncomplete;
822
79
      case 485:
823
79
        return SipResponseLayer::SipResponseStatusCode::Sip485Ambiguous;
824
79
      case 486:
825
79
        return SipResponseLayer::SipResponseStatusCode::Sip486BusyHere;
826
83
      case 487:
827
83
        return SipResponseLayer::SipResponseStatusCode::Sip487RequestTerminated;
828
73
      case 488:
829
73
        return SipResponseLayer::SipResponseStatusCode::Sip488NotAcceptableHere;
830
67
      case 489:
831
67
        return SipResponseLayer::SipResponseStatusCode::Sip489BadEvent;
832
37
      case 491:
833
37
        return SipResponseLayer::SipResponseStatusCode::Sip491RequestPending;
834
83
      case 493:
835
83
        return SipResponseLayer::SipResponseStatusCode::Sip493Undecipherable;
836
72
      case 494:
837
72
        return SipResponseLayer::SipResponseStatusCode::Sip494SecurityAgreementRequired;
838
      // 5xx: Server Failure
839
133
      case 500:
840
133
        return SipResponseLayer::SipResponseStatusCode::Sip500ServerInternalError;
841
169
      case 501:
842
169
        return SipResponseLayer::SipResponseStatusCode::Sip501NotImplemented;
843
46
      case 502:
844
46
        return SipResponseLayer::SipResponseStatusCode::Sip502BadGateway;
845
320
      case 503:
846
320
        return SipResponseLayer::SipResponseStatusCode::Sip503ServiceUnavailable;
847
45
      case 504:
848
45
        return SipResponseLayer::SipResponseStatusCode::Sip504ServerTimeout;
849
33
      case 505:
850
33
        return SipResponseLayer::SipResponseStatusCode::Sip505VersionNotSupported;
851
78
      case 513:
852
78
        return SipResponseLayer::SipResponseStatusCode::Sip513MessageTooLarge;
853
33
      case 555:
854
33
        return SipResponseLayer::SipResponseStatusCode::Sip555PushNotificationServiceNotSupported;
855
109
      case 580:
856
109
        return SipResponseLayer::SipResponseStatusCode::Sip580PreconditionFailure;
857
      // 6xx: Global Failure
858
116
      case 600:
859
116
        return SipResponseLayer::SipResponseStatusCode::Sip600BusyEverywhere;
860
97
      case 603:
861
97
        return SipResponseLayer::SipResponseStatusCode::Sip603Decline;
862
83
      case 604:
863
83
        return SipResponseLayer::SipResponseStatusCode::Sip604DoesNotExistAnywhere;
864
67
      case 606:
865
67
        return SipResponseLayer::SipResponseStatusCode::Sip606NotAcceptable;
866
33
      case 607:
867
33
        return SipResponseLayer::SipResponseStatusCode::Sip607Unwanted;
868
68
      case 608:
869
68
        return SipResponseLayer::SipResponseStatusCode::Sip608Rejected;
870
839
      default:
871
839
        return SipResponseLayer::SipStatusCodeUnknown;
872
35.1k
      }
873
35.1k
    }
874
  }  // namespace
875
876
  SipResponseLayer::SipResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
877
15.9k
      : SipLayer(data, dataLen, prevLayer, packet, SIPResponse)
878
15.9k
  {
879
15.9k
    m_FirstLine = new SipResponseFirstLine(this);
880
15.9k
    m_FieldsOffset = m_FirstLine->getSize();
881
15.9k
    parseFields();
882
15.9k
  }
883
884
  SipResponseLayer::SipResponseLayer(SipResponseLayer::SipResponseStatusCode statusCode, std::string statusCodeString,
885
                                     const std::string& sipVersion)
886
0
  {
887
0
    m_Protocol = SIPResponse;
888
0
    m_FirstLine = new SipResponseFirstLine(this, sipVersion, statusCode, std::move(statusCodeString));
889
0
    m_FieldsOffset = m_FirstLine->getSize();
890
0
  }
891
892
  SipResponseLayer::~SipResponseLayer()
893
15.9k
  {
894
15.9k
    delete m_FirstLine;
895
15.9k
  }
896
897
0
  SipResponseLayer::SipResponseLayer(const SipResponseLayer& other) : SipLayer(other)
898
0
  {
899
0
    m_FirstLine = new SipResponseFirstLine(this);
900
0
  }
901
902
  SipResponseLayer& SipResponseLayer::operator=(const SipResponseLayer& other)
903
0
  {
904
0
    SipLayer::operator=(other);
905
906
0
    if (m_FirstLine != nullptr)
907
0
      delete m_FirstLine;
908
909
0
    m_FirstLine = new SipResponseFirstLine(this);
910
911
0
    return *this;
912
0
  }
913
914
  std::string SipResponseLayer::toString() const
915
4.54k
  {
916
4.54k
    static const int maxLengthToPrint = 120;
917
4.54k
    std::string result = "SIP response, ";
918
4.54k
    int size = m_FirstLine->getSize() - 2;  // the -2 is to remove \r\n at the end of the first line
919
4.54k
    if (size <= 0)
920
0
    {
921
0
      result += std::string("CORRUPT DATA");
922
0
      return result;
923
0
    }
924
4.54k
    if (size <= maxLengthToPrint)
925
4.43k
    {
926
4.43k
      char* firstLine = new char[size + 1];
927
4.43k
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), size);
928
4.43k
      firstLine[size] = 0;
929
4.43k
      result += std::string(firstLine);
930
4.43k
      delete[] firstLine;
931
4.43k
    }
932
118
    else
933
118
    {
934
118
      char firstLine[maxLengthToPrint + 1];
935
118
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3);
936
118
      firstLine[maxLengthToPrint - 3] = '.';
937
118
      firstLine[maxLengthToPrint - 2] = '.';
938
118
      firstLine[maxLengthToPrint - 1] = '.';
939
118
      firstLine[maxLengthToPrint] = 0;
940
118
      result += std::string(firstLine);
941
118
    }
942
943
4.54k
    return result;
944
4.54k
  }
945
946
  // -------- Class SipResponseFirstLine -----------------
947
948
  int SipResponseFirstLine::getStatusCodeAsInt() const
949
0
  {
950
0
    return StatusCodeEnumToInt[m_StatusCode];
951
0
  }
952
953
  std::string SipResponseFirstLine::getStatusCodeString() const
954
0
  {
955
0
    std::string result;
956
0
    const int statusStringOffset = 12;
957
0
    if (m_StatusCode != SipResponseLayer::SipStatusCodeUnknown)
958
0
    {
959
0
      int statusStringEndOffset = m_FirstLineEndOffset - 2;
960
0
      if ((*(m_SipResponse->m_Data + statusStringEndOffset)) != '\r')
961
0
        statusStringEndOffset++;
962
0
      result.assign(reinterpret_cast<char*>(m_SipResponse->m_Data + statusStringOffset),
963
0
                    statusStringEndOffset - statusStringOffset);
964
0
    }
965
966
    // else first line is illegal, return empty string
967
968
0
    return result;
969
0
  }
970
971
  bool SipResponseFirstLine::setStatusCode(SipResponseLayer::SipResponseStatusCode newStatusCode,
972
                                           std::string statusCodeString)
973
0
  {
974
0
    if (newStatusCode == SipResponseLayer::SipStatusCodeUnknown)
975
0
    {
976
0
      PCPP_LOG_ERROR("Requested status code is SipStatusCodeUnknown");
977
0
      return false;
978
0
    }
979
980
    // extend or shorten layer
981
982
0
    size_t statusStringOffset = 12;
983
0
    if (statusCodeString == "")
984
0
      statusCodeString = StatusCodeEnumToString[newStatusCode];
985
0
    int lengthDifference = statusCodeString.length() - getStatusCodeString().length();
986
987
0
    if (lengthDifference > 0)
988
0
    {
989
0
      if (!m_SipResponse->extendLayer(statusStringOffset, lengthDifference))
990
0
      {
991
0
        PCPP_LOG_ERROR("Cannot change layer size");
992
0
        return false;
993
0
      }
994
0
    }
995
0
    else if (lengthDifference < 0)
996
0
    {
997
0
      if (!m_SipResponse->shortenLayer(statusStringOffset, 0 - lengthDifference))
998
0
      {
999
0
        PCPP_LOG_ERROR("Cannot change layer size");
1000
0
        return false;
1001
0
      }
1002
0
    }
1003
1004
0
    if (lengthDifference != 0)
1005
0
    {
1006
0
      m_SipResponse->shiftFieldsOffset(m_SipResponse->getFirstField(), lengthDifference);
1007
0
      m_SipResponse->m_FieldsOffset += lengthDifference;
1008
0
    }
1009
1010
    // copy status string
1011
0
    memcpy(m_SipResponse->m_Data + statusStringOffset, statusCodeString.c_str(), statusCodeString.length());
1012
1013
    // change status code
1014
0
    std::ostringstream statusCodeAsString;
1015
0
    statusCodeAsString << StatusCodeEnumToInt[newStatusCode];
1016
0
    memcpy(m_SipResponse->m_Data + 8, statusCodeAsString.str().c_str(), 3);
1017
1018
0
    m_StatusCode = newStatusCode;
1019
0
    m_FirstLineEndOffset += lengthDifference;
1020
1021
0
    return true;
1022
0
  }
1023
1024
  void SipResponseFirstLine::setVersion(const std::string& newVersion)
1025
0
  {
1026
0
    if (newVersion == "")
1027
0
      return;
1028
1029
0
    if (newVersion.length() != m_Version.length())
1030
0
    {
1031
0
      PCPP_LOG_ERROR("Expected version length is " << m_Version.length()
1032
0
                                                   << " characters in the format of SIP/x.y");
1033
0
      return;
1034
0
    }
1035
1036
0
    char* verPos = reinterpret_cast<char*>(m_SipResponse->m_Data);
1037
0
    memcpy(verPos, newVersion.c_str(), newVersion.length());
1038
0
    m_Version = newVersion;
1039
0
  }
1040
1041
  SipResponseLayer::SipResponseStatusCode SipResponseFirstLine::parseStatusCode(const char* data, size_t dataLen)
1042
39.7k
  {
1043
    // minimum data should be 12B long: "SIP/x.y XXX "
1044
39.7k
    if (!data || dataLen < 12)
1045
2.97k
    {
1046
2.97k
      return SipResponseLayer::SipStatusCodeUnknown;
1047
2.97k
    }
1048
1049
36.7k
    const char* statusCodeData = data + 8;
1050
36.7k
    if (statusCodeData[3] != ' ')
1051
5.09k
    {
1052
5.09k
      return SipResponseLayer::SipStatusCodeUnknown;
1053
5.09k
    }
1054
1055
31.6k
    return parseStatusCodePure(statusCodeData, 3);
1056
36.7k
  }
1057
1058
15.9k
  SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse) : m_SipResponse(sipResponse)
1059
15.9k
  {
1060
15.9k
    m_Version = parseVersion(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen());
1061
15.9k
    if (m_Version == "")
1062
28
    {
1063
28
      m_StatusCode = SipResponseLayer::SipStatusCodeUnknown;
1064
28
    }
1065
15.9k
    else
1066
15.9k
    {
1067
15.9k
      m_StatusCode = parseStatusCode(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen());
1068
15.9k
    }
1069
1070
15.9k
    char* endOfFirstLine;
1071
15.9k
    if ((endOfFirstLine = static_cast<char*>(
1072
15.9k
             memchr(reinterpret_cast<char*>(m_SipResponse->m_Data), '\n', m_SipResponse->m_DataLen))) != nullptr)
1073
15.4k
    {
1074
15.4k
      m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipResponse->m_Data) + 1;
1075
15.4k
      m_IsComplete = true;
1076
15.4k
    }
1077
563
    else
1078
563
    {
1079
563
      m_FirstLineEndOffset = m_SipResponse->getDataLen();
1080
563
      m_IsComplete = false;
1081
563
    }
1082
1083
15.9k
    if (Logger::getInstance().isDebugEnabled(PacketLogModuleSipLayer))
1084
0
    {
1085
0
      int statusCode =
1086
0
          (m_StatusCode == SipResponseLayer::SipStatusCodeUnknown ? 0 : StatusCodeEnumToInt[m_StatusCode]);
1087
0
      PCPP_LOG_DEBUG("Version='" << m_Version << "'; Status code=" << statusCode << " '" << getStatusCodeString()
1088
0
                                 << "'");
1089
0
    }
1090
15.9k
  }
1091
1092
  SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse, const std::string& version,
1093
                                             SipResponseLayer::SipResponseStatusCode statusCode,
1094
                                             std::string statusCodeString)
1095
0
  {
1096
0
    if (statusCode == SipResponseLayer::SipStatusCodeUnknown)
1097
0
    {
1098
0
      m_Exception.setMessage("Status code supplied was SipStatusCodeUnknown");
1099
0
      throw m_Exception;
1100
0
    }
1101
1102
0
    if (version == "")
1103
0
    {
1104
0
      m_Exception.setMessage("Version supplied was unknown");
1105
0
      throw m_Exception;
1106
0
    }
1107
1108
0
    m_SipResponse = sipResponse;
1109
1110
0
    m_StatusCode = statusCode;
1111
0
    m_Version = version;
1112
1113
0
    std::ostringstream statusCodeAsString;
1114
0
    statusCodeAsString << StatusCodeEnumToInt[m_StatusCode];
1115
0
    if (statusCodeString == "")
1116
0
      statusCodeString = StatusCodeEnumToString[m_StatusCode];
1117
0
    std::string firstLine = m_Version + " " + statusCodeAsString.str() + " " + statusCodeString + "\r\n";
1118
1119
0
    m_FirstLineEndOffset = firstLine.length();
1120
1121
0
    m_SipResponse->m_DataLen = firstLine.length();
1122
0
    m_SipResponse->m_Data = new uint8_t[m_SipResponse->m_DataLen];
1123
0
    memcpy(m_SipResponse->m_Data, firstLine.c_str(), m_SipResponse->m_DataLen);
1124
1125
0
    m_IsComplete = true;
1126
0
  }
1127
1128
  std::string SipResponseFirstLine::parseVersion(const char* data, size_t dataLen)
1129
32.7k
  {
1130
32.7k
    if (!data || dataLen < 8)  // "SIP/x.y "
1131
0
    {
1132
0
      PCPP_LOG_DEBUG("SIP response length < 8, cannot identify version");
1133
0
      return "";
1134
0
    }
1135
1136
32.7k
    if (data[0] != 'S' || data[1] != 'I' || data[2] != 'P' || data[3] != '/')
1137
4.12k
    {
1138
4.12k
      PCPP_LOG_DEBUG("SIP response does not begin with 'SIP/'");
1139
4.12k
      return "";
1140
4.12k
    }
1141
1142
28.6k
    const char* nextSpace = static_cast<const char*>(memchr(data, ' ', dataLen));
1143
28.6k
    if (nextSpace == nullptr)
1144
0
      return "";
1145
1146
28.6k
    return std::string(data, nextSpace - data);
1147
28.6k
  }
1148
1149
  std::pair<bool, SipResponseFirstLine::FirstLineData> SipResponseFirstLine::parseFirstLine(const char* data,
1150
                                                                                            size_t dataLen)
1151
3.65k
  {
1152
3.65k
    std::pair<bool, FirstLineData> result{};  // initialize to false and empty strings
1153
1154
    // Minimum data should be 12 bytes long: "SIP/x.y XXX "
1155
3.65k
    if (data == nullptr || dataLen < 12)
1156
5
    {
1157
5
      PCPP_LOG_DEBUG("SIP response length < 12, cannot parse first line");
1158
5
      return result;
1159
5
    }
1160
1161
3.65k
    if (pack4(data, 4) != "SIP/"_packed4)
1162
0
    {
1163
0
      PCPP_LOG_DEBUG("SIP response does not begin with 'SIP/'");
1164
0
      return result;
1165
0
    }
1166
1167
3.65k
    const auto dataEndIt = data + dataLen;
1168
    // Find first space (end of version)
1169
3.65k
    auto firstSpaceIt = std::find(data + 4, dataEndIt, ' ');
1170
3.65k
    if (firstSpaceIt == dataEndIt)
1171
76
    {
1172
76
      PCPP_LOG_DEBUG("No space after version in SIP response line");
1173
76
      return result;
1174
76
    }
1175
1176
    // Status code is strictly 3 characters followed by a space
1177
3.57k
    auto statusCodeIt = firstSpaceIt + 1;
1178
3.57k
    auto statusCodeEndIt = statusCodeIt + 3;
1179
3.57k
    if (*statusCodeEndIt != ' ')
1180
116
    {
1181
116
      PCPP_LOG_DEBUG("No space after status code in SIP response line");
1182
116
      return result;
1183
116
    }
1184
1185
3.46k
    auto statusCode = parseStatusCodePure(statusCodeIt, 3);
1186
3.46k
    if (statusCode == SipResponseLayer::SipStatusCodeUnknown)
1187
161
    {
1188
161
      PCPP_LOG_DEBUG("Unknown SIP status code");
1189
161
      return result;
1190
161
    }
1191
1192
    // Write parsed values to result
1193
3.30k
    result.first = true;
1194
3.30k
    result.second.version = std::string(data, firstSpaceIt);
1195
3.30k
    result.second.statusCode = statusCode;
1196
3.30k
    return result;
1197
3.46k
  }
1198
1199
}  // namespace pcpp