Coverage Report

Created: 2023-01-17 06:15

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