home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / fax-3.2.1 / lib / libfax / read.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-31  |  6.5 KB  |  337 lines

  1. /*
  2.   This file is part of the NetFax system.
  3.  
  4.   (c) Copyright 1989 by David M. Siegel and Sundar Narasimhan.
  5.       All rights reserved.
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation.
  10.  
  11.     This program is distributed in the hope that it will be useful, 
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <signal.h>
  23. #include <unistd.h>
  24. #include <errno.h>
  25. #include <sys/types.h>
  26. #include <sys/socket.h>
  27. #include <sys/time.h>
  28. #include <fcntl.h>
  29.  
  30. #include "log.h"
  31. #include "read.h"
  32.  
  33. static int fds[2];
  34. static int init = 0;
  35.  
  36. static void timeout_handler()
  37. {
  38.     char dummy;
  39.  
  40.     write(fds[0], &dummy, 1);
  41. }
  42.  
  43. static int timeout_init()
  44. {
  45.     int flags;
  46.  
  47.     /*
  48.      * The first part of the pair is for writing.  The second
  49.      * is for reading.  This is used to make alarm signal
  50.      * syncronous.  Thanks to Andy for this idea.
  51.      */
  52.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
  53.     log(L_EMERG, "can't make socketpair: %m");
  54.     return (-1);
  55.     }
  56.  
  57.     /*
  58.      * We make this non-blocking to make it easy to clear out
  59.      * any pending reads.
  60.      */
  61.     flags = fcntl(fds[1], F_GETFL, 0);
  62.     flags |= O_NDELAY;
  63.     if (fcntl(fds[1], F_SETFL, flags) < 0) {
  64.     log(L_EMERG, "can't set nonblocking: %m");
  65.     return (-1);
  66.     }
  67.  
  68.     signal(SIGALRM, timeout_handler);
  69.     
  70.     init = 1;
  71.  
  72.     return (0);
  73. }
  74.  
  75. static void timeout_set(seconds)
  76.      int seconds;
  77. {
  78.     char buf[128];
  79.  
  80.     /*
  81.      * Clear timeout.  This will work because we have set non-blocking 
  82.      * on this fd.
  83.      */
  84.     read(fds[1], buf, sizeof(buf));
  85.  
  86.     alarm(seconds);
  87. }
  88.  
  89. /*
  90.  * Read from fd into a buf with maxlength bufsize.  Return when
  91.  * a minimum of minsize bytes have been read.  Wait a maximum
  92.  * of seconds seconds before timing out.  Return 0 if a timeout
  93.  * occured.  Return -1 if the read failed.  In other cases,
  94.  * return the total bytes read.
  95.  */
  96. static int read_internal(fd, buf, bufsize)
  97.      int fd;
  98.      char *buf;
  99.      int bufsize;
  100. {
  101.     fd_set readfds;
  102.  
  103.     FD_ZERO(&readfds);
  104.     FD_SET(fd, &readfds);
  105.     FD_SET(fds[1], &readfds);
  106.  
  107.     switch (select(32, &readfds, NULL, NULL, NULL)) {
  108.       case 0:
  109.     log(L_ERR, "unexpect select return");
  110.     return (-1);
  111.       case -1:
  112.     if (errno == EINTR) {
  113.         log(L_ERR, "read timeout");
  114.         return (0);
  115.     } else {
  116.         log(L_ERR, "select error: %m");
  117.         return (-1);
  118.     }
  119.       default:
  120.     if (FD_ISSET(fds[1], &readfds)) {
  121.         char dummy[128];
  122.         read(fds[1], dummy, sizeof(dummy));
  123.         log(L_ERR, "read timeout");
  124.         return (0);
  125.     } else if (FD_ISSET(fd, &readfds)) {
  126.         int bytes = read(fd, buf, bufsize);
  127.         log(L_DEBUG, "got %d: \"%.*s\"", bytes, bytes, buf);
  128.         return (bytes);
  129.     } else {
  130.         log(L_ERR, "unknown fd is set");
  131.         return (-1);
  132.     }
  133.     }
  134. }
  135.  
  136. /*
  137.  * Like a normal read, except use a timeout.  Returns the bytes
  138.  * that were read.
  139.  *
  140.  * Return codes:
  141.  *     0    timeout
  142.  *    -1    failure, see errno for more information
  143.  */
  144. int tread(fd, buf, bufsize, timeout)
  145.      int fd;
  146.      char *buf;
  147.      int bufsize;
  148.      int timeout;
  149. {
  150.     int bytes;
  151.     
  152.     if (!init)
  153.       timeout_init();
  154.  
  155.     timeout_set(timeout);
  156.     bytes = read_internal(fd, buf, bufsize);
  157.     timeout_set(0);
  158.  
  159.     return (bytes);
  160. }
  161.  
  162. /*
  163.  * Like a normal read, except poll for input.  Return -1 on error or
  164.  * 0 if no data is available.
  165.  */
  166. int pread(fd, buf, bufsize)
  167.      int fd;
  168.      char *buf;
  169.      int bufsize;
  170. {
  171.     fd_set readfds;
  172.     struct timeval timeout;
  173.  
  174.     FD_ZERO(&readfds);
  175.     FD_SET(fd, &readfds);
  176.  
  177.     timeout.tv_sec = 0;
  178.     timeout.tv_usec = 0;
  179.     
  180.     switch (select(32, &readfds, NULL, NULL, &timeout)) {
  181.       case -1:
  182.     log(L_EMERG, "pread: select failed: %m");
  183.     return (-1);
  184.       case 1:
  185.     if (FD_ISSET(fd, &readfds))
  186.       return (read(fd, buf, bufsize));
  187.     break;
  188.       default:
  189.     break;
  190.     }
  191.  
  192.     return (0);
  193. }
  194.  
  195. /*
  196.   Read a string, terminated by a CR, into the buffer.  Return the
  197.   length of characters read, include the CR.  Skips any NL chars
  198.   that might be encountered, since they can safely be ignored.
  199.  
  200.   Return codes:
  201.         0    timeout
  202.      -1    failure, see errno for more information
  203. */
  204. int fdgets(fd, buf, bufsize)
  205.      int fd;
  206.      char *buf;
  207.      int bufsize;
  208. {
  209.     char *bufp = buf;
  210.     int i;
  211.  
  212.     for (i = 0; i < bufsize; i++) {
  213.     char c;
  214.     
  215.     switch (read_internal(fd, &c, 1)) {
  216.       case 0:
  217.         return (0);
  218.       case 1:
  219.         if (c != '\n') {
  220.         *bufp++ = c;
  221.         if (c == '\r')
  222.           return (i+1);
  223.         }
  224.         break;
  225.       default:
  226.         return (-1);
  227.     }
  228.     }
  229.  
  230.     return (i);
  231. }
  232.  
  233. /*
  234.  * Read a line, until a NL, with default timeout.  Return -1 on
  235.  * failure.  Return 0 on timeout.  Otherwise, return total bytes
  236.  * read;
  237.  */
  238. int tfdgets(fd, buf, bufsize, timeout)
  239.      int fd;
  240.      char *buf;
  241.      int bufsize;
  242.      int timeout;
  243. {
  244.     int bytes;
  245.  
  246.     if (!init)
  247.       timeout_init();
  248.  
  249.     timeout_set(timeout);
  250.     bytes = fdgets(fd, buf, bufsize);
  251.     timeout_set(0);
  252.  
  253.     return (bytes);
  254. }
  255.  
  256. int wait_for_char(fd, c_expect, timeout)
  257.      int fd;
  258.      char c_expect;
  259.      int timeout;
  260. {
  261.     if (!init)
  262.       timeout_init();
  263.  
  264.     timeout_set(timeout);
  265.  
  266.     log(L_DEBUG, "waiting %d seconds for char %d", timeout, c_expect);
  267.  
  268.     for (;;) {
  269.     char c;
  270.     
  271.     if (read_internal(fd, &c, 1) != 1) {
  272.         timeout_set(0);
  273.         return (-1);
  274.     }
  275.     
  276.     if (c == c_expect)
  277.       return (0);
  278.     }
  279. }
  280.  
  281. int wait_for_string(fd, s_expect, timeout)
  282.      int fd;
  283.      char *s_expect;
  284.      int timeout;
  285. {
  286.     if (!init)
  287.       timeout_init();
  288.  
  289.     timeout_set(timeout);
  290.  
  291.     log(L_DEBUG, "waiting %d seconds for string %s", timeout, s_expect);
  292.  
  293.     for (;;) {
  294.     char buf[BUFSIZ];
  295.     int bytes;
  296.     
  297.     if ((bytes = fdgets(fd, buf, sizeof(buf))) <= 0) {
  298.         timeout_set(0);
  299.         return (-1);
  300.     }
  301.  
  302.     if (bytes > 1) {
  303.         buf[bytes] = '\0';
  304.  
  305.         if (strncmp(s_expect, buf, strlen(s_expect)) == 0)
  306.           return (0);
  307.     }
  308.     }
  309. }
  310.  
  311. #ifdef DEBUG
  312.  
  313. static int test_fds[2];
  314.  
  315. void timeout_test()
  316. {
  317.     char buf[128];
  318.     int count;
  319.  
  320.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fds) < 0) {
  321.     perror("sockpair");
  322.     return;
  323.     }
  324.  
  325.     write(test_fds[1], "hello", 6);
  326.  
  327.     if ((count = tfdgets(test_fds[0], buf, sizeof(buf), 10)) <= 0) {
  328.     printf("read failed: %d\n", count);
  329.     close(test_fds[0]);
  330.     close(test_fds[1]);
  331.     return;
  332.     }
  333.  
  334.     printf("got %d bytes: \"%.*s\"\n", count, count, buf);
  335. }
  336. #endif DEBUG
  337.