upload tizen2.0 source
[framework/uifw/xorg/lib/libxfont.git] / src / fc / fsio.c
1 /*
2  * Copyright 1990 Network Computing Devices
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of Network Computing Devices not be
9  * used in advertising or publicity pertaining to distribution of the
10  * software without specific, written prior permission.  Network Computing
11  * Devices makes no representations about the suitability of this software
12  * for any purpose.  It is provided "as is" without express or implied
13  * warranty.
14  *
15  * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
17  * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
18  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
19  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
20  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
21  * OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author:      Dave Lemke, Network Computing Devices, Inc
24  */
25 /*
26  * font server i/o routines
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #ifdef WIN32
34 #define _WILLWINSOCK_
35 #include        "X11/Xwindows.h"
36 #endif
37
38 #define FONT_t
39 #define TRANS_CLIENT
40 #include        "X11/Xtrans/Xtrans.h"
41 #include        "X11/Xpoll.h"
42 #include        <X11/fonts/FS.h>
43 #include        <X11/fonts/FSproto.h>
44 #include        <X11/fonts/fontmisc.h>
45 #include        <X11/fonts/fontstruct.h>
46 #include        "fservestr.h"
47
48 #include        <stdio.h>
49 #include        <signal.h>
50 #include        <sys/types.h>
51 #if !defined(WIN32)
52 #ifndef Lynx
53 #include        <sys/socket.h>
54 #else
55 #include        <socket.h>
56 #endif
57 #endif
58 #include        <errno.h>
59 #ifdef WIN32
60 #define EWOULDBLOCK WSAEWOULDBLOCK
61 #undef EINTR
62 #define EINTR WSAEINTR
63 #endif
64
65
66
67 static int  padlength[4] = {0, 3, 2, 1};
68 fd_set _fs_fd_mask;
69
70 static int
71 _fs_resize (FSBufPtr buf, long size);
72
73 static void
74 _fs_downsize (FSBufPtr buf, long size);
75
76 int
77 _fs_poll_connect (XtransConnInfo trans_conn, int timeout)
78 {
79     fd_set          w_mask;
80     struct timeval  tv;
81     int             fs_fd = _FontTransGetConnectionNumber (trans_conn);
82     int             ret;
83
84     do
85     {
86         tv.tv_usec = 0;
87         tv.tv_sec = timeout;
88         FD_ZERO (&w_mask);
89         FD_SET (fs_fd, &w_mask);
90         ret = Select (fs_fd + 1, NULL, &w_mask, NULL, &tv);
91     } while (ret < 0 && ECHECK(EINTR));
92     if (ret == 0)
93         return FSIO_BLOCK;
94     if (ret < 0)
95         return FSIO_ERROR;
96     return FSIO_READY;
97 }
98
99 XtransConnInfo
100 _fs_connect(char *servername, int *err)
101 {
102     XtransConnInfo  trans_conn;         /* transport connection object */
103     int             ret;
104     int             i = 0;
105     int             retries = 5;
106
107     /*
108      * Open the network connection.
109      */
110     if( (trans_conn=_FontTransOpenCOTSClient(servername)) == NULL )
111     {
112         *err = FSIO_ERROR;
113         return 0;
114     }
115
116     /*
117      * Set the connection non-blocking since we use select() to block.
118      */
119
120     _FontTransSetOption(trans_conn, TRANS_NONBLOCKING, 1);
121
122     do {
123         i = _FontTransConnect(trans_conn,servername);
124     } while ((i == TRANS_TRY_CONNECT_AGAIN) && (retries-- > 0));
125
126     if (i < 0)
127     {
128         if (i == TRANS_IN_PROGRESS)
129             ret = FSIO_BLOCK;
130         else
131             ret = FSIO_ERROR;
132     }
133     else
134         ret = FSIO_READY;
135
136     if (ret == FSIO_ERROR)
137     {
138         _FontTransClose(trans_conn);
139         trans_conn = 0;
140     }
141
142     *err = ret;
143     return trans_conn;
144 }
145
146 static int
147 _fs_fill (FSFpePtr conn)
148 {
149     long    avail;
150     long    bytes_read;
151     Bool    waited = FALSE;
152
153     if (_fs_flush (conn) < 0)
154         return FSIO_ERROR;
155     /*
156      * Don't go overboard here; stop reading when we've
157      * got enough to satisfy the pending request
158      */
159     while ((conn->inNeed - (conn->inBuf.insert - conn->inBuf.remove)) > 0)
160     {
161         avail = conn->inBuf.size - conn->inBuf.insert;
162         /*
163          * For SVR4 with a unix-domain connection, ETEST() after selecting
164          * readable means the server has died.  To do this here, we look for
165          * two consecutive reads returning ETEST().
166          */
167         ESET (0);
168         bytes_read =_FontTransRead(conn->trans_conn,
169                                    conn->inBuf.buf + conn->inBuf.insert,
170                                    avail);
171         if (bytes_read > 0) {
172             conn->inBuf.insert += bytes_read;
173             waited = FALSE;
174         }
175         else
176         {
177             if (bytes_read == 0 || ETEST ())
178             {
179                 if (!waited)
180                 {
181                     waited = TRUE;
182                     if (_fs_wait_for_readable (conn, 0) == FSIO_BLOCK)
183                         return FSIO_BLOCK;
184                     continue;
185                 }
186             }
187             _fs_connection_died (conn);
188             return FSIO_ERROR;
189         }
190     }
191     return FSIO_READY;
192 }
193
194 /*
195  * Make space and return whether data have already arrived
196  */
197
198 int
199 _fs_start_read (FSFpePtr conn, long size, char **buf)
200 {
201     int     ret;
202
203     conn->inNeed = size;
204     if (fs_inqueued(conn) < size)
205     {
206         if (_fs_resize (&conn->inBuf, size) != FSIO_READY)
207         {
208             _fs_connection_died (conn);
209             return FSIO_ERROR;
210         }
211         ret = _fs_fill (conn);
212         if (ret == FSIO_ERROR)
213             return ret;
214         if (ret == FSIO_BLOCK || fs_inqueued(conn) < size)
215             return FSIO_BLOCK;
216     }
217     if (buf)
218         *buf = conn->inBuf.buf + conn->inBuf.remove;
219     return FSIO_READY;
220 }
221
222 void
223 _fs_done_read (FSFpePtr conn, long size)
224 {
225     if (conn->inBuf.insert - conn->inBuf.remove < size)
226     {
227 #ifdef DEBUG
228         fprintf (stderr, "_fs_done_read skipping to many bytes\n");
229 #endif
230         return;
231     }
232     conn->inBuf.remove += size;
233     conn->inNeed -= size;
234     _fs_downsize (&conn->inBuf, FS_BUF_MAX);
235 }
236
237 long
238 _fs_pad_length (long len)
239 {
240     return len + padlength[len&3];
241 }
242
243 int
244 _fs_flush (FSFpePtr conn)
245 {
246     long    bytes_written;
247     long    remain;
248
249     /* XXX - hack.  The right fix is to remember that the font server
250        has gone away when we first discovered it. */
251     if (conn->fs_fd < 0)
252         return FSIO_ERROR;
253
254     while ((remain = conn->outBuf.insert - conn->outBuf.remove) > 0)
255     {
256         bytes_written = _FontTransWrite(conn->trans_conn,
257                                         conn->outBuf.buf + conn->outBuf.remove,
258                                         (int) remain);
259         if (bytes_written > 0)
260         {
261             conn->outBuf.remove += bytes_written;
262         }
263         else
264         {
265             if (bytes_written == 0 || ETEST ())
266             {
267                 conn->brokenWriteTime = GetTimeInMillis () + FS_FLUSH_POLL;
268                 _fs_mark_block (conn, FS_BROKEN_WRITE);
269                 break;
270             }
271             if (!ECHECK (EINTR))
272             {
273                 _fs_connection_died (conn);
274                 return FSIO_ERROR;
275             }
276         }
277     }
278     if (conn->outBuf.remove == conn->outBuf.insert)
279     {
280         _fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE);
281         if (conn->outBuf.size > FS_BUF_INC)
282             conn->outBuf.buf = realloc (conn->outBuf.buf, FS_BUF_INC);
283         conn->outBuf.remove = conn->outBuf.insert = 0;
284     }
285     return FSIO_READY;
286 }
287
288 static int
289 _fs_resize (FSBufPtr buf, long size)
290 {
291     char    *new;
292     long    new_size;
293
294     if (buf->remove)
295     {
296         if (buf->remove != buf->insert)
297         {
298             memmove (buf->buf,
299                      buf->buf + buf->remove,
300                      buf->insert - buf->remove);
301         }
302         buf->insert -= buf->remove;
303         buf->remove = 0;
304     }
305     if (buf->size - buf->remove < size)
306     {
307         new_size = ((buf->remove + size + FS_BUF_INC) / FS_BUF_INC) * FS_BUF_INC;
308         new = realloc (buf->buf, new_size);
309         if (!new)
310             return FSIO_ERROR;
311         buf->buf = new;
312         buf->size = new_size;
313     }
314     return FSIO_READY;
315 }
316
317 static void
318 _fs_downsize (FSBufPtr buf, long size)
319 {
320     if (buf->insert == buf->remove)
321     {
322         buf->insert = buf->remove = 0;
323         if (buf->size > size)
324         {
325             buf->buf = realloc (buf->buf, size);
326             buf->size = size;
327         }
328     }
329 }
330
331 void
332 _fs_io_reinit (FSFpePtr conn)
333 {
334     conn->outBuf.insert = conn->outBuf.remove = 0;
335     _fs_downsize (&conn->outBuf, FS_BUF_INC);
336     conn->inBuf.insert = conn->inBuf.remove = 0;
337     _fs_downsize (&conn->inBuf, FS_BUF_MAX);
338 }
339
340 Bool
341 _fs_io_init (FSFpePtr conn)
342 {
343     conn->outBuf.insert = conn->outBuf.remove = 0;
344     conn->outBuf.buf = malloc (FS_BUF_INC);
345     if (!conn->outBuf.buf)
346         return FALSE;
347     conn->outBuf.size = FS_BUF_INC;
348
349     conn->inBuf.insert = conn->inBuf.remove = 0;
350     conn->inBuf.buf = malloc (FS_BUF_INC);
351     if (!conn->inBuf.buf)
352     {
353         free (conn->outBuf.buf);
354         conn->outBuf.buf = 0;
355         return FALSE;
356     }
357     conn->inBuf.size = FS_BUF_INC;
358
359     return TRUE;
360 }
361
362 void
363 _fs_io_fini (FSFpePtr conn)
364 {
365     if (conn->outBuf.buf)
366         free (conn->outBuf.buf);
367     if (conn->inBuf.buf)
368         free (conn->inBuf.buf);
369 }
370
371 static int
372 _fs_do_write(FSFpePtr conn, const char *data, long len, long size)
373 {
374     if (size == 0) {
375 #ifdef DEBUG
376         fprintf(stderr, "tried to write 0 bytes \n");
377 #endif
378         return FSIO_READY;
379     }
380
381     if (conn->fs_fd == -1)
382         return FSIO_ERROR;
383
384     while (conn->outBuf.insert + size > conn->outBuf.size)
385     {
386         if (_fs_flush (conn) < 0)
387             return FSIO_ERROR;
388         if (_fs_resize (&conn->outBuf, size) < 0)
389         {
390             _fs_connection_died (conn);
391             return FSIO_ERROR;
392         }
393     }
394     memcpy (conn->outBuf.buf + conn->outBuf.insert, data, len);
395     /* Clear pad data */
396     memset (conn->outBuf.buf + conn->outBuf.insert + len, 0, size - len);
397     conn->outBuf.insert += size;
398     _fs_mark_block (conn, FS_PENDING_WRITE);
399     return FSIO_READY;
400 }
401
402 /*
403  * Write the indicated bytes
404  */
405 int
406 _fs_write (FSFpePtr conn, const char *data, long len)
407 {
408     return _fs_do_write (conn, data, len, len);
409 }
410
411 /*
412  * Write the indicated bytes adding any appropriate pad
413  */
414 int
415 _fs_write_pad(FSFpePtr conn, const char *data, long len)
416 {
417     return _fs_do_write (conn, data, len, len + padlength[len & 3]);
418 }
419
420 int
421 _fs_wait_for_readable(FSFpePtr conn, int ms)
422 {
423     fd_set      r_mask;
424     fd_set      e_mask;
425     int         result;
426     struct timeval  tv;
427
428     for (;;) {
429         if (conn->fs_fd < 0)
430             return FSIO_ERROR;
431         FD_ZERO(&r_mask);
432         FD_ZERO(&e_mask);
433         tv.tv_sec = ms / 1000;
434         tv.tv_usec = (ms % 1000) * 1000;
435         FD_SET(conn->fs_fd, &r_mask);
436         FD_SET(conn->fs_fd, &e_mask);
437         result = Select(conn->fs_fd + 1, &r_mask, NULL, &e_mask, &tv);
438         if (result < 0)
439         {
440             if (ECHECK(EINTR) || ECHECK(EAGAIN))
441                 continue;
442             else
443                 return FSIO_ERROR;
444         }
445         if (result == 0)
446             return FSIO_BLOCK;
447         if (FD_ISSET(conn->fs_fd, &r_mask))
448             return FSIO_READY;
449         return FSIO_ERROR;
450     }
451 }