int test_udp(void) { struct udp_sock *uss2; struct udp_test *ut; int err; ut = mem_zalloc(sizeof(*ut), destructor); if (!ut) return ENOMEM; err = sa_set_str(&ut->cli, "127.0.0.1", 0); err |= sa_set_str(&ut->srv, "127.0.0.1", 0); if (err) goto out; err = udp_listen(&ut->usc, &ut->cli, udp_recv_client, ut); err |= udp_listen(&ut->uss, &ut->srv, udp_recv_server, ut); if (err) goto out; udp_rxbuf_presz_set(ut->uss, 16); err = udp_local_get(ut->usc, &ut->cli); err |= udp_local_get(ut->uss, &ut->srv); if (err) goto out; err = udp_register_helper(&ut->uh, ut->usc, 0, udp_helper_send, udp_helper_recv, ut); if (err) goto out; /* expect failure */ if (!udp_listen(&uss2, &ut->srv, udp_recv_client, ut)) { err = EBUSY; goto out; } /* Send from connected client UDP socket */ err = udp_connect(ut->usc, &ut->srv); if (err) goto out; /* Start test */ err = send_data(ut->usc, &ut->srv, data0); if (err) goto out; err = re_main_timeout(100); if (err) goto out; if (ut->err) err = ut->err; out: mem_deref(ut); return err; }
int test_stun_resp(void) { struct sa maddr; struct pl resp; int err; resp.p = (char *)respv4; resp.l = sizeof(respv4) - 1; err = sa_set_str(&maddr, "192.0.2.1", 32853); if (err) return err; err = test_resp(&resp, &maddr); if (err) return err; #ifdef HAVE_INET6 resp.p = (char *)respv6; resp.l = sizeof(respv6) - 1; err = sa_set_str(&maddr, "2001:db8:1234:5678:11:2233:4455:6677", 32853); if (err) return err; err = test_resp(&resp, &maddr); #endif return err; }
int sip_server_create(struct sip_server **srvp) { struct sip_server *srv; struct sa laddr_tp; int err; srv = mem_zalloc(sizeof *srv, destructor); if (!srv) return ENOMEM; err = sa_set_str(&laddr_tp, "127.0.0.1", 0); err |= sa_set_str(&srv->laddr, "127.0.0.1", 0); if (err) goto out; err = sip_alloc(&srv->sip, NULL, 16, 16, 16, "dummy SIP registrar", NULL, NULL); if (err) goto out; err = sip_transp_add(srv->sip, SIP_TRANSP_UDP, &laddr_tp); if (err) { warning("failed to add sip transport (%m)\n", err); goto out; } err = udp_listen(&srv->us, &srv->laddr, udp_recv, srv); if (err) { warning("sip: udp_listen on '%J' failed (%d/%m)\n", &srv->laddr, err, err); goto out; } err = udp_local_get(srv->us, &srv->laddr); if (err) { warning("sip: udp_local_get\n"); goto out; } #if 0 re_printf("sip: listen on %J\n", &srv->laddr); #endif out: if (err) mem_deref(srv); else *srvp = srv; return err; }
void TurnServer::init() { int err; err = sa_set_str(&addr, "127.0.0.1", 0); if (err) goto out; err = udp_listen(&us, &addr, turnserver_udp_recv, this); if (err) goto out; err = udp_local_get(us, &addr); if (err) goto out; turnd = (struct turnd *)mem_zalloc(sizeof(*turnd), destructor); /* turn_external_addr */ err = sa_set_str(&turnd->rel_addr, "127.0.0.1", 0); if (err) { goto out; } /* turn_max_lifetime, turn_max_allocations, udp_sockbuf_size */ turnd->lifetime_max = TURN_DEFAULT_LIFETIME; err = hash_alloc(&turnd->ht_alloc, 32); if (err) { error("turnd hash alloc error: %m\n", err); goto out; } err = restund_tcp_init(turnd, fake_certificate_rsa); ASSERT_EQ(0, err); addr_tcp = *restund_tcp_laddr(turnd, false); addr_tls = *restund_tcp_laddr(turnd, true); turnd->recvh = tcp_handler; turnd->arg = this; info("turn: listen=%J, lifetime=%u ext=%j\n", &addr, turnd->lifetime_max, &turnd->rel_addr); out: ASSERT_EQ(0, err); }
int dns_server_alloc(struct dns_server **srvp, bool rotate) { struct dns_server *srv; int err; if (!srvp) return EINVAL; srv = mem_zalloc(sizeof(*srv), destructor); if (!srv) return ENOMEM; err = sa_set_str(&srv->addr, "127.0.0.1", LOCAL_PORT); if (err) goto out; err = udp_listen(&srv->us, &srv->addr, udp_recv, srv); if (err) goto out; err = udp_local_get(srv->us, &srv->addr); if (err) goto out; srv->rotate = rotate; out: if (err) mem_deref(srv); else *srvp = srv; return err; }
TEST(media, ice_lite_options_in_sdp) { struct mediaflow *mf = NULL; struct sa laddr; int err; sa_set_str(&laddr, "127.0.0.1", 0); err = mediaflow_alloc(&mf, NULL, NULL, &laddr, MEDIAFLOW_ICELITE, CRYPTO_NONE, false, NULL, NULL, NULL, NULL); ASSERT_EQ(0, err); ASSERT_TRUE(mf != NULL); char sdp[4096]; err = mediaflow_generate_offer(mf, sdp, sizeof(sdp)); ASSERT_EQ(0, err); ASSERT_TRUE(find_in_sdp(sdp, "ice-lite")); ASSERT_FALSE(find_in_sdp(sdp, "trickle")); mem_deref(mf); }
virtual void SetUp() override { struct sa laddr; int err; #if 0 log_set_min_level(LOG_LEVEL_WARN); log_enable_stderr(true); #endif aucodec_register(&aucodecl, &dummy_opus); vidcodec_register(&vidcodecl, &dummy_vp8); sa_set_str(&laddr, "127.0.0.1", 0); err = create_dtls_srtp_context(&dtls, CERT_TYPE_RSA); ASSERT_EQ(0, err); err = mediaflow_alloc(&mf, dtls, &aucodecl, &laddr, MEDIAFLOW_TRICKLEICE_DUALSTACK, CRYPTO_DTLS_SRTP, false, mediaflow_localcand_handler, mediaflow_estab_handler, mediaflow_close_handler, this); ASSERT_EQ(0, err); ASSERT_TRUE(mf != NULL); }
static void lstnr_handler(struct sa *bnd_addr, struct udp_sock *us, void *arg) { const char *maddr; struct sa dst; int err; (void)arg; switch (sa_af(bnd_addr)) { case AF_INET: maddr = "224.0.0.1"; break; case AF_INET6: maddr = "ff02::1"; break; default: return; } sa_set_str(&dst, maddr, PCP_PORT_CLI); err = pcp_reply(us, &dst, NULL, PCP_ANNOUNCE, PCP_SUCCESS, 0, repcpd_epoch_time(), NULL); if (err) { warning("announce: failed to send ANNOUNCE from" " %J to %s (%m)\n", bnd_addr, maddr, err); return; } info("announce: sent ANNOUNCE from %J to %s\n", bnd_addr, maddr); }
/** * List interfaces using GetAdaptersInfo, which handles only IPv4 family. * * This is available from Windows 2000, and also works under Wine. */ static int if_list_gai(net_ifaddr_h *ifh, void *arg) { IP_ADAPTER_INFO info[32]; PIP_ADAPTER_INFO p = info; ULONG ulOutBufLen = sizeof(info); DWORD ret; ret = GetAdaptersInfo(info, &ulOutBufLen); if (ret != ERROR_SUCCESS) { DEBUG_WARNING("if_list: GetAdaptersInfo ret=%u\n", ret); return ENODEV; } for (p = info; p; p = p->Next) { struct sa sa; if (sa_set_str(&sa, p->IpAddressList.IpAddress.String, 0)) continue; if (ifh && ifh(p->AdapterName, &sa, arg)) break; } return 0; }
void http_init(struct httpc *app, struct request **rpp, char *str_uri) { int ok; struct request *request; struct pl pl_uri; struct url url; *rpp = NULL; pl_uri.p = NULL; str_dup((char**)&pl_uri.p, str_uri); pl_uri.l = strlen(str_uri); ok = url_decode(&url, &pl_uri); if(ok!=0) goto err_uri; request = mem_zalloc(sizeof(*request), destructor); ok = hash_alloc(&request->hdrht, HDR_HASH_SIZE); request->err_h = dummy_err; request->done_h = http_done; request->post = NULL; request->form = 0; request->www_auth.p = NULL; request->www_auth.l = 0; request->auth = NULL; request->retry = 0; pl_strdup(&request->host, &url.host); pl_strdup(&request->path, &url.path); request->secure = !pl_strcmp(&url.scheme, "https"); memcpy(&request->meth, "GET", 4); request->meth[4] = 0; if(url.port) request->port = url.port; else request->port = request->secure ? 443 : 80; DEBUG_INFO("secure: %d port %d\n", request->secure, request->port); sa_init(&request->dest, AF_INET); ok = sa_set_str(&request->dest, request->host, request->port); request->state = ok ? START : RESOLVED; request->app = app; *rpp = request; err_uri: if(pl_uri.p) mem_deref((void*)pl_uri.p); return; }
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; }
static int sipstack_fixture(struct sip **sipp) { struct sa laddr, laddrs; struct sip *sip = NULL; struct tls *tls = NULL; int err; (void)sa_set_str(&laddr, "127.0.0.1", LOCAL_PORT); (void)sa_set_str(&laddrs, "127.0.0.1", LOCAL_SECURE_PORT); err = sip_alloc(&sip, NULL, 32, 32, 32, "retest", exit_handler, NULL); if (err) goto out; err |= sip_transp_add(sip, SIP_TRANSP_UDP, &laddr); err |= sip_transp_add(sip, SIP_TRANSP_TCP, &laddr); if (err) goto out; #ifdef USE_TLS /* TLS-context for client -- no certificate needed */ err = tls_alloc(&tls, TLS_METHOD_SSLV23, NULL, NULL); if (err) goto out; err |= sip_transp_add(sip, SIP_TRANSP_TLS, &laddrs, tls); if (err) goto out; #endif out: mem_deref(tls); if (err) mem_deref(sip); else *sipp = sip; return err; }
static int get_android_dns(struct sa *nsv, uint32_t *n) { char value[PROP_VALUE_MAX] = {0}; if (__system_property_get("net.dns1", value)) { int err = sa_set_str(&nsv[0], value, DNS_PORT); if (err) return err; *n = 1; return 0; } return ENOENT; }
static int cons_alloc(struct ui_st **stp, struct ui_prm *prm, ui_input_h *h, void *arg) { struct sa local; struct ui_st *st; int err; if (!stp) return EINVAL; if (cons_cur) { *stp = mem_ref(cons_cur); return 0; } st = mem_zalloc(sizeof(*st), cons_destructor); if (!st) return ENOMEM; st->ui = mem_ref(cons); st->h = h; st->arg = arg; err = sa_set_str(&local, "0.0.0.0", prm->port ? prm->port : CONS_PORT); if (err) goto out; err = udp_listen(&st->us, &local, udp_recv, st); if (err) { DEBUG_WARNING("failed to listen on UDP port %d (%m)\n", sa_port(&local), err); goto out; } err = tcp_listen(&st->ts, &local, tcp_conn_handler, st); if (err) { DEBUG_WARNING("failed to listen on TCP port %d (%m)\n", sa_port(&local), err); goto out; } out: if (err) mem_deref(st); else *stp = cons_cur = st; return err; }
static int cons_init(void) { struct sa laddr; int err; if (conf_get_sa(conf_cur(), "cons_listen", &laddr)) { sa_set_str(&laddr, "0.0.0.0", CONS_PORT); } err = cons_alloc(&cons, &laddr); if (err) return err; ui_register(&ui_cons); return 0; }
int main(void) { struct sa laddr; 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; } (void)sa_set_str(&laddr, "0.0.0.0", 3456); /* Create listening TCP socket, IP address 0.0.0.0, TCP port 3456 */ err = tcp_listen(&ts, &laddr, connect_handler, NULL); if (err) { re_fprintf(stderr, "tcp listen error: %s\n", strerror(err)); goto out; } re_printf("listening on TCP socket: %J\n", &laddr); /* main loop */ err = re_main(signal_handler); out: /* destroy active TCP connections */ list_flush(&connl); /* free TCP socket */ ts = mem_deref(ts); /* free library state */ libre_close(); /* check for memory leaks */ tmr_debug(); mem_debug(); return err; }
TEST(media, ice_cand_decode) { struct ice_cand_attr cand; struct sa addr; int err; err = ice_cand_attr_decode(&cand, "42 1 udp 2113937151 10.0.0.63 2004 typ host"); ASSERT_EQ(0, err); sa_set_str(&addr, "10.0.0.63", 2004); ASSERT_STREQ("42", cand.foundation); ASSERT_EQ(1, cand.compid); ASSERT_EQ(IPPROTO_UDP, cand.proto); ASSERT_EQ(2113937151, cand.prio); ASSERT_TRUE(sa_cmp(&addr, &cand.addr, SA_ALL)); ASSERT_EQ(ICE_CAND_TYPE_HOST, cand.type); }
static int module_init(void) { struct sa laddr; int err; if (conf_get_sa(conf_cur(), "http_listen", &laddr)) { sa_set_str(&laddr, "0.0.0.0", 8000); } err = http_listen(&httpsock, &laddr, http_req_handler, NULL); if (err) return err; ui_register(&ui_http); info("httpd: listening on %J\n", &laddr); return 0; }
int turnserver_alloc(struct turnserver **turnp) { struct turnserver *turn; struct sa laddr; int err = 0; if (!turnp) return EINVAL; turn = mem_zalloc(sizeof(*turn), destructor); if (!turn) return ENOMEM; err = sa_set_str(&laddr, "127.0.0.1", 0); if (err) goto out; err = udp_listen(&turn->us, &laddr, srv_udp_recv, turn); if (err) goto out; err = udp_local_get(turn->us, &turn->laddr); if (err) goto out; err = tcp_listen(&turn->ts, &laddr, tcp_conn_handler, turn); if (err) goto out; err = tcp_sock_local_get(turn->ts, &turn->laddr_tcp); if (err) goto out; out: if (err) mem_deref(turn); else *turnp = turn; return err; }
static int rst_connect(struct rst *rst) { struct sa srv; int err; if (!sa_set_str(&srv, rst->host, rst->port)) { err = tcp_connect(&rst->tc, &srv, estab_handler, recv_handler, close_handler, rst); if (err) { re_printf("rst: tcp connect error: %m\n", err); } } else { err = dnsc_query(&rst->dnsq, net_dnsc(), rst->host, DNS_TYPE_A, DNS_CLASS_IN, true, dns_handler, rst); if (err) { re_printf("rst: dns query error: %m\n", err); } } 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; }
TEST_F(TestMedia, firefox45_interop) { char answer[4096]; struct sa laddr; int err; static const char *sdp_firefox = "v=0\r\n" "o=mozilla...THIS_IS_SDPARTA-45.0.2 7767043308804270395 0 IN IP4 0.0.0.0\r\n" "s=-\r\n" "t=0 0\r\n" "a=sendrecv\r\n" "a=fingerprint:sha-256 CD:7B:7C:A8:4F:A0:6D:DD:32:6F:3E:DD:F3:2D:07:F6:10:4D:D1:8F:E1:7F:95:32:7E:CB:33:17:BA:5B:65:19\r\n" "a=group:BUNDLE audio video\r\n" "a=ice-options:trickle\r\n" "a=msid-semantic:WMS *\r\n" "m=audio 50194 RTP/SAVPF 96\r\n" "c=IN IP4 54.155.57.143\r\n" "a=candidate:0 1 UDP 2122252543 192.168.10.88 60503 typ host\r\n" "a=candidate:1 1 UDP 1686052863 62.96.148.44 60503 typ srflx raddr 192.168.10.88 rport 60503\r\n" "a=candidate:2 1 UDP 92217343 54.155.57.143 50194 typ relay raddr 54.155.57.143 rport 50194\r\n" "a=sendrecv\r\n" "a=end-of-candidates\r\n" "a=ice-pwd:0393917a2d22af7bd38e661130e77d41\r\n" "a=ice-ufrag:cc92c585\r\n" "a=mid:audio\r\n" "a=msid:{da2198be-27c6-3844-871d-313e73fef45d} {d6ff7b2c-f689-a843-832c-843f59b52bbb}\r\n" "a=rtcp-mux\r\n" "a=rtpmap:96 opus/48000/2\r\n" "a=setup:actpass\r\n" "a=ssrc:2997989063 cname:{84d8043a-40ef-9b42-aff7-1104f80aaf43}\r\n" "m=video 50194 RTP/SAVPF 100\r\n" "c=IN IP4 54.155.57.143\r\n" "a=recvonly\r\n" "a=fmtp:100 max-fs=12288;max-fr=60\r\n" "a=ice-pwd:0393917a2d22af7bd38e661130e77d41\r\n" "a=ice-ufrag:cc92c585\r\n" "a=mid:video\r\n" "a=rtcp-fb:100 nack\r\n" "a=rtcp-fb:100 nack pli\r\n" "a=rtcp-fb:100 ccm fir\r\n" "a=rtcp-mux\r\n" "a=rtpmap:100 VP8/90000\r\n" "a=setup:actpass\r\n" "a=ssrc:934653567 cname:{84d8043a-40ef-9b42-aff7-1104f80aaf43}\r\n" ; sa_set_str(&laddr, "127.0.0.1", 0); /* Populate only 1 ICE candidate (plus EOC) */ err = mediaflow_add_local_host_candidate(mf, "eth0", &laddr); ASSERT_EQ(0, err); mediaflow_set_local_eoc(mf); err = mediaflow_add_video(mf, &vidcodecl); ASSERT_EQ(0, err); err = mediaflow_offeranswer(mf, answer, sizeof(answer), sdp_firefox); ASSERT_EQ(0, err); ASSERT_EQ(CRYPTO_DTLS_SRTP, mediaflow_crypto(mf)); ASSERT_TRUE(mediaflow_have_eoc(mf)); #if 0 re_printf("%s\n", answer); #endif /* verify some SDP attributes */ ASSERT_TRUE(find_in_sdp(answer, "a=fingerprint:sha-256")); ASSERT_TRUE(find_in_sdp(answer, "a=group:BUNDLE audio video")); ASSERT_TRUE(find_in_sdp(answer, "a=ice-options:trickle")); ASSERT_TRUE(find_in_sdp(answer, "a=end-of-candidates")); ASSERT_TRUE(find_in_sdp(answer, "a=ice-pwd")); ASSERT_TRUE(find_in_sdp(answer, "a=ice-ufrag")); ASSERT_TRUE(find_in_sdp(answer, "a=mid:audio")); ASSERT_TRUE(find_in_sdp(answer, "a=rtcp-mux")); ASSERT_TRUE(find_in_sdp(answer, "a=setup:active")); ASSERT_TRUE(find_in_sdp(answer, "m=video")); ASSERT_TRUE(find_in_sdp(answer, "a=mid:video")); ASSERT_TRUE(find_in_sdp(answer, "VP8/90000")); }
static int add_transp_af(const struct sa *laddr) { struct sa local; int err = 0; if (str_isset(uag.cfg->local)) { err = sa_decode(&local, uag.cfg->local, str_len(uag.cfg->local)); if (err) { err = sa_set_str(&local, uag.cfg->local, 0); if (err) { warning("ua: decode failed: '%s'\n", uag.cfg->local); return err; } } if (!sa_isset(&local, SA_ADDR)) { uint16_t port = sa_port(&local); (void)sa_set_sa(&local, &laddr->u.sa); sa_set_port(&local, port); } if (sa_af(laddr) != sa_af(&local)) return 0; } else { sa_cpy(&local, laddr); sa_set_port(&local, 0); } if (uag.use_udp) err |= sip_transp_add(uag.sip, SIP_TRANSP_UDP, &local); if (uag.use_tcp) err |= sip_transp_add(uag.sip, SIP_TRANSP_TCP, &local); if (err) { warning("ua: SIP Transport failed: %m\n", err); return err; } #ifdef USE_TLS if (uag.use_tls) { /* Build our SSL context*/ if (!uag.tls) { const char *cert = NULL; if (str_isset(uag.cfg->cert)) { cert = uag.cfg->cert; info("SIP Certificate: %s\n", cert); } err = tls_alloc(&uag.tls, TLS_METHOD_SSLV23, cert, NULL); if (err) { warning("ua: tls_alloc() failed: %m\n", err); return err; } } if (sa_isset(&local, SA_PORT)) sa_set_port(&local, sa_port(&local) + 1); err = sip_transp_add(uag.sip, SIP_TRANSP_TLS, &local, uag.tls); if (err) { warning("ua: SIP/TLS transport failed: %m\n", err); return err; } } #endif return err; }
static int test_stun_request(int proto, bool natted) { struct stunserver *srv = NULL; struct stun_ctrans *ct = NULL; struct nat *nat = NULL; struct test test; struct sa laddr, public_addr; int err; memset(&test, 0, sizeof(test)); err = stunserver_alloc(&srv); if (err) goto out; err = stun_alloc(&test.stun, NULL, NULL, NULL); if (err) goto out; if (proto == IPPROTO_UDP) { err = sa_set_str(&laddr, "127.0.0.1", 0); TEST_ERR(err); err = udp_listen(&test.us, &laddr, udp_recv_handler, &test); if (err) goto out; err = udp_local_get(test.us, &laddr); TEST_ERR(err); } if (natted) { err = sa_set_str(&public_addr, "4.5.6.7", 0); TEST_ERR(err); err = nat_alloc(&nat, srv->us, &public_addr); if (err) goto out; sa_set_port(&public_addr, sa_port(&laddr)); } else { public_addr = laddr; } err = stun_request(&ct, test.stun, proto, test.us, stunserver_addr(srv, proto), 0, STUN_METHOD_BINDING, NULL, 0, true, stun_resp_handler, &test, 0); if (err) goto out; TEST_ASSERT(ct != NULL); err = re_main_timeout(100); if (err) goto out; if (srv->err) { err = srv->err; goto out; } if (test.err) { err = test.err; goto out; } /* verify results */ TEST_ASSERT(srv->nrecv >= 1); TEST_EQUALS(1, test.n_resp); if (proto == IPPROTO_UDP) { TEST_SACMP(&public_addr, &test.mapped_addr, SA_ALL); } out: mem_deref(test.stun); mem_deref(test.us); mem_deref(nat); mem_deref(srv); return err; }
int test_sipsess(void) { struct test test; struct sa laddr; char to_uri[256]; int err; uint16_t port; memset(&test, 0, sizeof(test)); #ifndef WIN32 /* slurp warnings from SIP (todo: temp) */ (void)freopen("/dev/null", "w", stderr); #endif err = sip_alloc(&test.sip, NULL, 32, 32, 32, "retest", exit_handler, NULL); if (err) goto out; (void)sa_set_str(&laddr, "127.0.0.1", 0); err = sip_transp_add(test.sip, SIP_TRANSP_UDP, &laddr); if (err) goto out; err = sip_transp_laddr(test.sip, &laddr, SIP_TRANSP_UDP, NULL); if (err) goto out; port = sa_port(&laddr); err = sipsess_listen(&test.sock, test.sip, 32, conn_handler, &test); if (err) goto out; /* Connect to "b" */ (void)re_snprintf(to_uri, sizeof(to_uri), "sip:[email protected]:%u", port); err = sipsess_connect(&test.a, test.sock, to_uri, NULL, "sip:[email protected]", "a", NULL, 0, "application/sdp", NULL, NULL, NULL, false, offer_handler, answer_handler, NULL, estab_handler_a, NULL, NULL, close_handler, &test, NULL); if (err) goto out; err = re_main_timeout(200); if (err) goto out; if (test.err) { err = test.err; goto out; } /* okay here -- verify */ TEST_ASSERT(test.estab_a); TEST_ASSERT(test.estab_b); out: test.a = mem_deref(test.a); test.b = mem_deref(test.b); sipsess_close_all(test.sock); test.sock = mem_deref(test.sock); sip_close(test.sip, false); test.sip = mem_deref(test.sip); #ifndef WIN32 /* Restore stderr */ freopen("/dev/tty", "w", stderr); #endif 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; }
static void process_msg(struct turnserver *turn, int proto, void *sock, const struct sa *src, struct mbuf *mb) { struct stun_msg *msg = NULL; struct sa laddr; int err = 0; if (stun_msg_decode(&msg, mb, NULL)) { uint16_t numb, len; struct channel *chan; if (!turn->us_relay) return; ++turn->n_raw; numb = ntohs(mbuf_read_u16(mb)); len = ntohs(mbuf_read_u16(mb)); if (mbuf_get_left(mb) < len) { DEBUG_WARNING("short length: %zu < %u\n", mbuf_get_left(mb), len); } chan = find_channel_numb(turn, numb); if (!chan) { DEBUG_WARNING("channel not found: numb=%u\n", numb); return; } /* relay data from channel to peer */ (void)udp_send(turn->us_relay, &chan->peer, mb); return; } #if 0 re_printf("process: %s:%p:%J %s\n", net_proto2name(proto), sock, src, stun_method_name(stun_msg_method(msg))); #endif switch (stun_msg_method(msg)) { case STUN_METHOD_ALLOCATE: /* Max 1 allocation for now */ ++turn->n_allocate; if (turn->us_relay) { err = EALREADY; goto out; } turn->cli = *src; err = sa_set_str(&laddr, "127.0.0.1", 0); if (err) goto out; err = udp_listen(&turn->us_relay, &laddr, relay_udp_recv, turn); if (err) goto out; err = udp_local_get(turn->us_relay, &turn->relay); if (err) goto out; udp_rxbuf_presz_set(turn->us_relay, 4); err = stun_reply(proto, sock, src, 0, msg, NULL, 0, false, 2, STUN_ATTR_XOR_MAPPED_ADDR, src, STUN_ATTR_XOR_RELAY_ADDR, &turn->relay); break; case STUN_METHOD_CREATEPERM: { struct stun_attr *peer; ++turn->n_createperm; peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR); TEST_ASSERT(peer != NULL); add_permission(turn, &peer->v.xor_peer_addr); /* todo: install permissions and check them */ err = stun_reply(proto, sock, src, 0, msg, NULL, 0, false, 0); } break; case STUN_METHOD_CHANBIND: { struct stun_attr *chnr, *peer; ++turn->n_chanbind; TEST_ASSERT(turn->us_relay != NULL); chnr = stun_msg_attr(msg, STUN_ATTR_CHANNEL_NUMBER); peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR); if (!chnr || !peer) { DEBUG_WARNING("CHANBIND: missing chnr/peer attrib\n"); } TEST_ASSERT(turn->chanc < ARRAY_SIZE(turn->chanv)); turn->chanv[turn->chanc].nr = chnr->v.channel_number; turn->chanv[turn->chanc].peer = peer->v.xor_peer_addr; ++turn->chanc; err = stun_reply(proto, sock, src, 0, msg, NULL, 0, false, 0); } break; case STUN_METHOD_SEND: { struct stun_attr *peer, *data; ++turn->n_send; TEST_ASSERT(turn->us_relay != NULL); peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR); data = stun_msg_attr(msg, STUN_ATTR_DATA); if (!peer || !data) { DEBUG_WARNING("SEND: missing peer/data attrib\n"); goto out; } /* check for valid Permission */ if (!find_permission(turn, &peer->v.xor_peer_addr)) { DEBUG_NOTICE("no permission to peer %j\n", &peer->v.xor_peer_addr); goto out; } err = udp_send(turn->us_relay, &peer->v.xor_peer_addr, &data->v.data); } break; default: DEBUG_WARNING("unknown STUN method: %s\n", stun_method_name(stun_msg_method(msg))); err = EPROTO; break; } if (err) goto out; out: if (err && stun_msg_class(msg) == STUN_CLASS_REQUEST) { (void)stun_ereply(proto, sock, src, 0, msg, 500, "Server Error", NULL, 0, false, 0); } mem_deref(msg); }
/** * Do a DNS Discovery of a STUN Server * * @param dnsp Pointer to allocated DNS Discovery object * @param dnsc DNS Client * @param service Name of service to discover (e.g. "stun") * @param proto Transport protocol (e.g. "udp") * @param af Preferred Address Family * @param domain Domain name or IP address of STUN server * @param port Port number (if 0 do SRV lookup) * @param dnsh DNS Response handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode */ int stun_server_discover(struct stun_dns **dnsp, struct dnsc *dnsc, const char *service, const char *proto, int af, const char *domain, uint16_t port, stun_dns_h *dnsh, void *arg) { struct stun_dns *dns; int err; if (!dnsp || !service || !proto || !domain || !domain[0] || !dnsh) return EINVAL; dns = mem_zalloc(sizeof(*dns), dnsdisc_destructor); if (!dns) return ENOMEM; dns->port = service[strlen(service)-1] == 's' ? STUNS_PORT : STUN_PORT; dns->dnsh = dnsh; dns->arg = arg; dns->dnsc = dnsc; dns->af = af; /* Numeric IP address - no lookup */ if (0 == sa_set_str(&dns->srv, domain, port ? port : dns->port)) { DEBUG_INFO("IP (%s)\n", domain); resolved(dns, 0); err = 0; goto out; /* free now */ } /* Port specified - use AAAA or A lookup */ else if (port) { sa_set_in(&dns->srv, 0, port); DEBUG_INFO("resolving A query: (%s)\n", domain); err = a_or_aaaa_query(dns, domain); if (err) { DEBUG_WARNING("%s: A/AAAA lookup failed (%m)\n", domain, err); goto out; } } /* SRV lookup */ else { char q[256]; str_ncpy(dns->domain, domain, sizeof(dns->domain)); (void)re_snprintf(q, sizeof(q), "_%s._%s.%s", service, proto, domain); DEBUG_INFO("resolving SRV query: (%s)\n", q); err = dnsc_query(&dns->dq, dnsc, q, DNS_TYPE_SRV, DNS_CLASS_IN, true, srv_handler, dns); if (err) { DEBUG_WARNING("%s: SRV lookup failed (%m)\n", q, err); goto out; } } *dnsp = dns; return 0; out: mem_deref(dns); return err; }
/** * Send a SIP request * * @param reqp Pointer to allocated SIP request object * @param sip SIP Stack * @param stateful Stateful client transaction * @param met SIP Method string * @param metl Length of SIP Method string * @param uri Request URI * @param uril Length of Request URI string * @param route Next hop route URI * @param mb Buffer containing SIP request * @param sendh Send handler * @param resph Response handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode */ int sip_request(struct sip_request **reqp, struct sip *sip, bool stateful, const char *met, int metl, const char *uri, int uril, const struct uri *route, struct mbuf *mb, sip_send_h *sendh, sip_resp_h *resph, void *arg) { struct sip_request *req; struct sa dst; struct pl pl; int err; if (!sip || !met || !uri || !route || !mb) return EINVAL; if (pl_strcasecmp(&route->scheme, "sip")) return ENOSYS; req = mem_zalloc(sizeof(*req), destructor); if (!req) return ENOMEM; list_append(&sip->reql, &req->le, req); err = str_ldup(&req->met, met, metl); if (err) goto out; err = str_ldup(&req->uri, uri, uril); if (err) goto out; if (sip_param_decode(&route->params, "maddr", &pl)) pl = route->host; err = pl_strdup(&req->host, &pl); if (err) goto out; req->stateful = stateful; req->mb = mem_ref(mb); req->sip = sip; req->sendh = sendh; req->resph = resph; req->arg = arg; if (!sip_param_decode(&route->params, "transport", &pl)) { if (!pl_strcasecmp(&pl, "udp")) req->tp = SIP_TRANSP_UDP; else if (!pl_strcasecmp(&pl, "tcp")) req->tp = SIP_TRANSP_TCP; else if (!pl_strcasecmp(&pl, "tls")) req->tp = SIP_TRANSP_TLS; else { err = EPROTONOSUPPORT; goto out; } if (!sip_transp_supported(sip, req->tp, AF_UNSPEC)) { err = EPROTONOSUPPORT; goto out; } req->tp_selected = true; } else { req->tp = SIP_TRANSP_NONE; if (!transp_next(sip, &req->tp)) { err = EPROTONOSUPPORT; goto out; } req->tp_selected = false; } if (!sa_set_str(&dst, req->host, sip_transp_port(req->tp, route->port))) { err = request(req, req->tp, &dst); if (!req->stateful) { mem_deref(req); return err; } } else if (route->port) { req->port = sip_transp_port(req->tp, route->port); err = addr_lookup(req, req->host); } else if (req->tp_selected) { err = srv_lookup(req, req->host); } else { err = dnsc_query(&req->dnsq, sip->dnsc, req->host, DNS_TYPE_NAPTR, DNS_CLASS_IN, true, naptr_handler, req); } out: if (err) mem_deref(req); else if (reqp) { req->reqp = reqp; *reqp = req; } return err; }
/** * Send an HTTP request * * @param reqp Pointer to allocated HTTP request object * @param cli HTTP Client * @param met Request method * @param uri Request URI * @param resph Response handler * @param datah Content handler (optional) * @param arg Handler argument * @param fmt Formatted HTTP headers and body (optional) * * @return 0 if success, otherwise errorcode */ int http_request(struct http_req **reqp, struct http_cli *cli, const char *met, const char *uri, http_resp_h *resph, http_data_h *datah, void *arg, const char *fmt, ...) { struct pl scheme, host, port, path; struct http_req *req; uint16_t defport; bool secure; va_list ap; int err; if (!reqp || !cli || !met || !uri) return EINVAL; if (re_regex(uri, strlen(uri), "[a-z]+://[^:/]+[:]*[0-9]*[^]+", &scheme, &host, NULL, &port, &path) || scheme.p != uri) return EINVAL; if (!pl_strcasecmp(&scheme, "http") || !pl_strcasecmp(&scheme, "ws")) { secure = false; defport = 80; } #ifdef USE_TLS else if (!pl_strcasecmp(&scheme, "https") || !pl_strcasecmp(&scheme, "wss")) { secure = true; defport = 443; } #endif else return ENOTSUP; req = mem_zalloc(sizeof(*req), req_destructor); if (!req) return ENOMEM; req->tls = mem_ref(cli->tls); req->secure = secure; req->port = pl_isset(&port) ? pl_u32(&port) : defport; req->resph = resph; req->datah = datah; req->arg = arg; err = pl_strdup(&req->host, &host); if (err) goto out; req->mbreq = mbuf_alloc(1024); if (!req->mbreq) { err = ENOMEM; goto out; } err = mbuf_printf(req->mbreq, "%s %r HTTP/1.1\r\n" "Host: %r\r\n", met, &path, &host); if (fmt) { va_start(ap, fmt); err |= mbuf_vprintf(req->mbreq, fmt, ap); va_end(ap); } else { err |= mbuf_write_str(req->mbreq, "\r\n"); } if (err) goto out; req->mbreq->pos = 0; if (!sa_set_str(&req->srvv[0], req->host, req->port)) { req->srvc = 1; err = req_connect(req); if (err) goto out; } else { err = dnsc_query(&req->dq, cli->dnsc, req->host, DNS_TYPE_A, DNS_CLASS_IN, true, query_handler, req); if (err) goto out; } out: if (err) mem_deref(req); else { req->reqp = reqp; *reqp = req; } return err; }