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