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 67static int padlength[4] = {0, 3, 2, 1}; 68fd_set _fs_fd_mask; 69 70static int 71_fs_resize (FSBufPtr buf, long size); 72 73static void 74_fs_downsize (FSBufPtr buf, long size); 75 76int 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 99XtransConnInfo 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 146static 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 if (!ECHECK(EINTR)) 188 { 189 _fs_connection_died (conn); 190 return FSIO_ERROR; 191 } 192 } 193 } 194 return FSIO_READY; 195} 196 197/* 198 * Make space and return whether data have already arrived 199 */ 200 201int 202_fs_start_read (FSFpePtr conn, long size, char **buf) 203{ 204 int ret; 205 206 conn->inNeed = size; 207 if (fs_inqueued(conn) < size) 208 { 209 if (_fs_resize (&conn->inBuf, size) != FSIO_READY) 210 { 211 _fs_connection_died (conn); 212 return FSIO_ERROR; 213 } 214 ret = _fs_fill (conn); 215 if (ret == FSIO_ERROR) 216 return ret; 217 if (ret == FSIO_BLOCK || fs_inqueued(conn) < size) 218 return FSIO_BLOCK; 219 } 220 if (buf) 221 *buf = conn->inBuf.buf + conn->inBuf.remove; 222 return FSIO_READY; 223} 224 225void 226_fs_done_read (FSFpePtr conn, long size) 227{ 228 if (conn->inBuf.insert - conn->inBuf.remove < size) 229 { 230#ifdef DEBUG 231 fprintf (stderr, "_fs_done_read skipping to many bytes\n"); 232#endif 233 return; 234 } 235 conn->inBuf.remove += size; 236 conn->inNeed -= size; 237 _fs_downsize (&conn->inBuf, FS_BUF_MAX); 238} 239 240long 241_fs_pad_length (long len) 242{ 243 return len + padlength[len&3]; 244} 245 246int 247_fs_flush (FSFpePtr conn) 248{ 249 long bytes_written; 250 long remain; 251 252 /* XXX - hack. The right fix is to remember that the font server 253 has gone away when we first discovered it. */ 254 if (conn->fs_fd < 0) 255 return FSIO_ERROR; 256 257 while ((remain = conn->outBuf.insert - conn->outBuf.remove) > 0) 258 { 259 bytes_written = _FontTransWrite(conn->trans_conn, 260 conn->outBuf.buf + conn->outBuf.remove, 261 (int) remain); 262 if (bytes_written > 0) 263 { 264 conn->outBuf.remove += bytes_written; 265 } 266 else 267 { 268 if (bytes_written == 0 || ETEST ()) 269 { 270 conn->brokenWriteTime = GetTimeInMillis () + FS_FLUSH_POLL; 271 _fs_mark_block (conn, FS_BROKEN_WRITE); 272 break; 273 } 274 if (!ECHECK (EINTR)) 275 { 276 _fs_connection_died (conn); 277 return FSIO_ERROR; 278 } 279 } 280 } 281 if (conn->outBuf.remove == conn->outBuf.insert) 282 { 283 _fs_unmark_block (conn, FS_BROKEN_WRITE|FS_PENDING_WRITE); 284 if (conn->outBuf.size > FS_BUF_INC) 285 conn->outBuf.buf = realloc (conn->outBuf.buf, FS_BUF_INC); 286 conn->outBuf.remove = conn->outBuf.insert = 0; 287 } 288 return FSIO_READY; 289} 290 291static int 292_fs_resize (FSBufPtr buf, long size) 293{ 294 char *new; 295 long new_size; 296 297 if (buf->remove) 298 { 299 if (buf->remove != buf->insert) 300 { 301 memmove (buf->buf, 302 buf->buf + buf->remove, 303 buf->insert - buf->remove); 304 } 305 buf->insert -= buf->remove; 306 buf->remove = 0; 307 } 308 if (buf->size - buf->remove < size) 309 { 310 new_size = ((buf->remove + size + FS_BUF_INC) / FS_BUF_INC) * FS_BUF_INC; 311 new = realloc (buf->buf, new_size); 312 if (!new) 313 return FSIO_ERROR; 314 buf->buf = new; 315 buf->size = new_size; 316 } 317 return FSIO_READY; 318} 319 320static void 321_fs_downsize (FSBufPtr buf, long size) 322{ 323 if (buf->insert == buf->remove) 324 { 325 buf->insert = buf->remove = 0; 326 if (buf->size > size) 327 { 328 buf->buf = realloc (buf->buf, size); 329 buf->size = size; 330 } 331 } 332} 333 334void 335_fs_io_reinit (FSFpePtr conn) 336{ 337 conn->outBuf.insert = conn->outBuf.remove = 0; 338 _fs_downsize (&conn->outBuf, FS_BUF_INC); 339 conn->inBuf.insert = conn->inBuf.remove = 0; 340 _fs_downsize (&conn->inBuf, FS_BUF_MAX); 341} 342 343Bool 344_fs_io_init (FSFpePtr conn) 345{ 346 conn->outBuf.insert = conn->outBuf.remove = 0; 347 conn->outBuf.buf = malloc (FS_BUF_INC); 348 if (!conn->outBuf.buf) 349 return FALSE; 350 conn->outBuf.size = FS_BUF_INC; 351 352 conn->inBuf.insert = conn->inBuf.remove = 0; 353 conn->inBuf.buf = malloc (FS_BUF_INC); 354 if (!conn->inBuf.buf) 355 { 356 free (conn->outBuf.buf); 357 conn->outBuf.buf = 0; 358 return FALSE; 359 } 360 conn->inBuf.size = FS_BUF_INC; 361 362 return TRUE; 363} 364 365void 366_fs_io_fini (FSFpePtr conn) 367{ 368 if (conn->outBuf.buf) 369 free (conn->outBuf.buf); 370 if (conn->inBuf.buf) 371 free (conn->inBuf.buf); 372} 373 374static int 375_fs_do_write(FSFpePtr conn, const char *data, long len, long size) 376{ 377 if (size == 0) { 378#ifdef DEBUG 379 fprintf(stderr, "tried to write 0 bytes \n"); 380#endif 381 return FSIO_READY; 382 } 383 384 if (conn->fs_fd == -1) 385 return FSIO_ERROR; 386 387 while (conn->outBuf.insert + size > conn->outBuf.size) 388 { 389 if (_fs_flush (conn) < 0) 390 return FSIO_ERROR; 391 if (_fs_resize (&conn->outBuf, size) < 0) 392 { 393 _fs_connection_died (conn); 394 return FSIO_ERROR; 395 } 396 } 397 memcpy (conn->outBuf.buf + conn->outBuf.insert, data, len); 398 /* Clear pad data */ 399 memset (conn->outBuf.buf + conn->outBuf.insert + len, 0, size - len); 400 conn->outBuf.insert += size; 401 _fs_mark_block (conn, FS_PENDING_WRITE); 402 return FSIO_READY; 403} 404 405/* 406 * Write the indicated bytes 407 */ 408int 409_fs_write (FSFpePtr conn, const char *data, long len) 410{ 411 return _fs_do_write (conn, data, len, len); 412} 413 414/* 415 * Write the indicated bytes adding any appropriate pad 416 */ 417int 418_fs_write_pad(FSFpePtr conn, const char *data, long len) 419{ 420 return _fs_do_write (conn, data, len, len + padlength[len & 3]); 421} 422 423int 424_fs_wait_for_readable(FSFpePtr conn, int ms) 425{ 426 fd_set r_mask; 427 fd_set e_mask; 428 int result; 429 struct timeval tv; 430 431 for (;;) { 432 if (conn->fs_fd < 0) 433 return FSIO_ERROR; 434 FD_ZERO(&r_mask); 435 FD_ZERO(&e_mask); 436 tv.tv_sec = ms / 1000; 437 tv.tv_usec = (ms % 1000) * 1000; 438 FD_SET(conn->fs_fd, &r_mask); 439 FD_SET(conn->fs_fd, &e_mask); 440 result = Select(conn->fs_fd + 1, &r_mask, NULL, &e_mask, &tv); 441 if (result < 0) 442 { 443 if (ECHECK(EINTR) || ECHECK(EAGAIN)) 444 continue; 445 else 446 return FSIO_ERROR; 447 } 448 if (result == 0) 449 return FSIO_BLOCK; 450 if (FD_ISSET(conn->fs_fd, &r_mask)) 451 return FSIO_READY; 452 return FSIO_ERROR; 453 } 454} 455