pazpar2_play takes timings into account
[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 <time.h>
25 #include <stdlib.h>
26 #include <sys/select.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netdb.h>
30 #include <unistd.h>
31 #include <string.h>
32
33 #include <yaz/options.h>
34 #include <yaz/log.h>
35 #include <yaz/xmalloc.h>
36
37 struct con {
38     int fd;
39     long long id;
40     struct con *next;
41 };
42
43
44 static int run(FILE *inf, struct addrinfo *res)
45 {
46     long long tv_sec0 = 0;
47     long long tv_usec0 = 0;
48     struct con *cons = 0;
49
50     while (1)
51     {
52         long long tv_sec1;
53         long long tv_usec1;
54         long long id;
55         int sz, r, c;
56         char req[100];
57         size_t i;
58         struct con **conp;
59         c = fgetc(inf);
60         if (c == EOF)
61             break;
62
63         for (i = 0; c != '\n' && i < (sizeof(req)-2); i++)
64         {
65             req[i] = c;
66             c = fgetc(inf);
67         }
68         req[i] = 0;
69         r = sscanf(req, "%lld %lld %lld %d", &tv_sec1, &tv_usec1, &id, &sz);
70         if (r != 4)
71         {
72             fprintf(stderr, "bad line %s\n", req);
73             return -1;
74         }
75         if (tv_sec0)
76         {
77             struct timeval spec;
78
79             spec.tv_sec = tv_sec1 - tv_sec0;
80             if (tv_usec0 > tv_usec1)
81             {
82                 spec.tv_usec = 1000000 + tv_usec1 - tv_usec0;
83                 spec.tv_sec--;
84             }
85             else
86                 spec.tv_usec = tv_usec1 - tv_usec0;
87             
88             select(0, 0, 0, 0, &spec);
89         }
90         tv_sec0 = tv_sec1;
91         tv_usec0 = tv_usec1;
92         for (conp = &cons; *conp; conp = &(*conp)->next)
93             if ((*conp)->id == id)
94                 break;
95         if (!*conp)
96         {
97             struct addrinfo *rp;
98             int r, fd = -1;
99             for (rp = res; rp; rp = rp->ai_next)
100             {
101                 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
102                 if (fd != -1)
103                     break;
104             }
105             if (fd == -1)
106             {
107                 fprintf(stderr, "socket: cannot create\n");
108                 return -1;
109             }
110             r = connect(fd, rp->ai_addr, rp->ai_addrlen);
111             if (r)
112             {
113                 fprintf(stderr, "socket: cannot connect\n");
114                 return -1;
115             }
116
117             *conp = xmalloc(sizeof(**conp));
118             (*conp)->id = id;
119             (*conp)->fd = fd;
120             (*conp)->next = 0;
121         }
122         if (sz == 0)
123         {
124             struct con *c = *conp;
125             *conp = c->next;
126             close(c->fd);
127             xfree(c);
128         }
129         else
130         {
131             size_t cnt = 0;
132             while (cnt < sz)
133             {
134                 char buf[1024];
135                 ssize_t w;
136                 size_t r;
137                 size_t toread = sz - cnt;
138
139                 if (toread > sizeof(buf))
140                     toread = sizeof(buf);
141                 r = fread(buf, 1, toread, inf);
142                 if (r != toread)
143                 {
144                     fprintf(stderr, "fread truncated. toread=%lld r=%lld\n",
145                             (long long) toread, (long long) r);
146                     return -1;
147                 }
148                 w = write((*conp)->fd, buf, toread);
149                 if (w != toread)
150                 {
151                     fprintf(stderr, "write truncated\n");
152                     return -1;
153                 }
154                 cnt += toread;
155             }
156         }
157     }
158     return 0;
159 }
160
161 static void usage(void)
162 {
163     fprintf(stderr, "Usage: pazpar2_play infile host\n"
164             "    -v level                Set log level\n");
165     exit(1);
166 }
167
168 int main(int argc, char **argv)
169 {
170     int ret;
171     char *arg;
172     char *host = 0;
173     const char *file = 0;
174     while ((ret = options("v:", argv, argc, &arg)) != -2)
175     {
176         switch (ret)
177         {
178         case 'v':
179             yaz_log_init_level(yaz_log_mask_str(arg));
180             break;
181         case 0:
182             if (!file)
183                 file = arg;
184             else if (!host)
185                 host = xstrdup(arg);
186             else
187             {
188                 usage();
189             }
190             break;
191         default:
192             usage();
193             exit(1);
194         }
195     }
196     if (host && file)
197     {
198         char *port;
199         char *cp;
200         FILE *inf;
201
202         struct addrinfo hints, *res;
203         hints.ai_flags = 0;
204         hints.ai_family = AF_UNSPEC;
205         hints.ai_socktype = SOCK_STREAM;
206         hints.ai_protocol = 0;
207         hints.ai_addrlen        = 0;
208         hints.ai_addr           = NULL;
209         hints.ai_canonname      = NULL;
210         hints.ai_next           = NULL;
211     
212         cp = strchr(host, ':');
213         if (*cp)
214         {
215             *cp = 0;
216             port = cp+1;
217         }
218         else
219         {
220             port = "80";
221         }
222         if (getaddrinfo(host, port, &hints, &res))
223         {
224             fprintf(stderr, "cannot resolve %s:%s\n", host, port);
225             exit(1);
226         }
227
228         inf = fopen(file, "rb");
229         if (!inf)
230         {
231             fprintf(stderr, "cannot open %s\n", file);
232             exit(1);
233         }
234         run(inf, res);
235         fclose(inf);
236     }
237     else
238         usage();
239     return 0;
240 }
241
242
243 /*
244  * Local variables:
245  * c-basic-offset: 4
246  * c-file-style: "Stroustrup"
247  * indent-tabs-mode: nil
248  * End:
249  * vim: shiftwidth=4 tabstop=8 expandtab
250  */
251