Initial revision
authorSebastian Hammer <quinn@indexdata.com>
Tue, 14 Nov 2006 20:44:36 +0000 (20:44 +0000)
committerSebastian Hammer <quinn@indexdata.com>
Tue, 14 Nov 2006 20:44:36 +0000 (20:44 +0000)
22 files changed:
.cvsignore [new file with mode: 0644]
.gdb_history [new file with mode: 0644]
.pazpar2.c.swp [new file with mode: 0644]
.pazpar2.h.swp [new file with mode: 0644]
Makefile [new file with mode: 0644]
bad.pz [new file with mode: 0644]
command.c [new file with mode: 0644]
command.h [new file with mode: 0644]
danish.pz [new file with mode: 0644]
def.pz [new file with mode: 0644]
defport.pz [new file with mode: 0644]
eventl.c [new file with mode: 0644]
eventl.h [new file with mode: 0644]
h1.pz [new file with mode: 0644]
local.pz [new file with mode: 0644]
multi.pz [new file with mode: 0644]
multi.txt [new file with mode: 0644]
pazpar2.c [new file with mode: 0644]
pazpar2.h [new file with mode: 0644]
test.pz [new file with mode: 0644]
util.c [new file with mode: 0644]
util.h [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..62661d9
--- /dev/null
@@ -0,0 +1 @@
+paraz
diff --git a/.gdb_history b/.gdb_history
new file mode 100644 (file)
index 0000000..4377013
--- /dev/null
@@ -0,0 +1,208 @@
+break main
+run -c 2000
+quit
+break main
+run -c 2000
+next
+ste
+step
+next
+print hostbuf
+next
+un
+run
+nexrt
+next
+step
+next
+step
+next
+print p
+print *p
+next
+cont
+run
+quit
+break main
+run -c 2000
+next
+step
+next
+print hostbuf
+next
+list
+bt
+frame 1
+list
+break event_loop
+delete 1
+run
+next
+print *p
+next
+quit
+break command_accept
+run -c 2000
+next
+print s
+next
+print channel_list
+print *channel_list
+print *channel_list->next
+next
+print max
+next
+next
+quit
+breack command_command
+break command_command
+run -c 2000
+run
+next
+print *s
+print *s->channel
+run
+run
+run
+quit
+run -c 2000
+break command_command
+cont
+next
+break command_accept
+cont
+run
+finish
+cont
+next
+cont
+next
+print res
+next
+cont
+con
+cont
+quit
+run -c 2000
+break command_io
+cont
+cont
+next
+print buf
+quit
+run -c 2000
+break command_command
+cont
+next
+print argv
+cont
+next
+list
+break 54
+cont
+print argv
+print argc
+cont
+quit
+break load_targets
+run -c 2000
+finish
+print channel_list
+print *channel_list
+print *channel_list->data
+print *channel_list->next
+next
+break handler
+cont
+next
+print *target
+print *t
+next
+print res
+print errno
+print erddrno
+print (int)errno
+quit
+run -c 2000
+run -c 2001
+run
+run -c 2000
+break handler
+cont
+next
+print res
+next
+cont
+next
+h
+run -c 2001
+next
+cont
+next
+cont
+print channel_list
+print *channel_list
+print *channel_list->next
+print *channel_list->next->next
+run -c 2000
+next
+cont
+next
+cont
+next
+print *a
+print *a->u.initResponse
+next
+step
+next
+cont
+delete 1
+cont
+cont
+run -c 2000
+bt
+frame 4
+list
+print *session
+print *s
+list
+print *i
+run
+run -c 2001
+run -c 2000
+run -c 2001
+run -c 2000
+cont
+quit
+run -c 2000
+break handler
+cont
+cont
+cont
+cont
+cont
+next
+print *p
+next
+print *p
+next
+next
+print *p
+next
+print *p
+next
+cont
+next
+print *t
+next
+print *t
+print *s
+next
+quit
+break do_presentResponse
+run -c 2002
+next
+print *r
+print *r->presentStatus
+print *r->numberOfRecordsReturned
+quit
diff --git a/.pazpar2.c.swp b/.pazpar2.c.swp
new file mode 100644 (file)
index 0000000..64715bb
Binary files /dev/null and b/.pazpar2.c.swp differ
diff --git a/.pazpar2.h.swp b/.pazpar2.h.swp
new file mode 100644 (file)
index 0000000..44d32aa
Binary files /dev/null and b/.pazpar2.h.swp differ
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..51ce3df
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+# ParaZ. Copyright (C) 2000-2004, Index Data ApS
+# All rights reserved.
+# $Id: Makefile,v 1.1 2006-11-14 20:44:38 quinn Exp $
+
+SHELL=/bin/sh
+
+CC=gcc
+
+YAZCONF=yaz-config
+YAZLIBS=`$(YAZCONF) --libs`
+YAZCFLAGS=`$(YAZCONF) --cflags`
+
+PROG=pazpar2
+PROGO=pazpar2.o eventl.o util.o command.o
+
+all: $(PROG)
+
+$(PROG): $(PROGO)
+       $(CC) $(CFLAGS) $(YAZCFLAGS) -o $(PROG) $(PROGO) $(YAZLIBS)
+
+.c.o:
+       $(CC) -c $(CFLAGS) -I. $(YAZCFLAGS) $<
+
+clean:
+       rm -f *.[oa] test core mon.out gmon.out errlist $(PROG)
+
diff --git a/bad.pz b/bad.pz
new file mode 100644 (file)
index 0000000..6522dff
--- /dev/null
+++ b/bad.pz
@@ -0,0 +1,17 @@
+# one good target:
+target bagel.indexdata.dk/gils
+
+# One bad port with something behind it
+#target bagel.indexdata.dk:23/Telnet
+# Seems to hang for ever
+
+# One bad port with nothing behind it 
+target bagel.indexdata.dk:2/BadPort
+
+# One unknonw host
+target unknown.indexdata.dk
+
+connect
+init
+search @attr 1=4 utah
+present
diff --git a/command.c b/command.c
new file mode 100644 (file)
index 0000000..4ea72e1
--- /dev/null
+++ b/command.c
@@ -0,0 +1,350 @@
+/* $Id: command.c,v 1.1 2006-11-14 20:44:37 quinn Exp $ */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <yaz/yaz-util.h>
+#include <yaz/comstack.h>
+#include <netdb.h>
+
+#include "command.h"
+#include "util.h"
+#include "eventl.h"
+#include "pazpar2.h"
+
+extern IOCHAN channel_list;
+
+struct command_session {
+    IOCHAN channel;
+    char *outbuf;
+
+    int outbuflen;
+    int outbufwrit;
+
+    struct session *psession;
+};
+
+void command_destroy(struct command_session *s);
+void command_prompt(struct command_session *s);
+void command_puts(struct command_session *s, const char *buf);
+
+static int cmd_quit(struct command_session *s, char **argv, int argc)
+{
+    IOCHAN i = s->channel;
+    close(iochan_getfd(i));
+    iochan_destroy(i);
+    command_destroy(s);
+    return 0;
+}
+
+static int cmd_load(struct command_session *s, char **argv, int argc)
+{
+    if (argc != 2) {
+        command_puts(s, "Usage: load filename\n");
+    }
+    if (load_targets(s->psession, argv[1]) < 0)
+        command_puts(s, "Failed to open file\n");
+    return 1;
+}
+
+static int cmd_search(struct command_session *s, char **argv, int argc)
+{
+    if (argc != 2)
+    {
+        command_puts(s, "Usage: search word\n");
+        return 1;
+    }
+    search(s->psession, argv[1]);
+    return 1;
+}
+
+static int cmd_hitsbytarget(struct command_session *s, char **argv, int argc)
+{
+    int count;
+    int i;
+
+    struct hitsbytarget *ht = hitsbytarget(s->psession, &count);
+    for (i = 0; i < count; i++)
+    {
+        char buf[1024];
+
+        sprintf(buf, "%s: %d (%d records, diag=%d, state=%s)\n", ht[i].id, ht[i].hits,
+            ht[i].records, ht[i].diagnostic, ht[i].state);
+        command_puts(s, buf);
+    }
+    return 1;
+}
+
+static int cmd_stat(struct command_session *s, char **argv, int argc)
+{
+    char buf[1024];
+    struct statistics stat;
+
+    statistics(s->psession, &stat);
+    sprintf(buf, "Number of connections: %d\n", stat.num_connections);
+    command_puts(s, buf);
+    if (stat.num_no_connection)
+    {
+        sprintf(buf, "#No_connection:        %d\n", stat.num_no_connection);
+        command_puts(s, buf);
+    }
+    if (stat.num_connecting)
+    {
+        sprintf(buf, "#Connecting:           %d\n", stat.num_connecting);
+        command_puts(s, buf);
+    }
+    if (stat.num_initializing)
+    {
+        sprintf(buf, "#Initializing:         %d\n", stat.num_initializing);
+        command_puts(s, buf);
+    }
+    if (stat.num_searching)
+    {
+        sprintf(buf, "#Searching:            %d\n", stat.num_searching);
+        command_puts(s, buf);
+    }
+    if (stat.num_presenting)
+    {
+        sprintf(buf, "#Ppresenting:          %d\n", stat.num_presenting);
+        command_puts(s, buf);
+    }
+    if (stat.num_idle)
+    {
+        sprintf(buf, "#Idle:                 %d\n", stat.num_idle);
+        command_puts(s, buf);
+    }
+    if (stat.num_failed)
+    {
+        sprintf(buf, "#Failed:               %d\n", stat.num_failed);
+        command_puts(s, buf);
+    }
+    if (stat.num_error)
+    {
+        sprintf(buf, "#Error:                %d\n", stat.num_error);
+        command_puts(s, buf);
+    }
+    return 1;
+}
+
+static struct {
+    char *cmd;
+    int (*fun)(struct command_session *s, char *argv[], int argc);
+} cmd_array[] = {
+    {"quit", cmd_quit},
+    {"load", cmd_load},
+    {"search", cmd_search},
+    {"ht", cmd_hitsbytarget},
+    {"stat", cmd_stat},
+    {0,0}
+};
+
+void command_command(struct command_session *s, char *command)
+{
+    char *p;
+    char *argv[20];
+    int argc = 0;
+    int i;
+    int res = -1;
+
+    p = command;
+    while (*p)
+    {
+        while (isspace(*p))
+            p++;
+        if (!*p)
+            break;
+        argv[argc++] = p;
+        while (*p && !isspace(*p))
+            p++;
+        if (!*p)
+            break;
+        *(p++) = '\0';
+    }
+    if (argc) {
+        for (i = 0; cmd_array[i].cmd; i++)
+        {
+            if (!strcmp(cmd_array[i].cmd, argv[0])) {
+                res = (cmd_array[i].fun)(s, argv, argc);
+
+                break;
+            }
+        }
+        if (res < 0) {
+            command_puts(s, "Unknown command.\n");
+            command_prompt(s);
+        }
+        else if (res == 1) {
+            command_prompt(s);
+        }
+    }
+    else
+        command_prompt(s);
+
+}
+
+
+static void command_io(IOCHAN i, int event)
+{
+    int res;
+    char buf[1024];
+    struct command_session *s;
+
+    s = iochan_getdata(i);
+
+
+    switch (event)
+    {
+        case EVENT_INPUT:
+            res = read(iochan_getfd(i), buf, 1024);
+            if (res <= 0)
+            {
+                yaz_log(YLOG_WARN|YLOG_ERRNO, "read command");
+                close(iochan_getfd(i));
+                iochan_destroy(i);
+                command_destroy(s);
+                return;
+            }
+            if (!index(buf, '\n')) {
+                yaz_log(YLOG_WARN|YLOG_ERRNO, "Did not receive complete command");
+                close(iochan_getfd(i));
+                iochan_destroy(i);
+                command_destroy(s);
+                return;
+            }
+            buf[res] = '\0';
+            command_command(s, buf);
+            break;
+        case EVENT_OUTPUT:
+            if (!s->outbuflen || s->outbufwrit < 0)
+            {
+                yaz_log(YLOG_WARN, "Called with outevent but no data");
+                iochan_clearflag(i, EVENT_OUTPUT);
+            }
+            else
+            {
+                res = write(iochan_getfd(i), s->outbuf + s->outbufwrit, s->outbuflen -
+                    s->outbufwrit);
+                if (res < 0) {
+                    yaz_log(YLOG_WARN|YLOG_ERRNO, "write command");
+                    close(iochan_getfd(i));
+                    iochan_destroy(i);
+                    command_destroy(s);
+                }
+                else
+                {
+                    s->outbufwrit += res;
+                    if (s->outbufwrit >= s->outbuflen)
+                    {
+                        s->outbuflen = s->outbufwrit = 0;
+                        iochan_clearflag(i, EVENT_OUTPUT);
+                    }
+                }
+            }
+            break;
+        default:
+            yaz_log(YLOG_WARN, "Bad voodoo on socket");
+    }
+}
+
+void command_puts(struct command_session *s, const char *buf)
+{
+    int len = strlen(buf);
+    memcpy(s->outbuf + s->outbuflen, buf, len);
+    s->outbuflen += len;
+    iochan_setflag(s->channel, EVENT_OUTPUT);
+}
+
+void command_prompt(struct command_session *s)
+{
+    command_puts(s, "Pazpar2> ");
+}
+
+
+/* Accept a new command connection */
+static void command_accept(IOCHAN i, int event)
+{
+    struct sockaddr_in addr;
+    int fd = iochan_getfd(i);
+    socklen_t len;
+    int s;
+    IOCHAN c;
+    struct command_session *ses;
+    int flags;
+
+    len = sizeof addr;
+    if ((s = accept(fd, (struct sockaddr *) &addr, &len)) < 0)
+    {
+        yaz_log(YLOG_WARN|YLOG_ERRNO, "accept");
+        return;
+    }
+    if ((flags = fcntl(s, F_GETFL, 0)) < 0) 
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl");
+    if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0)
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl2");
+
+    yaz_log(YLOG_LOG, "New command connection");
+    c = iochan_create(s, command_io, EVENT_INPUT | EVENT_EXCEPT);
+
+    ses = xmalloc(sizeof(*ses));
+    ses->outbuf = xmalloc(50000);
+    ses->outbuflen = 0;
+    ses->outbufwrit = 0;
+    ses->channel = c;
+    ses->psession = new_session();
+    iochan_setdata(c, ses);
+
+    command_puts(ses, "Welcome to pazpar2\n\n");
+    command_prompt(ses);
+
+    c->next = channel_list;
+    channel_list = c;
+}
+
+void command_destroy(struct command_session *s) {
+    xfree(s->outbuf);
+    xfree(s);
+}
+
+/* Create a command-channel listener */
+void command_init(int port)
+{
+    IOCHAN c;
+    int l;
+    struct protoent *p;
+    struct sockaddr_in myaddr;
+
+    yaz_log(YLOG_LOG, "Command port is %d", port);
+    if (!(p = getprotobyname("tcp"))) {
+        abort();
+    }
+    if ((l = socket(PF_INET, SOCK_STREAM, p->p_proto)) < 0)
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "socket");
+    bzero(&myaddr, sizeof myaddr);
+    myaddr.sin_family = AF_INET;
+    myaddr.sin_addr.s_addr = INADDR_ANY;
+    myaddr.sin_port = port;
+    if (bind(l, (struct sockaddr *) &myaddr, sizeof myaddr) < 0) 
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "bind");
+    if (listen(l, 5) < 0) 
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "listen");
+
+    c = iochan_create(l, command_accept, EVENT_INPUT | EVENT_EXCEPT);
+    //iochan_setdata(c, &l);
+    c->next = channel_list;
+    channel_list = c;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/command.h b/command.h
new file mode 100644 (file)
index 0000000..25e5b99
--- /dev/null
+++ b/command.h
@@ -0,0 +1,6 @@
+#ifndef COMMAND_H
+#define COMMAND_H
+
+void command_init(int port);
+
+#endif
diff --git a/danish.pz b/danish.pz
new file mode 100644 (file)
index 0000000..ba1cc52
--- /dev/null
+++ b/danish.pz
@@ -0,0 +1,21 @@
+target cosmos.dnlb.dk:9909/DNL01
+target odin.dtv.dk:210/DTV01
+target dvjb1.kvl.dk:9909/dvj01
+target hermes.lib.cbs.dk:2100/S
+target a800.hha.dk:9909/hba01
+target z3950.kb.dk:2100/kgl01
+target hans.ruc.dk:2210/S
+target a500.aub.auc.dk:9909/AUB01
+target z3950.dbc.dk:213/def1forsk
+target z3950.dbc.dk:213/def1total
+target z3950.dbc.dk:213/danbibv2
+target hcb.bibnet.dk:2100/S
+target z3950.bibsys.no:2100/BIBSYS
+target z3950.libris.kb.se:210/libr
+target bagel.indexdata.dk/gils
+target www.deff.dk:2100/Default
+target www.deff.dk:2102/Default
+connect
+init
+search @attr 1=4 danmarks
+present
diff --git a/def.pz b/def.pz
new file mode 100644 (file)
index 0000000..1351fde
--- /dev/null
+++ b/def.pz
@@ -0,0 +1,17 @@
+target cosmos.dnlb.dk:9909/DNL01
+target odin.dtv.dk:210/DTV01
+target dvjb1.kvl.dk:9909/dvj01
+target hermes.lib.cbs.dk:2100/S
+target a800.hha.dk:9909/hba01
+target z3950.kb.dk:2100/kgl01
+target hans.ruc.dk:2210/S
+target a500.aub.auc.dk:9909/AUB01
+target z3950.dbc.dk:213/def1forsk
+target z3950.dbc.dk:213/def1total
+target z3950.dbc.dk:213/danbibv2
+target bagel/gils
+connect
+wait reset
+init
+wait reset
+search @attr 1=4 @attr 2=3 @attr 3=3 @attr 4=1 @attr 5=100 @attr 6=2 "pigen med"
diff --git a/defport.pz b/defport.pz
new file mode 100644 (file)
index 0000000..de0df23
--- /dev/null
@@ -0,0 +1,5 @@
+target www.deff.dk:2102/Default
+connect
+init
+search @attr 1=4 danmarks
+present
diff --git a/eventl.c b/eventl.c
new file mode 100644 (file)
index 0000000..fc188a3
--- /dev/null
+++ b/eventl.c
@@ -0,0 +1,142 @@
+/*
+ * ParaZ - a simple tool for harvesting performance data for parallel
+ * operations using Z39.50.
+ * Copyright (c) 2000-2004 Index Data ApS
+ * See LICENSE file for details.
+ */
+
+/*
+ * $Id: eventl.c,v 1.1 2006-11-14 20:44:37 quinn Exp $
+ * Based on revision YAZ' server/eventl.c 1.29.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <yaz/yconfig.h>
+#include <yaz/log.h>
+#include <yaz/comstack.h>
+#include <yaz/xmalloc.h>
+#include "eventl.h"
+#include <yaz/statserv.h>
+
+IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags)
+{
+    IOCHAN new_iochan;
+
+    if (!(new_iochan = (IOCHAN)xmalloc(sizeof(*new_iochan))))
+       return 0;
+    new_iochan->destroyed = 0;
+    new_iochan->fd = fd;
+    new_iochan->flags = flags;
+    new_iochan->fun = cb;
+    new_iochan->force_event = 0;
+    new_iochan->last_event = new_iochan->max_idle = 0;
+    new_iochan->next = NULL;
+    return new_iochan;
+}
+
+int event_loop(IOCHAN *iochans)
+{
+    do /* loop as long as there are active associations to process */
+    {
+       IOCHAN p, nextp;
+       fd_set in, out, except;
+       int res, max;
+       static struct timeval nullto = {0, 0}, to;
+       struct timeval *timeout;
+
+       FD_ZERO(&in);
+       FD_ZERO(&out);
+       FD_ZERO(&except);
+       timeout = &to; /* hang on select */
+       to.tv_sec = 30;
+       to.tv_usec = 0;
+       max = 0;
+       for (p = *iochans; p; p = p->next)
+       {
+           if (p->force_event)
+               timeout = &nullto;        /* polling select */
+           if (p->flags & EVENT_INPUT)
+               FD_SET(p->fd, &in);
+           if (p->flags & EVENT_OUTPUT)
+               FD_SET(p->fd, &out);
+           if (p->flags & EVENT_EXCEPT)
+               FD_SET(p->fd, &except);
+           if (p->fd > max)
+               max = p->fd;
+       }
+       if ((res = select(max + 1, &in, &out, &except, timeout)) < 0)
+       {
+           if (errno == EINTR)
+               continue;
+            else
+               abort();
+       }
+       for (p = *iochans; p; p = p->next)
+       {
+           int force_event = p->force_event;
+           time_t now = time(0);
+
+           p->force_event = 0;
+           if (!p->destroyed && (FD_ISSET(p->fd, &in) ||
+               force_event == EVENT_INPUT))
+           {
+               p->last_event = now;
+               (*p->fun)(p, EVENT_INPUT);
+           }
+           if (!p->destroyed && (FD_ISSET(p->fd, &out) ||
+               force_event == EVENT_OUTPUT))
+           {
+               p->last_event = now;
+               (*p->fun)(p, EVENT_OUTPUT);
+           }
+           if (!p->destroyed && (FD_ISSET(p->fd, &except) ||
+               force_event == EVENT_EXCEPT))
+           {
+               p->last_event = now;
+               (*p->fun)(p, EVENT_EXCEPT);
+           }
+           if (!p->destroyed && ((p->max_idle && now - p->last_event >
+               p->max_idle) || force_event == EVENT_TIMEOUT))
+           {
+               p->last_event = now;
+               (*p->fun)(p, EVENT_TIMEOUT);
+           }
+       }
+       for (p = *iochans; p; p = nextp)
+       {
+           nextp = p->next;
+
+           if (p->destroyed)
+           {
+               IOCHAN tmp = p, pr;
+
+               /* Now reset the pointers */
+                if (p == *iochans)
+                   *iochans = p->next;
+               else
+               {
+                   for (pr = *iochans; pr; pr = pr->next)
+                       if (pr->next == p)
+                           break;
+                   assert(pr); /* grave error if it weren't there */
+                   pr->next = p->next;
+               }
+               if (nextp == p)
+                   nextp = p->next;
+               xfree(tmp);
+           }
+       }
+    }
+    while (*iochans);
+    return 0;
+}
diff --git a/eventl.h b/eventl.h
new file mode 100644 (file)
index 0000000..b275852
--- /dev/null
+++ b/eventl.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1995-1999, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log: eventl.h,v $
+ * Revision 1.1  2006-11-14 20:44:38  quinn
+ * Initial revision
+ *
+ * Revision 1.1.1.1  2000/02/23 14:40:18  heikki
+ * Original import to cvs
+ *
+ * Revision 1.11  1999/04/20 09:56:48  adam
+ * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
+ * Modified all encoders/decoders to reflect this change.
+ *
+ * Revision 1.10  1998/01/29 13:30:23  adam
+ * Better event handle system for NT/Unix.
+ *
+ * Revision 1.9  1997/09/01 09:31:48  adam
+ * Removed definition statserv_remove from statserv.h to eventl.h.
+ *
+ * Revision 1.8  1995/06/19 12:39:09  quinn
+ * Fixed bug in timeout code. Added BER dumper.
+ *
+ * Revision 1.7  1995/06/16  10:31:34  quinn
+ * Added session timeout.
+ *
+ * Revision 1.6  1995/05/16  08:51:02  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.5  1995/05/15  11:56:37  quinn
+ * Asynchronous facilities. Restructuring of seshigh code.
+ *
+ * Revision 1.4  1995/03/27  08:34:23  quinn
+ * Added dynamic server functionality.
+ * Released bindings to session.c (is now redundant)
+ *
+ * Revision 1.3  1995/03/15  08:37:42  quinn
+ * Now we're pretty much set for nonblocking I/O.
+ *
+ * Revision 1.2  1995/03/14  10:28:00  quinn
+ * More work on demo server.
+ *
+ * Revision 1.1  1995/03/10  18:22:45  quinn
+ * The rudiments of an asynchronous server.
+ *
+ */
+
+#ifndef EVENTL_H
+#define EVENTL_H
+
+#include <time.h>
+
+struct iochan;
+
+typedef void (*IOC_CALLBACK)(struct iochan *i, int event);
+
+typedef struct iochan
+{
+    int fd;
+    int flags;
+#define EVENT_INPUT     0x01
+#define EVENT_OUTPUT    0x02
+#define EVENT_EXCEPT    0x04
+#define EVENT_TIMEOUT   0x08
+#define EVENT_WORK      0x10
+int force_event;
+    IOC_CALLBACK fun;
+    void *data;
+    int destroyed;
+    time_t last_event;
+    time_t max_idle;
+    
+    struct iochan *next;
+} *IOCHAN;
+
+#define iochan_destroy(i) (void)((i)->destroyed = 1)
+#define iochan_getfd(i) ((i)->fd)
+#define iochan_setfd(i, f) ((i)->fd = (f))
+#define iochan_getdata(i) ((i)->data)
+#define iochan_setdata(i, d) ((i)->data = d)
+#define iochan_getflags(i) ((i)->flags)
+#define iochan_setflags(i, d) ((i)->flags = d)
+#define iochan_setflag(i, d) ((i)->flags |= d)
+#define iochan_clearflag(i, d) ((i)->flags &= ~(d))
+#define iochan_getflag(i, d) ((i)->flags & d ? 1 : 0)
+#define iochan_getfun(i) ((i)->fun)
+#define iochan_setfun(i, d) ((i)->fun = d)
+#define iochan_setevent(i, e) ((i)->force_event = (e))
+#define iochan_getnext(i) ((i)->next)
+#define iochan_settimeout(i, t) ((i)->max_idle = (t), (i)->last_event = time(0))
+
+IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags);
+int event_loop(IOCHAN *iochans);
+#endif
diff --git a/h1.pz b/h1.pz
new file mode 100644 (file)
index 0000000..2e2f0fa
--- /dev/null
+++ b/h1.pz
@@ -0,0 +1,9 @@
+target bagel.indexdata.dk/gils
+#target bagel.indexdata.dk:2100/Default
+#target unknown.indexdata.dk
+target localhost:9999/Default
+connect
+wait reset
+init
+search @attr 1=4 utah
+present 2
diff --git a/local.pz b/local.pz
new file mode 100644 (file)
index 0000000..4056d53
--- /dev/null
+++ b/local.pz
@@ -0,0 +1,10 @@
+target bagel.indexdata.dk/gils
+connect
+init
+search @attr 1=4 utah
+present 1
+wait
+present 2
+wait
+present
+wait
\ No newline at end of file
diff --git a/multi.pz b/multi.pz
new file mode 100644 (file)
index 0000000..436f34f
--- /dev/null
+++ b/multi.pz
@@ -0,0 +1,9 @@
+target bagel.indexdata.dk/gils
+target bagel.indexdata.dk/Marc
+target muffin.indexdata.dk:8888/Default
+target muffin.indexdata.dk:9002/E97
+target ximum.indexdata.dk:9999/resolutions
+connect
+init
+search @attr 1=4 utah
+present
diff --git a/multi.txt b/multi.txt
new file mode 100644 (file)
index 0000000..55eb1b0
--- /dev/null
+++ b/multi.txt
@@ -0,0 +1,220 @@
+ 950876489,CONNECTED ,   0.001341, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876489,CONNECTED ,   0.001592, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876489,CONNECTED ,   0.001684, bagel.indexdata.dk/Marc, , 0, 0
+ 950876489,CONNECTED ,   0.001911, bagel.indexdata.dk/gils, , 0, 0
+ 950876489,CONNECTED ,   0.002035, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876489,INIT      ,   0.009192, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876489,INIT      ,   0.024619, bagel.indexdata.dk/Marc, , 0, 0
+ 950876489,INIT      ,   0.026139, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876489,INIT      ,   0.046127, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876489,FAILED    ,   0.046881, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876489,FINISHED  ,   0.047016, bagel.indexdata.dk/Marc, , 0, 0
+ 950876489,FAILED    ,   0.060261, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876489,FINISHED  ,   0.060485, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876489,INIT      ,   0.064298, bagel.indexdata.dk/gils, , 0, 0
+ 950876489,SEARCH    ,   0.083986, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876489,FINISHED  ,   0.084146, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876489,FAILED    ,   0.088662, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876489,FINISHED  ,   0.088829, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876489,SEARCH    ,   0.090702, bagel.indexdata.dk/gils, , 9, 0
+ 950876489,PRESENT   ,   0.126084, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876489,FINISHED  ,   0.126188, bagel.indexdata.dk/gils, , 0, 0
+ 950876489,COMPLETE  ,   0.126206, (all), , 0, 0
+ 950876492,CONNECTED ,   0.000596, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876492,CONNECTED ,   0.000838, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876492,CONNECTED ,   0.000930, bagel.indexdata.dk/Marc, , 0, 0
+ 950876492,CONNECTED ,   0.001110, bagel.indexdata.dk/gils, , 0, 0
+ 950876492,CONNECTED ,   0.001257, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876492,INIT      ,   0.008360, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876492,INIT      ,   0.018452, bagel.indexdata.dk/Marc, , 0, 0
+ 950876492,INIT      ,   0.024710, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876492,FAILED    ,   0.040495, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876492,FINISHED  ,   0.040674, bagel.indexdata.dk/Marc, , 0, 0
+ 950876492,INIT      ,   0.048323, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876492,INIT      ,   0.058978, bagel.indexdata.dk/gils, , 0, 0
+ 950876492,FAILED    ,   0.060665, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876492,FINISHED  ,   0.060778, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876492,SEARCH    ,   0.085355, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876492,FINISHED  ,   0.085575, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876492,SEARCH    ,   0.085628, bagel.indexdata.dk/gils, , 9, 0
+ 950876492,FAILED    ,   0.087761, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876492,FINISHED  ,   0.087854, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876492,PRESENT   ,   0.120268, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876492,FINISHED  ,   0.120381, bagel.indexdata.dk/gils, , 0, 0
+ 950876492,COMPLETE  ,   0.120399, (all), , 0, 0
+ 950876494,CONNECTED ,   0.000545, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876494,CONNECTED ,   0.000790, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876494,CONNECTED ,   0.000881, bagel.indexdata.dk/Marc, , 0, 0
+ 950876494,CONNECTED ,   0.001021, bagel.indexdata.dk/gils, , 0, 0
+ 950876494,CONNECTED ,   0.001220, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876494,INIT      ,   0.008265, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876494,INIT      ,   0.019415, bagel.indexdata.dk/Marc, , 0, 0
+ 950876494,INIT      ,   0.023800, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876494,FAILED    ,   0.041508, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876494,FINISHED  ,   0.041694, bagel.indexdata.dk/Marc, , 0, 0
+ 950876494,INIT      ,   0.046970, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876494,FAILED    ,   0.050530, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876494,FINISHED  ,   0.050647, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876494,INIT      ,   0.058910, bagel.indexdata.dk/gils, , 0, 0
+ 950876494,SEARCH    ,   0.070817, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876494,FINISHED  ,   0.070987, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876494,SEARCH    ,   0.085523, bagel.indexdata.dk/gils, , 9, 0
+ 950876494,FAILED    ,   0.086797, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876494,FINISHED  ,   0.086904, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876494,PRESENT   ,   0.121230, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876494,FINISHED  ,   0.121337, bagel.indexdata.dk/gils, , 0, 0
+ 950876494,COMPLETE  ,   0.121355, (all), , 0, 0
+ 950876496,CONNECTED ,   0.000778, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876496,CONNECTED ,   0.001021, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876496,CONNECTED ,   0.001168, bagel.indexdata.dk/Marc, , 0, 0
+ 950876496,CONNECTED ,   0.001307, bagel.indexdata.dk/gils, , 0, 0
+ 950876496,CONNECTED ,   0.001470, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876496,INIT      ,   0.008356, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876496,INIT      ,   0.018489, bagel.indexdata.dk/Marc, , 0, 0
+ 950876496,INIT      ,   0.025407, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876496,FAILED    ,   0.040572, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876496,FINISHED  ,   0.040706, bagel.indexdata.dk/Marc, , 0, 0
+ 950876496,INIT      ,   0.045839, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876496,INIT      ,   0.057905, bagel.indexdata.dk/gils, , 0, 0
+ 950876496,FAILED    ,   0.058305, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876496,FINISHED  ,   0.058395, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876496,SEARCH    ,   0.082661, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876496,FINISHED  ,   0.082791, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876496,SEARCH    ,   0.085132, bagel.indexdata.dk/gils, , 9, 0
+ 950876496,FAILED    ,   0.088815, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876496,FINISHED  ,   0.088918, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876496,PRESENT   ,   0.119781, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876496,FINISHED  ,   0.119867, bagel.indexdata.dk/gils, , 0, 0
+ 950876496,COMPLETE  ,   0.119884, (all), , 0, 0
+ 950876498,CONNECTED ,   0.000566, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876498,CONNECTED ,   0.000812, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876498,CONNECTED ,   0.000903, bagel.indexdata.dk/Marc, , 0, 0
+ 950876498,CONNECTED ,   0.001005, bagel.indexdata.dk/gils, , 0, 0
+ 950876498,CONNECTED ,   0.001236, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876498,INIT      ,   0.008423, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876498,INIT      ,   0.018266, bagel.indexdata.dk/Marc, , 0, 0
+ 950876498,INIT      ,   0.025240, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876498,FAILED    ,   0.041354, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876498,FINISHED  ,   0.041536, bagel.indexdata.dk/Marc, , 0, 0
+ 950876498,INIT      ,   0.047206, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876498,FAILED    ,   0.052106, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876498,FINISHED  ,   0.052232, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876498,INIT      ,   0.058767, bagel.indexdata.dk/gils, , 0, 0
+ 950876498,SEARCH    ,   0.076203, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876498,FINISHED  ,   0.076352, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876498,SEARCH    ,   0.085108, bagel.indexdata.dk/gils, , 9, 0
+ 950876498,FAILED    ,   0.085488, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876498,FINISHED  ,   0.085584, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876498,PRESENT   ,   0.134660, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876498,FINISHED  ,   0.134770, bagel.indexdata.dk/gils, , 0, 0
+ 950876498,COMPLETE  ,   0.134788, (all), , 0, 0
+ 950876500,CONNECTED ,   0.001486, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876500,CONNECTED ,   0.001957, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876500,CONNECTED ,   0.002047, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876500,CONNECTED ,   0.002151, bagel.indexdata.dk/Marc, , 0, 0
+ 950876500,CONNECTED ,   0.002239, bagel.indexdata.dk/gils, , 0, 0
+ 950876500,INIT      ,   0.008435, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876500,INIT      ,   0.019691, bagel.indexdata.dk/Marc, , 0, 0
+ 950876500,INIT      ,   0.026277, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876500,FAILED    ,   0.041745, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876500,FINISHED  ,   0.041963, bagel.indexdata.dk/Marc, , 0, 0
+ 950876500,INIT      ,   0.045740, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876500,FAILED    ,   0.057801, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876500,FINISHED  ,   0.057956, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876500,INIT      ,   0.059066, bagel.indexdata.dk/gils, , 0, 0
+ 950876500,SEARCH    ,   0.082227, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876500,FINISHED  ,   0.082353, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876500,SEARCH    ,   0.086360, bagel.indexdata.dk/gils, , 9, 0
+ 950876500,FAILED    ,   0.087483, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876500,FINISHED  ,   0.087572, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876500,PRESENT   ,   0.140876, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876500,FINISHED  ,   0.140986, bagel.indexdata.dk/gils, , 0, 0
+ 950876500,COMPLETE  ,   0.141004, (all), , 0, 0
+ 950876502,CONNECTED ,   0.000538, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876502,CONNECTED ,   0.000788, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876502,CONNECTED ,   0.000878, bagel.indexdata.dk/Marc, , 0, 0
+ 950876502,CONNECTED ,   0.001104, bagel.indexdata.dk/gils, , 0, 0
+ 950876502,CONNECTED ,   0.001210, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876502,INIT      ,   0.008454, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876502,INIT      ,   0.018353, bagel.indexdata.dk/Marc, , 0, 0
+ 950876502,INIT      ,   0.024693, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876502,FAILED    ,   0.040460, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876502,FINISHED  ,   0.040658, bagel.indexdata.dk/Marc, , 0, 0
+ 950876502,INIT      ,   0.045000, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876502,FAILED    ,   0.060012, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876502,FINISHED  ,   0.060171, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876502,INIT      ,   0.069047, bagel.indexdata.dk/gils, , 0, 0
+ 950876502,SEARCH    ,   0.083532, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876502,FINISHED  ,   0.083687, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876502,FAILED    ,   0.087489, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876502,FINISHED  ,   0.087666, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876502,SEARCH    ,   0.095443, bagel.indexdata.dk/gils, , 9, 0
+ 950876502,PRESENT   ,   0.131127, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876502,FINISHED  ,   0.131228, bagel.indexdata.dk/gils, , 0, 0
+ 950876502,COMPLETE  ,   0.131246, (all), , 0, 0
+ 950876505,CONNECTED ,   0.000569, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876505,CONNECTED ,   0.000819, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876505,CONNECTED ,   0.000908, bagel.indexdata.dk/Marc, , 0, 0
+ 950876505,CONNECTED ,   0.001122, bagel.indexdata.dk/gils, , 0, 0
+ 950876505,CONNECTED ,   0.001227, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876505,INIT      ,   0.008352, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876505,INIT      ,   0.024935, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876505,INIT      ,   0.033138, bagel.indexdata.dk/Marc, , 0, 0
+ 950876505,INIT      ,   0.042941, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876505,FAILED    ,   0.056214, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876505,FINISHED  ,   0.056397, bagel.indexdata.dk/Marc, , 0, 0
+ 950876505,FAILED    ,   0.057998, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876505,FINISHED  ,   0.058145, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876505,INIT      ,   0.073656, bagel.indexdata.dk/gils, , 0, 0
+ 950876505,SEARCH    ,   0.082495, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876505,FINISHED  ,   0.082632, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876505,FAILED    ,   0.088327, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876505,FINISHED  ,   0.088488, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876505,SEARCH    ,   0.100023, bagel.indexdata.dk/gils, , 9, 0
+ 950876505,PRESENT   ,   0.135071, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876505,FINISHED  ,   0.135178, bagel.indexdata.dk/gils, , 0, 0
+ 950876505,COMPLETE  ,   0.135196, (all), , 0, 0
+ 950876507,CONNECTED ,   0.000567, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876507,CONNECTED ,   0.000813, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876507,CONNECTED ,   0.000902, bagel.indexdata.dk/Marc, , 0, 0
+ 950876507,CONNECTED ,   0.001112, bagel.indexdata.dk/gils, , 0, 0
+ 950876507,CONNECTED ,   0.001218, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876507,INIT      ,   0.008370, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876507,INIT      ,   0.016265, bagel.indexdata.dk/Marc, , 0, 0
+ 950876507,INIT      ,   0.026364, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876507,FAILED    ,   0.038337, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876507,FINISHED  ,   0.038532, bagel.indexdata.dk/Marc, , 0, 0
+ 950876507,INIT      ,   0.045492, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876507,INIT      ,   0.055726, bagel.indexdata.dk/gils, , 0, 0
+ 950876507,FAILED    ,   0.059609, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876507,FINISHED  ,   0.059735, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876507,SEARCH    ,   0.082128, bagel.indexdata.dk/gils, , 9, 0
+ 950876507,SEARCH    ,   0.083731, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876507,FINISHED  ,   0.083835, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876507,FAILED    ,   0.104254, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876507,FINISHED  ,   0.104440, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876507,PRESENT   ,   0.118206, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876507,FINISHED  ,   0.118315, bagel.indexdata.dk/gils, , 0, 0
+ 950876507,COMPLETE  ,   0.118333, (all), , 0, 0
+ 950876509,CONNECTED ,   0.003709, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876509,CONNECTED ,   0.004189, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876509,CONNECTED ,   0.004281, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876509,CONNECTED ,   0.004387, bagel.indexdata.dk/Marc, , 0, 0
+ 950876509,CONNECTED ,   0.004512, bagel.indexdata.dk/gils, , 0, 0
+ 950876509,INIT      ,   0.008799, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876509,INIT      ,   0.028480, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876509,INIT      ,   0.032066, bagel.indexdata.dk/Marc, , 0, 0
+ 950876509,INIT      ,   0.045047, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876509,FAILED    ,   0.055137, bagel.indexdata.dk/Marc, search error, 0, 0
+ 950876509,FINISHED  ,   0.055310, bagel.indexdata.dk/Marc, , 0, 0
+ 950876509,FAILED    ,   0.056695, muffin.indexdata.dk:9002/E97, search error, 0, 0
+ 950876509,FINISHED  ,   0.056838, muffin.indexdata.dk:9002/E97, , 0, 0
+ 950876509,INIT      ,   0.072675, bagel.indexdata.dk/gils, , 0, 0
+ 950876509,SEARCH    ,   0.081390, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876509,FINISHED  ,   0.081532, muffin.indexdata.dk:8888/Default, , 0, 0
+ 950876509,FAILED    ,   0.087422, ximum.indexdata.dk:9999/resolutions, search error, 0, 0
+ 950876509,FINISHED  ,   0.087590, ximum.indexdata.dk:9999/resolutions, , 0, 0
+ 950876509,SEARCH    ,   0.099116, bagel.indexdata.dk/gils, , 9, 0
+ 950876509,PRESENT   ,   0.134118, bagel.indexdata.dk/gils, failed, 0, 0
+ 950876509,FINISHED  ,   0.134221, bagel.indexdata.dk/gils, , 0, 0
+ 950876509,COMPLETE  ,   0.134239, (all), , 0, 0
diff --git a/pazpar2.c b/pazpar2.c
new file mode 100644 (file)
index 0000000..b003664
--- /dev/null
+++ b/pazpar2.c
@@ -0,0 +1,643 @@
+/* $Id: pazpar2.c,v 1.1 2006-11-14 20:44:38 quinn Exp $ */
+
+
+#define PAZPAR2_VERSION "0.1"
+#define MAX_DATABASES 512
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <signal.h>
+
+#include <yaz/comstack.h>
+#include <yaz/tcpip.h>
+#include <yaz/proto.h>
+#include <yaz/readconf.h>
+#include <yaz/pquery.h>
+#include <yaz/yaz-util.h>
+
+#include "pazpar2.h"
+#include "eventl.h"
+#include "command.h"
+
+char *myname;
+static long int runId=-1;
+
+struct target
+{
+    struct session *session;
+    char fullname[256];
+    char hostport[128];
+    char *ibuf;
+    int ibufsize;
+    char databases[MAX_DATABASES][128];
+    COMSTACK link;
+    ODR odr_in, odr_out;
+    struct target *next;
+    void *addr;
+    int hits;
+    int records;
+    int setno;
+    int requestid;                              // ID of current outstanding request
+    int diagnostic;
+    enum target_state
+    {
+       No_connection,
+        Connecting,
+        Connected,
+        Initializing,
+        Searching,
+        Presenting,
+        Error,
+       Idle,
+        Failed
+    } state;
+};
+
+static char *state_strings[] = {
+    "No_connection",
+    "Connecting",
+    "Connected",
+    "Initializing",
+    "Searching",
+    "Presenting",
+    "Error",
+    "Idle",
+    "Failed"
+};
+
+
+IOCHAN channel_list = 0;
+
+static struct parameters {
+    int timeout;               /* operations timeout, in seconds */
+    char implementationId[128];
+    char implementationName[128];
+    char implementationVersion[128];
+    struct timeval base_time;
+    int toget;
+    int chunk;
+} global_parameters = 
+{
+    30,
+    "81",
+    "Index Data PazPar2 (MasterKey)",
+    PAZPAR2_VERSION,
+    {0,0},
+    100,
+    10
+};
+
+
+static int send_apdu(struct target *t, Z_APDU *a)
+{
+    char *buf;
+    int len, r;
+
+    if (!z_APDU(t->odr_out, &a, 0, 0))
+    {
+        odr_perror(t->odr_out, "Encoding APDU");
+       abort();
+    }
+    buf = odr_getbuf(t->odr_out, &len, 0);
+    r = cs_put(t->link, buf, len);
+    if (r < 0)
+    {
+        yaz_log(YLOG_WARN, "cs_put: %s", cs_errmsg(cs_errno(t->link)));
+        return -1;
+    }
+    else if (r == 1)
+    {
+        fprintf(stderr, "cs_put incomplete (ParaZ does not handle that)\n");
+    }
+    odr_reset(t->odr_out); /* release the APDU structure  */
+    return 0;
+}
+
+
+static void send_init(IOCHAN i)
+{
+    struct target *t = iochan_getdata(i);
+    Z_APDU *a = zget_APDU(t->odr_out, Z_APDU_initRequest);
+
+    a->u.initRequest->implementationId = global_parameters.implementationId;
+    a->u.initRequest->implementationName = global_parameters.implementationName;
+    a->u.initRequest->implementationVersion =
+       global_parameters.implementationVersion;
+    ODR_MASK_SET(a->u.initRequest->options, Z_Options_search);
+    ODR_MASK_SET(a->u.initRequest->options, Z_Options_present);
+    ODR_MASK_SET(a->u.initRequest->options, Z_Options_namedResultSets);
+
+    ODR_MASK_SET(a->u.initRequest->protocolVersion, Z_ProtocolVersion_1);
+    ODR_MASK_SET(a->u.initRequest->protocolVersion, Z_ProtocolVersion_2);
+    ODR_MASK_SET(a->u.initRequest->protocolVersion, Z_ProtocolVersion_3);
+    if (send_apdu(t, a) >= 0)
+    {
+       iochan_setflags(i, EVENT_INPUT);
+       t->state = Initializing;
+    }
+    else
+    {
+       iochan_destroy(i);
+       t->state = Failed;
+       cs_close(t->link);
+    }
+}
+
+static void send_search(IOCHAN i)
+{
+    struct target *t = iochan_getdata(i);
+    struct session *s = t->session;
+    Z_APDU *a = zget_APDU(t->odr_out, Z_APDU_searchRequest);
+    int ndb;
+    char **databaselist;
+    Z_Query *zquery;
+
+    yaz_log(YLOG_DEBUG, "Sending search");
+    a->u.searchRequest->query = zquery = odr_malloc(t->odr_out, sizeof(Z_Query));
+    zquery->which = Z_Query_type_1;
+    zquery->u.type_1 = p_query_rpn(t->odr_out, PROTO_Z3950, s->query);
+
+    for (ndb = 0; *t->databases[ndb]; ndb++)
+       ;
+    databaselist = odr_malloc(t->odr_out, sizeof(char*) * ndb);
+    for (ndb = 0; *t->databases[ndb]; ndb++)
+       databaselist[ndb] = t->databases[ndb];
+
+    a->u.searchRequest->resultSetName = "Default";
+    a->u.searchRequest->databaseNames = databaselist;
+    a->u.searchRequest->num_databaseNames = ndb;
+
+    if (send_apdu(t, a) >= 0)
+    {
+       iochan_setflags(i, EVENT_INPUT);
+       t->state = Searching;
+        t->requestid = s->requestid;
+    }
+    else
+    {
+       iochan_destroy(i);
+       t->state = Failed;
+       cs_close(t->link);
+    }
+    odr_reset(t->odr_out);
+}
+
+static void send_present(IOCHAN i)
+{
+    struct target *t = iochan_getdata(i);
+    Z_APDU *a = zget_APDU(t->odr_out, Z_APDU_presentRequest);
+    int toget;
+
+    toget = global_parameters.chunk;
+    if (toget > t->hits - t->records)
+       toget = t->hits - t->records;
+
+    yaz_log(YLOG_DEBUG, "Trying to present %d records\n", toget);
+
+    a->u.presentRequest->numberOfRecordsRequested = &toget;
+
+    a->u.presentRequest->resultSetId = "Default";
+
+    if (send_apdu(t, a) >= 0)
+    {
+       iochan_setflags(i, EVENT_INPUT);
+       t->state = Presenting;
+    }
+    else
+    {
+       iochan_destroy(i);
+       t->state = Failed;
+       cs_close(t->link);
+    }
+    odr_reset(t->odr_out);
+}
+
+static void do_initResponse(IOCHAN i, Z_APDU *a)
+{
+    struct target *t = iochan_getdata(i);
+    Z_InitResponse *r = a->u.initResponse;
+
+    yaz_log(YLOG_DEBUG, "Received init response");
+
+    if (*r->result)
+    {
+       t->state = Idle;
+    }
+    else
+    {
+       t->state = Failed;
+       iochan_destroy(i);
+       cs_close(t->link);
+    }
+}
+
+#if 0
+static char *search_geterror(Z_SearchRequest *r)
+{
+#endif
+    
+
+static void do_searchResponse(IOCHAN i, Z_APDU *a)
+{
+    struct target *t = iochan_getdata(i);
+    Z_SearchResponse *r = a->u.searchResponse;
+
+    yaz_log(YLOG_DEBUG, "Searchresponse (status=%d)", *r->searchStatus);
+
+    if (*r->searchStatus)
+    {
+       t->hits = *r->resultCount;
+        t->state = Idle;
+    }
+    else
+    {          /*"FAILED"*/
+       t->hits = 0;
+        t->state = Failed;
+        if (r->records) {
+            Z_Records *recs = r->records;
+            if (recs->which == Z_Records_NSD)
+            {
+                yaz_log(YLOG_WARN, "Non-surrogate diagnostic");
+                t->diagnostic = *recs->u.nonSurrogateDiagnostic->condition;
+                t->state = Error;
+            }
+        }
+    }
+}
+
+// FIXME Catch present errors!!!!!!!
+static void do_presentResponse(IOCHAN i, Z_APDU *a)
+{
+    struct target *t = iochan_getdata(i);
+    Z_PresentResponse *r = a->u.presentResponse;
+
+    if (r->records) {
+        Z_Records *recs = r->records;
+        if (recs->which == Z_Records_NSD)
+        {
+            yaz_log(YLOG_WARN, "Non-surrogate diagnostic");
+            t->diagnostic = *recs->u.nonSurrogateDiagnostic->condition;
+            t->state = Error;
+        }
+        else
+        {
+            yaz_log(YLOG_DEBUG, "Got Records!");
+        }
+    }
+
+    if (!*r->presentStatus && t->state != Error)
+    {
+        yaz_log(YLOG_DEBUG, "Good Present response");
+        t->records += *r->numberOfRecordsReturned;
+        t->state = Idle;
+    }
+    else if (*r->presentStatus) 
+    {
+        yaz_log(YLOG_WARN, "Bad Present response");
+        t->state = Error;
+    }
+}
+
+static void handler(IOCHAN i, int event)
+{
+    struct target *t = iochan_getdata(i);
+    struct session *s = t->session;
+    //static int waiting = 0;
+
+    if (t->state == No_connection) /* Start connection */
+    {
+       int res = cs_connect(t->link, t->addr);
+
+       t->state = Connecting;
+       if (!res) /* we are go */
+           iochan_setevent(i, EVENT_OUTPUT);
+       else if (res == 1)
+           iochan_setflags(i, EVENT_OUTPUT);
+       else
+       {
+           yaz_log(YLOG_WARN|YLOG_ERRNO, "ERROR %s connect\n", t->hostport);
+           cs_close(t->link);
+           t->state = Failed;
+           iochan_destroy(i);
+       }
+    }
+
+    else if (t->state == Connecting && event & EVENT_OUTPUT)
+    {
+       int errcode;
+        socklen_t errlen = sizeof(errcode);
+
+       if (getsockopt(cs_fileno(t->link), SOL_SOCKET, SO_ERROR, &errcode,
+           &errlen) < 0 || errcode != 0)
+       {
+           cs_close(t->link);
+           iochan_destroy(i);
+           t->state = Failed;
+           return;
+       }
+       else
+       {
+            yaz_log(YLOG_DEBUG, "Connect OK");
+           t->state = Connected;
+       }
+    }
+
+    else if (event & EVENT_INPUT)
+    {
+       int len = cs_get(t->link, &t->ibuf, &t->ibufsize);
+
+       if (len < 0)
+       {
+           cs_close(t->link);
+           iochan_destroy(i);
+           t->state = Failed;
+           return;
+       }
+       if (len == 0)
+       {
+           cs_close(t->link);
+           iochan_destroy(i);
+           t->state = Failed;
+           return;
+       }
+       else if (len > 1)
+       {
+            if (t->requestid == s->requestid || t->state == Initializing) 
+            {
+                Z_APDU *a;
+
+                odr_reset(t->odr_in);
+                odr_setbuf(t->odr_in, t->ibuf, len, 0);
+                if (!z_APDU(t->odr_in, &a, 0, 0))
+                {
+                    cs_close(t->link);
+                    iochan_destroy(i);
+                    t->state = Failed;
+                    return;
+                }
+                switch (a->which)
+                {
+                    case Z_APDU_initResponse:
+                        do_initResponse(i, a);
+                        break;
+                    case Z_APDU_searchResponse:
+                        do_searchResponse(i, a);
+                        break;
+                    case Z_APDU_presentResponse:
+                        do_presentResponse(i, a);
+                        break;
+                    default:
+                        yaz_log(YLOG_WARN, "Unexpected result from server");
+                        cs_close(t->link);
+                        iochan_destroy(i);
+                        t->state = Failed;
+                        return;
+                }
+                // if (cs_more(t->link))
+                //    iochan_setevent(i, EVENT_INPUT);
+            }
+            else  // we throw away response and go to idle mode
+                t->state = Idle;
+       }
+       /* if len==1 we do nothing but wait for more input */
+    }
+
+    else if (t->state == Connected) {
+        send_init(i);
+    }
+
+    if (t->state == Idle)
+    {
+        if (t->requestid != s->requestid) {
+            send_search(i);
+        }
+        else if (t->hits > 0 && t->records < global_parameters.toget &&
+            t->records < t->hits) {
+            send_present(i);
+        }
+    }
+}
+
+int load_targets(struct session *s, const char *fn)
+{
+    FILE *f = fopen(fn, "r");
+    char line[256];
+    struct target **target_p;
+
+    if (!f)
+    {
+        yaz_log(YLOG_WARN|YLOG_ERRNO, "open %s", fn);
+        return -1;
+    }
+
+    target_p = &s->targets;
+    while (fgets(line, 255, f))
+    {
+        char *url, *p;
+        struct target *target;
+        IOCHAN new;
+
+        if (strncmp(line, "target ", 7))
+            continue;
+        url = line + 7;
+        url[strlen(url) - 1] = '\0';
+        yaz_log(LOG_DEBUG, "Target: %s", url);
+
+        *target_p = target = xmalloc(sizeof(**target_p));
+        target->next = 0;
+        target_p = &target->next;
+        target->state = No_connection;
+        target->ibuf = 0;
+        target->ibufsize = 0;
+        target->odr_in = odr_createmem(ODR_DECODE);
+        target->odr_out = odr_createmem(ODR_ENCODE);
+        target->hits = -1;
+        target->setno = 0;
+        target->session = s;
+        target->requestid = -1;
+        target->records = 0;
+        target->diagnostic = 0;
+        strcpy(target->fullname, url);
+        if ((p = strchr(url, '/')))
+        {                  
+            *p = '\0';
+            strcpy(target->hostport, url);
+            *p = '/';
+            p++;
+            strcpy(target->databases[0], p);
+            target->databases[1][0] = '\0';
+        }
+        else
+        {
+            strcpy(target->hostport, url);
+            strcpy(target->databases[0], "Default");
+            target->databases[1][0] = '\0';
+        }
+
+       if (!(target->link = cs_create(tcpip_type, 0, PROTO_Z3950)))
+        {
+           yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create comstack");
+            exit(1);
+        }
+       if (!(target->addr = cs_straddr(target->link, target->hostport)))
+       {
+           printf("ERROR %s bad-address", target->hostport);
+           target->state = Failed;
+           continue;
+       }
+       new = iochan_create(cs_fileno(target->link), handler, 0);
+       iochan_setdata(new, target);
+       iochan_setevent(new, EVENT_EXCEPT);
+       new->next = channel_list;
+       channel_list = new;
+    }
+    fclose(f);
+
+    return 0;
+}
+
+void search(struct session *s, char *query)
+{
+    IOCHAN c;
+
+    yaz_log(YLOG_DEBUG, "Search");
+
+    // Determine what iochans belong to this session
+    // It might have been better to have a list of them
+
+    strcpy(s->query, query);
+    s->requestid++;
+    nmem_reset(s->nmem);
+    for (c = channel_list; c; c = c->next)
+    {
+        struct target *t;
+
+        if (iochan_getfun(c) != handler) // Not a Z target
+            continue;
+        t = iochan_getdata(c);
+        if (t->session == s)
+        {
+            t->hits = -1;
+            t->records = 0;
+            t->diagnostic = 0;
+
+            if (t->state == Error)
+                t->state = Idle;
+
+            if (t->state == Idle) 
+                iochan_setflag(c, EVENT_OUTPUT);
+        }
+    }
+}
+
+struct session *new_session() 
+{
+    struct session *session = xmalloc(sizeof(*session));
+
+    yaz_log(YLOG_DEBUG, "New pazpar2 session");
+    
+    session->requestid = -1;
+    session->targets = 0;
+    session->pqf_parser = yaz_pqf_create();
+    session->query[0] = '\0';
+    session->nmem = nmem_create();
+
+    return session;
+}
+
+struct hitsbytarget *hitsbytarget(struct session *s, int *count)
+{
+    static struct hitsbytarget res[1000]; // FIXME MM
+    IOCHAN c;
+
+    *count = 0;
+    for (c = channel_list; c; c = c->next)
+        if (iochan_getfun(c) == handler)
+        {
+            struct target *t = iochan_getdata(c);
+            if (t->session == s)
+            {
+                strcpy(res[*count].id, t->hostport);
+                res[*count].hits = t->hits;
+                res[*count].records = t->records;
+                res[*count].diagnostic = t->diagnostic;
+                res[*count].state = state_strings[(int) t->state];
+                (*count)++;
+            }
+        }
+
+    return res;
+}
+
+
+void statistics(struct session *s, struct statistics *stat)
+{
+    IOCHAN c;
+    int i;
+
+    bzero(stat, sizeof(*stat));
+    for (i = 0, c = channel_list; c; i++, c = c->next)
+    {
+        struct target *t;
+        if (iochan_getfun(c) != handler)
+            continue;
+        t = iochan_getdata(c);
+        switch (t->state)
+        {
+            case No_connection: stat->num_no_connection++; break;
+            case Connecting: stat->num_connecting++; break;
+            case Initializing: stat->num_initializing++; break;
+            case Searching: stat->num_searching++; break;
+            case Presenting: stat->num_presenting++; break;
+            case Idle: stat->num_idle++; break;
+            case Failed: stat->num_failed++; break;
+            case Error: stat->num_error++; break;
+            default: break;
+        }
+    }
+
+    stat->num_connections = i;
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    char *arg;
+
+    if (signal(SIGPIPE, SIG_IGN) < 0)
+        yaz_log(YLOG_WARN|YLOG_ERRNO, "signal");
+
+    myname = argv[0];
+    yaz_log_init(YLOG_DEFAULT_LEVEL|YLOG_DEBUG, "pazpar2", 0);
+
+    while ((ret = options("c:", argv, argc, &arg)) != -2)
+    {
+       switch (ret) {
+           case 0:
+               break;
+           case 'c':
+               command_init(atoi(arg));
+               break;
+           default:
+               fprintf(stderr, "Usage: pazpar2 -d comport");
+               exit(1);
+       }
+           
+    }
+
+    event_loop(&channel_list);
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/pazpar2.h b/pazpar2.h
new file mode 100644 (file)
index 0000000..1e22b78
--- /dev/null
+++ b/pazpar2.h
@@ -0,0 +1,57 @@
+#ifndef PAZPAR2_H
+#define PAZPAR2_H
+
+#include <yaz/pquery.h>
+
+struct session {
+    struct target *targets;
+    YAZ_PQF_Parser pqf_parser;
+    int requestid; 
+    char query[1024];
+    NMEM nmem;
+};
+
+struct record {
+    struct target *target;
+    int target_offset;
+    char *buf;
+    char *merge_key;
+    struct record *next_cluster;
+    struct record *head_cluster;
+};
+
+struct statistics {
+    int num_connections;
+    int num_no_connection;
+    int num_connecting;
+    int num_initializing;
+    int num_searching;
+    int num_presenting;
+    int num_idle;
+    int num_failed;
+    int num_error;
+};
+
+struct hitsbytarget {
+    char id[256];
+    int hits;
+    int diagnostic;
+    int records;
+    char* state;
+};
+
+struct hitsbytarget *hitsbytarget(struct session *s, int *count);
+struct session *new_session();
+int load_targets(struct session *s, const char *fn);
+void statistics(struct session *s, struct statistics *stat);
+void search(struct session *s, char *query);
+
+#endif
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/test.pz b/test.pz
new file mode 100644 (file)
index 0000000..0fb10c8
--- /dev/null
+++ b/test.pz
@@ -0,0 +1 @@
+target localhost:9999/Default
diff --git a/util.c b/util.c
new file mode 100644 (file)
index 0000000..a92d340
--- /dev/null
+++ b/util.c
@@ -0,0 +1,13 @@
+/* $Id: util.c,v 1.1 2006-11-14 20:44:38 quinn Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern char *myname;
+
+void die(char *string, char *add)
+{
+    fprintf(stderr, "%s: %s (%s)\n", myname, string, add ? add : "");
+    abort();
+}
+
diff --git a/util.h b/util.h
new file mode 100644 (file)
index 0000000..10f7981
--- /dev/null
+++ b/util.h
@@ -0,0 +1,8 @@
+/* $Id: util.h,v 1.1 2006-11-14 20:44:38 quinn Exp $ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+void die(char *string, char *add);
+
+#endif