Exemplo n.º 1
0
/** Create thread instances where needed
 *
 * @param[in] ctx	to allocate thread instance data in.
 * @param[in] inst	to allocate thread-instance data for.
 * @return
 *	- 0 on success.  The node/thread specific data will be inserted
 *	  into xlat_thread_inst_tree.
 *	- -1 on failure.
 */
static xlat_thread_inst_t *xlat_thread_inst_alloc(TALLOC_CTX *ctx, xlat_inst_t *inst)
{
	xlat_thread_inst_t	*thread_inst = NULL;

	(void)talloc_get_type_abort(inst, xlat_inst_t);

#ifdef HAVE_TALLOC_POOLED_OBJECT
	if (inst->node->xlat->thread_inst_size) {
		MEM(thread_inst = talloc_pooled_object(ctx, xlat_thread_inst_t,
						       1, inst->node->xlat->thread_inst_size));
		memset(thread_inst, 0, sizeof(*thread_inst));
	} else
#endif
		MEM(thread_inst = talloc_zero(ctx, xlat_thread_inst_t));
#ifdef HAVE_TALLOC_POOLED_OBJECT
	}
/** Locate a cache entry in redis
 *
 * @copydetails cache_entry_find_t
 */
static cache_status_t cache_entry_find(rlm_cache_entry_t **out,
				       UNUSED rlm_cache_config_t const *config, void *driver_inst,
				       REQUEST *request, UNUSED void *handle, uint8_t const *key, size_t key_len)
{
	rlm_cache_redis_t		*driver = driver_inst;
	size_t				i;

	fr_redis_cluster_state_t	state;
	fr_redis_conn_t			*conn;
	fr_redis_rcode_t		status;
	redisReply			*reply = NULL;
	int				s_ret;

	vp_map_t			*head = NULL, **last = &head;
#ifdef HAVE_TALLOC_POOLED_OBJECT
	size_t				pool_size = 0;
#endif
	rlm_cache_entry_t		*c;

	for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, key, key_len, false);
	     s_ret == REDIS_RCODE_TRY_AGAIN;	/* Continue */
	     s_ret = fr_redis_cluster_state_next(&state, &conn, driver->cluster, request, status, &reply)) {
		/*
		 *	Grab all the data for this hash, should return an array
		 *	of alternating keys/values which we then convert into maps.
		 */
		if (RDEBUG_ENABLED3) {
			char *p;

			p = fr_asprint(NULL, (char const *)key, key_len, '"');
			RDEBUG3("LRANGE %s 0 -1", key);
			talloc_free(p);
		}
		reply = redisCommand(conn->handle, "LRANGE %b 0 -1", key, key_len);
		status = fr_redis_command_status(conn, reply);
	}
	if (s_ret != REDIS_RCODE_SUCCESS) {
		RERROR("Failed retrieving entry");
		fr_redis_reply_free(reply);
		return CACHE_ERROR;
	}
	rad_assert(reply);	/* clang scan */

	if (reply->type != REDIS_REPLY_ARRAY) {
		REDEBUG("Bad result type, expected array, got %s",
			fr_int2str(redis_reply_types, reply->type, "<UNKNOWN>"));
		fr_redis_reply_free(reply);
		return CACHE_ERROR;
	}

	RDEBUG3("Entry contains %zu elements", reply->elements);

	if (reply->elements == 0) {
		fr_redis_reply_free(reply);
		return CACHE_MISS;
	}

	if (reply->elements % 3) {
		REDEBUG("Invalid number of reply elements (%zu).  "
			"Reply must contain triplets of keys operators and values",
			reply->elements);
		fr_redis_reply_free(reply);
		return CACHE_ERROR;
	}

#ifdef HAVE_TALLOC_POOLED_OBJECT
	/*
	 *	We can get a pretty good idea of the required size of the pool
	 */
	for (i = 0; i < reply->elements; i += 3) {
		pool_size += sizeof(vp_map_t) + (sizeof(vp_tmpl_t) * 2);
		if (reply->element[i]->type == REDIS_REPLY_STRING) pool_size += reply->element[i]->len + 1;
	}

	/*
	 *	reply->elements gives us the number of chunks, as the maps are triplets, and there
	 *	are three chunks per map
	 */

	c = talloc_pooled_object(NULL,  rlm_cache_entry_t, reply->elements, pool_size);
	memset(&pool, 0, sizeof(rlm_cache_entry_t));
#else
	c = talloc_zero(NULL, rlm_cache_entry_t);
#endif
	/*
	 *	Convert the key/value pairs back into maps
	 */
	for (i = 0; i < reply->elements; i += 3) {
		if (fr_redis_reply_to_map(c, last, request,
					  reply->element[i], reply->element[i + 1], reply->element[i + 2]) < 0) {
			talloc_free(c);
			fr_redis_reply_free(reply);
			return CACHE_ERROR;
		}
		last = &(*last)->next;
	}
	fr_redis_reply_free(reply);

	/*
	 *	Pull out the cache created date
	 */
	if ((head->lhs->tmpl_da->vendor == 0) && (head->lhs->tmpl_da->attr == PW_CACHE_CREATED)) {
		vp_map_t *map;

		c->created = head->rhs->tmpl_data_value.date;

		map = head;
		head = head->next;
		talloc_free(map);
	}

	/*
	 *	Pull out the cache expires date
	 */
	if ((head->lhs->tmpl_da->vendor == 0) && (head->lhs->tmpl_da->attr == PW_CACHE_EXPIRES)) {
		vp_map_t *map;

		c->expires = head->rhs->tmpl_data_value.date;

		map = head;
		head = head->next;
		talloc_free(map);
	}

	c->key = talloc_memdup(c, key, key_len);
	c->key_len = key_len;
	c->maps = head;
	*out = c;

	return CACHE_OK;
}