Coverage Report

Created: 2026-06-10 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/SipLayer.cpp
Line
Count
Source
1
3.43k
#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
42.6k
    {
21
42.6k
      return ((len > 0 ? static_cast<uint32_t>(data[0]) << 24 : 0) |
22
42.6k
              (len > 1 ? static_cast<uint32_t>(data[1]) << 16 : 0) |
23
42.6k
              (len > 2 ? static_cast<uint32_t>(data[2]) << 8 : 0) |
24
42.6k
              (len > 3 ? static_cast<uint32_t>(data[3]) : 0));
25
42.6k
    }
26
27
    constexpr uint32_t operator""_packed4(const char* str, size_t len)
28
139
    {
29
139
      return pack4(str, len);
30
139
    }
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
67.8k
  {
59
67.8k
    std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD);
60
67.8k
    std::transform(contentLengthFieldName.begin(), contentLengthFieldName.end(), contentLengthFieldName.begin(),
61
67.8k
                   ::tolower);
62
67.8k
    HeaderField* contentLengthField = getFieldByName(contentLengthFieldName);
63
67.8k
    if (contentLengthField != nullptr)
64
65.2k
      return atoi(contentLengthField->getFieldValue().c_str());
65
2.64k
    return 0;
66
67.8k
  }
67
68
  HeaderField* SipLayer::setContentLength(int contentLength, const std::string& prevFieldName)
69
4.66k
  {
70
4.66k
    std::ostringstream contentLengthAsString;
71
4.66k
    contentLengthAsString << contentLength;
72
4.66k
    std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD);
73
4.66k
    HeaderField* contentLengthField = getFieldByName(contentLengthFieldName);
74
4.66k
    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
4.66k
    else
80
4.66k
      contentLengthField->setFieldValue(contentLengthAsString.str());
81
82
4.66k
    return contentLengthField;
83
4.66k
  }
84
85
  void SipLayer::parseNextLayer()
86
72.4k
  {
87
72.4k
    if (getLayerPayloadSize() == 0)
88
9.86k
      return;
89
90
62.6k
    size_t headerLen = getHeaderLen();
91
62.6k
    std::string contentType;
92
62.6k
    if (getContentLength() > 0)
93
49.9k
    {
94
49.9k
      HeaderField* contentTypeField = getFieldByName(PCPP_SIP_CONTENT_TYPE_FIELD);
95
49.9k
      if (contentTypeField != nullptr)
96
47.4k
        contentType = contentTypeField->getFieldValue();
97
49.9k
    }
98
99
62.6k
    auto payload = m_Data + headerLen;
100
62.6k
    auto payloadLen = m_DataLen - headerLen;
101
102
62.6k
    if (contentType.find("application/sdp") != std::string::npos)
103
46.8k
    {
104
46.8k
      constructNextLayer<SdpLayer>(payload, payloadLen);
105
46.8k
    }
106
15.7k
    else
107
15.7k
    {
108
15.7k
      constructNextLayer<PayloadLayer>(payload, payloadLen);
109
15.7k
    }
110
62.6k
  }
111
112
  void SipLayer::computeCalculateFields()
113
6.76k
  {
114
6.76k
    HeaderField* contentLengthField = getFieldByName(PCPP_SIP_CONTENT_LENGTH_FIELD);
115
6.76k
    if (contentLengthField == nullptr)
116
1.03k
      return;
117
118
5.73k
    size_t headerLen = getHeaderLen();
119
5.73k
    if (m_DataLen > headerLen)
120
5.23k
    {
121
5.23k
      int currentContentLength = getContentLength();
122
5.23k
      if (currentContentLength != static_cast<int>(m_DataLen - headerLen))
123
4.66k
        setContentLength(m_DataLen - headerLen);
124
5.23k
    }
125
5.73k
  }
126
127
  SipLayer::SipParseResult SipLayer::detectSipMessageType(const uint8_t* data, size_t dataLen)
128
42.9k
  {
129
42.9k
    if (!data || dataLen < 3)
130
581
    {
131
581
      return SipLayer::SipParseResult::Unknown;
132
581
    }
133
134
42.3k
    uint32_t key = pack4(reinterpret_cast<const char*>(data), dataLen);
135
136
42.3k
    switch (key)
137
42.3k
    {
138
104
    case "INVI"_packed4:  // INVITE
139
131
    case "ACK "_packed4:  // ACK
140
131
    case "BYE "_packed4:  // BYE
141
131
    case "CANC"_packed4:  // CANCEL
142
131
    case "REGI"_packed4:  // REGISTER
143
131
    case "PRAC"_packed4:  // PRACK
144
924
    case "OPTI"_packed4:  // OPTIONS
145
924
    case "SUBS"_packed4:  // SUBSCRIBE
146
1.77k
    case "NOTI"_packed4:  // NOTIFY
147
1.77k
    case "PUBL"_packed4:  // PUBLISH
148
1.77k
    case "INFO"_packed4:  // INFO
149
1.77k
    case "REFE"_packed4:  // REFER
150
1.77k
    case "MESS"_packed4:  // MESSAGE
151
1.77k
    case "UPDA"_packed4:  // UPDATE
152
1.77k
      return SipLayer::SipParseResult::Request;
153
154
139
    case "SIP/"_packed4:
155
139
      return SipLayer::SipParseResult::Response;
156
157
40.4k
    default:
158
40.4k
      return SipLayer::SipParseResult::Unknown;
159
42.3k
    }
160
42.3k
  }
161
162
  SipLayer* SipLayer::parseSipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, uint16_t srcPort,
163
                                    uint16_t dstPort)
164
76.2k
  {
165
76.2k
    if (!(SipLayer::isSipPort(srcPort) || SipLayer::isSipPort(dstPort)))
166
0
    {
167
0
      return nullptr;
168
0
    }
169
170
76.2k
    if (SipRequestFirstLine::parseMethod(reinterpret_cast<char*>(data), dataLen) !=
171
76.2k
        SipRequestLayer::SipMethodUnknown)
172
64.4k
    {
173
64.4k
      return new SipRequestLayer(data, dataLen, prevLayer, packet);
174
64.4k
    }
175
176
11.7k
    if (SipResponseFirstLine::parseStatusCode(reinterpret_cast<char*>(data), dataLen) !=
177
11.7k
            SipResponseLayer::SipStatusCodeUnknown &&
178
9.53k
        !SipResponseFirstLine::parseVersion(reinterpret_cast<char*>(data), dataLen).empty())
179
7.69k
    {
180
7.69k
      return new SipResponseLayer(data, dataLen, prevLayer, packet);
181
7.69k
    }
182
183
4.08k
    return nullptr;
184
11.7k
  }
185
186
  SipLayer* SipLayer::parseSipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
187
42.9k
  {
188
42.9k
    SipLayer::SipParseResult sipParseResult = detectSipMessageType(data, dataLen);
189
190
42.9k
    if (sipParseResult == SipLayer::SipParseResult::Unknown)
191
41.0k
    {
192
41.0k
      return nullptr;
193
41.0k
    }
194
195
1.91k
    if (sipParseResult == SipLayer::SipParseResult::Request)
196
1.77k
    {
197
1.77k
      if (SipRequestFirstLine::parseFirstLine(reinterpret_cast<char*>(data), dataLen).first)
198
266
      {
199
266
        return new SipRequestLayer(data, dataLen, prevLayer, packet);
200
266
      }
201
1.50k
      return nullptr;
202
1.77k
    }
203
204
139
    if (SipResponseFirstLine::parseFirstLine(reinterpret_cast<char*>(data), dataLen).first)
205
55
    {
206
55
      return new SipResponseLayer(data, dataLen, prevLayer, packet);
207
55
    }
208
84
    return nullptr;
209
139
  }
210
211
  // -------- Class SipRequestFirstLine -----------------
212
213
64.7k
  SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest) : m_SipRequest(sipRequest)
214
64.7k
  {
215
64.7k
    m_Method = parseMethod(reinterpret_cast<char*>(m_SipRequest->m_Data), m_SipRequest->getDataLen());
216
64.7k
    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
64.7k
    else
222
64.7k
      m_UriOffset = SipMethodEnumToString[m_Method].length() + 1;
223
224
64.7k
    parseVersion();
225
226
64.7k
    char* endOfFirstLine;
227
64.7k
    if ((endOfFirstLine =
228
64.7k
             static_cast<char*>(memchr(reinterpret_cast<char*>(m_SipRequest->m_Data + m_VersionOffset), '\n',
229
64.7k
                                       m_SipRequest->m_DataLen - static_cast<size_t>(m_VersionOffset)))) != nullptr)
230
64.6k
    {
231
64.6k
      m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipRequest->m_Data) + 1;
232
64.6k
      m_IsComplete = true;
233
64.6k
    }
234
82
    else
235
82
    {
236
82
      m_FirstLineEndOffset = m_SipRequest->getDataLen();
237
82
      m_IsComplete = false;
238
82
    }
239
240
64.7k
    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
64.7k
  }
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
140k
  {
292
140k
    if (!data || dataLen < 4)
293
16
    {
294
16
      return SipRequestLayer::SipMethodUnknown;
295
16
    }
296
297
140k
    size_t spaceIndex = 0;
298
1.17M
    while (spaceIndex < dataLen && data[spaceIndex] != ' ')
299
1.03M
    {
300
1.03M
      spaceIndex++;
301
1.03M
    }
302
303
140k
    if (spaceIndex == 0 || spaceIndex == dataLen)
304
150
    {
305
150
      return SipRequestLayer::SipMethodUnknown;
306
150
    }
307
308
140k
    auto methodAdEnum = SipMethodStringToEnum.find(std::string(data, data + spaceIndex));
309
140k
    if (methodAdEnum == SipMethodStringToEnum.end())
310
11.6k
    {
311
11.6k
      return SipRequestLayer::SipMethodUnknown;
312
11.6k
    }
313
129k
    return methodAdEnum->second;
314
140k
  }
315
316
  std::pair<bool, SipRequestFirstLine::SipFirstLineData> SipRequestFirstLine::parseFirstLine(const char* data,
317
                                                                                             size_t dataLen)
318
1.77k
  {
319
1.77k
    SipFirstLineData result = { "", "", "" };
320
321
1.77k
    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
1.77k
    size_t firstSpaceIndex = 0;
329
15.2k
    while (firstSpaceIndex < dataLen && data[firstSpaceIndex] != ' ')
330
13.4k
    {
331
13.4k
      firstSpaceIndex++;
332
13.4k
    }
333
334
1.77k
    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
1.77k
    std::string methodStr{ data, firstSpaceIndex };
342
1.77k
    if (SipMethodStringToEnum.find(methodStr) == SipMethodStringToEnum.end())
343
126
    {
344
126
      PCPP_LOG_DEBUG("Unknown SIP method");
345
126
      return { false, result };
346
126
    }
347
348
    // Find second space (end of URI)
349
1.64k
    size_t secondSpaceIndex = firstSpaceIndex + 1;
350
33.8k
    while (secondSpaceIndex < dataLen && data[secondSpaceIndex] != ' ')
351
32.2k
      secondSpaceIndex++;
352
353
1.64k
    if (secondSpaceIndex == dataLen)
354
0
    {
355
0
      PCPP_LOG_DEBUG("No space before version");
356
0
      return { false, result };
357
0
    }
358
359
1.64k
    size_t uriLen = secondSpaceIndex - firstSpaceIndex - 1;
360
1.64k
    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
1.64k
    size_t lineEnd = secondSpaceIndex + 1;
368
27.3k
    while (lineEnd < dataLen && data[lineEnd] != '\r' && data[lineEnd] != '\n')
369
25.7k
      lineEnd++;
370
371
    // Minimum length for "SIP/x.y"
372
1.64k
    size_t versionLen = lineEnd - secondSpaceIndex - 1;
373
1.64k
    if (versionLen < 7)
374
110
    {
375
110
      PCPP_LOG_DEBUG("Version too short");
376
110
      return { false, result };
377
110
    }
378
379
1.53k
    const char* versionStart = data + secondSpaceIndex + 1;
380
1.53k
    if (versionStart[0] != 'S' || versionStart[1] != 'I' || versionStart[2] != 'P' || versionStart[3] != '/')
381
1.27k
    {
382
1.27k
      PCPP_LOG_DEBUG("Invalid SIP version format");
383
1.27k
      return { false, result };
384
1.27k
    }
385
386
    // All validations passed
387
266
    result.method = std::move(methodStr);
388
266
    result.uri = std::string{ data + firstSpaceIndex + 1, uriLen };
389
266
    result.version = std::string{ versionStart, versionLen };
390
391
266
    return { true, result };
392
1.53k
  }
393
394
  void SipRequestFirstLine::parseVersion()
395
64.7k
  {
396
64.7k
    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
64.7k
    char* data = reinterpret_cast<char*>(m_SipRequest->m_Data + m_UriOffset);
404
64.7k
    char* verPos = cross_platform_memmem(data, m_SipRequest->getDataLen() - m_UriOffset, " SIP/", 5);
405
64.7k
    if (verPos == nullptr)
406
27.4k
    {
407
27.4k
      m_Version = "";
408
27.4k
      m_VersionOffset = -1;
409
27.4k
      return;
410
27.4k
    }
411
412
    // verify packet doesn't end before the version, meaning still left place for " SIP/x.y" (7 chars)
413
37.3k
    if (static_cast<uint16_t>(verPos + 7 - reinterpret_cast<char*>(m_SipRequest->m_Data)) >
414
37.3k
        m_SipRequest->getDataLen())
415
0
    {
416
0
      m_Version = "";
417
0
      m_VersionOffset = -1;
418
0
      return;
419
0
    }
420
421
    // skip the space char
422
37.3k
    verPos++;
423
424
37.3k
    int endOfVerPos = 0;
425
845k
    while (((verPos + endOfVerPos) < reinterpret_cast<char*>(m_SipRequest->m_Data + m_SipRequest->m_DataLen)) &&
426
845k
           ((verPos + endOfVerPos)[0] != '\r') && ((verPos + endOfVerPos)[0] != '\n'))
427
808k
      endOfVerPos++;
428
429
37.3k
    m_Version = std::string(verPos, endOfVerPos);
430
431
37.3k
    m_VersionOffset = verPos - reinterpret_cast<char*>(m_SipRequest->m_Data);
432
37.3k
  }
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
64.7k
      : SipLayer(data, dataLen, prevLayer, packet, SIPRequest)
537
64.7k
  {
538
64.7k
    m_FirstLine = new SipRequestFirstLine(this);
539
64.7k
    m_FieldsOffset = m_FirstLine->getSize();
540
64.7k
    parseFields();
541
64.7k
  }
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
64.7k
  {
569
64.7k
    delete m_FirstLine;
570
64.7k
  }
571
572
  std::string SipRequestLayer::toString() const
573
11.3k
  {
574
11.3k
    static const int maxLengthToPrint = 120;
575
11.3k
    std::string result = "SIP request, ";
576
11.3k
    int size = m_FirstLine->getSize() - 2;  // the -2 is to remove \r\n at the end of the first line
577
11.3k
    if (size <= 0)
578
16
    {
579
16
      result += std::string("CORRUPT DATA");
580
16
      return result;
581
16
    }
582
11.3k
    if (size <= maxLengthToPrint)
583
10.5k
    {
584
10.5k
      char* firstLine = new char[size + 1];
585
10.5k
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), size);
586
10.5k
      firstLine[size] = 0;
587
10.5k
      result += std::string(firstLine);
588
10.5k
      delete[] firstLine;
589
10.5k
    }
590
780
    else
591
780
    {
592
780
      char firstLine[maxLengthToPrint + 1];
593
780
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3);
594
780
      firstLine[maxLengthToPrint - 3] = '.';
595
780
      firstLine[maxLengthToPrint - 2] = '.';
596
780
      firstLine[maxLengthToPrint - 1] = '.';
597
780
      firstLine[maxLengthToPrint] = 0;
598
780
      result += std::string(firstLine);
599
780
    }
600
601
11.3k
    return result;
602
11.3k
  }
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
17.6k
    {
698
17.6k
      if (data == nullptr || dataLen < 3)
699
0
      {
700
0
        return SipResponseLayer::SipStatusCodeUnknown;
701
0
      }
702
703
17.6k
      uint16_t code = 0;
704
17.6k
      code += (static_cast<uint16_t>(data[0]) - '0') * 100;
705
17.6k
      code += (static_cast<uint16_t>(data[1]) - '0') * 10;
706
17.6k
      code += (static_cast<uint16_t>(data[2]) - '0');
707
708
17.6k
      switch (code)
709
17.6k
      {
710
      // 1xx: Informational
711
12.6k
      case 100:
712
12.6k
        return SipResponseLayer::SipResponseStatusCode::Sip100Trying;
713
2.03k
      case 180:
714
2.03k
        return SipResponseLayer::SipResponseStatusCode::Sip180Ringing;
715
18
      case 181:
716
18
        return SipResponseLayer::SipResponseStatusCode::Sip181CallisBeingForwarded;
717
18
      case 182:
718
18
        return SipResponseLayer::SipResponseStatusCode::Sip182Queued;
719
0
      case 183:
720
0
        return SipResponseLayer::SipResponseStatusCode::Sip183SessioninProgress;
721
0
      case 199:
722
0
        return SipResponseLayer::SipResponseStatusCode::Sip199EarlyDialogTerminated;
723
      // 2xx: Success
724
2.20k
      case 200:
725
2.20k
        return SipResponseLayer::SipResponseStatusCode::Sip200OK;
726
0
      case 202:
727
0
        return SipResponseLayer::SipResponseStatusCode::Sip202Accepted;
728
6
      case 204:
729
6
        return SipResponseLayer::SipResponseStatusCode::Sip204NoNotification;
730
      // 3xx: Redirection
731
36
      case 300:
732
36
        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
0
      case 380:
740
0
        return SipResponseLayer::SipResponseStatusCode::Sip380AlternativeService;
741
      // 4xx: Client Failure
742
0
      case 400:
743
0
        return SipResponseLayer::SipResponseStatusCode::Sip400BadRequest;
744
0
      case 401:
745
0
        return SipResponseLayer::SipResponseStatusCode::Sip401Unauthorized;
746
0
      case 402:
747
0
        return SipResponseLayer::SipResponseStatusCode::Sip402PaymentRequired;
748
0
      case 403:
749
0
        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
0
      case 407:
757
0
        return SipResponseLayer::SipResponseStatusCode::Sip407ProxyAuthenticationRequired;
758
0
      case 408:
759
0
        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
360
      case 487:
827
360
        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
0
      case 501:
842
0
        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
0
      case 580:
856
0
        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
329
      default:
871
329
        return SipResponseLayer::SipStatusCodeUnknown;
872
17.6k
      }
873
17.6k
    }
874
  }  // namespace
875
876
  SipResponseLayer::SipResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
877
7.74k
      : SipLayer(data, dataLen, prevLayer, packet, SIPResponse)
878
7.74k
  {
879
7.74k
    m_FirstLine = new SipResponseFirstLine(this);
880
7.74k
    m_FieldsOffset = m_FirstLine->getSize();
881
7.74k
    parseFields();
882
7.74k
  }
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.74k
  {
894
7.74k
    delete m_FirstLine;
895
7.74k
  }
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.20k
  {
916
2.20k
    static const int maxLengthToPrint = 120;
917
2.20k
    std::string result = "SIP response, ";
918
2.20k
    int size = m_FirstLine->getSize() - 2;  // the -2 is to remove \r\n at the end of the first line
919
2.20k
    if (size <= 0)
920
0
    {
921
0
      result += std::string("CORRUPT DATA");
922
0
      return result;
923
0
    }
924
2.20k
    if (size <= maxLengthToPrint)
925
1.75k
    {
926
1.75k
      char* firstLine = new char[size + 1];
927
1.75k
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), size);
928
1.75k
      firstLine[size] = 0;
929
1.75k
      result += std::string(firstLine);
930
1.75k
      delete[] firstLine;
931
1.75k
    }
932
452
    else
933
452
    {
934
452
      char firstLine[maxLengthToPrint + 1];
935
452
      strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3);
936
452
      firstLine[maxLengthToPrint - 3] = '.';
937
452
      firstLine[maxLengthToPrint - 2] = '.';
938
452
      firstLine[maxLengthToPrint - 1] = '.';
939
452
      firstLine[maxLengthToPrint] = 0;
940
452
      result += std::string(firstLine);
941
452
    }
942
943
2.20k
    return result;
944
2.20k
  }
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
19.5k
  {
1043
    // minimum data should be 12B long: "SIP/x.y XXX "
1044
19.5k
    if (!data || dataLen < 12)
1045
16
    {
1046
16
      return SipResponseLayer::SipStatusCodeUnknown;
1047
16
    }
1048
1049
19.5k
    const char* statusCodeData = data + 8;
1050
19.5k
    if (statusCodeData[3] != ' ')
1051
1.97k
    {
1052
1.97k
      return SipResponseLayer::SipStatusCodeUnknown;
1053
1.97k
    }
1054
1055
17.5k
    return parseStatusCodePure(statusCodeData, 3);
1056
19.5k
  }
1057
1058
7.74k
  SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse) : m_SipResponse(sipResponse)
1059
7.74k
  {
1060
7.74k
    m_Version = parseVersion(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen());
1061
7.74k
    if (m_Version == "")
1062
0
    {
1063
0
      m_StatusCode = SipResponseLayer::SipStatusCodeUnknown;
1064
0
    }
1065
7.74k
    else
1066
7.74k
    {
1067
7.74k
      m_StatusCode = parseStatusCode(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen());
1068
7.74k
    }
1069
1070
7.74k
    char* endOfFirstLine;
1071
7.74k
    if ((endOfFirstLine = static_cast<char*>(
1072
7.74k
             memchr(reinterpret_cast<char*>(m_SipResponse->m_Data), '\n', m_SipResponse->m_DataLen))) != nullptr)
1073
7.09k
    {
1074
7.09k
      m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipResponse->m_Data) + 1;
1075
7.09k
      m_IsComplete = true;
1076
7.09k
    }
1077
654
    else
1078
654
    {
1079
654
      m_FirstLineEndOffset = m_SipResponse->getDataLen();
1080
654
      m_IsComplete = false;
1081
654
    }
1082
1083
7.74k
    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.74k
  }
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
17.2k
  {
1130
17.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
17.2k
    if (data[0] != 'S' || data[1] != 'I' || data[2] != 'P' || data[3] != '/')
1137
1.84k
    {
1138
1.84k
      PCPP_LOG_DEBUG("SIP response does not begin with 'SIP/'");
1139
1.84k
      return "";
1140
1.84k
    }
1141
1142
15.4k
    const char* nextSpace = static_cast<const char*>(memchr(data, ' ', dataLen));
1143
15.4k
    if (nextSpace == nullptr)
1144
0
      return "";
1145
1146
15.4k
    return std::string(data, nextSpace - data);
1147
15.4k
  }
1148
1149
  std::pair<bool, SipResponseFirstLine::FirstLineData> SipResponseFirstLine::parseFirstLine(const char* data,
1150
                                                                                            size_t dataLen)
1151
139
  {
1152
139
    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
139
    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
139
    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
139
    const auto dataEndIt = data + dataLen;
1168
    // Find first space (end of version)
1169
139
    auto firstSpaceIt = std::find(data + 4, dataEndIt, ' ');
1170
139
    if (firstSpaceIt == dataEndIt)
1171
6
    {
1172
6
      PCPP_LOG_DEBUG("No space after version in SIP response line");
1173
6
      return result;
1174
6
    }
1175
1176
    // Status code is strictly 3 characters followed by a space
1177
133
    auto statusCodeIt = firstSpaceIt + 1;
1178
133
    auto statusCodeEndIt = statusCodeIt + 3;
1179
133
    if (*statusCodeEndIt != ' ')
1180
36
    {
1181
36
      PCPP_LOG_DEBUG("No space after status code in SIP response line");
1182
36
      return result;
1183
36
    }
1184
1185
97
    auto statusCode = parseStatusCodePure(statusCodeIt, 3);
1186
97
    if (statusCode == SipResponseLayer::SipStatusCodeUnknown)
1187
42
    {
1188
42
      PCPP_LOG_DEBUG("Unknown SIP status code");
1189
42
      return result;
1190
42
    }
1191
1192
    // Write parsed values to result
1193
55
    result.first = true;
1194
55
    result.second.version = std::string(data, firstSpaceIt);
1195
55
    result.second.statusCode = statusCode;
1196
55
    return result;
1197
97
  }
1198
1199
}  // namespace pcpp