Coverage Report

Created: 2026-06-30 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/SipLayer.cpp
Line
Count
Source
1
2.63k
#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
51.7k
    {
21
51.7k
      return ((len > 0 ? static_cast<uint32_t>(data[0]) << 24 : 0) |
22
51.7k
              (len > 1 ? static_cast<uint32_t>(data[1]) << 16 : 0) |
23
51.7k
              (len > 2 ? static_cast<uint32_t>(data[2]) << 8 : 0) |
24
51.7k
              (len > 3 ? static_cast<uint32_t>(data[3]) : 0));
25
51.7k
    }
26
27
    constexpr uint32_t operator""_packed4(const char* str, size_t len)
28
462
    {
29
462
      return pack4(str, len);
30
462
    }
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
9.01k
  {
59
9.01k
    std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD);
60
9.01k
    std::transform(contentLengthFieldName.begin(), contentLengthFieldName.end(), contentLengthFieldName.begin(),
61
9.01k
                   ::tolower);
62
9.01k
    HeaderField* contentLengthField = getFieldByName(contentLengthFieldName);
63
9.01k
    if (contentLengthField != nullptr)
64
5.18k
      return atoi(contentLengthField->getFieldValue().c_str());
65
3.82k
    return 0;
66
9.01k
  }
67
68
  HeaderField* SipLayer::setContentLength(int contentLength, const std::string& prevFieldName)
69
618
  {
70
618
    std::ostringstream contentLengthAsString;
71
618
    contentLengthAsString << contentLength;
72
618
    std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD);
73
618
    HeaderField* contentLengthField = getFieldByName(contentLengthFieldName);
74
618
    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
618
    else
80
618
      contentLengthField->setFieldValue(contentLengthAsString.str());
81
82
618
    return contentLengthField;
83
618
  }
84
85
  void SipLayer::parseNextLayer()
86
12.7k
  {
87
12.7k
    if (getLayerPayloadSize() == 0)
88
4.44k
      return;
89
90
8.32k
    size_t headerLen = getHeaderLen();
91
8.32k
    std::string contentType;
92
8.32k
    if (getContentLength() > 0)
93
4.43k
    {
94
4.43k
      HeaderField* contentTypeField = getFieldByName(PCPP_SIP_CONTENT_TYPE_FIELD);
95
4.43k
      if (contentTypeField != nullptr)
96
4.41k
        contentType = contentTypeField->getFieldValue();
97
4.43k
    }
98
99
8.32k
    auto payload = m_Data + headerLen;
100
8.32k
    auto payloadLen = m_DataLen - headerLen;
101
102
8.32k
    if (contentType.find("application/sdp") != std::string::npos)
103
4.27k
    {
104
4.27k
      constructNextLayer<SdpLayer>(payload, payloadLen);
105
4.27k
    }
106
4.05k
    else
107
4.05k
    {
108
4.05k
      constructNextLayer<PayloadLayer>(payload, payloadLen);
109
4.05k
    }
110
8.32k
  }
111
112
  void SipLayer::computeCalculateFields()
113
2.31k
  {
114
2.31k
    HeaderField* contentLengthField = getFieldByName(PCPP_SIP_CONTENT_LENGTH_FIELD);
115
2.31k
    if (contentLengthField == nullptr)
116
1.36k
      return;
117
118
948
    size_t headerLen = getHeaderLen();
119
948
    if (m_DataLen > headerLen)
120
683
    {
121
683
      int currentContentLength = getContentLength();
122
683
      if (currentContentLength != static_cast<int>(m_DataLen - headerLen))
123
618
        setContentLength(m_DataLen - headerLen);
124
683
    }
125
948
  }
126
127
  SipLayer::SipParseResult SipLayer::detectSipMessageType(const uint8_t* data, size_t dataLen)
128
51.5k
  {
129
51.5k
    if (!data || dataLen < 3)
130
640
    {
131
640
      return SipLayer::SipParseResult::Unknown;
132
640
    }
133
134
50.8k
    uint32_t key = pack4(reinterpret_cast<const char*>(data), dataLen);
135
136
50.8k
    switch (key)
137
50.8k
    {
138
81
    case "INVI"_packed4:  // INVITE
139
93
    case "ACK "_packed4:  // ACK
140
93
    case "BYE "_packed4:  // BYE
141
93
    case "CANC"_packed4:  // CANCEL
142
118
    case "REGI"_packed4:  // REGISTER
143
118
    case "PRAC"_packed4:  // PRACK
144
118
    case "OPTI"_packed4:  // OPTIONS
145
118
    case "SUBS"_packed4:  // SUBSCRIBE
146
808
    case "NOTI"_packed4:  // NOTIFY
147
808
    case "PUBL"_packed4:  // PUBLISH
148
808
    case "INFO"_packed4:  // INFO
149
808
    case "REFE"_packed4:  // REFER
150
808
    case "MESS"_packed4:  // MESSAGE
151
808
    case "UPDA"_packed4:  // UPDATE
152
808
      return SipLayer::SipParseResult::Request;
153
154
462
    case "SIP/"_packed4:
155
462
      return SipLayer::SipParseResult::Response;
156
157
49.5k
    default:
158
49.5k
      return SipLayer::SipParseResult::Unknown;
159
50.8k
    }
160
50.8k
  }
161
162
  SipLayer* SipLayer::parseSipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, uint16_t srcPort,
163
                                    uint16_t dstPort)
164
11.8k
  {
165
11.8k
    if (!(SipLayer::isSipPort(srcPort) || SipLayer::isSipPort(dstPort)))
166
0
    {
167
0
      return nullptr;
168
0
    }
169
170
11.8k
    if (SipRequestFirstLine::parseMethod(reinterpret_cast<char*>(data), dataLen) !=
171
11.8k
        SipRequestLayer::SipMethodUnknown)
172
5.42k
    {
173
5.42k
      return new SipRequestLayer(data, dataLen, prevLayer, packet);
174
5.42k
    }
175
176
6.43k
    if (SipResponseFirstLine::parseStatusCode(reinterpret_cast<char*>(data), dataLen) !=
177
6.43k
            SipResponseLayer::SipStatusCodeUnknown &&
178
4.98k
        !SipResponseFirstLine::parseVersion(reinterpret_cast<char*>(data), dataLen).empty())
179
4.93k
    {
180
4.93k
      return new SipResponseLayer(data, dataLen, prevLayer, packet);
181
4.93k
    }
182
183
1.50k
    return nullptr;
184
6.43k
  }
185
186
  SipLayer* SipLayer::parseSipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
187
51.5k
  {
188
51.5k
    SipLayer::SipParseResult sipParseResult = detectSipMessageType(data, dataLen);
189
190
51.5k
    if (sipParseResult == SipLayer::SipParseResult::Unknown)
191
50.2k
    {
192
50.2k
      return nullptr;
193
50.2k
    }
194
195
1.27k
    if (sipParseResult == SipLayer::SipParseResult::Request)
196
808
    {
197
808
      if (SipRequestFirstLine::parseFirstLine(reinterpret_cast<char*>(data), dataLen).first)
198
106
      {
199
106
        return new SipRequestLayer(data, dataLen, prevLayer, packet);
200
106
      }
201
702
      return nullptr;
202
808
    }
203
204
462
    if (SipResponseFirstLine::parseFirstLine(reinterpret_cast<char*>(data), dataLen).first)
205
447
    {
206
447
      return new SipResponseLayer(data, dataLen, prevLayer, packet);
207
447
    }
208
15
    return nullptr;
209
462
  }
210
211
  // -------- Class SipRequestFirstLine -----------------
212
213
5.52k
  SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest) : m_SipRequest(sipRequest)
214
5.52k
  {
215
5.52k
    m_Method = parseMethod(reinterpret_cast<char*>(m_SipRequest->m_Data), m_SipRequest->getDataLen());
216
5.52k
    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
5.52k
    else
222
5.52k
      m_UriOffset = SipMethodEnumToString[m_Method].length() + 1;
223
224
5.52k
    parseVersion();
225
226
5.52k
    char* endOfFirstLine;
227
5.52k
    if ((endOfFirstLine =
228
5.52k
             static_cast<char*>(memchr(reinterpret_cast<char*>(m_SipRequest->m_Data + m_VersionOffset), '\n',
229
5.52k
                                       m_SipRequest->m_DataLen - static_cast<size_t>(m_VersionOffset)))) != nullptr)
230
5.36k
    {
231
5.36k
      m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipRequest->m_Data) + 1;
232
5.36k
      m_IsComplete = true;
233
5.36k
    }
234
163
    else
235
163
    {
236
163
      m_FirstLineEndOffset = m_SipRequest->getDataLen();
237
163
      m_IsComplete = false;
238
163
    }
239
240
5.52k
    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
5.52k
  }
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
19.2k
  {
292
19.2k
    if (!data || dataLen < 4)
293
5
    {
294
5
      return SipRequestLayer::SipMethodUnknown;
295
5
    }
296
297
19.2k
    size_t spaceIndex = 0;
298
287k
    while (spaceIndex < dataLen && data[spaceIndex] != ' ')
299
268k
    {
300
268k
      spaceIndex++;
301
268k
    }
302
303
19.2k
    if (spaceIndex == 0 || spaceIndex == dataLen)
304
1.07k
    {
305
1.07k
      return SipRequestLayer::SipMethodUnknown;
306
1.07k
    }
307
308
18.2k
    auto methodAdEnum = SipMethodStringToEnum.find(std::string(data, data + spaceIndex));
309
18.2k
    if (methodAdEnum == SipMethodStringToEnum.end())
310
7.25k
    {
311
7.25k
      return SipRequestLayer::SipMethodUnknown;
312
7.25k
    }
313
10.9k
    return methodAdEnum->second;
314
18.2k
  }
315
316
  std::pair<bool, SipRequestFirstLine::SipFirstLineData> SipRequestFirstLine::parseFirstLine(const char* data,
317
                                                                                             size_t dataLen)
318
808
  {
319
808
    SipFirstLineData result = { "", "", "" };
320
321
808
    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
808
    size_t firstSpaceIndex = 0;
329
5.67k
    while (firstSpaceIndex < dataLen && data[firstSpaceIndex] != ' ')
330
4.86k
    {
331
4.86k
      firstSpaceIndex++;
332
4.86k
    }
333
334
808
    if (firstSpaceIndex == 0 || firstSpaceIndex == dataLen)
335
0
    {
336
0
      PCPP_LOG_DEBUG("Invalid METHOD in SIP request line");
337
0
      return { false, result };
338
0
    }
339
340
    // Validate method exists in SipMethodStringToEnum
341
808
    std::string methodStr{ data, firstSpaceIndex };
342
808
    if (SipMethodStringToEnum.find(methodStr) == SipMethodStringToEnum.end())
343
0
    {
344
0
      PCPP_LOG_DEBUG("Unknown SIP method");
345
0
      return { false, result };
346
0
    }
347
348
    // Find second space (end of URI)
349
808
    size_t secondSpaceIndex = firstSpaceIndex + 1;
350
5.60k
    while (secondSpaceIndex < dataLen && data[secondSpaceIndex] != ' ')
351
4.79k
      secondSpaceIndex++;
352
353
808
    if (secondSpaceIndex == dataLen)
354
12
    {
355
12
      PCPP_LOG_DEBUG("No space before version");
356
12
      return { false, result };
357
12
    }
358
359
796
    size_t uriLen = secondSpaceIndex - firstSpaceIndex - 1;
360
796
    if (uriLen == 0)
361
0
    {
362
0
      PCPP_LOG_DEBUG("Empty URI");
363
0
      return { false, result };
364
0
    }
365
366
    // Find end of line
367
796
    size_t lineEnd = secondSpaceIndex + 1;
368
9.80k
    while (lineEnd < dataLen && data[lineEnd] != '\r' && data[lineEnd] != '\n')
369
9.00k
      lineEnd++;
370
371
    // Minimum length for "SIP/x.y"
372
796
    size_t versionLen = lineEnd - secondSpaceIndex - 1;
373
796
    if (versionLen < 7)
374
0
    {
375
0
      PCPP_LOG_DEBUG("Version too short");
376
0
      return { false, result };
377
0
    }
378
379
796
    const char* versionStart = data + secondSpaceIndex + 1;
380
796
    if (versionStart[0] != 'S' || versionStart[1] != 'I' || versionStart[2] != 'P' || versionStart[3] != '/')
381
690
    {
382
690
      PCPP_LOG_DEBUG("Invalid SIP version format");
383
690
      return { false, result };
384
690
    }
385
386
    // All validations passed
387
106
    result.method = std::move(methodStr);
388
106
    result.uri = std::string{ data + firstSpaceIndex + 1, uriLen };
389
106
    result.version = std::string{ versionStart, versionLen };
390
391
106
    return { true, result };
392
796
  }
393
394
  void SipRequestFirstLine::parseVersion()
395
5.52k
  {
396
5.52k
    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
5.52k
    char* data = reinterpret_cast<char*>(m_SipRequest->m_Data + m_UriOffset);
404
5.52k
    char* verPos = cross_platform_memmem(data, m_SipRequest->getDataLen() - m_UriOffset, " SIP/", 5);
405
5.52k
    if (verPos == nullptr)
406
3.76k
    {
407
3.76k
      m_Version = "";
408
3.76k
      m_VersionOffset = -1;
409
3.76k
      return;
410
3.76k
    }
411
412
    // verify packet doesn't end before the version, meaning still left place for " SIP/x.y" (7 chars)
413
1.75k
    if (static_cast<uint16_t>(verPos + 7 - reinterpret_cast<char*>(m_SipRequest->m_Data)) >
414
1.75k
        m_SipRequest->getDataLen())
415
5
    {
416
5
      m_Version = "";
417
5
      m_VersionOffset = -1;
418
5
      return;
419
5
    }
420
421
    // skip the space char
422
1.75k
    verPos++;
423
424
1.75k
    int endOfVerPos = 0;
425
20.4k
    while (((verPos + endOfVerPos) < reinterpret_cast<char*>(m_SipRequest->m_Data + m_SipRequest->m_DataLen)) &&
426
20.4k
           ((verPos + endOfVerPos)[0] != '\r') && ((verPos + endOfVerPos)[0] != '\n'))
427
18.6k
      endOfVerPos++;
428
429
1.75k
    m_Version = std::string(verPos, endOfVerPos);
430
431
1.75k
    m_VersionOffset = verPos - reinterpret_cast<char*>(m_SipRequest->m_Data);
432
1.75k
  }
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
5.52k
      : SipLayer(data, dataLen, prevLayer, packet, SIPRequest)
537
5.52k
  {
538
5.52k
    m_FirstLine = new SipRequestFirstLine(this);
539
5.52k
    m_FieldsOffset = m_FirstLine->getSize();
540
5.52k
    parseFields();
541
5.52k
  }
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
5.52k
  {
569
5.52k
    delete m_FirstLine;
570
5.52k
  }
571
572
  std::string SipRequestLayer::toString() const
573
2.17k
  {
574
2.17k
    static const int maxLengthToPrint = 120;
575
2.17k
    std::string result = "SIP request, ";
576
2.17k
    int size = m_FirstLine->getSize() - 2;  // the -2 is to remove \r\n at the end of the first line
577
2.17k
    if (size <= 0)
578
0
    {
579
0
      result += std::string("CORRUPT DATA");
580
0
      return result;
581
0
    }
582
2.17k
    if (size <= maxLengthToPrint)
583
2.07k
    {
584
2.07k
      char* firstLine = new char[size + 1];
585
2.07k
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), size);
586
2.07k
      firstLine[size] = 0;
587
2.07k
      result += std::string(firstLine);
588
2.07k
      delete[] firstLine;
589
2.07k
    }
590
104
    else
591
104
    {
592
104
      char firstLine[maxLengthToPrint + 1];
593
104
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3);
594
104
      firstLine[maxLengthToPrint - 3] = '.';
595
104
      firstLine[maxLengthToPrint - 2] = '.';
596
104
      firstLine[maxLengthToPrint - 1] = '.';
597
104
      firstLine[maxLengthToPrint] = 0;
598
104
      result += std::string(firstLine);
599
104
    }
600
601
2.17k
    return result;
602
2.17k
  }
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
12.5k
    {
698
12.5k
      if (data == nullptr || dataLen < 3)
699
0
      {
700
0
        return SipResponseLayer::SipStatusCodeUnknown;
701
0
      }
702
703
12.5k
      uint16_t code = 0;
704
12.5k
      code += (static_cast<uint16_t>(data[0]) - '0') * 100;
705
12.5k
      code += (static_cast<uint16_t>(data[1]) - '0') * 10;
706
12.5k
      code += (static_cast<uint16_t>(data[2]) - '0');
707
708
12.5k
      switch (code)
709
12.5k
      {
710
      // 1xx: Informational
711
914
      case 100:
712
914
        return SipResponseLayer::SipResponseStatusCode::Sip100Trying;
713
2.00k
      case 180:
714
2.00k
        return SipResponseLayer::SipResponseStatusCode::Sip180Ringing;
715
5
      case 181:
716
5
        return SipResponseLayer::SipResponseStatusCode::Sip181CallisBeingForwarded;
717
0
      case 182:
718
0
        return SipResponseLayer::SipResponseStatusCode::Sip182Queued;
719
0
      case 183:
720
0
        return SipResponseLayer::SipResponseStatusCode::Sip183SessioninProgress;
721
104
      case 199:
722
104
        return SipResponseLayer::SipResponseStatusCode::Sip199EarlyDialogTerminated;
723
      // 2xx: Success
724
8.31k
      case 200:
725
8.31k
        return SipResponseLayer::SipResponseStatusCode::Sip200OK;
726
0
      case 202:
727
0
        return SipResponseLayer::SipResponseStatusCode::Sip202Accepted;
728
0
      case 204:
729
0
        return SipResponseLayer::SipResponseStatusCode::Sip204NoNotification;
730
      // 3xx: Redirection
731
0
      case 300:
732
0
        return SipResponseLayer::SipResponseStatusCode::Sip300MultipleChoices;
733
0
      case 301:
734
0
        return SipResponseLayer::SipResponseStatusCode::Sip301MovedPermanently;
735
0
      case 302:
736
0
        return SipResponseLayer::SipResponseStatusCode::Sip302MovedTemporarily;
737
0
      case 305:
738
0
        return SipResponseLayer::SipResponseStatusCode::Sip305UseProxy;
739
5
      case 380:
740
5
        return SipResponseLayer::SipResponseStatusCode::Sip380AlternativeService;
741
      // 4xx: Client Failure
742
0
      case 400:
743
0
        return SipResponseLayer::SipResponseStatusCode::Sip400BadRequest;
744
612
      case 401:
745
612
        return SipResponseLayer::SipResponseStatusCode::Sip401Unauthorized;
746
80
      case 402:
747
80
        return SipResponseLayer::SipResponseStatusCode::Sip402PaymentRequired;
748
115
      case 403:
749
115
        return SipResponseLayer::SipResponseStatusCode::Sip403Forbidden;
750
0
      case 404:
751
0
        return SipResponseLayer::SipResponseStatusCode::Sip404NotFound;
752
0
      case 405:
753
0
        return SipResponseLayer::SipResponseStatusCode::Sip405MethodNotAllowed;
754
0
      case 406:
755
0
        return SipResponseLayer::SipResponseStatusCode::Sip406NotAcceptable;
756
80
      case 407:
757
80
        return SipResponseLayer::SipResponseStatusCode::Sip407ProxyAuthenticationRequired;
758
186
      case 408:
759
186
        return SipResponseLayer::SipResponseStatusCode::Sip408RequestTimeout;
760
0
      case 409:
761
0
        return SipResponseLayer::SipResponseStatusCode::Sip409Conflict;
762
0
      case 410:
763
0
        return SipResponseLayer::SipResponseStatusCode::Sip410Gone;
764
0
      case 411:
765
0
        return SipResponseLayer::SipResponseStatusCode::Sip411LengthRequired;
766
0
      case 412:
767
0
        return SipResponseLayer::SipResponseStatusCode::Sip412ConditionalRequestFailed;
768
0
      case 413:
769
0
        return SipResponseLayer::SipResponseStatusCode::Sip413RequestEntityTooLarge;
770
0
      case 414:
771
0
        return SipResponseLayer::SipResponseStatusCode::Sip414RequestURITooLong;
772
0
      case 415:
773
0
        return SipResponseLayer::SipResponseStatusCode::Sip415UnsupportedMediaType;
774
0
      case 416:
775
0
        return SipResponseLayer::SipResponseStatusCode::Sip416UnsupportedURIScheme;
776
0
      case 417:
777
0
        return SipResponseLayer::SipResponseStatusCode::Sip417UnknownResourcePriority;
778
0
      case 420:
779
0
        return SipResponseLayer::SipResponseStatusCode::Sip420BadExtension;
780
0
      case 421:
781
0
        return SipResponseLayer::SipResponseStatusCode::Sip421ExtensionRequired;
782
0
      case 422:
783
0
        return SipResponseLayer::SipResponseStatusCode::Sip422SessionIntervalTooSmall;
784
0
      case 423:
785
0
        return SipResponseLayer::SipResponseStatusCode::Sip423IntervalTooBrief;
786
0
      case 424:
787
0
        return SipResponseLayer::SipResponseStatusCode::Sip424BadLocationInformation;
788
0
      case 425:
789
0
        return SipResponseLayer::SipResponseStatusCode::Sip425BadAlertMessage;
790
0
      case 428:
791
0
        return SipResponseLayer::SipResponseStatusCode::Sip428UseIdentityHeader;
792
0
      case 429:
793
0
        return SipResponseLayer::SipResponseStatusCode::Sip429ProvideReferrerIdentity;
794
0
      case 430:
795
0
        return SipResponseLayer::SipResponseStatusCode::Sip430FlowFailed;
796
0
      case 433:
797
0
        return SipResponseLayer::SipResponseStatusCode::Sip433AnonymityDisallowed;
798
0
      case 436:
799
0
        return SipResponseLayer::SipResponseStatusCode::Sip436BadIdentityInfo;
800
0
      case 437:
801
0
        return SipResponseLayer::SipResponseStatusCode::Sip437UnsupportedCertificate;
802
0
      case 438:
803
0
        return SipResponseLayer::SipResponseStatusCode::Sip438InvalidIdentityHeader;
804
0
      case 439:
805
0
        return SipResponseLayer::SipResponseStatusCode::Sip439FirstHopLacksOutboundSupport;
806
0
      case 440:
807
0
        return SipResponseLayer::SipResponseStatusCode::Sip440MaxBreadthExceeded;
808
0
      case 469:
809
0
        return SipResponseLayer::SipResponseStatusCode::Sip469BadInfoPackage;
810
0
      case 470:
811
0
        return SipResponseLayer::SipResponseStatusCode::Sip470ConsentNeeded;
812
0
      case 480:
813
0
        return SipResponseLayer::SipResponseStatusCode::Sip480TemporarilyUnavailable;
814
0
      case 481:
815
0
        return SipResponseLayer::SipResponseStatusCode::Sip481Call_TransactionDoesNotExist;
816
0
      case 482:
817
0
        return SipResponseLayer::SipResponseStatusCode::Sip482LoopDetected;
818
0
      case 483:
819
0
        return SipResponseLayer::SipResponseStatusCode::Sip483TooManyHops;
820
0
      case 484:
821
0
        return SipResponseLayer::SipResponseStatusCode::Sip484AddressIncomplete;
822
0
      case 485:
823
0
        return SipResponseLayer::SipResponseStatusCode::Sip485Ambiguous;
824
0
      case 486:
825
0
        return SipResponseLayer::SipResponseStatusCode::Sip486BusyHere;
826
0
      case 487:
827
0
        return SipResponseLayer::SipResponseStatusCode::Sip487RequestTerminated;
828
0
      case 488:
829
0
        return SipResponseLayer::SipResponseStatusCode::Sip488NotAcceptableHere;
830
0
      case 489:
831
0
        return SipResponseLayer::SipResponseStatusCode::Sip489BadEvent;
832
0
      case 491:
833
0
        return SipResponseLayer::SipResponseStatusCode::Sip491RequestPending;
834
0
      case 493:
835
0
        return SipResponseLayer::SipResponseStatusCode::Sip493Undecipherable;
836
0
      case 494:
837
0
        return SipResponseLayer::SipResponseStatusCode::Sip494SecurityAgreementRequired;
838
      // 5xx: Server Failure
839
0
      case 500:
840
0
        return SipResponseLayer::SipResponseStatusCode::Sip500ServerInternalError;
841
60
      case 501:
842
60
        return SipResponseLayer::SipResponseStatusCode::Sip501NotImplemented;
843
0
      case 502:
844
0
        return SipResponseLayer::SipResponseStatusCode::Sip502BadGateway;
845
0
      case 503:
846
0
        return SipResponseLayer::SipResponseStatusCode::Sip503ServiceUnavailable;
847
0
      case 504:
848
0
        return SipResponseLayer::SipResponseStatusCode::Sip504ServerTimeout;
849
0
      case 505:
850
0
        return SipResponseLayer::SipResponseStatusCode::Sip505VersionNotSupported;
851
0
      case 513:
852
0
        return SipResponseLayer::SipResponseStatusCode::Sip513MessageTooLarge;
853
0
      case 555:
854
0
        return SipResponseLayer::SipResponseStatusCode::Sip555PushNotificationServiceNotSupported;
855
15
      case 580:
856
15
        return SipResponseLayer::SipResponseStatusCode::Sip580PreconditionFailure;
857
      // 6xx: Global Failure
858
0
      case 600:
859
0
        return SipResponseLayer::SipResponseStatusCode::Sip600BusyEverywhere;
860
0
      case 603:
861
0
        return SipResponseLayer::SipResponseStatusCode::Sip603Decline;
862
0
      case 604:
863
0
        return SipResponseLayer::SipResponseStatusCode::Sip604DoesNotExistAnywhere;
864
0
      case 606:
865
0
        return SipResponseLayer::SipResponseStatusCode::Sip606NotAcceptable;
866
0
      case 607:
867
0
        return SipResponseLayer::SipResponseStatusCode::Sip607Unwanted;
868
0
      case 608:
869
0
        return SipResponseLayer::SipResponseStatusCode::Sip608Rejected;
870
90
      default:
871
90
        return SipResponseLayer::SipStatusCodeUnknown;
872
12.5k
      }
873
12.5k
    }
874
  }  // namespace
875
876
  SipResponseLayer::SipResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
877
7.24k
      : SipLayer(data, dataLen, prevLayer, packet, SIPResponse)
878
7.24k
  {
879
7.24k
    m_FirstLine = new SipResponseFirstLine(this);
880
7.24k
    m_FieldsOffset = m_FirstLine->getSize();
881
7.24k
    parseFields();
882
7.24k
  }
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
7.24k
  {
894
7.24k
    delete m_FirstLine;
895
7.24k
  }
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
2.44k
  {
916
2.44k
    static const int maxLengthToPrint = 120;
917
2.44k
    std::string result = "SIP response, ";
918
2.44k
    int size = m_FirstLine->getSize() - 2;  // the -2 is to remove \r\n at the end of the first line
919
2.44k
    if (size <= 0)
920
0
    {
921
0
      result += std::string("CORRUPT DATA");
922
0
      return result;
923
0
    }
924
2.44k
    if (size <= maxLengthToPrint)
925
2.44k
    {
926
2.44k
      char* firstLine = new char[size + 1];
927
2.44k
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), size);
928
2.44k
      firstLine[size] = 0;
929
2.44k
      result += std::string(firstLine);
930
2.44k
      delete[] firstLine;
931
2.44k
    }
932
2
    else
933
2
    {
934
2
      char firstLine[maxLengthToPrint + 1];
935
2
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3);
936
2
      firstLine[maxLengthToPrint - 3] = '.';
937
2
      firstLine[maxLengthToPrint - 2] = '.';
938
2
      firstLine[maxLengthToPrint - 1] = '.';
939
2
      firstLine[maxLengthToPrint] = 0;
940
2
      result += std::string(firstLine);
941
2
    }
942
943
2.44k
    return result;
944
2.44k
  }
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
13.7k
  {
1043
    // minimum data should be 12B long: "SIP/x.y XXX "
1044
13.7k
    if (!data || dataLen < 12)
1045
771
    {
1046
771
      return SipResponseLayer::SipStatusCodeUnknown;
1047
771
    }
1048
1049
12.9k
    const char* statusCodeData = data + 8;
1050
12.9k
    if (statusCodeData[3] != ' ')
1051
826
    {
1052
826
      return SipResponseLayer::SipStatusCodeUnknown;
1053
826
    }
1054
1055
12.1k
    return parseStatusCodePure(statusCodeData, 3);
1056
12.9k
  }
1057
1058
7.24k
  SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse) : m_SipResponse(sipResponse)
1059
7.24k
  {
1060
7.24k
    m_Version = parseVersion(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen());
1061
7.24k
    if (m_Version == "")
1062
1.86k
    {
1063
1.86k
      m_StatusCode = SipResponseLayer::SipStatusCodeUnknown;
1064
1.86k
    }
1065
5.38k
    else
1066
5.38k
    {
1067
5.38k
      m_StatusCode = parseStatusCode(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen());
1068
5.38k
    }
1069
1070
7.24k
    char* endOfFirstLine;
1071
7.24k
    if ((endOfFirstLine = static_cast<char*>(
1072
7.24k
             memchr(reinterpret_cast<char*>(m_SipResponse->m_Data), '\n', m_SipResponse->m_DataLen))) != nullptr)
1073
5.38k
    {
1074
5.38k
      m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipResponse->m_Data) + 1;
1075
5.38k
      m_IsComplete = true;
1076
5.38k
    }
1077
1.86k
    else
1078
1.86k
    {
1079
1.86k
      m_FirstLineEndOffset = m_SipResponse->getDataLen();
1080
1.86k
      m_IsComplete = false;
1081
1.86k
    }
1082
1083
7.24k
    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
7.24k
  }
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
12.2k
  {
1130
12.2k
    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
12.2k
    if (data[0] != 'S' || data[1] != 'I' || data[2] != 'P' || data[3] != '/')
1137
1.91k
    {
1138
1.91k
      PCPP_LOG_DEBUG("SIP response does not begin with 'SIP/'");
1139
1.91k
      return "";
1140
1.91k
    }
1141
1142
10.3k
    const char* nextSpace = static_cast<const char*>(memchr(data, ' ', dataLen));
1143
10.3k
    if (nextSpace == nullptr)
1144
0
      return "";
1145
1146
10.3k
    return std::string(data, nextSpace - data);
1147
10.3k
  }
1148
1149
  std::pair<bool, SipResponseFirstLine::FirstLineData> SipResponseFirstLine::parseFirstLine(const char* data,
1150
                                                                                            size_t dataLen)
1151
462
  {
1152
462
    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
462
    if (data == nullptr || dataLen < 12)
1156
0
    {
1157
0
      PCPP_LOG_DEBUG("SIP response length < 12, cannot parse first line");
1158
0
      return result;
1159
0
    }
1160
1161
462
    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
462
    const auto dataEndIt = data + dataLen;
1168
    // Find first space (end of version)
1169
462
    auto firstSpaceIt = std::find(data + 4, dataEndIt, ' ');
1170
462
    if (firstSpaceIt == dataEndIt)
1171
0
    {
1172
0
      PCPP_LOG_DEBUG("No space after version in SIP response line");
1173
0
      return result;
1174
0
    }
1175
1176
    // Status code is strictly 3 characters followed by a space
1177
462
    auto statusCodeIt = firstSpaceIt + 1;
1178
462
    auto statusCodeEndIt = statusCodeIt + 3;
1179
462
    if (*statusCodeEndIt != ' ')
1180
0
    {
1181
0
      PCPP_LOG_DEBUG("No space after status code in SIP response line");
1182
0
      return result;
1183
0
    }
1184
1185
462
    auto statusCode = parseStatusCodePure(statusCodeIt, 3);
1186
462
    if (statusCode == SipResponseLayer::SipStatusCodeUnknown)
1187
15
    {
1188
15
      PCPP_LOG_DEBUG("Unknown SIP status code");
1189
15
      return result;
1190
15
    }
1191
1192
    // Write parsed values to result
1193
447
    result.first = true;
1194
447
    result.second.version = std::string(data, firstSpaceIt);
1195
447
    result.second.statusCode = statusCode;
1196
447
    return result;
1197
462
  }
1198
1199
}  // namespace pcpp