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