home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xntp3.zip / kernel / tty_clk_STREAM < prev    next >
Text File  |  1992-05-28  |  5KB  |  267 lines

  1. /*
  2.  * Timestamp STREAMS module for SunOS 4.1
  3.  *
  4.  * Copyright 1991, Nick Sayer
  5.  *
  6.  * Special thanks to Greg Onufer for his debug assists.
  7.  *
  8.  * Should be PUSHed directly on top of a serial I/O channel.
  9.  * For any character in a user-designated set, adds a kernel
  10.  * timestamp to that character.
  11.  *
  12.  * BUGS:
  13.  *
  14.  * Only so many characters can be timestamped. This number, however,
  15.  * is adjustable.
  16.  *
  17.  * The null character ($00) cannot be timestamped.
  18.  *
  19.  * The M_DATA messages passed upstream will not be the same
  20.  * size as when they arrive from downstream, even if no
  21.  * timestamp character is in the message. This, however,
  22.  * should not affect anything.
  23.  *
  24.  */
  25.  
  26. #include "clk.h"
  27. #if NCLK > 0
  28. /*
  29.  * How big should the messages we pass upstream be?
  30.  */
  31. #define MESSAGE_SIZE 128
  32.  
  33. #include <string.h>
  34. #include <sys/types.h>
  35. #include <sys/stream.h>
  36. #include <sys/param.h>
  37. #include <sys/time.h>
  38. #include <sys/kernel.h>
  39. #include <sys/user.h>
  40. #include <sys/errno.h>
  41. #include <syslog.h>
  42.  
  43. #include <sys/clkdefs.h>
  44.  
  45. static struct module_info rminfo = { 0, "clk", 0, INFPSZ, 0, 0 };
  46. static struct module_info wminfo = { 0, "clk", 0, INFPSZ, 0, 0 };
  47. static int clkopen(), clkrput(), clkwput(), clkclose();
  48.  
  49. static struct qinit rinit = { clkrput, NULL, clkopen, clkclose, NULL,
  50.     &rminfo, NULL };
  51.  
  52. static struct qinit winit = { clkwput, NULL, NULL, NULL, NULL,
  53.     &wminfo, NULL };
  54.  
  55. struct streamtab clkinfo = { &rinit, &winit, NULL, NULL };
  56.  
  57. struct priv_data_type
  58. {
  59.   char in_use;
  60.   char string[CLK_MAXSTRSIZE];
  61. } priv_data[NCLK];
  62.  
  63. char first_open=1;
  64.  
  65. /*
  66.  * God only knows why, but linking with strchr() and index() fail
  67.  * on my system, so here's a renamed copy.
  68.  */
  69.  
  70. u_char *str_chr(s,c)
  71. u_char *s;
  72. int c;
  73. {
  74.   while (*s)
  75.     if(*s++ == c)
  76.       return (s-1);
  77.   return NULL;
  78. }
  79.  
  80. /*ARGSUSED*/
  81. static int clkopen(q, dev, flag, sflag)
  82. queue_t *q;
  83. dev_t dev;
  84. int flag;
  85. int sflag;
  86. {
  87.   int i;
  88.  
  89. /* Damn it! We can't even have the global data struct properly
  90.    initialized! So we have a mark to tell us to init the global
  91.    data on the first open */
  92.  
  93.   if (first_open)
  94.   {
  95.     first_open=0;
  96.  
  97.     for(i=0;i<NCLK;i++)
  98.       priv_data[i].in_use=0;
  99.   }
  100.  
  101.   for(i=0;i<NCLK;i++)
  102.     if(!priv_data[i].in_use)
  103.     {
  104.       priv_data[i].in_use++;
  105.       ((struct priv_data_type *) (q->q_ptr))=priv_data+i;
  106.       priv_data[i].string[0]=0;
  107.       return (0);
  108.     }
  109.   u.u_error = EBUSY;
  110.   return (OPENFAIL);
  111. }
  112.  
  113. /*ARGSUSED*/
  114. static int clkclose(q, flag)
  115. queue_t *q;
  116. int flag;
  117. {
  118.   ((struct priv_data_type *) (q->q_ptr))->in_use=0;
  119.  
  120.   return (0);
  121. }
  122.  
  123. /*
  124.  * Now the crux of the biscuit.
  125.  *
  126.  * If it's an M_DATA package, we take each character and pass
  127.  * it to clkchar.
  128.  */
  129.  
  130. void clkchar();
  131.  
  132. static int clkrput(q, mp)
  133. queue_t *q;
  134. mblk_t *mp;
  135. {
  136.   mblk_t *bp;
  137.  
  138.   switch(mp->b_datap->db_type)
  139.   {
  140.     case M_DATA:
  141.       clkchar(0,q,2);
  142.       for(bp=mp; bp!=NULL; bp=bp->b_cont)
  143.       {
  144.     while(bp->b_rptr < bp->b_wptr)
  145.       clkchar( ((u_char)*(bp->b_rptr++)) , q , 0 );
  146.       }
  147.       clkchar(0,q,1);
  148.       freemsg(mp);
  149.     break;
  150.     default:
  151.       putnext(q,mp);
  152.     break;
  153.   }
  154.  
  155. }
  156.  
  157. /*
  158.  * If it's a matching M_IOCTL, handle it.
  159.  */
  160.  
  161. static int clkwput(q, mp)
  162. queue_t *q;
  163. mblk_t *mp;
  164. {
  165.   struct iocblk *iocp;
  166.  
  167.   switch(mp->b_datap->db_type)
  168.   {
  169.     case M_IOCTL:
  170.       iocp=(struct iocblk*) mp->b_rptr;
  171.       if (iocp->ioc_cmd==CLK_SETSTR)
  172.       {
  173.         strncpy( ((struct priv_data_type *) (RD(q)->q_ptr))->string,
  174.       (char *) mp->b_cont->b_rptr,CLK_MAXSTRSIZE);
  175.         /* make sure it's null terminated */
  176.     ((struct priv_data_type *) (RD(q)->q_ptr))->string[CLK_MAXSTRSIZE-1]=0;
  177.     mp->b_datap->db_type = M_IOCACK;
  178.     qreply(q,mp);
  179.       }
  180.       else
  181.     putnext(q,mp);
  182.     break;
  183.     default:
  184.       putnext(q,mp);
  185.     break;
  186.   }
  187. }
  188.  
  189. /*
  190.  * Now clkchar. It takes a character, a queue pointer and an action
  191.  * flag and depending on the flag either:
  192.  *
  193.  * 0 - adds the character to the current message. If there's a
  194.  * timestamp to be done, do that too. If the message is less than
  195.  * 8 chars from being full, link in a new one, and set it up for
  196.  * the next call.
  197.  *
  198.  * 1 - sends the whole mess to Valhala.
  199.  *
  200.  * 2 - set things up.
  201.  *
  202.  * Yeah, it's an ugly hack. Complaints may be filed with /dev/null.
  203.  */
  204.  
  205.  
  206. void clkchar(c,q,f)
  207.     register u_char c;
  208.     queue_t *q;
  209.     char f;
  210. {
  211.   static char error;
  212.   static mblk_t *message,*mp;
  213.   struct timeval tv;
  214.  
  215. /* Get a timestamp ASAP! */
  216.   uniqtime(&tv);
  217.  
  218.   switch(f)
  219.   {
  220.     case 1:
  221.       if (!error)
  222.         putnext(q,message);
  223.     break;
  224.     case 2:
  225.       mp=message= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO);
  226.       error=(message==NULL);
  227.       if (error)
  228.     log(LOG_ERR,"clk: cannot allocate message - data lost");
  229.     break;
  230.     case 0:
  231.       if (error) /* If we had an error, forget it. */
  232.     return;
  233.  
  234.       *mp->b_wptr++=c; /* Put the char away first.
  235.  
  236.       /* If it's in the special string, append a struct timeval */
  237.  
  238.       if (str_chr( ((struct priv_data_type *) (q->q_ptr))->string ,
  239.         c )!=NULL)
  240.       {
  241.       int i;
  242.  
  243.       for (i=0;i<sizeof(struct timeval);i++)
  244.         *mp->b_wptr++= *( ((char*)&tv) + i );
  245.       }
  246.  
  247.       /* If we don't have space for a complete struct timeval, and a
  248.          char, it's time for a new mp block */
  249.  
  250.       if (((mp->b_wptr-mp->b_rptr)+sizeof(struct timeval)+2)>MESSAGE_SIZE)
  251.       {
  252.       mp->b_cont= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO);
  253.       error=(mp->b_cont==NULL);
  254.       if (error)
  255.       {
  256.         log(LOG_ERR,"clk: cannot allocate message - data lost");
  257.         freemsg(message);
  258.           }
  259.           mp=mp->b_cont;
  260.       }
  261.  
  262.     break;
  263.   }
  264. }
  265.  
  266. #endif
  267.