Coverage Report

Created: 2026-07-16 07:15

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