added reply handler

This commit is contained in:
hyung-hwan 2018-03-21 10:38:10 +00:00
parent 69e50af80f
commit f675835a11
6 changed files with 599 additions and 334 deletions

View File

@ -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,6 +151,12 @@ 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
{ {
@ -160,12 +169,59 @@ struct hcl_client_t
{ {
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)
{ {
hcl_oow_t i; return hcl_compoocharsbcstr(client->rep.tok.ptr, client->rep.tok.len, str) == 0;
printf ("{");
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) static HCL_INLINE int is_token_integer (hcl_client_t* client, hcl_oow_t* value)
{
hcl_oow_t i;
hcl_oow_t v = 0;
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 */
} }
@ -380,13 +443,19 @@ print_tok (client);
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,59 +495,193 @@ 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;
} }
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; 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)
{
/* the data is treated as raw octets by this client */
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 else
{ {
while (ptr < end) 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,52 +905,31 @@ 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)
{ {
HCL_MMGR_FREE (client->mmgr, 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);
}
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)
{ {
@ -694,28 +937,10 @@ int hcl_client_setoption (hcl_client_t* client, hcl_client_option_t id, const vo
{ {
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;
} }

View File

@ -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

View File

@ -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,
@ -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;
} }
} }

View File

@ -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;

View File

@ -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, ',');
len = cm? (cm - flt): hcl_countbcstr(flt);
if (hcl_compbcharsbcstr(flt, len, "gc") == 0) trait |= HCL_CLIENT_TRAIT_DEBUG_GC;
else if (hcl_compbcharsbcstr(flt, len, "bigint") == 0) trait |= HCL_CLIENT_TRAIT_DEBUG_BIGINT;
else else
{ {
fprintf (stderr, "ERROR: unknown debug option value - %.*s\n", (int)len, flt); printf ("GOT LONG_FORM RESPONSE[%d]\n", (int)type);
return -1;
} }
} }
while (cm);
hcl_client_setoption (client, HCL_CLIENT_TRAIT, &trait); static void end_reply (hcl_client_t* client, hcl_client_end_reply_state_t state)
return 0; {
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");
}
} }
#endif
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,13 +484,6 @@ 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' },
{ ":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' } { 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));
} }
if (xtn->logfd >= 0)
{
close (xtn->logfd); close (xtn->logfd);
xtn->logfd = -1; xtn->logfd = -1;
xtn->logfd_istty = 0; xtn->logfd_istty = 0;
}
hcl_client_close (client); hcl_client_close (client);
return n; return n;

View File

@ -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));
} }
if (xtn->logfd >= 0)
{
close (xtn->logfd); close (xtn->logfd);
xtn->logfd = -1; xtn->logfd = -1;
xtn->logfd_istty = 0; xtn->logfd_istty = 0;
}
hcl_server_close (server); hcl_server_close (server);
return n; return n;