Пример #1
0
static bool cryptosuite_issupported(const struct pl *suite)
{
	if (0 == pl_strcasecmp(suite, aes_cm_128_hmac_sha1_32)) return true;
	if (0 == pl_strcasecmp(suite, aes_cm_128_hmac_sha1_80)) return true;

	return false;
}
Пример #2
0
int decode_sdpparam_h264(struct videnc_state *st, const struct pl *name,
			 const struct pl *val)
{
	if (0 == pl_strcasecmp(name, "packetization-mode")) {
		st->u.h264.packetization_mode = pl_u32(val);

		if (st->u.h264.packetization_mode != 0) {
			warning("avcodec: illegal packetization-mode %u\n",
				st->u.h264.packetization_mode);
			return EPROTO;
		}
	}
	else if (0 == pl_strcasecmp(name, "profile-level-id")) {
		struct pl prof = *val;
		if (prof.l != 6) {
			warning("avcodec: invalid profile-level-id (%r)\n",
				val);
			return EPROTO;
		}

		prof.l = 2;
		st->u.h264.profile_idc = pl_x32(&prof); prof.p += 2;
		st->u.h264.profile_iop = pl_x32(&prof); prof.p += 2;
		st->u.h264.level_idc   = pl_x32(&prof);
	}
	else if (0 == pl_strcasecmp(name, "max-fs")) {
		st->u.h264.max_fs = pl_u32(val);
	}
	else if (0 == pl_strcasecmp(name, "max-smbps")) {
		st->u.h264.max_smbps = pl_u32(val);
	}

	return 0;
}
static enum ice_tcptype ice_tcptype_resolve(const struct pl *pl)
{
	if (0 == pl_strcasecmp(pl, "active"))  return ICE_TCP_ACTIVE;
	if (0 == pl_strcasecmp(pl, "passive")) return ICE_TCP_PASSIVE;
	if (0 == pl_strcasecmp(pl, "so"))      return ICE_TCP_SO;

	return (enum ice_tcptype)-1;
}
Пример #4
0
static enum h263_fmt h263_fmt(const struct pl *name)
{
	if (0 == pl_strcasecmp(name, "sqcif")) return H263_FMT_SQCIF;
	if (0 == pl_strcasecmp(name, "qcif"))  return H263_FMT_QCIF;
	if (0 == pl_strcasecmp(name, "cif"))   return H263_FMT_CIF;
	if (0 == pl_strcasecmp(name, "cif4"))  return H263_FMT_4CIF;
	if (0 == pl_strcasecmp(name, "cif16")) return H263_FMT_16CIF;
	return H263_FMT_OTHER;
}
Пример #5
0
/**
 * Add a contact
 *
 * @param contacts Contacts container
 * @param contactp Pointer to allocated contact (optional)
 * @param addr     Contact in SIP address format
 *
 * @return 0 if success, otherwise errorcode
 */
int contact_add(struct contacts *contacts,
		struct contact **contactp, const struct pl *addr)
{
	struct contact *c;
	struct pl pl;
	int err;

	if (!contacts)
		return EINVAL;

	c = mem_zalloc(sizeof(*c), destructor);
	if (!c)
		return ENOMEM;

	err = pl_strdup(&c->buf, addr);
	if (err)
		goto out;

	pl_set_str(&pl, c->buf);

	err = sip_addr_decode(&c->addr, &pl);
	if (err) {
		warning("contact: decode error '%r'\n", addr);
		goto out;
	}

	if (0 == msg_param_decode(&c->addr.params, "access", &pl)) {

		if (0 == pl_strcasecmp(&pl, "block")) {
			c->access = ACCESS_BLOCK;
		}
		else if (0 == pl_strcasecmp(&pl, "allow")) {
			c->access = ACCESS_ALLOW;
		}
		else {
			warning("contact: unknown 'access=%r' for '%r'\n",
				&pl, addr);
			err = EINVAL;
			goto out;
		}
	}
	else
		c->access = ACCESS_UNKNOWN;

	c->status = PRESENCE_UNKNOWN;

	list_append(&contacts->cl, &c->le, c);
	hash_append(contacts->cht, hash_joaat_pl(&c->addr.auri), &c->he, c);

 out:
	if (err)
		mem_deref(c);
	else if (contactp)
		*contactp = c;

	return err;
}
Пример #6
0
enum cand_type ice_cand_name2type(const struct pl *name)
{
	if (0 == pl_strcasecmp(name, "host"))  return CAND_TYPE_HOST;
	if (0 == pl_strcasecmp(name, "srflx")) return CAND_TYPE_SRFLX;
	if (0 == pl_strcasecmp(name, "prflx")) return CAND_TYPE_PRFLX;
	if (0 == pl_strcasecmp(name, "relay")) return CAND_TYPE_RELAY;

	return (enum cand_type)-1;
}
Пример #7
0
static enum aufmt resolve_aufmt(const struct pl *fmt)
{
	if (0 == pl_strcasecmp(fmt, "s16"))     return AUFMT_S16LE;
	if (0 == pl_strcasecmp(fmt, "s16le"))   return AUFMT_S16LE;
	if (0 == pl_strcasecmp(fmt, "float"))   return AUFMT_FLOAT;
	if (0 == pl_strcasecmp(fmt, "s24_3le")) return AUFMT_S24_3LE;

	return (enum aufmt)-1;
}
Пример #8
0
static void notify_handler(struct sip *sip, const struct sip_msg *msg,
			   void *arg)
{
	enum presence_status status = PRESENCE_CLOSED;
	struct presence *pres = arg;
	const struct sip_hdr *hdr;
	struct pl pl;

	pres->failc = 0;

	hdr = sip_msg_hdr(msg, SIP_HDR_CONTENT_TYPE);
	if (!hdr || 0 != pl_strcasecmp(&hdr->val, "application/pidf+xml")) {

		if (hdr)
			(void)re_printf("presence: unsupported"
					" content-type: '%r'\n",
					&hdr->val);

		sip_treplyf(NULL, NULL, sip, msg, false,
			    415, "Unsupported Media Type",
			    "Accept: application/pidf+xml\r\n"
			    "Content-Length: 0\r\n"
			    "\r\n");
		return;
	}

	if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb),
		      "<status>[^<]*<basic>[^<]*</basic>[^<]*</status>",
		      NULL, &pl, NULL)) {

		if (!pl_strcasecmp(&pl, "open"))
			status = PRESENCE_OPEN;
	}

	if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb),
		      "<rpid:away/>")) {

		status = PRESENCE_CLOSED;
	}
	else if (!re_regex((const char *)mbuf_buf(msg->mb),
			   mbuf_get_left(msg->mb),
			   "<rpid:busy/>")) {

		status = PRESENCE_BUSY;
	}
	else if (!re_regex((const char *)mbuf_buf(msg->mb),
			   mbuf_get_left(msg->mb),
			   "<rpid:on-the-phone/>")) {

		status = PRESENCE_BUSY;
	}

	(void)sip_treply(NULL, sip, msg, 200, "OK");

	contact_set_presence(pres->contact, status);
}
Пример #9
0
static int module_init(void)
{
	struct pl pl;

	if (conf_get(conf_cur(), "video_selfview", &pl))
		return 0;

	if (0 == pl_strcasecmp(&pl, "window"))
		vidfilt_register(&selfview_win);
	else if (0 == pl_strcasecmp(&pl, "pip"))
		vidfilt_register(&selfview_pip);

	return 0;
}
Пример #10
0
int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl)
{
	struct pl state, param;
	int err;

	if (!ss || !pl)
		return EINVAL;

	err = re_regex(pl->p, pl->l, "[a-z]+[ \t\r\n]*[^]*",
		       &state, NULL, &ss->params);
	if (err)
		return EBADMSG;

	if (!pl_strcasecmp(&state, "active"))
		ss->state = SIPEVENT_ACTIVE;
	else if (!pl_strcasecmp(&state, "pending"))
		ss->state = SIPEVENT_PENDING;
	else if (!pl_strcasecmp(&state, "terminated"))
		ss->state = SIPEVENT_TERMINATED;
	else
		ss->state = -1;

	if (!msg_param_decode(&ss->params, "reason", &param)) {

		if (!pl_strcasecmp(&param, "deactivated"))
			ss->reason = SIPEVENT_DEACTIVATED;
		else if (!pl_strcasecmp(&param, "probation"))
			ss->reason = SIPEVENT_PROBATION;
		else if (!pl_strcasecmp(&param, "rejected"))
			ss->reason = SIPEVENT_REJECTED;
		else if (!pl_strcasecmp(&param, "timeout"))
			ss->reason = SIPEVENT_TIMEOUT;
		else if (!pl_strcasecmp(&param, "giveup"))
			ss->reason = SIPEVENT_GIVEUP;
		else if (!pl_strcasecmp(&param, "noresource"))
			ss->reason = SIPEVENT_NORESOURCE;
		else
			ss->reason = -1;
	}
	else {
		ss->reason = -1;
	}

	if (!msg_param_decode(&ss->params, "expires", &param))
		ss->expires = param;
	else
		ss->expires = pl_null;

	if (!msg_param_decode(&ss->params, "retry-after", &param))
		ss->retry_after = param;
	else
		ss->retry_after = pl_null;

	return 0;
}
Пример #11
0
static int module_init(void)
{
	struct pl pl = PL("pip");

	(void)conf_get(conf_cur(), "video_selfview", &pl);

	if (0 == pl_strcasecmp(&pl, "window"))
		vidfilt_register(&selfview_win);
	else if (0 == pl_strcasecmp(&pl, "pip"))
		vidfilt_register(&selfview_pip);

	(void)conf_get_vidsz(conf_cur(), "selfview_size", &selfview_size);

	return 0;
}
Пример #12
0
static bool value_handler(const struct sip_hdr *hdr, const struct sip_msg *msg,
			  void *arg)
{
	(void)msg;

	return 0 == pl_strcasecmp(&hdr->val, (const char *)arg);
}
Пример #13
0
static enum ice_transp transp_resolve(const struct pl *transp)
{
	if (!pl_strcasecmp(transp, "UDP"))
		return ICE_TRANSP_UDP;

	return ICE_TRANSP_NONE;
}
Пример #14
0
static void reload_handler(struct mbuf *mb)
{
	bool dbg = force_debug;
	struct conf *lconf;
	struct pl opt;
	int err;
	(void)mb;

	err = conf_alloc(&lconf, configfile);
	if (err) {
		restund_error("error loading configuration: %s: %m\n",
			      configfile, err);
		return;
	}

	conf = mem_deref(conf);
	conf = lconf;

	if (!conf_get(conf, "debug", &opt) && !pl_strcasecmp(&opt, "yes"))
		dbg = true;

	restund_log_enable_debug(dbg);

	restund_info("configuration reloaded from %s (debug%s)\n",
		     configfile, dbg ? " enabled" : " disabled");
}
Пример #15
0
static int conf_get_vidfmt(const struct conf *conf, const char *name,
			   int *fmtp)
{
	struct pl pl;
	int fmt;
	int err;

	err = conf_get(conf, name, &pl);
	if (err)
		return err;

	for (fmt=0; fmt<VID_FMT_N; fmt++) {

		const char *str = vidfmt_name(fmt);

		if (0 == pl_strcasecmp(&pl, str)) {

			*fmtp = fmt;
			return 0;
		}
	}

	warning("config: %s: pixel format not supported (%r)\n", name, &pl);

	return ENOENT;
}
Пример #16
0
/**
 * Find a User-Agent (UA) which has certain address parameter and/or value
 *
 * @param name  SIP Address parameter name
 * @param value SIP Address parameter value (optional)
 *
 * @return User-Agent (UA) if found, otherwise NULL
 */
struct ua *uag_find_param(const char *name, const char *value)
{
	struct le *le;

	for (le = uag.ual.head; le; le = le->next) {
		struct ua *ua = le->data;
		struct sip_addr *laddr = account_laddr(ua->acc);
		struct pl val;

		if (value) {

			if (0 == msg_param_decode(&laddr->params, name, &val)
			    &&
			    0 == pl_strcasecmp(&val, value)) {
				return ua;
			}
		}
		else {
			if (0 == msg_param_exists(&laddr->params, name, &val))
				return ua;
		}
	}

	return NULL;
}
Пример #17
0
static int notifier_add(struct sipevent_sock *sock, const struct sip_msg *msg,
			struct ua *ua)
{
	const struct sip_hdr *hdr;
	struct sipevent_event se;
	struct notifier *not;
	int err;

	hdr = sip_msg_hdr(msg, SIP_HDR_EVENT);
	if (!hdr)
		return EPROTO;

	err = sipevent_event_decode(&se, &hdr->val);
	if (err)
		return err;

	if (pl_strcasecmp(&se.event, "presence")) {
		info("presence: unexpected event '%r'\n", &se.event);
		return EPROTO;
	}

	err = notifier_alloc(&not, sock, msg, &se, ua);
	if (err)
		return err;

	(void)notify(not, my_status);

	return 0;
}
Пример #18
0
static void decode_param(const struct pl *name, const struct pl *val,
			 void *arg)
{
	struct aucodec_st *st = arg;
	int err;

	if (0 == pl_strcasecmp(name, "bitrate")) {
		st->bitrate = pl_u32(val) * 1000;
	}
	else if (0 == pl_strcasecmp(name, "frame-size")) {
		st->frame_size = pl_u32(val);

		if (st->frame_size & 0x1) {
			DEBUG_WARNING("frame-size is NOT even: %u\n",
				      st->frame_size);
		}
	}
	else if (0 == pl_strcasecmp(name, "low-overhead")) {
		struct pl fs, bpfv;
		uint32_t i;

		st->low_overhead = true;

		err = re_regex(val->p, val->l, "[0-9]+/[0-9,]+", &fs, &bpfv);
		if (err)
			return;

		st->frame_size = pl_u32(&fs);

		for (i=0; i<ARRAY_SIZE(st->bpfv) && bpfv.l > 0; i++) {
			struct pl bpf, co;

			co.l = 0;
			if (re_regex(bpfv.p, bpfv.l, "[0-9]+[,]*", &bpf, &co))
				break;

			pl_advance(&bpfv, bpf.l + co.l);

			st->bpfv[i] = pl_u32(&bpf);
		}
		st->bpfn = i;
	}
	else {
		DEBUG_NOTICE("unknown param: %r = %r\n", name, val);
	}
}
Пример #19
0
static bool cmp_handler(struct le *le, void *arg)
{
	struct realm *realm = le->data;
	struct pl *chrealm = arg;

	/* handle multiple authenticate headers with equal realm value */
	if (realm->nc == 1)
		return false;

	return 0 == pl_strcasecmp(chrealm, realm->realm);
}
Пример #20
0
bool hdr_fetch(struct le *le, void *arg)
{
    int err = 0;
    struct http_hdr *hdr = le->data;
    struct hdr_fetch *op = arg;

    if(pl_strcasecmp(&hdr->name, op->name) == 0) {
        err = pl_strdup(op->val, &hdr->val);
        return true;
    }

    return false;
}
Пример #21
0
/**
 * Get the boolean value of a configuration item
 *
 * @param conf Configuration object
 * @param name Name of config item key
 * @param val  Returned boolean value of config item, if present
 *
 * @return 0 if success, otherwise errorcode
 */
int conf_get_bool(const struct conf *conf, const char *name, bool *val)
{
	struct pl pl;
	int err;

	if (!conf || !name || !val)
		return EINVAL;

	err = conf_get(conf, name, &pl);
	if (err)
		return err;

	if (!pl_strcasecmp(&pl, "true"))
		*val = true;
	else if (!pl_strcasecmp(&pl, "yes"))
		*val = true;
	else if (!pl_strcasecmp(&pl, "1"))
		*val = true;
	else
		*val = false;

	return 0;
}
Пример #22
0
static int module_init(void)
{
	int err = 0;

#ifdef MODULE_CONF
	struct pl pl;

	if (!conf_get(conf_cur(), "opus_application", &pl)) {

		if (!pl_strcasecmp(&pl, "voip"))
			opus.app = OPUS_APPLICATION_VOIP;
		else if (!pl_strcasecmp(&pl, "audio"))
			opus.app = OPUS_APPLICATION_AUDIO;
		else {
			DEBUG_WARNING("unknown application: %r\n", &pl);
		}
	}

	if (!conf_get(conf_cur(), "opus_bandwidth", &pl)) {

		if (!pl_strcasecmp(&pl, "narrowband"))
			opus.bandwidth = OPUS_BANDWIDTH_NARROWBAND;
		else if (!pl_strcasecmp(&pl, "mediumband"))
			opus.bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
		else if (!pl_strcasecmp(&pl, "wideband"))
			opus.bandwidth = OPUS_BANDWIDTH_WIDEBAND;
		else if (!pl_strcasecmp(&pl, "superwideband"))
			opus.bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
		else if (!pl_strcasecmp(&pl, "fullband"))
			opus.bandwidth = OPUS_BANDWIDTH_FULLBAND;
		else {
			DEBUG_WARNING("unknown bandwidth: %r\n", &pl);
		}
	}

	conf_get_u32(conf_cur(),  "opus_complexity", &opus.complex);
	conf_get_u32(conf_cur(),  "opus_bitrate",    &opus.bitrate);
	conf_get_bool(conf_cur(), "opus_vbr",        &opus.vbr);
#endif

	err |= aucodec_register(&codecv[0], NULL, "opus", 48000, 2, NULL,
				alloc, encode, decode, NULL);

	err |= aucodec_register(&codecv[1], NULL, "opus", 48000, 1, NULL,
				alloc, encode, decode, NULL);
#if 0
	err |= aucodec_register(&codecv[2], NULL, "opus", 32000, 1, NULL,
				alloc, encode, decode, NULL);
#endif

	return err;
}
Пример #23
0
/*
  decode sdpparameter for h264
*/
static void param_handler(const struct pl *name, const struct pl *val,
			  void *arg)
{
	struct videnc_state *st = arg;

	if (0 == pl_strcasecmp(name, "packetization-mode")) {
		st->h264.packetization_mode = pl_u32(val);

		if (st->h264.packetization_mode != 0) {
			warning("gst_video: illegal packetization-mode %u\n",
				st->h264.packetization_mode);
			return;
		}
	}
	else if (0 == pl_strcasecmp(name, "profile-level-id")) {
		struct pl prof = *val;
		if (prof.l != 6) {
			warning("gst_video: invalid profile-level-id (%r)\n",
				val);
			return;
		}

		prof.l = 2;
		st->h264.profile_idc = pl_x32(&prof); prof.p += 2;
		st->h264.profile_iop = pl_x32(&prof); prof.p += 2;
		st->h264.level_idc   = pl_x32(&prof);
	}
	else if (0 == pl_strcasecmp(name, "max-fs")) {
		st->h264.max_fs = pl_u32(val);
	}
	else if (0 == pl_strcasecmp(name, "max-smbps")) {
		st->h264.max_smbps = pl_u32(val);
	}

	return;
}
Пример #24
0
static void http_req_handler(struct http_conn *conn,
			     const struct http_msg *msg, void *arg)
{
	(void)arg;

	if (0 == pl_strcasecmp(&msg->path, "/")) {

		http_creply(conn, 200, "OK",
			    "text/html;charset=UTF-8",
			    "%H", html_print_cmd, msg);
	}
	else {
		http_ereply(conn, 404, "Not Found");
	}
}
Пример #25
0
static const struct mod_export *lookup_static_module(const struct pl *pl)
{
	struct pl name;
	uint32_t i;

	if (re_regex(pl->p, pl->l, "[^.]+.[^]*", &name, NULL))
		name = *pl;

	for (i=0; ; i++) {
		const struct mod_export *me = mod_table[i];
		if (!me)
			return NULL;
		if (0 == pl_strcasecmp(&name, me->name))
			return me;
	}

	return NULL;
}
Пример #26
0
/**
 * Find a module by name in the list of loaded modules
 *
 * @param name Name of module to find
 *
 * @return Module if found, NULL if not found
 */
struct mod *mod_find(const char *name)
{
	struct le *le;
	struct pl x;

	if (!name)
		return NULL;

	if (re_regex(name, strlen(name), "[/]*[^./]+" MOD_EXT, NULL, &x))
		return NULL;

	for (le = modl.head; le; le = le->next) {
		struct mod *m = le->data;

		if (0 == pl_strcasecmp(&x, m->me->name))
			return m;
	}

	return NULL;
}
Пример #27
0
/**
 * Find the correct UA from the contact user
 *
 * @param cuser Contact username
 *
 * @return Matching UA if found, NULL if not found
 */
struct ua *uag_find(const struct pl *cuser)
{
	struct le *le;

	for (le = uag.ual.head; le; le = le->next) {
		struct ua *ua = le->data;

		if (0 == pl_strcasecmp(cuser, ua->cuser))
			return ua;
	}

	/* Try also matching by AOR, for better interop */
	for (le = uag.ual.head; le; le = le->next) {
		struct ua *ua = le->data;

		if (0 == pl_casecmp(cuser, &ua->acc->luri.user))
			return ua;
	}

	return NULL;
}
Пример #28
0
int subscriber_init(void)
{
	struct le *le;
	int err = 0;

	for (le = list_head(contact_list()); le; le = le->next) {

		struct contact *c = le->data;
		struct sip_addr *addr = contact_addr(c);
		struct pl val;

		if (0 == msg_param_decode(&addr->params, "presence", &val) &&
		    0 == pl_strcasecmp(&val, "p2p")) {

			err |= presence_alloc(le->data);
		}
	}

	info("Subscribing to %u contacts\n", list_count(&presencel));

	return err;
}
Пример #29
0
int stun_uri_decode(struct stun_uri *stun_uri, const char *str)
{
	struct uri uri;
	struct pl pl_uri;
	uint16_t port;
	struct pl transp;
	int err;

	if (!stun_uri || !str)
		return EINVAL;

	pl_set_str(&pl_uri, str);

	err = uri_decode(&uri, &pl_uri);
	if (err) {
		warning("cannot decode URI (%r)\n", &pl_uri);
		return err;
	}

	if (0 == pl_strcasecmp(&uri.scheme, "stun") ||
	    0 == pl_strcasecmp(&uri.scheme, "stuns")) {

		stun_uri->scheme = STUN_SCHEME_STUN;
	}
	else if (0 == pl_strcasecmp(&uri.scheme, "turn") ||
		 0 == pl_strcasecmp(&uri.scheme, "turns")) {

		stun_uri->scheme = STUN_SCHEME_TURN;
	}
	else {
		warning("unsupported stun scheme (%r)\n", &uri.scheme);
		return ENOTSUP;
	}

	stun_uri->secure = 's' == tolower(uri.scheme.p[uri.scheme.l-1]);

	if (uri.port)
		port = uri.port;
	else if (stun_uri->secure)
		port = 5349;
	else
		port = 3478;

	err = sa_set(&stun_uri->addr, &uri.host, port);
	if (err) {
		warning("invalid stun address (%r)\n", &uri.host);
		return err;
	}

	if (0 == re_regex(str, strlen(str), "?transport=[a-z]+", &transp)) {

		if (0 == pl_strcasecmp(&transp, "udp"))
			stun_uri->proto = IPPROTO_UDP;
		else if (0 == pl_strcasecmp(&transp, "tcp"))
			stun_uri->proto = IPPROTO_TCP;
		else {
			warning("unsupported stun transport (%r)\n", &transp);
			return ENOTSUP;
		}

	}
	else {
		stun_uri->proto = IPPROTO_UDP;
	}

	return 0;
}
Пример #30
0
/**
 * 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;
}