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