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