static void bye_handler(struct sipsess_sock *sock, const struct sip_msg *msg) { struct sip *sip = sock->sip; struct sipsess *sess; sess = sipsess_find(sock, msg); if (!sess) { (void)sip_reply(sip, msg, 481, "Call Does Not Exist"); return; } if (!sip_dialog_rseq_valid(sess->dlg, msg)) { (void)sip_reply(sip, msg, 500, "Server Internal Error"); return; } (void)sip_treply(NULL, sip, msg, 200, "OK"); sess->peerterm = true; if (sess->terminated) return; if (sess->st) { (void)sip_treply(&sess->st, sess->sip, sess->msg, 487, "Request Terminated"); } sipsess_terminate(sess, E_SIP_SESSION_CLOSED_BYE, NULL); }
/* Handle incoming calls */ static void sipsess_conn_handler(const struct sip_msg *msg, void *arg) { const struct sip_hdr *hdr; struct ua *ua; struct call *call = NULL; char to_uri[256]; int err; (void)arg; ua = uag_find(&msg->uri.user); if (!ua) { warning("ua: %r: UA not found: %r\n", &msg->from.auri, &msg->uri.user); (void)sip_treply(NULL, uag_sip(), msg, 404, "Not Found"); return; } /* handle multiple calls */ if (list_count(&ua->calls) + 1 > MAX_CALLS) { info("ua: rejected call from %r (maximum %d calls)\n", &msg->from.auri, MAX_CALLS); (void)sip_treply(NULL, uag.sip, msg, 486, "Busy Here"); return; } /* Handle Require: header, check for any required extensions */ hdr = sip_msg_hdr_apply(msg, true, SIP_HDR_REQUIRE, require_handler, ua); if (hdr) { info("ua: call from %r rejected with 420" " -- option-tag '%r' not supported\n", &msg->from.auri, &hdr->val); (void)sip_treplyf(NULL, NULL, uag.sip, msg, false, 420, "Bad Extension", "Unsupported: %r\r\n" "Content-Length: 0\r\n\r\n", &hdr->val); return; } (void)pl_strcpy(&msg->to.auri, to_uri, sizeof(to_uri)); err = ua_call_alloc(&call, ua, VIDMODE_ON, msg, NULL, to_uri); if (err) { warning("ua: call_alloc: %m\n", err); goto error; } err = call_accept(call, uag.sock, msg); if (err) goto error; return; error: mem_deref(call); (void)sip_treply(NULL, uag.sip, msg, 500, "Call Error"); }
/* called upon incoming calls */ static void connect_handler(const struct sip_msg *msg, void *arg) { struct mbuf *mb; bool got_offer; int err; (void)arg; if (sess) { /* Already in a call */ (void)sip_treply(NULL, sip, msg, 486, "Busy Here"); return; } got_offer = (mbuf_get_left(msg->mb) > 0); /* Decode SDP offer if incoming INVITE contains SDP */ if (got_offer) { err = sdp_decode(sdp, msg->mb, true); if (err) { re_fprintf(stderr, "unable to decode SDP offer: %s\n", strerror(err)); goto out; } update_media(); } /* Encode SDP */ err = sdp_encode(&mb, sdp, !got_offer); if (err) { re_fprintf(stderr, "unable to encode SDP: %s\n", strerror(err)); goto out; } /* Answer incoming call */ err = sipsess_accept(&sess, sess_sock, msg, 200, "OK", name, "application/sdp", mb, auth_handler, NULL, false, offer_handler, answer_handler, establish_handler, NULL, NULL, close_handler, NULL, NULL); mem_deref(mb); /* free SDP buffer */ if (err) { re_fprintf(stderr, "session accept error: %s\n", strerror(err)); goto out; } out: if (err) { (void)sip_treply(NULL, sip, msg, 500, strerror(err)); } else { re_printf("accepting incoming call from <%r>\n", &msg->from.auri); } }
static void reinvite_handler(struct sipsess_sock *sock, const struct sip_msg *msg) { struct sip *sip = sock->sip; struct sipsess *sess; struct mbuf *desc; char m[256]; int err; sess = sipsess_find(sock, msg); if (!sess || sess->terminated) { (void)sip_treply(NULL, sip, msg, 481, "Call Does Not Exist"); return; } if (!sip_dialog_rseq_valid(sess->dlg, msg)) { (void)sip_treply(NULL, sip, msg, 500, "Server Internal Error"); return; } if (sess->st || sess->awaiting_answer) { (void)sip_treplyf(NULL, NULL, sip, msg, false, 500, "Server Internal Error", "Retry-After: 5\r\n" "Content-Length: 0\r\n" "\r\n"); return; } if (sess->req) { (void)sip_treply(NULL, sip, msg, 491, "Request Pending"); return; } err = sess->offerh(&desc, msg, sess->arg); if (err) { (void)sip_reply(sip, msg, 488, str_error(err, m, sizeof(m))); return; } (void)sip_dialog_update(sess->dlg, msg); (void)sipsess_reply_2xx(sess, msg, 200, "OK", desc, NULL, NULL); /* pending modifications considered outdated; sdp may have changed in above exchange */ sess->desc = mem_deref(sess->desc); sess->modify_pending = false; tmr_cancel(&sess->tmr); mem_deref(desc); }
static void bye_handler(struct sipsess_sock *sock, const struct sip_msg *msg) { struct sip *sip = sock->sip; struct sipsess *sess; sess = sipsess_find(sock, msg); if (!sess) { (void)sip_reply(sip, msg, 481, "Call Does Not Exist"); return; } if (!sip_dialog_rseq_valid(sess->dlg, msg)) { (void)sip_reply(sip, msg, 500, "Server Internal Error"); return; } (void)sip_treplyf(NULL, NULL, sip, msg, false, 200, "OK", "%s" "Content-Length: 0\r\n" "\r\n", sess->close_hdrs); sess->peerterm = true; if (sess->terminated) return; if (sess->st) { (void)sip_treply(&sess->st, sess->sip, sess->msg, 487, "Request Terminated"); } sipsess_terminate(sess, ECONNRESET, NULL); }
static bool request_handler(const struct sip_msg *msg, void *arg) { struct message *message = arg; struct ua *ua; struct le *le = message->lsnrl.head; bool hdld = false; if (pl_strcmp(&msg->met, "MESSAGE")) return false; ua = uag_find(&msg->uri.user); if (!ua) { (void)sip_treply(NULL, uag_sip(), msg, 404, "Not Found"); return true; } while (le) { struct message_lsnr *lsnr = le->data; le = le->next; handle_message(lsnr, ua, msg); hdld = true; } return hdld; }
static bool sub_handler(const struct sip_msg *msg, void *arg) { struct ua *ua; (void)arg; ua = uag_find(&msg->uri.user); if (!ua) { warning("presence: no UA found for %r\n", &msg->uri.user); (void)sip_treply(NULL, uag_sip(), msg, 404, "Not Found"); return true; } if (notifier_add(evsock, msg, ua)) (void)sip_treply(NULL, uag_sip(), msg, 400, "Bad Presence"); return true; }
static void notify_handler(struct sip *sip, const struct sip_msg *msg, void *arg) { enum presence_status status = PRESENCE_CLOSED; struct presence *pres = arg; const struct sip_hdr *hdr; struct pl pl; pres->failc = 0; hdr = sip_msg_hdr(msg, SIP_HDR_CONTENT_TYPE); if (!hdr || 0 != pl_strcasecmp(&hdr->val, "application/pidf+xml")) { if (hdr) (void)re_printf("presence: unsupported" " content-type: '%r'\n", &hdr->val); sip_treplyf(NULL, NULL, sip, msg, false, 415, "Unsupported Media Type", "Accept: application/pidf+xml\r\n" "Content-Length: 0\r\n" "\r\n"); return; } if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "<status>[^<]*<basic>[^<]*</basic>[^<]*</status>", NULL, &pl, NULL)) { if (!pl_strcasecmp(&pl, "open")) status = PRESENCE_OPEN; } if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "<rpid:away/>")) { status = PRESENCE_CLOSED; } else if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "<rpid:busy/>")) { status = PRESENCE_BUSY; } else if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "<rpid:on-the-phone/>")) { status = PRESENCE_BUSY; } (void)sip_treply(NULL, sip, msg, 200, "OK"); contact_set_presence(pres->contact, status); }
static void notify_handler(struct sip *sip, const struct sip_msg *msg, void *arg) { struct mwi *mwi = arg; if (mbuf_get_left(msg->mb)) { re_printf("----- MWI for %s -----\n", ua_aor(mwi->ua)); re_printf("%b\n", mbuf_buf(msg->mb), mbuf_get_left(msg->mb)); } (void)sip_treply(NULL, sip, msg, 200, "OK"); }
static void bye_handler(struct sipsess_sock *sock, const struct sip_msg *msg) { struct sip *sip = sock->sip; struct sipsess *sess; // char tmp[256]; sess = sipsess_find(sock, msg); if (!sess) { (void)sip_reply(sip, msg, 481, "Call Does Not Exist"); return; } if (!sip_dialog_rseq_valid(sess->dlg, msg)) { (void)sip_reply(sip, msg, 500, "Server Internal Error"); return; } /* QXIP */ if (sess->xrtpstats && !sess->xrtpstats[0] == '\0') { /* Inject X-RTP-Stat header */ (void)sip_treplyf(NULL, NULL, sip, msg, false, 200, "OK", "X-RTP-Stat: %s\r\nContent-Length: 0\r\n\r\n", sess->xrtpstats); } else { /* Vanilla 200 OK */ (void)sip_treply(NULL, sip, msg, 200, "OK"); } sess->peerterm = true; if (sess->terminated) return; if (sess->st) { (void)sip_treply(&sess->st, sess->sip, sess->msg, 487, "Request Terminated"); } sipsess_terminate(sess, ECONNRESET, NULL); }
static void cancel_handler(void *arg) { struct sipsess *sess = arg; (void)sip_treply(&sess->st, sess->sip, sess->msg, 487, "Request Terminated"); sess->peerterm = true; if (sess->terminated) return; sipsess_terminate(sess, ECONNRESET, NULL); }
static void notify_handler(struct sip *sip, const struct sip_msg *msg, void *arg) { struct mwi *mwi = arg; if (mbuf_get_left(msg->mb)) { ui_output("----- MWI for %s -----\n", ua_aor(mwi->ua)); ui_output("%b\n", mbuf_buf(msg->mb), mbuf_get_left(msg->mb)); } (void)sip_treply(NULL, sip, msg, 200, "OK"); if (mwi->shutdown) mem_deref(mwi); }
static bool request_handler(const struct sip_msg *msg, void *arg) { struct ua *ua; (void)arg; if (pl_strcmp(&msg->met, "MESSAGE")) return false; ua = uag_find(&msg->uri.user); if (!ua) { (void)sip_treply(NULL, uag_sip(), msg, 404, "Not Found"); return true; } handle_message(ua, msg); return true; }
static void handle_options(struct ua *ua, const struct sip_msg *msg) { struct sip_contact contact; struct call *call = NULL; struct mbuf *desc = NULL; int err; err = ua_call_alloc(&call, ua, VIDMODE_ON, NULL, NULL, NULL); if (err) { (void)sip_treply(NULL, uag.sip, msg, 500, "Call Error"); return; } err = call_sdp_get(call, &desc, true); if (err) goto out; sip_contact_set(&contact, ua_cuser(ua), &msg->dst, msg->tp); err = sip_treplyf(NULL, NULL, uag.sip, msg, true, 200, "OK", "Allow: %s\r\n" "%H" "%H" "Content-Type: application/sdp\r\n" "Content-Length: %zu\r\n" "\r\n" "%b", uag_allowed_methods(), ua_print_supported, ua, sip_contact_print, &contact, mbuf_get_left(desc), mbuf_buf(desc), mbuf_get_left(desc)); if (err) { warning("ua: options: sip_treplyf: %m\n", err); } out: mem_deref(desc); mem_deref(call); }
static void internal_connect_handler(const struct sip_msg *msg, void *arg) { struct sipsess_sock *sock = arg; (void)sip_treply(NULL, sock->sip, msg, 486, "Busy Here"); }
static void notify_handler(struct sip *sip, const struct sip_msg *msg, void *arg) { enum presence_status status = PRESENCE_CLOSED; struct presence *pres = arg; const struct sip_hdr *type_hdr, *length_hdr; struct pl pl; pres->failc = 0; type_hdr = sip_msg_hdr(msg, SIP_HDR_CONTENT_TYPE); if (!type_hdr) { length_hdr = sip_msg_hdr(msg, SIP_HDR_CONTENT_LENGTH); if (0 == pl_strcmp(&length_hdr->val, "0")) { status = PRESENCE_UNKNOWN; goto done; } } if (!type_hdr || 0 != pl_strcasecmp(&type_hdr->val, "application/pidf+xml")) { if (type_hdr) warning("presence: unsupported content-type: '%r'\n", &type_hdr->val); sip_treplyf(NULL, NULL, sip, msg, false, 415, "Unsupported Media Type", "Accept: application/pidf+xml\r\n" "Content-Length: 0\r\n" "\r\n"); return; } if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "<basic>[^<]+</basic>", &pl)) { if (!pl_strcasecmp(&pl, "open")) status = PRESENCE_OPEN; } if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "<rpid:away/>")) { status = PRESENCE_CLOSED; } else if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "<rpid:busy/>")) { status = PRESENCE_BUSY; } else if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "<rpid:on-the-phone/>")) { status = PRESENCE_BUSY; } done: (void)sip_treply(NULL, sip, msg, 200, "OK"); contact_set_presence(pres->contact, status); }
int call_accept(struct call *call, struct sipsess_sock *sess_sock, const struct sip_msg *msg) { bool got_offer; int err; if (!call || !msg) return EINVAL; got_offer = (mbuf_get_left(msg->mb) > 0); err = pl_strdup(&call->peer_uri, &msg->from.auri); if (err) return err; if (pl_isset(&msg->from.dname)) { err = pl_strdup(&call->peer_name, &msg->from.dname); if (err) return err; } if (got_offer) { err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; call->got_offer = true; /* Check if we have any common audio codecs, after * the SDP offer has been parsed */ if (!have_common_audio_codecs(call)) { info("call: no common audio codecs - rejected\n"); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "No audio codecs"); return 0; } } err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing", ua_cuser(call->ua), "application/sdp", NULL, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: sipsess_accept: %m\n", err); return err; } set_state(call, STATE_INCOMING); /* New call */ tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call); if (!call->acc->mnat) call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); return err; }
int call_accept(struct call *call, struct sipsess_sock *sess_sock, const struct sip_msg *msg) { bool got_offer; int err; if (!call || !msg) return EINVAL; call->outgoing = false; got_offer = (mbuf_get_left(msg->mb) > 0); err = pl_strdup(&call->peer_uri, &msg->from.auri); if (err) return err; if (pl_isset(&msg->from.dname)) { err = pl_strdup(&call->peer_name, &msg->from.dname); if (err) return err; } if (got_offer) { struct sdp_media *m; const struct sa *raddr; err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; call->got_offer = true; /* * Each media description in the SDP answer MUST * use the same network type as the corresponding * media description in the offer. * * See RFC 6157 */ m = stream_sdpmedia(audio_strm(call->audio)); raddr = sdp_media_raddr(m); if (sa_af(raddr) != call->af) { info("call: incompatible address-family" " (local=%s, remote=%s)\n", net_af2name(call->af), net_af2name(sa_af(raddr))); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "Wrong address family"); return 0; } /* Check if we have any common audio codecs, after * the SDP offer has been parsed */ if (!have_common_audio_codecs(call)) { info("call: no common audio codecs - rejected\n"); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "No audio codecs"); return 0; } } err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing", ua_cuser(call->ua), "application/sdp", NULL, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: sipsess_accept: %m\n", err); return err; } set_state(call, STATE_INCOMING); /* New call */ tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call); if (!call->acc->mnat) call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); return err; }