Implement pazpar2_play utility
authorAdam Dickmeiss <adam@indexdata.dk>
Sat, 26 Mar 2011 21:59:37 +0000 (22:59 +0100)
committerAdam Dickmeiss <adam@indexdata.dk>
Sat, 26 Mar 2011 21:59:37 +0000 (22:59 +0100)
This will read the HTTP request file that is generated by Pazpar2
when option -R is used. At this point, the timings are not used
(all requests executed without pause).

src/.gitignore
src/Makefile.am
src/pazpar2_play.c [new file with mode: 0644]

index b810359..1430d65 100644 (file)
@@ -1,5 +1,6 @@
 yaz
 pazpar2
+pazpar2_play
 Makefile
 Makefile.in
 config.h
index 5ff1aa8..c956188 100644 (file)
@@ -1,6 +1,7 @@
 # This file is part of Pazpar2.
 
 sbin_PROGRAMS = pazpar2
+noinst_PROGRAMS = pazpar2_play
 
 EXTRA_DIST = pazpar2.rpm.init pazpar2.rpm.logrotate
 
@@ -34,6 +35,9 @@ libpazpar2_a_SOURCES = pazpar2_config.c pazpar2_config.h eventl.c eventl.h \
 pazpar2_SOURCES = pazpar2.c
 pazpar2_LDADD = libpazpar2.a $(YAZLIB)
 
+pazpar2_play_SOURCES = pazpar2_play.c
+pazpar2_play_LDADD = $(YAZLIB)
+
 test_sel_thread_SOURCES = test_sel_thread.c
 test_sel_thread_LDADD = libpazpar2.a $(YAZLIB)
 
diff --git a/src/pazpar2_play.c b/src/pazpar2_play.c
new file mode 100644 (file)
index 0000000..298a3d3
--- /dev/null
@@ -0,0 +1,231 @@
+/* This file is part of Pazpar2.
+   Copyright (C) 2006-2011 Index Data
+
+Pazpar2 is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <yaz/options.h>
+#include <yaz/log.h>
+#include <yaz/xmalloc.h>
+
+struct con {
+    int fd;
+    long long id;
+    struct con *next;
+};
+
+
+static int run(FILE *inf, struct addrinfo *res)
+{
+    long long tv_sec0;
+    long long tv_usec0;
+    struct con *cons = 0;
+    while (1)
+    {
+        long long tv_sec1;
+        long long tv_usec1;
+        long long id;
+        int sz, r, c;
+        char req[100];
+        size_t i;
+        struct con **conp;
+        c = fgetc(inf);
+        if (c == EOF)
+            break;
+
+        for (i = 0; c != '\n' && i < (sizeof(req)-2); i++)
+        {
+            req[i] = c;
+            c = fgetc(inf);
+        }
+        req[i] = 0;
+        r = sscanf(req, "%lld %lld %lld %d", &tv_sec1, &tv_usec1, &id, &sz);
+        if (r != 4)
+        {
+            fprintf(stderr, "bad line %s\n", req);
+            return -1;
+        }
+        for (conp = &cons; *conp; conp = &(*conp)->next)
+            if ((*conp)->id == id)
+                break;
+        if (!*conp)
+        {
+            struct addrinfo *rp;
+            int r, fd = -1;
+            for (rp = res; rp; rp = rp->ai_next)
+            {
+                fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+                if (fd != -1)
+                    break;
+            }
+            if (fd == -1)
+            {
+                fprintf(stderr, "socket: cannot create\n");
+                return -1;
+            }
+            r = connect(fd, rp->ai_addr, rp->ai_addrlen);
+            if (r)
+            {
+                fprintf(stderr, "socket: cannot connect\n");
+                return -1;
+            }
+
+            *conp = xmalloc(sizeof(**conp));
+            (*conp)->id = id;
+            (*conp)->fd = fd;
+            (*conp)->next = 0;
+        }
+        if (sz == 0)
+        {
+            struct con *c = *conp;
+            *conp = c->next;
+            close(c->fd);
+            xfree(c);
+        }
+        else
+        {
+            size_t cnt = 0;
+            while (cnt < sz)
+            {
+                char buf[1024];
+                ssize_t w;
+                size_t r;
+                size_t toread = sz - cnt;
+
+                if (toread > sizeof(buf))
+                    toread = sizeof(buf);
+                r = fread(buf, 1, toread, inf);
+                if (r != toread)
+                {
+                    fprintf(stderr, "fread truncated. toread=%lld r=%lld\n",
+                            (long long) toread, (long long) r);
+                    return -1;
+                }
+                w = write((*conp)->fd, buf, toread);
+                if (w != toread)
+                {
+                    fprintf(stderr, "write truncated\n");
+                    return -1;
+                }
+                cnt += toread;
+            }
+        }
+    }
+    return 0;
+}
+
+static void usage(void)
+{
+    fprintf(stderr, "Usage: pazpar2_play infile host\n"
+            "    -v level                Set log level\n");
+    exit(1);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+    char *arg;
+    char *host = 0;
+    const char *file = 0;
+    while ((ret = options("v:", argv, argc, &arg)) != -2)
+    {
+       switch (ret)
+        {
+        case 'v':
+            yaz_log_init_level(yaz_log_mask_str(arg));
+            break;
+        case 0:
+            if (!file)
+                file = arg;
+            else if (!host)
+                host = xstrdup(arg);
+            else
+            {
+                usage();
+            }
+            break;
+        default:
+            usage();
+            exit(1);
+       }
+    }
+    if (host && file)
+    {
+        char *port;
+        char *cp;
+        FILE *inf;
+
+        struct addrinfo hints, *res;
+        hints.ai_flags = 0;
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+        hints.ai_protocol = 0;
+        hints.ai_addrlen        = 0;
+        hints.ai_addr           = NULL;
+        hints.ai_canonname      = NULL;
+        hints.ai_next           = NULL;
+    
+        cp = strchr(host, ':');
+        if (*cp)
+        {
+            *cp = 0;
+            port = cp+1;
+        }
+        else
+        {
+            port = "80";
+        }
+        if (getaddrinfo(host, port, &hints, &res))
+        {
+            fprintf(stderr, "cannot resolve %s:%s\n", host, port);
+            exit(1);
+        }
+
+        inf = fopen(file, "rb");
+        if (!inf)
+        {
+            fprintf(stderr, "cannot open %s\n", file);
+            exit(1);
+        }
+        run(inf, res);
+        fclose(inf);
+    }
+    else
+        usage();
+    return 0;
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+