Пример #1
0
map_t store_deserialize(const str *input)
{
	map_t map;
	cJSON *json_map, *obj;
	str key;
	int_str_t value;

	map = map_create(AVLMAP_SHARED);
	if (!map) {
		LM_ERR("oom\n");
		return NULL;
	}

	cJSON_InitHooks(&shm_hooks);

	json_map = cJSON_Parse(input->s);
	if (!json_map) {
		LM_ERR("bad JSON input or oom\n");
		goto out;
	}

	if (json_map->type != cJSON_Object) {
		LM_BUG("non-cJSON_Object kv_store col type (%d)", json_map->type);
		goto out;
	}

	for (obj = json_map->child; obj; obj = obj->next) {
		init_str(&key, obj->string);

		switch (obj->type) {
		case cJSON_String:
			value.is_str = 1;
			init_str(&value.s, obj->valuestring);
			break;
		case cJSON_Number:
			value.is_str = 0;
			value.i = obj->valueint;
			break;
		default:
			LM_BUG("unknown obj type (%d)", obj->type);
			continue;
		}

		if (!kv_put(map, &key, &value))
			LM_ERR("oom, map will be incomplete\n");
	}

out:
	cJSON_Delete(json_map);
	cJSON_InitHooks(NULL);
	return map;
}
Пример #2
0
int match_node(const node_info_t *a, const node_info_t *b,
               enum cl_node_match_op match_op)
{
	switch (match_op) {
	case NODE_CMP_ANY:
		break;
	case NODE_CMP_EQ_SIP_ADDR:
		lock_get(a->lock);
		if (!a->sip_addr.s || !b->sip_addr.s ||
				str_strcmp(&a->sip_addr, &b->sip_addr)) {
			lock_release(a->lock);
			return 0;
		}
		lock_release(a->lock);
		break;
	case NODE_CMP_NEQ_SIP_ADDR:
		lock_get(a->lock);
		if (!a->sip_addr.s || !b->sip_addr.s ||
				!str_strcmp(&a->sip_addr, &b->sip_addr)) {
			lock_release(a->lock);
			return 0;
		}
		lock_release(a->lock);
		break;
	default:
		LM_BUG("unknown match_op: %d\n", match_op);
		return 0;
	}

	LM_DBG("matched node %d\n", b->node_id);
	return 1;
}
Пример #3
0
/*
 *
 * pack as hep; version depends on hep_version
 * @in1 source sockkadr
 * @in2 dest sockkadr
 * @in3 protocolo
 * @in4 SIP payload
 * @in5 SIP payload length
 * @out1 packed buffer
 * @out2 packed buffer length
 * it's your job to free the buffers
 */
int pack_hep(union sockaddr_union* from_su, union sockaddr_union* to_su,
		int proto, char *payload, int plen, char **retbuf, int *retlen)
{

	switch (hep_version) {
		case 1:
		case 2:
			if (pack_hepv2(from_su, to_su, proto, payload,
										plen, retbuf, retlen) < 0) {
				LM_ERR("failed to pack using hep protocol version 3\n");
				return -1;
			}
			break;
		case 3:
			if (pack_hepv3(from_su, to_su, proto, payload,
										plen, retbuf, retlen) < 0) {
				LM_ERR("failed to pack using hep protocol version 3\n");
				return -1;
			}
			break;
		default:
			/* version check is being done at startup */
			LM_BUG("invalid hep protocol version [%d]!"
					"Probably memory corruption\n", hep_version);
			return -1;
	}

	return 0;
}
Пример #4
0
/*
 * Convert TLS method string to integer
 */
int tls_parse_method(str* method)
{
	cfg_option_t* opt;

	if (!method) {
		LM_BUG("Invalid parameter value\n");
		return -1;
	}

	opt = cfg_lookup_token(methods, method);
	if (!opt) return -1;

#if OPENSSL_VERSION_NUMBER < 0x1000100fL
	if(opt->val == TLS_USE_TLSv1_1 || opt->val == TLS_USE_TLSv1_1_PLUS) {
		LM_ERR("tls v1.1 not supported by this libssl version: %ld\n",
				(long)OPENSSL_VERSION_NUMBER);
		return -1;
	}
#endif
#if OPENSSL_VERSION_NUMBER < 0x1000105fL
	if(opt->val == TLS_USE_TLSv1_2 || opt->val == TLS_USE_TLSv1_2_PLUS) {
		LM_ERR("tls v1.2 not supported by this libssl version: %ld\n",
				(long)OPENSSL_VERSION_NUMBER);
		return -1;
	}
#endif

	return opt->val;
}
Пример #5
0
static int db_sqlite_bind_values(sqlite3_stmt* stmt, const db_val_t* v, const int n)
{
	int i, ret;

	if (n>0 && v) {
		for (i=0; i<n; i++) {
			if (VAL_NULL(v+i)) {
				ret=sqlite3_bind_null(stmt, i+1);
				goto check_ret;
			}


			switch(VAL_TYPE(v+i)) {
				/* every param has '+1' index because in sqlite the leftmost
				 * parameter has index '1' */
				case DB_INT:
					ret=sqlite3_bind_int(stmt, i+1, VAL_INT(v+i));
					break;
				case DB_BIGINT:
					ret=sqlite3_bind_int64(stmt, i+1, VAL_BIGINT(v+i));
					break;
				case DB_DOUBLE:
					ret=sqlite3_bind_double(stmt, i+1, VAL_DOUBLE(v+i));
					break;
				case DB_STRING:
					ret=sqlite3_bind_text(stmt, i+1, VAL_STRING(v+i),
											strlen(VAL_STRING(v+i)), SQLITE_STATIC);
					break;
				case DB_STR:
					ret=sqlite3_bind_text(stmt, i+1, VAL_STR(v+i).s,
											VAL_STR(v+i).len, SQLITE_STATIC);
					break;
				case DB_DATETIME:
					ret=sqlite3_bind_int64(stmt, i+1, (long int)VAL_TIME(v+i));
					break;
				case DB_BLOB:
					ret=sqlite3_bind_blob(stmt, i+1, (void*)VAL_BLOB(v+i).s,
											VAL_BLOB(v+i).len, SQLITE_STATIC);
					break;
				case DB_BITMAP:
					ret=sqlite3_bind_int(stmt, i+1, (int)VAL_BITMAP(v+i));
					break;
				default:
					LM_BUG("invalid db type\n");
					return 1;
			}

check_ret:
			if (ret != SQLITE_OK) {
				return ret;
			}
		}
	}

	return SQLITE_OK;
}
Пример #6
0
/* Register pre- or post-script callbacks.
 * Returns -1 on error, 0 on success
 */
int register_script_cb( cb_function f, unsigned int flags, void *param )
{
	struct script_cb	**cb_array;
	int	i;

	/* type checkings */
	if ( (flags&((1<<SCRIPT_CB_NUM)-1))==0 ) {
		LM_BUG("callback flag not specified\n");
		return -1;
	}
	if ( (flags&(~(PRE_SCRIPT_CB|POST_SCRIPT_CB))) >= 1<<SCRIPT_CB_NUM ) {
		LM_BUG("unsupported callback flags: %u\n",
			flags);
		return -1;
	}
	if ( (flags&(PRE_SCRIPT_CB|POST_SCRIPT_CB))==0 ||
	(flags&PRE_SCRIPT_CB && flags&POST_SCRIPT_CB) ) {
		LM_BUG("callback POST or PRE type must be exactly one\n");
		return -1;
	}

	if (flags&PRE_SCRIPT_CB)
		cb_array = pre_script_cb;
	else
		cb_array = post_script_cb;

	/* Add the callback to the lists.
	 * (as many times as many flags are set)
	 */
	for (i=0; i<SCRIPT_CB_NUM; i++) {
		if ((flags&(1<<i)) == 0)
			continue;
		if (add_callback(&cb_array[i], f, param) < 0)
			goto add_error;
	}
	return 0;

add_error:
	LM_ERR("failed to add callback\n");
	return -1;
}
Пример #7
0
static mi_response_t *cluster_send_mi(const mi_params_t *params,
								struct mi_handler *async_hdl)
{
	int cluster_id, node_id;
	int rc;
	str cmd_name;
	mi_item_t *cmd_params_arr = NULL;
	int no_params = 0;

	if (get_mi_int_param(params, "cluster_id", &cluster_id) < 0)
		return init_mi_param_error();
	if (cluster_id < 1)
		return init_mi_error(400, MI_SSTR("Bad value for 'cluster_id'"));

	if (get_mi_int_param(params, "destination", &node_id) < 0)
		return init_mi_param_error();
	if (node_id < 1)
		return init_mi_error(400, MI_SSTR("Bad value for 'destination'"));
	if (node_id == current_id)
		return init_mi_error(400, MI_SSTR("Local node specified as destination"));

	if (get_mi_string_param(params, "cmd_name", &cmd_name.s, &cmd_name.len) < 0)
		return init_mi_param_error();

	rc = try_get_mi_array_param(params, "cmd_params", &cmd_params_arr, &no_params);
	if (rc < 0) {
		cmd_params_arr = NULL;
		if (rc == -2)
			return init_mi_param_error();
	}

	rc = send_mi_cmd(cluster_id, node_id, cmd_name, cmd_params_arr, no_params);
	switch (rc) {
		case CLUSTERER_SEND_SUCCES:
			LM_DBG("MI command <%.*s> sent\n", cmd_name.len, cmd_name.s);
			return init_mi_result_ok();
		case CLUSTERER_CURR_DISABLED:
			LM_INFO("Local node disabled, MI command <%.*s> not sent\n",
				cmd_name.len, cmd_name.s);
			return init_mi_result_string(MI_SSTR("Local node disabled"));
		case CLUSTERER_DEST_DOWN:
			LM_ERR("Destination down, MI command <%.*s> not sent\n",
				cmd_name.len, cmd_name.s);
			return init_mi_error(400, MI_SSTR("Destination down"));
		case CLUSTERER_SEND_ERR:
			LM_ERR("Error sending MI command <%.*s>+\n",
				cmd_name.len, cmd_name.s);
			return init_mi_error(400, MI_SSTR("Send error"));
		default:
			LM_BUG("Bad send error code\n");
			return init_mi_error(400, MI_SSTR("Internal error"));
	}
}
Пример #8
0
int db_postgres_async_resume(db_con_t *_h, int fd, db_res_t **_r, void *_priv)
{
	struct pool_con *con = (struct pool_con *)_priv;
	PGresult *res = NULL;

#ifdef EXTRA_DEBUG
	if (!db_match_async_con(fd, _h)) {
		LM_BUG("no conn match for fd %d", fd);
		abort();
	}
#endif


	db_switch_to_async(_h, con);

	if( PQconsumeInput(CON_CONNECTION(_h)) == 0) {
		LM_ERR("Unable to consume input\n");
		db_switch_to_sync(_h);
		db_store_async_con(_h, con);
		return -1;
	}

	if(PQisBusy(CON_CONNECTION(_h))) {
		async_status = ASYNC_CONTINUE;

		db_switch_to_sync(_h);
		return 1;
	}

	while (1) {
		if ((res = PQgetResult(CON_CONNECTION(_h)))) {
			CON_RESULT(_h) = res;
		} else {
			break;
		}
	}

	if (_r) {
		if (db_postgres_store_result(_h, _r) != 0) {
			LM_ERR("failed to store result\n");
			db_switch_to_sync(_h);
			db_store_async_con(_h, con);
			return -2;
		}
	}

	db_switch_to_sync(_h);
	db_store_async_con(_h, con);

	return 0;
}
Пример #9
0
static int avpops_init(void)
{
	LM_INFO("initializing...\n");

	if (db_table.s)
		db_table.len = strlen(db_table.s);
	uuid_col.len = strlen(uuid_col.s);
	attribute_col.len = strlen(attribute_col.s);
	value_col.len = strlen(value_col.s);
	type_col.len = strlen(type_col.s);
	username_col.len = strlen(username_col.s);
	domain_col.len = strlen(domain_col.s);

	default_db_url = get_default_db_url();
	if (default_db_url==NULL) {
		if (db_default_url==NULL) {
			LM_ERR("no DB URL provision into the module!\n");
			return -1;
		}
		/* if nothing explicitly set as DB URL, add automatically
		 * the default DB URL */
		if (add_db_url(STR_PARAM, db_default_url)!=0) {
			LM_ERR("failed to use the default DB URL!\n");
			return -1;
		}
		default_db_url = get_default_db_url();
		if (default_db_url==NULL) {
			LM_BUG("Really ?!\n");
			return -1;
		}
	}

	/* bind to the DB module */
	if (avpops_db_bind()<0)
		goto error;

	init_store_avps(db_columns);

	printbuf = (char*)pkg_malloc((buf_size+1)*sizeof(char));
	if(printbuf==NULL) {
		LM_ERR("no pkg memory left\n");
		return -1;
	}

	return 0;
error:
	return -1;
}
Пример #10
0
/* Execute post-script callbacks of a given type.
 * Always returns 1, success.
 */
int exec_post_script_cb( struct sip_msg *msg, enum script_cb_type type)
{
	struct script_cb	*cb;
	unsigned int	flags;

	if (type > SCRIPT_CB_NUM) {
		LM_BUG("unknown callback type %d\n", type);
		return 1;
	}

	flags = POST_SCRIPT_CB | (1<<(type-1));
	for (cb=post_script_cb[type-1]; cb ; cb=cb->next){
		cb->cbf(msg, flags, cb->param);
	}
	return 1;
}
Пример #11
0
/*
 * setter function for $acc_extra
 */
int pv_set_acc_extra(struct sip_msg *msg, pv_param_t *param, int op,
		pv_value_t *val)
{
	int tag_idx;

	acc_ctx_t* ctx=try_fetch_ctx();

	if (param == NULL || val == NULL) {
		LM_ERR("bad params!\n");
		return -1;
	}

	if (ctx == NULL) {
		/* if we don't have a context then create it */
		if (init_acc_ctx(&ctx) < 0) {
			LM_ERR("failed to create accounting context!\n");
			return -1;
		}

		ACC_PUT_CTX(ctx);
	}


	tag_idx = param->pvn.u.isname.name.n;
	/* sanity checks for the tag; it should be valid since
	 * we found it in the parse name function */
	if (tag_idx < 0 || tag_idx >= extra_tgs_len) {
		LM_BUG("invalid tag value! probably a memory corruption issue!\n");
		return -1;
	}


	/* go through all extras and fetch first value you find
	 * all the extras with the same tag will have the same
	 * value */
	accX_lock(&ctx->lock);
	if (set_value_shm(val, &ctx->extra_values[tag_idx]) < 0) {
		LM_ERR("failed to set extra <%.*s> value!\n",
				extra_tags[tag_idx].len, extra_tags[tag_idx].s);
		accX_unlock(&ctx->lock);
		return -1;
	}
	accX_unlock(&ctx->lock);

	return 0;
}
Пример #12
0
/* Execute pre-script callbacks of a given type.
 * Returns 0 on error, 1 on success
 */
int exec_pre_script_cb( struct sip_msg *msg, enum script_cb_type type)
{
	struct script_cb	*cb;
	unsigned int	flags;

	if (type > SCRIPT_CB_NUM) {
		LM_BUG("unknown callback type %d\n", type);
		return 0;
	}

	flags = PRE_SCRIPT_CB | (1<<(type-1));
	for (cb=pre_script_cb[type-1]; cb ; cb=cb->next ) {
		/* stop on error */
		if (cb->cbf(msg, flags, cb->param)==0)
			return 0;
	}
	return 1;
}
Пример #13
0
/*
 * Wrapper around SSL_write, returns number of bytes written on success, *
 * -1 on error, 0 when it would block
 */
static int tls_write(struct tcp_connection *c, int fd, const void *buf,
												size_t len, short *poll_events)
{
	int             ret,
					err;
	/*
	* runs within write lock, no need to lock here
	*/
	SSL            *ssl;

	ssl = (SSL *) c->extra_data;

	ret = SSL_write(ssl, buf, len);
	if (ret > 0) {
		LM_DBG("write was successful (%d bytes)\n", ret);
		return ret;
	} else {
		err = SSL_get_error(ssl, ret);
		switch (err) {
		case SSL_ERROR_ZERO_RETURN:
			LM_DBG("connection closed cleanly\n");
			c->state = S_CONN_EOF;
			return -1;
		case SSL_ERROR_WANT_READ:
			if (poll_events)
				*poll_events = POLLIN;
			return 0;
		case SSL_ERROR_WANT_WRITE:
			if (poll_events)
				*poll_events = POLLOUT;
			return 0;
		default:
			LM_ERR("TLS connection to %s:%d write failed\n",
				ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
			LM_ERR("TLS write error:\n");
			c->state = S_CONN_BAD;
			tls_print_errstack();
			return -1;
		}
	}

	LM_BUG("bug\n");
	return -1;
}
Пример #14
0
/*
 * Wrapper around SSL_read
 *
 * returns number of bytes read, 0 on eof and transits into S_CONN_EOF, -1
 * on error
 */
static int _tls_read(struct tcp_connection *c, void *buf, size_t len)
{
	int ret, err;
	SSL *ssl;

	ssl = c->extra_data;

	ret = SSL_read(ssl, buf, len);
	if (ret > 0) {
		LM_DBG("%d bytes read\n", ret);
		return ret;
	} else {
		err = SSL_get_error(ssl, ret);
		switch (err) {
		case SSL_ERROR_ZERO_RETURN:
			LM_DBG("TLS connection to %s:%d closed cleanly\n",
				ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
			/*
			* mark end of file
			*/
			c->state = S_CONN_EOF;
			return 0;

		case SSL_ERROR_WANT_READ:
		case SSL_ERROR_WANT_WRITE:
			return 0;

		case SSL_ERROR_SYSCALL:
			LM_ERR("SYSCALL error -> (%d) <%s>\n",errno,strerror(errno));
		default:
			LM_ERR("TLS connection to %s:%d read failed\n",
				ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
			LM_ERR("TLS read error: %d\n",err);
			c->state = S_CONN_BAD;
			tls_print_errstack();
			return -1;
		}
	}

	LM_BUG("bug\n");
	return -1;
}
Пример #15
0
static struct usr_avp *pack_evi_params_as_avp_list(evi_params_t *params)
{
	struct usr_avp *avp, *head=NULL;
	evi_param_t *e_param;
	int_str val;
	int avp_id;

	/* take all the EVI parameters and convert them into AVPs */
	for( e_param=params->first ; e_param ; e_param=e_param->next ) {

		/* get an AVP name matching the param name */
		if (parse_avp_spec( &e_param->name, &avp_id)<0) {
			LM_ERR("cannot get AVP ID for name <%.*s>, skipping..\n",
				e_param->name.len, e_param->name.s);
			continue;
		}

		/* create a new AVP */
		if (e_param->flags&EVI_STR_VAL) {
			val.s = e_param->val.s;
			avp = new_avp( AVP_VAL_STR, avp_id, val);
		} else if (e_param->flags&EVI_INT_VAL) {
			val.n = e_param->val.n;
			avp = new_avp( 0, avp_id, val);
		} else {
			LM_BUG("EVI param no STR, nor INT, ignoring...\n");
			continue;
		}

		if (avp==NULL) {
			LM_ERR("cannot get create new AVP name <%.*s>, skipping..\n",
				e_param->name.len, e_param->name.s);
			continue;
		}

		/* link the AVP */
		avp->next = head;
		head = avp;
	}

	return head;
}
Пример #16
0
/*
 * getter function for $acc_extra
 */
int pv_get_acc_extra(struct sip_msg *msg, pv_param_t *param,
		pv_value_t *val)
{
	int tag_idx;

	acc_ctx_t* ctx=try_fetch_ctx();

	if (param == NULL || val == NULL) {
		LM_ERR("bad input params!\n");
		return -1;
	}

	if (ctx == NULL) {
		/* if we don't have a context then create it */
		if (init_acc_ctx(&ctx) < 0) {
			LM_ERR("failed to create accounting context!\n");
			return -1;
		}

		ACC_PUT_CTX(ctx);
	}

	tag_idx = param->pvn.u.isname.name.n;
	/* sanity checks for the tag; it should be valid since
	 * we found it in the parse name function */
	if (tag_idx < 0 || tag_idx >= extra_tgs_len) {
		LM_BUG("invalid tag value! probably a memory corruption issue!\n");
		return -1;
	}


	accX_lock(&ctx->lock);
	if (ctx->extra_values[tag_idx].value.s == NULL) {
		val->flags = PV_VAL_NULL;
	} else {
		val->rs = ctx->extra_values[tag_idx].value;
		val->flags = PV_VAL_STR;
	}
	accX_unlock(&ctx->lock);

	return 0;
}
Пример #17
0
void wrap_tm_func(struct cell* t, int type, struct tmcb_params* p)
{
	char* buf = t->uac[p->code].request.buffer.s;
	int olen = t->uac[p->code].request.buffer.len;
	void* args;

	switch (type) {
		case COMPRESS_CB:
			if ((args = GET_GLOBAL_CTX(compress_ctx_pos)) == NULL)
				break;

			if (mc_compress_cb(&buf, args, TM_CB, &olen) < 0) {
				LM_ERR("compression failed\n");
				return;
			}

			pkg_free(args);
			SET_GLOBAL_CTX(compress_ctx_pos, NULL);
			break;
		case COMPACT_CB:
			/* if not registered yet we take from global context */
			if ((args = GET_GLOBAL_CTX(compact_ctx_pos)) == NULL)
				break;

			if (mc_compact_cb(&buf, args, TM_CB, &olen) < 0) {
				LM_ERR("compaction failed\n");
				return;
			}

			pkg_free(args);
			SET_GLOBAL_CTX(compact_ctx_pos, NULL);

			break;
		default:
			LM_BUG("!!! invalid CB type arg!\n");
			return;
	}

	t->uac[p->code].request.buffer.s = buf;
	t->uac[p->code].request.buffer.len = olen;
}
Пример #18
0
void remove_part_struct(struct pm_part_struct *part_struct)
{
	struct pm_part_struct *before, *el;

	if (!part_structs)
		LM_BUG("no part structs; what are you asking for?\n");

	before = el =  part_structs;
	while (el) {
		if (part_struct == el) {
			if (el->next)
				before->next = el->next;
			pkg_free(el);
		}

		if (before != el)
			before = before->next;

		el = el->next;
	}
}
Пример #19
0
static int fixup_wpvar(void **param)
{
	int ret;
	pv_spec_t *spec;
	ret = fixup_pvar(param);
	if (ret != 0) {
		LM_ERR("cannot parse pvar\n");
		return -1;
	}
	spec = *(pv_spec_t **)param;
	if (!spec) {
		LM_BUG("cannot find spec");
		return -1;
	}
	if (!spec->setf)
	{
		LM_ERR("pvar not writable\n");
		return -1;
	}
	return 0;
}
Пример #20
0
int add_listener(struct socket_id *sock, enum si_flags flags)
{
	/*
	 * XXX: using the new version, the protocol _MUST_ be specified
	 * otherwise UDP will be assumed
	 */
	enum sip_protos proto = sock->proto;

	/* validate the protocol */
	if (proto < PROTO_FIRST || proto >= PROTO_LAST) {
		LM_BUG("invalid protocol number %d\n", proto);
		return -1;
	}

	/* convert to socket_info */
	if (new_sock2list(sock->name, sock->port, sock->proto, sock->adv_name, sock->adv_port,
			sock->children, flags, &protos[proto].listeners) < 0) {
		LM_ERR("cannot add socket to the list\n");
		return -1;
	}

	return 0;
}
Пример #21
0
static inline unsigned short uri2port(const struct sip_uri *puri)
{
	if (puri->port.s) {
		return puri->port_no;
	} else switch (puri->type) {
		case SIP_URI_T:
		case TEL_URI_T:
			if (puri->transport_val.len == sizeof("TLS") - 1) {
				unsigned trans;
				trans = puri->transport_val.s[0] | 0x20; trans <<= 8;
				trans |= puri->transport_val.s[1] | 0x20; trans <<= 8;
				trans |= puri->transport_val.s[2] | 0x20;
				if (trans == 0x746C73) /* t l s */
					return SIPS_PORT;
			}
			return SIP_PORT;
		case SIPS_URI_T:
		case TELS_URI_T:
			return SIPS_PORT;
		default:
			LM_BUG("unexpected URI type %d.\n", puri->type);
	}
	return 0;
}
Пример #22
0
static struct tcp_connection* ws_connect(struct socket_info* send_sock,
		union sockaddr_union* to, int *fd)
{
	struct tcp_connection *c;

	if ((c=ws_sync_connect(send_sock, to))==0) {
		LM_ERR("connect failed\n");
		return NULL;
	}
	/* the state of the connection should be NONE, otherwise something is
	 * wrong */
	if (WS_TYPE(c) != WS_NONE) {
		LM_BUG("invalid type for connection %d\n", WS_TYPE(c));
		goto error;
	}
	WS_TYPE(c) = WS_CLIENT;

	if (ws_client_handshake(c) < 0) {
		LM_ERR("cannot complete WebSocket handshake\n");
		goto error;
	}

	*fd = c->fd;
	/* clear the fd, just in case */
	c->fd = -1;
	/* handshake done - send the socket to main */
	if (tcp_conn_send(c) < 0) {
		LM_ERR("cannot send socket to main\n");
		goto error;
	}

	return c;
error:
	tcp_conn_destroy(c);
	return NULL;
}
Пример #23
0
/**
 * Evaluates the routing elements in locally originated request or reply to
 * locally originated request.
 * If original INVITE was in-dialog (had to-tag), it uses the
 * routes present there (b/c the 2xx for it does not have a RR set, normally).
 * Otherwise, use the reply (b/c the INVITE does not have yet the complete
 * route set).
 *
 * @return: negative for failure; out params:
 *  - list: route set;
 *  - ruri: RURI to be used in ACK;
 *  - nexthop: where to first send the ACK.
 *
 *  NOTE: assumes rpl's parsed to EOF!
 *
 */
static int eval_uac_routing(sip_msg_t *rpl, const struct retr_buf *inv_rb,
		str* contact, struct rte **list, str *ruri, str *next_hop)
{
	sip_msg_t orig_inv, *sipmsg; /* reparse original INVITE */
	rte_t *t, *prev_t, *rtset = NULL;
	int is_req;
	struct sip_uri puri;
	static size_t chklen;

	/* parse the retr. buffer */
	memset(&orig_inv, 0, sizeof(struct sip_msg));
	orig_inv.buf = inv_rb->buffer;
	orig_inv.len = inv_rb->buffer_len;
	LM_DBG("reparsing retransmission buffer of original INVITE:\n%.*s\n",
			(int)orig_inv.len, orig_inv.buf);
	if (parse_msg(orig_inv.buf, orig_inv.len, &orig_inv) != 0) {
		LM_ERR("failed to parse retr buffer (weird!): \n%.*s\n",
				(int)orig_inv.len, orig_inv.buf);
		return -1;
	}

	/* check if we need to look at request or reply */
	if ((parse_headers(&orig_inv, HDR_TO_F, 0) < 0) || (! orig_inv.to)) {
		/* the bug is at message assembly */
		LM_BUG("failed to parse INVITE retr. buffer and/or extract 'To' HF:"
				"\n%.*s\n", (int)orig_inv.len, orig_inv.buf);
		goto error;
	}
	if (((struct to_body *)orig_inv.to->parsed)->tag_value.len) {
		LM_DBG("building ACK for in-dialog INVITE (using RS in orig. INV.)\n");
		if (parse_headers(&orig_inv, HDR_EOH_F, 0) < 0) {
			LM_BUG("failed to parse INVITE retr. buffer to EOH:"
					"\n%.*s\n", (int)orig_inv.len, orig_inv.buf);
			goto error;
		}
		sipmsg = &orig_inv;
		is_req = 1;
	} else {
		LM_DBG("building ACK for out-of-dialog INVITE (using RS in RR set).\n");
		sipmsg = rpl;
		is_req = 0;
	}

	/* extract the route set */
	if (get_uac_rs(sipmsg, is_req, &rtset) < 0) {
		LM_ERR("failed to extract route set.\n");
		goto error;
	}

	if (! rtset) { /* No routes */
		*ruri = *contact;
		*next_hop = *contact;
	} else if (! is_req) { /* out of dialog req. */
		if (parse_uri(rtset->ptr->nameaddr.uri.s, rtset->ptr->nameaddr.uri.len,
				&puri) < 0) {
			LM_ERR("failed to parse first route in set.\n");
			goto error;
		}

		if (puri.lr.s) { /* Next hop is loose router */
			*ruri = *contact;
			*next_hop = rtset->ptr->nameaddr.uri;
		} else { /* Next hop is strict router */
			*ruri = rtset->ptr->nameaddr.uri;
			*next_hop = *ruri;
			/* consume first route, b/c it will be put in RURI */
			t = rtset;
			rtset = rtset->next;
			pkg_free(t);
		}
	} else {
		unsigned long route_flags = inv_rb->flags;
		LM_DBG("UAC rb flags: 0x%x.\n", (unsigned int)route_flags);
eval_flags:
		switch (route_flags & (F_RB_NH_LOOSE|F_RB_NH_STRICT)) {
		case 0:
			LM_WARN("calculate_hooks() not called when built the local UAC of "
					"in-dialog request, or called with empty route set.\n");
			/* try to figure out what kind of hop is the next one
			 * (strict/loose) by reading the original invite */
			if ((route_flags = nhop_type(&orig_inv, rtset, &inv_rb->dst,
					contact))) {
				LM_DBG("original request's next hop type evaluated to: 0x%x.\n",
						(unsigned int)route_flags);
				goto eval_flags;
			} else {
				LM_ERR("failed to establish what kind of router the next "
						"hop is.\n");
				goto error;
			}
			break;
		case F_RB_NH_LOOSE:
			*ruri = *contact;
			*next_hop = rtset->ptr->nameaddr.uri;
			break;
		case F_RB_NH_STRICT:
			/* find ptr to last route body that contains the (possibly) old
			 * remote target
			 */
			for (t = rtset, prev_t = NULL; t->next; prev_t = t, t = t->next)
				;
			if ((t->ptr->len == contact->len) &&
					(memcmp(t->ptr->nameaddr.name.s, contact->s,
							contact->len) == 0)){
				/* the remote target didn't update -> keep the whole route set,
				 * including the last entry */
				/* do nothing */
			} else {
				/* trash last entry and replace with new remote target */
				free_rte_list(t);
				/* compact the rr_t struct along with rte. this way, free'ing
				 * it can be done along with rte chunk, independent of Route
				 * header parser's allocator (using pkg/shm) */
				chklen = sizeof(struct rte) + sizeof(rr_t);
				if (! (t = pkg_malloc(chklen))) {
					ERR("out of pkg memory (%d required)\n", (int)chklen);
					/* last element was freed, unlink it */
					if(prev_t == NULL) {
						/* there is only one elem in route set: the remote target */
						rtset = NULL;
					} else {
						prev_t->next = NULL;
					}
					goto error;
				}
				/* this way, .free_rr is also set to 0 (!!!) */
				memset(t, 0, chklen);
				((rr_t *)&t[1])->nameaddr.name = *contact;
				((rr_t *)&t[1])->len = contact->len;
				/* chain the new route elem in set */
				if (prev_t == NULL)
					/* there is only one elem in route set: the remote target */
					rtset = t;
				else
					prev_t->next = t;
			}

			*ruri = *GET_RURI(&orig_inv); /* reuse original RURI */
			*next_hop = *ruri;
			break;
		default:
			/* probably a mem corruption */
			LM_BUG("next hop of original request marked as both loose"
					" and strict router (buffer: %.*s).\n",
					inv_rb->buffer_len, inv_rb->buffer);
#ifdef EXTRA_DEBUG
			abort();
#else
			goto error;
#endif
		}
	}

	*list = rtset;
	free_sip_msg(&orig_inv);
	/* all went well */
	return 0;

error:
	free_sip_msg(&orig_inv);
	if (rtset)
		free_rte_list(rtset);
	return -1;
}
Пример #24
0
/* Build a local request based on a previous request; main
 * customers of this function are local ACK and local CANCEL
 */
char *build_local(struct cell *Trans,unsigned int branch,
	unsigned int *len, char *method, int method_len, str *to
#ifdef CANCEL_REASON_SUPPORT
	, struct cancel_reason* reason
#endif /* CANCEL_REASON_SUPPORT */
	)
{
	char                *cancel_buf, *p, *via;
	unsigned int         via_len;
	struct hdr_field    *hdr;
	char branch_buf[MAX_BRANCH_PARAM_LEN];
	int branch_len;
	str branch_str;
	str via_id;
	struct hostport hp;
#ifdef CANCEL_REASON_SUPPORT
	int reason_len, code_len;
	struct hdr_field *reas1, *reas_last;
#endif /* CANCEL_REASON_SUPPORT */

	/* init */
	via_id.s=0;
	via_id.len=0;

	/* method, separators, version: "CANCEL sip:[email protected] SIP/2.0" */
	*len=SIP_VERSION_LEN + method_len + 2 /* spaces */ + CRLF_LEN;
	*len+=Trans->uac[branch].uri.len;

	/*via*/
	if (!t_calc_branch(Trans,  branch,
		branch_buf, &branch_len ))
		goto error;
	branch_str.s=branch_buf;
	branch_str.len=branch_len;
	set_hostport(&hp, (is_local(Trans))?0:(Trans->uas.request));
#ifdef USE_TCP
	if (!is_local(Trans) && ((Trans->uas.request->rcv.proto==PROTO_TCP)
#ifdef USE_TLS
				|| (Trans->uas.request->rcv.proto==PROTO_TLS)
#endif /* USE_TLS */
		)){
		if ((via_id.s=id_builder(Trans->uas.request,
									(unsigned int*)&via_id.len))==0){
			LM_ERR("id builder failed\n");
			/* try to continue without id */
		}
	}
#endif /* USE_TCP */
	via=via_builder(&via_len, NULL, &Trans->uac[branch].request.dst,
		&branch_str, via_id.s?&via_id:0 , &hp );

	/* via_id.s not needed anylonger => free it */
	if (via_id.s) {
		pkg_free(via_id.s);
		via_id.s=0;
		via_id.len=0;
	}

	if (!via) {
		LM_ERR("no via header got from builder\n");
		goto error;
	}
	*len+= via_len;
	/*headers*/
	*len+=Trans->from.len+Trans->callid.len+to->len+
		+Trans->cseq_n.len+1+method_len+CRLF_LEN+MAXFWD_HEADER_LEN;


	/* copy'n'paste Route headers */
	if (!is_local(Trans)) {
		for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
			if (hdr->type==HDR_ROUTE_T)
				*len+=hdr->len;
	}

	/* User Agent */
	if (server_signature) {
		*len += user_agent_hdr.len + CRLF_LEN;
	}
	/* Content Length, EoM */
	*len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
#ifdef CANCEL_REASON_SUPPORT
	reason_len = 0;
	reas1 = 0;
	reas_last = 0;
	/* compute reason size (if no reason or disabled => reason_len == 0)*/
	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
		if (likely(reason->cause > 0 &&
					cfg_get(tm, tm_cfg, local_cancel_reason))){
			/* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */
			reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN +
				(reason->u.text.s?
					REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) +
				CRLF_LEN;
		} else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS &&
					!(Trans->flags & T_NO_E2E_CANCEL_REASON))) {
			reason_len = reason->u.packed_hdrs.len;
		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
					reason->u.e2e_cancel &&
					!(Trans->flags & T_NO_E2E_CANCEL_REASON)) {
			/* parse the entire cancel, to get all the Reason headers */
			if(parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0)<0) {
				LM_WARN("failed to parse headers\n");
			}
			for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr;
					hdr; hdr=next_sibling_hdr(hdr)) {
				/* hdr->len includes CRLF */
				reason_len += hdr->len;
				reas_last=hdr;
			}
		} else if (unlikely(reason->cause < CANCEL_REAS_MIN))
			LM_BUG("unhandled reason cause %d\n", reason->cause);
	}
	*len+= reason_len;
#endif /* CANCEL_REASON_SUPPORT */
	*len+= CRLF_LEN; /* end of msg. */

	cancel_buf=shm_malloc( *len+1 );
	if (!cancel_buf) {
		LM_ERR("cannot allocate memory\n");
		goto error01;
	}
	p = cancel_buf;

	append_str( p, method, method_len );
	append_str( p, " ", 1 );
	append_str( p, Trans->uac[branch].uri.s, Trans->uac[branch].uri.len);
	append_str( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN );

	/* insert our via */
	append_str(p,via,via_len);

	/*other headers*/
	append_str( p, Trans->from.s, Trans->from.len );
	append_str( p, Trans->callid.s, Trans->callid.len );
	append_str( p, to->s, to->len );

	append_str( p, Trans->cseq_n.s, Trans->cseq_n.len );
	append_str( p, " ", 1 );
	append_str( p, method, method_len );
	append_str( p, CRLF, CRLF_LEN );
	append_str( p, MAXFWD_HEADER, MAXFWD_HEADER_LEN );

	if (!is_local(Trans))  {
		for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
			if(hdr->type==HDR_ROUTE_T) {
				append_str(p, hdr->name.s, hdr->len );
			}
	}

	/* User Agent header */
	if (server_signature) {
		append_str(p, user_agent_hdr.s, user_agent_hdr.len );
		append_str(p, CRLF, CRLF_LEN );
	}
	/* Content Length */
	append_str(p, CONTENT_LENGTH "0" CRLF, CONTENT_LENGTH_LEN + 1 + CRLF_LEN);
#ifdef CANCEL_REASON_SUPPORT
	/* add reason if needed */
	if (reason_len) {
		if (likely(reason->cause > 0)) {
			append_str(p, REASON_PREFIX, REASON_PREFIX_LEN);
			code_len=ushort2sbuf(reason->cause, p,
									*len-(int)(p-cancel_buf));
			if (unlikely(code_len==0))
				LM_BUG("not enough space to write reason code");
			p+=code_len;
			if (reason->u.text.s){
				append_str(p, REASON_TEXT, REASON_TEXT_LEN);
				*p='"'; p++;
				append_str(p, reason->u.text.s, reason->u.text.len);
				*p='"'; p++;
			}
			append_str(p, CRLF, CRLF_LEN);
		} else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS)) {
			append_str(p, reason->u.packed_hdrs.s, reason->u.packed_hdrs.len);
		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
			for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) {
				/* hdr->len includes CRLF */
				append_str(p, hdr->name.s, hdr->len);
				if (likely(hdr==reas_last))
					break;
			}
		}
	}
#endif /* CANCEL_REASON_SUPPORT */
	append_str(p, CRLF, CRLF_LEN); /* msg. end */
	*p=0;

	pkg_free(via);
	return cancel_buf;
error01:
	pkg_free(via);
error:
	return NULL;
}
Пример #25
0
/* Re-parsing version of build_local() function:
 * it builds a local CANCEL or ACK (for non-200 response) request based on
 * the previous INVITE which was sent out.
 *
 * Can not be used to build other type of requests!
 */
char *build_local_reparse(struct cell *Trans,unsigned int branch,
	unsigned int *len, char *method, int method_len, str *to
#ifdef CANCEL_REASON_SUPPORT
	, struct cancel_reason *reason
#endif /* CANCEL_REASON_SUPPORT */
	)
{
	char	*invite_buf, *invite_buf_end;
	char	*cancel_buf;
	char	*s, *s1, *d;	/* source and destination buffers */
	short	invite_len;
	enum _hdr_types_t	hf_type;
	int	first_via, to_len;
	int cancel_buf_len;
#ifdef CANCEL_REASON_SUPPORT
	int reason_len, code_len;
	struct hdr_field *reas1, *reas_last, *hdr;
#endif /* CANCEL_REASON_SUPPORT */
	int hadded = 0;
	sr_cfgenv_t *cenv = NULL;

	invite_buf = Trans->uac[branch].request.buffer;
	invite_len = Trans->uac[branch].request.buffer_len;

	if (!invite_buf || !invite_len) {
		LM_ERR("INVITE is missing\n");
		goto error;
	}
	if ((*invite_buf != 'I') && (*invite_buf != 'i')) {
		LM_ERR("trying to build with local reparse"
					" for a non-INVITE request?\n");
		goto error;
	}

#ifdef CANCEL_REASON_SUPPORT
	reason_len = 0;
	reas1 = 0;
	reas_last = 0;
	/* compute reason size (if no reason or disabled => reason_len == 0)*/
	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
		if (likely(reason->cause > 0 &&
					cfg_get(tm, tm_cfg, local_cancel_reason))){
			/* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */
			reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN +
				(reason->u.text.s?
					REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) +
				CRLF_LEN;
		} else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS &&
					!(Trans->flags & T_NO_E2E_CANCEL_REASON))) {
			reason_len = reason->u.packed_hdrs.len;
		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
					reason->u.e2e_cancel &&
					!(Trans->flags & T_NO_E2E_CANCEL_REASON)) {
			/* parse the entire cancel, to get all the Reason headers */
			if(parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0)<0) {
				LM_WARN("failed to parse headers\n");
			}
			for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr;
					hdr; hdr=next_sibling_hdr(hdr)) {
				/* hdr->len includes CRLF */
				reason_len += hdr->len;
				reas_last=hdr;
			}
		} else if (unlikely(reason->cause < CANCEL_REAS_MIN))
			LM_BUG("unhandled reason cause %d\n", reason->cause);
	}
#endif /* CANCEL_REASON_SUPPORT */

	invite_buf_end = invite_buf + invite_len;
	s = invite_buf;

	/* Allocate memory for the new message.
	The new request will be smaller than the INVITE, so the same size is enough.
	I just extend it with the length of new To HF to be sure.
	Ugly, but we avoid lots of checks and memory allocations this way */
	to_len = to ? to->len : 0;
#ifdef CANCEL_REASON_SUPPORT
	cancel_buf_len = invite_len + to_len + reason_len;
#else
	cancel_buf_len = invite_len + to_len;
#endif /* CANCEL_REASON_SUPPORT */
	cancel_buf = shm_malloc(sizeof(char)*cancel_buf_len);
	if (!cancel_buf)
	{
		LM_ERR("cannot allocate shared memory\n");
		goto error;
	}
	d = cancel_buf;

	/* method name + space */
	append_str(d, method, method_len);
	*d = ' ';
	d++;
	/* skip "INVITE " and copy the rest of the line including CRLF */
	s += 7;
	s1 = s;
	s = eat_line(s, invite_buf_end - s);
	append_str(d, s1, s - s1);

	cenv = sr_cfgenv_get();

	/* check every header field name,
	we must exclude and modify some of the headers */
	first_via = 1;
	while (s < invite_buf_end) {
		s1 = s;
		if ((*s == '\n') || (*s == '\r')) {
			/* end of SIP msg */
			hf_type = HDR_EOH_T;
		} else {
			/* parse HF name */
			s = lw_get_hf_name(s, invite_buf_end,
						&hf_type);
		}

		switch(hf_type) {
			case HDR_CSEQ_T:
				/* find the method name and replace it */
				while ((s < invite_buf_end)
					&& ((*s == ':') || (*s == ' ') || (*s == '\t') ||
						((*s >= '0') && (*s <= '9')))
					) s++;
				append_str(d, s1, s - s1);
				append_str(d, method, method_len);
				append_str(d, CRLF, CRLF_LEN);
				s = lw_next_line(s, invite_buf_end);
				break;

			case HDR_VIA_T:
				s = lw_next_line(s, invite_buf_end);
				if (first_via) {
					/* copy hf */
					append_str(d, s1, s - s1);
					first_via = 0;
				} /* else skip this line, we need olny the first via */
				break;

			case HDR_TO_T:
				if (to_len == 0) {
					/* there is no To tag required, just copy paste
					 * the header */
					s = lw_next_line(s, invite_buf_end);
					append_str(d, s1, s - s1);
				} else {
					/* use the given To HF instead of the original one */
					append_str(d, to->s, to->len);
					/* move the pointer to the next line */
					s = lw_next_line(s, invite_buf_end);
				}
				break;

			case HDR_FROM_T:
			case HDR_CALLID_T:
			case HDR_ROUTE_T:
			case HDR_MAXFORWARDS_T:
				/* copy hf */
				s = lw_next_line(s, invite_buf_end);
				append_str(d, s1, s - s1);
				break;

			case HDR_REQUIRE_T:
			case HDR_PROXYREQUIRE_T:
				/* skip this line */
				s = lw_next_line(s, invite_buf_end);
				break;

			case HDR_CONTENTLENGTH_T:
				/* copy hf name with 0 value */
				append_str(d, s1, s - s1);
				append_str(d, ": 0" CRLF, 3 + CRLF_LEN);
				/* move the pointer to the next line */
				s = lw_next_line(s, invite_buf_end);
				break;

			case HDR_EOH_T:
				/* end of SIP message found */
#ifdef CANCEL_REASON_SUPPORT
				/* add reason if needed */
				if (reason_len) {
					/* if reason_len !=0, no need for any reason enabled
					 * checks */
					if (likely(reason->cause > 0)) {
						append_str(d, REASON_PREFIX, REASON_PREFIX_LEN);
						code_len=ushort2sbuf(reason->cause, d,
										cancel_buf_len-(int)(d-cancel_buf));
						if (unlikely(code_len==0))
							LM_BUG("not enough space to write reason code");
						d+=code_len;
						if (reason->u.text.s){
							append_str(d, REASON_TEXT, REASON_TEXT_LEN);
							*d='"'; d++;
							append_str(d, reason->u.text.s,
											reason->u.text.len);
							*d='"'; d++;
						}
						append_str(d, CRLF, CRLF_LEN);
					} else if (likely(reason->cause ==
										CANCEL_REAS_PACKED_HDRS)) {
							append_str(d, reason->u.packed_hdrs.s,
											reason->u.packed_hdrs.len);
					} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
						for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) {
							/* hdr->len includes CRLF */
							append_str(d, hdr->name.s, hdr->len);
							if (likely(hdr==reas_last))
								break;
						}
					}
				}
#endif /* CANCEL_REASON_SUPPORT */
				/* final (end-of-headers) CRLF */
				append_str(d, CRLF, CRLF_LEN);
				*len = d - cancel_buf;
				/* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */
				return cancel_buf;

			default:
				s = lw_next_line(s, invite_buf_end);
				hadded = 0;

				/* uac auth headers */
				if(Trans->uas.request &&
						(Trans->uas.request->msg_flags & FL_UAC_AUTH)) {
					if(s1 + cenv->uac_cseq_auth.len + 2 < invite_buf_end) {
						if(s1[cenv->uac_cseq_auth.len]==':'
								&& strncmp(s1, cenv->uac_cseq_auth.s,
									cenv->uac_cseq_auth.len)==0) {
							hadded = 1;
							append_str(d, s1, s - s1);
						} else if(s1[cenv->uac_cseq_refresh.len]==':'
								&& strncmp(s1, cenv->uac_cseq_refresh.s,
									cenv->uac_cseq_refresh.len)==0) {
							hadded = 1;
							append_str(d, s1, s - s1);
						}
					}
				}

				if(likely(hadded==0)) {
					if (cfg_get(tm, tm_cfg, ac_extra_hdrs).len
							&& (s1 + cfg_get(tm, tm_cfg, ac_extra_hdrs).len < invite_buf_end)
							&& (strncasecmp(s1,
									cfg_get(tm, tm_cfg, ac_extra_hdrs).s,
									cfg_get(tm, tm_cfg, ac_extra_hdrs).len) == 0)) {
						append_str(d, s1, s - s1);
					}
				}
				break;
		}
	}

	/* HDR_EOH_T was not found in the buffer, the message is corrupt */
	LM_ERR("HDR_EOH_T was not found\n");

	shm_free(cancel_buf);
error:
	LM_ERR("cannot build %.*s request\n", method_len, method);
	return NULL;

}
Пример #26
0
static int avpops_init(void)
{
	int i;

	LM_INFO("initializing...\n");

	if (db_table.s)
		db_table.len = strlen(db_table.s);
	uuid_col.len = strlen(uuid_col.s);
	attribute_col.len = strlen(attribute_col.s);
	value_col.len = strlen(value_col.s);
	type_col.len = strlen(type_col.s);
	username_col.len = strlen(username_col.s);
	domain_col.len = strlen(domain_col.s);

	/* search if any avp_db_* function is used */
	for (i=0; cmds[i].name != NULL; i++) {
		if (strncasecmp(cmds[i].name, AVPDB, sizeof(AVPDB)-1) == 0 &&
				(is_script_func_used(cmds[i].name, cmds[i].param_no))) {
			need_db=1;
		}
	}

	for (i=0; acmds[i].name != NULL; i++) {
		if (strncasecmp(acmds[i].name, AVPDB, sizeof(AVPDB)-1) == 0 &&
				(is_script_async_func_used(acmds[i].name, acmds[i].param_no))) {
			need_db=1;
		}
	}

	if (need_db) {
		default_db_url = get_default_db_url();
		if (default_db_url==NULL) {
			if (db_default_url==NULL) {
				LM_ERR("no DB URL provision into the module!\n");
				return -1;
			}
			/* if nothing explicitly set as DB URL, add automatically
			 * the default DB URL */
			if (add_db_url(STR_PARAM, db_default_url)!=0) {
				LM_ERR("failed to use the default DB URL!\n");
				return -1;
			}
			default_db_url = get_default_db_url();
			if (default_db_url==NULL) {
				LM_BUG("Really ?!\n");
				return -1;
			}
		}

		/* bind to the DB module */
		if (avpops_db_bind()<0)
			goto error;

		init_store_avps(db_columns);
	}

	printbuf = (char*)pkg_malloc((buf_size+1)*sizeof(char));
	if(printbuf==NULL) {
		LM_ERR("no pkg memory left\n");
		return -1;
	}

	return 0;
error:
	return -1;
}
Пример #27
0
int solve_module_dependencies(struct sr_module *modules)
{
	struct sr_module_dep *md, *it;
	struct sr_module *this, *mod;
	enum module_type mod_type;
	enum dep_type dep_type;
	int dep_solved;

	/*
	 * now that we've loaded all shared libraries,
	 * we can attempt to solve each dependency
	 */
	for (it = unsolved_deps.next; it; ) {
		md = it;
		it = it->next;

		LM_DBG("solving dependency %s -> %s %.*s\n", md->mod->exports->name,
				 mod_type_to_string(md->mod_type), md->dep.len, md->dep.s);

		dep_type = md->type;

		/*
		 * for generic dependencies (e.g. dialog depends on MOD_TYPE_SQLDB),
		 * first load all modules of given type
		 */
		if (!md->dep.s) {
			this = md->mod;
			mod_type = md->mod_type;

			for (dep_solved = 0, mod = modules; mod; mod = mod->next) {
				if (mod != this && mod->exports->type == mod_type) {
					if (!md) {
						md = pkg_malloc(sizeof *md);
						if (!md) {
							LM_ERR("no more pkg\n");
							return -1;
						}
						memset(md, 0, sizeof *md);
					}

					/*
					 * re-purpose this structure by linking it into a module's
					 * list of dependencies (will be used at init time)
					 *
					 * md->mod used to point to (highlighted with []):
					 *		[sr_module A] ---> "mod_name"
					 *
					 * now, the dependency is solved. md->mod will point to:
					 *		sr_module A  ---> [sr_module B]
					 */
					md->mod = mod;
					md->next = this->sr_deps;
					this->sr_deps = md;

					md = NULL;
					dep_solved++;
				}
			}
		} else {
			for (dep_solved = 0, mod = modules; mod; mod = mod->next) {
				if (strcmp(mod->exports->name, md->dep.s) == 0) {

					/* quick sanity check */
					if (mod->exports->type != md->mod_type)
						LM_BUG("[%.*s %d] -> [%s %d]\n", md->dep.len, md->dep.s,
								md->mod_type, mod->exports->name,
								mod->exports->type);

					/* same re-purposing technique as above */
					md->next = md->mod->sr_deps;
					md->mod->sr_deps = md;
					md->mod = mod;

					dep_solved++;
					break;
				}
			}
		}

		/* treat unmet dependencies using the intended behaviour */
		if (!dep_solved) {
			switch (dep_type) {
			case DEP_SILENT:
				LM_DBG("module %s depends on %s%s%s%.*s%s%s, but %s loaded!\n",
						md->mod->exports->name,
						md->dep.len == 0 ?
							((md->mod_type == MOD_TYPE_SQLDB ||
							  md->mod_type == MOD_TYPE_AAA) ? "an " :
							md->mod_type == MOD_TYPE_CACHEDB ? "a " : "") : "",
						mod_type_to_string(md->mod_type),
						md->dep.len == 0 ? "" : " ",
						md->dep.len, md->dep.s,
						md->script_param ? " due to modparam " : "",
						md->script_param ? md->script_param : "",
						md->dep.len == 0 ? "none was" : "it was not");
				break;
			case DEP_WARN:
			case DEP_ABORT:
				LM_WARN("module %s depends on %s%s%s%.*s%s%s, but %s loaded!\n",
						md->mod->exports->name,
						md->dep.len == 0 ?
							((md->mod_type == MOD_TYPE_SQLDB ||
							  md->mod_type == MOD_TYPE_AAA) ? "an " :
							md->mod_type == MOD_TYPE_CACHEDB ? "a " : "") : "",
						mod_type_to_string(md->mod_type),
						md->dep.len == 0 ? "" : " ",
						md->dep.len, md->dep.s,
						md->script_param ? " due to modparam " : "",
						md->script_param ? md->script_param : "",
						md->dep.len == 0 ? "none was" : "it was not");
				break;
			}

			pkg_free(md);
			if (dep_type == DEP_ABORT)
				return -1;
		}
	}

	return 0;
}
Пример #28
0
enum async_ret_code resume_async_http_req(int fd, struct sip_msg *msg, void *_param)
{
	CURLcode rc;
	CURLMcode mrc;
	rest_async_param *param = (rest_async_param *)_param;
	int running, max_fd;
	long http_rc;
	fd_set rset, wset, eset;
	pv_value_t val;

	mrc = curl_multi_perform(multi_handle, &running);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_perform: %s\n", curl_multi_strerror(mrc));
		return -1;
	}
	LM_DBG("running handles: %d\n", running);

	if (running == running_handles) {
		async_status = ASYNC_CONTINUE;
		return 1;
	}

	if (running > running_handles) {
		LM_BUG("incremented handles!!");
		/* default async status is DONE */
		return -1;
	}

	running_handles = running;

	FD_ZERO(&rset);
	mrc = curl_multi_fdset(multi_handle, &rset, &wset, &eset, &max_fd);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_fdset: %s\n", curl_multi_strerror(mrc));
		/* default async status is DONE */
		return -1;
	}

	if (max_fd == -1) {
		if (running_handles != 0) {
			LM_BUG("running_handles == %d", running_handles);
			abort();
			/* default async status is DONE */
			return -1;
		}

		if (FD_ISSET(fd, &rset)) {
			LM_BUG("fd %d is still in rset!", fd);
			abort();
			/* default async status is DONE */
			return -1;
		}

	} else if (FD_ISSET(fd, &rset)) {
		LM_DBG("fd %d still transfering...\n", fd);
		async_status = ASYNC_CONTINUE;
		return 1;
	}

	if (del_transfer(fd) != 0) {
		LM_BUG("failed to delete fd %d", fd);
		abort();
		/* default async status is DONE */
		return -1;
	}

	mrc = curl_multi_remove_handle(multi_handle, param->handle);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc));
		/* default async status is DONE */
		return -1;
	}

	val.flags = PV_VAL_STR;
	val.rs = param->body;
	if (pv_set_value(msg, param->body_pv, 0, &val) != 0)
		LM_ERR("failed to set output body pv\n");

	if (param->ctype_pv) {
		val.rs = param->ctype;
		if (pv_set_value(msg, param->ctype_pv, 0, &val) != 0)
			LM_ERR("failed to set output ctype pv\n");
	}

	if (param->code_pv) {
		rc = curl_easy_getinfo(param->handle, CURLINFO_RESPONSE_CODE, &http_rc);
		if (rc != CURLE_OK) {
			LM_ERR("curl_easy_getinfo: %s\n", curl_easy_strerror(rc));
			http_rc = 0;
		}

		LM_DBG("Last response code: %ld\n", http_rc);

		val.flags = PV_VAL_INT|PV_TYPE_INT;
		val.ri = (int)http_rc;
		if (pv_set_value(msg, param->code_pv, 0, &val) != 0)
			LM_ERR("failed to set output code pv\n");
	}

	pkg_free(param->body.s);
	if (param->ctype_pv && param->ctype.s)
		pkg_free(param->ctype.s);
	curl_easy_cleanup(param->handle);
	pkg_free(param);

	/* default async status is DONE */
	return 1;
}
Пример #29
0
enum async_ret_code resume_async_http_req(int fd, struct sip_msg *msg, void *_param)
{
	CURLcode rc;
	CURLMcode mrc;
	rest_async_param *param = (rest_async_param *)_param;
	int running = 0, max_fd;
	long http_rc;
	fd_set rset, wset, eset;
	pv_value_t val;
	int ret = 1, retr;
	CURLM *multi_handle;

	multi_handle = param->multi_list->multi_handle;

	retr = 0;
	do {
		mrc = curl_multi_perform(multi_handle, &running);
		if (mrc != CURLM_CALL_MULTI_PERFORM)
			break;
		LM_DBG("retry last perform...\n");
		usleep(_async_resume_retr_itv);
		retr += _async_resume_retr_itv;
	} while (retr < _async_resume_retr_timeout);

	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_perform: %s\n", curl_multi_strerror(mrc));
		return -1;
	}

	LM_DBG("running handles: %d\n", running);
	if (running == 1) {
		LM_DBG("transfer in progress...\n");
		async_status = ASYNC_CONTINUE;
		return 1;
	}

	if (running != 0) {
		LM_BUG("non-zero running handles!! (%d)", running);
		abort();
	}

	FD_ZERO(&rset);
	mrc = curl_multi_fdset(multi_handle, &rset, &wset, &eset, &max_fd);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_fdset: %s\n", curl_multi_strerror(mrc));
		ret = -1;
		goto out;
	}

	if (max_fd == -1) {
		if (FD_ISSET(fd, &rset)) {
			LM_BUG("fd %d is still in rset!", fd);
			abort();
		}

	} else if (FD_ISSET(fd, &rset)) {
		LM_DBG("fd %d still transferring...\n", fd);
		async_status = ASYNC_CONTINUE;
		return 1;
	}

	curl_slist_free_all(param->header_list);

	if (del_transfer(fd) != 0) {
		LM_BUG("failed to delete fd %d", fd);
		abort();
	}

	mrc = curl_multi_remove_handle(multi_handle, param->handle);
	if (mrc != CURLM_OK) {
		LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc));
		/* default async status is ASYNC_DONE */
		return -1;
	}
	put_multi(param->multi_list);

	val.flags = PV_VAL_STR;
	val.rs = param->body;
	if (pv_set_value(msg, param->body_pv, 0, &val) != 0)
		LM_ERR("failed to set output body pv\n");

	if (param->ctype_pv) {
		val.rs = param->ctype;
		if (pv_set_value(msg, param->ctype_pv, 0, &val) != 0)
			LM_ERR("failed to set output ctype pv\n");
	}

	if (param->code_pv) {
		rc = curl_easy_getinfo(param->handle, CURLINFO_RESPONSE_CODE, &http_rc);
		if (rc != CURLE_OK) {
			LM_ERR("curl_easy_getinfo: %s\n", curl_easy_strerror(rc));
			http_rc = 0;
		}

		LM_DBG("Last response code: %ld\n", http_rc);

		val.flags = PV_VAL_INT|PV_TYPE_INT;
		val.ri = (int)http_rc;
		if (pv_set_value(msg, param->code_pv, 0, &val) != 0)
			LM_ERR("failed to set output code pv\n");
	}

out:
	pkg_free(param->body.s);
	if (param->ctype_pv && param->ctype.s)
		pkg_free(param->ctype.s);
	curl_easy_cleanup(param->handle);
	if ( param->tparam ) {
		pkg_free( param->tparam );
	}
	pkg_free(param);

	/* default async status is ASYNC_DONE */
	return ret;
}
Пример #30
0
int ws_process(struct tcp_connection *con)
{
	struct ws_req *req;
	struct ws_req *newreq;
	long size = 0;
	enum ws_close_code ret_code = WS_ERR_NONE;
	unsigned char bk;
	char *msg_buf;
	int msg_len;
	struct receive_info local_rcv;

	if (con->con_req) {
		req=(struct ws_req *)con->con_req;
		LM_DBG("Using the per connection buff \n");
	} else {
		LM_DBG("Using the global ( per process ) buff \n");
		init_ws_req(&ws_current_req, 0);
		req=&ws_current_req;
	}

again:
	if (req->tcp.error == TCP_REQ_OK) {
		if (req->tcp.parsed >= req->tcp.pos) {
			if (ws_raw_read(con, &req->tcp) < 0) {
				LM_ERR("failed to read %d:%s\n", errno, strerror(errno));
				goto error;
			}
		}
		ret_code = ws_parse(req);
		if (ret_code)
			goto error;

		/* eof check:
		 * is EOF if eof on fd and r.  not complete yet,
		 * if r. is complete we might have a second unparsed
		 * request after it, so postpone release_with_eof
		 */
		if ((con->state==S_CONN_EOF) && (req->tcp.complete==0)) {
			LM_DBG("EOF received\n");
			goto done;
		}
		/* sanity mask checks */
		if ((WS_TYPE(con) == WS_CLIENT && req->is_masked) ||
			(WS_TYPE(con) == WS_SERVER && !req->is_masked)) {
			LM_DBG("malformed WS msg - %s %s\n",
					req->is_masked ? "masked" : "not masked",
					WS_TYPE(con) == WS_CLIENT ? "client" : "server");
			ret_code = WS_ERR_BADDATA;
			goto error;
		}
	}

	if (req->tcp.complete) {

		/* update the timeout - we succesfully read the request */
		tcp_conn_set_lifetime(con, ws_send_timeout);
		con->timeout=con->lifetime;

		/* if we are here everything is nice and ok*/
		update_stat( pt[process_no].load, +1 );
		/* rcv.bind_address should always be !=0 */
		bind_address=con->rcv.bind_address;

		con->rcv.proto_reserved1=con->id; /* copy the id */
		size=req->tcp.pos-req->tcp.parsed;

		switch (req->op) {
		case WS_OP_CLOSE:
			if (req->tcp.content_len) {
				/* for now we are only interested in the code, not the reason */
				ret_code = WS_CLOSE_CODE(req);
				switch(ret_code) {
				case WS_ERR_NORMAL: LM_DBG("Normal WebSocket close\n"); break;
				case WS_ERR_CLIENT: LM_DBG("Client error close\n"); break;
				case WS_ERR_PROTO:  LM_DBG("WebSocket protocol error\n"); break;
				case WS_ERR_BADDATA: LM_DBG("Data type not consistent\n"); break;
				case WS_ERR_POLICY: LM_DBG("Bad policy close\n"); break;
				case WS_ERR_TOO_BIG: LM_DBG("Packet too big close\n"); break;
				case WS_ERR_BADEXT: LM_DBG("Bad extension close\n"); break;
				case WS_ERR_UNEXPECT: LM_DBG("Unexpected condition close\n"); break;
				default:
					LM_DBG("Unknown WebSocket close: %d\n", ret_code);
				}
			} else {
				ret_code = WS_ERR_NORMAL;
			}
			/* respond to close */
			WS_CODE(con) = ret_code;
			ws_send_close(con);
			WS_CODE(con) = WS_ERR_NOSEND;

			/* release the connextion */
			con->state = S_CONN_EOF;
			goto done;

		case WS_OP_PING:
			if (ws_send_pong(con, req) < 0)
					LM_ERR("cannot send PONG msg\n");
			break;

		case WS_OP_PONG:
			LM_DBG("Received WebSocket PONG\n");
			break;

		case WS_OP_TEXT:
		case WS_OP_BIN:

			bk = *req->tcp.parsed;
			*req->tcp.parsed = 0;
			msg_buf = req->tcp.body;
			msg_len = req->tcp.parsed-req->tcp.body;
			local_rcv = con->rcv;

			if (!size) {
				/* did not read any more things -  we can release
				 * the connection */
				LM_DBG("We're releasing the connection in state %d \n",
					con->state);
				if (req != &ws_current_req) {
					/* we have the buffer in the connection tied buff -
					 *	detach it , release the conn and free it afterwards */
					con->con_req = NULL;
				}
				/* TODO - we could indicate to the TCP net layer to release
				 * the connection -> other worker may read the next available
				 * message on the pipe */
			} else {
				LM_DBG("We still have things on the pipe - "
					"keeping connection \n");
			}

			if (receive_msg(msg_buf, msg_len, &local_rcv) <0)
					LM_ERR("receive_msg failed \n");

			*req->tcp.parsed = bk;

			break;

			default:
				LM_BUG("Can't handle %d\n", req->op);
				goto error;
			}

		update_stat( pt[process_no].load, -1 );

		if (size) memmove(req->tcp.buf, req->tcp.parsed, size);
#ifdef EXTRA_DEBUG
		LM_DBG("preparing for new request, kept %ld bytes\n", size);
#endif
		init_ws_req(req, size);
		con->msg_attempts = 0;

		/* if we still have some unparsed bytes, try to  parse them too*/
		if (size)
			goto again;
		/* cleanup the existing request */
		if (req != &ws_current_req)
			pkg_free(req);

	} else {
		/* request not complete - check the if the thresholds are exceeded */

		con->msg_attempts++;
		if (con->msg_attempts == ws_max_msg_chunks) {
			LM_ERR("Made %u read attempts but message is not complete yet - "
				   "closing connection \n",con->msg_attempts);
			goto error;
		}

		if (req == &ws_current_req) {
			/* let's duplicate this - most likely another conn will come in */

			LM_DBG("We didn't manage to read a full request\n");
			newreq = pkg_malloc(sizeof(struct ws_req));
			if (newreq == NULL) {
				LM_ERR("No more mem for dynamic con request buffer\n");
				goto error;
			}

			if (req->tcp.pos != req->tcp.buf) {
				/* we have read some bytes */
				memcpy(newreq->tcp.buf,req->tcp.buf,req->tcp.pos-req->tcp.buf);
				newreq->tcp.pos = newreq->tcp.buf + (req->tcp.pos-req->tcp.buf);
			} else {
				newreq->tcp.pos = newreq->tcp.buf;
			}

			if (req->tcp.start != req->tcp.buf)
				newreq->tcp.start = newreq->tcp.buf +(req->tcp.start-req->tcp.buf);
			else
				newreq->tcp.start = newreq->tcp.buf;

			if (req->tcp.parsed != req->tcp.buf)
				newreq->tcp.parsed =newreq->tcp.buf+(req->tcp.parsed-req->tcp.buf);
			else
				newreq->tcp.parsed = newreq->tcp.buf;

			if (req->tcp.body != 0) {
				newreq->tcp.body = newreq->tcp.buf + (req->tcp.body-req->tcp.buf);
			} else
				newreq->tcp.body = 0;

			newreq->tcp.complete=req->tcp.complete;
			newreq->tcp.has_content_len=req->tcp.has_content_len;
			newreq->tcp.content_len=req->tcp.content_len;
			newreq->tcp.bytes_to_go=req->tcp.bytes_to_go;
			newreq->tcp.error = req->tcp.error;
			newreq->tcp.state = req->tcp.state;

			newreq->op = req->op;
			newreq->mask = req->mask;
			newreq->is_masked = req->is_masked;

			con->con_req = (struct tcp_req *)newreq;
		}
	}

	LM_DBG("ws_read end\n");
done:
	/* connection will be released */
	return size;
error:
	WS_CODE(con) = ret_code;
	if (WS_CODE(con) != WS_ERR_NONE) {
		ws_send_close(con);
		WS_CODE(con) = WS_ERR_NOSEND;
	}
	return -1;
}