static int oa_init(struct oa *oa) { struct sa laddr; int err; if (!oa->alice) { (void)sa_set_str(&laddr, "1.2.3.4", 0); err = sdp_session_alloc(&oa->alice, &laddr); if (err) return err; } if (!oa->bob) { (void)sa_set_str(&laddr, "5.6.7.8", 0); err = sdp_session_alloc(&oa->bob, &laddr); if (err) return err; } return 0; }
/** * Test parsing of various SDP messages from various vendors */ int test_sdp_parse(void) { struct sdp_session *sess = NULL; struct sdp_media *audio; struct mbuf *mb; struct sa laddr; uint32_t i; int err; mb = mbuf_alloc(2048); if (!mb) return ENOMEM; sa_init(&laddr, AF_INET); for (i=0; i<ARRAY_SIZE(msgs); i++) { sess = mem_deref(sess); err = sdp_session_alloc(&sess, &laddr); if (err) goto out; err = sdp_media_add(&audio, sess, sdp_media_audio, 5004, sdp_proto_rtpavp); if (err) goto out; err = sdp_format_add(NULL, audio, false, ref_pt, ref_cname, ref_srate, 1, NULL, NULL, NULL, false, NULL); if (err) goto out; err = sdp_format_add(NULL, audio, false, "8", "PCMA", 8000, 1, NULL, NULL, NULL, false, NULL); if (err) goto out; mbuf_rewind(mb); (void)mbuf_write_str(mb, msgs[i]); mb->pos = 0; err = sdp_decode(sess, mb, true); if (err) goto out; } out: mem_deref(sess); mem_deref(mb); return err; }
/** * Allocate a new Call state object * * @param callp Pointer to allocated Call state object * @param cfg Global configuration * @param lst List of call objects * @param local_name Local display name (optional) * @param local_uri Local SIP uri * @param acc Account parameters * @param ua User-Agent * @param prm Call parameters * @param msg SIP message for incoming calls * @param xcall Optional call to inherit properties from * @param eh Call event handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode */ int call_alloc(struct call **callp, const struct config *cfg, struct list *lst, const char *local_name, const char *local_uri, struct account *acc, struct ua *ua, const struct call_prm *prm, const struct sip_msg *msg, struct call *xcall, call_event_h *eh, void *arg) { struct call *call; enum vidmode vidmode = prm ? prm->vidmode : VIDMODE_OFF; bool use_video = true, got_offer = false; int label = 0; int err = 0; if (!cfg || !local_uri || !acc || !ua) return EINVAL; call = mem_zalloc(sizeof(*call), call_destructor); if (!call) return ENOMEM; MAGIC_INIT(call); call->config_avt = cfg->avt; tmr_init(&call->tmr_inv); call->acc = mem_ref(acc); call->ua = ua; call->state = STATE_IDLE; call->eh = eh; call->arg = arg; call->af = prm ? prm->af : AF_INET; err = str_dup(&call->local_uri, local_uri); if (local_name) err |= str_dup(&call->local_name, local_name); if (err) goto out; /* Init SDP info */ err = sdp_session_alloc(&call->sdp, net_laddr_af(call->af)); if (err) goto out; err = sdp_session_set_lattr(call->sdp, true, "tool", "baresip " BARESIP_VERSION); if (err) goto out; /* Check for incoming SDP Offer */ if (msg && mbuf_get_left(msg->mb)) got_offer = true; /* Initialise media NAT handling */ if (acc->mnat) { err = acc->mnat->sessh(&call->mnats, net_dnsc(), call->af, acc->stun_host, acc->stun_port, acc->stun_user, acc->stun_pass, call->sdp, !got_offer, mnat_handler, call); if (err) { warning("call: medianat session: %m\n", err); goto out; } } call->mnat_wait = true; /* Media encryption */ if (acc->menc) { if (acc->menc->sessh) { err = acc->menc->sessh(&call->mencs, call->sdp, !got_offer, menc_error_handler, call); if (err) { warning("call: mediaenc session: %m\n", err); goto out; } } } /* Audio stream */ err = audio_alloc(&call->audio, cfg, call, call->sdp, ++label, acc->mnat, call->mnats, acc->menc, call->mencs, acc->ptime, account_aucodecl(call->acc), audio_event_handler, audio_error_handler, call); if (err) goto out; #ifdef USE_VIDEO /* We require at least one video codec, and at least one video source or video display */ use_video = (vidmode != VIDMODE_OFF) && (list_head(account_vidcodecl(call->acc)) != NULL) && (NULL != vidsrc_find(NULL) || NULL != vidisp_find(NULL)); /* Video stream */ if (use_video) { err = video_alloc(&call->video, cfg, call, call->sdp, ++label, acc->mnat, call->mnats, acc->menc, call->mencs, "main", account_vidcodecl(call->acc), video_error_handler, call); if (err) goto out; } if (str_isset(cfg->bfcp.proto)) { err = bfcp_alloc(&call->bfcp, call->sdp, cfg->bfcp.proto, !got_offer, acc->mnat, call->mnats); if (err) goto out; } #else (void)use_video; (void)vidmode; #endif /* inherit certain properties from original call */ if (xcall) { call->not = mem_ref(xcall->not); } list_append(lst, &call->le, call); out: if (err) mem_deref(call); else if (callp) *callp = call; return err; }
int main(int argc, char *argv[]) { struct sa nsv[16]; struct dnsc *dnsc = NULL; struct sa laddr; uint32_t nsc; int err; /* errno return values */ /* enable coredumps to aid debugging */ (void)sys_coredump_set(true); /* initialize libre state */ err = libre_init(); if (err) { re_fprintf(stderr, "re init failed: %s\n", strerror(err)); goto out; } nsc = ARRAY_SIZE(nsv); /* fetch list of DNS server IP addresses */ err = dns_srv_get(NULL, 0, nsv, &nsc); if (err) { re_fprintf(stderr, "unable to get dns servers: %s\n", strerror(err)); goto out; } /* create DNS client */ err = dnsc_alloc(&dnsc, NULL, nsv, nsc); if (err) { re_fprintf(stderr, "unable to create dns client: %s\n", strerror(err)); goto out; } /* create SIP stack instance */ err = sip_alloc(&sip, dnsc, 32, 32, 32, "ua demo v" VERSION " (" ARCH "/" OS ")", exit_handler, NULL); if (err) { re_fprintf(stderr, "sip error: %s\n", strerror(err)); goto out; } /* fetch local IP address */ err = net_default_source_addr_get(AF_INET, &laddr); if (err) { re_fprintf(stderr, "local address error: %s\n", strerror(err)); goto out; } /* listen on random port */ sa_set_port(&laddr, 0); /* add supported SIP transports */ err |= sip_transp_add(sip, SIP_TRANSP_UDP, &laddr); err |= sip_transp_add(sip, SIP_TRANSP_TCP, &laddr); if (err) { re_fprintf(stderr, "transport error: %s\n", strerror(err)); goto out; } /* create SIP session socket */ err = sipsess_listen(&sess_sock, sip, 32, connect_handler, NULL); if (err) { re_fprintf(stderr, "session listen error: %s\n", strerror(err)); goto out; } /* create the RTP/RTCP socket */ err = rtp_listen(&rtp, IPPROTO_UDP, &laddr, 10000, 30000, true, rtp_handler, rtcp_handler, NULL); if (err) { re_fprintf(stderr, "rtp listen error: %m\n", err); goto out; } re_printf("local RTP port is %u\n", sa_port(rtp_local(rtp))); /* create SDP session */ err = sdp_session_alloc(&sdp, &laddr); if (err) { re_fprintf(stderr, "sdp session error: %s\n", strerror(err)); goto out; } /* add audio sdp media, using port from RTP socket */ err = sdp_media_add(&sdp_media, sdp, "audio", sa_port(rtp_local(rtp)), "RTP/AVP"); if (err) { re_fprintf(stderr, "sdp media error: %s\n", strerror(err)); goto out; } /* add G.711 sdp media format */ err = sdp_format_add(NULL, sdp_media, false, "0", "PCMU", 8000, 1, NULL, NULL, NULL, false, NULL); if (err) { re_fprintf(stderr, "sdp format error: %s\n", strerror(err)); goto out; } /* invite provided URI */ if (argc > 1) { struct mbuf *mb; /* create SDP offer */ err = sdp_encode(&mb, sdp, true); if (err) { re_fprintf(stderr, "sdp encode error: %s\n", strerror(err)); goto out; } err = sipsess_connect(&sess, sess_sock, argv[1], name, uri, name, NULL, 0, "application/sdp", mb, auth_handler, NULL, false, offer_handler, answer_handler, progress_handler, establish_handler, NULL, NULL, close_handler, NULL, NULL); mem_deref(mb); /* free SDP buffer */ if (err) { re_fprintf(stderr, "session connect error: %s\n", strerror(err)); goto out; } re_printf("inviting <%s>...\n", argv[1]); } else { err = sipreg_register(®, sip, registrar, uri, uri, 60, name, NULL, 0, 0, auth_handler, NULL, false, register_handler, NULL, NULL, NULL); if (err) { re_fprintf(stderr, "register error: %s\n", strerror(err)); goto out; } re_printf("registering <%s>...\n", uri); } /* main loop */ err = re_main(signal_handler); out: /* clean up/free all state */ mem_deref(sdp); /* will also free sdp_media */ mem_deref(rtp); mem_deref(sess_sock); mem_deref(sip); mem_deref(dnsc); /* free librar state */ libre_close(); /* check for memory leaks */ tmr_debug(); mem_debug(); return err; }
/** Test BFCP in SDP -- RFC 4583 */ int test_sdp_bfcp(void) { static const char *msg_offer = "v=0\r\n" "o=alice 2890844526 2890844526 IN IP4 1.2.3.4\r\n" "s=-\r\n" "c=IN IP4 1.2.3.4\r\n" "t=0 0\r\n" "m=application 50000 TCP/BFCP *\r\n" "a=sendrecv\r\n" "a=setup:passive\r\n" "a=connection:new\r\n" "a=floorctrl:s-only\r\n" "a=confid:4321\r\n" "a=userid:1234\r\n" "a=floorid:1 m-stream:10\r\n" "a=floorid:2 m-stream:11\r\n" "m=audio 50002 RTP/AVP 0\r\n" "a=sendrecv\r\n" "a=label:10\r\n" "m=video 50004 RTP/AVP 31\r\n" "a=sendrecv\r\n" "a=label:11\r\n" ; struct sdp_session *alice = NULL, *bob = NULL; struct sdp_media *bfcp, *audio, *video; struct mbuf *mbo = NULL, *mba = NULL; struct sa laddr; int err; /* create sessions */ (void)sa_set_str(&laddr, "1.2.3.4", 0); err = sdp_session_alloc(&alice, &laddr); if (err) goto out; err = sdp_media_add(&bfcp, alice, "application", 50000, "TCP/BFCP"); if (err) goto out; err |= sdp_media_set_lattr(bfcp, true, "setup", "passive"); err |= sdp_media_set_lattr(bfcp, true, "connection", "new"); err |= sdp_media_set_lattr(bfcp, true, "floorctrl", "s-only"); err |= sdp_media_set_lattr(bfcp, true, "confid", "4321"); err |= sdp_media_set_lattr(bfcp, true, "userid", "1234"); err |= sdp_media_set_lattr(bfcp, false, "floorid", "1 m-stream:10"); sdp_media_del_lattr(bfcp, "floorid"); /* test attr delete */ err |= sdp_media_set_lattr(bfcp, false, "floorid", "1 m-stream:10"); err |= sdp_media_set_lattr(bfcp, false, "floorid", "2 m-stream:11"); if (err) goto out; err = sdp_media_add(&audio, alice, "audio", 50002, "RTP/AVP"); if (err) goto out; err = sdp_media_add(&video, alice, "video", 50004, "RTP/AVP"); if (err) goto out; err |= sdp_media_set_lattr(audio, true, "label", "10"); err |= sdp_media_set_lattr(video, true, "label", "11"); if (err) goto out; err = sdp_format_add(NULL, bfcp, false, "*", NULL, 0, 0, NULL, NULL, NULL, false, NULL); err |= sdp_format_add(NULL, audio, false, "0", NULL, 0, 0, NULL, NULL, NULL, false, NULL); err |= sdp_format_add(NULL, video, false, "31", NULL, 0, 0, NULL, NULL, NULL, false, NULL); if (err) goto out; /* create and send offer, compare offer */ err = sdp_encode(&mbo, alice, true); if (err) goto out; if (!sdp_cmp(mbo, msg_offer)) { DEBUG_WARNING("offer failed:\n%b", mbo->buf, mbo->end); err = EBADMSG; goto out; } out: mem_deref(alice); mem_deref(bob); mem_deref(mbo); mem_deref(mba); return err; }
int test_sdp_all(void) { struct sdp_session *sess = NULL; struct sdp_media *audio = NULL; struct mbuf *desc = NULL; struct sa ref; const struct sdp_format *rc = NULL, *sc; struct sa laddr; int err; (void)sa_set_str(&laddr, ref_host, 0); err = sdp_session_alloc(&sess, &laddr); if (err) goto out; err = sdp_media_add(&audio, sess, sdp_media_audio, 5004, sdp_proto_rtpavp); if (err) goto out; err = sdp_format_add(NULL, audio, false, ref_pt, ref_cname, ref_srate, 1, NULL, NULL, NULL, false, NULL); err |= sdp_format_add(NULL, audio, false, "110", cname_speex, 16000, 2, NULL, NULL, NULL, false, NULL); if (err) goto out; /* find codec - expected */ sc = sdp_media_format(audio, true, NULL, 0, "PCMU", 8000, 1); if (!sc) { DEBUG_WARNING("codec not found\n"); err = ENOENT; goto out; } sc = sdp_media_format(audio, true, NULL, 110, "Speex", 16000, 2); if (!sc) { DEBUG_WARNING("codec not found: speex\n"); err = ENOENT; goto out; } /* find codec - not expected */ sc = sdp_media_format(audio, true, NULL, -1, "Speex", 8000, 1); if (sc) { DEBUG_WARNING("unexpected codec found\n"); err = EINVAL; goto out; } err = sdp_encode(&desc, sess, true); if (err) goto out; if (!sdp_cmp(desc, ref_msg)) { DEBUG_WARNING("ref: %s\n", ref_msg); DEBUG_WARNING("sdp: %b\n", desc->buf, desc->end); err = EBADMSG; goto out; } err = sdp_decode(sess, desc, false); if (err) goto out; rc = sdp_media_rformat(audio, NULL); if (!rc) { err = ENOENT; goto out; } err = sa_set_str(&ref, ref_host, ref_port); if (err) goto out; err = EINVAL; if (!sa_cmp(sdp_media_raddr(audio), &ref, SA_ALL)) goto out; if (!rc) goto out; if (0 != strcmp(rc->id, ref_pt)) goto out; if (0 != strcmp(ref_cname, rc->name)) goto out; if (rc->srate != ref_srate) goto out; err = 0; out: mem_deref(audio); mem_deref(sess); mem_deref(desc); return err; }