summaryrefslogtreecommitdiffstats
path: root/src/parser/response.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser/response.cpp')
-rwxr-xr-xsrc/parser/response.cpp237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/parser/response.cpp b/src/parser/response.cpp
new file mode 100755
index 0000000..83f47eb
--- /dev/null
+++ b/src/parser/response.cpp
@@ -0,0 +1,237 @@
+/*
+ Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <cassert>
+
+#include "response.h"
+#include "util.h"
+#include "parse_ctrl.h"
+#include "audits/memman.h"
+
+t_response::t_response() : t_sip_message() {}
+
+t_response::t_response(const t_response &r) : t_sip_message(r) ,
+ code(r.code),
+ reason(r.reason),
+ src_ip_port_request(r.src_ip_port_request)
+{
+}
+
+t_response::t_response(int _code, string _reason) : t_sip_message() {
+ code = _code;
+
+ if (_reason == "") {
+ switch (code) {
+ case 100: reason = REASON_100; break;
+ case 180: reason = REASON_180; break;
+ case 181: reason = REASON_181; break;
+ case 182: reason = REASON_182; break;
+ case 183: reason = REASON_183; break;
+ case 200: reason = REASON_200; break;
+ case 202: reason = REASON_202; break;
+ case 300: reason = REASON_300; break;
+ case 301: reason = REASON_301; break;
+ case 302: reason = REASON_302; break;
+ case 305: reason = REASON_305; break;
+ case 380: reason = REASON_380; break;
+ case 400: reason = REASON_400; break;
+ case 401: reason = REASON_401; break;
+ case 402: reason = REASON_402; break;
+ case 403: reason = REASON_403; break;
+ case 404: reason = REASON_404; break;
+ case 405: reason = REASON_405; break;
+ case 406: reason = REASON_406; break;
+ case 407: reason = REASON_407; break;
+ case 408: reason = REASON_408; break;
+ case 410: reason = REASON_410; break;
+ case 412: reason = REASON_412; break;
+ case 413: reason = REASON_413; break;
+ case 414: reason = REASON_414; break;
+ case 415: reason = REASON_415; break;
+ case 416: reason = REASON_416; break;
+ case 420: reason = REASON_420; break;
+ case 421: reason = REASON_421; break;
+ case 423: reason = REASON_423; break;
+ case 480: reason = REASON_480; break;
+ case 481: reason = REASON_481; break;
+ case 482: reason = REASON_482; break;
+ case 483: reason = REASON_483; break;
+ case 484: reason = REASON_484; break;
+ case 485: reason = REASON_485; break;
+ case 486: reason = REASON_486; break;
+ case 487: reason = REASON_487; break;
+ case 488: reason = REASON_488; break;
+ case 489: reason = REASON_489; break;
+ case 491: reason = REASON_491; break;
+ case 493: reason = REASON_493; break;
+ case 500: reason = REASON_500; break;
+ case 501: reason = REASON_501; break;
+ case 502: reason = REASON_502; break;
+ case 503: reason = REASON_503; break;
+ case 504: reason = REASON_504; break;
+ case 505: reason = REASON_505; break;
+ case 513: reason = REASON_513; break;
+ case 600: reason = REASON_600; break;
+ case 603: reason = REASON_603; break;
+ case 604: reason = REASON_604; break;
+ case 606: reason = REASON_606; break;
+ default: reason = "Unknown Error";
+ }
+ } else {
+ reason = _reason;
+ }
+}
+
+int t_response::get_class(void) const {
+ return code / 100;
+}
+
+bool t_response::is_provisional(void) const {
+ return (get_class() == R_1XX);
+}
+
+bool t_response::is_final(void) const {
+ return (get_class() != R_1XX);
+}
+
+bool t_response::is_success(void) const {
+ return (get_class() == R_2XX);
+}
+
+string t_response::encode(bool add_content_length) {
+ string s;
+
+ s = "SIP/" + version + ' ' + int2str(code, "%3d") + ' ' + reason;
+ s += CRLF;
+ s += t_sip_message::encode(add_content_length);
+
+ return s;
+}
+
+list<string> t_response::encode_env(void) {
+ string s;
+
+ list<string> l = t_sip_message::encode_env();
+
+ s = "SIPSTATUS_CODE=";
+ s += int2str(code, "%3d");
+ l.push_back(s);
+
+ s = "SIPSTATUS_REASON=";
+ s += reason;
+ l.push_back(s);
+
+ return l;
+}
+
+t_sip_message *t_response::copy(void) const {
+ t_sip_message *m = new t_response(*this);
+ MEMMAN_NEW(m);
+ return m;
+}
+
+bool t_response::is_valid(bool &fatal, string &reason) const {
+ if (!t_sip_message::is_valid(fatal, reason)) return false;
+
+ fatal = false;
+
+ switch(hdr_cseq.method) {
+ case INVITE:
+ if (get_class() == R_2XX && !hdr_contact.is_populated()) {
+ reason = "Contact header missing";
+ return false;
+ }
+ break;
+ case SUBSCRIBE:
+ // RFC 3265 7.1, 7.2
+ /*
+ Some SIP servers do not send the mandatory Expires header.
+ For interoperability this deviation is allowed.
+ if (get_class()== R_2XX && !hdr_expires.is_populated()) {
+ reason = "Expires header missing";
+ return false;
+ }
+ */
+
+ switch (code) {
+ case R_489_BAD_EVENT:
+ if (!hdr_allow_events.is_populated()) {
+ reason = "Allow-Events header missing";
+ return false;
+ }
+ break;
+ }
+
+ break;
+ case NOTIFY:
+ // RFC 3265 7.1, 7.2
+ switch (code) {
+ case R_489_BAD_EVENT:
+ if (!hdr_allow_events.is_populated()) {
+ reason = "Allow-Events header is missing";
+ return false;
+ }
+ break;
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ if (hdr_rseq.is_populated()) {
+ // RFC 3262 7.1
+ // The value ranges from 1 to 2**32 - 1
+ if (hdr_rseq.resp_nr == 0) {
+ reason = "RSeq is zero";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool t_response::must_authenticate(void) const {
+ return (code == R_401_UNAUTHORIZED &&
+ hdr_www_authenticate.is_populated() ||
+ code == R_407_PROXY_AUTH_REQUIRED &&
+ hdr_proxy_authenticate.is_populated());
+}
+
+void t_response::get_destination(t_ip_port &ip_port) const {
+ assert(hdr_via.is_populated());
+
+ if (src_ip_port_request.transport == "tcp") {
+ // RFC 3261 18.2.2
+ // For TCP the response should be sent on the connection on which
+ // the request was received. So the address returned here is the
+ // alternative destination when the connection is closed already.
+ ip_port = src_ip_port_request;
+ } else {
+ hdr_via.get_response_dst(ip_port);
+ }
+}
+
+void t_response::calc_local_ip(void) {
+ t_ip_port dst;
+
+ get_destination(dst);
+ if (dst.ipaddr != 0) {
+ local_ip_ = get_src_ip4_address_for_dst(dst.ipaddr);
+ }
+}