static int request_next(struct sip_request *req) { struct dnsrr *rr; struct sa dst; int err; again: rr = list_ledata(req->addrl.head); if (!rr) { rr = list_ledata(req->srvl.head); if (!rr) return ENOENT; req->port = rr->rdata.srv.port; dns_rrlist_apply2(&req->cachel, rr->rdata.srv.target, DNS_TYPE_A, DNS_TYPE_AAAA, DNS_CLASS_IN, true, rr_append_handler, &req->addrl); list_unlink(&rr->le); if (req->addrl.head) { mem_deref(rr); goto again; } err = addr_lookup(req, rr->rdata.srv.target); mem_deref(rr); return err; } switch (rr->type) { case DNS_TYPE_A: sa_set_in(&dst, rr->rdata.a.addr, req->port); break; case DNS_TYPE_AAAA: sa_set_in6(&dst, rr->rdata.aaaa.addr, req->port); break; default: return EINVAL; } list_unlink(&rr->le); mem_deref(rr); err = request(req, req->tp, &dst); if (err) { if (req->addrl.head || req->srvl.head) goto again; } return err; }
static struct sipsess *sipsess_find(struct sipsess_sock *sock, const struct sip_msg *msg) { return list_ledata(hash_lookup(sock->ht_sess, hash_joaat_pl(&msg->callid), cmp_handler, (void *)msg)); }
static int request_next(struct request *req, struct sa* dst) { struct dnsrr *rr; int err = 0; rr = list_ledata(req->addrl.head); if(!rr) return -ENOENT; switch (rr->type) { case DNS_TYPE_A: sa_set_in(dst, rr->rdata.a.addr, req->port); break; case DNS_TYPE_AAAA: sa_set_in6(dst, rr->rdata.aaaa.addr, req->port); break; default: return EINVAL; } list_unlink(&rr->le); mem_deref(rr); return err; }
/** * Poll all timers in the current thread * * @param tmrl Timer list */ void tmr_poll(struct list *tmrl) { const uint64_t jfs = tmr_jiffies(); for (;;) { struct tmr *tmr; tmr_h *th; void *th_arg; tmr = list_ledata(tmrl->head); if (!tmr || (tmr->jfs > jfs)) { break; } th = tmr->th; th_arg = tmr->arg; tmr->th = NULL; list_unlink(&tmr->le); if (!th) continue; #if TMR_DEBUG call_handler(th, th_arg); #else th(th_arg); #endif } }
struct tls_conn *tls_udp_conn(const struct tls_sock *ts, const struct sa *peer) { if (!ts) return NULL; return list_ledata(hash_lookup(ts->ht_conn, sa_hash(peer, SA_ALL), hash_cmp_handler, (void *)peer)); }
/** * Lookup a SIP uri in all registered contacts * * @param contacts Contacts container * @param uri SIP uri to lookup * * @return Matching contact if found, otherwise NULL */ struct contact *contact_find(const struct contacts *contacts, const char *uri) { if (!contacts) return NULL; return list_ledata(hash_lookup(contacts->cht, hash_joaat_str(uri), find_handler, (void *)uri)); }
static struct allocation *allocation_find(int proto, const struct sa *src, const struct sa *dst) { struct tuple tup; tup.cli_addr = src; tup.srv_addr = dst; tup.proto = proto; return list_ledata(hash_lookup(turnd.ht_alloc, sa_hash(src, SA_ALL), hash_cmp_handler, &tup)); }
static int media_decode(struct sdp_media **mp, struct sdp_session *sess, bool offer, const struct pl *pl) { struct pl name, port, proto, fmtv, fmt; struct sdp_media *m; int err; if (re_regex(pl->p, pl->l, "[a-z]+ [^ ]+ [^ ]+[^]*", &name, &port, &proto, &fmtv)) return EBADMSG; m = list_ledata(*mp ? (*mp)->le.next : sess->medial.head); if (!m) { if (!offer) return EPROTO; m = sdp_media_find(sess, &name, &proto); if (!m) { err = sdp_media_radd(&m, sess, &name, &proto); if (err) return err; } else { list_unlink(&m->le); list_append(&sess->medial, &m->le, m); } } else { if (pl_strcmp(&name, m->name)) return offer ? ENOTSUP : EPROTO; if (pl_strcmp(&proto, m->proto)) return ENOTSUP; } while (!re_regex(fmtv.p, fmtv.l, " [^ ]+", &fmt)) { pl_advance(&fmtv, fmt.p + fmt.l - fmtv.p); err = sdp_format_radd(m, &fmt); if (err) return err; } m->raddr = sess->raddr; sa_set_port(&m->raddr, pl_u32(&port)); m->rdir = sess->rdir; *mp = m; return 0; }
/** * Get number of milliseconds until the next timer expires * * @param tmrl Timer-list * * @return Number of [ms], or 0 if no active timers */ uint64_t tmr_next_timeout(struct list *tmrl) { const uint64_t jif = tmr_jiffies(); const struct tmr *tmr; tmr = list_ledata(tmrl->head); if (!tmr) return 0; if (tmr->jfs <= jif) return 1; else return tmr->jfs - jif; }
TEST_F(cryptoboxtest, tmp) { #define NUM 3 struct device *a; add_devices(NUM); connect_devices(); //debug(); /* number of peers is always N-1 */ a = (struct device *)list_ledata(devicel.head); ASSERT_EQ(NUM-1, list_count(&a->peerl)); }
int sipsess_reply_ack(struct sipsess *sess, const struct sip_msg *msg, bool *awaiting_answer) { struct sipsess_reply *reply; reply = list_ledata(list_apply(&sess->replyl, false, cmp_handler, (void *)msg)); if (!reply) return ENOENT; *awaiting_answer = reply->awaiting_answer; mem_deref(reply); return 0; }
static int send_tcp(struct dns_query *q) { const struct sa *srv; struct tcpconn *tc; int err = 0; if (!q) return EINVAL; while (q->ntx < *q->srvc) { srv = &q->srvv[q->ntx++]; DEBUG_NOTICE("trying tcp server#%u: %J\n", q->ntx-1, srv); tc = list_ledata(hash_lookup(q->dnsc->ht_tcpconn, sa_hash(srv, SA_ALL), tcpconn_cmp_handler, (void *)srv)); if (!tc) { err = tcpconn_alloc(&tc, q->dnsc, srv); if (err) continue; } if (tc->connected) { q->mb.pos = 0; err = tcp_send(tc->conn, &q->mb); if (err) { tcpconn_close(tc, err); continue; } tmr_start(&tc->tmr, tc->dnsc->conf.idle_timeout, tcpconn_timeout_handler, tc); DEBUG_NOTICE("tcp send %J\n", srv); } list_append(&tc->ql, &q->le_tc, q); q->tc = mem_ref(tc); break; } return err; }
void send_all() { struct le *le; for (le = devicel.head; le; le = le->next) { struct device *dev = (struct device *)le->data, *other; struct le *next; next = le->next ? le->next : devicel.head; other = (struct device *)list_ledata(next); err = device_new_session(dev, other); ASSERT_EQ(0, err); send_message(dev, other, hello_msg, sizeof(hello_msg)); } }
static bool response_handler(const struct sip_msg *msg, void *arg) { struct sip_ctrans *ct; struct sip *sip = arg; ct = list_ledata(hash_lookup(sip->ht_ctrans, hash_joaat_pl(&msg->via.branch), cmp_handler, (void *)msg)); if (!ct) return false; if (ct->invite) { invite_response(ct, msg); return true; } switch (ct->state) { case TRYING: case PROCEEDING: if (msg->scode < 200) { ct->state = PROCEEDING; ct->resph(0, msg, ct->arg); } else { ct->state = COMPLETED; ct->resph(0, msg, ct->arg); if (sip_transp_reliable(ct->tp)) { mem_deref(ct); break; } tmr_start(&ct->tmr, SIP_T4, tmr_handler, ct); tmr_cancel(&ct->tmre); } break; default: break; } return true; }
struct chan *chan_peer_find(const struct chanlist *cl, const struct sa *peer) { struct chan *chan; if (!cl || !peer) return NULL; chan = list_ledata(hash_lookup(cl->ht_peer, sa_hash(peer, SA_ALL), hash_peer_cmp_handler, (void *)peer)); if (!chan) return NULL; if (chan->expires < time(NULL)) { restund_debug("turn: allocation %p channel 0x%x %J expired\n", chan->al, chan->numb, &chan->peer); mem_deref(chan); return NULL; } return chan; }
struct chan *chan_numb_find(const struct chanlist *cl, uint16_t numb) { struct chan *chan; if (!cl) return NULL; chan = list_ledata(hash_lookup(cl->ht_numb, numb, hash_numb_cmp_handler, &numb)); if (!chan) return NULL; if (chan->expires < time(NULL)) { restund_debug("turn: allocation %p channel 0x%x %J expired\n", chan->al, chan->numb, &chan->peer); mem_deref(chan); return NULL; } return chan; }
/* Test sending messages between 3 devices */ TEST_F(cryptoboxtest, three_devices) { struct le *le; add_devices(3); /* Connect the devices */ connect_devices(); for (le = devicel.head; le; le = le->next) { struct device *dev = (struct device *)le->data, *other; struct le *next; next = le->next ? le->next : devicel.head; other = (struct device *)list_ledata(next); err = device_new_session(dev, other); ASSERT_EQ(0, err); send_message(dev, other, hello_msg, sizeof(hello_msg)); } }
static int dequeue(struct tcp_conn *tc) { struct tcp_qent *qe = list_ledata(tc->sendq.head); ssize_t n; #ifdef MSG_NOSIGNAL const int flags = MSG_NOSIGNAL; /* disable SIGPIPE signal */ #else const int flags = 0; #endif if (!qe) { if (tc->sendh) tc->sendh(tc->arg); return 0; } n = send(tc->fdc, BUF_CAST mbuf_buf(&qe->mb), qe->mb.end - qe->mb.pos, flags); if (n < 0) { if (EAGAIN == errno) return 0; #ifdef WIN32 if (WSAEWOULDBLOCK == WSAGetLastError()) return 0; #endif return errno; } tc->txqsz -= n; qe->mb.pos += n; if (qe->mb.pos >= qe->mb.end) mem_deref(qe); return 0; }
int location_update(struct list *locl, const struct sip_msg *msg, const struct sip_addr *contact, uint32_t expires) { struct location *loc, *loc_new = NULL; struct loctmp *tmp; struct pl pl; int err; if (!locl || !msg || !contact) return EINVAL; loc = list_ledata(list_apply(locl, true, cmp_handler, (void *)&contact->uri)); if (!loc) { if (expires == 0) return 0; loc = loc_new = mem_zalloc(sizeof(*loc), destructor_location); if (!loc) return ENOMEM; list_append(locl, &loc->le, loc); } else { if (!pl_strcmp(&msg->callid, loc->callid) && msg->cseq.num <= loc->cseq) return EPROTO; if (expires == 0) { loc->rm = true; return 0; } } tmp = mem_zalloc(sizeof(*tmp), destructor_loctmp); if (!tmp) { err = ENOMEM; goto out; } err = pl_strdup(&tmp->uri, &contact->auri); if (err) goto out; pl_set_str(&pl, tmp->uri); if (uri_decode(&tmp->duri, &pl)) { err = EBADMSG; goto out; } err = pl_strdup(&tmp->callid, &msg->callid); if (err) goto out; if (!msg_param_decode(&contact->params, "q", &pl)) tmp->q = pl_float(&pl); else tmp->q = 1; tmp->cseq = msg->cseq.num; tmp->expires = expires; tmp->src = msg->src; out: if (err) { mem_deref(loc_new); mem_deref(tmp); } else { mem_deref(loc->tmp); loc->tmp = tmp; } return err; }
static bool auth_handler(const struct sip_hdr *hdr, const struct sip_msg *msg, void *arg) { struct httpauth_digest_chall ch; struct sip_auth *auth = arg; struct realm *realm = NULL; int err; (void)msg; if (httpauth_digest_challenge_decode(&ch, &hdr->val)) { err = EBADMSG; goto out; } if (pl_isset(&ch.algorithm) && pl_strcasecmp(&ch.algorithm, "md5")) { err = ENOSYS; goto out; } realm = list_ledata(list_apply(&auth->realml, true, cmp_handler, &ch.realm)); if (!realm) { realm = mem_zalloc(sizeof(*realm), realm_destructor); if (!realm) { err = ENOMEM; goto out; } list_append(&auth->realml, &realm->le, realm); err = pl_strdup(&realm->realm, &ch.realm); if (err) goto out; err = auth->authh(&realm->user, &realm->pass, realm->realm, auth->arg); if (err) goto out; } else { if (!pl_isset(&ch.stale) || pl_strcasecmp(&ch.stale, "true")) { err = EAUTH; goto out; } realm->nonce = mem_deref(realm->nonce); realm->qop = mem_deref(realm->qop); realm->opaque = mem_deref(realm->opaque); } realm->hdr = hdr->id; realm->nc = 1; err = pl_strdup(&realm->nonce, &ch.nonce); if (pl_isset(&ch.qop)) err |= pl_strdup(&realm->qop, &ch.qop); if (pl_isset(&ch.opaque)) err |= pl_strdup(&realm->opaque, &ch.opaque); out: if (err) { mem_deref(realm); auth->err = err; return true; } return false; }
static struct device *find_device(const char *device) { return list_ledata(hash_lookup(ht_device, hash_joaat_str(device), list_apply_handler, (void *)device)); }
static struct perm *perm_find(const struct turnc *turnc, const struct sa *peer) { return list_ledata(hash_lookup(turnc->perms, sa_hash(peer, SA_ADDR), hash_cmp_handler, (void *)peer)); }
struct vidisp_st *vidbridge_disp_find(const char *device) { return list_ledata(hash_lookup(ht_disp, hash_joaat_str(device), list_apply_handler, (void *)device)); }
static int reply_recv(struct dnsc *dnsc, struct mbuf *mb) { struct dns_query *q = NULL; uint32_t i, j, nv[3]; struct dnsquery dq; int err = 0; if (!dnsc || !mb) return EINVAL; dq.name = NULL; if (dns_hdr_decode(mb, &dq.hdr) || !dq.hdr.qr) { err = EBADMSG; goto out; } err = dns_dname_decode(mb, &dq.name, 0); if (err) goto out; if (mbuf_get_left(mb) < 4) { err = EBADMSG; goto out; } dq.type = ntohs(mbuf_read_u16(mb)); dq.dnsclass = ntohs(mbuf_read_u16(mb)); q = list_ledata(hash_lookup(dnsc->ht_query, hash_joaat_str_ci(dq.name), query_cmp_handler, &dq)); if (!q) { err = ENOENT; goto out; } /* try next server */ if (dq.hdr.rcode == DNS_RCODE_SRV_FAIL && q->ntx < *q->srvc) { if (!q->tc) /* try next UDP server immediately */ tmr_start(&q->tmr, 0, udp_timeout_handler, q); err = EPROTO; goto out; } nv[0] = dq.hdr.nans; nv[1] = dq.hdr.nauth; nv[2] = dq.hdr.nadd; for (i=0; i<ARRAY_SIZE(nv); i++) { for (j=0; j<nv[i]; j++) { struct dnsrr *rr = NULL; err = dns_rr_decode(mb, &rr, 0); if (err) { query_handler(q, err, NULL, NULL, NULL, NULL); mem_deref(q); goto out; } list_append(&q->rrlv[i], &rr->le_priv, rr); } } if (q->type == DNS_QTYPE_AXFR) { struct dnsrr *rrh, *rrt; rrh = list_ledata(list_head(&q->rrlv[0])); rrt = list_ledata(list_tail(&q->rrlv[0])); /* Wait for last AXFR reply with terminating SOA record */ if (dq.hdr.rcode == DNS_RCODE_OK && dq.hdr.nans > 0 && (!rrt || rrt->type != DNS_TYPE_SOA || rrh == rrt)) { DEBUG_INFO("waiting for last SOA record in reply\n"); goto out; } } query_handler(q, 0, &dq.hdr, &q->rrlv[0], &q->rrlv[1], &q->rrlv[2]); mem_deref(q); out: mem_deref(dq.name); return err; }
static inline struct dname *dname_lookup(struct hash *ht_dname, const char *name) { return list_ledata(hash_lookup(ht_dname, hash_joaat_str_ci(name), lookup_handler, (void *)name)); }