err.c 29.4 KB
Newer Older
	}
#endif

ERR_STATE *ERR_get_state(void)
	{
	static ERR_STATE fallback;
	ERR_STATE *ret,tmp,*tmpp=NULL;
	int i;
	CRYPTO_THREADID tid;

	err_fns_check();
	CRYPTO_THREADID_current(&tid);
	CRYPTO_THREADID_cpy(&tmp.tid, &tid);
	ret=ERRFN(thread_get_item)(&tmp);

	/* ret == the error state, if NULL, make a new one */
	if (ret == NULL)
		{
		ret=(ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE));
		if (ret == NULL) return(&fallback);
		CRYPTO_THREADID_cpy(&ret->tid, &tid);
		ret->top=0;
		ret->bottom=0;
		for (i=0; i<ERR_NUM_ERRORS; i++)
			{
			ret->err_data[i]=NULL;
			ret->err_data_flags[i]=0;
			}
		tmpp = ERRFN(thread_set_item)(ret);
		/* To check if insertion failed, do a get. */
		if (ERRFN(thread_get_item)(ret) != ret)
			{
			ERR_STATE_free(ret); /* could not insert it */
			return(&fallback);
			}
		/* If a race occured in this function and we came second, tmpp
		 * is the first one that we just replaced. */
		if (tmpp)
			ERR_STATE_free(tmpp);
		}
	return ret;
	}

int ERR_get_next_error_library(void)
	{
	err_fns_check();
	return ERRFN(get_next_lib)();
	}

void ERR_set_error_data(char *data, int flags)
	{
	ERR_STATE *es;
	int i;

	es=ERR_get_state();

	i=es->top;
	if (i == 0)
		i=ERR_NUM_ERRORS-1;

	err_clear_data(es,i);
	es->err_data[i]=data;
	es->err_data_flags[i]=flags;
	}

void ERR_add_error_data(int num, ...)
	{
	va_list args;
	va_start(args, num);
	ERR_add_error_vdata(num, args);
	va_end(args);
	}

void ERR_add_error_vdata(int num, va_list args)
	{
	int i,n,s;
	char *str,*p,*a;

	s=80;
	str=OPENSSL_malloc(s+1);
	if (str == NULL) return;
	str[0]='\0';

	n=0;
	for (i=0; i<num; i++)
		{
		a=va_arg(args, char*);
		/* ignore NULLs, thanks to Bob Beck <beck@obtuse.com> */
		if (a != NULL)
			{
			n+=strlen(a);
			if (n > s)
				{
				s=n+20;
				p=OPENSSL_realloc(str,s+1);
				if (p == NULL)
					{
					OPENSSL_free(str);
					return;
					}
				else
					str=p;
				}
			BUF_strlcat(str,a,(size_t)s+1);
			}
		}
	ERR_set_error_data(str,ERR_TXT_MALLOCED|ERR_TXT_STRING);
	}

int ERR_set_mark(void)
	{
	ERR_STATE *es;

	es=ERR_get_state();

	if (es->bottom == es->top) return 0;
	es->err_flags[es->top]|=ERR_FLAG_MARK;
	return 1;
	}

int ERR_pop_to_mark(void)
	{
	ERR_STATE *es;

	es=ERR_get_state();

	while(es->bottom != es->top
		&& (es->err_flags[es->top] & ERR_FLAG_MARK) == 0)
		{
		err_clear(es,es->top);
		es->top-=1;
		if (es->top == -1) es->top=ERR_NUM_ERRORS-1;
		}
		
	if (es->bottom == es->top) return 0;
	es->err_flags[es->top]&=~ERR_FLAG_MARK;
	return 1;
	}