Coverage Report

Created: 2024-02-25 06:29

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