home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / network / src_1218.zip / SOCKUSER.C < prev    next >
C/C++ Source or Header  |  1991-03-10  |  12KB  |  547 lines

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