From 951fce6496397a6d8c11e15ab5b60b46abc43467 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Tue, 9 Jan 2007 13:56:47 +0000 Subject: [PATCH] Implemented Generic select hook for ZOOM (bug #803). This is achieved with the following new functions: ZOOM_process_event, ZOOM_connection_get_{socket,mask,timeout}, ZOOM_connection_fire_event_{timeout,socket}. The existing blocking event handler, ZOOM_event, is a wrapper for the + blocking ZOOM_event_sys_{poll,select}. --- NEWS | 8 ++ debian/rules | 2 +- include/yaz/zoom.h | 114 ++++++++++++++-- src/Makefile.am | 5 +- src/zoom-c.c | 371 +++++++++++++++------------------------------------- src/zoom-p.h | 7 +- src/zoom-socket.c | 219 +++++++++++++++++++++++++++++++ win/makefile | 3 +- 8 files changed, 450 insertions(+), 279 deletions(-) create mode 100644 src/zoom-socket.c diff --git a/NEWS b/NEWS index 308869c..908ffd8 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,11 @@ +Implemented Generic select hook for ZOOM (bug #803). This is achieved with +the following new functions: + ZOOM_process_event, + ZOOM_connection_get_{socket,mask,timeout}, + ZOOM_connection_fire_event_{timeout,socket}. +The existing blocking event handler, ZOOM_event, is a wrapper for the ++ blocking ZOOM_event_sys_{poll,select}. + Implemented function ccl_xml_config which parses XML version of CCL configuration (bug #798). diff --git a/debian/rules b/debian/rules index e2f3ad1..a50b062 100755 --- a/debian/rules +++ b/debian/rules @@ -98,7 +98,7 @@ binary-arch: build install dh_fixperms # dh_perl # dh_python - dh_makeshlibs -V 'libyaz (>= 2.1.44)' + dh_makeshlibs -V 'libyaz (>= 2.1.45)' dh_installdeb dh_shlibdeps -l debian/libyaz/usr/lib dh_gencontrol diff --git a/include/yaz/zoom.h b/include/yaz/zoom.h index 7909b4d..1128239 100644 --- a/include/yaz/zoom.h +++ b/include/yaz/zoom.h @@ -24,7 +24,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* $Id: zoom.h,v 1.41 2007-01-03 08:42:14 adam Exp $ */ +/* $Id: zoom.h,v 1.42 2007-01-09 13:56:48 adam Exp $ */ /** * \file zoom.h @@ -339,17 +339,115 @@ ZOOM_options_get_int (ZOOM_options opt, const char *name, int defa); ZOOM_API(void) ZOOM_options_set_int(ZOOM_options opt, const char *name, int value); -/* ----------------------------------------------------------- */ -/* events */ -/* poll for events on a number of connections. Returns positive - integer if event occurred ; zero if none occurred and no more - events are pending. The positive integer specifies the - connection for which the event occurred. */ +/** \brief select/poll socket mask: read */ +#define ZOOM_SELECT_READ 1 +/** \brief select/poll socket mask: write */ +#define ZOOM_SELECT_WRITE 2 +/** \brief select/poll socket mask: except */ +#define ZOOM_SELECT_EXCEPT 4 + +/** \brief wait for events on connection(s) (BLOCKING) + \param no number of connections (size of cs) + \param cs connection array + \retval 0 no event was fired + \retval >0 event was fired for connection at (retval-1) + + blocking poll for events on a number of connections. Returns positive + integer if event occurred ; zero if none occurred and no more + events are pending. The positive integer specifies the + connection for which the event occurred. +*/ ZOOM_API(int) ZOOM_event (int no, ZOOM_connection *cs); + +/** \brief determines if connection is idle (no active or pending work) + \param c connection + \retval 1 is idle + \retval 0 is non-idle (active) +*/ +ZOOM_API(int) +ZOOM_connection_is_idle(ZOOM_connection c); + + +/** \brief processes one event for one of connections given + \param no number of connections (size of cs) + \param cs connection array + \retval 0 no event was processed + \retval >0 event was processed for connection at (retval-1) + + This function attemps to deal with outstandings events in + a non-blocking fashion. If no events was processed (return value of 0), + then the system should attempt to deal with sockets in blocking mode + using socket select/poll which means calling the following functions: + ZOOM_connection_get_socket, ZOOM_connection_get_mask, + ZOOM_connection_get_timeout. +*/ +ZOOM_API(int) + ZOOM_process_event(int no, ZOOM_connection *cs); + + +/** \brief get socket fd for ZOOM connection + \param c connection + \retval -1 no socket assigned for connection + \retval >=0 socket for connection + + Use this function when preparing for socket/poll and + in conjunction with ZOOM_connection_get_mask. +*/ +ZOOM_API(int) + ZOOM_connection_get_socket(ZOOM_connection c); + + +/** \brief get socket mask for connection + \param c connection + \returns mask for connection (possibly 0) + + Use this function when preparing for socket select/poll and + in conjunction with ZOOM_connection_get_socket. +*/ ZOOM_API(int) -ZOOM_connection_is_idle(ZOOM_connection cs); + ZOOM_connection_get_mask(ZOOM_connection c); + + +/** \brief set socket mask for connection (DO NOT call outside zoom) */ +ZOOM_API(int) + ZOOM_connection_set_mask(ZOOM_connection c, int mask); + + +/** \brief get timeout in seconds for ZOOM connection + \param c connection + \returns timeout value in seconds + + Use this function when preparing for socket/poll and + in conjunction with ZOOM_connection_get_socket. +*/ +ZOOM_API(int) + ZOOM_connection_get_timeout(ZOOM_connection c); + + +/** \brief fire socket event timeout + \param c connection + \retval 0 event was fired OK + \retval -1 event was not fired + + Call this function when a timeout occurs - for example in the + case of select(2) returning 0. +*/ +ZOOM_API(int) + ZOOM_connection_fire_event_timeout(ZOOM_connection c); + + +/** \brief fire socket event activity (read,write,except) + \param c connection + \param mask or'ed mask of ZOOM_SELECT_.. values + \retval 0 event was fired OK + \retval -1 event was not fired +*/ +ZOOM_API(int) + ZOOM_connection_fire_event_socket(ZOOM_connection c, int mask); + + ZOOM_END_CDECL /* diff --git a/src/Makefile.am b/src/Makefile.am index 692de94..3e8c349 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ ## This file is part of the YAZ toolkit. ## Copyright (C) 1995-2007, Index Data, All rights reserved. -## $Id: Makefile.am,v 1.49 2007-01-08 10:48:07 adam Exp $ +## $Id: Makefile.am,v 1.50 2007-01-09 13:56:48 adam Exp $ YAZ_VERSION_INFO=2:1:0 @@ -71,7 +71,8 @@ libyaz_la_SOURCES=version.c options.c log.c \ zget.c yaz-ccl.c diag-entry.c diag-entry.h diagbib1.c diagsrw.c \ diagsru_update.c logrpn.c \ otherinfo.c pquery.c sortspec.c z3950oid.c charneg.c initopt.c \ - zoom-c.c zoom-opt.c zoom-p.h grs1disp.c zgdu.c soap.c srw.c srwutil.c \ + zoom-c.c zoom-socket.c zoom-opt.c zoom-p.h \ + grs1disp.c zgdu.c soap.c srw.c srwutil.c \ opacdisp.c cclfind.c ccltoken.c cclerrms.c cclqual.c cclptree.c \ cclqfile.c cclstr.c cclxmlconfig.c \ cql.y cqlstdio.c cqltransform.c cqlutil.c xcqlutil.c cqlstring.c \ diff --git a/src/zoom-c.c b/src/zoom-c.c index 2a9d433..1888229 100644 --- a/src/zoom-c.c +++ b/src/zoom-c.c @@ -2,7 +2,7 @@ * Copyright (C) 1995-2007, Index Data ApS * See the file LICENSE for details. * - * $Id: zoom-c.c,v 1.104 2007-01-03 08:42:15 adam Exp $ + * $Id: zoom-c.c,v 1.105 2007-01-09 13:56:48 adam Exp $ */ /** * \file zoom-c.c @@ -27,25 +27,6 @@ #include #include -#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_SYS_TIME_H -#include -#endif -#if HAVE_SYS_POLL_H -#include -#endif -#if HAVE_SYS_SELECT_H -#include -#endif -#ifdef WIN32 -#if FD_SETSIZE < 512 -#define FD_SETSIZE 512 -#endif -#include -#endif - static int log_api = 0; static int log_details = 0; @@ -318,7 +299,7 @@ ZOOM_API(ZOOM_connection) c->proto = PROTO_Z3950; c->cs = 0; - c->mask = 0; + ZOOM_connection_set_mask(c, 0); c->reconnect_ok = 0; c->state = STATE_IDLE; c->addinfo = 0; @@ -960,7 +941,7 @@ static void do_close(ZOOM_connection c) if (c->cs) cs_close(c->cs); c->cs = 0; - c->mask = 0; + ZOOM_connection_set_mask(c, 0); c->state = STATE_IDLE; } @@ -1115,7 +1096,7 @@ static zoom_ret do_connect(ZOOM_connection c) /* no init request for SRW .. */ assert(c->tasks->which == ZOOM_TASK_CONNECT); ZOOM_connection_remove_task(c); - c->mask = 0; + ZOOM_connection_set_mask(c, 0); ZOOM_connection_exec_task(c); } c->state = STATE_ESTABLISHED; @@ -1123,12 +1104,13 @@ static zoom_ret do_connect(ZOOM_connection c) } else if (ret > 0) { - c->state = STATE_CONNECTING; - c->mask = ZOOM_SELECT_EXCEPT; + int mask = ZOOM_SELECT_EXCEPT; if (c->cs->io_pending & CS_WANT_WRITE) - c->mask += ZOOM_SELECT_WRITE; + mask += ZOOM_SELECT_WRITE; if (c->cs->io_pending & CS_WANT_READ) - c->mask += ZOOM_SELECT_READ; + mask += ZOOM_SELECT_READ; + ZOOM_connection_set_mask(c, mask); + c->state = STATE_CONNECTING; return zoom_pending; } } @@ -1137,20 +1119,6 @@ static zoom_ret do_connect(ZOOM_connection c) return zoom_complete; } -int z3950_connection_socket(ZOOM_connection c) -{ - if (c->cs) - return cs_fileno(c->cs); - return -1; -} - -int z3950_connection_mask(ZOOM_connection c) -{ - if (c->cs) - return c->mask; - return 0; -} - static void otherInfo_attach(ZOOM_connection c, Z_APDU *a, ODR out) { int i; @@ -1276,7 +1244,7 @@ static zoom_ret ZOOM_connection_send_init(ZOOM_connection c) odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName)); - version = odr_strdup(c->odr_out, "$Revision: 1.104 $"); + version = odr_strdup(c->odr_out, "$Revision: 1.105 $"); if (strlen(version) > 10) /* check for unexpanded CVS strings */ version[strlen(version)-2] = '\0'; ireq->implementationVersion = @@ -3452,7 +3420,7 @@ static void recv_apdu(ZOOM_connection c, Z_APDU *apdu) { Z_InitResponse *initrs; - c->mask = 0; + ZOOM_connection_set_mask(c, 0); yaz_log(log_details, "%p recv_apdu apdu->which=%d", c, apdu->which); switch(apdu->which) { @@ -3682,7 +3650,7 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres) "Content-Type"); const char *connection_head = z_HTTP_header_lookup(hres->headers, "Connection"); - c->mask = 0; + ZOOM_connection_set_mask(c, 0); yaz_log(log_details, "%p handle_http", c); if (content_type && !yaz_strcmp_del("text/xml", content_type, "; ")) @@ -3826,17 +3794,18 @@ static zoom_ret do_write_ex(ZOOM_connection c, char *buf_out, int len_out) } else if (r == 1) { - c->mask = ZOOM_SELECT_EXCEPT; + int mask = ZOOM_SELECT_EXCEPT; if (c->cs->io_pending & CS_WANT_WRITE) - c->mask += ZOOM_SELECT_WRITE; + mask += ZOOM_SELECT_WRITE; if (c->cs->io_pending & CS_WANT_READ) - c->mask += ZOOM_SELECT_READ; + mask += ZOOM_SELECT_READ; + ZOOM_connection_set_mask(c, mask); yaz_log(log_details, "%p do_write_ex write incomplete mask=%d", c, c->mask); } else { - c->mask = ZOOM_SELECT_READ|ZOOM_SELECT_EXCEPT; + ZOOM_connection_set_mask(c, ZOOM_SELECT_READ|ZOOM_SELECT_EXCEPT); yaz_log(log_details, "%p do_write_ex write complete mask=%d", c, c->mask); } @@ -4014,11 +3983,12 @@ static void ZOOM_connection_do_io(ZOOM_connection c, int mask) "cs_rcvconnect returned %d", c, ret); if (ret == 1) { - c->mask = ZOOM_SELECT_EXCEPT; + int mask = ZOOM_SELECT_EXCEPT; if (c->cs->io_pending & CS_WANT_WRITE) - c->mask += ZOOM_SELECT_WRITE; + mask += ZOOM_SELECT_WRITE; if (c->cs->io_pending & CS_WANT_READ) - c->mask += ZOOM_SELECT_READ; + mask += ZOOM_SELECT_READ; + ZOOM_connection_set_mask(c, mask); } else if (ret == 0) { @@ -4032,7 +4002,7 @@ static void ZOOM_connection_do_io(ZOOM_connection c, int mask) /* no init request for SRW .. */ assert(c->tasks->which == ZOOM_TASK_CONNECT); ZOOM_connection_remove_task(c); - c->mask = 0; + ZOOM_connection_set_mask(c, 0); ZOOM_connection_exec_task(c); } c->state = STATE_ESTABLISHED; @@ -4074,216 +4044,6 @@ ZOOM_API(int) return cs->last_event; } -ZOOM_API(int) - ZOOM_event(int no, ZOOM_connection *cs) -{ - int timeout = 30; /* default timeout in seconds */ - int timeout_set = 0; /* whether it was overriden at all */ -#if HAVE_SYS_POLL_H - struct pollfd pollfds[1024]; - ZOOM_connection poll_cs[1024]; -#else - struct timeval tv; - fd_set input, output, except; -#endif - int i, r, nfds; - int max_fd = 0; - - yaz_log(log_details, "ZOOM_event(no=%d,cs=%p)", no, cs); - - for (i = 0; ioptions, "timeout", -2); - if (this_timeout != -2) - { - /* ensure the minimum timeout is used */ - if (!timeout_set) - timeout = this_timeout; - else if (this_timeout != -1 && this_timeout < timeout) - timeout = this_timeout; - timeout_set = 1; - } -#if HAVE_SYS_POLL_H - if (mask) - { - short poll_events = 0; - - if (mask & ZOOM_SELECT_READ) - poll_events += POLLIN; - if (mask & ZOOM_SELECT_WRITE) - poll_events += POLLOUT; - if (mask & ZOOM_SELECT_EXCEPT) - poll_events += POLLERR; - pollfds[nfds].fd = fd; - pollfds[nfds].events = poll_events; - pollfds[nfds].revents = 0; - poll_cs[nfds] = c; - nfds++; - } -#else - if (mask & ZOOM_SELECT_READ) - { - FD_SET(fd, &input); - nfds++; - } - if (mask & ZOOM_SELECT_WRITE) - { - FD_SET(fd, &output); - nfds++; - } - if (mask & ZOOM_SELECT_EXCEPT) - { - FD_SET(fd, &except); - nfds++; - } -#endif - } - if (!nfds) - return 0; - -#if HAVE_SYS_POLL_H - while ((r = poll(pollfds, nfds, - (timeout == -1 ? -1 : timeout * 1000))) < 0 - && errno == EINTR) - { - ; - } - if (r < 0) - yaz_log(YLOG_WARN|YLOG_ERRNO, "ZOOM_event: poll"); - for (i = 0; imask) - { - int mask = 0; - if (pollfds[i].revents & POLLIN) - mask += ZOOM_SELECT_READ; - if (pollfds[i].revents & POLLOUT) - mask += ZOOM_SELECT_WRITE; - if (pollfds[i].revents & POLLERR) - mask += ZOOM_SELECT_EXCEPT; - if (mask) - ZOOM_connection_do_io(c, mask); - } - else if (r == 0 && c->mask) - { - ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT); - /* timeout and this connection was waiting */ - set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0); - do_close(c); - ZOOM_connection_put_event(c, event); - } - } -#else - tv.tv_sec = timeout; - tv.tv_usec = 0; - - while ((r = select(max_fd+1, &input, &output, &except, - (timeout == -1 ? 0 : &tv))) < 0 && errno == EINTR) - { - ; - } - if (r < 0) - yaz_log(YLOG_WARN|YLOG_ERRNO, "ZOOM_event: select"); - - r = select(max_fd+1, &input, &output, &except, (timeout == -1 ? 0 : &tv)); - for (i = 0; imask) - { - /* no timeout and real socket */ - if (FD_ISSET(fd, &input)) - mask += ZOOM_SELECT_READ; - if (FD_ISSET(fd, &output)) - mask += ZOOM_SELECT_WRITE; - if (FD_ISSET(fd, &except)) - mask += ZOOM_SELECT_EXCEPT; - if (mask) - ZOOM_connection_do_io(c, mask); - } - if (r == 0 && c->mask) - { - ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT); - /* timeout and this connection was waiting */ - set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0); - do_close(c); - ZOOM_connection_put_event(c, event); - } - } -#endif - for (i = 0; imask) + { + ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT); + /* timeout and this connection was waiting */ + set_ZOOM_error(c, ZOOM_ERROR_TIMEOUT, 0); + do_close(c); + ZOOM_connection_put_event(c, event); + } + return 0; +} + +ZOOM_API(int) + ZOOM_process_event(int no, ZOOM_connection *cs) +{ + int i; + + yaz_log(log_details, "ZOOM_event_poll(no=%d,cs=%p)", no, cs); + + for (i = 0; imask && mask) + ZOOM_connection_do_io(c, mask); + return 0; +} + +ZOOM_API(int) ZOOM_connection_get_socket(ZOOM_connection c) +{ + if (c->cs) + return cs_fileno(c->cs); + return -1; +} + +ZOOM_API(int) ZOOM_connection_set_mask(ZOOM_connection c, int mask) +{ + c->mask = mask; + if (!c->cs) + return -1; + return 0; +} + +ZOOM_API(int) ZOOM_connection_get_mask(ZOOM_connection c) +{ + if (c->cs) + return c->mask; + return 0; +} + +ZOOM_API(int) ZOOM_connection_get_timeout(ZOOM_connection c) +{ + return ZOOM_options_get_int(c->options, "timeout", 30); +} + /* * Local variables: * c-basic-offset: 4 diff --git a/src/zoom-p.h b/src/zoom-p.h index cd0004f..68f1880 100644 --- a/src/zoom-p.h +++ b/src/zoom-p.h @@ -2,7 +2,7 @@ * Copyright (C) 1995-2005, Index Data ApS * See the file LICENSE for details. * - * $Id: zoom-p.h,v 1.16 2007-01-03 08:42:15 adam Exp $ + * $Id: zoom-p.h,v 1.17 2007-01-09 13:56:48 adam Exp $ */ /** * \file zoom-p.h @@ -38,10 +38,6 @@ typedef struct ZOOM_task_p *ZOOM_task; #define STATE_CONNECTING 1 #define STATE_ESTABLISHED 2 -#define ZOOM_SELECT_READ 1 -#define ZOOM_SELECT_WRITE 2 -#define ZOOM_SELECT_EXCEPT 4 - struct ZOOM_connection_p { enum oid_proto proto; COMSTACK cs; @@ -196,6 +192,7 @@ struct ZOOM_Event_p { }; void ZOOM_options_addref (ZOOM_options opt); + /* * Local variables: * c-basic-offset: 4 diff --git a/src/zoom-socket.c b/src/zoom-socket.c new file mode 100644 index 0000000..a3adebf --- /dev/null +++ b/src/zoom-socket.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 1995-2007, Index Data ApS + * See the file LICENSE for details. + * + * $Id: zoom-socket.c,v 1.1 2007-01-09 13:56:48 adam Exp $ + */ +/** + * \file zoom-socket.c + * \brief Implements ZOOM C socket interface. + */ + +#include +#include +#include +#include + +#include + +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#if HAVE_SYS_POLL_H +#include +#endif +#if HAVE_SYS_SELECT_H +#include +#endif +#ifdef WIN32 +#if FD_SETSIZE < 512 +#define FD_SETSIZE 512 +#endif +#include +#endif + + +ZOOM_API(int) + ZOOM_event_sys_select(int no, ZOOM_connection *cs) +{ + struct timeval tv; + fd_set input, output, except; + int i, r; + int max_fd = 0; + int timeout = 30; + int nfds = 0; + + FD_ZERO(&input); + FD_ZERO(&output); + FD_ZERO(&except); + + for (i = 0; i