http://gimel.esc.cam.ac.uk/james/rpld/src/rpld-1.7.tar.gz
[rpld.git] / client.c
1 /*************************************************
2 *     rpld - an IBM style RIPL server            *
3 *************************************************/
4
5 /* Copyright (c) 1999,2000, James McKenzie.
6  *                      All rights reserved
7  * Copyright (c) 1998,2000, Christopher Lightfoot.
8  *                      All rights reserved
9  *
10  * By using this file, you agree to the terms and conditions set
11  * forth in the LICENCE file which can be found at the top level of
12  * the rpld distribution.
13  *
14  * IBM is a trademark of IBM corp.
15  *
16  */
17
18
19 static char rcsid[] =
20   "$Id: client.c,v 1.29 2000/09/26 04:06:07 root Exp root $";
21
22 /*
23  * $Log: client.c,v $
24  * Revision 1.29  2000/09/26 04:06:07  root
25  * #
26  *
27  * Revision 1.28  2000/09/26 03:48:23  root
28  * #
29  *
30  * Revision 1.27  2000/09/26 02:32:46  root
31  * #
32  *
33  * Revision 1.26  2000/09/26 02:31:38  root
34  * #
35  *
36  * Revision 1.25  2000/09/26 01:41:22  root
37  * #
38  *
39  * Revision 1.24  2000/09/26 01:41:20  root
40  * #
41  *
42  * Revision 1.23  2000/09/26 01:39:17  root
43  * #
44  *
45  * Revision 1.22  2000/09/26 01:03:19  root
46  * #
47  *
48  * Revision 1.21  2000/07/29 23:25:58  root
49  * #
50  *
51  * Revision 1.20  2000/07/29 23:25:25  root
52  * #
53  *
54  * Revision 1.19  2000/07/23 19:14:19  root
55  * #
56  *
57  * Revision 1.18  2000/07/23 19:07:49  root
58  * #
59  *
60  * Revision 1.17  2000/07/17 10:49:20  root
61  * #
62  *
63  * Revision 1.16  2000/07/17 10:45:38  root
64  * #
65  *
66  * Revision 1.15  2000/07/17 10:43:54  root
67  * #
68  *
69  * Revision 1.14  2000/07/17 10:43:34  root
70  * #
71  *
72  * Revision 1.13  2000/07/16 14:22:06  root
73  * #
74  *
75  * Revision 1.12  2000/07/16 14:05:28  root
76  * #
77  *
78  * Revision 1.11  2000/07/16 13:18:10  root
79  * #
80  *
81  * Revision 1.1  2000/07/16 13:16:33  root
82  * #
83  *
84  * Revision 1.10  1999/09/14 17:12:38  root
85  * #
86  *
87  * Revision 1.9  1999/09/14 17:12:05  root
88  * #
89  *
90  * Revision 1.8  1999/09/13 11:17:35  root
91  * \#
92  *
93  * Revision 1.7  1999/09/13 11:05:27  root
94  * \#
95  *
96  * Revision 1.6  1999/09/13 11:04:13  root
97  * \#
98  *
99  */
100
101 #include "project.h"
102
103 struct client *clients = NULL;
104
105 void
106 cache_locally (struct clfile *f)
107 {
108   int fd;
109   int len;
110
111   fd = open (f->path, O_RDONLY);
112
113   if (fd < 0)
114     {
115       syslog (LOG_ERR, "can't open %s:%m", f->path);
116       return;
117     }
118
119   len = f->length;
120
121   if (len < 0)
122     {
123       len = lseek (fd, 0, SEEK_END);
124       lseek (fd, 0, SEEK_SET);
125     }
126
127   f->data = malloc (len);
128   f->length = len;
129
130   lseek (fd, f->offset, SEEK_SET);
131   read (fd, f->data, len);
132
133   f->offset = 0;
134
135   close (fd);
136
137   free (f->path);
138   f->path = NULL;
139 }
140
141 /* Cache the last client */
142 struct client *
143 find_client_by_mac (unsigned char *mac)
144 {
145   struct client *pc = NULL, *c = clients;
146
147 /* We need to match clients by a (possibly partial) MAC address; however
148  * this struct client is also used to transmit to them, so we need to return
149  * a struct client containing a _real_ MAC address; this is a first and
150  * pretty ugly implementation of this idea.
151  */
152   while (c)
153     {
154       if (memcmp (mac, c->mac, c->partial_mac_len) == 0)
155         {
156           /* if partial match, create new struct client */
157           if (c->partial_mac_len != ETH_ALEN)
158             {
159               pc = (struct client *) malloc (sizeof (struct client));
160               memcpy (pc, c, sizeof (struct client));
161
162               pc->next = c->next;
163               c->next = clients;
164               clients = c;
165
166               return pc;
167             }
168
169           /* else reorder the tree for speed, and return the found client */
170           if (pc)
171             {                   /*Short circuit for next time */
172               pc->next = c->next;
173               c->next = clients;
174               clients = c;
175             }
176           return (c);
177         }
178
179       pc = c;
180       c = c->next;
181     }
182
183   return (NULL);
184 }
185
186 void
187 client_calc_offsets (struct client *c)
188 {
189   struct clfile *f;
190   int bn = 0;
191   int len;
192   int fd;
193   int blocks;
194
195   f = c->files;
196
197   while (f)
198     {
199
200       f->sblock = bn;
201
202       if (f->path)
203         {
204           fd = open (f->path, O_RDONLY);
205           if (fd < 0)
206             {
207               syslog (LOG_ERR, "can't open %s:%m", f->path);
208               return;
209             }
210           len = f->length;
211           if (len < 0)
212             {
213               len = lseek (fd, 0, SEEK_END);
214               len -= f->offset;
215             }
216           close (fd);
217         }
218       else
219         {
220           len = f->length;
221         }
222
223 #ifdef DEBUG
224       printf ("%s is %d bytes long gives", f->path, len);
225 #endif
226       blocks = len / (c->blocklen);
227       len = len - (blocks * c->blocklen);
228
229       if (len == 0)
230         blocks--;
231
232       bn += blocks;
233       f->eblock = bn;
234
235 #ifdef DEBUG
236       printf (" %d blocks [%d,%d]\n", blocks, f->sblock, f->eblock);
237 #endif
238
239       bn++;
240
241       f = f->next;
242
243     }
244
245 }
246
247
248 #define NOTINRANGE(l,v,h) (((v)<(l)) || ((v)>(h)))
249 void
250 client_get_block (struct client *c, struct rpl_packet *p)
251 {
252   struct clfile *f;
253   int toread;
254   int offset;
255
256   f = c->file;
257
258   p->datalen = 0;               /* Some buggy clients request
259                                    * blocks after the end when
260                                    * they get confused */
261
262   if ((!f) || (NOTINRANGE (f->sblock, c->blocknum, f->eblock)))
263     {
264       if ((f) && (f->f))
265         {
266           fclose (f->f);
267           f->f = NULL;
268         }
269       f = c->files;
270       while (f && (f->eblock < c->blocknum))
271         f = f->next;
272
273       if (!f)
274         {
275           syslog (LOG_ERR, "this shouldn't happen oops!");
276           return;
277         }
278
279       if (f->path)
280         {
281           f->f = fopen (f->path, "r");
282           if (!f->f)
283             {
284               c->file = NULL;
285
286               syslog (LOG_ERR, "failed to open %s ", f->path);
287               return;
288             }
289
290         }
291
292       c->file = f;
293     }
294
295
296   offset = (c->blocklen) * (c->blocknum - f->sblock);
297
298   if (f->length > 0)
299     {
300       toread = f->length - offset;
301       if (toread > c->blocklen)
302         toread = c->blocklen;
303     }
304   else
305     {
306       toread = c->blocklen;
307     }
308
309   if (f->path)
310     {                           /* A real file */
311       fseek (f->f, offset + f->offset, SEEK_SET);
312       p->datalen = fread (p->data, 1, toread, f->f);
313       if ((p->datalen != toread) && (c->blocknum != f->eblock))
314         {
315           syslog (LOG_ERR, "short read on %s", f->path);
316         }
317     }
318   else
319     {                           /*cached */
320       bcopy (f->data + offset, p->data, toread);
321       p->datalen = toread;
322     }
323
324   p->addr.load = f->load_addr + offset;
325
326 }
327
328 int
329 client_last_block (struct client *c)
330 {
331   struct clfile *f;
332   f = c->file;
333
334   if ((!f) || (NOTINRANGE (f->sblock, c->blocknum, f->eblock)))
335     {
336       if ((f) && (f->f))
337         {
338           fclose (f->f);
339           f->f = NULL;
340         }
341       c->file = NULL;
342       f = c->files;
343       while (f && (f->eblock < c->blocknum))
344         f = f->next;
345
346       if (!f)
347         {
348           syslog (LOG_ERR, "this shouldn't happen oops!");
349           return 1;             /*Infact past the last block */
350         }
351     }
352
353   if (!(f->next) && (f->eblock == c->blocknum))
354     {
355       return 1;
356     }
357
358
359   return 0;
360 }
361
362 void
363 client_flush_cache (struct client *c)
364 {
365
366   struct clfile *f;
367   f = c->file;
368
369   if ((f) && (f->f))
370     {
371       fclose (f->f);
372       f->f = NULL;
373       c->file = NULL;
374     }
375
376 }
377
378 clients_check_status ()
379 {
380   struct client *c = clients;
381
382   downloading = 0;
383   pacing = 0;
384
385   while (c)
386     {
387       if ((c->state == ST_FILEDATA) && (!c->nospew))
388         {
389           downloading++;
390           if (pacing < c->pacing)
391             pacing = c->pacing;
392         }
393       c = c->next;
394     }
395
396 }
397
398 client_dispatch (struct llcdrv *lld)
399 {
400   struct client *c = clients;
401
402   while (c)
403     {
404       if ((c->state == ST_FILEDATA) && (!c->nospew))
405         {
406           file_data_frame (lld, c);
407         }
408       c = c->next;
409
410     }
411
412 }