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