17.4 IO and Testing of Dispatcher

Team-FLY

17.4 I/O and Testing of Dispatcher

This section develops dispatcher I/O functions and debugging layout. The dispatcher receives input data from standard input by calling getpacket and sends output data on standard output by calling putpacket , as shown in Figure 17.5. The data is always transferred in two parts . First, the dispatcher reads or writes a header of type taskpacket_t . Second, it uses the length member in the header to determine how many bytes of packet data to read or to write. Finally, it reads or writes the data portion of the packet. Assume that the packet data field contains no more than MAX_PACK_SIZE bytes so that the dispatcher can use a fixed-length buffer of MAX_PACK_SIZE bytes to hold the packet data during input and output.

Figure 17.5. Basic dispatcher I/O.

graphics/17fig05.gif

The getpacket function has the following prototype.

 int getpacket(int fd, int *compidp, int *taskidp,                packet_t *typep, int *lenp, unsigned char *buf); 

The getpacket function reads a taskpacket_t header from fd and then reads into buf the number of bytes specified by the length member. If successful, getpacket returns 0. If unsuccessful , getpacket returns 1 and sets errno . The getpacket function sets *compidp , *taskidp , *typep and *lenp from the compid , taskid , type and length members of the packet header, respectively. If getpacket receives an end-of-file while trying to read a packet, it returns 1 and sets errno . Since errno will not automatically be set, you must pick an appropriate value. There is no standard error number to represent end-of-file. One possibility is to use EINVAL .

The putpacket function has the following prototype.

 int putpacket(int fd, int compid, int taskid,                packet_t type, int len, unsigned char *buf); 

The putpacket function assembles a taskpacket_t header from compid , taskid , type and len . It then writes the packet header to fd followed by len bytes from buf . If successful, putpacket returns 0. If unsuccessful, putpacket returns 1 and sets errno .

Example 17.4

The following program uses getpacket and putpacket to copy packets from standard input to standard output.

 #include <unistd.h> #include "ntpvm.h" int getpacket(int, int *, int *, packet_t *, int *, unsigned char *); int putpacket(int, int, int, packet_t, int, unsigned char *); int main(void) {    unsigned char buf[MAX_PACK_SIZE];    int compid;    int taskid;    int tdatalen;    int tin, tout;    packet_t type;    tin = STDIN_FILENO;    tout = STDOUT_FILENO;    while (getpacket(tin, &compid, &taskid, &type, &tdatalen, buf) != -1) {       if (putpacket(tout, compid, taskid, type, tdatalen, buf) == -1)          break;    }    return 0; } 

The specification for Part I of the project is as follows .

  1. Write the getpacket and putpacket functions.

  2. Compile and run lint on the program to make sure that there are no syntax errors.

  3. Test the program, using one of the methods described below.

  4. Add debugging messages to the loop of the main program to show what values are being read and written. All debugging messages should go to standard error.

The hardest part of the NTPVM project is the testing of the dispatcher. The dispatcher communicates with standard input and standard output, using packets that have non-ASCII components . During debugging, the dispatcher should producemessages on standard error reporting its progress. A small amount of work is needed to isolate the dispatcher output and input from the informative messages by directing the three types of I/O to appear in ASCII format on different screens.

Program 17.2 shows the a2ts filter that reads ASCII characters from standard input, constructs a task packet, and writes it to standard output. The a2ts program writes all prompt messages to standard error, so it can be run either with interactive prompts or with standard input redirected from a file. For interactive use, a2ts prompts for the required information, sending the prompts to standard error.

Program 17.2 a2ts.c

The filter a2ts prompts for information and writes a task packet to standard output. Some error checking is omitted .

 #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "restart.h" #include "ntpvm.h" #define MAX_LINE_SIZE 100 #define TERMINATE_STRING "!!!!!\n" static char *typename[] = {"Start Task", "Data", "Broadcast", "Done",                          "Terminate", "Barrier"}; int main(void)  {    char buf[MAX_PACK_SIZE + MAX_LINE_SIZE];    char *bufptr;    int i;    int linelen;    taskpacket_t pack;    int tasktype;    int wsize;    wsize = sizeof(taskpacket_t);    fprintf(stderr, "Ready for first packet\n");    for(; ;) {                       /* loop with menu for interactive input */       fprintf(stderr, "Enter compid:");       if (scanf("%d", &pack.compid) == EOF)          break;       fprintf(stderr, "Enter taskid:");       scanf("%d", &pack.taskid);       fprintf(stderr, "Enter task type:\n");       for (i=0; i< NUMTYPES; i++)          fprintf(stderr, "   %d = %s\n", i, typename[i]);       scanf("%d", &tasktype);       pack.type = tasktype;       pack.length = 0;       bufptr = buf;       *bufptr = 0;       fprintf(stderr, "Enter first line of data (%.*s to end):\n",          strlen(TERMINATE_STRING) - 1, TERMINATE_STRING);       while ((linelen = readline(STDIN_FILENO, bufptr, MAX_LINE_SIZE)) != -1) {          if (linelen == 0)             break;          if (strcmp(TERMINATE_STRING, bufptr) == 0)             break;          bufptr = bufptr + linelen;          pack.length = pack.length + linelen;          if (pack.length >= MAX_PACK_SIZE) {             fprintf(stderr, "**** Maximum packet size exceeded\n");             return 1;          }          fprintf(stderr, "Received %d, total=%d, Enter line (%.*s to end):\n",              linelen, pack.length, strlen(TERMINATE_STRING) - 1,              TERMINATE_STRING);       }       fprintf(stderr, "Writing packet header: %d %d %d %d\n",           pack.compid, pack.taskid, (int)pack.type, pack.length);       if (write(STDOUT_FILENO, &pack, wsize) != wsize) {          fprintf(stderr, "Error writing packet\n");          return 1;       }       fprintf(stderr, "Writing %d bytes\n", pack.length);       if (write(STDOUT_FILENO, buf, pack.length) != pack.length) {          fprintf(stderr,"Error writing packet\n");          return 1;       }       fprintf(stderr, "Ready for next packet\n");    }    fprintf(stderr, "a2ts exiting normally\n");    return 0; } 

The ts2a filter of Program 17.3 reads a task packet from standard input and writes the contents of the packet to standard output in ASCII format. For this project, assume that the data portion of a task packet always contains ASCII information.

Exercise 17.5

The ts2a program assumes that header and data will each be read with a single call to read . How would you make this more robust?

Answer:

Use the readblock function from the restart library described in Appendix B.

Program 17.3 ts2a.c

The ts2a filter reads a packet from standard input and writes the header and data to standard output in ASCII format. Some error checking is omitted .

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "ntpvm.h" #define MAX_LINE_SIZE 100 static char *typename[] = {"Start Task", "Data", "Broadcast", "Done",                          "Terminate", "Barrier"}; int main(void) {    char buf[MAX_PACK_SIZE + MAX_LINE_SIZE];    int bytesread;    taskpacket_t pack;    int wsize;    wsize = sizeof(taskpacket_t);    fprintf(stderr, "***** Waiting for first packet\n");    for(; ;) {       bytesread =  read(STDIN_FILENO, &pack, wsize);       if (bytesread == 0) {          fprintf(stderr, "End-of-file received\n");          break;       }       if (bytesread != wsize) {          fprintf(stderr, "Error reading packet header\n");          return 1;       }       if ((pack.type < 0)  (pack.type >= NUMTYPES)) {          fprintf(stderr, "Got invalid packet\n");          return 1;       }       printf("Received packet header of type %s\n",typename[pack.type]);       printf("   compid = %d, taskid = %d, length = %d\n",              pack.compid, pack.taskid, pack.length);       fflush(stdout);       if (pack.length > MAX_PACK_SIZE) {          fprintf(stderr, "Task data is too long\n");          return 1;       }       if (read(STDIN_FILENO, buf, pack.length) != pack.length) {          fprintf(stderr, "Error reading packet data\n");          return 1;       }       write(STDOUT_FILENO, buf, pack.length);       fprintf(stderr, "***** Waiting for next packet\n");    }    return 0; } 
Example 17.6

The following command prompts for the fields of a packet. It then echoes the packet to standard output in ASCII format.

 a2ts  ts2a 

The a2ts program of Example 17.6 interactively prompts for packet information and writes the information as a binary packet to its standard output. The standard output of a2ts is piped into standard input of ts2a . The ts2a program reads binary packets from its standard input and outputs them in ASCII format to its standard output. Input entered to a2ts will be interleaved with output from ts2a , but this should not be a problem since ts2a will not produce any output until a2ts has received an entire packet.

Example 17.7

The following command shows a possible method of testing the dispatcher interactively. For now, use the testpacket program of Example 17.4 instead of the dispatcher.

 a2ts  dispatcher  ts2a 

Example 17.7 pipes standard output of a2ts into standard input of the dispatcher and standard output of the dispatcher into ts2a . The command line of Example 17.7 allows a user to enter ASCII data and to display the task packet output in ASCII. Unfortunately, real tests produce too much data from different sources, making it difficult to distinguish information from different programs. Input to a2ts and output from ts2a will be interleaved with error messages sent to standard error. The next two subsections propose two different methods for handling this problem.

17.4.1 Testing with multiple windows

The first strategy for improving the usability of a2ts and ts2a in testing the dispatcher is to use separate windows, as shown in Figure 17.6. The dispatcher, which runs in the dispatcher window , redirects its standard input to the named pipe inpipe and its standard output to the named pipe outpipe . The output from the dispatcher's standard error still appears in the dispatcher window. The a2ts program reads from standard input in the input window and writes to its standard output, which is redirected to the named pipe inpipe . Enter packets in ASCII format in this window. The ts2a program redirects its standard input to the named pipe outpipe . As the dispatcher runs, ts2a displays dispatcher output in the output window.

Figure 17.6 shows the setup for the three windows. Be sure to use the same working directory for all three windows. The procedure for running the dispatcher is as follows.

Figure 17.6. Use three windows to debug the NTPVM dispatcher.

graphics/17fig06.gif

  1. Create two named pipes in the dispatcher window by executing the following commands.

     mkfifo outpipe mkfifo inpipe 
  2. Start the dispatcher in the dispatcher window by executing the following command.

     dispatcher < inpipe > outpipe 

    This window displays only the messages that the dispatcher sends to standard error, since both standard input and standard output are redirected.

  3. In the output window, execute the following command.

     ts2a < outpipe 

    This window displays the packets coming from the standard output of the dispatcher.

  4. In the input window, execute the following command.

     a2ts > inpipe 

    This window displays the prompts for the user to enter packets. The a2ts program converts the entered information from ASCII to packet format and writes it to the standard input of the dispatcher.

Figure 17.7 shows the layout of the windows for the debugging. If you do not have a workstation that supports multiple windows, try to persuade your system administrator to install a program such as screen , which supports multiple screens on an ASCII terminal.

Figure 17.7. Logical process layout for debugging the dispatcher.

graphics/17fig07.gif

17.4.2 Testing with remote logging

The second strategy for testing the dispatcher uses the remote logging facility discussed in Section 10.3.4 and in Appendix D. Replace the ts2a program with the ts2log program of Program 17.4. The ts2log program uses the r_readblock function of the restart library described in Appendix B.

Example 17.8

The following command shows how to test the dispatcher by using remote logging.

 a2ts  dispatcher  ts2log 

The dispatcher should also log events. It could send the packets to standard output and have the ts2log program receive them through redirection. Alternatively, the dispatcher could log them directly.

Program 17.4 ts2log.c

A program that logs packets using the remote logging utilities. Some error checking is omitted.

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "ntpvm.h" #include "restart.h" #include "rlogging.h" #define MAX_LINE_SIZE 100 static char *typename[] = {"Start Task", "Data", "Broadcast", "Done",                          "Terminate", "Barrier"}; int main(void) {    char buf[MAX_PACK_SIZE + MAX_LINE_SIZE];    int bytesread;    LFILE *lf;    taskpacket_t pack;    int wsize;    wsize = sizeof(taskpacket_t);    lf = lopen(NULL,0);    if (lf == NULL)       fprintf(stderr, "Failed to open remote logger.\n");    for(; ;) {       bytesread =  readblock(STDIN_FILENO, &pack, wsize);       if (bytesread == 0) {          lprintf(lf, "End-of-file received\n");          break;       }       if (bytesread != wsize) {          lprintf(lf, "Error reading packet header\n");          return 1;       }       if ((pack.type < 0)  (pack.type >= NUMTYPES)) {          fprintf(stderr, "Got invalid packet\n");          return 1;       }       lprintf(lf, "%s %s\n   compid = %d\n   taskid = %d\n   length = %d\n",              "Received packet header of type",              typename[pack.type], pack.compid, pack.taskid, pack.length);       if (pack.length > MAX_PACK_SIZE) {          lprintf(lf, "Task data is too long\n");          return 1;       }       if (readblock(STDIN_FILENO, buf, pack.length) != pack.length) {          lprintf(lf, "Error reading packet data\n");          return 1;       }       lprintf(lf, buf, pack.length);    }    return 0; } 
Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net