/* Copyright (C) 2005-2009 Michel de Boer 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, see . */ #include #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 t_response::encode_env(void) { string s; list 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); } }