fsio.c revision 41c30155
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 _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 198int 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 222void 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 237long 238_fs_pad_length (long len) 239{ 240 return len + padlength[len&3]; 241} 242 243int 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 288static 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 317static 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 331void 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 340Bool 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 362void 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 371static 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 */ 405int 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 */ 414int 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 420int 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} 452