static void retransmit_handler(void *arg) { struct sip_ctrans *ct = arg; uint32_t timeout; int err; ct->txc++; switch (ct->state) { case TRYING: timeout = MIN(SIP_T1<<ct->txc, SIP_T2); break; case CALLING: timeout = SIP_T1<<ct->txc; break; case PROCEEDING: timeout = SIP_T2; break; default: return; } tmr_start(&ct->tmre, timeout, retransmit_handler, ct); err = sip_transp_send(&ct->qent, ct->sip, NULL, ct->tp, &ct->dst, ct->mb, transport_handler, ct); if (err) { terminate(ct, err); mem_deref(ct); } }
int sip_ctrans_request(struct sip_ctrans **ctp, struct sip *sip, enum sip_transp tp, const struct sa *dst, char *met, char *branch, struct mbuf *mb, sip_resp_h *resph, void *arg) { struct sip_ctrans *ct; int err; if (!sip || !dst || !met || !branch || !mb) return EINVAL; ct = mem_zalloc(sizeof(*ct), destructor); if (!ct) return ENOMEM; hash_append(sip->ht_ctrans, hash_joaat_str(branch), &ct->he, ct); ct->invite = !strcmp(met, "INVITE"); ct->branch = mem_ref(branch); ct->met = mem_ref(met); ct->mb = mem_ref(mb); ct->dst = *dst; ct->tp = tp; ct->sip = sip; ct->state = ct->invite ? CALLING : TRYING; ct->resph = resph ? resph : dummy_handler; ct->arg = arg; err = sip_transp_send(&ct->qent, sip, NULL, tp, dst, mb, transport_handler, ct); if (err) goto out; tmr_start(&ct->tmr, 64 * SIP_T1, tmr_handler, ct); if (!sip_transp_reliable(ct->tp)) tmr_start(&ct->tmre, SIP_T1, retransmit_handler, ct); out: if (err) mem_deref(ct); else if (ctp) *ctp = ct; return err; }
/** * Send a SIP message * * @param sip SIP stack instance * @param sock Optional socket to send from * @param tp SIP transport * @param dst Destination network address * @param mb Buffer containing SIP message * * @return 0 if success, otherwise errorcode */ int sip_send(struct sip *sip, void *sock, enum sip_transp tp, const struct sa *dst, struct mbuf *mb) { return sip_transp_send(NULL, sip, sock, tp, dst, mb, NULL, NULL); }