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