Saturday, November 8, 2014

Unix Prog: streams mechanism(3)

1. stream write mode
ioctl can be used to get or set the write mode.
ioctl can use: I_GWROPT to get the write mode.
ioctl can also use: I_SWROPT to set the write mode.

Current two write modes:
1) SNDZERO: a zero-length write to a pipe or FIFO will cause a zero-length message to be sent downstream
2) SNDPIPE: causes SIGPIPE to be sent to the calling process that calls either write or putmsg after an error has occured on a stream.

System Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/stropts.h  
 ......  
 #define I_SWROPT  (__SID |19) /* Set the write mode. */  
 #define I_GWROPT  (__SID |20) /* Return the current write mode setting. */  
 ......  
 /* Possible mode for `I_SWROPT'. */  
 #define SNDZERO     0x001  /* Send a zero-length message downstream when a  
                   `write' of 0 bytes occurs. */  
 #ifdef __USE_GNU  
 # define SNDPIPE    0x002  /* Send SIGPIPE on write and putmsg if  
                   sd_werror is set. */  
 #endif  
 ......  

2. getmsg, getpmsg
System Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/stropts.h  
 ......  
 /* Receive next message from a STREAMS file.  
   
   This function is a cancellation point and therefore not marked with  
   __THROW. */  
 extern int getmsg (int __fildes, struct strbuf *__restrict __ctlptr,  
           struct strbuf *__restrict __dataptr,  
           int *__restrict __flagsp);  
   
 /* Receive next message from a STREAMS file, with *FLAGSP allowing to  
   control which message.  
   
   This function is a cancellation point and therefore not marked with  
   __THROW. */  
 extern int getpmsg (int __fildes, struct strbuf *__restrict __ctlptr,  
           struct strbuf *__restrict __dataptr,  
           int *__restrict __bandp, int *__restrict __flagsp);  
 ......  

Rules for getmsg:
1) If the integer pointed to by flagptr is 0, getmsg returns the next message on the stream head's read queue. After receiving the message, if the message is high-priority message, the integer pointed to by flagptr is set to RS_HIPRI.
2) If we want to only get the high-priority message, before calling, we need to set the integer pointed to by flagptr to RS_HIPRI.

Rules for getpmsg:
1) We can set the integer pointed to by flagptr to MSG_HIPRI to receive only high-priority messages. We can set the integer to MSG_BAND and then set the integer pointed to by bandptr to a nonzero priority value to receive only messages from that band, or higher priority.
2) If we only want to receive the first available message, we can set the integer pointed to by flagptr to MSG_ANY; on return, the integer will be overwritten with either MSG_HIPRI or MSG_BAND, depending on the type of message received. If the received message was not a high-priority message, the integer pointed to by bandptr will contain the message's priority band.

Rule for ctlptr, dataptr:
1) If ctlptr->maxlen is -1, the control portion of the message will remain on the stream head's read queue, and we will not process it.
2) If dataptr->maxlen is -1, the data portion of the message is not processed and remains the on the stream head's read queue.

3. stream read mode:
We can use ioctl to change the stream read mode. We need to use "I_GRDOPT" as second argument to get the stream read mode, we also need to use "I_SRDOPT" as the second argument to set up the stream read mode.

The read mode is a combination of message read mode and protocol read mode:
1) message read mode:
RNORM: normal, byte-stream mode, either the requested number of bytes have been read or there is no more data.
RMSGN: message-nondiscard mode. either the requested number of bytes have been read or a message boundary is encountered. If it reads the partial message, the rest of the data in the message is left on the stream for subsequent read.
RMSGD: message-discard mode. If a partial message is used, the remainder of the message is discarded.

2) control information read mode:
RPROTNORM: Protocol-normal mode
RPROTDAT: protocol-data mode, read returns the control portion as data
RPROTDIS: protocol-discard mode: read discards the control information but returns any data in the message.

Only one of read mode and one of control mode can be set at a time, default mode is: RNORM | RPROTNORM

System Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/stropts.h  
 ......  
 /* Options for `I_SRDOPT'. */  
 #define RNORM      0x0000 /* Byte-STREAM mode, the default. */  
 #define RMSGD      0x0001 /* Message-discard mode.  */  
 #define RMSGN      0x0002 /* Message-nondiscard mode.  */  
 #define RPROTDAT    0x0004 /* Deliver the control part of a message as  
                   data. */  
 #define RPROTDIS    0x0008 /* Discard the control part of a message,  
                   delivering any data part. */  
 #define RPROTNORM    0x0010 /* Fail `read' with EBADMSG if a message  
                   containing a control part is at the front  
                   of the STREAM head read queue. */  
 ......  

4. Example:
read.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<stropts.h>  
   
 #define BUFFSIZE 4096  
   
 int main(int argc, char* argv[])  
 {  
  int n, flag;  
  char ctlbuf[BUFFSIZE], datbuf[BUFFSIZE];  
  struct strbuf ctl, dat;  
   
  // Setup the buffer  
  ctl.buf = ctlbuf;  
  ctl.maxlen = BUFFSIZE;  
  dat.buf = datbuf;  
  dat.maxlen = BUFFSIZE;  
   
  // Read the data from standard input stream  
  for(;;) {  
   flag = 0;  
   if((n = getmsg(STDIN_FILENO, &ctl, &dat, &flag)) < 0) {  
    printf("getmsg error!\n");  
    exit(1);  
   }  
   fprintf(stderr, "flag = %d, ctl.len = %d, dat.len = %d\n", flag, ctl.len, dat.len);  
   if(dat.len == 0) exit(0);  
   else if(dat.len > 0)  
    if(write(STDOUT_FILENO, dat.buf, dat.len) != dat.len) {  
     printf("write error!\n");  
     exit(2);  
    }  
  }  
   
  exit(0);  
 }  

shell:
getmsg is not implemented on linux OS. under solaris, the expected output:
 $echo hello, world | ./read.out  
 flag = 0, ctl.len = -1, dat.len = 13  
 hello, world  
 flag = 0, ctl.len = 0, dat.len = 0  
 $./read.out  
 this is line 1  
 flag = 0, ctl.len = -1, dat.len = 15  
 this is line 1  
 and line 2  
 flag = 0, ctl.len = -1, dat.len = 11  
 and line 2  
 ^D  
 flag = 0, ctl.len = -1, dat.len = 0  

No comments:

Post a Comment