added reply handler
This commit is contained in:
		
							
								
								
									
										672
									
								
								hcl/lib/hcl-c.c
									
									
									
									
									
								
							
							
						
						
									
										672
									
								
								hcl/lib/hcl-c.c
									
									
									
									
									
								
							| @ -31,9 +31,11 @@ | |||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
|  |  | ||||||
| #define HCL_SERVER_TOKEN_NAME_ALIGN 64 | #define HCL_CLIENT_TOKEN_NAME_ALIGN 64 | ||||||
| #define HCL_SERVER_WID_MAP_ALIGN 512 | #define HCL_CLIENT_WID_MAP_ALIGN 512 | ||||||
| #define HCL_SERVER_PROTO_REPLY_BUF_SIZE 1300 | #define HCL_CLIENT_PROTO_REPLY_BUF_SIZE 1300 | ||||||
|  |  | ||||||
|  | #define HCL_CLIENT_REPLY_MAX_HDRKEY_LEN 128 | ||||||
|  |  | ||||||
| #if defined(_WIN32) | #if defined(_WIN32) | ||||||
| #	include <windows.h> | #	include <windows.h> | ||||||
| @ -78,12 +80,18 @@ | |||||||
| #	include <poll.h> | #	include <poll.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| enum hcl_client_reply_type_t | struct dummy_hcl_xtn_t | ||||||
| { | { | ||||||
| 	HCL_CLIENT_REPLY_TYPE_OK = 0, | 	hcl_client_t* client; | ||||||
| 	HCL_CLIENT_REPLY_TYPE_ERROR = 1 |  | ||||||
| }; | }; | ||||||
| typedef enum hcl_client_reply_type_t hcl_client_reply_type_t; | typedef struct dummy_hcl_xtn_t dummy_hcl_xtn_t; | ||||||
|  |  | ||||||
|  | enum hcl_client_reply_attr_type_t | ||||||
|  | { | ||||||
|  | 	HCL_CLIENT_REPLY_ATTR_TYPE_UNKNOWN, | ||||||
|  | 	HCL_CLIENT_REPLY_ATTR_TYPE_DATA | ||||||
|  | }; | ||||||
|  | typedef enum hcl_client_reply_attr_type_t hcl_client_reply_attr_type_t; | ||||||
|  |  | ||||||
| enum hcl_client_state_t | enum hcl_client_state_t | ||||||
| { | { | ||||||
| @ -93,11 +101,14 @@ enum hcl_client_state_t | |||||||
| 	HCL_CLIENT_STATE_IN_REPLY_VALUE_UNQUOTED, | 	HCL_CLIENT_STATE_IN_REPLY_VALUE_UNQUOTED, | ||||||
| 	HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED, | 	HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED, | ||||||
| 	HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED_TRAILER, | 	HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED_TRAILER, | ||||||
| 	HCL_CLIENT_STATE_IN_HEADER_NAME, | 	HCL_CLIENT_STATE_IN_ATTR_KEY, | ||||||
| 	HCL_CLIENT_STATE_IN_HEADER_VALUE, | 	HCL_CLIENT_STATE_IN_ATTR_VALUE_START, | ||||||
| 	HCL_CLIENT_STATE_IN_DATA, | 	HCL_CLIENT_STATE_IN_ATTR_VALUE_UNQUOTED, | ||||||
| 	HCL_CLIENT_STATE_IN_BINARY_DATA, | 	HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED, | ||||||
| 	HCL_CLIENT_STATE_IN_CHUNK, | 	HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED_TRAILER, | ||||||
|  |  | ||||||
|  | 	HCL_CLIENT_STATE_IN_LENGTH_BOUNDED_DATA, | ||||||
|  | 	HCL_CLIENT_STATE_IN_CHUNKED_DATA | ||||||
| }; | }; | ||||||
| typedef enum hcl_client_state_t hcl_client_state_t; | typedef enum hcl_client_state_t hcl_client_state_t; | ||||||
|  |  | ||||||
| @ -105,7 +116,8 @@ struct hcl_client_t | |||||||
| { | { | ||||||
| 	hcl_mmgr_t* mmgr; | 	hcl_mmgr_t* mmgr; | ||||||
| 	hcl_cmgr_t* cmgr; | 	hcl_cmgr_t* cmgr; | ||||||
| 	/*hcl_t* dummy_hcl;*/ | 	hcl_client_prim_t prim; | ||||||
|  | 	hcl_t* dummy_hcl; | ||||||
|  |  | ||||||
| 	hcl_errnum_t errnum; | 	hcl_errnum_t errnum; | ||||||
| 	struct | 	struct | ||||||
| @ -119,12 +131,8 @@ struct hcl_client_t | |||||||
| 	{ | 	{ | ||||||
| 		unsigned int trait; | 		unsigned int trait; | ||||||
| 		unsigned int logmask; | 		unsigned int logmask; | ||||||
| 		hcl_oow_t worker_max_count; |  | ||||||
| 		hcl_oow_t worker_stack_size; |  | ||||||
| 		hcl_ntime_t worker_idle_timeout; |  | ||||||
| 	} cfg; | 	} cfg; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	struct | 	struct | ||||||
| 	{ | 	{ | ||||||
| 		hcl_bch_t* ptr; | 		hcl_bch_t* ptr; | ||||||
| @ -135,11 +143,6 @@ struct hcl_client_t | |||||||
| 	hcl_client_state_t state; | 	hcl_client_state_t state; | ||||||
| 	struct | 	struct | ||||||
| 	{ | 	{ | ||||||
| 		/* |  | ||||||
| 		hcl_ooch_t* ptr; |  | ||||||
| 		hcl_oow_t len; |  | ||||||
| 		hcl_oow_t capa; |  | ||||||
| 		*/ |  | ||||||
| 		struct | 		struct | ||||||
| 		{ | 		{ | ||||||
| 			hcl_ooch_t* ptr; | 			hcl_ooch_t* ptr; | ||||||
| @ -148,24 +151,77 @@ struct hcl_client_t | |||||||
| 		} tok; | 		} tok; | ||||||
|  |  | ||||||
| 		hcl_client_reply_type_t type; | 		hcl_client_reply_type_t type; | ||||||
| 		 | 		hcl_client_reply_attr_type_t last_attr_type; | ||||||
|  | 		struct | ||||||
|  | 		{ | ||||||
|  | 			hcl_ooch_t buf[HCL_CLIENT_REPLY_MAX_HDRKEY_LEN]; | ||||||
|  | 			hcl_oow_t  len; | ||||||
|  | 		} last_attr_key; /* the last attr key shown */ | ||||||
|  |  | ||||||
| 		union | 		union | ||||||
| 		{ | 		{ | ||||||
| 			struct | 			struct | ||||||
| 			{ | 			{ | ||||||
| 				hcl_oow_t nsplen; /* length remembered when the white space was shown */ | 				hcl_oow_t nsplen; /* length remembered when the white space was shown */ | ||||||
| 			} reply_value_unquoted; | 			} reply_value_unquoted; | ||||||
| 			 |  | ||||||
| 			struct | 			struct | ||||||
| 			{ | 			{ | ||||||
| 				int escaped; | 				int escaped; | ||||||
| 			} reply_value_quoted; | 			} reply_value_quoted; | ||||||
|  |  | ||||||
|  | 			struct | ||||||
|  | 			{ | ||||||
|  | 				hcl_oow_t nsplen; /* length remembered when the white space was shown */ | ||||||
|  | 			} attr_value_unquoted; | ||||||
|  |  | ||||||
|  | 			struct | ||||||
|  | 			{ | ||||||
|  | 				int escaped; | ||||||
|  | 			} attr_value_quoted; | ||||||
|  |  | ||||||
|  | 			struct | ||||||
|  | 			{ | ||||||
|  | 				hcl_oow_t max; | ||||||
|  | 				hcl_oow_t tally; | ||||||
|  | 			} length_bounded_data; | ||||||
|  |  | ||||||
|  | 			struct | ||||||
|  | 			{ | ||||||
|  | 				int in_data_part; | ||||||
|  | 				int negated; | ||||||
|  | 				hcl_oow_t max; /* chunk length */ | ||||||
|  | 				hcl_oow_t tally;  | ||||||
|  | 				hcl_oow_t total; | ||||||
|  | 				hcl_oow_t clcount;  | ||||||
|  | 			} chunked_data; | ||||||
| 		} u; | 		} u; | ||||||
| 	} rep; | 	} rep; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* ========================================================================= */ | /* ========================================================================= */ | ||||||
|  |  | ||||||
|  | static void log_write_for_dummy (hcl_t* hcl, unsigned int mask, const hcl_ooch_t* msg, hcl_oow_t len) | ||||||
|  | { | ||||||
|  | 	dummy_hcl_xtn_t* xtn = (dummy_hcl_xtn_t*)hcl_getxtn(hcl); | ||||||
|  | 	hcl_client_t* client; | ||||||
|  |  | ||||||
|  | 	client = xtn->client; | ||||||
|  | 	client->prim.log_write (client, mask, msg, len); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void syserrstrb (hcl_t* hcl, int syserr, hcl_bch_t* buf, hcl_oow_t len) | ||||||
|  | { | ||||||
|  | #if defined(HAVE_STRERROR_R) | ||||||
|  | 	strerror_r (syserr, buf, len); | ||||||
|  | #else | ||||||
|  | 	/* this may not be thread safe */ | ||||||
|  | 	hcl_copybcstr (buf, len, strerror(syserr)); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ========================================================================= */ | ||||||
|  |  | ||||||
| static HCL_INLINE int is_spacechar (hcl_bch_t c) | static HCL_INLINE int is_spacechar (hcl_bch_t c) | ||||||
| { | { | ||||||
| @ -220,23 +276,36 @@ static int add_to_reply_token (hcl_client_t* client, hcl_ooch_t ch) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void print_tok (hcl_client_t* client) | static HCL_INLINE int is_token (hcl_client_t* client, const hcl_bch_t* str) | ||||||
|  | { | ||||||
|  | 	return hcl_compoocharsbcstr(client->rep.tok.ptr, client->rep.tok.len, str) == 0; | ||||||
|  | }  | ||||||
|  |  | ||||||
|  | static HCL_INLINE int is_token_integer (hcl_client_t* client, hcl_oow_t* value) | ||||||
| { | { | ||||||
| 	hcl_oow_t i; | 	hcl_oow_t i; | ||||||
| 	printf ("{"); | 	hcl_oow_t v = 0; | ||||||
| 	for (i = 0; i < client->rep.tok.len; i++) |  | ||||||
| 		printf ("%lc", client->rep.tok.ptr[i]); |  | ||||||
| 	printf ("}\n"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int handle_char (hcl_client_t* client, hcl_ooci_t c) | 	if (client->rep.tok.len <= 0) return 0; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < client->rep.tok.len; i++) | ||||||
|  | 	{ | ||||||
|  | 		if (!is_digitchar(client->rep.tok.ptr[i])) return 0; | ||||||
|  | 		v = v * 10 + (client->rep.tok.ptr[i] - '0'); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	*value = v; | ||||||
|  | 	return 1; | ||||||
|  | }  | ||||||
|  |  | ||||||
|  | static int handle_char (hcl_client_t* client, hcl_ooci_t c, hcl_oow_t nbytes) | ||||||
| { | { | ||||||
| 	switch (client->state) | 	switch (client->state) | ||||||
| 	{ | 	{ | ||||||
| 		case HCL_CLIENT_STATE_START: | 		case HCL_CLIENT_STATE_START: | ||||||
| 			if (c == HCL_OOCI_EOF) | 			if (c == HCL_OOCI_EOF) | ||||||
| 			{ | 			{ | ||||||
| 				printf ("unexpected end of reply\n"); | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "unexpected end before reply name"); | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 			else if (c == '.') | 			else if (c == '.') | ||||||
| @ -253,8 +322,7 @@ static int handle_char (hcl_client_t* client, hcl_ooci_t c) | |||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				/* TODO: set error code? or log error messages? */ | 				hcl_client_seterrbfmt (client, HCL_EINVAL, "reply line not starting with a period"); | ||||||
| 				printf ("reply line not starting with .\n"); |  | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @ -266,17 +334,17 @@ static int handle_char (hcl_client_t* client, hcl_ooci_t c) | |||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				if (hcl_compoocharsbcstr(client->rep.tok.ptr, client->rep.tok.len, ".OK") == 0) | 				if (is_token(client, ".OK")) | ||||||
| 				{ | 				{ | ||||||
| 					client->rep.type = HCL_CLIENT_REPLY_TYPE_OK; | 					client->rep.type = HCL_CLIENT_REPLY_TYPE_OK; | ||||||
| 				} | 				} | ||||||
| 				else if (hcl_compoocharsbcstr(client->rep.tok.ptr, client->rep.tok.len, ".ERROR") == 0) | 				else if (is_token(client, ".ERROR")) | ||||||
| 				{ | 				{ | ||||||
| 					client->rep.type = HCL_CLIENT_REPLY_TYPE_ERROR; | 					client->rep.type = HCL_CLIENT_REPLY_TYPE_ERROR; | ||||||
| 				} | 				} | ||||||
| 				else | 				else | ||||||
| 				{ | 				{ | ||||||
| 					printf ("unknown reply name - [%.*ls]", (int)client->rep.tok.len, client->rep.tok.ptr); | 					hcl_client_seterrbfmt (client, HCL_EINVAL, "unknown reply name %.*js", client->rep.tok.len, client->rep.tok.ptr); | ||||||
| 					goto oops; | 					goto oops; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| @ -288,9 +356,7 @@ static int handle_char (hcl_client_t* client, hcl_ooci_t c) | |||||||
| 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_START: | 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_START: | ||||||
| 			if (c == HCL_OOCI_EOF) | 			if (c == HCL_OOCI_EOF) | ||||||
| 			{ | 			{ | ||||||
| 				/* sudden end of EOF without NL */ | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of reply line without newline"); | ||||||
| 				printf ("suddend enf of input without NL\n"); |  | ||||||
| 				/* TOOD: call call back as it it's just a normal reply. and don't goto oops*/ |  | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 			else if (is_spacechar(c)) | 			else if (is_spacechar(c)) | ||||||
| @ -300,16 +366,19 @@ static int handle_char (hcl_client_t* client, hcl_ooci_t c) | |||||||
| 			} | 			} | ||||||
| 			else if (c == '\n') | 			else if (c == '\n') | ||||||
| 			{ | 			{ | ||||||
| 				/* no value is specified. switch to a long-format response */ | 				/* no value is specified. even no whitespaces. | ||||||
| 				client->state = HCL_CLIENT_STATE_IN_HEADER_NAME; | 				 * switch to a long-format response */ | ||||||
|  | 				client->prim.start_reply (client, client->rep.type, HCL_NULL, 0); | ||||||
|  |  | ||||||
|  | 				client->state = HCL_CLIENT_STATE_IN_ATTR_KEY; | ||||||
| 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | ||||||
| 				client->rep.u.reply_value_quoted.escaped = 0; |  | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			else if (c == '\"') | 			else if (c == '\"') | ||||||
| 			{ | 			{ | ||||||
| 				client->state = HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED; | 				client->state = HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED; | ||||||
| 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | ||||||
|  | 				client->rep.u.reply_value_quoted.escaped = 0; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			else  | 			else  | ||||||
| @ -324,20 +393,13 @@ static int handle_char (hcl_client_t* client, hcl_ooci_t c) | |||||||
| 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_UNQUOTED: | 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_UNQUOTED: | ||||||
| 			if (c == HCL_OOCI_EOF) | 			if (c == HCL_OOCI_EOF) | ||||||
| 			{ | 			{ | ||||||
| 				/* sudden end of EOF without NL */ | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of reply line without newline"); | ||||||
| 				printf ("suddend enf of input without NL\n"); |  | ||||||
| 				/* TOOD: call call back as it it's just a normal reply. and don't goto oops*/ |  | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 			else if (c == '\n') | 			else if (c == '\n') | ||||||
| 			{ | 			{ | ||||||
| 				client->rep.tok.len = client->rep.u.reply_value_unquoted.nsplen; | 				client->rep.tok.len = client->rep.u.reply_value_unquoted.nsplen; | ||||||
| printf ("reply value....===>"); | 				goto reply_value_end; | ||||||
| print_tok (client); |  | ||||||
| /* TODO: call callback */ |  | ||||||
| 				client->state = HCL_CLIENT_STATE_START; |  | ||||||
| 				clear_reply_token (client); |  | ||||||
| 				break; |  | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| @ -349,15 +411,16 @@ print_tok (client); | |||||||
| 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED: | 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED: | ||||||
| 			if (c == HCL_OOCI_EOF) | 			if (c == HCL_OOCI_EOF) | ||||||
| 			{ | 			{ | ||||||
| 				/* sudden end of EOF without NL */ | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of reply line without closing quote"); | ||||||
| 				printf ("suddend enf of input witjpit closing quote. -> total failure\n"); |  | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 			else  | 			else  | ||||||
| 			{ | 			{ | ||||||
| 				if (client->rep.u.reply_value_quoted.escaped) | 				if (client->rep.u.reply_value_quoted.escaped) | ||||||
| 				{ | 				{ | ||||||
| 					if (c == 'n') c = '\n'; | 					if (c == '\\') c = '\\'; | ||||||
|  | 					else if (c == '\"') c = '\"'; | ||||||
|  | 					else if (c == 'n') c = '\n'; | ||||||
| 					else if (c == 'r') c = '\r'; | 					else if (c == 'r') c = '\r'; | ||||||
| 					/* TODO: more escaping handling */ | 					/* TODO: more escaping handling */ | ||||||
| 				} | 				} | ||||||
| @ -376,17 +439,23 @@ print_tok (client); | |||||||
| 				if (add_to_reply_token(client, c) <= -1) goto oops; | 				if (add_to_reply_token(client, c) <= -1) goto oops; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 		 |  | ||||||
| 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED_TRAILER: | 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED_TRAILER: | ||||||
| 			if (c == HCL_OOCI_EOF) | 			if (c == HCL_OOCI_EOF) | ||||||
| 			{ | 			{ | ||||||
| 				printf ("suddend enf of input witjpit closing quote. -> total failure\n"); | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of reply line without newline"); | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 			else if (c == '\n') | 			else if (c == '\n') | ||||||
| 			{ | 			{ | ||||||
| printf ("reply value....===>"); | 			reply_value_end: | ||||||
| print_tok (client); | 				/* short-form format. the data pointer is passed to the start_reply  | ||||||
|  | 				 * callback. no end_reply callback is invoked. the data is assumed | ||||||
|  | 				 * to be in UTF-8 encoding. this is different from the data in the | ||||||
|  | 				 * long-format reply which is treated as octet stream */ | ||||||
|  | 				client->prim.start_reply (client, client->rep.type, client->rep.tok.ptr, client->rep.tok.len); | ||||||
|  | 				/* no end_reply() callback for the short-form reply */ | ||||||
|  |  | ||||||
| 				client->state = HCL_CLIENT_STATE_START; | 				client->state = HCL_CLIENT_STATE_START; | ||||||
| 				clear_reply_token (client); | 				clear_reply_token (client); | ||||||
| 				break; | 				break; | ||||||
| @ -398,14 +467,14 @@ print_tok (client); | |||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				printf ("garbage after a quoted reply value [%lc]\n", c); | 				hcl_client_seterrbfmt (client, HCL_EINVAL, "garbage after quoted reply value"); | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 		case HCL_CLIENT_STATE_IN_HEADER_NAME: | 		case HCL_CLIENT_STATE_IN_ATTR_KEY: | ||||||
| 			if (c == HCL_OOCI_EOF) | 			if (c == HCL_OOCI_EOF) | ||||||
| 			{ | 			{ | ||||||
| 				printf ("suddend end of input without a header name\n"); | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of attribute line"); | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 			else if (client->rep.tok.len == 0) | 			else if (client->rep.tok.len == 0) | ||||||
| @ -417,7 +486,7 @@ print_tok (client); | |||||||
| 				} | 				} | ||||||
| 				else if (c != '.') | 				else if (c != '.') | ||||||
| 				{ | 				{ | ||||||
| 					printf ("header not starting with a period\n"); | 					hcl_client_seterrbfmt (client, HCL_EINVAL, "attribute name not starting with a period"); | ||||||
| 					goto oops; | 					goto oops; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| @ -426,58 +495,192 @@ print_tok (client); | |||||||
| 			} | 			} | ||||||
| 			else	if (is_alphachar(c) || (client->rep.tok.len > 2 && c == '-')) | 			else	if (is_alphachar(c) || (client->rep.tok.len > 2 && c == '-')) | ||||||
| 			{ | 			{ | ||||||
|  | 				if (client->rep.tok.len >= HCL_CLIENT_REPLY_MAX_HDRKEY_LEN) | ||||||
|  | 				{ | ||||||
|  | 					hcl_client_seterrbfmt (client, HCL_EINVAL, "attribute name too long"); | ||||||
|  | 					goto oops; | ||||||
|  | 				} | ||||||
| 				if (add_to_reply_token(client, c) <= -1) goto oops; | 				if (add_to_reply_token(client, c) <= -1) goto oops; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				printf ("JKJJJJJJJJJ=>\n"); | 				if (is_token(client, ".DATA")) | ||||||
| 				print_tok(client); |  | ||||||
| 				if (hcl_compoocharsbcstr(client->rep.tok.ptr, client->rep.tok.len, ".ENCODING") == 0) |  | ||||||
| 				{ | 				{ | ||||||
| 					printf ("encoding....\n"); | 					client->rep.last_attr_type = HCL_CLIENT_REPLY_ATTR_TYPE_DATA; | ||||||
| 				} |  | ||||||
| 				else if (hcl_compoocharsbcstr(client->rep.tok.ptr, client->rep.tok.len, ".LENGTH") == 0) |  | ||||||
| 				{ |  | ||||||
| 					printf ("length....\n"); |  | ||||||
| 				} |  | ||||||
| 				else if (hcl_compoocharsbcstr(client->rep.tok.ptr, client->rep.tok.len, ".DATA") == 0) |  | ||||||
| 				{ |  | ||||||
| 					printf ("data....\n"); |  | ||||||
| 				} | 				} | ||||||
|  | 				/* PUT more known attribute handling here */ | ||||||
| 				else | 				else | ||||||
| 				{ | 				{ | ||||||
| 					printf ("unknown header ---> [%.*ls]\n", (int)client->rep.tok.len, client->rep.tok.ptr); | 					client->rep.last_attr_type = HCL_CLIENT_REPLY_ATTR_TYPE_UNKNOWN; | ||||||
| 					goto oops; |  | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				client->state = HCL_CLIENT_STATE_IN_HEADER_VALUE; | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len <= HCL_COUNTOF(client->rep.last_attr_key.buf)); | ||||||
|  | 				hcl_copyoochars (client->rep.last_attr_key.buf, client->rep.tok.ptr, client->rep.tok.len); | ||||||
|  | 				client->rep.last_attr_key.len = client->rep.tok.len; | ||||||
|  |  | ||||||
|  | 				client->state = HCL_CLIENT_STATE_IN_ATTR_VALUE_START; | ||||||
| 				clear_reply_token (client); | 				clear_reply_token (client); | ||||||
| 				/* [IMPORTANT] fall thru */ | 				/* [IMPORTANT] fall thru */ | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| /* | 		case HCL_CLIENT_STATE_IN_ATTR_VALUE_START: | ||||||
| echo -n -e '.OK"YOYO   bc\n\" abc"    \n    .ERROR             "XYZ"\n.OK\n.ENCODING chunked\n' |~/xxx/bin/hclc 11111 |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| 		case HCL_CLIENT_STATE_IN_HEADER_VALUE: |  | ||||||
| 			if (c == HCL_OOCI_EOF) | 			if (c == HCL_OOCI_EOF) | ||||||
| 			{ | 			{ | ||||||
| 				printf ("sudden end of input whthout header value\n"); | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end without attribute value"); | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
|  | 			else if (is_spacechar(c)) | ||||||
|  | 			{ | ||||||
|  | 				/* do nothing. skip it */ | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
| 			else if (c == '\n') | 			else if (c == '\n') | ||||||
| 			{ | 			{ | ||||||
| 				printf ("XXXXXXXXXXXXXXxx\n"); | 				hcl_client_seterrbfmt (client, HCL_EINVAL, "no attribute value for %.*js\n", client->rep.last_attr_key.len, client->rep.last_attr_key.buf); | ||||||
|  | 				goto oops; | ||||||
|  | 			} | ||||||
|  | 			else if (c == '\"') | ||||||
|  | 			{ | ||||||
|  | 				client->state = HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED; | ||||||
|  | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | ||||||
|  | 				client->rep.u.attr_value_quoted.escaped = 0; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			else  | 			else  | ||||||
| 			{ | 			{ | ||||||
| 				printf ("add to header value....\n"); | 				/* the first value character has been encountered */ | ||||||
|  | 				client->state = HCL_CLIENT_STATE_IN_ATTR_VALUE_UNQUOTED; | ||||||
|  | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | ||||||
|  | 				client->rep.u.attr_value_unquoted.nsplen = 0; | ||||||
|  | 				/* [IMPORTANT] fall thru */ | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		case HCL_CLIENT_STATE_IN_ATTR_VALUE_UNQUOTED: | ||||||
|  | 			if (c == HCL_OOCI_EOF) | ||||||
|  | 			{ | ||||||
|  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of attribute line without newline"); | ||||||
|  | 				goto oops; | ||||||
|  | 			} | ||||||
|  | 			else if (c == '\n') | ||||||
|  | 			{ | ||||||
|  | 				client->rep.tok.len = client->rep.u.attr_value_unquoted.nsplen; | ||||||
|  | 				goto attr_value_end; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | ||||||
|  | 				if (!is_spacechar(c)) client->rep.u.attr_value_unquoted.nsplen = client->rep.tok.len; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			break; | 		case HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED: | ||||||
|  | 			if (c == HCL_OOCI_EOF) | ||||||
|  | 			{ | ||||||
|  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of attribute value without closing quote"); | ||||||
|  | 				goto oops; | ||||||
|  | 			} | ||||||
|  | 			else  | ||||||
|  | 			{ | ||||||
|  | 				if (client->rep.u.attr_value_quoted.escaped) | ||||||
|  | 				{ | ||||||
|  | 					if (c == '\\') c = '\\'; | ||||||
|  | 					else if (c == '\"') c = '\"'; | ||||||
|  | 					else if (c == 'n') c = '\n'; | ||||||
|  | 					else if (c == 'r') c = '\r'; | ||||||
|  | 					/* TODO: more escaping handling */ | ||||||
|  | 				} | ||||||
|  | 				else if (c == '\\') | ||||||
|  | 				{ | ||||||
|  | 					client->rep.u.attr_value_quoted.escaped = 1; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				else if (c == '\"') | ||||||
|  | 				{ | ||||||
|  | 					client->state = HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED_TRAILER; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				client->rep.u.attr_value_quoted.escaped = 0; | ||||||
|  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		case HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED_TRAILER: | ||||||
|  | 			if (c == HCL_OOCI_EOF) | ||||||
|  | 			{ | ||||||
|  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of attribute line without newline"); | ||||||
|  | 				goto oops; | ||||||
|  | 			} | ||||||
|  | 			else if (c == '\n') | ||||||
|  | 			{ | ||||||
|  | 			attr_value_end: | ||||||
|  | 				if (client->prim.feed_attr) | ||||||
|  | 				{ | ||||||
|  | 					hcl_oocs_t key, val; | ||||||
|  | 					key.ptr = client->rep.last_attr_key.buf; | ||||||
|  | 					key.len = client->rep.last_attr_key.len; | ||||||
|  | 					val.ptr = client->rep.tok.ptr; | ||||||
|  | 					val.len = client->rep.tok.len; | ||||||
|  | 					client->prim.feed_attr (client, &key, &val); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (client->rep.last_attr_type == HCL_CLIENT_REPLY_ATTR_TYPE_DATA) | ||||||
|  | 				{ | ||||||
|  | 					hcl_oow_t length; | ||||||
|  |  | ||||||
|  | 					/* this must be the last attr. the trailing part are all data */ | ||||||
|  | 					if (is_token(client, "chunked")) | ||||||
|  | 					{ | ||||||
|  | 						client->state = HCL_CLIENT_STATE_IN_CHUNKED_DATA; | ||||||
|  | 						HCL_MEMSET (&client->rep.u.chunked_data, 0, HCL_SIZEOF(client->rep.u.chunked_data)); | ||||||
|  | 					} | ||||||
|  | 					else if (is_token_integer(client, &length)) | ||||||
|  | 					{ | ||||||
|  | 						if (length > 0) | ||||||
|  | 						{ | ||||||
|  | 							client->state = HCL_CLIENT_STATE_IN_LENGTH_BOUNDED_DATA; | ||||||
|  | 							/* [NOTE] the max length for the length-bounded transfer scheme is limited | ||||||
|  | 							 *        by the system word size as of this implementation */ | ||||||
|  | 							client->rep.u.length_bounded_data.max = length;  | ||||||
|  | 							client->rep.u.length_bounded_data.tally = 0; | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							/* .DATA 0 has been received. this should be end of the reply */ | ||||||
|  | 							client->state = HCL_CLIENT_STATE_START; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						hcl_client_seterrbfmt (client, HCL_EINVAL, "invalid attribute value for .DATA - %.*js", client->rep.tok.len, client->rep.tok.ptr); | ||||||
|  | 						goto oops; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					/* continue processing the next attr */ | ||||||
|  | 					client->state = HCL_CLIENT_STATE_IN_ATTR_KEY; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				clear_reply_token (client); | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 			else if (is_spacechar(c)) | ||||||
|  | 			{ | ||||||
|  | 				/* skip white spaces after the closing quote */ | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				hcl_client_seterrbfmt (client, HCL_EINVAL, "garbage after quoted attribute value for %.*js", client->rep.last_attr_key.len, client->rep.last_attr_key.buf); | ||||||
|  | 				goto oops; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		default: | ||||||
|  | 			/* this function must not be called for .DATA */ | ||||||
|  | 			hcl_client_seterrbfmt (client, HCL_EINTERN, "internal error - must not be called for state %d", client->state); | ||||||
|  | 			goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| @ -494,18 +697,118 @@ static int feed_reply_data (hcl_client_t* client, const hcl_bch_t* data, hcl_oow | |||||||
| 	ptr = data; | 	ptr = data; | ||||||
| 	end = ptr + len; | 	end = ptr + len; | ||||||
|  |  | ||||||
| //printf ("<<<%.*s>>>\n", (int)len, data); | 	while (ptr < end) | ||||||
| 	if (client->state == HCL_CLIENT_STATE_IN_BINARY_DATA) |  | ||||||
| 	{ | 	{ | ||||||
| 	} | 		if (client->state == HCL_CLIENT_STATE_IN_LENGTH_BOUNDED_DATA) | ||||||
| 	else | 		{ | ||||||
| 	{ | 			/* the data is treated as raw octets by this client */ | ||||||
| 		while (ptr < end) | 			hcl_oow_t capa, avail, taken; | ||||||
|  |  | ||||||
|  | 			capa = client->rep.u.length_bounded_data.max - client->rep.u.length_bounded_data.tally; | ||||||
|  | 			avail = end - ptr; | ||||||
|  | 			taken = (avail < capa)? avail: capa; | ||||||
|  |  | ||||||
|  | 			if (client->prim.feed_data) | ||||||
|  | 			{ | ||||||
|  | 				client->prim.feed_data (client, ptr, taken); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			ptr += taken; | ||||||
|  | 			client->rep.u.length_bounded_data.tally = taken; | ||||||
|  | 			if (taken == capa) | ||||||
|  | 			{ | ||||||
|  | 				/* read all data. no more */ | ||||||
|  | 				client->state = HCL_CLIENT_STATE_START; | ||||||
|  | 				client->prim.end_reply (client, HCL_CLIENT_END_REPLY_STATE_OK); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		else if (client->state == HCL_CLIENT_STATE_IN_CHUNKED_DATA) | ||||||
|  | 		{ | ||||||
|  | 			/* the data is treated as raw octets by this client */ | ||||||
|  | 			if (client->rep.u.chunked_data.in_data_part) | ||||||
|  | 			{ | ||||||
|  | 				hcl_oow_t capa, avail, taken; | ||||||
|  |  | ||||||
|  | 				capa = client->rep.u.chunked_data.max - client->rep.u.chunked_data.tally; | ||||||
|  | 				avail = end - ptr; | ||||||
|  | 				taken = (avail < capa)? avail: capa; | ||||||
|  |  | ||||||
|  | 				if (client->prim.feed_data) | ||||||
|  | 				{ | ||||||
|  | 					client->prim.feed_data (client, ptr, taken); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				ptr += taken; | ||||||
|  | 				client->rep.u.chunked_data.tally += taken; | ||||||
|  | 				client->rep.u.chunked_data.total += taken; | ||||||
|  | 				if (taken == capa) | ||||||
|  | 				{ | ||||||
|  | 					/* finished one chunk */ | ||||||
|  | 					client->rep.u.chunked_data.negated = 0; | ||||||
|  | 					client->rep.u.chunked_data.max = 0; | ||||||
|  | 					client->rep.u.chunked_data.tally = 0; | ||||||
|  | 					client->rep.u.chunked_data.clcount = 0; | ||||||
|  | 					client->rep.u.chunked_data.in_data_part = 0; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				while (ptr < end) | ||||||
|  | 				{ | ||||||
|  | 					hcl_bchu_t bc = (hcl_bchu_t)*ptr; | ||||||
|  | 					if (bc == '-' && client->rep.u.chunked_data.clcount == 0 && !client->rep.u.chunked_data.negated) | ||||||
|  | 					{ | ||||||
|  | 						client->rep.u.chunked_data.negated = 1; | ||||||
|  | 					} | ||||||
|  | 					else if (bc == ':')  | ||||||
|  | 					{ | ||||||
|  | 						ptr++; | ||||||
|  |  | ||||||
|  | 						if (client->rep.u.chunked_data.clcount == 0) | ||||||
|  | 						{ | ||||||
|  | 							hcl_client_seterrbfmt (client, HCL_EINVAL, "clone without valid chunk length"); | ||||||
|  | 							goto oops; | ||||||
|  | 						} | ||||||
|  |  | ||||||
|  | 						if (client->rep.u.chunked_data.negated) | ||||||
|  | 						{ | ||||||
|  | 							client->prim.end_reply (client, HCL_CLIENT_END_REPLY_STATE_REVOKED); | ||||||
|  | 							client->state = HCL_CLIENT_STATE_START; | ||||||
|  |  | ||||||
|  | 						} | ||||||
|  | 						if (client->rep.u.chunked_data.max == 0) | ||||||
|  | 						{ | ||||||
|  | 							client->prim.end_reply (client, HCL_CLIENT_END_REPLY_STATE_OK); | ||||||
|  | 							client->state = HCL_CLIENT_STATE_START; | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							client->rep.u.chunked_data.in_data_part = 1; | ||||||
|  | 							client->rep.u.chunked_data.tally = 0; | ||||||
|  | 						} | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 					else if (is_digitchar(bc))  | ||||||
|  | 					{ | ||||||
|  | 						client->rep.u.chunked_data.max = client->rep.u.chunked_data.max * 10 + (bc - '0'); | ||||||
|  | 						client->rep.u.chunked_data.clcount++; | ||||||
|  | 						ptr++; | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						hcl_client_seterrbfmt (client, HCL_EINVAL, "invalid chunk length character  - code[%#x]", bc); | ||||||
|  | 						goto oops; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
| 		{ | 		{ | ||||||
| 			hcl_ooci_t c; | 			hcl_ooci_t c; | ||||||
|  | 			hcl_oow_t bcslen; | ||||||
|  |  | ||||||
| 	#if defined(HCL_OOCH_IS_UCH) | 	#if defined(HCL_OOCH_IS_UCH) | ||||||
| 			hcl_oow_t bcslen, ucslen; | 			hcl_oow_t ucslen; | ||||||
| 			hcl_ooch_t uc; | 			hcl_ooch_t uc; | ||||||
| 			int n; | 			int n; | ||||||
|  |  | ||||||
| @ -518,7 +821,6 @@ static int feed_reply_data (hcl_client_t* client, const hcl_bch_t* data, hcl_oow | |||||||
| 				if (n == -3) | 				if (n == -3) | ||||||
| 				{ | 				{ | ||||||
| 					/* incomplete sequence */ | 					/* incomplete sequence */ | ||||||
| 					printf ("incompelete....feed me more\n"); |  | ||||||
| 					*xlen = ptr - data; | 					*xlen = ptr - data; | ||||||
| 					return 0; /* feed more for incomplete sequence */ | 					return 0; /* feed more for incomplete sequence */ | ||||||
| 				} | 				} | ||||||
| @ -527,11 +829,12 @@ static int feed_reply_data (hcl_client_t* client, const hcl_bch_t* data, hcl_oow | |||||||
| 			ptr += bcslen; | 			ptr += bcslen; | ||||||
| 			c = uc; | 			c = uc; | ||||||
| 	#else | 	#else | ||||||
|  | 			bcslen = 1; | ||||||
| 			c = *ptr++; | 			c = *ptr++; | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
| printf ("[%lc]\n", c); | //printf ("[%lc]\n", c); | ||||||
| 			if (handle_char(client, c) <= -1) goto oops; | 			if (handle_char(client, c, bcslen) <= -1) goto oops; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -540,7 +843,7 @@ printf ("[%lc]\n", c); | |||||||
|  |  | ||||||
| oops: | oops: | ||||||
| 	/* TODO: compute the number of processes bytes so far and return it via a parameter??? */ | 	/* TODO: compute the number of processes bytes so far and return it via a parameter??? */ | ||||||
| printf ("feed oops....\n"); | /*printf ("feed oops....\n");*/ | ||||||
| 	return -1; | 	return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -571,14 +874,10 @@ static int feed_all_reply_data (hcl_client_t* client, hcl_bch_t* buf, hcl_oow_t | |||||||
| hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_prim_t* prim, hcl_errnum_t* errnum) | hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_prim_t* prim, hcl_errnum_t* errnum) | ||||||
| { | { | ||||||
| 	hcl_client_t* client; | 	hcl_client_t* client; | ||||||
| #if 0 |  | ||||||
| 	hcl_t* hcl; | 	hcl_t* hcl; | ||||||
| 	hcl_vmprim_t vmprim; | 	hcl_vmprim_t vmprim; | ||||||
| 	hcl_tmr_t* tmr; |  | ||||||
| 	dummy_hcl_xtn_t* xtn; | 	dummy_hcl_xtn_t* xtn; | ||||||
| 	int pfd[2], fcv; | /*	unsigned int trait;*/ | ||||||
| 	unsigned int trait; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	client = (hcl_client_t*)HCL_MMGR_ALLOC(mmgr, HCL_SIZEOF(*client) + xtnsize); | 	client = (hcl_client_t*)HCL_MMGR_ALLOC(mmgr, HCL_SIZEOF(*client) + xtnsize); | ||||||
| 	if (!client)  | 	if (!client)  | ||||||
| @ -587,15 +886,9 @@ hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_p | |||||||
| 		return HCL_NULL; | 		return HCL_NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #if 0 |  | ||||||
| 	HCL_MEMSET (&vmprim, 0, HCL_SIZEOF(vmprim)); | 	HCL_MEMSET (&vmprim, 0, HCL_SIZEOF(vmprim)); | ||||||
| 	vmprim.log_write = log_write_for_dummy; | 	vmprim.log_write = log_write_for_dummy; | ||||||
| 	vmprim.syserrstrb = syserrstrb; | 	vmprim.syserrstrb = syserrstrb; | ||||||
| 	vmprim.dl_open = dl_open; |  | ||||||
| 	vmprim.dl_close = dl_close; |  | ||||||
| 	vmprim.dl_getsym = dl_getsym; |  | ||||||
| 	vmprim.vm_gettime = vm_gettime; |  | ||||||
| 	vmprim.vm_sleep = vm_sleep; |  | ||||||
|  |  | ||||||
| 	hcl = hcl_open(mmgr, HCL_SIZEOF(*xtn), 2048, &vmprim, errnum); | 	hcl = hcl_open(mmgr, HCL_SIZEOF(*xtn), 2048, &vmprim, errnum); | ||||||
| 	if (!hcl)  | 	if (!hcl)  | ||||||
| @ -604,35 +897,6 @@ hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_p | |||||||
| 		return HCL_NULL; | 		return HCL_NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	tmr = hcl_tmr_open(hcl, 0, 1024); /* TOOD: make the timer's default size configurable */ |  | ||||||
| 	if (!tmr) |  | ||||||
| 	{ |  | ||||||
| 		hcl_close (hcl); |  | ||||||
| 		HCL_MMGR_FREE (mmgr, client); |  | ||||||
| 		return HCL_NULL; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (pipe(pfd) <= -1) |  | ||||||
| 	{ |  | ||||||
| 		hcl_tmr_close (tmr); |  | ||||||
| 		hcl_close (hcl); |  | ||||||
| 		HCL_MMGR_FREE (mmgr, client); |  | ||||||
| 		return HCL_NULL; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| #if defined(O_CLOEXEC) |  | ||||||
| 	fcv = fcntl(pfd[0], F_GETFD, 0); |  | ||||||
| 	if (fcv >= 0) fcntl(pfd[0], F_SETFD, fcv | O_CLOEXEC); |  | ||||||
| 	fcv = fcntl(pfd[1], F_GETFD, 0); |  | ||||||
| 	if (fcv >= 0) fcntl(pfd[1], F_SETFD, fcv | O_CLOEXEC); |  | ||||||
| #endif |  | ||||||
| #if defined(O_NONBLOCK) |  | ||||||
| 	fcv = fcntl(pfd[0], F_GETFL, 0); |  | ||||||
| 	if (fcv >= 0) fcntl(pfd[0], F_SETFL, fcv | O_NONBLOCK); |  | ||||||
| 	fcv = fcntl(pfd[1], F_GETFL, 0); |  | ||||||
| 	if (fcv >= 0) fcntl(pfd[1], F_SETFL, fcv | O_NONBLOCK); |  | ||||||
| #endif |  | ||||||
| 	 |  | ||||||
| 	xtn = (dummy_hcl_xtn_t*)hcl_getxtn(hcl); | 	xtn = (dummy_hcl_xtn_t*)hcl_getxtn(hcl); | ||||||
| 	xtn->client = client; | 	xtn->client = client; | ||||||
|  |  | ||||||
| @ -641,81 +905,42 @@ hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_p | |||||||
| 	client->cmgr = hcl_get_utf8_cmgr(); | 	client->cmgr = hcl_get_utf8_cmgr(); | ||||||
| 	client->prim = *prim; | 	client->prim = *prim; | ||||||
| 	client->dummy_hcl = hcl; | 	client->dummy_hcl = hcl; | ||||||
| 	client->tmr = tmr; |  | ||||||
|  |  | ||||||
| 	client->cfg.logmask = ~0u; | 	client->cfg.logmask = ~0u; | ||||||
| 	client->cfg.worker_stack_size = 512000UL;  |  | ||||||
| 	client->cfg.actor_heap_size = 512000UL; |  | ||||||
|  |  | ||||||
| 	HCL_INITNTIME (&client->cfg.worker_idle_timeout, 0, 0); |  | ||||||
| 	HCL_INITNTIME (&client->cfg.actor_max_runtime, 0, 0); |  | ||||||
|  |  | ||||||
| 	client->mux_pipe[0] = pfd[0]; |  | ||||||
| 	client->mux_pipe[1] = pfd[1]; |  | ||||||
|  |  | ||||||
| 	client->wid_map.free_first = HCL_SERVER_WID_INVALID; |  | ||||||
| 	client->wid_map.free_last = HCL_SERVER_WID_INVALID; |  | ||||||
| 	 |  | ||||||
| 	pthread_mutex_init (&client->worker_mutex, HCL_NULL); |  | ||||||
| 	pthread_mutex_init (&client->tmr_mutex, HCL_NULL); |  | ||||||
| 	pthread_mutex_init (&client->log_mutex, HCL_NULL); |  | ||||||
|  |  | ||||||
| 	/* the dummy hcl is used for this client to perform primitive operations | 	/* the dummy hcl is used for this client to perform primitive operations | ||||||
| 	 * such as getting system time or logging. so the heap size doesn't  | 	 * such as getting system time or logging. so the heap size doesn't  | ||||||
| 	 * need to be changed from the tiny value set above. */ | 	 * need to be changed from the tiny value set above. */ | ||||||
| 	hcl_setoption (client->dummy_hcl, HCL_LOG_MASK, &client->cfg.logmask); | 	hcl_setoption (client->dummy_hcl, HCL_LOG_MASK, &client->cfg.logmask); | ||||||
| 	hcl_setcmgr (client->dummy_hcl, client->cmgr); | 	hcl_setcmgr (client->dummy_hcl, client->cmgr); | ||||||
| 	hcl_getoption (client->dummy_hcl, HCL_TRAIT, &trait); |  | ||||||
| #if defined(HCL_BUILD_DEBUG) |  | ||||||
| 	if (client->cfg.trait & HCL_SERVER_TRAIT_DEBUG_GC) trait |= HCL_DEBUG_GC; |  | ||||||
| 	if (client->cfg.trait & HCL_SERVER_TRAIT_DEBUG_BIGINT) trait |= HCL_DEBUG_BIGINT; |  | ||||||
| #endif |  | ||||||
| 	hcl_setoption (client->dummy_hcl, HCL_TRAIT, &trait); |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| 	HCL_MEMSET (client, 0, HCL_SIZEOF(*client) + xtnsize); |  | ||||||
| 	client->mmgr = mmgr; |  | ||||||
| 	client->cmgr = hcl_get_utf8_cmgr(); |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	return client; | 	return client; | ||||||
| } | } | ||||||
|  |  | ||||||
| void hcl_client_close (hcl_client_t* client) | void hcl_client_close (hcl_client_t* client) | ||||||
| { | { | ||||||
|  | 	if (client->rep.tok.ptr) | ||||||
|  | 	{ | ||||||
|  | 		hcl_client_freemem (client, client->rep.tok.ptr); | ||||||
|  | 		client->rep.tok.ptr = HCL_NULL; | ||||||
|  | 		client->rep.tok.len = 0; | ||||||
|  | 		client->rep.tok.capa = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hcl_close (client->dummy_hcl); | ||||||
| 	HCL_MMGR_FREE (client->mmgr, client); | 	HCL_MMGR_FREE (client->mmgr, client); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| int hcl_client_setoption (hcl_client_t* client, hcl_client_option_t id, const void* value) | int hcl_client_setoption (hcl_client_t* client, hcl_client_option_t id, const void* value) | ||||||
| { | { | ||||||
| 	switch (id) | 	switch (id) | ||||||
| 	{ | 	{ | ||||||
| 		case HCL_CLIENT_TRAIT: | 		case HCL_CLIENT_TRAIT: | ||||||
| 			client->cfg.trait = *(const unsigned int*)value; | 			client->cfg.trait = *(const unsigned int*)value; | ||||||
| 		#if 0 |  | ||||||
| 			if (client->dummy_hcl) |  | ||||||
| 			{ |  | ||||||
| 				/* setting this affects the dummy hcl immediately. |  | ||||||
| 				 * existing hcl instances inside worker threads won't get  |  | ||||||
| 				 * affected. new hcl instances to be created later  |  | ||||||
| 				 * is supposed to use the new value */ |  | ||||||
| 				unsigned int trait; |  | ||||||
|  |  | ||||||
| 				hcl_getoption (client->dummy_hcl, HCL_TRAIT, &trait); |  | ||||||
| 			#if defined(HCL_BUILD_DEBUG) |  | ||||||
| 				if (client->cfg.trait & HCL_CLIENT_TRAIT_DEBUG_GC) trait |= HCL_DEBUG_GC; |  | ||||||
| 				if (client->cfg.trait & HCL_CLIENT_TRAIT_DEBUG_BIGINT) trait |= HCL_DEBUG_BIGINT; |  | ||||||
| 			#endif |  | ||||||
| 				hcl_setoption (client->dummy_hcl, HCL_TRAIT, &trait); |  | ||||||
| 			} |  | ||||||
| 		#endif |  | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
| 		case HCL_CLIENT_LOG_MASK: | 		case HCL_CLIENT_LOG_MASK: | ||||||
| 			client->cfg.logmask = *(const unsigned int*)value; | 			client->cfg.logmask = *(const unsigned int*)value; | ||||||
| 		#if 0 |  | ||||||
| 			if (client->dummy_hcl)  | 			if (client->dummy_hcl)  | ||||||
| 			{ | 			{ | ||||||
| 				/* setting this affects the dummy hcl immediately. | 				/* setting this affects the dummy hcl immediately. | ||||||
| @ -724,19 +949,6 @@ int hcl_client_setoption (hcl_client_t* client, hcl_client_option_t id, const vo | |||||||
| 				 * is supposed to use the new value */ | 				 * is supposed to use the new value */ | ||||||
| 				hcl_setoption (client->dummy_hcl, HCL_LOG_MASK, value); | 				hcl_setoption (client->dummy_hcl, HCL_LOG_MASK, value); | ||||||
| 			} | 			} | ||||||
| 		#endif |  | ||||||
| 			return 0; |  | ||||||
|  |  | ||||||
| 		case HCL_CLIENT_WORKER_MAX_COUNT: |  | ||||||
| 			client->cfg.worker_max_count = *(hcl_oow_t*)value; |  | ||||||
| 			return 0; |  | ||||||
|  |  | ||||||
| 		case HCL_CLIENT_WORKER_STACK_SIZE: |  | ||||||
| 			client->cfg.worker_stack_size = *(hcl_oow_t*)value; |  | ||||||
| 			return 0; |  | ||||||
|  |  | ||||||
| 		case HCL_CLIENT_WORKER_IDLE_TIMEOUT: |  | ||||||
| 			client->cfg.worker_idle_timeout = *(hcl_ntime_t*)value; |  | ||||||
| 			return 0; | 			return 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -755,18 +967,6 @@ int hcl_client_getoption (hcl_client_t* client, hcl_client_option_t id, void* va | |||||||
| 		case HCL_CLIENT_LOG_MASK: | 		case HCL_CLIENT_LOG_MASK: | ||||||
| 			*(unsigned int*)value = client->cfg.logmask; | 			*(unsigned int*)value = client->cfg.logmask; | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
| 		case HCL_CLIENT_WORKER_MAX_COUNT: |  | ||||||
| 			*(hcl_oow_t*)value = client->cfg.worker_max_count; |  | ||||||
| 			return 0; |  | ||||||
|  |  | ||||||
| 		case HCL_CLIENT_WORKER_STACK_SIZE: |  | ||||||
| 			*(hcl_oow_t*)value = client->cfg.worker_stack_size; |  | ||||||
| 			return 0; |  | ||||||
|  |  | ||||||
| 		case HCL_CLIENT_WORKER_IDLE_TIMEOUT: |  | ||||||
| 			*(hcl_ntime_t*)value = client->cfg.worker_idle_timeout; |  | ||||||
| 			return 0; |  | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	hcl_client_seterrnum (client, HCL_EINVAL); | 	hcl_client_seterrnum (client, HCL_EINVAL); | ||||||
| @ -817,6 +1017,54 @@ void hcl_client_seterrnum (hcl_client_t* client, hcl_errnum_t errnum) | |||||||
| 	client->errmsg.len = 0; | 	client->errmsg.len = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void hcl_client_seterrbfmt (hcl_client_t* client, hcl_errnum_t errnum, const hcl_bch_t* fmt, ...) | ||||||
|  | { | ||||||
|  | 	va_list ap; | ||||||
|  |  | ||||||
|  | 	va_start (ap, fmt); | ||||||
|  | 	hcl_seterrbfmtv (client->dummy_hcl, errnum, fmt, ap); | ||||||
|  | 	va_end (ap); | ||||||
|  |  | ||||||
|  | 	HCL_ASSERT (client->dummy_hcl, HCL_COUNTOF(client->errmsg.buf) == HCL_COUNTOF(client->dummy_hcl->errmsg.buf)); | ||||||
|  | 	client->errnum = errnum; | ||||||
|  | 	hcl_copyoochars (client->errmsg.buf, client->dummy_hcl->errmsg.buf, HCL_COUNTOF(client->errmsg.buf)); | ||||||
|  | 	client->errmsg.len = client->dummy_hcl->errmsg.len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void hcl_client_seterrufmt (hcl_client_t* client, hcl_errnum_t errnum, const hcl_uch_t* fmt, ...) | ||||||
|  | { | ||||||
|  | 	va_list ap; | ||||||
|  |  | ||||||
|  | 	va_start (ap, fmt); | ||||||
|  | 	hcl_seterrufmtv (client->dummy_hcl, errnum, fmt, ap); | ||||||
|  | 	va_end (ap); | ||||||
|  |  | ||||||
|  | 	HCL_ASSERT (client->dummy_hcl, HCL_COUNTOF(client->errmsg.buf) == HCL_COUNTOF(client->dummy_hcl->errmsg.buf)); | ||||||
|  | 	client->errnum = errnum; | ||||||
|  | 	hcl_copyoochars (client->errmsg.buf, client->dummy_hcl->errmsg.buf, HCL_COUNTOF(client->errmsg.buf)); | ||||||
|  | 	client->errmsg.len = client->dummy_hcl->errmsg.len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ========================================================================= */ | ||||||
|  |  | ||||||
|  | void hcl_client_logbfmt (hcl_client_t* client, unsigned int mask, const hcl_bch_t* fmt, ...) | ||||||
|  | { | ||||||
|  | 	va_list ap; | ||||||
|  | 	va_start (ap, fmt); | ||||||
|  | 	hcl_logbfmtv (client->dummy_hcl, mask, fmt, ap); | ||||||
|  | 	va_end (ap); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void hcl_client_logufmt (hcl_client_t* client, unsigned int mask, const hcl_uch_t* fmt, ...) | ||||||
|  | { | ||||||
|  | 	va_list ap; | ||||||
|  | 	va_start (ap, fmt); | ||||||
|  | 	hcl_logufmtv (client->dummy_hcl, mask, fmt, ap); | ||||||
|  | 	va_end (ap); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ========================================================================= */ | ||||||
|  |  | ||||||
| void* hcl_client_allocmem (hcl_client_t* client, hcl_oow_t size) | void* hcl_client_allocmem (hcl_client_t* client, hcl_oow_t size) | ||||||
| { | { | ||||||
| 	void* ptr; | 	void* ptr; | ||||||
| @ -848,7 +1096,6 @@ void hcl_client_freemem (hcl_client_t* client, void* ptr) | |||||||
| 	HCL_MMGR_FREE (client->mmgr, ptr); | 	HCL_MMGR_FREE (client->mmgr, ptr); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /* ========================================================================= */ | /* ========================================================================= */ | ||||||
|  |  | ||||||
| int hcl_client_start (hcl_client_t* client, const hcl_bch_t* addrs) | int hcl_client_start (hcl_client_t* client, const hcl_bch_t* addrs) | ||||||
| @ -887,7 +1134,6 @@ int hcl_client_start (hcl_client_t* client, const hcl_bch_t* addrs) | |||||||
| 		if (offset > 0) HCL_MEMMOVE (&buf[0], &buf[xlen], offset); | 		if (offset > 0) HCL_MEMMOVE (&buf[0], &buf[xlen], offset); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| printf ("hcl client start returns success\n"); |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -36,38 +36,84 @@ enum hcl_client_option_t | |||||||
| { | { | ||||||
| 	HCL_CLIENT_TRAIT, | 	HCL_CLIENT_TRAIT, | ||||||
| 	HCL_CLIENT_LOG_MASK, | 	HCL_CLIENT_LOG_MASK, | ||||||
| 	HCL_CLIENT_WORKER_MAX_COUNT, |  | ||||||
| 	HCL_CLIENT_WORKER_STACK_SIZE, |  | ||||||
| 	HCL_CLIENT_WORKER_IDLE_TIMEOUT |  | ||||||
| }; | }; | ||||||
| typedef enum hcl_client_option_t hcl_client_option_t; | typedef enum hcl_client_option_t hcl_client_option_t; | ||||||
|  |  | ||||||
| enum hcl_client_trait_t | enum hcl_client_trait_t | ||||||
| { | { | ||||||
| #if defined(HCL_BUILD_DEBUG) | 	/* no trait defined at this moment. XXXX is just a placeholder */ | ||||||
| 	HCL_CLIENT_TRAIT_DEBUG_GC         = (1 << 0), | 	HCL_CLIENT_XXXX  = (1 << 0) | ||||||
| 	HCL_CLIENT_TRAIT_DEBUG_BIGINT     = (1 << 1), |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	HCL_CLIENT_TRAIT_READABLE_PROTO   = (1 << 2), |  | ||||||
| 	HCL_CLIENT_TRAIT_USE_LARGE_PAGES  = (1 << 3) |  | ||||||
| }; | }; | ||||||
| typedef enum hcl_client_trait_t hcl_client_trait_t; | typedef enum hcl_client_trait_t hcl_client_trait_t; | ||||||
|  |  | ||||||
|  | /* ========================================================================= */ | ||||||
|  |  | ||||||
|  | enum hcl_client_reply_type_t | ||||||
|  | { | ||||||
|  | 	HCL_CLIENT_REPLY_TYPE_OK = 0, | ||||||
|  | 	HCL_CLIENT_REPLY_TYPE_ERROR = 1 | ||||||
|  | }; | ||||||
|  | typedef enum hcl_client_reply_type_t hcl_client_reply_type_t; | ||||||
|  |  | ||||||
| typedef void (*hcl_client_log_write_t) ( | typedef void (*hcl_client_log_write_t) ( | ||||||
| 	hcl_client_t*     client, | 	hcl_client_t*     client, | ||||||
| 	hcl_oow_t         wid, |  | ||||||
| 	unsigned int      mask, | 	unsigned int      mask, | ||||||
| 	const hcl_ooch_t* msg, | 	const hcl_ooch_t* msg, | ||||||
| 	hcl_oow_t         len | 	hcl_oow_t         len | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | typedef void (*hcl_client_start_reply_t) ( | ||||||
|  | 	hcl_client_t*           client, | ||||||
|  | 	hcl_client_reply_type_t type, | ||||||
|  | 	const hcl_ooch_t*       dptr, | ||||||
|  | 	hcl_oow_t               dlen | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | typedef void (*hcl_client_feed_attr_t) ( | ||||||
|  | 	hcl_client_t*     client, | ||||||
|  | 	const hcl_oocs_t* key, | ||||||
|  | 	const hcl_oocs_t* val | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | typedef void (*hcl_client_start_data_t) ( | ||||||
|  | 	hcl_client_t*     client | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | typedef void (*hcl_client_feed_data_t) ( | ||||||
|  | 	hcl_client_t*     client, | ||||||
|  | 	const void*       ptr, | ||||||
|  | 	hcl_oow_t         len | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | typedef void (*hcl_client_end_data_t) ( | ||||||
|  | 	hcl_client_t*     client | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | enum hcl_client_end_reply_state_t | ||||||
|  | { | ||||||
|  | 	HCL_CLIENT_END_REPLY_STATE_OK, | ||||||
|  | 	HCL_CLIENT_END_REPLY_STATE_REVOKED, | ||||||
|  | 	HCL_CLIENT_END_REPLY_STATE_ERROR | ||||||
|  | }; | ||||||
|  | typedef enum hcl_client_end_reply_state_t hcl_client_end_reply_state_t; | ||||||
|  |  | ||||||
|  | typedef void (*hcl_client_end_reply_t) ( | ||||||
|  | 	hcl_client_t*                client, | ||||||
|  | 	hcl_client_end_reply_state_t state | ||||||
|  | ); | ||||||
|  |  | ||||||
| struct hcl_client_prim_t | struct hcl_client_prim_t | ||||||
| { | { | ||||||
| 	hcl_client_log_write_t log_write; | 	hcl_client_log_write_t     log_write; | ||||||
|  |  | ||||||
|  | 	hcl_client_start_reply_t   start_reply;   /* mandatory */ | ||||||
|  | 	hcl_client_feed_attr_t     feed_attr; /* optional */ | ||||||
|  | 	hcl_client_feed_data_t     feed_data;     /* optional */ | ||||||
|  | 	hcl_client_end_reply_t     end_reply;     /* mandatory */ | ||||||
| }; | }; | ||||||
| typedef struct hcl_client_prim_t hcl_client_prim_t; | typedef struct hcl_client_prim_t hcl_client_prim_t; | ||||||
|  |  | ||||||
|  | /* ========================================================================= */ | ||||||
|  |  | ||||||
| #if defined(__cplusplus) | #if defined(__cplusplus) | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -141,9 +187,33 @@ HCL_EXPORT void hcl_client_seterrnum ( | |||||||
| 	hcl_errnum_t  errnum | 	hcl_errnum_t  errnum | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | HCL_EXPORT void hcl_client_seterrbfmt ( | ||||||
|  | 	hcl_client_t*    client, | ||||||
|  | 	hcl_errnum_t     errnum, | ||||||
|  | 	const hcl_bch_t* fmt, | ||||||
|  | 	... | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | HCL_EXPORT void hcl_client_seterrufmt ( | ||||||
|  | 	hcl_client_t*    client, | ||||||
|  | 	hcl_errnum_t     errnum, | ||||||
|  | 	const hcl_uch_t* fmt, | ||||||
|  | 	... | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | HCL_EXPORT void hcl_client_logbfmt ( | ||||||
|  | 	hcl_client_t*    client, | ||||||
|  | 	unsigned int     mask, | ||||||
|  | 	const hcl_bch_t* fmt, | ||||||
|  | 	... | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | HCL_EXPORT void hcl_client_logufmt ( | ||||||
|  | 	hcl_client_t*    client, | ||||||
|  | 	unsigned int     mask, | ||||||
|  | 	const hcl_uch_t* fmt, | ||||||
|  | 	... | ||||||
|  | ); | ||||||
|  |  | ||||||
| HCL_EXPORT void* hcl_client_allocmem ( | HCL_EXPORT void* hcl_client_allocmem ( | ||||||
| 	hcl_client_t* client, | 	hcl_client_t* client, | ||||||
| @ -167,7 +237,6 @@ HCL_EXPORT void hcl_client_freemem ( | |||||||
| 	void*         ptr | 	void*         ptr | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  |  | ||||||
| #if defined(__cplusplus) | #if defined(__cplusplus) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -161,7 +161,6 @@ struct dummy_hcl_xtn_t | |||||||
| }; | }; | ||||||
| typedef struct dummy_hcl_xtn_t dummy_hcl_xtn_t; | typedef struct dummy_hcl_xtn_t dummy_hcl_xtn_t; | ||||||
|  |  | ||||||
|  |  | ||||||
| enum hcl_server_proto_token_type_t | enum hcl_server_proto_token_type_t | ||||||
| { | { | ||||||
| 	HCL_SERVER_PROTO_TOKEN_EOF, | 	HCL_SERVER_PROTO_TOKEN_EOF, | ||||||
| @ -276,7 +275,7 @@ struct hcl_server_wid_map_data_t | |||||||
| 	} u; | 	} u; | ||||||
| }; | }; | ||||||
| typedef struct hcl_server_wid_map_data_t hcl_server_wid_map_data_t; | typedef struct hcl_server_wid_map_data_t hcl_server_wid_map_data_t; | ||||||
| 		 |  | ||||||
| struct hcl_server_t | struct hcl_server_t | ||||||
| { | { | ||||||
| 	hcl_mmgr_t*  mmgr; | 	hcl_mmgr_t*  mmgr; | ||||||
| @ -1111,12 +1110,12 @@ static int write_reply_chunk (hcl_server_proto_t* proto) | |||||||
| 		if (proto->reply.nchunks <= 0) | 		if (proto->reply.nchunks <= 0) | ||||||
| 		{ | 		{ | ||||||
| 			/* this is the first chunk */ | 			/* this is the first chunk */ | ||||||
| 			iov[count].iov_base = ".OK\n.ENCODING chunked\n.DATA\n"; | 			iov[count].iov_base = ".OK\n.DATA chunked\n"; | ||||||
| 			iov[count++].iov_len = 28; | 			iov[count++].iov_len = 18; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		iov[count].iov_base = cl, | 		iov[count].iov_base = cl, | ||||||
| 		iov[count++].iov_len = snprintf(cl, HCL_SIZEOF(cl), "%s%zu:", (((proto->worker->server->cfg.trait & HCL_SERVER_TRAIT_READABLE_PROTO) && proto->reply.nchunks > 0)? "\n": ""), proto->reply.len);  | 		iov[count++].iov_len = snprintf(cl, HCL_SIZEOF(cl), "%zu:", proto->reply.len);  | ||||||
| 	} | 	} | ||||||
| 	iov[count].iov_base = proto->reply.buf; | 	iov[count].iov_base = proto->reply.buf; | ||||||
| 	iov[count++].iov_len = proto->reply.len; | 	iov[count++].iov_len = proto->reply.len; | ||||||
| @ -1245,14 +1244,14 @@ int hcl_server_proto_end_reply (hcl_server_proto_t* proto, const hcl_ooch_t* fai | |||||||
| 			/* some chunks have beed emitted. but at the end, an error has occurred. | 			/* some chunks have beed emitted. but at the end, an error has occurred. | ||||||
| 			 * send -1: as the last chunk. the receiver must rub out the reply | 			 * send -1: as the last chunk. the receiver must rub out the reply | ||||||
| 			 * buffer received so far and expect the following .ERROR response */ | 			 * buffer received so far and expect the following .ERROR response */ | ||||||
| 			static hcl_ooch_t err0[] = { '-','1',':','\n' }; | 			static hcl_ooch_t err0[] = { '-','1',':' }; | ||||||
| 			if (proto->reply.len > 0 && write_reply_chunk(proto) <= -1) return -1; | 			if (proto->reply.len > 0 && write_reply_chunk(proto) <= -1) return -1; | ||||||
|  |  | ||||||
| 			proto->reply.type = HCL_SERVER_PROTO_REPLY_SIMPLE; /* switch to the simple mode forcibly */ | 			proto->reply.type = HCL_SERVER_PROTO_REPLY_SIMPLE; /* switch to the simple mode forcibly */ | ||||||
| 			proto->reply.nchunks = 0; | 			proto->reply.nchunks = 0; | ||||||
| 			proto->reply.len = 0; | 			proto->reply.len = 0; | ||||||
|  |  | ||||||
| 			if (hcl_server_proto_feed_reply(proto, err0, 4, 0) <= -1) return -1; | 			if (hcl_server_proto_feed_reply(proto, err0, 3, 0) <= -1) return -1; | ||||||
| 			goto simple_error; | 			goto simple_error; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -53,8 +53,7 @@ enum hcl_server_trait_t | |||||||
| 	HCL_SERVER_TRAIT_DEBUG_BIGINT     = (1 << 1), | 	HCL_SERVER_TRAIT_DEBUG_BIGINT     = (1 << 1), | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| 	HCL_SERVER_TRAIT_READABLE_PROTO   = (1 << 2), | 	HCL_SERVER_TRAIT_USE_LARGE_PAGES  = (1 << 2) | ||||||
| 	HCL_SERVER_TRAIT_USE_LARGE_PAGES  = (1 << 3) |  | ||||||
| }; | }; | ||||||
| typedef enum hcl_server_trait_t hcl_server_trait_t; | typedef enum hcl_server_trait_t hcl_server_trait_t; | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										141
									
								
								hcl/lib/main-c.c
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								hcl/lib/main-c.c
									
									
									
									
									
								
							| @ -190,7 +190,7 @@ static void flush_log (hcl_client_t* client, int fd) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| static void log_write (hcl_client_t* client, hcl_oow_t wid, unsigned int mask, const hcl_ooch_t* msg, hcl_oow_t len) | static void log_write (hcl_client_t* client, unsigned int mask, const hcl_ooch_t* msg, hcl_oow_t len) | ||||||
| { | { | ||||||
| 	hcl_bch_t buf[256]; | 	hcl_bch_t buf[256]; | ||||||
| 	hcl_oow_t ucslen, bcslen; | 	hcl_oow_t ucslen, bcslen; | ||||||
| @ -242,15 +242,6 @@ static void log_write (hcl_client_t* client, hcl_oow_t wid, unsigned int mask, c | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		write_log (client, logfd, ts, tslen); | 		write_log (client, logfd, ts, tslen); | ||||||
|  |  | ||||||
| #if 0 |  | ||||||
| 		if (wid != HCL_CLIENT_WID_INVALID) |  | ||||||
| 		{ |  | ||||||
| 			/* TODO: check if the underlying snprintf support %zd */ |  | ||||||
| 			tslen = snprintf (ts, sizeof(ts), "[%zu] ", wid); |  | ||||||
| 			write_log (client, logfd, ts, tslen); |  | ||||||
| 		} |  | ||||||
| #endif |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (logfd == xtn->logfd && xtn->logfd_istty) | 	if (logfd == xtn->logfd && xtn->logfd_istty) | ||||||
| @ -445,38 +436,43 @@ static int handle_logopt (hcl_client_t* client, const hcl_bch_t* str) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| #if defined(HCL_BUILD_DEBUG) | static void start_reply (hcl_client_t* client, hcl_client_reply_type_t type, const hcl_ooch_t* dptr, hcl_oow_t dlen) | ||||||
| static int handle_dbgopt (hcl_client_t* client, const char* str) |  | ||||||
| { | { | ||||||
| 	const hcl_bch_t* cm, * flt; | 	if (dptr) | ||||||
| 	hcl_oow_t len; |  | ||||||
| 	unsigned int trait; |  | ||||||
|  |  | ||||||
| 	hcl_client_getoption (client, HCL_CLIENT_TRAIT, &trait); |  | ||||||
|  |  | ||||||
| 	cm = str - 1; |  | ||||||
| 	do |  | ||||||
| 	{ | 	{ | ||||||
| 		flt = cm + 1; | 		printf ("GOT SHORT-FORM RESPONSE[%d] with data <<%.*ls>>\n", (int)type, (int)dlen, dptr); | ||||||
|  | 	} | ||||||
| 		cm = hcl_findbcharinbcstr(flt, ','); | 	else | ||||||
| 		len = cm? (cm - flt): hcl_countbcstr(flt); | 	{ | ||||||
| 		if (hcl_compbcharsbcstr(flt, len, "gc") == 0)  trait |= HCL_CLIENT_TRAIT_DEBUG_GC; | 		printf ("GOT LONG_FORM RESPONSE[%d]\n", (int)type); | ||||||
| 		else if (hcl_compbcharsbcstr(flt, len, "bigint") == 0)  trait |= HCL_CLIENT_TRAIT_DEBUG_BIGINT; |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			fprintf (stderr, "ERROR: unknown debug option value - %.*s\n", (int)len, flt); |  | ||||||
| 			return -1; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	while (cm); |  | ||||||
|  |  | ||||||
| 	hcl_client_setoption (client, HCL_CLIENT_TRAIT, &trait); |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  | static void end_reply (hcl_client_t* client, hcl_client_end_reply_state_t state) | ||||||
|  | { | ||||||
|  | 	if (state == HCL_CLIENT_END_REPLY_STATE_ERROR) | ||||||
|  | 	{ | ||||||
|  | printf (">>>>>>>>>>>>>>>>>>>>> reply error....\n"); | ||||||
|  | 	} | ||||||
|  | 	else if (state == HCL_CLIENT_END_REPLY_STATE_REVOKED) | ||||||
|  | 	{ | ||||||
|  | printf (">>>>>>>>>>>>>>>>>>>>>> REPLY revoked....\n"); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | printf (">>>>>>>>>>>>>>>>>>>>> REPLY ENDED OK....\n"); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void feed_attr (hcl_client_t* client, const hcl_oocs_t* key, const hcl_oocs_t* val) | ||||||
|  | { | ||||||
|  | printf ("GOT HEADER ====> [%.*ls] ===> [%.*ls]\n", (int)key->len, key->ptr, (int)val->len, val->ptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void feed_data (hcl_client_t* client, const void* ptr, hcl_oow_t len) | ||||||
|  | { | ||||||
|  | printf ("GOT DATA>>>>>>>>>[%.*s]>>>>>>>\n", (int)len, ptr); | ||||||
|  | } | ||||||
| /* ========================================================================= */ | /* ========================================================================= */ | ||||||
|  |  | ||||||
| #define MIN_WORKER_STACK_SIZE 512000ul | #define MIN_WORKER_STACK_SIZE 512000ul | ||||||
| @ -488,14 +484,7 @@ int main (int argc, char* argv[]) | |||||||
| 	static hcl_bopt_lng_t lopt[] = | 	static hcl_bopt_lng_t lopt[] = | ||||||
| 	{ | 	{ | ||||||
| 		{ ":log",                  'l'  }, | 		{ ":log",                  'l'  }, | ||||||
| 		{ "large-pages",           '\0' }, | 		{ HCL_NULL,                '\0' } | ||||||
| 		{ ":worker-max-count",     '\0' }, |  | ||||||
| 		{ ":worker-stack-size",    '\0' }, |  | ||||||
| 		{ ":worker-idle-timeout",  '\0' }, |  | ||||||
| 	#if defined(HCL_BUILD_DEBUG) |  | ||||||
| 		{ ":debug",       '\0' }, /* NOTE: there is no short option for --debug */ |  | ||||||
| 	#endif |  | ||||||
| 		{ HCL_NULL,       '\0' } |  | ||||||
| 	}; | 	}; | ||||||
| 	static hcl_bopt_t opt = | 	static hcl_bopt_t opt = | ||||||
| 	{ | 	{ | ||||||
| @ -507,14 +496,7 @@ int main (int argc, char* argv[]) | |||||||
| 	client_xtn_t* xtn; | 	client_xtn_t* xtn; | ||||||
| 	hcl_client_prim_t client_prim; | 	hcl_client_prim_t client_prim; | ||||||
| 	int n; | 	int n; | ||||||
|  |  | ||||||
| 	const char* logopt = HCL_NULL; | 	const char* logopt = HCL_NULL; | ||||||
| 	const char* dbgopt = HCL_NULL; |  | ||||||
| 	hcl_oow_t worker_max_count = 0; |  | ||||||
| 	hcl_oow_t worker_stack_size = MIN_ACTOR_HEAP_SIZE; |  | ||||||
| 	hcl_ntime_t worker_idle_timeout = { 0, 0 }; |  | ||||||
| 	int large_pages = 0; |  | ||||||
| 	unsigned int trait; |  | ||||||
|  |  | ||||||
| 	setlocale (LC_ALL, ""); | 	setlocale (LC_ALL, ""); | ||||||
|  |  | ||||||
| @ -535,30 +517,7 @@ int main (int argc, char* argv[]) | |||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
| 			case '\0': | 			case '\0': | ||||||
| 				if (hcl_compbcstr(opt.lngopt, "large-pages") == 0) | 				goto print_usage; | ||||||
| 				{ |  | ||||||
| 					large_pages = 1; |  | ||||||
| 				} |  | ||||||
| 				else if (hcl_compbcstr(opt.lngopt, "worker-max-count") == 0) |  | ||||||
| 				{ |  | ||||||
| 					worker_max_count = strtoul(opt.arg, HCL_NULL, 0); |  | ||||||
| 				} |  | ||||||
| 				else if (hcl_compbcstr(opt.lngopt, "worker-stack-size") == 0) |  | ||||||
| 				{ |  | ||||||
| 					worker_stack_size = strtoul(opt.arg, HCL_NULL, 0); |  | ||||||
| 					if (worker_stack_size <= MIN_WORKER_STACK_SIZE) worker_stack_size = MIN_WORKER_STACK_SIZE; |  | ||||||
| 				} |  | ||||||
| 				else if (hcl_compbcstr(opt.lngopt, "worker-idle-timeout") == 0) |  | ||||||
| 				{ |  | ||||||
| 					worker_idle_timeout.sec = strtoul(opt.arg, HCL_NULL, 0); |  | ||||||
| 				} |  | ||||||
| 			#if defined(HCL_BUILD_DEBUG) |  | ||||||
| 				else if (hcl_compbcstr(opt.lngopt, "debug") == 0) |  | ||||||
| 				{ |  | ||||||
| 					dbgopt = opt.arg; |  | ||||||
| 				} |  | ||||||
| 			#endif |  | ||||||
| 				else goto print_usage; |  | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
| 			case ':': | 			case ':': | ||||||
| @ -578,6 +537,10 @@ int main (int argc, char* argv[]) | |||||||
|  |  | ||||||
| 	memset (&client_prim, 0, HCL_SIZEOF(client_prim)); | 	memset (&client_prim, 0, HCL_SIZEOF(client_prim)); | ||||||
| 	client_prim.log_write = log_write; | 	client_prim.log_write = log_write; | ||||||
|  | 	client_prim.start_reply = start_reply; | ||||||
|  | 	client_prim.feed_attr = feed_attr; | ||||||
|  | 	client_prim.feed_data = feed_data; | ||||||
|  | 	client_prim.end_reply = end_reply; | ||||||
|  |  | ||||||
| 	client = hcl_client_open(&sys_mmgr, HCL_SIZEOF(client_xtn_t), &client_prim, HCL_NULL); | 	client = hcl_client_open(&sys_mmgr, HCL_SIZEOF(client_xtn_t), &client_prim, HCL_NULL); | ||||||
| 	if (!client) | 	if (!client) | ||||||
| @ -600,22 +563,6 @@ int main (int argc, char* argv[]) | |||||||
| 		xtn->logmask = HCL_LOG_ALL_TYPES | HCL_LOG_ERROR | HCL_LOG_FATAL; | 		xtn->logmask = HCL_LOG_ALL_TYPES | HCL_LOG_ERROR | HCL_LOG_FATAL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #if defined(HCL_BUILD_DEBUG) |  | ||||||
| 	if (dbgopt) |  | ||||||
| 	{ |  | ||||||
| 		if (handle_dbgopt(client, dbgopt) <= -1) goto oops; |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	hcl_client_getoption (client, HCL_CLIENT_TRAIT, &trait); |  | ||||||
| 	if (large_pages) trait |= HCL_CLIENT_TRAIT_USE_LARGE_PAGES; |  | ||||||
| 	else trait &= ~HCL_CLIENT_TRAIT_USE_LARGE_PAGES; |  | ||||||
| 	hcl_client_setoption (client, HCL_CLIENT_TRAIT, &trait); |  | ||||||
|  |  | ||||||
| 	hcl_client_setoption (client, HCL_CLIENT_WORKER_MAX_COUNT, &worker_max_count); |  | ||||||
| 	hcl_client_setoption (client, HCL_CLIENT_WORKER_STACK_SIZE, &worker_stack_size); |  | ||||||
| 	hcl_client_setoption (client, HCL_CLIENT_WORKER_IDLE_TIMEOUT, &worker_idle_timeout); |  | ||||||
|  |  | ||||||
| 	g_client = client; | 	g_client = client; | ||||||
| 	set_signal (SIGINT, handle_sigint); | 	set_signal (SIGINT, handle_sigint); | ||||||
| 	set_signal_to_ignore (SIGPIPE); | 	set_signal_to_ignore (SIGPIPE); | ||||||
| @ -627,13 +574,15 @@ int main (int argc, char* argv[]) | |||||||
|  |  | ||||||
| 	if (n <= -1) | 	if (n <= -1) | ||||||
| 	{ | 	{ | ||||||
| 	//	hcl_client_logbfmt (client, HCL_LOG_APP | HCL_LOG_FATAL, "client error[%d] - %js\n", hcl_client_geterrnum(client), hcl_client_geterrmsg(client)); | 		hcl_client_logbfmt (client, HCL_LOG_APP | HCL_LOG_FATAL, "client error[%d] - %js\n", hcl_client_geterrnum(client), hcl_client_geterrmsg(client)); | ||||||
| printf ("hcl client error... = %d\n", hcl_client_geterrnum(client)); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	close (xtn->logfd); | 	if (xtn->logfd >= 0) | ||||||
| 	xtn->logfd = -1; | 	{ | ||||||
| 	xtn->logfd_istty = 0; | 		close (xtn->logfd); | ||||||
|  | 		xtn->logfd = -1; | ||||||
|  | 		xtn->logfd_istty = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	hcl_client_close (client); | 	hcl_client_close (client); | ||||||
| 	return n; | 	return n; | ||||||
|  | |||||||
| @ -667,9 +667,12 @@ int main (int argc, char* argv[]) | |||||||
| 		hcl_server_logbfmt (server, HCL_LOG_APP | HCL_LOG_FATAL, "server error[%d] - %js\n", hcl_server_geterrnum(server), hcl_server_geterrmsg(server)); | 		hcl_server_logbfmt (server, HCL_LOG_APP | HCL_LOG_FATAL, "server error[%d] - %js\n", hcl_server_geterrnum(server), hcl_server_geterrmsg(server)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	close (xtn->logfd); | 	if (xtn->logfd >= 0) | ||||||
| 	xtn->logfd = -1; | 	{ | ||||||
| 	xtn->logfd_istty = 0; | 		close (xtn->logfd); | ||||||
|  | 		xtn->logfd = -1; | ||||||
|  | 		xtn->logfd_istty = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	hcl_server_close (server); | 	hcl_server_close (server); | ||||||
| 	return n; | 	return n; | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user