Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/SipLayer.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "TextBasedProtocol.h"
4
5
/// @file
6
7
/// @namespace pcpp
8
/// @brief The main namespace for the PcapPlusPlus lib
9
namespace pcpp
10
{
11
// some popular SIP header fields
12
13
/// From field
14
#define PCPP_SIP_FROM_FIELD "From"
15
/// To field
16
#define PCPP_SIP_TO_FIELD "To"
17
/// Via field
18
#define PCPP_SIP_VIA_FIELD "Via"
19
/// Call-ID field
20
#define PCPP_SIP_CALL_ID_FIELD "Call-ID"
21
/// Content-Type field
22
10.3k
#define PCPP_SIP_CONTENT_TYPE_FIELD "Content-Type"
23
/// Content-Length field
24
19.7k
#define PCPP_SIP_CONTENT_LENGTH_FIELD "Content-Length"
25
/// Content-Disposition field
26
#define PCPP_SIP_CONTENT_DISPOSITION_FIELD "Content-Disposition"
27
/// Content-Encoding field
28
#define PCPP_SIP_CONTENT_ENCODING_FIELD "Content-Encoding"
29
/// Content-Language field
30
#define PCPP_SIP_CONTENT_LANGUAGE_FIELD "Content-Language"
31
/// CSeq field
32
#define PCPP_SIP_CSEQ_FIELD "CSeq"
33
/// Contact field
34
#define PCPP_SIP_CONTACT_FIELD "Contact"
35
/// Max-Forwards field
36
#define PCPP_SIP_MAX_FORWARDS_FIELD "Max-Forwards"
37
/// User-Agent field
38
#define PCPP_SIP_USER_AGENT_FIELD "User-Agent"
39
/// Accept field
40
#define PCPP_SIP_ACCEPT_FIELD "Accept"
41
/// Accept-Encoding field
42
#define PCPP_SIP_ACCEPT_ENCODING_FIELD "Accept-Encoding"
43
/// Accept-Language field
44
#define PCPP_SIP_ACCEPT_LANGUAGE_FIELD "Accept-Language"
45
/// Allow field
46
#define PCPP_SIP_ALLOW_FIELD "Allow"
47
/// Authorization field
48
#define PCPP_SIP_AUTHORIZATION_FIELD "Authorization"
49
/// Date field
50
#define PCPP_SIP_DATE_FIELD "Date"
51
/// MIME-Version field
52
#define PCPP_SIP_MIME_VERSION_FIELD "MIME-Version"
53
/// Reason field
54
#define PCPP_SIP_REASON_FIELD "Reason"
55
/// Supported field
56
#define PCPP_SIP_SUPPORTED_FIELD "Supported"
57
/// Server field
58
#define PCPP_SIP_SERVER_FIELD "Server"
59
/// WWW-Authenticate fild
60
#define PCPP_SIP_WWW_AUTHENTICATE_FIELD "WWW-Authenticate"
61
/// Retry-After field
62
#define PCPP_SIP_RETRY_AFTER_FIELD "Retry-After"
63
/// Record-Route field
64
#define PCPP_SIP_RECORD_ROUTE_FIELD "Record-Route"
65
66
  /// @class SipLayer
67
  /// Represents a general SIP message. It's an abstract class and cannot be instantiated. It's inherited by
68
  /// SipRequestLayer and SipResponseLayer
69
  class SipLayer : public TextBasedProtocolMessage
70
  {
71
  public:
72
    /// The length of the body of many SIP response messages is determined by a SIP header field called
73
    /// "Content-Length". This method parses this field, extracts its value and return it. If this field doesn't
74
    /// exist 0 is returned
75
    /// @return SIP response body length determined by "Content-Length" field
76
    int getContentLength() const;
77
78
    /// The length of the body of many SIP messages is determined by a header field called "Content-Length". This
79
    /// method sets The content-length field value. The method supports several cases:
80
    /// - If the "Content-Length" field exists - the method will only replace the existing value with the new value
81
    /// - If the "Content-Length" field doesn't exist - the method will create this field and put the value in it.
82
    /// Here are also 2 cases:
83
    ///   - If prevFieldName is specified - the new "Content-Length" field will be created after it
84
    ///   - If prevFieldName isn't specified or doesn't exist - the new "Content-Length" field will be created as
85
    ///   the
86
    /// last field before end-of-header field
87
    ///
88
    /// @param[in] contentLength The content length value to set
89
    /// @param[in] prevFieldName Optional parameter, if specified and "Content-Length" field doesn't exist, it will
90
    /// be created after this field
91
    /// @return A pointer to the "Content-Length" field, or nullptr if creation failed
92
    HeaderField* setContentLength(int contentLength, const std::string& prevFieldName = "");
93
94
    // Overridden methods
95
96
    OsiModelLayer getOsiModelLayer() const override
97
1.94k
    {
98
1.94k
      return OsiModelSesionLayer;
99
1.94k
    }
100
101
    /// Currently identifies only SDP if content-length field exists and set to a value greater than zero.
102
    /// If content-length field doesn't exist or set to zero and still there is data after this layer, a
103
    /// PayloadLayer will be created
104
    void parseNextLayer() override;
105
106
    /// Set the content-length only if a content-length field already exists and if its current value is different
107
    /// than the total length of the next layer(s)
108
    void computeCalculateFields() override;
109
110
    /// A static method that checks whether the port is considered as SIP
111
    /// @param[in] port The port number to be checked
112
    static bool isSipPort(uint16_t port)
113
321k
    {
114
321k
      return port == 5060 || port == 5061;
115
321k
    }
116
117
  protected:
118
    SipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol)
119
20.4k
        : TextBasedProtocolMessage(data, dataLen, prevLayer, packet, protocol)
120
20.4k
    {}
121
0
    SipLayer() : TextBasedProtocolMessage()
122
0
    {}
123
0
    SipLayer(const SipLayer& other) : TextBasedProtocolMessage(other)
124
0
    {}
125
    SipLayer& operator=(const SipLayer& other)
126
0
    {
127
0
      TextBasedProtocolMessage::operator=(other);
128
0
      return *this;
129
0
    }
130
131
    // implementation of abstract methods
132
    char getHeaderFieldNameValueSeparator() const override
133
20.4k
    {
134
20.4k
      return ':';
135
20.4k
    }
136
    bool spacesAllowedBetweenHeaderFieldNameAndValue() const override
137
20.4k
    {
138
20.4k
      return true;
139
20.4k
    }
140
  };
141
142
  class SipRequestFirstLine;
143
144
  /// @class SipRequestLayer
145
  /// Represents a SIP request header and inherits all basic functionality of SipLayer and TextBasedProtocolMessage.
146
  /// The functionality that is added for this class is the SIP first line concept. A SIP request has the following
147
  /// first line: <i>INVITE sip:bla@bla.com:12345 SIP/2.0</i> Since it's not an "ordinary" header field, it requires a
148
  /// special treatment and gets a class of it's own: SipRequestFirstLine. In most cases a SIP request will be
149
  /// contained in a single packet but for cases it is not, only the first packet will be identified as SIP request
150
  /// layer. You can find out whether the header is complete by using SipLayer#isHeaderComplete()
151
  class SipRequestLayer : public SipLayer
152
  {
153
    friend class SipRequestFirstLine;
154
155
  public:
156
    /// SIP request methods
157
    enum SipMethod
158
    {
159
      /// INVITE
160
      SipINVITE,
161
      /// ACK
162
      SipACK,
163
      /// BYE
164
      SipBYE,
165
      /// CANCEL
166
      SipCANCEL,
167
      /// REFISTER
168
      SipREGISTER,
169
      /// PRACK
170
      SipPRACK,
171
      /// OPTIONS
172
      SipOPTIONS,
173
      /// SUBSCRIBE
174
      SipSUBSCRIBE,
175
      /// NOTIFY
176
      SipNOTIFY,
177
      /// PUBLISH
178
      SipPUBLISH,
179
      /// INFO
180
      SipINFO,
181
      /// REFER
182
      SipREFER,
183
      /// MESSAGE
184
      SipMESSAGE,
185
      /// UPDATE
186
      SipUPDATE,
187
      /// Unknown SIP method
188
      SipMethodUnknown
189
    };
190
191
    /// A constructor that creates the layer from an existing packet raw data
192
    /// @param[in] data A pointer to the raw data
193
    /// @param[in] dataLen Size of the data in bytes
194
    /// @param[in] prevLayer A pointer to the previous layer
195
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
196
    SipRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
197
198
    /// A constructor that allocates a new SIP request with only the first line filled. The request will be created
199
    /// without further fields. The user can then add fields using addField() or insertField() methods
200
    /// @param[in] method The SIP method to be used in this SIP request
201
    /// @param[in] requestUri The URI of the request
202
    /// @param[in] version SIP version to be used in this request. Default is "SIP/2.0"
203
    SipRequestLayer(SipMethod method, const std::string& requestUri, const std::string& version = "SIP/2.0");
204
205
    ~SipRequestLayer() override;
206
207
    /// A copy constructor for this layer. Inherits base copy constructor SipLayer and adds the functionality
208
    /// of copying the first line
209
    /// @param[in] other The instance to copy from
210
    SipRequestLayer(const SipRequestLayer& other);
211
212
    /// An assignment operator overload for this layer. This method inherits base assignment operator
213
    /// SipLayer#operator=() and adds the functionality of copying the first line
214
    /// @param[in] other The instance to copy from
215
    SipRequestLayer& operator=(const SipRequestLayer& other);
216
217
    /// @return A pointer to the first line instance for this message
218
    SipRequestFirstLine* getFirstLine() const
219
0
    {
220
0
      return m_FirstLine;
221
0
    }
222
223
    // implement Layer's abstract methods
224
225
    std::string toString() const override;
226
227
  private:
228
    SipRequestFirstLine* m_FirstLine;
229
  };
230
231
  class SipResponseFirstLine;
232
233
  /// @class SipResponseLayer
234
  /// Represents an SIP response message and inherits all basic functionality of SipLayer and
235
  /// TextBasedProtocolMessage. The functionality that is added for this class is the SIP first line concept. A SIP
236
  /// response has the following first line: <i>200 OK SIP/2.0</i> Since it's not an "ordinary" header field, it
237
  /// requires a special treatment and gets a class of it's own: SipResponseFirstLine. In most cases a SIP response
238
  /// will be contained in a single packet but for cases it is not, only the first packet will be identified as SIP
239
  /// response layer. You can find out whether the header is complete by using SipLayer#isHeaderComplete()
240
  class SipResponseLayer : public SipLayer
241
  {
242
    friend class SipResponseFirstLine;
243
244
  public:
245
    /// Enum for SIP response status codes. List is taken from Wikipedia:
246
    /// https://en.wikipedia.org/wiki/List_of_SIP_response_codes
247
    enum SipResponseStatusCode
248
    {
249
      /// Extended search being performed may take a significant time so a forking proxy must send a 100 Trying
250
      /// response
251
      Sip100Trying,
252
      /// Destination user agent received INVITE, and is alerting user of call
253
      Sip180Ringing,
254
      /// Servers can optionally send this response to indicate a call is being forwarded
255
      Sip181CallisBeingForwarded,
256
      /// Indicates that the destination was temporarily unavailable, so the server has queued the call until the
257
      /// destination is available. A server may send multiple 182 responses to update progress of the queue
258
      Sip182Queued,
259
      /// This response may be used to send extra information for a call which is still being set up
260
      Sip183SessioninProgress,
261
      /// Can be used by User Agent Server to indicate to upstream SIP entities (including the User Agent Client
262
      /// (UAC)) that an early dialog has been terminated
263
      Sip199EarlyDialogTerminated,
264
      /// Indicates the request was successful
265
      Sip200OK,
266
      /// Indicates that the request has been accepted for processing, but the processing has not been completed
267
      Sip202Accepted,
268
      /// Indicates the request was successful, but the corresponding response will not be received
269
      Sip204NoNotification,
270
      /// The address resolved to one of several options for the user or client to choose between, which are
271
      /// listed in the message body or the message's Contact fields
272
      Sip300MultipleChoices,
273
      /// The original Request-URI is no longer valid, the new address is given in the Contact header field, and
274
      /// the client should update any records of the original Request-URI with the new value
275
      Sip301MovedPermanently,
276
      /// The client should try at the address in the Contact field. If an Expires field is present, the client
277
      /// may cache the result for that period of time
278
      Sip302MovedTemporarily,
279
      /// The Contact field details a proxy that must be used to access the requested destination
280
      Sip305UseProxy,
281
      /// The call failed, but alternatives are detailed in the message body
282
      Sip380AlternativeService,
283
      /// The request could not be understood due to malformed syntax
284
      Sip400BadRequest,
285
      /// The request requires user authentication. This response is issued by UASs and registrars
286
      Sip401Unauthorized,
287
      /// Reserved for future use
288
      Sip402PaymentRequired,
289
      /// The server understood the request, but is refusing to fulfill it
290
      Sip403Forbidden,
291
      /// The server has definitive information that the user does not exist at the domain specified in the
292
      /// Request-URI. This status is also returned if the domain in the Request-URI does not match any of the
293
      /// domains handled by the recipient of the request
294
      Sip404NotFound,
295
      /// The method specified in the Request-Line is understood, but not allowed for the address identified by
296
      /// the Request-URI
297
      Sip405MethodNotAllowed,
298
      /// The resource identified by the request is only capable of generating response entities that have content
299
      /// characteristics but not acceptable according to the Accept header field sent in the request
300
      Sip406NotAcceptable,
301
      /// The request requires user authentication. This response is issued by proxies
302
      Sip407ProxyAuthenticationRequired,
303
      /// Couldn't find the user in time. The server could not produce a response within a suitable amount of
304
      /// time, for example, if it could not determine the location of the user in time. The client MAY repeat the
305
      /// request without modifications at any later time
306
      Sip408RequestTimeout,
307
      /// User already registered
308
      Sip409Conflict,
309
      /// The user existed once, but is not available here any more
310
      Sip410Gone,
311
      /// The server will not accept the request without a valid Content-Length
312
      Sip411LengthRequired,
313
      /// The given precondition has not been met
314
      Sip412ConditionalRequestFailed,
315
      /// Request body too large
316
      Sip413RequestEntityTooLarge,
317
      /// The server is refusing to service the request because the Request-URI is longer than the server is
318
      /// willing to interpret
319
      Sip414RequestURITooLong,
320
      /// Request body in a format not supported
321
      Sip415UnsupportedMediaType,
322
      /// Request-URI is unknown to the server
323
      Sip416UnsupportedURIScheme,
324
      /// There was a resource-priority option tag, but no Resource-Priority header
325
      Sip417UnknownResourcePriority,
326
      /// Bad SIP Protocol Extension used, not understood by the server
327
      Sip420BadExtension,
328
      /// The server needs a specific extension not listed in the Supported header
329
      Sip421ExtensionRequired,
330
      /// The received request contains a Session-Expires header field with a duration below the minimum timer
331
      Sip422SessionIntervalTooSmall,
332
      /// Expiration time of the resource is too short
333
      Sip423IntervalTooBrief,
334
      /// The request's location content was malformed or otherwise unsatisfactory
335
      Sip424BadLocationInformation,
336
      /// The server rejected a non-interactive emergency call, indicating that the request was malformed enough
337
      /// that no reasonable emergency response to the alert can be determined
338
      Sip425BadAlertMessage,
339
      /// The server policy requires an Identity header, and one has not been provided
340
      Sip428UseIdentityHeader,
341
      /// The server did not receive a valid Referred-By token on the request
342
      Sip429ProvideReferrerIdentity,
343
      /// A specific flow to a user agent has failed, although other flows may succeed. This response is intended
344
      /// for use between proxy devices, and should not be seen by an endpoint (and if it is seen by one, should
345
      /// be treated as a 400 Bad Request response)
346
      Sip430FlowFailed,
347
      /// The request has been rejected because it was anonymous
348
      Sip433AnonymityDisallowed,
349
      /// The request has an Identity-Info header, and the URI scheme in that header cannot be dereferenced
350
      Sip436BadIdentityInfo,
351
      /// The server was unable to validate a certificate for the domain that signed the request
352
      Sip437UnsupportedCertificate,
353
      /// The server obtained a valid certificate that the request claimed was used to sign the request, but was
354
      /// unable to verify that signature
355
      Sip438InvalidIdentityHeader,
356
      /// The first outbound proxy the user is attempting to register through does not support the "outbound"
357
      /// feature of RFC 5626, although the registrar does
358
      Sip439FirstHopLacksOutboundSupport,
359
      /// If a SIP proxy determines a response context has insufficient Incoming Max-Breadth to carry out a
360
      /// desired parallel fork, and the proxy is unwilling/unable to compensate by forking serially or sending a
361
      /// redirect, that proxy MUST return a 440 response. A client receiving a 440 response can infer that its
362
      /// request did not reach all possible destinations
363
      Sip440MaxBreadthExceeded,
364
      /// If a SIP UA receives an INFO request associated with an Info Package that the UA has not indicated
365
      /// willingness to receive, the UA MUST send a 469 response, which contains a Recv-Info header field with
366
      /// Info Packages for which the UA is willing to receive INFO requests
367
      Sip469BadInfoPackage,
368
      /// The source of the request did not have the permission of the recipient to make such a request
369
      Sip470ConsentNeeded,
370
      /// Callee currently unavailable
371
      Sip480TemporarilyUnavailable,
372
      /// Server received a request that does not match any dialog or transaction
373
      Sip481Call_TransactionDoesNotExist,
374
      /// Server has detected a loop
375
      Sip482LoopDetected,
376
      /// Max-Forwards header has reached the value '0'
377
      Sip483TooManyHops,
378
      /// Request-URI incomplete
379
      Sip484AddressIncomplete,
380
      /// Request-URI is ambiguous
381
      Sip485Ambiguous,
382
      /// Callee is busy
383
      Sip486BusyHere,
384
      /// Request has terminated by bye or cancel
385
      Sip487RequestTerminated,
386
      /// Some aspect of the session description or the Request-URI is not acceptable
387
      Sip488NotAcceptableHere,
388
      /// The server did not understand an event package specified in an Event header field
389
      Sip489BadEvent,
390
      /// Server has some pending request from the same dialog
391
      Sip491RequestPending,
392
      /// Request contains an encrypted MIME body, which recipient can not decrypt
393
      Sip493Undecipherable,
394
      /// The server has received a request that requires a negotiated security mechanism, and the response
395
      /// contains a list of suitable security mechanisms for the requester to choose between, or a digest
396
      /// authentication challenge
397
      Sip494SecurityAgreementRequired,
398
      /// The server could not fulfill the request due to some unexpected condition
399
      Sip500ServerInternalError,
400
      /// The server does not have the ability to fulfill the request, such as because it does not recognize the
401
      /// request method. (Compare with 405 Method Not Allowed, where the server recognizes the method but does
402
      /// not allow or support it.)
403
      Sip501NotImplemented,
404
      /// The server is acting as a gateway or proxy, and received an invalid response from a downstream server
405
      /// while attempting to fulfill the request
406
      Sip502BadGateway,
407
      /// The server is undergoing maintenance or is temporarily overloaded and so cannot process the request. A
408
      /// "Retry-After" header field may specify when the client may reattempt its request
409
      Sip503ServiceUnavailable,
410
      /// The server attempted to access another server in attempting to process the request, and did not receive
411
      /// a prompt response
412
      Sip504ServerTimeout,
413
      /// The SIP protocol version in the request is not supported by the server
414
      Sip505VersionNotSupported,
415
      /// The request message length is longer than the server can process
416
      Sip513MessageTooLarge,
417
      /// The server does not support the push notification service identified in a 'pn-provider' SIP URI
418
      /// parameter
419
      Sip555PushNotificationServiceNotSupported,
420
      /// The server is unable or unwilling to meet some constraints specified in the offer
421
      Sip580PreconditionFailure,
422
      /// All possible destinations are busy. Unlike the 486 response, this response indicates the destination
423
      /// knows there are no alternative destinations (such as a voicemail server) able to accept the call
424
      Sip600BusyEverywhere,
425
      /// The destination does not wish to participate in the call, or cannot do so, and additionally the
426
      /// destination knows there are no alternative destinations (such as a voicemail server) willing to accept
427
      /// the call
428
      Sip603Decline,
429
      /// The server has authoritative information that the requested user does not exist anywhere
430
      Sip604DoesNotExistAnywhere,
431
      /// The user's agent was contacted successfully but some aspects of the session description such as the
432
      /// requested media, bandwidth, or addressing style were not acceptable
433
      Sip606NotAcceptable,
434
      /// The called party did not want this call from the calling party. Future attempts from the calling party
435
      /// are likely to be similarly rejected
436
      Sip607Unwanted,
437
      /// An intermediary machine or process rejected the call attempt
438
      Sip608Rejected,
439
      /// Unknown SIP status code
440
      SipStatusCodeUnknown
441
    };
442
443
    /// A constructor that creates the layer from an existing packet raw data
444
    /// @param[in] data A pointer to the raw data
445
    /// @param[in] dataLen Size of the data in bytes
446
    /// @param[in] prevLayer A pointer to the previous layer
447
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
448
    SipResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
449
450
    /// A constructor that allocates a new SIP response with only the first line filled. The request will be created
451
    /// without further fields. The user can then add fields using addField() or insertField() methods
452
    /// @param[in] statusCode SIP status code to set
453
    /// @param[in] statusCodeString Most status codes have their default string, e.g 200 is usually "OK" etc.
454
    /// But the user can set a non-default status code string and it will be written in the header first line. Empty
455
    /// string ("") means using the default status code string. Also, the default is using the default status code
456
    /// string
457
    /// @param[in] sipVersion SIP version to set, default is SIP/2.0
458
    explicit SipResponseLayer(SipResponseLayer::SipResponseStatusCode statusCode, std::string statusCodeString = "",
459
                              const std::string& sipVersion = "SIP/2.0");
460
461
    ~SipResponseLayer() override;
462
463
    /// A copy constructor for this layer. This copy constructor inherits base copy constructor SipLayer and adds
464
    /// the functionality of copying the first line as well
465
    /// @param[in] other The instance to copy from
466
    SipResponseLayer(const SipResponseLayer& other);
467
468
    /// An assignment operator overload for this layer. This method inherits base assignment operator
469
    /// SipLayer#operator=() and adds the functionality of copying the first line as well
470
    /// @param[in] other The instance to copy from
471
    SipResponseLayer& operator=(const SipResponseLayer& other);
472
473
    /// @return A pointer to the first line instance for this message
474
    SipResponseFirstLine* getFirstLine() const
475
0
    {
476
0
      return m_FirstLine;
477
0
    }
478
479
    // implement Layer's abstract methods
480
481
    std::string toString() const override;
482
483
  private:
484
    SipResponseFirstLine* m_FirstLine;
485
  };
486
487
  /// @class SipRequestFirstLine
488
  /// Represents an SIP request first line. The first line includes 3 parameters: SIP method (e.g INVITE, ACK, BYE,
489
  /// etc.), URI (e.g sip:bla@bla.com:12345) and SIP version (usually SIP/2.0). All these parameters are included in
490
  /// this class, and the user can retrieve or set them. This class cannot be instantiated by users, it's created
491
  /// inside SipRequestLayer and user can get a pointer to an instance of it. All "getters" of this class retrieve the
492
  /// actual data of the SIP request and the "setters" actually change the packet data. Since SIP is a textual
493
  /// protocol, most fields aren't of fixed size and this also applies to the first line parameters. So many "setter"
494
  /// methods of this class may need to shorten or extend the data in SipRequestLayer. These methods will return a
495
  /// false value if this action failed
496
  class SipRequestFirstLine
497
  {
498
    friend class SipRequestLayer;
499
500
  public:
501
    /// @return The SIP request method
502
    SipRequestLayer::SipMethod getMethod() const
503
0
    {
504
0
      return m_Method;
505
0
    }
506
507
    /// Set the SIP request method
508
    /// @param[in] newMethod The method to set
509
    /// @return False if newMethod is SipRequestLayer#SipMethodUnknown or if shortening/extending the
510
    /// SipRequestLayer data failed. True otherwise
511
    bool setMethod(SipRequestLayer::SipMethod newMethod);
512
513
    /// @return A copied version of the URI (notice changing the return value won't change the actual data of the
514
    /// packet)
515
    std::string getUri() const;
516
517
    /// Set the URI
518
    /// @param[in] newUri The URI to set
519
    /// @return False if shortening/extending the SipRequestLayer data failed. True otherwise
520
    bool setUri(const std::string& newUri);
521
522
    /// @return The SIP version
523
    std::string getVersion() const
524
0
    {
525
0
      return m_Version;
526
0
    }
527
528
    /// A static method for parsing the SIP method out of raw data
529
    /// @param[in] data The raw data
530
    /// @param[in] dataLen The raw data length
531
    /// @return The parsed SIP method
532
    static SipRequestLayer::SipMethod parseMethod(const char* data, size_t dataLen);
533
534
    /// @return The size in bytes of the SIP request first line
535
    int getSize() const
536
19.6k
    {
537
19.6k
      return m_FirstLineEndOffset;
538
19.6k
    }
539
540
    /// As explained in SipRequestLayer, a SIP message can sometimes spread over more than 1 packet, so when looking
541
    /// at a single packet the header can be partial. Same goes for the first line - it can spread over more than 1
542
    /// packet. This method returns an indication whether the first line is partial
543
    /// @return False if the first line is partial, true if it's complete
544
    bool isComplete() const
545
0
    {
546
0
      return m_IsComplete;
547
0
    }
548
549
    /// @class SipRequestFirstLineException
550
    /// This exception can be thrown while constructing SipRequestFirstLine (the constructor is private, so the
551
    /// construction happens only in SipRequestLayer). This kind of exception is thrown if trying to construct with
552
    /// SIP method of SipRequestLayer#SipMethodUnknown or with empty SIP version
553
    class SipRequestFirstLineException : public std::exception
554
    {
555
    public:
556
      ~SipRequestFirstLineException() noexcept
557
16.6k
      {}
558
      void setMessage(const std::string& message)
559
0
      {
560
0
        m_Message = message;
561
0
      }
562
      virtual const char* what() const noexcept
563
0
      {
564
0
        return m_Message.c_str();
565
0
      }
566
567
    private:
568
      std::string m_Message;
569
    };
570
571
  private:
572
    SipRequestFirstLine(SipRequestLayer* sipRequest);
573
    SipRequestFirstLine(SipRequestLayer* sipRequest, SipRequestLayer::SipMethod method, const std::string& version,
574
                        const std::string& uri);
575
576
    void parseVersion();
577
578
    SipRequestLayer* m_SipRequest;
579
    SipRequestLayer::SipMethod m_Method;
580
    std::string m_Version;
581
    int m_VersionOffset;
582
    int m_UriOffset;
583
    int m_FirstLineEndOffset;
584
    bool m_IsComplete;
585
    SipRequestFirstLineException m_Exception;
586
  };
587
588
  /// @class SipResponseFirstLine
589
  /// Represents an SIP response message first line. The first line includes 2 parameters: status code (e.g 100 Trying
590
  /// ,200 OK, etc.), and SIP version (usually SIP/2.0). These 2 parameters are included in this class, and the user
591
  /// can retrieve or set them. This class cannot be instantiated by users, it's created inside SipResponseLayer and
592
  /// user can get a pointer to an instance of it. The "getter" methods of this class will retrieve the actual data of
593
  /// the SIP response and the "setter" methods will change the packet data. Since SIP is a textual protocol, most
594
  /// fields aren't of fixed size and this also applies to the first line parameters. So most "setter" methods of this
595
  /// class may need to shorten or extend the data in SipResponseLayer. These methods will return a false value if
596
  /// this action failed
597
  class SipResponseFirstLine
598
  {
599
    friend class SipResponseLayer;
600
601
  public:
602
    /// @return The status code as SipResponseLayer#SipResponseStatusCode enum
603
    SipResponseLayer::SipResponseStatusCode getStatusCode() const
604
0
    {
605
0
      return m_StatusCode;
606
0
    }
607
608
    /// @return The status code number as integer (e.g 200, 100, etc.)
609
    int getStatusCodeAsInt() const;
610
611
    /// @return The status code message (e.g "OK", "Trying", etc.)
612
    std::string getStatusCodeString() const;
613
614
    /// Set the status code
615
    /// @param[in] newStatusCode The new status code to set
616
    /// @param[in] statusCodeString An optional parameter: set a non-default status code message (e.g "Bla Bla"
617
    /// instead of "Not Found"). If this parameter isn't supplied or supplied as empty string (""), the default
618
    /// message for the status code will be set
619
    bool setStatusCode(SipResponseLayer::SipResponseStatusCode newStatusCode, std::string statusCodeString = "");
620
621
    /// @return The SIP version
622
    std::string getVersion() const
623
0
    {
624
0
      return m_Version;
625
0
    }
626
627
    /// Set the SIP version. The version to set is expected to be in the format of SIP/x.y otherwise an error will
628
    /// be written to log
629
    /// @param[in] newVersion The SIP version to set
630
    void setVersion(const std::string& newVersion);
631
632
    /// A static method for parsing the SIP status code out of raw data
633
    /// @param[in] data The raw data
634
    /// @param[in] dataLen The raw data length
635
    /// @return The parsed SIP status code as enum
636
    static SipResponseLayer::SipResponseStatusCode parseStatusCode(const char* data, size_t dataLen);
637
638
    /// A static method for parsing the SIP version out of raw data
639
    /// @param[in] data The raw data
640
    /// @param[in] dataLen The raw data length
641
    /// @return The parsed SIP version string or an empty string if version cannot be extracted
642
    static std::string parseVersion(const char* data, size_t dataLen);
643
644
    /// @return The size in bytes of the SIP response first line
645
    int getSize() const
646
4.65k
    {
647
4.65k
      return m_FirstLineEndOffset;
648
4.65k
    }
649
650
    /// As explained in SipResponseLayer, A SIP message can sometimes spread over more than 1 packet, so when
651
    /// looking at a single packet the header can be partial. Same goes for the first line - it can spread over more
652
    /// than 1 packet. This method returns an indication whether the first line is partial
653
    /// @return False if the first line is partial, true if it's complete
654
    bool isComplete() const
655
0
    {
656
0
      return m_IsComplete;
657
0
    }
658
659
    /// @class SipResponseFirstLineException
660
    /// This exception can be thrown while constructing SipResponseFirstLine (the constructor is private, so the
661
    /// construction happens only in SipResponseLayer). This kind of exception will be thrown if trying to construct
662
    /// with SIP status code of SipResponseLayer#SipStatusCodeUnknown or with an empty SIP version
663
    class SipResponseFirstLineException : public std::exception
664
    {
665
    public:
666
      ~SipResponseFirstLineException() noexcept
667
3.82k
      {}
668
      void setMessage(const std::string& message)
669
0
      {
670
0
        m_Message = message;
671
0
      }
672
      virtual const char* what() const noexcept
673
0
      {
674
0
        return m_Message.c_str();
675
0
      }
676
677
    private:
678
      std::string m_Message;
679
    };
680
681
  private:
682
    SipResponseFirstLine(SipResponseLayer* sipResponse);
683
    SipResponseFirstLine(SipResponseLayer* sipResponse, const std::string& version,
684
                         SipResponseLayer::SipResponseStatusCode statusCode, std::string statusCodeString = "");
685
686
    SipResponseLayer* m_SipResponse;
687
    std::string m_Version;
688
    SipResponseLayer::SipResponseStatusCode m_StatusCode;
689
    int m_FirstLineEndOffset;
690
    bool m_IsComplete;
691
    SipResponseFirstLineException m_Exception;
692
  };
693
694
}  // namespace pcpp