Reworked YAZ GFS XML config. Added pqf2cql support.
* 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 $
*/
/**
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;
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;
}
* 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 $
*/
/**
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)
* 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
request_initq(&anew->incoming);
request_initq(&anew->outgoing);
anew->proto = cs_getproto(link);
+ anew->cql_transform = 0;
return anew;
}
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)
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,
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)
{
}
else
{
- rr.query->u.type_1 = 0;
yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
&srw_res->num_diagnostics, 11, 0);
}
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
{
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,
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 */
}
* 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
#define SESSION_H
#include <yaz/comstack.h>
+#include <yaz/cql.h>
#include <yaz/odr.h>
#include <yaz/oid.h>
#include <yaz/proto.h>
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*/
struct bend_initrequest *init;
statserv_options_block *last_control;
+ cql_transform_t cql_transform;
} association;
association *create_association(IOCHAN channel, COMSTACK link,
* 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 $
*/
/**
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 */
"", /* PID fname */
0, /* background daemon */
"", /* SSL certificate filename */
- "", /* XML config filename */
+ "" /* XML config filename */
};
static int max_sessions = 0;
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;
}
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))
xfree(assoc->init);
assoc->init = 0;
}
+ assoc->cql_transform = gfs->cql_transform;
assoc->last_control = &gfs->cb;
statserv_setcontrol(&gfs->cb);
return 1;
}
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;
}
}
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();
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"))
+ {
+ /*
+ <listen id="listenerid">tcp:@:9999</listen>
+ */
+ 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;
}
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; i<MAX_PORTS; i++)
- ports[i] = 0;
+ struct gfs_listen *gfs = gfs_listen_list;
+ int id_no;
- for (; gfs; gfs = gfs->next)
- {
- int port = gfs->port;
- if (port)
- {
- for (i = 0; i<MAX_PORTS && ports[i] != port; i++)
- if (ports[i] == 0)
- {
- ports[i] = port;
- break;
- }
- }
- }
- for (i = 0; i<MAX_PORTS && ports[i]; i++)
+ for (id_no = 1; gfs; gfs = gfs->next, id_no++)
{
- char where[80];
- sprintf(where, "@:%d", ports[i]);
- add_listener(where, ports[i]);
+ if (gfs->address)
+ add_listener(gfs->address, id_no);
}
}
}
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;
-## $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
--- /dev/null
+<!-- $Id: config1.xml,v 1.1 2005-03-01 20:37:01 adam Exp $ -->
+<yazgfs>
+ <listen id="public9900">tcp:@:9900</listen>
+ <listen id="public9901">tcp:@:9901</listen>
+ <server>
+ <host>host1</host>
+ <directory>/var/www/s1</directory>
+ <config>zebra1.cfg</config>
+ </server>
+ <server>
+ <host>host2</host>
+ <directory>/var/www/s2</directory>
+ <config>zebra2.cfg</config>
+ </server>
+ <server listenref="public9901">
+ <directory>/var/www/s3</directory>
+ <config>zebra3.cfg</config>
+ <pqf2cql>../etc/pqf.properties</pqf2cql>
+ </server>
+</yazgfs>