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 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; }
static int media_alloc(struct mnat_media **mp, struct mnat_sess *sess, int proto, void *sock1, void *sock2, struct sdp_media *sdpm) { struct mnat_media *m; struct sa laddr; struct pcp_map map; unsigned i; int err = 0; if (!mp || !sess || !sdpm || proto != IPPROTO_UDP) return EINVAL; m = mem_zalloc(sizeof(*m), media_destructor); if (!m) return ENOMEM; m->compc = sock2 ? 2 : 1; list_append(&sess->medial, &m->le, m); m->sess = sess; m->sdpm = mem_ref(sdpm); for (i=0; i<m->compc; i++) { struct comp *comp = &m->compv[i]; comp->id = i+1; comp->media = m; err = udp_local_get(i==0 ? sock1 : sock2, &laddr); if (err) goto out; rand_bytes(map.nonce, sizeof(map.nonce)); map.proto = proto; map.int_port = sa_port(&laddr); /* note: using same address-family as the PCP server */ sa_init(&map.ext_addr, sa_af(&pcp_srv)); info("pcp: %s: internal port for %s is %u\n", sdp_media_name(sdpm), i==0 ? "RTP" : "RTCP", map.int_port); err = pcp_request(&comp->pcp, NULL, &pcp_srv, PCP_MAP, LIFETIME, &map, pcp_resp_handler, comp, 0); if (err) goto out; } out: if (err) mem_deref(m); else if (mp) { *mp = m; } return err; }
int allocation_create(struct allocator *allocator, unsigned ix, int proto, const struct sa *srv, const char *username, const char *password, struct tls *tls, bool turn_ind, allocation_h *alloch, void *arg) { struct allocation *alloc; struct sa laddr; int err; if (!allocator || !proto || !srv) return EINVAL; sa_init(&laddr, sa_af(srv)); alloc = mem_zalloc(sizeof(*alloc), destructor); if (!alloc) return ENOMEM; list_append(&allocator->allocl, &alloc->le, alloc); (void)gettimeofday(&alloc->sent, NULL); alloc->atime = -1; alloc->ix = ix; alloc->allocator = allocator; alloc->proto = proto; alloc->secure = tls != NULL; alloc->srv = *srv; alloc->user = username; alloc->pass = password; alloc->turn_ind = turn_ind; alloc->alloch = alloch; alloc->arg = arg; alloc->tls = mem_ref(tls); receiver_init(&alloc->recv, allocator->session_cookie, alloc->ix); err = udp_listen(&alloc->us_tx, &laddr, NULL, NULL); if (err) { re_fprintf(stderr, "allocation: failed to create UDP tx socket" " (%m)\n", err); goto out; } udp_local_get(alloc->us_tx, &alloc->laddr_tx); err = start(alloc); if (err) goto out; out: if (err) mem_deref(alloc); return err; }
// receive callback void p2p_receive_handler(const char* data, uint32_t len, struct p2pconnection* p2pcon) { //struct p2pconnection* p2pcon = (struct p2pconnection*)arg; int fd = udp_sock_fd(p2pcon->ulsock, AF_INET); struct sa* lsa =NULL; lsa = (struct sa*)mem_zalloc(sizeof(struct sa),NULL); udp_local_get(p2pcon->ulsock, lsa); CUDT::postRecv(p2pcon->udtsock, &(lsa->u.sa), data, len); re_printf("p2p receive data:%s\n", data); }
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); }
// connect callback void p2p_request_handler(struct p2phandle *p2p, const char* peername, struct p2pconnection **p2pcon) { re_fprintf(stderr, "p2p accept from:%s\n", peername); int err = p2p_accept(p2p, p2pcon, peername, p2p_receive_handler, *p2pcon); int fdaccept = udp_sock_fd((*p2pcon)->ulsock, AF_INET); struct sa* lsa = NULL; lsa = (struct sa*)mem_zalloc(sizeof(struct sa),NULL); udp_local_get((*p2pcon)->ulsock, lsa); sa_cpy(lsa, p2p->sactl); int fdlisten = tcp_conn_fd(p2p->ltcp); UDPSOCKET udpsock = (UDPSOCKET)fdlisten; (*p2pcon)->udtsock = CUDT::socket(AF_INET, SOCK_STREAM, 0); CUDT::bind((*p2pcon)->udtsock, &udpsock, &(p2p->sactl->u.sa), p2p->sactl->len); CUDT::listen((*p2pcon)->udtsock, &(lsa->u.sa), 10); if (err) { re_fprintf(stderr, "p2p accept error:%s\n", strerror(err)); return ; } }
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 comp_alloc(struct comp *comp, void *sock) { struct sa laddr; int err; err = udp_local_get(sock, &laddr); if (err) goto out; comp->int_port = sa_port(&laddr); info("natpmp: `%s' stream comp %u local UDP port is %u\n", sdp_media_name(comp->media->sdpm), comp->id, comp->int_port); err = natpmp_mapping_request(&comp->natpmp, &natpmp_srv, comp->int_port, 0, comp->lifetime, natpmp_resp_handler, comp); if (err) goto out; out: 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; }
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); }
/** * Add a SIP transport * * @param sip SIP stack instance * @param tp SIP Transport * @param laddr Local network address * @param ... Optional transport parameters such as TLS context * * @return 0 if success, otherwise errorcode */ int sip_transp_add(struct sip *sip, enum sip_transp tp, const struct sa *laddr, ...) { struct sip_transport *transp; struct tls *tls; va_list ap; int err; if (!sip || !laddr || !sa_isset(laddr, SA_ADDR)) return EINVAL; transp = mem_zalloc(sizeof(*transp), transp_destructor); if (!transp) return ENOMEM; list_append(&sip->transpl, &transp->le, transp); transp->sip = sip; transp->tp = tp; va_start(ap, laddr); switch (tp) { case SIP_TRANSP_UDP: err = udp_listen((struct udp_sock **)&transp->sock, laddr, udp_recv_handler, transp); if (err) break; err = udp_local_get(transp->sock, &transp->laddr); break; case SIP_TRANSP_TLS: tls = va_arg(ap, struct tls *); if (!tls) { err = EINVAL; break; } transp->tls = mem_ref(tls); /*@fallthrough@*/ case SIP_TRANSP_TCP: err = tcp_listen((struct tcp_sock **)&transp->sock, laddr, tcp_connect_handler, transp); if (err) break; err = tcp_sock_local_get(transp->sock, &transp->laddr); break; default: err = EPROTONOSUPPORT; break; } va_end(ap); if (err) mem_deref(transp); 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; }
static void udp_read(struct udp_sock *us, int fd) { struct mbuf *mb = mbuf_alloc(us->rxsz); struct sa src; struct le *le; int err = 0; ssize_t n; if (!mb) return; src.len = sizeof(src.u); n = recvfrom(fd, BUF_CAST mb->buf + us->rx_presz, mb->size - us->rx_presz, 0, &src.u.sa, &src.len); if (n < 0) { err = errno; if (EAGAIN == err) goto out; #ifdef EWOULDBLOCK if (EWOULDBLOCK == err) goto out; #endif #if TARGET_OS_IPHONE if (ENOTCONN == err) { struct udp_sock *us_new; struct sa laddr; err = udp_local_get(us, &laddr); if (err) goto out; if (-1 != us->fd) { fd_close(us->fd); (void)close(us->fd); us->fd = -1; } if (-1 != us->fd6) { fd_close(us->fd6); (void)close(us->fd6); us->fd6 = -1; } err = udp_listen(&us_new, &laddr, NULL, NULL); if (err) goto out; us->fd = us_new->fd; us->fd6 = us_new->fd6; us_new->fd = -1; us_new->fd6 = -1; mem_deref(us_new); udp_thread_attach(us); goto out; } #endif /* cache error code */ us->err = err; goto out; } mb->pos = us->rx_presz; mb->end = n + us->rx_presz; (void)mbuf_resize(mb, mb->end); /* call helpers */ le = us->helpers.head; while (le) { struct udp_helper *uh = le->data; bool hdld; le = le->next; hdld = uh->recvh(&src, mb, uh->arg); if (hdld) goto out; } us->rh(&src, mb, us->arg); out: mem_deref(mb); }
/** * Allocate a new NAT Mapping Behaviour Discovery session * * @param nmp Pointer to allocated NAT Mapping object * @param laddr Local IP address * @param srv STUN Server IP address and port * @param proto Transport protocol * @param conf STUN configuration (Optional) * @param mh Mapping handler * @param arg Handler argument * * @return 0 if success, errorcode if failure */ int nat_mapping_alloc(struct nat_mapping **nmp, const struct sa *laddr, const struct sa *srv, int proto, const struct stun_conf *conf, nat_mapping_h *mh, void *arg) { struct nat_mapping *nm; int i, err; if (!nmp || !laddr || !srv || !mh) return EINVAL; nm = mem_zalloc(sizeof(*nm), mapping_destructor); if (!nm) return ENOMEM; err = stun_alloc(&nm->stun, conf, NULL, NULL); if (err) goto out; nm->proto = proto; sa_cpy(&nm->laddr, laddr); switch (proto) { case IPPROTO_UDP: err = udp_listen(&nm->us, &nm->laddr, udp_recv_handler, nm); if (err) goto out; err = udp_local_get(nm->us, &nm->laddr); if (err) goto out; break; case IPPROTO_TCP: /* Allocate and bind 3 TCP Sockets */ for (i=0; i<3; i++) { err = tcp_conn_alloc(&nm->tcv[i], srv, tcp_estab_handler, tcp_recv_handler, tcp_close_handler, nm); if (err) goto out; err = tcp_conn_bind(nm->tcv[i], &nm->laddr); if (err) goto out; err = tcp_conn_local_get(nm->tcv[i], &nm->laddr); if (err) goto out; } break; default: err = EPROTONOSUPPORT; goto out; } sa_cpy(&nm->srv, srv); nm->mh = mh; nm->arg = arg; *nmp = nm; out: if (err) mem_deref(nm); 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; }