From 0eb177db961fb990d1d39fc426a0c6d64ef1b065 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sat, 28 Jul 2012 03:51:07 +0000 Subject: [PATCH] added a little timeout handling code to nwio --- qse/include/qse/awk/std.h | 2 +- qse/include/qse/cmn/nwio.h | 37 ++++++---- qse/lib/awk/std.c | 92 ++++++++++++++++--------- qse/lib/cmn/nwio.c | 134 +++++++++++++++++++++++++++++++++++-- 4 files changed, 214 insertions(+), 51 deletions(-) diff --git a/qse/include/qse/awk/std.h b/qse/include/qse/awk/std.h index 56302f38..e42e03b6 100644 --- a/qse/include/qse/awk/std.h +++ b/qse/include/qse/awk/std.h @@ -182,7 +182,7 @@ void* qse_awk_rtx_getxtnstd ( * The qse_awk_rtx_getcmgrstd() function gets the current character * manager associated with a particular I/O target indicated by the name * @a ioname if #QSE_CHAR_IS_WCHAR is defined. It always returns #QSE_NULL - * if #QSE_CHAR_IS_MCHAR. + * if #QSE_CHAR_IS_MCHAR is defined. */ qse_cmgr_t* qse_awk_rtx_getcmgrstd ( qse_awk_rtx_t* rtx, diff --git a/qse/include/qse/cmn/nwio.h b/qse/include/qse/cmn/nwio.h index 31776a2f..f7f78f13 100644 --- a/qse/include/qse/cmn/nwio.h +++ b/qse/include/qse/cmn/nwio.h @@ -59,6 +59,7 @@ enum qse_nwio_errnum_t QSE_NWIO_ENOENT, /**< no such file */ QSE_NWIO_EEXIST, /**< already exist */ QSE_NWIO_EINTR, /**< interrupted */ + QSE_NWIO_ETMOUT, /**< timed out */ QSE_NWIO_EPIPE, /**< broken pipe */ QSE_NWIO_ECONN, /**< connection refused */ QSE_NWIO_EILSEQ, /**< illegal sequence */ @@ -71,6 +72,13 @@ enum qse_nwio_errnum_t }; typedef enum qse_nwio_errnum_t qse_nwio_errnum_t; +struct qse_nwio_tmout_t +{ + int r, w, c, a; +}; + +typedef struct qse_nwio_tmout_t qse_nwio_tmout_t; + #if defined(_WIN32) typedef qse_intptr_t qse_nwio_hnd_t; #elif defined(__OS2__) @@ -89,11 +97,12 @@ typedef struct qse_nwio_t qse_nwio_t; struct qse_nwio_t { QSE_DEFINE_COMMON_FIELDS (nwio) - int flags; - qse_nwio_errnum_t errnum; - qse_nwio_hnd_t handle; - qse_tio_t* tio; - int status; + int flags; + qse_nwio_errnum_t errnum; + qse_nwio_tmout_t tmout; + qse_nwio_hnd_t handle; + qse_tio_t* tio; + int status; }; #define QSE_NWIO_HANDLE(nwio) ((nwio)->handle) @@ -113,10 +122,11 @@ QSE_DEFINE_COMMON_FUNCTIONS (nwio) * as a pointer to qse_nwio_hnd_t. */ qse_nwio_t* qse_nwio_open ( - qse_mmgr_t* mmgr, - qse_size_t ext, - const qse_nwad_t* nwad, - int flags + qse_mmgr_t* mmgr, + qse_size_t ext, + const qse_nwad_t* nwad, + int flags, + const qse_nwio_tmout_t* tmout ); /** @@ -130,10 +140,11 @@ void qse_nwio_close ( * The qse_nwio_close() function opens a file into @a nwio. */ int qse_nwio_init ( - qse_nwio_t* nwio, - qse_mmgr_t* mmgr, - const qse_nwad_t* nwad, - int flags + qse_nwio_t* nwio, + qse_mmgr_t* mmgr, + const qse_nwad_t* nwad, + int flags, + const qse_nwio_tmout_t* tmout ); /** diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index 3a53e87b..951b877d 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -126,9 +126,11 @@ typedef struct ioattr_t { qse_cmgr_t* cmgr; qse_char_t cmgr_name[64]; /* i assume that the cmgr name never exceeds this length */ - qse_long_t timeout[3]; + qse_long_t tmout[4]; } ioattr_t; +static ioattr_t* get_ioattr (qse_htb_t* tab, const qse_char_t* ptr, qse_size_t len); + static qse_flt_t custom_awk_pow (qse_awk_t* awk, qse_flt_t x, qse_flt_t y) { #if defined(HAVE_POWL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE) @@ -804,14 +806,16 @@ int qse_awk_parsestd ( /*** RTX_OPENSTD ***/ static qse_ssize_t nwio_handler_open ( - qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod, int flags, qse_nwad_t* nwad) + qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod, int flags, + qse_nwad_t* nwad, qse_nwio_tmout_t* tmout) { qse_nwio_t* handle; handle = qse_nwio_open ( qse_awk_rtx_getmmgr(rtx), 0, nwad, flags | QSE_NWIO_TEXT | QSE_NWIO_IGNOREMBWCERR | - QSE_NWIO_REUSEADDR | QSE_NWIO_READNORETRY | QSE_NWIO_WRITENORETRY + QSE_NWIO_REUSEADDR | QSE_NWIO_READNORETRY | QSE_NWIO_WRITENORETRY, + tmout ); if (handle == QSE_NULL) return -1; @@ -1031,9 +1035,30 @@ static qse_ssize_t awk_rio_pipe ( if (riod->mode != QSE_AWK_RIO_PIPE_RW || parse_rwpipe_uri (riod->name, &flags, &nwad) <= -1) + { return pio_handler_open (rtx, riod); + } else - return nwio_handler_open (rtx, riod, flags, &nwad); + { + qse_nwio_tmout_t tmout_buf; + qse_nwio_tmout_t* tmout = QSE_NULL; + ioattr_t* ioattr; + rxtn_t* rxtn; + + rxtn = (rxtn_t*) QSE_XTN (rtx); + + ioattr = get_ioattr (&rxtn->cmgrtab, riod->name, qse_strlen(riod->name)); + if (ioattr) + { + tmout = &tmout_buf; + tmout->r = ioattr->tmout[0]; + tmout->w = ioattr->tmout[1]; + tmout->c = ioattr->tmout[2]; + tmout->a = ioattr->tmout[3]; + } + + return nwio_handler_open (rtx, riod, flags, &nwad, tmout); + } } else if (riod->handle2) return nwio_handler_rest (rtx, cmd, riod, data, size); @@ -1715,32 +1740,12 @@ static int fnc_time (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm) return 0; } -qse_cmgr_t* qse_awk_rtx_getcmgrstd ( - qse_awk_rtx_t* rtx, const qse_char_t* ioname) -{ -#if defined(QSE_CHAR_IS_WCHAR) - rxtn_t* rxtn; - qse_htb_pair_t* pair; - ioattr_t* ioattr; - - rxtn = (rxtn_t*) QSE_XTN (rtx); - QSE_ASSERT (rxtn->cmgrtab_inited == 1); - - pair = qse_htb_search (&rxtn->cmgrtab, ioname, qse_strlen(ioname)); - if (pair) - { - ioattr = (ioattr_t*)QSE_HTB_VPTR(pair); - return ioattr->cmgr; - } -#endif - return QSE_NULL; -} - static int timeout_code (const qse_char_t* name) { if (qse_strcmp (name, QSE_T("rtimeout")) == 0) return 0; if (qse_strcmp (name, QSE_T("wtimeout")) == 0) return 1; if (qse_strcmp (name, QSE_T("ctimeout")) == 0) return 2; + if (qse_strcmp (name, QSE_T("atimeout")) == 0) return 3; return -1; } @@ -1748,13 +1753,24 @@ static QSE_INLINE void init_ioattr (ioattr_t* ioattr) { int i; QSE_MEMSET (ioattr, 0, QSE_SIZEOF(*ioattr)); - for (i = 0; i < QSE_COUNTOF(ioattr->timeout); i++) + for (i = 0; i < QSE_COUNTOF(ioattr->tmout); i++) { /* a negative number for no timeout */ - ioattr->timeout[i] = -999; + ioattr->tmout[i] = -999; } } +static ioattr_t* get_ioattr ( + qse_htb_t* tab, const qse_char_t* ptr, qse_size_t len) +{ + qse_htb_pair_t* pair; + + pair = qse_htb_search (tab, ptr, len); + if (pair) return QSE_HTB_VPTR(pair); + + return QSE_NULL; +} + static qse_htb_pair_t* find_or_make_ioattr ( qse_awk_rtx_t* rtx, qse_htb_t* tab, const qse_char_t* ptr, qse_size_t len) { @@ -1767,7 +1783,7 @@ static qse_htb_pair_t* find_or_make_ioattr ( init_ioattr (&ioattr); - pair = qse_htb_insert (tab, ptr, len, &ioattr, QSE_SIZEOF(ioattr)); + pair = qse_htb_insert (tab, (void*)ptr, len, (void*)&ioattr, QSE_SIZEOF(ioattr)); if (pair == QSE_NULL) { qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL); @@ -1841,7 +1857,7 @@ static int fnc_setioattr (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm) } ioattr = QSE_HTB_VPTR(pair); - ioattr->timeout[tmout] = l; + ioattr->tmout[tmout] = l; } #if defined(QSE_CHAR_IS_WCHAR) else if (qse_strcmp (ptr[1], QSE_T("codepage")) == 0) @@ -1955,7 +1971,7 @@ static int fnc_getioattr (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm) if ((tmout = timeout_code (ptr[1])) >= 0) { - rv = qse_awk_rtx_makeintval (rtx, ioattr->timeout[tmout]); + rv = qse_awk_rtx_makeintval (rtx, ioattr->tmout[tmout]); if (rv == QSE_NULL) { ret = -1; @@ -1999,6 +2015,22 @@ done: return ret; } +qse_cmgr_t* qse_awk_rtx_getcmgrstd ( + qse_awk_rtx_t* rtx, const qse_char_t* ioname) +{ +#if defined(QSE_CHAR_IS_WCHAR) + rxtn_t* rxtn; + ioattr_t* ioattr; + + rxtn = (rxtn_t*) QSE_XTN (rtx); + QSE_ASSERT (rxtn->cmgrtab_inited == 1); + + ioattr = get_ioattr (&rxtn->cmgrtab, ioname, qse_strlen(ioname)); + if (ioattr) return ioattr->cmgr; +#endif + return QSE_NULL; +} + #define ADDFNC(awk,name,min,max,fnc,valid) \ if (qse_awk_addfnc (\ (awk), (name), qse_strlen(name), \ diff --git a/qse/lib/cmn/nwio.c b/qse/lib/cmn/nwio.c index b09e252c..d27b0000 100644 --- a/qse/lib/cmn/nwio.c +++ b/qse/lib/cmn/nwio.c @@ -19,6 +19,7 @@ */ #include +#include #include "mem.h" #if defined(_WIN32) @@ -37,6 +38,7 @@ # include "syscall.h" # include # include +# include #endif QSE_IMPLEMENT_COMMON_FUNCTIONS (nwio) @@ -249,14 +251,15 @@ static qse_nwio_errnum_t tio_errnum_to_nwio_errnum (qse_tio_t* tio) } qse_nwio_t* qse_nwio_open ( - qse_mmgr_t* mmgr, qse_size_t xtnsize, const qse_nwad_t* nwad, int flags) + qse_mmgr_t* mmgr, qse_size_t xtnsize, const qse_nwad_t* nwad, + int flags, const qse_nwio_tmout_t* tmout) { qse_nwio_t* nwio; nwio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_nwio_t) + xtnsize); if (nwio == QSE_NULL) return QSE_NULL; - if (qse_nwio_init (nwio, mmgr, nwad, flags) <= -1) + if (qse_nwio_init (nwio, mmgr, nwad, flags, tmout) <= -1) { QSE_MMGR_FREE (mmgr, nwio); return QSE_NULL; @@ -272,7 +275,8 @@ void qse_nwio_close (qse_nwio_t* nwio) } int qse_nwio_init ( - qse_nwio_t* nwio, qse_mmgr_t* mmgr, const qse_nwad_t* nwad, int flags) + qse_nwio_t* nwio, qse_mmgr_t* mmgr, const qse_nwad_t* nwad, + int flags, const qse_nwio_tmout_t* tmout) { #if defined(AF_INET) union sockaddr_t addr; @@ -289,7 +293,15 @@ int qse_nwio_init ( nwio->mmgr = mmgr; nwio->flags = flags; nwio->errnum = QSE_NWIO_ENOERR; - + if (tmout) nwio->tmout = *tmout; + else + { + nwio->tmout.r = -1; + nwio->tmout.w = -1; + nwio->tmout.c = -1; + nwio->tmout.a = -1; + } + #if defined(AF_INET) tmp = nwad_to_sockaddr (nwad, &family, &addr); if (tmp <= -1) @@ -504,10 +516,82 @@ int qse_nwio_init ( } else { - if (connect (nwio->handle, (struct sockaddr*)&addr, addrlen) <= -1) + int orgfl, xret; + + if (nwio->tmout.c >= 0 && (flags & QSE_NWIO_TCP)) { - nwio->errnum = syserr_to_errnum (errno); - goto oops; + orgfl = fcntl (nwio->handle, F_GETFL, 0); + if (orgfl <= -1 || + fcntl (nwio->handle, F_SETFL, orgfl | O_NONBLOCK) <= -1) + { + nwio->errnum = syserr_to_errnum (errno); + goto oops; + } + } + + xret = connect (nwio->handle, (struct sockaddr*)&addr, addrlen); + + if (nwio->tmout.c >= 0 && (flags & QSE_NWIO_TCP)) + { + fd_set wfds; + struct timeval tv; + + if ((xret <= -1 && errno != EINPROGRESS) || + fcntl (nwio->handle, F_SETFL, orgfl) <= -1) + { + nwio->errnum = syserr_to_errnum (errno); + goto oops; + } + + FD_ZERO (&wfds); + FD_SET (nwio->handle, &wfds); + tv.tv_sec = nwio->tmout.c / QSE_MSECS_PER_SEC; + tv.tv_usec = (nwio->tmout.c % QSE_MSECS_PER_SEC) * + QSE_USECS_PER_MSEC; + + xret = select (nwio->handle + 1, + QSE_NULL, &wfds, QSE_NULL, &tv); + if (xret <= -1) + { + nwio->errnum = syserr_to_errnum (errno); + goto oops; + } + else if (xret == 0) + { + nwio->errnum = QSE_NWIO_ETMOUT; + goto oops; + } + else if (!FD_ISSET (nwio->handle, &wfds)) + { + nwio->errnum = QSE_NWIO_ECONN; + goto oops; + } + else + { + #if defined(HAVE_SOCKLEN_T) + socklen_t xlen; + #else + int xlen; + #endif + if (getsockopt (nwio->handle, SOL_SOCKET, SO_ERROR, (char*)&xret, &xlen) <= -1) + { + nwio->errnum = syserr_to_errnum (errno); + goto oops; + } + else if (xret != 0) + { + nwio->errnum = syserr_to_errnum (xret); + goto oops; + } + } + } + else + { + if (xret <= -1) + { + nwio->errnum = syserr_to_errnum (errno); + goto oops; + } } } #endif @@ -640,6 +724,33 @@ void qse_nwio_purge (qse_nwio_t* nwio) if (nwio->tio) qse_tio_purge (nwio->tio); } +static int wait_for_data (qse_nwio_t* nwio, int tmout, int what) +{ + int xret; + fd_set fds[2]; + struct timeval tv; + + FD_ZERO (&fds[0]); + FD_ZERO (&fds[1]); + FD_SET (nwio->handle, &fds[what]); + tv.tv_sec = tmout / QSE_MSECS_PER_SEC; + tv.tv_usec = (tmout % QSE_MSECS_PER_SEC) * + QSE_USECS_PER_MSEC; + + xret = select (nwio->handle + 1, &fds[0], &fds[1], QSE_NULL, &tv); + if (xret <= -1) + { + nwio->errnum = syserr_to_errnum (errno); + return -1; + } + else if (xret == 0) + { + nwio->errnum = QSE_NWIO_ETMOUT; + return -1; + } + + return 0; +} /* ---------------------------------------------------------- */ static qse_ssize_t nwio_read (qse_nwio_t* nwio, void* buf, qse_size_t size) @@ -749,6 +860,10 @@ reread: #endif addrlen = QSE_SIZEOF(addr); + /* it's similar to accept for tcp. + * since i'm expecting the first sender and call + * connect() to it below. + * TODO: do i have apply tmout.a instead of tmout.r??? */ n = recvfrom ( nwio->handle, buf, size, 0, (struct sockaddr*)&addr, &addrlen); @@ -779,6 +894,11 @@ reread: } else { + if (nwio->tmout.r >= 0) + { + if (wait_for_data (nwio, nwio->tmout.r, 0) <= -1) return -1; + } + n = recv (nwio->handle, buf, size, 0); if (n <= -1) {