/* * SIP message related functions * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of Kamailio, a free SIP server. * * Kamailio 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 * * Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! * \file * \brief SIP registrar module - SIP message related functions * \ingroup registrar */ #include "../../core/parser/hf.h" #include "../../core/dprint.h" #include "../../core/parser/parse_expires.h" #include "../../core/ut.h" #include "../../core/qvalue.h" #include "../../core/rand/kam_rand.h" #include "registrar.h" /* Module parameters */ #include "regtime.h" /* act_time */ #include "rerrno.h" #include "sip_msg.h" #include "config.h" #include <stdlib.h> static struct hdr_field* act_contact; /* \brief * Return randomized expires between expires-range% and expires. * RFC allows only value less or equal to the one provided by UAC. */ static inline int randomize_expires( int expires, int range ) { int range_min; /* if no range is given just return expires */ if(range == 0) return expires; range_min = expires - (float)range/100 * expires; return range_min + (float)(kam_rand()%100)/100 * ( expires - range_min ); } /*! \brief * Return value of Expires header field * if the HF exists, if the HF doesn't exist, * returns -1; */ static inline int get_expires_hf(struct sip_msg* _m) { exp_body_t* p; if (_m->expires) { p = (exp_body_t*)_m->expires->parsed; if (p->valid) { return p->val; } } return -1; } /*! \brief * Parse the whole message and bodies of all header fields * that will be needed by registrar */ int parse_message(struct sip_msg* _m) { if (parse_headers(_m, HDR_EOH_F, 0) == -1) { rerrno = R_PARSE; LM_ERR("failed to parse headers\n"); return -1; } if (!_m->to) { rerrno = R_TO_MISS; LM_ERR("To not found\n"); return -2; } if (!_m->callid) { rerrno = R_CID_MISS; LM_ERR("Call-ID not found\n"); return -3; } if (!_m->cseq) { rerrno = R_CS_MISS; LM_ERR("CSeq not found\n"); return -4; } if (_m->expires && !_m->expires->parsed && (parse_expires(_m->expires) < 0)) { rerrno = R_PARSE_EXP; LM_ERR("failed to parse expires body\n"); return -5; } if(parse_contact_headers(_m) < 0) { rerrno = R_PARSE_CONT; LM_ERR("failed to parse Contact body\n"); return -6; } return 0; } /*! \brief * Check if the originating REGISTER message was formed correctly * The whole message must be parsed before calling the function * _s indicates whether the contact was star */ int check_contacts(struct sip_msg* _m, int* _s) { struct hdr_field* p; contact_t* c; *_s = 0; /* Message without contacts is OK */ if (_m->contact == 0) return 0; if (((contact_body_t*)_m->contact->parsed)->star == 1) { /* The first Contact HF is star */ /* Expires must be zero */ if (get_expires_hf(_m) != 0) { LM_WARN("expires must be 0 for star contact\n"); rerrno = R_STAR_EXP; return 1; } /* Message must contain no contacts */ if (((contact_body_t*)_m->contact->parsed)->contacts) { LM_WARN("star contact cannot be mixed with other contacts\n"); rerrno = R_STAR_CONT; return 1; } /* Message must contain no other Contact HFs */ p = _m->contact->next; while(p) { if (p->type == HDR_CONTACT_T) { LM_WARN("star contact cannot be mixed with other contacts\n"); rerrno = R_STAR_CONT; return 1; } p = p->next; } *_s = 1; } else { /* The first Contact HF is not star */ p = _m->contact; while(p) { if (p->type == HDR_CONTACT_T) { /* Message must contain no star Contact HF */ if (((contact_body_t*)p->parsed)->star == 1) { LM_WARN("star contact cannot be mixed with other contacts\n"); rerrno = R_STAR_CONT; return 1; } /* check also the length of all contacts */ for(c=((contact_body_t*)p->parsed)->contacts ; c ; c=c->next) { if (c->uri.len > contact_max_size) { LM_WARN("contact uri is too long: [%.*s]\n", c->uri.len, c->uri.s); rerrno = R_CONTACT_LEN; return 1; } if (c->received && c->received->len>RECEIVED_MAX_SIZE) { LM_WARN("received attribute of contact is too long\n"); rerrno = R_CONTACT_LEN; return 1; } } } p = p->next; } } return 0; } /*! \brief * Get the first contact in message */ contact_t* get_first_contact(struct sip_msg* _m) { if (_m->contact == 0) return 0; act_contact = _m->contact; return (((contact_body_t*)_m->contact->parsed)->contacts); } /*! \brief * Get next contact in message */ contact_t* get_next_contact(contact_t* _c) { struct hdr_field* p; if (_c->next == 0) { p = act_contact->next; while(p) { if (p->type == HDR_CONTACT_T) { act_contact = p; return (((contact_body_t*)p->parsed)->contacts); } p = p->next; } return 0; } else { return _c->next; } } /*! \brief * Calculate absolute expires value per contact as follows: * 1) If the contact has expires value, use the value. If it * is not zero, add actual time to it * 2) If the contact has no expires parameter, use expires * header field in the same way * 3) If the message contained no expires header field, use * the default value */ void calc_contact_expires(struct sip_msg* _m, param_t* _ep, int* _e, int novariation) { int range = 0; if (!_ep || !_ep->body.len) { *_e = get_expires_hf(_m); if ( *_e < 0 ) { *_e = cfg_get(registrar, registrar_cfg, default_expires); range = cfg_get(registrar, registrar_cfg, default_expires_range); } else { range = cfg_get(registrar, registrar_cfg, expires_range); } } else { if (str2int(&_ep->body, (unsigned int*)_e) < 0) { *_e = cfg_get(registrar, registrar_cfg, default_expires); range = cfg_get(registrar, registrar_cfg, default_expires_range); } else { range = cfg_get(registrar, registrar_cfg, expires_range); } } if ( *_e != 0 ) { if (*_e < cfg_get(registrar, registrar_cfg, min_expires)) { if(reg_min_expires_mode) { rerrno = R_LOW_EXP; return; } else { *_e = cfg_get(registrar, registrar_cfg, min_expires); } } if (!novariation) { *_e = randomize_expires( *_e, range ); if (*_e < cfg_get(registrar, registrar_cfg, min_expires)) { *_e = cfg_get(registrar, registrar_cfg, min_expires); } } if (cfg_get(registrar, registrar_cfg, max_expires) && (*_e > cfg_get(registrar, registrar_cfg, max_expires))) { *_e = cfg_get(registrar, registrar_cfg, max_expires); } /* Convert to absolute value */ *_e += act_time; } } /*! \brief * Calculate contact q value as follows: * 1) If xavp_cfg q has been defined, use it * 2) If q parameter exists in contact, use it * 3) If the parameter doesn't exist in contact, use the default value */ int calc_contact_q(param_t* _q, qvalue_t* _r) { sr_xavp_t *vavp = NULL; str xqname = str_init("q"); if (reg_xavp_cfg.s != NULL) vavp = xavp_get_child_with_ival(®_xavp_cfg, &xqname); if (vavp != NULL) { if ((vavp->val.v.i >= 0) && (vavp->val.v.i <= 1000)) { *_r = vavp->val.v.i; return 0; } else { rerrno = R_INV_Q; /* Invalid q parameter */ LM_ERR("invalid q parameter\n"); return -1; } } if (!_q || (_q->body.len == 0)) { *_r = cfg_get(registrar, registrar_cfg, default_q); } else { if (str2q(_r, _q->body.s, _q->body.len) < 0) { rerrno = R_INV_Q; /* Invalid q parameter */ LM_ERR("invalid q parameter\n"); return -1; } } return 0; }