int pf_create(struct pf **pfp, struct udp_sock *us, const char *name) { struct pf *pf; int err; if (!pfp || !us) return EINVAL; pf = mem_zalloc(sizeof(*pf), pf_destructor); if (!pf) return ENOMEM; pf->us = mem_ref(us); str_ncpy(pf->name, name, sizeof(pf->name)); err = udp_register_helper(&pf->uh, us, -1000, /* very low layer */ pf_send_handler, pf_recv_handler, pf); if (err) mem_deref(pf); else *pfp = pf; return err; }
/** * Start TLS on a UDP socket (aka DTLS). The UDP socket can act as a * client or a server, and multiple DTLS connections can be established to * multiple peers, all from the same UDP socket. * * @param tsp Pointer to allocated TLS socket * @param tls TLS context * @param us UDP socket * @param layer Protocol stack layer * @param bsize Bucket size for hash table (0 for default) * * @return 0 if success, otherwise errorcode */ int tls_start_udp(struct tls_sock **tsp, struct tls *tls, struct udp_sock *us, int layer, uint32_t bsize) { struct tls_sock *ts; int err; if (!tsp || !tls || !us) return EINVAL; ts = mem_zalloc(sizeof(*ts), destructor); if (!ts) return ENOMEM; err = hash_alloc(&ts->ht_conn, bsize ? bsize : 4); if (err) goto out; err = udp_register_helper(&ts->uh, us, layer, send_handler, recv_handler, ts); if (err) goto out; ts->us = mem_ref(us); ts->tls = mem_ref(tls); out: if (err) mem_deref(ts); else *tsp = ts; return err; }
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; }
static int media_alloc(struct menc_media **stp, struct menc_sess *sess, struct rtp_sock *rtp, int proto, void *rtpsock, void *rtcpsock, struct sdp_media *sdpm) { struct menc_media *st; zrtp_status_t s; int layer = 10; /* above zero */ int err = 0; (void)rtcpsock; if (!stp || !sess || proto != IPPROTO_UDP) return EINVAL; st = *stp; if (st) goto start; st = mem_zalloc(sizeof(*st), media_destructor); if (!st) return ENOMEM; st->sess = sess; st->rtpsock = mem_ref(rtpsock); err = udp_register_helper(&st->uh, rtpsock, layer, udp_helper_send, udp_helper_recv, st); if (err) goto out; s = zrtp_stream_attach(sess->zrtp_session, &st->zrtp_stream); if (s != zrtp_status_ok) { warning("zrtp: zrtp_stream_attach failed (status=%d)\n", s); err = EPROTO; goto out; } zrtp_stream_set_userdata(st->zrtp_stream, st); out: if (err) { mem_deref(st); return err; } else *stp = st; start: if (sa_isset(sdp_media_raddr(sdpm), SA_ALL)) { st->raddr = *sdp_media_raddr(sdpm); s = zrtp_stream_start(st->zrtp_stream, rtp_sess_ssrc(rtp)); if (s != zrtp_status_ok) { warning("zrtp: zrtp_stream_start: status = %d\n", s); } } return err; }
int dtls_flow_alloc(struct dtls_flow **flowp, struct tls *tls, struct udp_sock *us, dtls_estab_h *estabh, void *arg) { struct dtls_flow *flow; int err = ENOMEM; if (!flowp || !tls || !us || !estabh) return EINVAL; flow = mem_zalloc(sizeof(*flow), destructor); if (!flow) return ENOMEM; flow->tls = tls; flow->us = mem_ref(us); flow->estabh = estabh; flow->arg = arg; err = udp_register_helper(&flow->uh, us, LAYER_DTLS, NULL, recv_handler, flow); if (err) goto out; flow->ssl = SSL_new(tls->ctx); if (!flow->ssl) { ERR_clear_error(); goto out; } flow->sbio_in = BIO_new(BIO_s_mem()); if (!flow->sbio_in) goto out; flow->sbio_out = BIO_new(&bio_udp_send); if (!flow->sbio_out) { BIO_free(flow->sbio_in); goto out; } flow->sbio_out->ptr = flow; SSL_set_bio(flow->ssl, flow->sbio_in, flow->sbio_out); tmr_init(&flow->tmr); err = 0; out: if (err) mem_deref(flow); else *flowp = flow; return err; }
int icem_comp_alloc(struct icem_comp **cp, struct icem *icem, int id, void *sock) { struct icem_comp *comp; struct sa local; int err; if (!cp || !icem || id<1 || id>255 || !sock) return EINVAL; comp = mem_zalloc(sizeof(*comp), destructor); if (!comp) return ENOMEM; comp->id = id; comp->sock = mem_ref(sock); comp->icem = icem; err = udp_register_helper(&comp->uh, sock, icem->layer, NULL, helper_recv_handler, comp); if (err) goto out; err = udp_local_get(comp->sock, &local); if (err) goto out; comp->lport = sa_port(&local); out: if (err) mem_deref(comp); else *cp = comp; return err; }
/** * Allocate a TURN Client * * @param turncp Pointer to allocated TURN Client * @param conf Optional STUN Configuration * @param proto Transport Protocol * @param sock Transport socket * @param layer Transport layer * @param srv TURN Server IP-address * @param username Authentication username * @param password Authentication password * @param lifetime Allocate lifetime in [seconds] * @param th TURN handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode */ int turnc_alloc(struct turnc **turncp, const struct stun_conf *conf, int proto, void *sock, int layer, const struct sa *srv, const char *username, const char *password, uint32_t lifetime, turnc_h *th, void *arg) { struct turnc *turnc; int err; if (!turncp || !sock || !srv || !username || !password || !th) return EINVAL; turnc = mem_zalloc(sizeof(*turnc), destructor); if (!turnc) return ENOMEM; err = stun_alloc(&turnc->stun, conf, NULL, NULL); if (err) goto out; err = str_dup(&turnc->username, username); if (err) goto out; err = str_dup(&turnc->password, password); if (err) goto out; err = turnc_perm_hash_alloc(&turnc->perms, PERM_HASH_SIZE); if (err) goto out; err = turnc_chan_hash_alloc(&turnc->chans, CHAN_HASH_SIZE); if (err) goto out; tmr_init(&turnc->tmr); turnc->proto = proto; turnc->sock = mem_ref(sock); turnc->psrv = *srv; turnc->srv = *srv; turnc->lifetime = lifetime; turnc->th = th; turnc->arg = arg; switch (proto) { case IPPROTO_UDP: err = udp_register_helper(&turnc->uh, sock, layer, udp_send_handler, udp_recv_handler, turnc); break; default: err = 0; break; } if (err) goto out; err = allocate_request(turnc); if (err) goto out; out: if (err) mem_deref(turnc); else *turncp = turnc; return err; }
/* * you can call this at any time * * @param addr HOST: SA_ADDR portion is used * non-HOST: SA_ADDR + SA_PORT portion is used * * @param base_addr Optional * @param rel_addr Optional * * @param layer mandatory for HOST and RELAY candidates */ int trice_lcand_add(struct ice_lcand **lcandp, struct trice *icem, unsigned compid, int proto, uint32_t prio, const struct sa *addr, const struct sa *base_addr, enum ice_cand_type type, const struct sa *rel_addr, enum ice_tcptype tcptype, void *sock, int layer) { struct ice_lcand *lcand; int err = 0; if (!icem || !compid || !proto || !addr) return EINVAL; if (!sa_isset(addr, SA_ADDR)) { DEBUG_WARNING("lcand_add: SA_ADDR is not set\n"); return EINVAL; } if (type != ICE_CAND_TYPE_HOST) { if (!sa_isset(addr, SA_PORT)) { DEBUG_WARNING("lcand_add: %s: SA_PORT" " must be set (%J)\n", ice_cand_type2name(type), addr); return EINVAL; } } /* lookup candidate, replace if PRIO is higher */ /* TODO: dont look up TCP-ACTIVE types for now (port is zero) */ if (proto == IPPROTO_UDP) { lcand = trice_lcand_find(icem, -1, compid, proto, addr); if (lcand) { trice_printf(icem, "add_local[%s.%J] --" " candidate already exists" " (%H)\n", ice_cand_type2name(type), addr, trice_cand_print, lcand); if (prio > lcand->attr.prio) lcand = mem_deref(lcand); else { goto out; } } } err = trice_add_lcandidate(&lcand, icem, &icem->lcandl, compid, NULL, proto, prio, addr, base_addr, type, rel_addr, tcptype); if (err) return err; if (type == ICE_CAND_TYPE_HOST) { switch (proto) { case IPPROTO_UDP: if (sock) { struct sa laddr; lcand->us = mem_ref(sock); err = udp_local_get(lcand->us, &laddr); if (err) goto out; lcand->attr.addr = *addr; sa_set_port(&lcand->attr.addr, sa_port(&laddr)); } else { err = udp_listen(&lcand->us, addr, dummy_udp_recv, lcand); if (err) goto out; err = udp_local_get(lcand->us, &lcand->attr.addr); if (err) goto out; } err = udp_register_helper(&lcand->uh, lcand->us, layer, udp_helper_send_handler, udp_helper_recv_handler, lcand); if (err) goto out; break; case IPPROTO_TCP: /* TCP-transport has 3 variants: active, passive, so */ if (lcand->attr.tcptype == ICE_TCP_ACTIVE) { /* the port MUST be set to 9 (i.e., Discard) */ /*sa_set_port(&lcand->attr.addr, 9); */ } else if (lcand->attr.tcptype == ICE_TCP_PASSIVE || lcand->attr.tcptype == ICE_TCP_SO) { err = tcp_listen(&lcand->ts, addr, tcp_conn_handler, lcand); if (err) goto out; err = tcp_local_get(lcand->ts, &lcand->attr.addr); if (err) goto out; } else { err = EPROTONOSUPPORT; goto out; } break; default: err = EPROTONOSUPPORT; goto out; } } else if (type == ICE_CAND_TYPE_RELAY) { switch (proto) { case IPPROTO_UDP: if (sock) { lcand->us = mem_ref(sock); } else { err = udp_listen(&lcand->us, NULL, dummy_udp_recv, lcand); if (err) goto out; } err = udp_register_helper(&lcand->uh, lcand->us, layer, udp_helper_send_handler, udp_helper_recv_handler, lcand); if (err) goto out; break; default: err = EPROTONOSUPPORT; goto out; } } else if (type == ICE_CAND_TYPE_SRFLX || type == ICE_CAND_TYPE_PRFLX) { /* Special case for SRFLX UDP candidates, if he has * its own UDP-socket that can be used. */ if (proto == IPPROTO_UDP && sock) { lcand->us = mem_ref(sock); err = udp_register_helper(&lcand->uh, lcand->us, layer, udp_helper_send_handler, udp_helper_recv_handler, lcand); if (err) goto out; } } lcand->layer = layer; /* pair this local-candidate with all existing remote-candidates */ err = trice_candpair_with_local(icem, lcand); if (err) goto out; /* new pair -- refresh the checklist timer */ trice_checklist_refresh(icem); out: if (err) mem_deref(lcand); else if (lcandp) *lcandp = lcand; return err; }
static void turnc_handler(int err, uint16_t scode, const char *reason, const struct sa *relay_addr, const struct sa *mapped_addr, const struct stun_msg *msg, void *arg) { struct candidate *cand = arg; struct ice_lcand *lcand_relay=0, *lcand_srflx=0, *base = cand->base; uint32_t prio; if (err || scode) { re_printf("TURN client error: %u %s (%m)\n", scode, reason, err); goto out; } /* check if the relayed address is of the same Address Family * as the base candidate */ if (sa_af(relay_addr) != sa_af(&base->attr.addr)) { re_printf("could not use RELAY address (AF mismatch)\n"); goto out; } if (stun_msg_method(msg) == STUN_METHOD_ALLOCATE) { re_printf("TURN allocation okay (turn-proto=%s)\n", net_proto2name(cand->turn_proto)); cand->turn_ok = true; } /* RELAY */ re_printf("adding RELAY candidate %s.%J\n", net_proto2name(base->attr.proto), relay_addr); prio = calc_prio(ICE_CAND_TYPE_RELAY, base->attr.proto, base->attr.tcptype, sa_af(&base->attr.addr), cand->turn_proto); err = trice_lcand_add(&lcand_relay, base->icem, base->attr.compid, base->attr.proto, prio, relay_addr, relay_addr, ICE_CAND_TYPE_RELAY, mapped_addr, base->attr.tcptype, base->us, LAYER_ICE); if (err) { re_fprintf(stderr, "failed to add RELAY candidate (%m)\n", err); goto out; } if (cand->turn_proto == IPPROTO_TCP) { /* NOTE: this is needed to snap up outgoing UDP-packets */ err = udp_register_helper(&cand->uh_turntcp, lcand_relay->us, LAYER_TURN, turntcp_send_handler, NULL, cand); if (err) { re_printf("helper error\n"); goto out; } } /* SRFLX */ if (cand->turn_proto == base->attr.proto) { re_printf("adding SRFLX candidate %s.%J\n", net_proto2name(base->attr.proto), mapped_addr); prio = calc_prio(ICE_CAND_TYPE_SRFLX, base->attr.proto, base->attr.tcptype, sa_af(&base->attr.addr), base->attr.proto); err = trice_lcand_add(&lcand_srflx, base->icem, base->attr.compid, base->attr.proto, prio, mapped_addr, &base->attr.addr, ICE_CAND_TYPE_SRFLX, &base->attr.addr, base->attr.tcptype, NULL, LAYER_ICE); if (err) { re_fprintf(stderr, "failed to add SRFLX" " candidate (%m)\n", err); goto out; } } err = control_send_message(cand->ag->cli, "a=candidate:%H\r\n" "a=candidate:%H\r\n" , ice_cand_attr_encode, &lcand_relay->attr, ice_cand_attr_encode, lcand_srflx ? &lcand_srflx->attr : 0); if (err) goto out; candidate_add_permissions(cand); out: candidate_done(cand); }
static int alloc(struct menc_media **stp, struct menc_sess *sess, struct rtp_sock *rtp, int proto, void *rtpsock, void *rtcpsock, struct sdp_media *sdpm) { struct menc_st *st; const char *rattr = NULL; int layer = 10; /* above zero */ int err = 0; bool mux = (rtpsock == rtcpsock); (void)sess; (void)rtp; if (!stp || !sdpm) return EINVAL; if (proto != IPPROTO_UDP) return EPROTONOSUPPORT; st = (struct menc_st *)*stp; if (!st) { st = mem_zalloc(sizeof(*st), destructor); if (!st) return ENOMEM; st->sdpm = mem_ref(sdpm); err = sdp_media_set_alt_protos(st->sdpm, 4, "RTP/AVP", "RTP/AVPF", "RTP/SAVP", "RTP/SAVPF"); if (err) goto out; if (rtpsock) { st->rtpsock = mem_ref(rtpsock); err |= udp_register_helper(&st->uh_rtp, rtpsock, layer, send_handler, recv_handler, st); } if (rtcpsock && !mux) { st->rtcpsock = mem_ref(rtcpsock); err |= udp_register_helper(&st->uh_rtcp, rtcpsock, layer, send_handler, recv_handler, st); } if (err) goto out; /* set our preferred crypto-suite */ err |= str_dup(&st->crypto_suite, aes_cm_128_hmac_sha1_80); if (err) goto out; err = setup_srtp(st); if (err) goto out; } /* SDP handling */ if (sdp_media_rattr(st->sdpm, "crypto")) { rattr = sdp_media_rattr_apply(st->sdpm, "crypto", sdp_attr_handler, st); if (!rattr) { DEBUG_WARNING("no valid a=crypto attribute from" " remote peer\n"); } } if (!rattr) err = sdp_enc(st, sdpm, 0, st->crypto_suite); out: if (err) mem_deref(st); else *stp = (struct menc_media *)st; return err; }
static int media_alloc(struct menc_media **stp, struct menc_sess *sess, struct rtp_sock *rtp, struct udp_sock *rtpsock, struct udp_sock *rtcpsock, const struct sa *raddr_rtp, const struct sa *raddr_rtcp, struct sdp_media *sdpm) { struct menc_st *st; const char *rattr = NULL; int layer = 10; /* above zero */ int err = 0; bool mux = (rtpsock == rtcpsock); (void)sess; (void)rtp; (void)raddr_rtp; (void)raddr_rtcp; if (!stp || !sdpm || !sess) return EINVAL; st = (struct menc_st *)*stp; if (!st) { st = mem_zalloc(sizeof(*st), destructor); if (!st) return ENOMEM; st->sess = sess; st->sdpm = mem_ref(sdpm); if (0 == str_cmp(sdp_media_proto(sdpm), "RTP/AVP")) { err = sdp_media_set_alt_protos(st->sdpm, 4, "RTP/AVP", "RTP/AVPF", "RTP/SAVP", "RTP/SAVPF"); if (err) goto out; } if (rtpsock) { st->rtpsock = mem_ref(rtpsock); err |= udp_register_helper(&st->uh_rtp, rtpsock, layer, send_handler, recv_handler, st); } if (rtcpsock && !mux) { st->rtcpsock = mem_ref(rtcpsock); err |= udp_register_helper(&st->uh_rtcp, rtcpsock, layer, send_handler, recv_handler, st); } if (err) goto out; /* set our preferred crypto-suite */ err |= str_dup(&st->crypto_suite, preferred_suite); if (err) goto out; rand_bytes(st->key_tx, sizeof(st->key_tx)); } /* SDP handling */ if (sdp_media_rport(sdpm)) st->got_sdp = true; if (sdp_media_rattr(st->sdpm, "crypto")) { rattr = sdp_media_rattr_apply(st->sdpm, "crypto", sdp_attr_handler, st); if (!rattr) { warning("srtp: no valid a=crypto attribute from" " remote peer\n"); } } if (!rattr) err = sdp_enc(st, sdpm, 1, st->crypto_suite); out: if (err) mem_deref(st); else *stp = (struct menc_media *)st; return err; }