Enhancements and new bugs in Generic Frontend Server..
authorAdam Dickmeiss <adam@indexdata.dk>
Tue, 1 Mar 2005 20:37:01 +0000 (20:37 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Tue, 1 Mar 2005 20:37:01 +0000 (20:37 +0000)
Reworked YAZ GFS XML config. Added pqf2cql support.

src/eventl.c
src/eventl.h
src/seshigh.c
src/session.h
src/statserv.c
ztest/Makefile.am
ztest/config1.xml [new file with mode: 0644]

index 649e6de..5084f2d 100644 (file)
@@ -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;
 }
 
index b3d663b..a737c13 100644 (file)
@@ -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)
index 70581d4..4a3766f 100644 (file)
@@ -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 */
     }
index 69402ab..96a32e0 100644 (file)
@@ -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 <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*/
@@ -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,
index fd9a575..aceecbf 100644 (file)
@@ -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"))
+       {
+           /*
+             <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;
        }
@@ -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; 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);
     }
 }
 
@@ -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;
index 4b81af4..2c276f2 100644 (file)
@@ -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 (file)
index 0000000..262dae6
--- /dev/null
@@ -0,0 +1,20 @@
+<!-- $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>