Implement pazpar2_play utility
[pazpar2-moved-to-github.git] / src / pazpar2_play.c
1 /* This file is part of Pazpar2.
2    Copyright (C) 2006-2011 Index Data
3
4 Pazpar2 is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netdb.h>
28 #include <unistd.h>
29 #include <string.h>
30
31 #include <yaz/options.h>
32 #include <yaz/log.h>
33 #include <yaz/xmalloc.h>
34
35 struct con {
36     int fd;
37     long long id;
38     struct con *next;
39 };
40
41
42 static int run(FILE *inf, struct addrinfo *res)
43 {
44     long long tv_sec0;
45     long long tv_usec0;
46     struct con *cons = 0;
47     while (1)
48     {
49         long long tv_sec1;
50         long long tv_usec1;
51         long long id;
52         int sz, r, c;
53         char req[100];
54         size_t i;
55         struct con **conp;
56         c = fgetc(inf);
57         if (c == EOF)
58             break;
59
60         for (i = 0; c != '\n' && i < (sizeof(req)-2); i++)
61         {
62             req[i] = c;
63             c = fgetc(inf);
64         }
65         req[i] = 0;
66         r = sscanf(req, "%lld %lld %lld %d", &tv_sec1, &tv_usec1, &id, &sz);
67         if (r != 4)
68         {
69             fprintf(stderr, "bad line %s\n", req);
70             return -1;
71         }
72         for (conp = &cons; *conp; conp = &(*conp)->next)
73             if ((*conp)->id == id)
74                 break;
75         if (!*conp)
76         {
77             struct addrinfo *rp;
78             int r, fd = -1;
79             for (rp = res; rp; rp = rp->ai_next)
80             {
81                 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
82                 if (fd != -1)
83                     break;
84             }
85             if (fd == -1)
86             {
87                 fprintf(stderr, "socket: cannot create\n");
88                 return -1;
89             }
90             r = connect(fd, rp->ai_addr, rp->ai_addrlen);
91             if (r)
92             {
93                 fprintf(stderr, "socket: cannot connect\n");
94                 return -1;
95             }
96
97             *conp = xmalloc(sizeof(**conp));
98             (*conp)->id = id;
99             (*conp)->fd = fd;
100             (*conp)->next = 0;
101         }
102         if (sz == 0)
103         {
104             struct con *c = *conp;
105             *conp = c->next;
106             close(c->fd);
107             xfree(c);
108         }
109         else
110         {
111             size_t cnt = 0;
112             while (cnt < sz)
113             {
114                 char buf[1024];
115                 ssize_t w;
116                 size_t r;
117                 size_t toread = sz - cnt;
118
119                 if (toread > sizeof(buf))
120                     toread = sizeof(buf);
121                 r = fread(buf, 1, toread, inf);
122                 if (r != toread)
123                 {
124                     fprintf(stderr, "fread truncated. toread=%lld r=%lld\n",
125                             (long long) toread, (long long) r);
126                     return -1;
127                 }
128                 w = write((*conp)->fd, buf, toread);
129                 if (w != toread)
130                 {
131                     fprintf(stderr, "write truncated\n");
132                     return -1;
133                 }
134                 cnt += toread;
135             }
136         }
137     }
138     return 0;
139 }
140
141 static void usage(void)
142 {
143     fprintf(stderr, "Usage: pazpar2_play infile host\n"
144             "    -v level                Set log level\n");
145     exit(1);
146 }
147
148 int main(int argc, char **argv)
149 {
150     int ret;
151     char *arg;
152     char *host = 0;
153     const char *file = 0;
154     while ((ret = options("v:", argv, argc, &arg)) != -2)
155     {
156         switch (ret)
157         {
158         case 'v':
159             yaz_log_init_level(yaz_log_mask_str(arg));
160             break;
161         case 0:
162             if (!file)
163                 file = arg;
164             else if (!host)
165                 host = xstrdup(arg);
166             else
167             {
168                 usage();
169             }
170             break;
171         default:
172             usage();
173             exit(1);
174         }
175     }
176     if (host && file)
177     {
178         char *port;
179         char *cp;
180         FILE *inf;
181
182         struct addrinfo hints, *res;
183         hints.ai_flags = 0;
184         hints.ai_family = AF_UNSPEC;
185         hints.ai_socktype = SOCK_STREAM;
186         hints.ai_protocol = 0;
187         hints.ai_addrlen        = 0;
188         hints.ai_addr           = NULL;
189         hints.ai_canonname      = NULL;
190         hints.ai_next           = NULL;
191     
192         cp = strchr(host, ':');
193         if (*cp)
194         {
195             *cp = 0;
196             port = cp+1;
197         }
198         else
199         {
200             port = "80";
201         }
202         if (getaddrinfo(host, port, &hints, &res))
203         {
204             fprintf(stderr, "cannot resolve %s:%s\n", host, port);
205             exit(1);
206         }
207
208         inf = fopen(file, "rb");
209         if (!inf)
210         {
211             fprintf(stderr, "cannot open %s\n", file);
212             exit(1);
213         }
214         run(inf, res);
215         fclose(inf);
216     }
217     else
218         usage();
219     return 0;
220 }
221
222
223 /*
224  * Local variables:
225  * c-basic-offset: 4
226  * c-file-style: "Stroustrup"
227  * indent-tabs-mode: nil
228  * End:
229  * vim: shiftwidth=4 tabstop=8 expandtab
230  */
231