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