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