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