ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/deliantra/server/socket/image.c
Revision: 1.4
Committed: Mon May 1 12:22:03 2006 UTC (20 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: LAST_C_VERSION, difficulty_fix_merge_060810_2300
Branch point for: difficulty_fix
Changes since 1.3: +1 -1 lines
Log Message:
Fix another crash.

Some clueless idiot decided to name the constant that defines the maximum
buffer size PLUS ONE to MAXSOCKBUF, and some naive people believed that
would actually be the max sock buf size. It's not.

File Contents

# User Rev Content
1 root 1.1 /*
2     * static char *rcsid_init_c =
3 root 1.2 * "$Id$";
4 root 1.1 */
5    
6     /*
7     CrossFire, A Multiplayer game for X-windows
8    
9     Copyright (C) 2001 Mark Wedel
10     Copyright (C) 1992 Frank Tore Johansen
11    
12     This program is free software; you can redistribute it and/or modify
13     it under the terms of the GNU General Public License as published by
14     the Free Software Foundation; either version 2 of the License, or
15     (at your option) any later version.
16    
17     This program is distributed in the hope that it will be useful,
18     but WITHOUT ANY WARRANTY; without even the implied warranty of
19     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20     GNU General Public License for more details.
21    
22     You should have received a copy of the GNU General Public License
23     along with this program; if not, write to the Free Software
24     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25    
26     The author can be reached via e-mail to crossfire-devel@real-time.com
27     */
28    
29     /** \file
30     * Image related communication
31     *
32     * \date 2003-12-02
33     *
34     * This file deals with the image related communication to the
35     * client. I've located all the functions in this file - this
36     * localizes it more, and means that we don't need to declare
37     * things like all the structures as globals.
38     */
39    
40     #include <global.h>
41     #include <sproto.h>
42    
43     #include <newclient.h>
44     #include <newserver.h>
45     #include <loader.h>
46    
47     #define MAX_FACE_SETS 20 /**< Maximum number of image sets the program will handle */
48    
49     /** Information about one image */
50     typedef struct FaceInfo {
51     uint8 *data; /**< image data */
52     uint16 datalen; /**< length of the xpm data */
53     uint32 checksum; /**< Checksum of face data */
54     } FaceInfo;
55    
56     /** Information about one face set */
57     typedef struct {
58     char *prefix; /**< */
59     char *fullname;
60     uint8 fallback; /**< faceset to use when an image is not found in this faceset */
61     char *size;
62     char *extension;
63     char *comment;
64     FaceInfo *faces; /**< images in this faceset */
65     } FaceSets;
66    
67     static FaceSets facesets[MAX_FACE_SETS]; /**< All facesets */
68    
69     /**
70     * Checks specified faceset is valid
71     * \param fsn faceset number
72     */
73     int is_valid_faceset(int fsn)
74     {
75     if (fsn >=0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix) return TRUE;
76     return FALSE;
77     }
78    
79     /**
80     * Frees all faceset information
81     */
82     void free_socket_images(void)
83     {
84     int num,q;
85    
86     for(num=0;num<MAX_FACE_SETS; num++) {
87     if (facesets[num].prefix) {
88     for (q=0; q<nrofpixmaps; q++)
89     if (facesets[num].faces[q].data) free(facesets[num].faces[q].data);
90     free(facesets[num].prefix);
91     free(facesets[num].fullname);
92     free(facesets[num].size);
93     free(facesets[num].extension);
94     free(facesets[num].comment);
95     free(facesets[num].faces);
96     }
97     }
98     }
99    
100     /**
101     * This returns the set we will actually use when sending
102     * a face. This is used because the image files may be sparse.
103     * This function is recursive. imageno is the face number we are
104     * trying to send
105     *
106     * If face is not found in specified faceset, tries with 'fallback' faceset.
107     *
108     * \param faceset faceset to check
109     * \param imageno image number
110     *
111     */
112     static int get_face_fallback(int faceset, int imageno)
113     {
114     /* faceset 0 is supposed to have every image, so just return. Doing
115     * so also prevents infinite loops in the case if it not having
116     * the face, but in that case, we are likely to crash when we try
117     * to access the data, but that is probably preferable to an infinite
118     * loop.
119     */
120     if (faceset==0) return 0;
121    
122     if (!facesets[faceset].prefix) {
123     LOG(llevError,"get_face_fallback called with unused set (%d)?\n", faceset);
124     return 0; /* use default set */
125     }
126     if (facesets[faceset].faces[imageno].data) return faceset;
127     return get_face_fallback(facesets[faceset].fallback, imageno);
128     }
129    
130     /**
131     * Checks fallback are correctly defined.
132     * This is a simple recursive function that makes sure the fallbacks
133     * are all proper (eg, the fall back to defined sets, and also
134     * eventually fall back to 0). At the top level, togo is set to MAX_FACE_SETS,
135     * if togo gets to zero, it means we have a loop.
136     * This is only run when we first load the facesets.
137     */
138     static void check_faceset_fallback(int faceset, int togo)
139     {
140     int fallback = facesets[faceset].fallback;
141    
142     /* proper case - falls back to base set */
143     if (fallback == 0) return;
144    
145     if (!facesets[fallback].prefix) {
146     LOG(llevError,"Face set %d falls to non set faceset %d\n", faceset, fallback);
147     abort();
148     }
149     togo--;
150     if (togo == 0) {
151     LOG(llevError,"Infinite loop found in facesets. aborting.\n");
152     abort();
153     }
154     check_faceset_fallback(fallback, togo);
155     }
156    
157 root 1.3 #define MAX_IMAGE_SIZE 10000
158 root 1.1
159     /**
160     * Loads all the image types into memory.
161     *
162     * This way, we can easily send them to the client. We should really do something
163     * better than abort on any errors - on the other hand, these are all fatal
164     * to the server (can't work around them), but the abort just seems a bit
165     * messy (exit would probably be better.)
166     *
167     * Couple of notes: We assume that the faces are in a continous block.
168     * This works fine for now, but this could perhaps change in the future
169     *
170     * Function largely rewritten May 2000 to be more general purpose.
171     * The server itself does not care what the image data is - to the server,
172     * it is just data it needs to allocate. As such, the code is written
173     * to do such.
174     */
175    
176     void read_client_images(void)
177     {
178     char filename[400];
179     char buf[HUGE_BUF];
180     char *cp, *cps[7];
181     FILE *infile;
182     int num,len,compressed, fileno,i, badline;
183    
184     memset(facesets, 0, sizeof(facesets));
185     sprintf(filename,"%s/image_info",settings.datadir);
186     if ((infile=open_and_uncompress(filename, 0, &compressed))==NULL) {
187     LOG(llevError,"Unable to open %s\n", filename);
188     abort();
189     }
190     while (fgets(buf, HUGE_BUF-1, infile)!=NULL) {
191     badline=0;
192    
193     if (buf[0] == '#') continue;
194     if (!(cps[0] = strtok(buf, ":"))) badline=1;
195     for (i=1; i<7; i++) {
196     if (!(cps[i] = strtok(NULL, ":"))) badline=1;
197     }
198     if (badline) {
199     LOG(llevError,"Bad line in image_info file, ignoring line:\n %s", buf);
200     } else {
201     len = atoi(cps[0]);
202     if (len >=MAX_FACE_SETS) {
203     LOG(llevError,"To high a setnum in image_info file: %d > %d\n",
204     len, MAX_FACE_SETS);
205     abort();
206     }
207     facesets[len].prefix = strdup_local(cps[1]);
208     facesets[len].fullname = strdup_local(cps[2]);
209     facesets[len].fallback = atoi(cps[3]);
210     facesets[len].size = strdup_local(cps[4]);
211     facesets[len].extension = strdup_local(cps[5]);
212     facesets[len].comment = strdup_local(cps[6]);
213     }
214     }
215     close_and_delete(infile,compressed);
216     for (i=0; i<MAX_FACE_SETS; i++) {
217     if (facesets[i].prefix) check_faceset_fallback(i, MAX_FACE_SETS);
218     }
219     /* Loaded the faceset information - now need to load up the
220     * actual faces.
221     */
222    
223     for (fileno=0; fileno<MAX_FACE_SETS; fileno++) {
224     /* if prefix is not set, this is not used */
225     if (!facesets[fileno].prefix) continue;
226     facesets[fileno].faces = calloc(nrofpixmaps, sizeof(FaceInfo));
227    
228     sprintf(filename,"%s/crossfire.%d",settings.datadir, fileno);
229     LOG(llevDebug,"Loading image file %s\n", filename);
230    
231     if ((infile = open_and_uncompress(filename,0,&compressed))==NULL) {
232     LOG(llevError,"Unable to open %s\n", filename);
233     abort();
234     }
235     while(fgets(buf, HUGE_BUF-1, infile)!=NULL) {
236     if(strncmp(buf,"IMAGE ",6)!=0) {
237     LOG(llevError,"read_client_images:Bad image line - not IMAGE, instead\n%s",buf);
238     abort();
239     }
240     num = atoi(buf+6);
241     if (num<0 || num>=nrofpixmaps) {
242     LOG(llevError,"read_client_images: Image num %d not in 0..%d\n%s",
243     num,nrofpixmaps,buf);
244     abort();
245     }
246     /* Skip accross the number data */
247     for (cp=buf+6; *cp!=' '; cp++) ;
248     len = atoi(cp);
249     if (len==0 || len>MAX_IMAGE_SIZE) {
250     LOG(llevError,"read_client_images: length not valid: %d > %d \n%s",
251     len,MAX_IMAGE_SIZE,buf);
252     abort();
253     }
254     /* We don't actualy care about the name if the image that
255     * is embedded in the image file, so just ignore it.
256     */
257     facesets[fileno].faces[num].datalen = len;
258     facesets[fileno].faces[num].data = malloc(len);
259     if ((i=fread(facesets[fileno].faces[num].data, len, 1, infile))!=1) {
260     LOG(llevError,"read_client_images: Did not read desired amount of data, wanted %d, got %d\n%s",
261     len, i, buf);
262     abort();
263     }
264     facesets[fileno].faces[num].checksum=0;
265     for (i=0; i<len; i++) {
266     ROTATE_RIGHT(facesets[fileno].faces[num].checksum);
267     facesets[fileno].faces[num].checksum += facesets[fileno].faces[num].data[i];
268     facesets[fileno].faces[num].checksum &= 0xffffffff;
269     }
270     }
271     close_and_delete(infile,compressed);
272     } /* For fileno < MAX_FACE_SETS */
273     }
274    
275     /**
276     * Client tells us what type of faces it wants. Also sets
277     * the caching attribute.
278     *
279     */
280    
281     void SetFaceMode(char *buf, int len, NewSocket *ns)
282     {
283     char tmp[256];
284    
285     int mask =(atoi(buf) & CF_FACE_CACHE), mode=(atoi(buf) & ~CF_FACE_CACHE);
286    
287     if (mode==CF_FACE_NONE) {
288     ns->facecache=1;
289     } else if (mode!=CF_FACE_PNG) {
290     sprintf(tmp,"drawinfo %d %s", NDI_RED,"Warning - send unsupported face mode. Will use Png");
291     Write_String_To_Socket(ns, tmp, strlen(tmp));
292     #ifdef ESRV_DEBUG
293     LOG(llevDebug,"SetFaceMode: Invalid mode from client: %d\n", mode);
294     #endif
295     }
296     if (mask) {
297     ns->facecache=1;
298     }
299     }
300    
301     /**
302     * Client has requested pixmap that it somehow missed getting.
303     * This will be called often if the client is
304     * caching images.
305     */
306    
307     void SendFaceCmd(char *buff, int len, NewSocket *ns)
308     {
309     long tmpnum = atoi(buff);
310     short facenum=tmpnum & 0xffff;
311    
312     if(facenum!=0)
313     esrv_send_face(ns, facenum,1);
314     }
315    
316     /**
317     * Sends a face to a client if they are in pixmap mode
318     * nothing gets sent in bitmap mode.
319     * If nocache is true (nonzero), ignore the cache setting from the client -
320     * this is needed for the askface, in which we really do want to send the
321     * face (and askface is the only place that should be setting it). Otherwise,
322     * we look at the facecache, and if set, send the image name.
323     */
324    
325     void esrv_send_face(NewSocket *ns,short face_num, int nocache)
326     {
327     SockList sl;
328     char fallback;
329    
330     if (face_num <= 0 || face_num >= nrofpixmaps) {
331     LOG(llevError,"esrv_send_face (%d) out of bounds??\n",face_num);
332     return;
333     }
334    
335     sl.buf = malloc(MAXSOCKBUF);
336     fallback = get_face_fallback(ns->faceset, face_num);
337    
338     if (facesets[fallback].faces[face_num].data == NULL) {
339     LOG(llevError,"esrv_send_face: faces[%d].data == NULL\n",face_num);
340     return;
341     }
342    
343     if (ns->facecache && !nocache) {
344     if (ns->image2)
345     strcpy((char*)sl.buf, "face2 ");
346     else if (ns->sc_version >= 1026)
347     strcpy((char*)sl.buf, "face1 ");
348     else
349     strcpy((char*)sl.buf, "face ");
350    
351     sl.len=strlen(sl.buf);
352     SockList_AddShort(&sl, face_num);
353     if (ns->image2)
354     SockList_AddChar(&sl, fallback);
355     if (ns->sc_version >= 1026)
356     SockList_AddInt(&sl, facesets[fallback].faces[face_num].checksum);
357     strcpy((char*)sl.buf + sl.len, new_faces[face_num].name);
358     sl.len += strlen(new_faces[face_num].name);
359     Send_With_Handling(ns, &sl);
360     }
361     else {
362     if (ns->image2)
363     strcpy((char*)sl.buf, "image2 ");
364     else
365     strcpy((char*)sl.buf, "image ");
366     sl.len=strlen((char*)sl.buf);
367     SockList_AddInt(&sl, face_num);
368     if (ns->image2)
369     SockList_AddChar(&sl, fallback);
370     SockList_AddInt(&sl, facesets[fallback].faces[face_num].datalen);
371     memcpy(sl.buf+sl.len, facesets[fallback].faces[face_num].data,
372     facesets[fallback].faces[face_num].datalen);
373     sl.len += facesets[fallback].faces[face_num].datalen;
374     Send_With_Handling(ns, &sl);
375     }
376     ns->faces_sent[face_num] |= NS_FACESENT_FACE;
377     free(sl.buf);
378     }
379    
380     /**
381     * Sends the number of images, checksum of the face file,
382     * and the image_info file information. See the doc/Developers/protocol
383     * if you want further detail.
384     */
385    
386     void send_image_info(NewSocket *ns, char *params)
387     {
388     SockList sl;
389     int i;
390    
391     sl.buf = malloc(MAXSOCKBUF);
392    
393     sprintf(sl.buf,"replyinfo image_info\n%d\n%d\n", nrofpixmaps-1, bmaps_checksum);
394     for (i=0; i<MAX_FACE_SETS; i++) {
395     if (facesets[i].prefix) {
396     sprintf(sl.buf + strlen(sl.buf), "%d:%s:%s:%d:%s:%s:%s",
397     i, facesets[i].prefix, facesets[i].fullname, facesets[i].fallback,
398     facesets[i].size, facesets[i].extension, facesets[i].comment);
399     }
400     }
401     sl.len = strlen(sl.buf);
402     Send_With_Handling(ns, &sl);
403     free(sl.buf);
404     }
405    
406     /**
407     * Sends requested face information.
408     * \param ns socket to send to
409     * \param params contains first and last index of face
410     *
411     * For each image in [start..stop] sends
412     * - checksum
413     * - name
414     */
415     void send_image_sums(NewSocket *ns, char *params)
416     {
417     int start, stop;
418     short i;
419     char qq;
420     char *cp, buf[MAX_BUF];
421     SockList sl;
422    
423     sl.buf = malloc(MAXSOCKBUF);
424    
425     start = atoi(params);
426     for (cp = params; *cp != '\0'; cp++)
427     if (*cp == ' ') break;
428    
429     stop = atoi(cp);
430     if (stop < start || *cp == '\0' || (stop-start)>1000 || stop >= nrofpixmaps) {
431     sprintf(buf,"replyinfo image_sums %d %d", start, stop);
432     cs_write_string(ns, buf, strlen(buf));
433     return;
434     }
435     sprintf(sl.buf,"replyinfo image_sums %d %d ", start, stop);
436    
437     sl.len = strlen(sl.buf);
438    
439     for (i=start; i<=stop; i++) {
440     SockList_AddShort(&sl, i);
441     ns->faces_sent[i] |= NS_FACESENT_FACE;
442    
443     qq = get_face_fallback(ns->faceset, i);
444     SockList_AddInt(&sl, facesets[qq].faces[i].checksum);
445     SockList_AddChar(&sl, qq);
446    
447     qq = strlen(new_faces[i].name);
448     SockList_AddChar(&sl, ( char )( qq + 1 ));
449     strcpy(sl.buf + sl.len, new_faces[i].name);
450     sl.len += qq;
451     SockList_AddChar(&sl, 0);
452     }
453     /* It would make more sense to catch this pre-emptively in the code above.
454     * however, if this really happens, we probably just want to cut down the
455     * size to less than 1000, since that is what we claim the protocol would
456     * support.
457     */
458 root 1.4 if (sl.len >= MAXSOCKBUF) {
459 root 1.1 LOG(llevError,"send_image_send: buffer overrun, %d > %d\n", sl.len, MAXSOCKBUF);
460     abort();
461     }
462     Send_With_Handling(ns, &sl);
463     free(sl.buf);
464     }