home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / SOCKUSER.C < prev    next >
C/C++ Source or Header  |  1993-04-03  |  12KB  |  557 lines

  1. /****************************************************************************
  2. *    sockuser.c                                                                *
  3. *    $Id: sockuser.c 1.2 93/04/03 16:21:39 ROOT_DOS Exp $
  4. *                                                                            *
  5. *    01 Apr 93    1.3        GT    recvchar () - skip ^Z in ASCII mode.            *
  6. ****************************************************************************/
  7.  
  8. /* Higher level user subroutines built on top of the socket primitives
  9.  * Copyright 1991 Phil Karn, KA9Q
  10.  */
  11. #include "global.h"
  12. #ifdef    ANSIPROTO
  13. #include <stdarg.h>
  14. #endif
  15. #include "mbuf.h"
  16. #include "proc.h"
  17. #include "socket.h"
  18. #include "usock.h"
  19. #include "session.h"
  20. #include "nr4.h"
  21.  
  22.  
  23. /* Higher-level receive routine, intended for connection-oriented sockets.
  24.  * Can be used with datagram sockets, although the sender id is lost.
  25.  */
  26. int
  27. recv(s,buf,len,flags)
  28. int s;        /* Socket index */
  29. char *buf;    /* User buffer */
  30. int len;    /* Max length to receive */
  31. int flags;    /* Unused; will eventually select oob data, etc */
  32. {
  33.     struct mbuf *bp;
  34.     int cnt;
  35.  
  36.     if(len == 0)
  37.         return 0;    /* Otherwise would be interp as "all" */
  38.  
  39.     cnt = recv_mbuf(s,&bp,flags,NULLCHAR,(int *)NULL);
  40.     if(cnt > 0){
  41.         cnt = min(cnt,len);
  42.         pullup(&bp,buf,(int16)cnt);
  43.         free_p(bp);
  44.     }
  45.     return cnt;
  46. }
  47. /* Higher level receive routine, intended for datagram sockets. Can also
  48.  * be used for connection-oriented sockets, although from and fromlen are
  49.  * ignored.
  50.  */
  51. int
  52. recvfrom(s,buf,len,flags,from,fromlen)
  53. int s;        /* Socket index */
  54. char *buf;    /* User buffer */
  55. int len;    /* Maximum length */
  56. int flags;    /* Unused; will eventually select oob data, etc */
  57. char *from;    /* Source address, only for datagrams */
  58. int *fromlen;    /* Length of source address */
  59. {
  60.     struct mbuf *bp;
  61.     register int cnt;
  62.  
  63.     cnt = recv_mbuf(s,&bp,flags,from,fromlen);
  64.     if(cnt > 0){
  65.         cnt = min(cnt,len);
  66.         pullup(&bp,buf,(int16)cnt);
  67.         free_p(bp);
  68.     }
  69.     return cnt;
  70. }
  71. /* High level send routine */
  72. int
  73. send(s,buf,len,flags)
  74. int s;        /* Socket index */
  75. char *buf;    /* User buffer */
  76. int len;    /* Length of buffer */
  77. int flags;    /* Unused; will eventually select oob data, etc */
  78. {
  79.     register struct mbuf *bp;
  80.     char sock[MAXSOCKSIZE];
  81.     int i = MAXSOCKSIZE;
  82.  
  83.     if(getpeername(s,sock,&i) == -1)
  84.         return -1;
  85.     bp = qdata(buf,(int16)len);
  86.     return send_mbuf(s,bp,flags,sock,i);
  87. }
  88. /* High level send routine, intended for datagram sockets. Can be used on
  89.  * connection-oriented sockets, but "to" and "tolen" are ignored.
  90.  */
  91. int
  92. sendto(s,buf,len,flags,to,tolen)
  93. int s;        /* Socket index */
  94. char *buf;    /* User buffer */
  95. int len;    /* Length of buffer */
  96. int flags;    /* Unused; will eventually select oob data, etc */
  97. char *to;    /* Destination, only for datagrams */
  98. int tolen;    /* Length of destination */
  99. {
  100.     register struct mbuf *bp;
  101.  
  102.     bp = qdata(buf,(int16)len);
  103.     return send_mbuf(s,bp,flags,to,tolen);
  104. }
  105. /* Receive a newline-terminated line from a socket, returning # chars read.
  106.  * The end-of-line sequence is recognized and translated into a single '\n'.
  107.  */
  108. int
  109. recvline(s,buf,len)
  110. int s;        /* Socket index */
  111. char *buf;    /* User buffer */
  112. unsigned len;    /* Length of buffer */
  113. {
  114.     int c;
  115.     int cnt = 0;
  116.  
  117.     while(len-- > 1){
  118.         if((c = recvchar(s)) == EOF){
  119.             cnt = -1;
  120.             break;
  121.         }
  122.         if(buf != NULLCHAR)
  123.             *buf++ = c;
  124.         cnt++;
  125.         if(uchar(c) == '\n')
  126.             break;
  127.     }
  128.     if(buf != NULLCHAR)
  129.         *buf = '\0';
  130.     return cnt;
  131. }
  132. #if    defined(ANSIPROTO)
  133. /* Do printf on a user socket */
  134. int
  135. usprintf(int s,char *fmt,...)
  136. {
  137.     va_list args;
  138.     int len;
  139.  
  140.     va_start(args,fmt);
  141.     len = usvprintf(s,fmt,args);
  142.     va_end(args);
  143.     return len;
  144. }
  145. /* Printf on standard output socket */
  146. int
  147. tprintf(char *fmt,...)
  148. {
  149.     va_list args;
  150.     int len;
  151.  
  152.     va_start(args,fmt);
  153.     len = usvprintf(Curproc->output,fmt,args);
  154.     va_end(args);
  155.     return len;
  156. }
  157. /* The guts of printf, uses variable arg version of sprintf */
  158. int
  159. usvprintf(int s,char *fmt, va_list args)
  160. {
  161.     int len,withargs;
  162.     char *buf;
  163.  
  164.     if(strchr(fmt,'%') == NULLCHAR){
  165.         /* Common case optimization: no args, so we don't
  166.          * need vsprintf()
  167.          */
  168.         withargs = 0;
  169.         buf = fmt;
  170.         len = strlen(fmt);
  171.     } else {
  172.         /* Use a default value that is hopefully longer than the
  173.          * biggest output string we'll ever print (!)
  174.          */
  175.         withargs = 1;
  176.         buf = mallocw(SOBUF);
  177.         vsprintf(buf,fmt,args);
  178.         len = strlen(buf);
  179.     }
  180.     if(usputs(s,buf) == EOF)
  181.         len = -1;
  182.     if(withargs)
  183.         free(buf);
  184.     return len;
  185. }
  186. #else
  187. /*VARARGS*/
  188. /* Printf to standard output socket */
  189. int
  190. tprintf(fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
  191. char *fmt;        /* Message format */
  192. int arg1,arg2,arg3;    /* Arguments */
  193. int arg4,arg5,arg6;
  194. int arg7,arg8,arg9;
  195. int arg10,arg11,arg12;
  196. {
  197.     return usprintf(Curproc->output,fmt,arg1,arg2,arg3,arg4,arg5,arg6,
  198.         arg7,arg8,arg9,arg10,arg11,arg12);
  199. }
  200. /* Printf to socket. Doesn't use ANSI vsprintf */
  201. int
  202. usprintf(s,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
  203. int s;            /* Socket index */
  204. char *fmt;        /* Message format */
  205. int arg1,arg2,arg3;    /* Arguments */
  206. int arg4,arg5,arg6;
  207. int arg7,arg8,arg9;
  208. int arg10,arg11,arg12;
  209. {
  210.     int len,withargs;
  211.     char *buf;
  212.  
  213.     if(strchr(fmt,'%') == NULLCHAR){
  214.         /* No args, so we don't need vsprintf() */
  215.         withargs = 0;
  216.         buf = fmt;
  217.         len = strlen(fmt);
  218.     } else {
  219.         /* Use a default value that is hopefully longer than the
  220.          * biggest output string we'll ever print (!)
  221.          */
  222.         withargs = 1;
  223.         buf = mallocw(SOBUF);
  224.         sprintf(buf,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,
  225.          arg8,arg9,arg10,arg11,arg12);
  226.         len = strlen(buf);
  227.     }
  228.     if(usputs(s,buf) == EOF)
  229.         len = -1;
  230.  
  231.     if(withargs)
  232.         free(buf);
  233.     return len;
  234. }
  235. #endif
  236. /* Buffered putchar to a socket */
  237. int
  238. usputc(s,c)
  239. int s;
  240. char c;
  241. {
  242.     struct usock *up;
  243.     register struct mbuf *bp;
  244.     char *cp;
  245.     int newline,len;
  246.  
  247.     if((up = itop(s)) == NULLUSOCK){
  248.         errno = EBADF;
  249.         return -1;
  250.     }
  251.     if(c == '\n' && (up->flag & SOCK_ASCII)){
  252.         newline = 1;
  253.         len = strlen(up->eol);
  254.     } else {
  255.         newline = 0;
  256.         len = 1;
  257.     }
  258.     /* Make sure there's room in the current buffer, if any */
  259.     if((bp = up->obuf) != NULLBUF){
  260.         if((bp->cnt >= bp->size - len) && usflush(s) == -1)
  261.             return EOF;
  262.     }
  263.     if(up->obuf == NULLBUF){
  264.         /* Allocate a buffer of appropriate size */
  265.         switch(up->type){
  266.         case TYPE_NETROML4:
  267.             up->obuf = ambufw(NR4MAXINFO);
  268.             break;
  269.         default:
  270.             up->obuf = ambufw(BUFSIZ);
  271.             break;
  272.         }
  273.     }
  274.     /* Note: the buffer must be larger than the end-of-line sequence! */
  275.     bp = up->obuf;
  276.     cp = &bp->data[bp->cnt];
  277.     if(newline){
  278.         /* Translate into appropriate end-of-line sequence */
  279.         strncpy(cp,up->eol,len);
  280.     } else {
  281.         *cp = c;
  282.     }
  283.     bp->cnt += len;
  284.     /* Flush if necessary */
  285.     if(c == up->flush && up->flush != -1 && usflush(s) == -1)
  286.             return -1;
  287.  
  288.     return (int)uchar(c);
  289. }
  290. /* Put a character to standard output socket */
  291. int
  292. tputc(c)
  293. char c;
  294. {
  295.     return usputc(Curproc->output,c);
  296. }
  297. #ifndef    oldusputs
  298. /* Buffered puts to a socket */
  299. int
  300. usputs(s,buf)
  301. int s;
  302. char *buf;
  303. {
  304.     register struct usock *up;
  305.     register struct mbuf *bp;
  306.     char *cp,*wp;
  307.     int16 len,clen;
  308.     int doflush;
  309.     int eol_len;
  310.     int16 flushpt;
  311.     int ascii;
  312.  
  313.     if((up = itop(s)) == NULLUSOCK){
  314.         errno = EBADF;
  315.         return EOF;
  316.     }
  317.     ascii = up->flag & SOCK_ASCII;
  318.     if(ascii)
  319.         eol_len = strlen(up->eol);
  320.     doflush = (up->flush != -1) && (strchr(buf,up->flush) != NULLCHAR);
  321.     len = strlen(buf);
  322.  
  323.     while(len != 0){
  324.         if(up->obuf == NULLBUF){
  325.             /* Allocate a buffer of appropriate size */
  326.             switch(up->type){
  327.             case TYPE_NETROML4:
  328.                 clen = NR4MAXINFO;
  329.                 break;
  330.             default:
  331.                 clen = BUFSIZ;
  332.                 break;
  333.             }
  334.             up->obuf = ambufw(clen);
  335.         }
  336.         /* Note: the buffer must be larger than the end-of-line sequence! */
  337.         bp = up->obuf;
  338.         wp = &bp->data[bp->cnt];
  339.         if(ascii && (cp = strchr(buf,'\n')) != NULLCHAR){
  340.             /* Copy up to, but not including, newline */
  341.             clen = cp - buf;
  342.         } else {
  343.             /* Copy whole thing */
  344.             clen = len;
  345.         }
  346.         /* ...but no more than the room available */
  347.         clen = min(clen,bp->size - bp->cnt);
  348.         if(clen != 0){
  349.             memcpy(wp,buf,clen);
  350.             wp += clen;
  351.             bp->cnt += clen;
  352.             buf += clen;
  353.             len -= clen;
  354.         }
  355.         /* Set flush threshold to allow for eol, if enabled */
  356.         if(ascii)
  357.             flushpt = bp->size - eol_len;
  358.         else
  359.             flushpt = bp->size;
  360.  
  361.         if(ascii && *buf == '\n' && bp->cnt < flushpt){
  362.             /* Add appropriate end-of-line sequence */
  363.             strncpy(wp,up->eol,eol_len);
  364.             wp += eol_len;
  365.             bp->cnt += eol_len;
  366.             buf++;    /* Skip newline in buffer */
  367.             len--;
  368.         }
  369.         if(bp->cnt >= flushpt){
  370.             /* Buffer full, flush and get another */
  371.             if(usflush(s) == -1)
  372.                 return EOF;
  373.         }
  374.     }    
  375.     if(doflush && usflush(s) == -1)
  376.         return EOF;
  377.  
  378.     return 0;
  379. }
  380.  
  381. #else
  382.  
  383. int
  384. usputs(s,x)
  385. int s;
  386. register char *x;
  387. {
  388.     while(*x != '\0')
  389.         if(usputc(s,*x++) == EOF)
  390.             return EOF;
  391.     return 0;
  392. }
  393. #endif
  394.  
  395. /* Put a string to standard output socket */
  396. int
  397. tputs(s)
  398. char *s;
  399. {
  400.     return usputs(Curproc->output,s);
  401. }
  402.  
  403. /* Read a raw character from a socket with stream buffering. */
  404. int
  405. rrecvchar(s)
  406. int s;            /* Socket index */
  407. {
  408.     register struct usock *up;
  409.  
  410.     if((up = itop(s)) == NULLUSOCK){
  411.         return EOF;
  412.     }
  413.     /* Replenish if necessary */
  414.     if(up->ibuf == NULLBUF && recv_mbuf(s,&up->ibuf,0,NULLCHAR,0) <= 0)
  415.         return EOF;
  416.  
  417.     return PULLCHAR(&up->ibuf);    /* Returns -1 if eof */
  418. }
  419. /* This function recognizes the end-of-line sequence for the stream
  420.  * and translates it into a single '\n'.
  421.  */
  422. int
  423. recvchar(s)
  424. int s;            /* Socket index */
  425. {
  426.     int c;
  427.     register struct usock *up;
  428.  
  429.     if((up = itop(s)) == NULLUSOCK)
  430.         return EOF;
  431.  
  432.     c = rrecvchar(s);
  433.  
  434.     while (c == '\032' && (up->flag & SOCK_ASCII) != 0)
  435.         c = rrecvchar (s);                /* skip embedded ^Z                    */
  436.  
  437.     if(c != up->eol[0] || !(up->flag & SOCK_ASCII))
  438.         return c;
  439.  
  440.     /* This is the first char of a eol sequence. If the eol sequence is
  441.      * more than one char long, eat the next character in the input stream.
  442.      */
  443.     if(up->eol[1] != '\0'){
  444.         (void)rrecvchar(s);
  445.     }
  446.     return '\n';
  447. }
  448. /* Flush output on a socket stream */
  449. int
  450. usflush(s)
  451. int s;
  452. {
  453.     register struct usock *up;
  454.     struct mbuf *bp;
  455.  
  456.     if((up = itop(s)) == NULLUSOCK)
  457.         return -1;
  458.  
  459.     if(up->obuf != NULLBUF){
  460.         bp = up->obuf;
  461.         up->obuf = NULLBUF;
  462.         return send_mbuf(s,bp,0,NULLCHAR,0);
  463.     }
  464.     return 0;
  465. }
  466. /* Flush output socket */
  467. void
  468. tflush()
  469. {
  470.     usflush(Current->output);
  471. }
  472.  
  473. /* Print prompt and read one character */
  474. int
  475. keywait(prompt,flush)
  476. char *prompt;    /* Optional prompt */
  477. int flush;    /* Flush queued input? */
  478. {
  479.     int c;
  480.     int i;
  481.  
  482.     if(flush && socklen(Curproc->input,1) != 0)
  483.         recv_mbuf(Curproc->input,NULLBUFP,0,NULLCHAR,0); /* flush */
  484.     if(prompt == NULLCHAR)
  485.         prompt = "Hit enter to continue"; 
  486.     tprintf(prompt);
  487.     tflush();
  488.     c = recvchar(Curproc->input);
  489.     /* Get rid of the prompt */
  490.     for(i=strlen(prompt);i != 0;i--)
  491.         tputc('\b');
  492.     for(i=strlen(prompt);i != 0;i--)
  493.         tputc(' ');
  494.     for(i=strlen(prompt);i != 0;i--)
  495.         tputc('\b');
  496.     tflush();
  497.     return (int)c;
  498. }
  499.  
  500. /* Set the end-of-line sequence on a socket */
  501. int
  502. seteol(s,seq)
  503. int s;
  504. char *seq;
  505. {
  506.     register struct usock *up;
  507.  
  508.     if((up = itop(s)) == NULLUSOCK)
  509.         return -1;
  510.  
  511.     if(seq != NULLCHAR)
  512.         strncpy(up->eol,seq,sizeof(up->eol));
  513.     else
  514.         *up->eol = '\0';
  515.     return 0;
  516. }
  517. /* Enable/disable eol translation, return previous state */
  518. int
  519. sockmode(s,mode)
  520. int s,mode;
  521. {
  522.     struct usock *up;
  523.     int prev;
  524.  
  525.     if((up = itop(s)) == NULLUSOCK)
  526.         return -1;
  527.     usflush(s);
  528.     prev = up->flag;
  529.     switch(mode){
  530.     case SOCK_BINARY:
  531.     case SOCK_ASCII:
  532.         up->flag = mode;
  533.         break;
  534.     default:
  535.         break;
  536.     }
  537.     return prev;
  538. }
  539. /* Specify the character to trigger automatic output buffer
  540.  * flushing, or -1 to disable it. Return the previous setting.
  541.  */
  542. int
  543. setflush(s,c)
  544. int s;
  545. int c;
  546. {
  547.     register struct usock *up;
  548.     int old;
  549.  
  550.     if((up = itop(s)) == NULLUSOCK)
  551.         return -1;
  552.  
  553.     old = up->flush;
  554.     up->flush = c;
  555.     return old;
  556. }
  557.