int call_answer(struct call *call, uint16_t scode) { struct mbuf *desc; int err; if (!call || !call->sess) return EINVAL; if (STATE_INCOMING != call->state) { return 0; } info("answering call from %s with %u\n", call->peer_uri, scode); if (call->got_offer) { err = update_media(call); if (err) return err; } err = sdp_encode(&desc, call->sdp, !call->got_offer); if (err) return err; err = sipsess_answer(call->sess, scode, "Answering", desc, "Allow: %s\r\n", uag_allowed_methods()); mem_deref(desc); return err; }
void tcsipcall_control(struct tcsipcall*call, int action) { int err; struct mbuf *mb = NULL; /* * XXX: drop bytes when confirmation received * */ switch(action) { case CALL_ACCEPT: if(call->cstate & (CSTATE_ERR|CSTATE_EST)) return; if(call->cdir != CALL_IN) return; if(! (call->cstate & CSTATE_ICE)) { DROP(call->cstate, CSTATE_RING); return; } // 200 err = tcmedia_offer(call->media, call->msg->mb, &mb); if(err) { DROP(call->cstate, CSTATE_RING); err |= CSTATE_ERR; break; } /* * Workarround * * libre uses msg->dst to fill in Contact header * value. * This works well for UDP where one socket used * for both send and recieve, but no for TCP * TCP transport uses one socket for listen * and other to connect to registar. * Address msg->dst is the recieving part * of upstream socket UAC->REGISTAR * and cannot be used to connect from outside * * */ sa_set_port((struct sa*)&call->msg->dst, sa_port(&call->uac->laddr)); sipsess_answer(call->sess, 200, "OK", mb, NULL); mem_deref(mb); DROP(call->cstate, CSTATE_RING); call->cstate |= CSTATE_EST; break; case CALL_REJECT: case CALL_BYE: if( TEST(call->cstate, CSTATE_IN_RING) ) { sipsess_reject(call->sess, 486, "Reject", NULL); DROP(call->cstate, CSTATE_IN_RING); call->reason = CEND_HANG; } if( TEST(call->cstate, CSTATE_EST) ) { // bye sent automatically in deref DROP(call->cstate, CSTATE_EST); call->reason = CEND_OK; } if( TEST(call->cstate, CSTATE_OUT_RING ) ) { // cancel DROP(call->cstate, CSTATE_EST); call->reason = CEND_CANCEL; } tcsipcall_hangup(call); break; } }