📄 dlg.c
字号:
if (!_m->cseq && ((parse_headers(_m, HDR_CSEQ, 0) == -1) || !_m->cseq)) { LOG(L_ERR, "get_cseq_method(): Error while parsing CSeq\n"); return -1; } _method->s = get_cseq(_m)->method.s; _method->len = get_cseq(_m)->method.len; return 0;}/* * Handle dialog in DLG_CONFIRMED state, we will be processing * a response to a request sent within a dialog */static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m){ int code; str method, contact; code = _m->first_line.u.reply.statuscode; /* Dialog has been already confirmed, that means we received * a response to a request sent within the dialog. We will * update remote target URI if and only if the message sent was * a target refresher. */ /* FIXME: Currently we support only INVITEs as target refreshers, * this should be generalized */ /* IF we receive a 481 response, terminate the dialog because * the remote peer indicated that it didn't have the dialog * state anymore, signal this termination with a positive return * value */ if (code == 481) { _d->state = DLG_DESTROYED; return 1; } /* Do nothing if not 2xx */ if ((code < 200) || (code >= 300)) return 0; if (get_cseq_method(_m, &method) < 0) return -1; if ((method.len == 6) && !memcmp("INVITE", method.s, 6)) { /* Get contact if any and update remote target */ if (parse_headers(_m, HDR_CONTACT, 0) == -1) { LOG(L_ERR, "dlg_confirmed_resp_uac(): Error while parsing headers\n"); return -2; } /* Try to extract contact URI */ if (get_contact_uri(_m, &contact) < 0) return -3; /* If there is a contact URI */ if (contact.len) { /* Free old remote target if any */ if (_d->rem_target.s) shm_free(_d->rem_target.s); /* Duplicate new remote target */ if (str_duplicate(&_d->rem_target, &contact) < 0) return -4; } } return 0;}/* * A response arrived, update dialog */int dlg_response_uac(dlg_t* _d, struct sip_msg* _m){ if (!_d || !_m) { LOG(L_ERR, "dlg_response_uac(): Invalid parameter value\n"); return -1; } /* The main dispatcher */ switch(_d->state) { case DLG_NEW: return dlg_new_resp_uac(_d, _m); case DLG_EARLY: return dlg_early_resp_uac(_d, _m); case DLG_CONFIRMED: return dlg_confirmed_resp_uac(_d, _m); case DLG_DESTROYED: LOG(L_ERR, "dlg_response_uac(): Cannot handle destroyed dialog\n"); return -2; } LOG(L_ERR, "dlg_response_uac(): Error in switch statement\n"); return -3;}/* * Get CSeq number * Does not parse headers !! */static inline int get_cseq_value(struct sip_msg* _m, unsigned int* _cs){ str num; if (_m->cseq == 0) { LOG(L_ERR, "get_cseq_value(): CSeq header not found\n"); return -1; } num.s = get_cseq(_m)->number.s; num.len = get_cseq(_m)->number.len; trim_leading(&num); if (str2int(&num, _cs) < 0) { LOG(L_ERR, "get_cseq_value(): Error while converting cseq number\n"); return -2; } return 0;}/* * Copy To or From URI without tag parameter */static inline int get_dlg_uri(struct hdr_field* _h, str* _s){ struct to_param* ptr, *prev; struct to_body* body; char* tag = 0; /* Makes gcc happy */ int tag_len = 0, len; if (!_h) { LOG(L_ERR, "get_dlg_uri(): Header field not found\n"); return -1; } /* From was already parsed when extracting tag * and To is parsed by default */ body = (struct to_body*)_h->parsed; ptr = body->param_lst; prev = 0; while(ptr) { if (ptr->type == TAG_PARAM) break; prev = ptr; ptr = ptr->next; } if (ptr) { /* Tag param found */ if (prev) { tag = prev->value.s + prev->value.len; } else { tag = body->body.s + body->body.len; } if (ptr->next) { tag_len = ptr->value.s + ptr->value.len - tag; } else { tag_len = _h->body.s + _h->body.len - tag; } } _s->s = shm_malloc(_h->body.len - tag_len); if (!_s->s) { LOG(L_ERR, "get_dlg_uri(): No memory left\n"); return -1; } if (tag_len) { len = tag - _h->body.s; memcpy(_s->s, _h->body.s, len); memcpy(_s->s + len, tag + tag_len, _h->body.len - len - tag_len); _s->len = _h->body.len - tag_len; } else { memcpy(_s->s, _h->body.s, _h->body.len); _s->len = _h->body.len; } return 0;}/* * Extract all information from a request * and update a dialog structure */static inline int request2dlg(struct sip_msg* _m, dlg_t* _d){ str contact, rtag, callid; if (parse_headers(_m, HDR_EOH, 0) == -1) { LOG(L_ERR, "request2dlg(): Error while parsing headers"); return -1; } if (get_contact_uri(_m, &contact) < 0) return -2; if (contact.len && str_duplicate(&_d->rem_target, &contact) < 0) return -3; if (get_from_tag(_m, &rtag) < 0) goto err1; if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1; if (get_callid(_m, &callid) < 0) goto err2; if (callid.len && str_duplicate(&_d->id.call_id, &callid) < 0) goto err2; if (get_cseq_value(_m, &_d->rem_seq.value) < 0) goto err3; _d->rem_seq.is_set = 1; if (get_dlg_uri(_m->from, &_d->rem_uri) < 0) goto err3; if (get_dlg_uri(_m->to, &_d->loc_uri) < 0) goto err4; if (get_route_set(_m, &_d->route_set, NORMAL_ORDER) < 0) goto err5; return 0; err5: if (_d->loc_uri.s) shm_free(_d->loc_uri.s); _d->loc_uri.s = 0; _d->loc_uri.len = 0; err4: if (_d->rem_uri.s) shm_free(_d->rem_uri.s); _d->rem_uri.s = 0; _d->rem_uri.len = 0; err3: if (_d->id.call_id.s) shm_free(_d->id.call_id.s); _d->id.call_id.s = 0; _d->id.call_id.len = 0; err2: if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s); _d->id.rem_tag.s = 0; _d->id.rem_tag.len = 0; err1: if (_d->rem_target.s) shm_free(_d->rem_target.s); _d->rem_target.s = 0; _d->rem_target.len = 0; return -4;}/* * Establishing a new dialog, UAS side */int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d){ dlg_t* res; str tag; if (!_req || /*!_tag ||*/ !_d) { LOG(L_ERR, "new_dlg_uas(): Invalid parameter value\n"); return -1; } if ((_code < 200) || (_code > 299)) { DBG("new_dlg_uas(): Not a 2xx, no dialog created\n"); return -2; } res = (dlg_t*)shm_malloc(sizeof(dlg_t)); if (res == 0) { LOG(L_ERR, "new_dlg_uac(): No memory left\n"); return -3; } /* Clear everything */ memset(res, 0, sizeof(dlg_t)); if (request2dlg(_req, res) < 0) { LOG(L_ERR, "new_dlg_uas(): Error while converting request to dialog\n"); return -4; } tag.s = tm_tags; tag.len = TOTAG_VALUE_LEN; calc_crc_suffix(_req, tm_tag_suffix); if (str_duplicate(&res->id.loc_tag, &tag) < 0) { free_dlg(res); return -5; } *_d = res; (*_d)->state = DLG_CONFIRMED; if (calculate_hooks(*_d) < 0) { LOG(L_ERR, "new_dlg_uas(): Error while calculating hooks\n"); shm_free(*_d); return -6; } return 0;}/* * UAS side - update a dialog from a request */int dlg_request_uas(dlg_t* _d, struct sip_msg* _m){ str contact; int cseq; if (!_d || !_m) { LOG(L_ERR, "dlg_request_uas(): Invalid parameter value\n"); return -1; } /* We must check if the request is not out of order or retransmission * first, if so then we will not update anything */ if (parse_headers(_m, HDR_CSEQ, 0) == -1) { LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n"); return -2; } if (get_cseq_value(_m, (unsigned int*)&cseq) < 0) return -3; if (_d->rem_seq.is_set && (cseq <= _d->rem_seq.value)) return 0; /* Neither out of order nor retransmission -> update */ _d->rem_seq.value = cseq; _d->rem_seq.is_set = 1; /* We will als update remote target URI if the message * is target refresher */ if (_m->first_line.u.request.method_value == METHOD_INVITE) { /* target refresher */ if (parse_headers(_m, HDR_CONTACT, 0) == -1) { LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n"); return -4; } if (get_contact_uri(_m, &contact) < 0) return -5; if (contact.len) { if (_d->rem_target.s) shm_free(_d->rem_target.s); if (str_duplicate(&_d->rem_target, &contact) < 0) return -6; } } return 0;}/* * Calculate length of the route set */int calculate_routeset_length(dlg_t* _d){ int len; rr_t* ptr; len = 0; ptr = _d->hooks.first_route; if (ptr) { len = ROUTE_PREFIX_LEN; len += CRLF_LEN; } while(ptr) { len += ptr->len; ptr = ptr->next; if (ptr) len += ROUTE_SEPARATOR_LEN; } if (_d->hooks.last_route) { len += ROUTE_SEPARATOR_LEN + 2; /* < > */ len += _d->hooks.last_route->len; } return len;}/* * * Print the route set */char* print_routeset(char* buf, dlg_t* _d){ rr_t* ptr; ptr = _d->hooks.first_route; if (ptr || _d->hooks.last_route) { memcpy(buf, ROUTE_PREFIX, ROUTE_PREFIX_LEN); buf += ROUTE_PREFIX_LEN; } while(ptr) { memcpy(buf, ptr->nameaddr.name.s, ptr->len); buf += ptr->len; ptr = ptr->next; if (ptr) { memcpy(buf, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN); buf += ROUTE_SEPARATOR_LEN; } } if (_d->hooks.last_route) { if (_d->hooks.first_route) { memcpy(buf, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN); buf += ROUTE_SEPARATOR_LEN; } memcpy(buf, "<", 1); buf++; memcpy(buf, _d->hooks.last_route->s, _d->hooks.last_route->len); buf += _d->hooks.last_route->len; *buf = '>'; buf++; } if (_d->hooks.first_route || _d->hooks.last_route) { memcpy(buf, CRLF, CRLF_LEN); buf += CRLF_LEN; } return buf;}/* * Destroy a dialog state */void free_dlg(dlg_t* _d){ if (!_d) return; if (_d->id.call_id.s) shm_free(_d->id.call_id.s); if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s); if (_d->id.loc_tag.s) shm_free(_d->id.loc_tag.s); if (_d->loc_uri.s) shm_free(_d->loc_uri.s); if (_d->rem_uri.s) shm_free(_d->rem_uri.s); if (_d->rem_target.s) shm_free(_d->rem_target.s); /* Free all routes in the route set */ shm_free_rr(&_d->route_set); shm_free(_d);}/* * Print a dialog structure, just for debugging */void print_dlg(FILE* out, dlg_t* _d){ fprintf(out, "====dlg_t===\n"); fprintf(out, "id.call_id : '%.*s'\n", _d->id.call_id.len, _d->id.call_id.s); fprintf(out, "id.rem_tag : '%.*s'\n", _d->id.rem_tag.len, _d->id.rem_tag.s); fprintf(out, "id.loc_tag : '%.*s'\n", _d->id.loc_tag.len, _d->id.loc_tag.s); fprintf(out, "loc_seq.value : %d\n", _d->loc_seq.value); fprintf(out, "loc_seq.is_set: %s\n", _d->loc_seq.is_set ? "YES" : "NO"); fprintf(out, "rem_seq.value : %d\n", _d->rem_seq.value); fprintf(out, "rem_seq.is_set: %s\n", _d->rem_seq.is_set ? "YES" : "NO"); fprintf(out, "loc_uri : '%.*s'\n", _d->loc_uri.len, _d->loc_uri.s); fprintf(out, "rem_uri : '%.*s'\n", _d->rem_uri.len, _d->rem_uri.s); fprintf(out, "rem_target : '%.*s'\n", _d->rem_target.len, _d->rem_target.s); fprintf(out, "secure: : %d\n", _d->secure); fprintf(out, "state : "); switch(_d->state) { case DLG_NEW: fprintf(out, "DLG_NEW\n"); break; case DLG_EARLY: fprintf(out, "DLG_EARLY\n"); break; case DLG_CONFIRMED: fprintf(out, "DLG_CONFIRMED\n"); break; case DLG_DESTROYED: fprintf(out, "DLG_DESTROYED\n"); break; } print_rr(out, _d->route_set); if (_d->hooks.request_uri) fprintf(out, "hooks.request_uri: '%.*s'\n", _d->hooks.request_uri->len, _d->hooks.request_uri->s); if (_d->hooks.next_hop) fprintf(out, "hooks.next_hop : '%.*s'\n", _d->hooks.next_hop->len, _d->hooks.next_hop->s); if (_d->hooks.first_route) fprintf(out, "hooks.first_route: '%.*s'\n", _d->hooks.first_route->len, _d->hooks.first_route->nameaddr.name.s); if (_d->hooks.last_route) fprintf(out, "hooks.last_route : '%.*s'\n", _d->hooks.last_route->len, _d->hooks.last_route->s); fprintf(out, "====dlg_t====\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -