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