home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Portable Patmos 1.1 / patmos-src / src / sock_std.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-19  |  8.7 KB  |  550 lines  |  [TEXT/R*ch]

  1. /*
  2.  * BSD-style socket emulation library for the Mac
  3.  * Original author: Tom Milligan
  4.  * Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
  5.  *
  6.  * This source file is placed in the public domian.
  7.  * Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
  8.  *
  9.  *      National Center for Supercomputing Applications
  10.  *      152 Computing Applications Building
  11.  *      605 E. Springfield Ave.
  12.  *      Champaign, IL  61820
  13.  */
  14.  
  15. /*
  16.  *    A really hacked up stdio interface for the MacTCP socket library
  17.  *    
  18.  *    routines:
  19.  *
  20.  *        fdopen
  21.  *        fileno
  22.  *        fgetc
  23.  *        ungetc
  24.  *        fread
  25.  *        fputc
  26.  *        fwrite
  27.  *        fprintf
  28.  *        fflush
  29.  *        fclose
  30.  *        ferror
  31.  *        feof
  32.  *        clearerr
  33.  *
  34.  *    hacks:
  35.  *
  36.  *        the stdio data are stored in the socket descriptor. fdopen() calls
  37.  *        simply return a pointer to the descriptor. The first call per
  38.  *        socket initializes stdio for both read and write. (The "rw"
  39.  *        parameter to fdopen() is ignored.) The first fclose() will destroy
  40.  *        all stdio streams open on the socket.
  41.  *
  42.  *        ungetc will return EOF if the buffer is full.
  43.  *
  44.  *        printf uses a fixed size buffer to build the message.
  45.  *
  46.  *    non-blocking i/o
  47.  *
  48.  *        all read operations which would block return EOF with errno set 
  49.  *        to EWOULDBLOCK courtesy of the read() call.
  50.  *
  51.  *        write operations hide the EINPROGRESS 'error' from the write()
  52.  *        call, but generate EALREADY when a second operation is attempted.
  53.  *
  54.  *        NOTE: the write() call ties up the stdio buffer until it finishes. 
  55.  *
  56.  *        How to code a write operation....
  57.  *
  58.  *        for(;;)
  59.  *        {
  60.  *            errno = 0;
  61.  *            if (s_fprintf(stream, blah, blah) != EOF)
  62.  *                break;
  63.  *            
  64.  *            if (errno == EALREADY)
  65.  *            {
  66.  *                Handle_Mac_Events();
  67.  *                continue;
  68.  *            }
  69.  *            else
  70.  *            {
  71.  *                a real error ...
  72.  *            }
  73.  *        }
  74.  *
  75.  *        How to code a read ...
  76.  *
  77.  *        for(;;)
  78.  *        {
  79.  *            errno = 0;
  80.  *            c = s_fgetc(inFile);
  81.  *            if (c != EOF)
  82.  *                break;
  83.  *            if (errno == EWOULDBLOCK || errno == EALREADY)
  84.  *            {
  85.  *                Handle_Mac_Events();
  86.  *                continue;
  87.  *            }
  88.  *            else if (errno == 0)
  89.  *            {
  90.  *                a real end of file ...
  91.  *            }
  92.  *            else
  93.  *            {
  94.  *                a real error ...
  95.  *            }
  96.  *        }
  97.  */
  98.  
  99. #ifdef USEDUMP
  100. # pragma load "Socket.dump"
  101.  
  102. #else
  103. # include <Events.h>
  104. # include <Memory.h>
  105. # include <Types.h>
  106. # include <Stdio.h>
  107.  
  108. # include <s_types.h>
  109. # include <neti_in.h>
  110. # include <neterrno.h>
  111. # include <s_socket.h>
  112. # include <s_time.h>
  113. # include <s_uio.h>
  114.  
  115. # include "sock_str.h"
  116. # include "sock_int.h"
  117.  
  118. #endif
  119.  
  120. #include <StdArg.h>
  121.  
  122. extern SocketPtr sockets;
  123. extern SpinFn spinroutine;
  124.  
  125. /*
  126.  *    tuneable constants
  127.  */
  128. #define SOCK_IOINBUF_SIZE        128        /* Size of stdio input buffer */
  129. #define SOCK_IOOUTBUF_SIZE        128        /* Size of stdio output buffer */
  130.  
  131. static struct timeval select_poll = {0,0};
  132.  
  133. /*
  134.  *    s_fdopen() - open a stdio stream on a socket
  135.  */
  136. Ptr s_fdopen(
  137.     int fd,
  138.     char *type)
  139. {
  140. #pragma unused(type)
  141.     SocketPtr sp;
  142.     
  143. #if    SOCK_STDIO_DEBUG >= 3
  144.     dprintf("s_fdopen: opening on fd %d\n",fd);
  145. #endif
  146.     if (! sock_good_fd(fd)) 
  147.     {
  148.         (void)sock_err(EBADF);
  149.         return(NULL);
  150.     }
  151.         
  152.     sp = sockets+fd;
  153.     if (is_stdio(sp)) 
  154.         return((Ptr)sp);
  155.     
  156.     sp->inbuf = (char *)NewPtr(SOCK_IOINBUF_SIZE);
  157.     if (sp->inbuf == NULL) 
  158.     {
  159.         errno = ENOMEM;
  160.         return(NULL);
  161.     }
  162.     sp->outbuf = (char *)NewPtr(SOCK_IOOUTBUF_SIZE);
  163.     if (sp->outbuf == NULL) 
  164.     {
  165.         DisposPtr(sp->inbuf);
  166.         errno = ENOMEM;
  167.         return(NULL);
  168.     }
  169.     
  170.     sp->inbufptr  = sp->inbuf;
  171.     sp->inbufcount  = 0;
  172.     sp->outbufptr = sp->outbuf;
  173.     sp->outbufcount = 0;
  174.     
  175.     sp->ioerr = false;
  176.     sp->ioeof = false;
  177.  
  178.     return((Ptr)sp);
  179. }
  180.  
  181. /*
  182.  *    s_fileno()
  183.  */
  184. int s_fileno(
  185.     SocketPtr sp)
  186. {
  187. #if    SOCK_STDIO_DEBUG >= 3
  188.     dprintf("s_fileno:  on FILE * %08x\n",sp);
  189. #endif
  190.     if (! is_stdio(sp)) 
  191.     {
  192.         return(sock_err(EBADF));
  193.         return(EOF);
  194.     }
  195. #if    SOCK_STDIO_DEBUG >= 5
  196.     dprintf("   returning fd %d\n",sp->fd);
  197. #endif
  198.     return(sp->fd);
  199. }
  200.  
  201. /*
  202.  *    s_fgetc()
  203.  *
  204.  */
  205. int s_fgetc(
  206.     SocketPtr sp)
  207. {
  208.     char c;    
  209.         
  210.     if (stdio_read(sp, &c, 1) != 1)
  211.         return(EOF);
  212.         
  213.     return(c);
  214. }
  215.  
  216. /*
  217.  *    s_ungetc()
  218.  *
  219.  */
  220. int s_ungetc(
  221.     char c,
  222.     SocketPtr sp)
  223. {
  224.     
  225. #if    SOCK_STDIO_DEBUG >=3
  226.     dprintf("s_ungetc: %08x\n",sp);
  227. #endif
  228.  
  229.     if (! is_stdio(sp)) 
  230.     {
  231.         (void)sock_err(EBADF);
  232.         return(EOF);
  233.     }
  234.  
  235.     if (sp->ioeof)        /* Once an EOF; Always an EOF */
  236.         return(EOF);
  237.         
  238.     /*
  239.      *    Pop onto buffer, if there is room. 
  240.      */
  241.     if (sp->inbufptr == sp->inbuf)
  242.         return(EOF);
  243.     else 
  244.     {
  245.         *(sp->inbufptr++) = c;
  246.         sp->inbufcount++;
  247.         return(0);
  248.     }
  249. }
  250.  
  251. /*
  252.  *    s_fread()
  253.  */
  254. int s_fread(
  255.     char *buffer,
  256.     int size,
  257.     int nitems,
  258.     SocketPtr sp)
  259. {
  260.     return(stdio_read(sp, buffer, size*nitems));
  261. }
  262.     
  263. /*
  264.  *    stdio_read()
  265.  *
  266.  *    Buffered i/o.  Read buflen chars into buf.
  267.  *  Returns length read, EOF on error.
  268.  */
  269. static int stdio_read(
  270.     SocketPtr sp,
  271.     char *buffer,
  272.     int buflen)
  273. {
  274.     unsigned long tocopy;
  275.     Ptr buf;
  276.     unsigned long len;
  277.     int cache = false;    /* a flag ===> read into sp->inbuf */
  278.  
  279. #if    SOCK_STDIO_DEBUG >=3
  280.     dprintf("stdio_read: %08x for %d bytes\n",sp,buflen);
  281. #endif    
  282.  
  283.     if (! is_stdio(sp)) 
  284.     {
  285.         (void)sock_err(EBADF);
  286.         return(EOF);
  287.     }
  288.  
  289.     if (sp->ioeof)        /* Once an EOF; Always an EOF */
  290.         return(EOF);
  291.  
  292.     /*
  293.      *    return already buffered characters
  294.      */
  295.     if (sp->inbufcount != 0) 
  296.     {
  297.         tocopy = min(sp->inbufcount, buflen);
  298.         bcopy(sp->inbufptr, buffer, tocopy);
  299.         sp->inbufptr += tocopy;
  300.         sp->inbufcount -= tocopy;
  301.         return(tocopy);
  302.     }
  303.  
  304.     if (buflen > SOCK_IOINBUF_SIZE) 
  305.     {
  306.         /*
  307.          *    Read into user's buffer
  308.          */
  309.         buf = buffer;
  310.         len = buflen;
  311.     }
  312.     else 
  313.     {
  314.         /*
  315.          *    Read into stdio buffer
  316.          */
  317.         cache = true;
  318.         buf     = sp->inbuf;
  319.         len        = SOCK_IOINBUF_SIZE;
  320.     }
  321.  
  322.     len = s_read(sp->fd, buf, len);
  323.     switch(len) 
  324.     {
  325.         case -1:
  326.             sp->ioerr = true;
  327.             return(EOF);
  328.             
  329.         case 0:
  330.             sp->ioeof = true;
  331.             return(EOF);
  332.     }
  333.     if (cache) 
  334.     {
  335.         tocopy = min(buflen, len);
  336.         bcopy(sp->inbuf, buffer, tocopy);    /* copy to client's buffer */
  337.         sp->inbufcount     = len - tocopy;
  338.         sp->inbufptr     = sp->inbuf + tocopy;
  339.         return(tocopy);
  340.     }
  341.     return(len);            
  342. }
  343.  
  344.  
  345. static int stdio_write(
  346.     SocketPtr sp,
  347.     char *buffer,
  348.     unsigned long buflen);
  349.     
  350. /*
  351.  *    s_fputc()
  352.  *
  353.  */
  354. int s_fputc(
  355.     char c,
  356.     SocketPtr sp)
  357. {
  358.     if (stdio_write(sp, &c, 1) == EOF)
  359.         return(EOF);
  360.         
  361.     return(c);
  362. }
  363.                 
  364. /*
  365.  *    s_fprintf()
  366.  * Modified to use StdArg macros by Charlie Reiman
  367.  * Wednesday, August 8, 1990 2:52:31 PM
  368.  *
  369.  */
  370. int s_fprintf(
  371.     SocketPtr sp,
  372.     char *fmt,
  373.     ...)
  374. {
  375.     va_list    nextArg;
  376.     int len;
  377.     char buf[1000];
  378.     
  379.     va_start(nextArg,fmt);
  380.     
  381.     (void) vsprintf(buf,fmt,nextArg);
  382.     len = strlen(buf);
  383.     return(stdio_write(sp, buf, len));
  384. }
  385.  
  386. /*
  387.  *    s_fwrite()
  388.  *
  389.  */
  390.  
  391. int s_fwrite(
  392.     char *buffer,
  393.     int size,
  394.     int nitems,
  395.     SocketPtr sp)
  396. {
  397.     return(stdio_write(sp, buffer, size*nitems));
  398. }
  399.  
  400. /*
  401.  *    stdio_write()
  402.  *
  403.  *    Buffered i/o.  Move buflen chars into stdio buf., writing out as necessary.
  404.  *    Returns # of characters written, or EOF.
  405.  */
  406. static int stdio_write(
  407.     SocketPtr sp,
  408.     char *buffer,
  409.     unsigned long buflen)
  410. {
  411.     long buffree;
  412.     struct iovec iov[2];
  413.     
  414. #if    SOCK_STDIO_DEBUG >=3
  415.     dprintf("stdio_write: %08x for %d bytes\n",sp,buflen);
  416. #endif    
  417.  
  418.     if (! is_stdio(sp))
  419.     {
  420.         (void) sock_err(EBADF);
  421.         return(EOF);
  422.     }
  423.     
  424.     /* will the new stuff fit in the buffer? */
  425.     buffree = SOCK_IOOUTBUF_SIZE - sp->outbufcount;
  426.     if (buflen < buffree)
  427.     {
  428.         /* yes...add it in */
  429.         bcopy(buffer, sp->outbufptr, buflen);
  430.         sp->outbufptr += buflen;
  431.         sp->outbufcount += buflen;
  432.         return(buflen);
  433.     }
  434.     else
  435.     {
  436.         /* no...send both buffers now */
  437.         iov[0].iov_len = sp->outbufcount;
  438.         iov[0].iov_base = sp->outbuf;
  439.         iov[1].iov_len = buflen;
  440.         iov[1].iov_base = buffer;
  441.         /* hide the 'error' generated by a non-blocking write */
  442.         if (s_writev(sp->fd,&iov[0],2) < 0 && errno != EINPROGRESS)
  443.         {
  444.             sp->ioerr = true;
  445.             return(EOF);
  446.         }
  447.  
  448.         sp->outbufptr = sp->outbuf;
  449.         sp->outbufcount = 0;
  450.  
  451.         return(buflen);
  452.     }
  453. }
  454.  
  455. /*
  456.  *    s_fflush()
  457.  *
  458.  */
  459. int s_fflush(
  460.     SocketPtr sp)
  461. {
  462. #if    SOCK_STDIO_DEBUG >=3
  463.     dprintf("s_fflush: %08x\n",sp);
  464. #endif
  465.     if (! is_stdio(sp))
  466.     {
  467.         (void)sock_err(EBADF);
  468.         return(EOF);
  469.     }
  470.     
  471.     if (sp->outbufcount == 0)
  472.         return(0);
  473.  
  474.     if (s_write(sp->fd,sp->outbuf,sp->outbufcount) < 0)
  475.         /* hide the 'error' generated by non-blocking I/O */
  476.         if (errno != EINPROGRESS)
  477.         {
  478.             sp->ioerr = true;
  479.             return(EOF);
  480.         }
  481.  
  482.     sp->outbufptr = sp->outbuf;
  483.     sp->outbufcount = 0;
  484.     return(0);
  485. }
  486.  
  487. /*
  488.  *    s_fclose() - close the stdio stream AND the underlying socket
  489.  */
  490. int s_fclose(
  491.     SocketPtr sp)
  492. {    
  493. #if    SOCK_STDIO_DEBUG >=3
  494.     dprintf("s_fclose: %08x\n",sp);
  495. #endif
  496.     
  497.     if (s_fflush(sp) == EOF) /* flush validates sp */
  498.         return(EOF);
  499.  
  500.     if (sp->inbuf != NULL) DisposPtr(sp->inbuf);
  501.     if (sp->outbuf != NULL) DisposPtr(sp->outbuf);
  502.     
  503.     return(s_close(sp->fd));
  504. }
  505.  
  506. /*
  507.  *    s_ferror()
  508.  */
  509. int s_ferror(
  510.     SocketPtr sp)
  511. {
  512.     if (! is_stdio(sp))
  513.     {
  514.         (void)sock_err(EBADF);
  515.         return(EOF);
  516.     }
  517.     return(sp->ioerr);
  518. }
  519.  
  520. /*
  521.  *    s_feof()
  522.  */
  523. int s_feof(
  524.     SocketPtr sp)
  525. {
  526.     if (! is_stdio(sp))
  527.     {
  528.         (void)sock_err(EBADF);
  529.         return(EOF);
  530.     }    
  531.     return(sp->ioeof);
  532. }
  533.  
  534. /*
  535.  *    s_clearerr()
  536.  */
  537. int s_clearerr(
  538.     SocketPtr sp)
  539. {    
  540.     if (! is_stdio(sp))
  541.     {
  542.         (void)sock_err(EBADF);
  543.         return(EOF);
  544.     }
  545.     sp->ioerr = false;
  546.     sp->ioeof = false;
  547.     return (0);
  548. }
  549.  
  550.