From 8b2791efeb9e671fabf90c36c6828a5bf71c887b Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Tue, 1 Mar 2005 20:37:01 +0000 Subject: [PATCH] Enhancements and new bugs in Generic Frontend Server.. Reworked YAZ GFS XML config. Added pqf2cql support. --- src/eventl.c | 6 +- src/eventl.h | 4 +- src/seshigh.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++------- src/session.h | 13 ++++- src/statserv.c | 129 +++++++++++++++++++++++++++-------------- ztest/Makefile.am | 4 +- ztest/config1.xml | 20 +++++++ 7 files changed, 269 insertions(+), 74 deletions(-) create mode 100644 ztest/config1.xml diff --git a/src/eventl.c b/src/eventl.c index 649e6de..5084f2d 100644 --- a/src/eventl.c +++ b/src/eventl.c @@ -2,7 +2,7 @@ * Copyright (C) 1995-2005, Index Data ApS * See the file LICENSE for details. * - * $Id: eventl.c,v 1.7 2005-02-01 14:46:47 adam Exp $ + * $Id: eventl.c,v 1.8 2005-03-01 20:37:01 adam Exp $ */ /** @@ -55,7 +55,7 @@ static int log_level=0; static int log_level_initialized=0; -IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags, int port) +IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags, int chan_id) { IOCHAN new_iochan; @@ -74,7 +74,7 @@ IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags, int port) new_iochan->force_event = 0; new_iochan->last_event = new_iochan->max_idle = 0; new_iochan->next = NULL; - new_iochan->port = port; + new_iochan->chan_id = chan_id; return new_iochan; } diff --git a/src/eventl.h b/src/eventl.h index b3d663b..a737c13 100644 --- a/src/eventl.h +++ b/src/eventl.h @@ -2,7 +2,7 @@ * Copyright (C) 1995-2005, Index Data ApS * See the file LICENSE for details. * - * $Id: eventl.h,v 1.4 2005-02-01 14:46:47 adam Exp $ + * $Id: eventl.h,v 1.5 2005-03-01 20:37:01 adam Exp $ */ /** @@ -39,7 +39,7 @@ int force_event; time_t max_idle; struct iochan *next; - int port; /* listening port (0 if none ) */ + int chan_id; /* listening port (0 if none ) */ } *IOCHAN; #define iochan_destroy(i) (void)((i)->destroyed = 1) diff --git a/src/seshigh.c b/src/seshigh.c index 70581d4..4a3766f 100644 --- a/src/seshigh.c +++ b/src/seshigh.c @@ -2,7 +2,7 @@ * Copyright (C) 1995-2005, Index Data ApS * See the file LICENSE for details. * - * $Id: seshigh.c,v 1.47 2005-02-01 14:46:47 adam Exp $ + * $Id: seshigh.c,v 1.48 2005-03-01 20:37:01 adam Exp $ */ /** * \file seshigh.c @@ -177,6 +177,7 @@ association *create_association(IOCHAN channel, COMSTACK link, request_initq(&anew->incoming); request_initq(&anew->outgoing); anew->proto = cs_getproto(link); + anew->cql_transform = 0; return anew; } @@ -475,8 +476,6 @@ static void assoc_init_reset(association *assoc) odr_strdup (assoc->encode, cs_addrstr(assoc->client_link)); yaz_log(log_requestdetail, "peer %s", assoc->init->peer_name); - - } static int srw_bend_init(association *assoc, Z_SRW_diagnostic **d, int *num) @@ -623,6 +622,79 @@ static int srw_bend_fetch(association *assoc, int pos, return rr.errcode; } +static int cql2pqf(ODR odr, const char *cql, cql_transform_t ct, + Z_Query *query_result) +{ + /* have a CQL query and CQL to PQF transform .. */ + CQL_parser cp = cql_parser_create(); + int r; + int srw_errcode = 0; + const char *add = 0; + char rpn_buf[512]; + + r = cql_parser_string(cp, cql); + if (r) + { + /* CQL syntax error */ + srw_errcode = 10; + } + if (!r) + { + /* Syntax OK */ + r = cql_transform_buf(ct, + cql_parser_result(cp), + rpn_buf, sizeof(rpn_buf)-1); + if (r) + srw_errcode = cql_transform_error(ct, &add); + } + if (!r) + { + /* Syntax & transform OK. */ + /* Convert PQF string to Z39.50 to RPN query struct */ + YAZ_PQF_Parser pp = yaz_pqf_create(); + Z_RPNQuery *rpnquery = yaz_pqf_parse(pp, odr, rpn_buf); + if (!rpnquery) + { + size_t off; + const char *pqf_msg; + int code = yaz_pqf_error(pp, &pqf_msg, &off); + yaz_log(YLOG_WARN, "PQF Parser Error %s (code %d)", + pqf_msg, code); + srw_errcode = 10; + } + else + { + query_result->which = Z_Query_type_1; + query_result->u.type_1 = rpnquery; + } + yaz_pqf_destroy(pp); + } + cql_parser_destroy(cp); + return srw_errcode; +} + +static int cql2pqf_scan(ODR odr, const char *cql, cql_transform_t ct, + Z_AttributesPlusTerm *result) +{ + Z_Query query; + Z_RPNQuery *rpn; + int srw_error = cql2pqf(odr, cql, ct, &query); + if (srw_error) + return srw_error; + if (query.which != Z_Query_type_1 && query.which != Z_Query_type_101) + return 10; /* bad query type */ + rpn = query.u.type_1; + if (!rpn->RPNStructure) + return 10; /* must be structure */ + if (rpn->RPNStructure->which != Z_RPNStructure_simple) + return 10; /* must be simple */ + if (rpn->RPNStructure->u.simple->which != Z_Operand_APT) + return 10; /* must be attributes plus term node .. */ + memcpy(result, rpn->RPNStructure->u.simple->u.attributesPlusTerm, + sizeof(*result)); + return 0; +} + static void srw_bend_search(association *assoc, request *req, Z_SRW_searchRetrieveRequest *srw_req, Z_SRW_searchRetrieveResponse *srw_res, @@ -647,19 +719,36 @@ static void srw_bend_search(association *assoc, request *req, rr.referenceId = 0; rr.query = (Z_Query *) odr_malloc (assoc->decode, sizeof(*rr.query)); + rr.query->u.type_1 = 0; if (srw_req->query_type == Z_SRW_query_type_cql) { - ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext)); - ext->direct_reference = odr_getoidbystr(assoc->decode, - "1.2.840.10003.16.2"); - ext->indirect_reference = 0; - ext->descriptor = 0; - ext->which = Z_External_CQL; - ext->u.cql = srw_req->query.cql; - - rr.query->which = Z_Query_type_104; - rr.query->u.type_104 = ext; + if (assoc->cql_transform) + { + int srw_errcode = cql2pqf(assoc->encode, srw_req->query.cql, + assoc->cql_transform, rr.query); + if (srw_errcode) + { + yaz_add_srw_diagnostic(assoc->encode, + &srw_res->diagnostics, + &srw_res->num_diagnostics, + srw_errcode, 0); + } + } + else + { + /* CQL query to backend. Wrap it - Z39.50 style */ + ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext)); + ext->direct_reference = odr_getoidbystr(assoc->decode, + "1.2.840.10003.16.2"); + ext->indirect_reference = 0; + ext->descriptor = 0; + ext->which = Z_External_CQL; + ext->u.cql = srw_req->query.cql; + + rr.query->which = Z_Query_type_104; + rr.query->u.type_104 = ext; + } } else if (srw_req->query_type == Z_SRW_query_type_pqf) { @@ -687,7 +776,6 @@ static void srw_bend_search(association *assoc, request *req, } else { - rr.query->u.type_1 = 0; yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics, &srw_res->num_diagnostics, 11, 0); } @@ -927,11 +1015,33 @@ static void srw_bend_scan(association *assoc, request *req, else if (srw_req->query_type == Z_SRW_query_type_cql && assoc->init->bend_srw_scan) { - bsrr->term = 0; - bsrr->attributeset = VAL_NONE; - bsrr->scanClause = srw_req->scanClause.cql; - ((int (*)(void *, bend_scan_rr *)) - (*assoc->init->bend_srw_scan))(assoc->backend, bsrr); + if (assoc->cql_transform) + { + bsrr->scanClause = 0; + bsrr->attributeset = VAL_NONE; + bsrr->term = odr_malloc(assoc->decode, sizeof(*bsrr->term)); + int srw_error = cql2pqf_scan(assoc->encode, + srw_req->scanClause.cql, + assoc->cql_transform, + bsrr->term); + if (srw_error) + yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics, + &srw_res->num_diagnostics, + srw_error, 0); + else + { + ((int (*)(void *, bend_scan_rr *)) + (*assoc->init->bend_scan))(assoc->backend, bsrr); + } + } + else + { + bsrr->term = 0; + bsrr->attributeset = VAL_NONE; + bsrr->scanClause = srw_req->scanClause.cql; + ((int (*)(void *, bend_scan_rr *)) + (*assoc->init->bend_srw_scan))(assoc->backend, bsrr); + } } else { @@ -1602,7 +1712,7 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb) assoc->init->implementation_name, odr_prepend(assoc->encode, "GFS", resp->implementationName)); - version = odr_strdup(assoc->encode, "$Revision: 1.47 $"); + version = odr_strdup(assoc->encode, "$Revision: 1.48 $"); if (strlen(version) > 10) /* check for unexpanded CVS strings */ version[strlen(version)-2] = '\0'; resp->implementationVersion = odr_prepend(assoc->encode, @@ -1866,11 +1976,24 @@ static Z_APDU *process_searchRequest(association *assoc, request *reqb, nmem_transfer(bsrr->stream->mem, reqb->request_mem); bsrr->decode = assoc->decode; bsrr->print = assoc->print; - bsrr->errcode = 0; bsrr->hits = 0; + bsrr->errcode = 0; bsrr->errstring = NULL; bsrr->search_info = NULL; - (assoc->init->bend_search)(assoc->backend, bsrr); + + if (assoc->cql_transform && + req->query->which == Z_Query_type_104 && + req->query->u.type_104->which == Z_External_CQL) + { + /* have a CQL query and a CQL to PQF transform .. */ + int srw_errcode = + cql2pqf(bsrr->stream, req->query->u.type_104->u.cql, + assoc->cql_transform, bsrr->query); + if (srw_errcode) + bsrr->errcode = yaz_diag_srw_to_bib1(srw_errcode); + } + if (!bsrr->errcode) + (assoc->init->bend_search)(assoc->backend, bsrr); if (!bsrr->request) /* backend not ready with the search response */ return 0; /* should not be used any more */ } diff --git a/src/session.h b/src/session.h index 69402ab..96a32e0 100644 --- a/src/session.h +++ b/src/session.h @@ -2,7 +2,7 @@ * Copyright (C) 1995-2005, Index Data ApS * See the file LICENSE for details. * - * $Id: session.h,v 1.5 2005-02-01 14:46:47 adam Exp $ + * $Id: session.h,v 1.6 2005-03-01 20:37:01 adam Exp $ */ /** * \file session.h @@ -12,6 +12,7 @@ #define SESSION_H #include +#include #include #include #include @@ -21,10 +22,17 @@ struct gfs_server { statserv_options_block cb; char *host; - int port; + int listen_ref; + cql_transform_t cql_transform; struct gfs_server *next; }; +struct gfs_listen { + char *id; + char *address; + struct gfs_listen *next; +}; + typedef enum { REQUEST_IDLE, /* the request is just sitting in the queue */ REQUEST_PENDING /* operation pending (b'end processing or network I/O*/ @@ -97,6 +105,7 @@ typedef struct association struct bend_initrequest *init; statserv_options_block *last_control; + cql_transform_t cql_transform; } association; association *create_association(IOCHAN channel, COMSTACK link, diff --git a/src/statserv.c b/src/statserv.c index fd9a575..aceecbf 100644 --- a/src/statserv.c +++ b/src/statserv.c @@ -5,7 +5,7 @@ * NT threaded server code by * Chas Woodfield, Fretwell Downing Informatics. * - * $Id: statserv.c,v 1.22 2005-02-07 11:23:47 adam Exp $ + * $Id: statserv.c,v 1.23 2005-03-01 20:37:01 adam Exp $ */ /** @@ -64,6 +64,7 @@ static IOCHAN pListener = NULL; static struct gfs_server *gfs_server_list = 0; +static struct gfs_listen *gfs_listen_list = 0; static NMEM gfs_nmem = 0; static char *me = "statserver"; /* log prefix */ @@ -114,7 +115,7 @@ statserv_options_block control_block = { "", /* PID fname */ 0, /* background daemon */ "", /* SSL certificate filename */ - "", /* XML config filename */ + "" /* XML config filename */ }; static int max_sessions = 0; @@ -209,7 +210,21 @@ static struct gfs_server * gfs_server_new() memcpy(&n->cb, &control_block, sizeof(control_block)); n->next = 0; n->host = 0; - n->port = 0; + n->listen_ref = 0; + n->cql_transform = 0; + return n; +} + +static struct gfs_listen * gfs_listen_new(const char *id, + const char *address) +{ + struct gfs_listen *n = nmem_malloc(gfs_nmem, sizeof(*n)); + if (id) + n->id = nmem_strdup(gfs_nmem, id); + else + n->id = 0; + n->next = 0; + n->address = nmem_strdup(gfs_nmem, address); return n; } @@ -230,13 +245,14 @@ int control_association(association *assoc, const char *host, int force_open) struct gfs_server *gfs; for (gfs = gfs_server_list; gfs; gfs = gfs->next) { - int port_match = 0; + int listen_match = 0; int host_match = 0; if ( !gfs->host || (host && gfs->host && !strcmp(host, gfs->host))) host_match = 1; - if (assoc->client_chan->port == gfs->port) - port_match= 1; - if (port_match && host_match) + if (!gfs->listen_ref || + gfs->listen_ref == assoc->client_chan->chan_id) + listen_match = 1; + if (listen_match && host_match) { if (force_open || (assoc->last_control != &gfs->cb && assoc->backend)) @@ -248,6 +264,7 @@ int control_association(association *assoc, const char *host, int force_open) xfree(assoc->init); assoc->init = 0; } + assoc->cql_transform = gfs->cql_transform; assoc->last_control = &gfs->cb; statserv_setcontrol(&gfs->cb); return 1; @@ -255,12 +272,14 @@ int control_association(association *assoc, const char *host, int force_open) } statserv_setcontrol(0); assoc->last_control = 0; + assoc->cql_transform = 0; return 0; } else { statserv_setcontrol(&control_block); assoc->last_control = &control_block; + assoc->cql_transform = 0; return 1; } } @@ -268,6 +287,7 @@ int control_association(association *assoc, const char *host, int force_open) static void xml_config_read() { struct gfs_server **gfsp = &gfs_server_list; + struct gfs_listen **gfslp = &gfs_listen_list; #if HAVE_XML2 xmlNodePtr ptr = xml_config_get_root(); @@ -275,33 +295,73 @@ static void xml_config_read() return; for (ptr = ptr->children; ptr; ptr = ptr->next) { - if (ptr->type == XML_ELEMENT_NODE && - !strcmp((const char *) ptr->name, "server")) + if (ptr->type != XML_ELEMENT_NODE) + continue; + struct _xmlAttr *attr = ptr->properties; + if (!strcmp((const char *) ptr->name, "listen")) + { + /* + tcp:@:9999 + */ + const char *id = 0; + const char *address = + nmem_dup_xml_content(gfs_nmem, ptr->children); + for ( ; attr; attr = attr->next) + if (!strcmp(attr->name, "id") + && attr->children && attr->children->type == XML_TEXT_NODE) + id = nmem_dup_xml_content(gfs_nmem, attr->children); + if (address) + { + *gfslp = gfs_listen_new(id, address); + gfslp = &(*gfslp)->next; + *gfslp = 0; /* make listener list consistent for search */ + } + } + else if (!strcmp((const char *) ptr->name, "server")) { xmlNodePtr ptr_children = ptr->children; xmlNodePtr ptr; - + const char *listenref = 0; + + for ( ; attr; attr = attr->next) + if (!strcmp(attr->name, "listenref") + && attr->children && attr->children->type == XML_TEXT_NODE) + listenref = nmem_dup_xml_content(gfs_nmem, attr->children); *gfsp = gfs_server_new(); + if (listenref) + { + int id_no; + struct gfs_listen *gl = gfs_listen_list; + for (id_no = 1; gl; gl = gl->next, id_no++) + if (gl->id && !strcmp(gl->id, listenref)) + { + (*gfsp)->listen_ref = id_no; + break; + } + if (!gl) + yaz_log(YLOG_WARN, "Non-existent listenref '%s' in server " + "config element", listenref); + } for (ptr = ptr_children; ptr; ptr = ptr->next) { - if (ptr->type == XML_ELEMENT_NODE && - !strcmp((const char *) ptr->name, "host")) + if (ptr->type != XML_ELEMENT_NODE) + continue; + if (!strcmp((const char *) ptr->name, "host")) { (*gfsp)->host = nmem_dup_xml_content(gfs_nmem, ptr->children); } - if (ptr->type == XML_ELEMENT_NODE && - !strcmp((const char *) ptr->name, "port")) - { - (*gfsp)->port = atoi(nmem_dup_xml_content(gfs_nmem, - ptr->children)); - } - if (ptr->type == XML_ELEMENT_NODE && - !strcmp((const char *) ptr->name, "config")) + if (!strcmp((const char *) ptr->name, "config")) { strcpy((*gfsp)->cb.configname, nmem_dup_xml_content(gfs_nmem, ptr->children)); } + if (!strcmp((const char *) ptr->name, "pqf2cql")) + { + (*gfsp)->cql_transform = cql_transform_open_fname( + nmem_dup_xml_content(gfs_nmem, ptr->children) + ); + } } gfsp = &(*gfsp)->next; } @@ -346,30 +406,13 @@ static void xml_config_close() static void xml_config_add_listeners() { -#define MAX_PORTS 200 - struct gfs_server *gfs = gfs_server_list; - int i, ports[MAX_PORTS]; - for (i = 0; inext) - { - int port = gfs->port; - if (port) - { - for (i = 0; inext, id_no++) { - char where[80]; - sprintf(where, "@:%d", ports[i]); - add_listener(where, ports[i]); + if (gfs->address) + add_listener(gfs->address, id_no); } } @@ -840,7 +883,7 @@ static void *new_session (void *vp) } if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session, mask, - parent_chan->port))) + parent_chan->chan_id))) { yaz_log(YLOG_FATAL, "Failed to create iochan"); return 0; diff --git a/ztest/Makefile.am b/ztest/Makefile.am index 4b81af4..2c276f2 100644 --- a/ztest/Makefile.am +++ b/ztest/Makefile.am @@ -1,10 +1,10 @@ -## $Id: Makefile.am,v 1.18 2004-05-02 00:07:11 adam Exp $ +## $Id: Makefile.am,v 1.19 2005-03-01 20:37:01 adam Exp $ bin_PROGRAMS=yaz-ztest yaz_ztest_SOURCES=ztest.c read-grs.c read-marc.c -EXTRA_DIST=dummy-records dummy-words dummy-grs ztest.pem +EXTRA_DIST=dummy-records dummy-words dummy-grs ztest.pem config1.xml if ISTHR extra=../src/libyazthread.la diff --git a/ztest/config1.xml b/ztest/config1.xml new file mode 100644 index 0000000..262dae6 --- /dev/null +++ b/ztest/config1.xml @@ -0,0 +1,20 @@ + + + tcp:@:9900 + tcp:@:9901 + + host1 + /var/www/s1 + zebra1.cfg + + + host2 + /var/www/s2 + zebra2.cfg + + + /var/www/s3 + zebra3.cfg + ../etc/pqf.properties + + -- 1.7.10.4