diff --git a/bin/main-c.c b/bin/main-c.c index 86cfdd8..bc9a7e1 100644 --- a/bin/main-c.c +++ b/bin/main-c.c @@ -779,7 +779,16 @@ int main (int argc, char* argv[]) set_signal (SIGINT, handle_sigint); set_signal_to_ignore (SIGPIPE); +#if 0 + n = hcl_client_connect(client, argv[opt.ind], reuse_addr); + if (n <= -1) + { + fprintf (stderr, "ERROR: %s\n", hcl_client_geterrbmsg(client)); + goto oops; + } +#else n = handle_request(client, argv[opt.ind], argv[opt.ind + 1], reuse_addr, shut_wr_after_req); +#endif set_signal_to_default (SIGINT); set_signal_to_default (SIGPIPE); diff --git a/lib/hcl-x.h b/lib/hcl-x.h index f8eeb01..48e4ea4 100644 --- a/lib/hcl-x.h +++ b/lib/hcl-x.h @@ -306,15 +306,10 @@ HCL_EXPORT void hcl_client_close ( hcl_client_t* client ); -HCL_EXPORT void hcl_client_reset ( - hcl_client_t* client -); - -HCL_EXPORT int hcl_client_feed ( +HCL_EXPORT int hcl_client_connnect ( hcl_client_t* client, - const void* ptr, - hcl_oow_t len, - hcl_oow_t* xlen + const char* ptr, + int reuse_addr ); HCL_EXPORT int hcl_client_setoption ( @@ -360,6 +355,15 @@ HCL_EXPORT const hcl_ooch_t* hcl_client_geterrmsg ( hcl_client_t* client ); +HCL_EXPORT const hcl_bch_t* hcl_client_geterrbmsg ( + hcl_client_t* client +); + +HCL_EXPORT const hcl_uch_t* hcl_client_geterrumsg ( + hcl_client_t* client +); + + HCL_EXPORT void hcl_client_seterrnum ( hcl_client_t* client, hcl_errnum_t errnum @@ -415,6 +419,7 @@ HCL_EXPORT void hcl_client_freemem ( void* ptr ); + /* ---------------------------------------------------------------------- */ HCL_EXPORT hcl_xproto_t* hcl_xproto_open ( diff --git a/lib/x-client.c b/lib/x-client.c index 915ecbc..2d573b3 100644 --- a/lib/x-client.c +++ b/lib/x-client.c @@ -97,6 +97,11 @@ struct hcl_client_t hcl_errnum_t errnum; struct { + #if defined(HCL_OOCH_IS_BCH) + hcl_uch_t xerrmsg[HCL_ERRMSG_CAPA]; + #else + hcl_bch_t xerrmsg[HCL_ERRMSG_CAPA * 2]; + #endif hcl_ooch_t buf[HCL_ERRMSG_CAPA]; hcl_oow_t len; } errmsg; @@ -106,6 +111,9 @@ struct hcl_client_t hcl_bitmask_t trait; hcl_bitmask_t logmask; } cfg; + + int sck; + hcl_xproto_t* proto; }; @@ -127,14 +135,14 @@ hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_p client_hcl_xtn_t* xtn; client = (hcl_client_t*)HCL_MMGR_ALLOC(mmgr, HCL_SIZEOF(*client) + xtnsize); - if (!client) + if (HCL_UNLIKELY(!client)) { if (errnum) *errnum = HCL_ESYSMEM; return HCL_NULL; } hcl = hcl_openstdwithmmgr(mmgr, HCL_SIZEOF(*xtn), errnum); - if (!hcl) + if (HCL_UNLIKELY(!hcl)) { HCL_MMGR_FREE (mmgr, client); return HCL_NULL; @@ -152,6 +160,7 @@ hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_p client->_cmgr = hcl_get_utf8_cmgr(); client->prim = *prim; client->dummy_hcl = hcl; + client->sck = -1; client->cfg.logmask = ~(hcl_bitmask_t)0; @@ -166,6 +175,8 @@ hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_p void hcl_client_close (hcl_client_t* client) { + if (client->proto) hcl_xproto_close (client->proto); + if (client->sck >= 0) close (client->sck); hcl_close (client->dummy_hcl); HCL_MMGR_FREE (client->_mmgr, client); } @@ -249,6 +260,40 @@ const hcl_ooch_t* hcl_client_geterrmsg (hcl_client_t* client) return client->errmsg.buf; } +const hcl_bch_t* hcl_client_geterrbmsg (hcl_client_t* client) +{ +#if defined(HCL_OOCH_IS_BCH) + return (client->errmsg.len <= 0)? hcl_errnum_to_errstr(client->errnum): client->errmsg.buf; +#else + const hcl_ooch_t* msg; + hcl_oow_t wcslen, mbslen; + + msg = (client->errmsg.len <= 0)? hcl_errnum_to_errstr(client->errnum): client->errmsg.buf; + + mbslen = HCL_COUNTOF(client->errmsg.xerrmsg); + hcl_conv_ucstr_to_bcstr_with_cmgr (msg, &wcslen, client->errmsg.xerrmsg, &mbslen, client->_cmgr); + + return client->errmsg.xerrmsg; +#endif +} + +const hcl_uch_t* hcl_client_geterrumsg (hcl_client_t* client) +{ +#if defined(HCL_OOCH_IS_BCH) + const hcl_ooch_t* msg; + hcl_oow_t wcslen, mbslen; + + msg = (client->errmsg.len <= 0)? hcl_errnum_to_errstr(client->errnum): client->errmsg.buf; + + wcslen = HCL_COUNTOF(client->errmsg.xerrmsg); + hcl_conv_bcstr_to_ucstr_with_cmgr (msg, &mbslen, client->errmsg.xerrmsg, &wcslen, client->_cmgr, 1); + + return client->errmsg.xerrmsg; +#else + return (client->errmsg.len == '\0')? hcl_errnum_to_errstr(client->errnum): client->errmsg.buf; +#endif +} + void hcl_client_seterrnum (hcl_client_t* client, hcl_errnum_t errnum) { /*if (client->shuterr) return; */ @@ -334,3 +379,260 @@ void hcl_client_freemem (hcl_client_t* client, void* ptr) { HCL_MMGR_FREE (client->_mmgr, ptr); } + +/* ========================================================================= */ + +struct proto_xtn_t +{ + hcl_client_t* client; +}; +typedef struct proto_xtn_t proto_xtn_t; + +static int handle_packet (hcl_xproto_t* proto, hcl_xpkt_type_t type, const void* data, hcl_oow_t len) +{ + if (type == HCL_XPKT_STDOUT) + { + /*if (len > 0) fwrite (data, 1, len, stdout); */ + if (len > 0) fprintf (stdout, "%.*s", (int)len, data); + } + return 1; +} + +#if 0 + +int hcl_client_process (hcl_client_t* client, const char* ipaddr, const char* script, int reuse_addr, int shut_wr_after_req) +{ + hcl_oow_t used, avail; + int x; + hcl_bch_t buf[256]; + ssize_t n; + const char* scptr; + const char* sccur; + hcl_xproto_t* proto = HCL_NULL; + + proto_xtn_t* proto_xtn; + hcl_xproto_cb_t proto_cb; + + scptr = sccur = script; + while (1) + { + struct pollfd pfd; + + pfd.fd = sck; + pfd.events = POLLIN; + if (*sccur != '\0') pfd.events |= POLLOUT; + pfd.revents = 0; + + n = poll(&pfd, 1, 1000); + if (n <= -1) + { + fprintf (stderr, "poll error on %d - %s\n", sck, strerror(n)); + goto oops; + } + + if (n == 0) + { + /* TODO: proper timeout handling */ + continue; + } + + if (pfd.revents & POLLERR) + { + fprintf (stderr, "error condition detected on %d\n", sck); + goto oops; + } + + if (pfd.revents & POLLOUT) + { + hcl_xpkt_hdr_t hdr; + struct iovec iov[2]; + hcl_uint16_t seglen; + + while (*sccur != '\0' && sccur - scptr < HCL_XPKT_MAX_PLD_LEN) sccur++; + + seglen = sccur - scptr; + + hdr.id = 1; /* TODO: */ + hdr.type = HCL_XPKT_CODE | (((seglen >> 8) & 0x0F) << 4); + hdr.len = seglen & 0xFF; + + iov[0].iov_base = &hdr; + iov[0].iov_len = HCL_SIZEOF(hdr); + iov[1].iov_base = scptr; + iov[1].iov_len = seglen; + + hcl_sys_send_iov (sck, iov, 2); /* TODO: error check */ + + scptr = sccur; + + if (*sccur == '\0') + { + hdr.id = 1; /* TODO: */ + hdr.type = HCL_XPKT_EXECUTE; + hdr.len = 0; + + iov[0].iov_base = &hdr; + iov[0].iov_len = HCL_SIZEOF(hdr); + hcl_sys_send_iov (sck, iov, 1); + + if (shut_wr_after_req) + { + shutdown (sck, SHUT_WR); + } + else + { + hdr.type = HCL_XPKT_DISCONNECT; + hdr.id = 1; /* TODO: */ + hdr.len = 0; + + iov[0].iov_base = &hdr; + iov[0].iov_len = HCL_SIZEOF(hdr); + hcl_sys_send_iov (sck, iov, 1); + } + } + } + + if (pfd.revents & POLLIN) + { + hcl_oow_t bcap; + hcl_uint8_t* bptr; + + bptr = hcl_xproto_getbuf(proto, &bcap);; + x = recv(sck, bptr, bcap, 0); + if (x <= -1) + { + if (errno == EINTR) goto carry_on; /* didn't read read */ + /*hcl_seterrwithsyserr (hcl, 0, errno); */ + /* TODO: error info set... */ + return -1; + } + if (x == 0) hcl_xproto_seteof(proto, 1); + hcl_xproto_advbuf (proto, x); + } + + + carry_on: + while (hcl_xproto_ready(proto)) + { + if ((n = hcl_xproto_process(proto)) <= -1) + { + /* TODO: proper error message */ + return -1; + } + if (n == 0) + { + /* TODO: chceck if there is remaining data in the buffer...?? */ + printf ("NO MORE DATA. EXITING...\n"); + goto done; + } + } + + if (hcl_xproto_geteof(proto)) break; + } +done: + +/* TODO: we can check if the buffer has all been consumed. if not, there is trailing garbage.. */ + /*{ + struct linger linger; + linger.l_onoff = 1; + linger.l_linger = 0; + setsockopt (sck, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger)); + }*/ + + hcl_xproto_close (proto); + close (sck); + return 0; + +oops: + if (proto) hcl_xproto_close (proto); + if (sck >= 0) close (sck); + return -1; +} +#endif + +int hcl_client_connect (hcl_client_t* client, const char* ipaddr, int reuse_addr) +{ + hcl_sckaddr_t sckaddr; + hcl_scklen_t scklen; + int sckfam; + int sck = -1; + hcl_xproto_t* proto = HCL_NULL; + + proto_xtn_t* proto_xtn; + hcl_xproto_cb_t proto_cb; + + sckfam = hcl_bchars_to_sckaddr(ipaddr, strlen(ipaddr), &sckaddr, &scklen); + if (sckfam <= -1) + { + hcl_client_seterrbfmt (client, HCL_EINVAL, "cannot convert ip address - %hs", ipaddr); + goto oops; + } + + sck = socket(sckfam, SOCK_STREAM, 0); + if (sck <= -1) + { + hcl_client_seterrbfmt (client, HCL_ESYSERR, "cannot create socket - %hs", strerror(errno)); + goto oops; + } + + if (reuse_addr) + { + if (sckfam == AF_INET) + { + struct sockaddr_in anyaddr; + int opt = 1; + setsockopt(sck, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); + memset (&anyaddr, 0, HCL_SIZEOF(anyaddr)); + anyaddr.sin_family = sckfam; + if (bind(sck, (struct sockaddr *)&anyaddr, scklen) <= -1) + { + hcl_client_seterrbfmt (client, HCL_ESYSERR, + "cannot bind socket %d - %hs", sck, strerror(errno)); + goto oops; + } + } + else if (sckfam == AF_INET6) + { + struct sockaddr_in6 anyaddr; + int opt = 1; + setsockopt(sck, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); + memset (&anyaddr, 0, HCL_SIZEOF(anyaddr)); + anyaddr.sin6_family = sckfam; + if (bind(sck, (struct sockaddr *)&anyaddr, scklen) <= -1) + { + hcl_client_seterrbfmt (client, HCL_ESYSERR, + "cannot bind socket %d - %hs", sck, strerror(errno)); + goto oops; + } + } + } + + if (connect(sck, (struct sockaddr*)&sckaddr, scklen) <= -1) + { + hcl_client_seterrbfmt (client, HCL_ESYSERR, + "cannot connect socket %d to %hs - %hs", sck, ipaddr, strerror(errno)); + goto oops; + } + + + memset (&proto, 0, HCL_SIZEOF(proto_cb)); + proto_cb.on_packet = handle_packet; + + proto = hcl_xproto_open(hcl_client_getmmgr(client), &proto_cb, HCL_SIZEOF(*proto_xtn)); + if (HCL_UNLIKELY(!proto)) + { + fprintf (stderr, "cannot open protocol to %s\n", ipaddr); + goto oops; + } + proto_xtn = hcl_xproto_getxtn(proto); + proto_xtn->client = client; + + client->sck = sck; + client->proto = proto; + return 0; + +oops: + if (proto) hcl_xproto_close (proto); + if (sck >= 0) close (sck); + return -1; +}