/* * random * * ABSTRACT: * * This program is an example program using vots. * It runs in one of two modes, either as the initiator * or, as the responder. * * The initiator requests a connection to with the test * node TEST, to the tsap RANDOM. Once the connection * has been established, it expects 1,000,000 bytes of * data to be transmitted by the test responder in * random sized buffers (not greater than 2000 bytes). * When all of the data has been received, the test * initiator disconnects. * * The test responder acts as a passive TSAP and only ever * has one transport connection. The test initiator has * many transport connections and is multi-threaded. * * ENVIRONMENT: * VAX/VMS V5.0 * * MODIFICATION HISTORY: * * X-2 PEY0000 Paul Yager 17-Oct-1994 * Remove display of unused IOSB 3rd word. */ /* * INCLUDE FILES: */ #include #include #include #include #include #include #include #include #include "sys$library:osit" #include "sys$library:lnmdef" #include ctype /* * EQUATED SYMBOLS: */ #define TRUE 1 #define FALSE 0 /* ** AST Enable/Disable flags */ #define BLOCK_AST 0 #define ENABLE_AST 1 /* * Event Flag allocation */ #define SYNC_EFN 1 /* EFN for synchronous requests */ #define ASYNC_EFN 0 /* EFN for asynchronous requests */ #define BREAK_EFN 2 /* EFN for disconnection requests */ /* * MACROS: */ #define $error(test) (!((test) & STS$K_SUCCESS)) /* * OWN STORAGE: */ /* * the number of test streams active (initiator only) */ unsigned int random$gl_tests = 0; /* * information about the mailbox, there is only one mailbox used, * it may be shared by several transport connections */ #define RANDOM$K_MBX_NAMLEN 64 #define RANDOM$K_MBX_MSG_SIZE OSIT$K_MAX_NCB+5 char mbx_name_text [RANDOM$K_MBX_NAMLEN]; $DESCRIPTOR (mbx_name, mbx_name_text); struct mailblock { unsigned int channel; short int iosb [4]; struct { short int type; /* Message code */ short int unit; /* Device unit number */ unsigned char nct; /* Number of bytes in device name */ unsigned char nam [OSIT$K_MAX_NCB]; /* Address of device name string */ } msg; }; /* * Structure of test block, this contains all of the information relevent * to a particular transport connection or test */ #define RANDOM$K_TEST_COUNT 3 struct testblock { struct testblock *next; struct { unsigned wfdis :1; unsigned initiator :1; unsigned unused :14; } flags; short int channel; short int iosb [4]; short int unit; unsigned int tx_total; unsigned int tx; unsigned int rx_total; unsigned int rx; struct dsc$descriptor_s in_desc; struct dsc$descriptor_s out_desc; unsigned char input_list [OSIT$K_MAX_OUTPUT_ITEM_LIST]; unsigned char output_list [OSIT$K_MAX_OUTPUT_ITEM_LIST]; }; /* * structure of a data block, every read or write has one of * these */ #define RANDOM$K_MAX_DATA_SIZE 3000 #define RANDOM$K_TOTAL_DATA 15000 struct datablock { short int iosb [4]; struct testblock *test; unsigned char data [RANDOM$K_MAX_DATA_SIZE]; }; /* * Mailbox messge format. */ struct msg { short int type; /* Message code */ short int unit; /* Device unit number */ unsigned char nct; /* Number of bytes in device name */ unsigned char nam [64]; /* Address of device name string */ }; /* * global variables */ int zero = 0; int status; struct testblock *random$ga_tests; $DESCRIPTOR (osi, "OSIT$DEVICE"); /* * TABLE OF CONTENTS: */ unsigned int main (), initiator (), responder (), request(), create_mailbox(), accept(), process_mailbox_message(); void request_ast(), bldlst_connect(), post_mailbox_read(), display_list(), report_error(), display_item(), disconnect(), bldlst_ncb(), readdata(), writedata(), accept_ast(), write_ast (), read_ast (), disconnect_ast(), mailbox_ast(), deassign(); struct testblock *assign(); unsigned int *add_string_item(); /* * EXTERNAL REFERENCES: */ int SYS$QIO (), SYS$QIOW (), SYS$ASSIGN (), SYS$CREMBX(), SYS$SETSFM (), SYS$GETDVIW (), SYS$DASSGN (), SYS$HIBER (), SYS$SETAST (), SYS$WAKE (), SYS$TRNLNM (); int time(), free(), rand(), srand(); void *malloc(); int LIB$SIGNAL (), LIB$STOP (), LIB$ASN_WTH_MBX (), LIB$MOVC3 (), LIB$WAIT (), LIB$PARSE_NCB (); /* -------------------------------------------------------------------- */ unsigned int main () /* -------------------------------------------------------------------- */ /* * FUNCTIONAL DESCRIPTION: * * This routine tries to translate sys$net - if it can, it assumes * that it's an the test responder, otherwise it assumes that * it's the test initiator * * FORMAL PARAMETERS: * * None. * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * SS$_NORMAL or whatever is returned by initiator, * responder or TNRLOG. * * SIDE EFFECTS: * * None. */ { unsigned int status; static char ncbbuf [OSIT$K_MAX_NCB]; $DESCRIPTOR (ncb, ncbbuf); unsigned int attr; $DESCRIPTOR (lognam, "SYS$NET"); $DESCRIPTOR (tabnam, "LNM$PROCESS_TABLE"); struct { unsigned short int bufsiz; unsigned short int itmcod; char *bufadr; unsigned int retlen; unsigned int endoflist; } itmlst; /* * initialise */ status = SS$_NORMAL; random$ga_tests = 0; /* * announce who we are */ printf("RANDOM [1.0]\n"); /* * assign a mailbox */ if (!($error(status = create_mailbox()))) { /* * Obtain the NCB from a translation of SYS$NET */ attr = LNM$M_CASE_BLIND; itmlst.bufsiz = OSIT$K_MAX_NCB; itmlst.itmcod = LNM$_STRING; itmlst.bufadr = ncb.dsc$a_pointer; itmlst.retlen = (unsigned int)&(ncb.dsc$w_length); status = SYS$TRNLNM (&attr, &tabnam, &lognam, 0, &itmlst); /* * call either the test initiator or the test responder, depending * on whether there was a translation or not */ if $error (status) { if (status == SS$_NOLOGNAM) { printf("role - test initiator\n"); status = initiator (); } else printf("\nerror: translation of logical name sys$net failed\n"); } else { printf("role - test responder\n"); status = responder (&ncb); } /* end else passive tsap */ /* * if we get to this point, and everything went well, then just * sleep, this test program works asynchronously and is multi-threaded, * ast routines do all of the work */ if (!($error (status))) SYS$HIBER (); } /* end else mailbox created */ /* * return the status to the caller */ return status; } /* end routine main */ /* -------------------------------------------------------------------- */ unsigned int initiator () /* -------------------------------------------------------------------- */ /* * FUNCTIONAL DESCRIPTION: * * This routine is called when the program is acting in the role * of test initiator, it assigns a channel to VOTS, which allocates * a test block and makes an outbound connection request to the * test responder. That completes when the ast routine fires, the * tester then waits for data from the test responder. * * FORMAL PARAMETERS: * * None. * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { unsigned int i, status; struct testblock *test; for (i=0;iflags.initiator = TRUE; /* ** Block AST's while updating these structures. */ SYS$SETAST(BLOCK_AST); random$gl_tests++; test->next = random$ga_tests; random$ga_tests = test; status = request(test); SYS$SETAST(ENABLE_AST); } /* * return the status to the caller */ return (status); } /* end routine initiator */ /* -------------------------------------------------------------------- */ unsigned int responder (ncb) /* -------------------------------------------------------------------- */ struct dsc$descriptor *ncb; /* * FUNCTIONAL DESCRIPTION: * * This routine is called when the program is acting in the role * of test responder, it assigns a channel to VOTS, which allocates * a test block and accepts the inbound connection request from the * test initiator. That completes when the ast routine fires, the * tester then transmits data to the test initiator. * * FORMAL PARAMETERS: * * ncb - descriptor of ncb gained from logical translation * of SYS$NET * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { unsigned int status; struct testblock *test; long t; if ((test = assign()) == 0) status = SS$_INSFMEM; else /* * we have a channel to VOTS, initialise the random transmit * buffer size generator, build an input item list and accept * the inbound connection request */ { test->flags.initiator = FALSE; t = time(); srand (t); test->in_desc.dsc$b_dtype = DSC$K_DTYPE_T; test->in_desc.dsc$b_class = DSC$K_CLASS_S; test->in_desc.dsc$w_length = OSIT$K_MAX_OUTPUT_ITEM_LIST; test->in_desc.dsc$a_pointer = (char *)&(test->input_list); bldlst_ncb (&test->in_desc, ncb); random$ga_tests = test; status = accept(test, &test->in_desc); } /* * return the status to the caller */ return (status); } /* end routine responder */ /* -------------------------------------------------------------------- */ void request_ast(test) /* -------------------------------------------------------------------- */ struct testblock *test; /* * FUNCTIONAL DESCRIPTION: * * This ast routine checks the status of the outbound connection * request made and, if it worked, continues with the test. * * FORMAL PARAMETERS: * * test - pointer at a test block for this thread test code * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { /* * check to see if it worked */ if ($error (test->iosb [0])) report_error (test->iosb[0], test); else /* * display the output item list and perform a read on the * established channel */ { printf ("[%d] connection established\n", test->unit); printf ("\toutput item list for an outbound CR:\n"); display_list (test->output_list, test->iosb[1]); readdata (test); } } /* end routine request_ast */ /* -------------------------------------------------------------------- */ unsigned int request(test) /* -------------------------------------------------------------------- */ struct testblock *test; /* * FUNCTIONAL DESCRIPTION: * * This routine makes an outbound transport connection request * to tsap RANDOM on node TEST. * * FORMAL PARAMETERS: * * test - pointer at a test block for this thread test code * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { /* ** Initialize the input descriptor */ test->in_desc.dsc$b_dtype = DSC$K_DTYPE_T; test->in_desc.dsc$b_class = DSC$K_CLASS_S; test->in_desc.dsc$w_length = OSIT$K_MAX_OUTPUT_ITEM_LIST; test->in_desc.dsc$a_pointer = (char *)&(test->input_list); /* ** Initialize the output descriptor */ test->out_desc.dsc$b_dtype = DSC$K_DTYPE_T; test->out_desc.dsc$b_class = DSC$K_CLASS_S; test->out_desc.dsc$w_length = OSIT$K_MAX_OUTPUT_ITEM_LIST; test->out_desc.dsc$a_pointer = (char *)&(test->output_list); /* * build an input item list and make the connection request */ bldlst_connect(&test->in_desc); /* * now make the outbound connection request */ printf ("[%d] making an outbound connection request\n", test->unit); status = SYS$QIO (0, test->channel, IO$_ACCESS, &(test->iosb), &request_ast, test, &test->in_desc, 0, &test->out_desc, 0, 0, 0); /* * return the status to the caller */ return (status); } /* end routine request */ /* -------------------------------------------------------------------- */ struct testblock *assign() /* -------------------------------------------------------------------- */ /* * FUNCTIONAL DESCRIPTION: * * This routine allocates a test block and assigns a channel * to VOTS * * FORMAL PARAMETERS: * * None. * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { struct testblock *test; static unsigned int unit, l; /* * GETDVI item list structure and item list */ struct itmlst { short int itm_len; /* Length of buffer in bytes */ short int itm_code; /* Item to be extracted */ char *itm_buffer; /* Buffer to fill with information */ int *itm_retlen; /* Address of longword for length */ }; struct itmlst vots_unit_itm [2] = { {4, DVI$_UNIT, (char *)&unit, (int *)&l}, {0,0,0,0} }; /* * allocate a testblock */ if ((test = malloc(sizeof(struct testblock))) == 0) printf("error: failed to allocate a testblock\n"); else { printf ("[-] assigning a VOTS channel\n"); if ($error (status = SYS$ASSIGN (&osi, &(test->channel), 0, &mbx_name))) { report_error (status, test); free (test); } else { /* * find out the unit number of the device that we've just allocated * we're quoted this in any mailbox messages, so use it to figure * out which TC the mailbox message was for */ status = SYS$GETDVIW (SYNC_EFN, test->channel, 0, &vots_unit_itm, 0, 0, 0, 0); if ($error (status)) report_error (status, test); else { /* * set up the unit number in the testblock */ test->unit = unit; /* ** Initialize the next pointer. */ test->next = NULL; } } } /* end of testblock allocated */ return (test); } /* end routine assign */ /* -------------------------------------------------------------------- */ unsigned int create_mailbox() /* -------------------------------------------------------------------- */ /* * FUNCTIONAL DESCRIPTION: * * This routine creates a mailbox and posts a read on it * * FORMAL PARAMETERS: * * None. * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { struct mailblock *mail; /* * GETDVI item list structure and item list */ struct itmlst { short int itm_len; /* Length of buffer in bytes */ short int itm_code; /* Item to be extracted */ char *itm_buffer; /* Buffer to fill with information */ int *itm_retlen; /* Address of longword for length */ }; struct itmlst mbx_nam_itm [2] = { {RANDOM$K_MBX_NAMLEN, DVI$_DEVNAM, (char *)&mbx_name_text, (int *)&mbx_name.dsc$w_length}, {0,0,0,0} }; /* * allocate a mailbox message block */ if ((mail = malloc(sizeof(struct mailblock))) == 0) printf("error: failed to allocate a mailblock\n"); else { printf ("creating a mailbox\n"); if ($error (status = SYS$CREMBX (0, &(mail->channel), RANDOM$K_MBX_MSG_SIZE, 0, 0, 0, 0))) { printf("error: failed to create a mailbox\n"); free (mail); } else { printf ("mailbox channel (%d) assigned\n", mail->channel); /* * find out the device name of the mailbox that we've just created, * we use this when we allocate channels to VOTS which associate * themselves with that mailbox. */ status = SYS$GETDVIW (SYNC_EFN, mail->channel, 0, &mbx_nam_itm, 0, 0, 0, 0); if ($error (status)) { printf ("error, failed to get mailbox's name\n"); LIB$STOP (status); } else { /* * post a read on the associated mailbox */ post_mailbox_read (mail); } } } /* end of testblock allocated */ return (status); } /* end routine create_mailbox */ /* -------------------------------------------------------------------- */ void deassign(test) /* -------------------------------------------------------------------- */ struct testblock *test; /* * FUNCTIONAL DESCRIPTION: * * This routine deassigns a channel, it's only called by the * responder, so we don't need to worry about tidying up the * linked list of test blocks. * * FORMAL PARAMETERS: * * None. * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { printf ("[%d] deassigning the channel to VOTS\n", test->unit); if ($error (status = SYS$DASSGN (test->channel))) report_error (status, test); free(test); } /* end routine deassign */ /* -------------------------------------------------------------------- */ void disconnect_ast(test) /* -------------------------------------------------------------------- */ struct testblock *test; /* * FUNCTIONAL DESCRIPTION: * * This ast routine checks the status of the disconnection made * and, if it worked, and we're the initiator, it starts up * another test session * * FORMAL PARAMETERS: * * test - pointer at a test block for this thread test code * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { unsigned int initiator_flag; /* * check to see if it worked */ if ($error (test->iosb[0]) && (test->iosb[0] != SS$_FILNOTACC)) report_error (test->iosb[0], test); else /* * deassign the channel */ { printf ("[%d] disconnection succeeded\n", test->unit); /* ** Save the value of flags.initiator since the test block ** will be deallocated as part of the deassign call. */ initiator_flag = test->flags.initiator; /* ** Remove this testblock from the linked list. First need ** to find the address of the linked block before this. */ { struct testblock *prevtest; prevtest = random$ga_tests; while ((prevtest->next != test) && (prevtest->next != NULL)) { prevtest = prevtest->next; } if ((prevtest != NULL) && (prevtest->next == test)) { /* ** Unlink test from this list. */ prevtest->next = test->next; } else if (test == random$ga_tests) { /* ** test was the first element in the list. */ random$ga_tests = test->next; } } deassign (test); if (initiator_flag) { random$gl_tests--; if (random$gl_tests == 0) SYS$WAKE(0,0); } else SYS$WAKE(0,0); } } /* end routine disconnect_ast */ /* -------------------------------------------------------------------- */ void disconnect(test) /* -------------------------------------------------------------------- */ struct testblock *test; /* * FUNCTIONAL DESCRIPTION: * * This routine disconnects the current TC. * * FORMAL PARAMETERS: * * test - pointer at a testblock * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { /* * disconnect the tc */ printf ("[%d] performing a disconnection\n", test->unit); status = SYS$QIO (0, test->channel, IO$_DEACCESS, &(test->iosb), &disconnect_ast, test, 0, 0, 0, 0, 0, 0); if ($error (status)) report_error (status, test); } /* end routine disconnect */ /* -------------------------------------------------------------------- */ void write_ast (data) /* -------------------------------------------------------------------- */ struct datablock *data; /* * FUNCTIONAL DESCRIPTION: * * This function is called when a write request on a connection * has been completed. It frees off the buffer when it's finished * with it. * * FORMAL PARAMETERS: * * data - pointer at a data buffer * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. * */ { struct testblock *test; test = data->test; if ($error (data->iosb [0])) report_error (data->iosb[0], test); else { test->tx_total = test->tx_total + data->iosb [1]; test->tx++; free (data); /* * if we've sent all of the data, then just set the waiting for * disconnection flag and wait for a mailbox message telling * us that the connection has gone away */ if (test->tx_total >= RANDOM$K_TOTAL_DATA) { printf ("[%d] %d blocks of average size %d transmitted\n", test->unit, test->tx, test->tx_total/test->tx); test->flags.wfdis = TRUE; } else writedata (test); } } /* end routine write_ast */ /* -------------------------------------------------------------------- */ void writedata(test) /* -------------------------------------------------------------------- */ struct testblock *test; /* * FUNCTIONAL DESCRIPTION: * * This routine sends a random sized block of data on the TC * * FORMAL PARAMETERS: * * test - pointer at a testblock * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { struct datablock *data; unsigned int size; if ((data = malloc(sizeof(struct datablock))) == 0) { printf("[%d] error: failed to allocate a write block\n", test->unit); report_error (SS$_INSFMEM, test); } else { data->test = test; size = rand () % RANDOM$K_MAX_DATA_SIZE; if ($error (status = SYS$QIO (ASYNC_EFN, test->channel, IO$_WRITEVBLK, &(data->iosb), &write_ast, data, &(data->data), size, 0, 0, 0, 0))) report_error (status, test); } /* end else allocated a data block */ } /* end routine writedata */ /* -------------------------------------------------------------------- */ void read_ast (data) /* -------------------------------------------------------------------- */ struct datablock *data; /* * FUNCTIONAL DESCRIPTION: * * This function is called when a read request on a connection * has been completed. If it completed successfully, it increments * the read data count, and if all of the data has been received, * it disconnects the connection. * * FORMAL PARAMETERS: * * data - pointer at a datablock containing the iosb and * the data read * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. * */ { struct testblock *test; test = data->test; if ($error (data->iosb [0])) report_error (data->iosb[0], test); else { test->rx_total = test->rx_total + data->iosb [1]; test->rx++; free (data); /* * if that was the last of the data to be received, then print * the results and disconnect */ if (test->rx_total >= RANDOM$K_TOTAL_DATA) { printf ("[%d] %d blocks of average size %d received\n", test->unit, test->rx, test->rx_total/test->rx); disconnect (test); } else readdata (test); } } /* end routine read_ast */ /* -------------------------------------------------------------------- */ void readdata(test) /* -------------------------------------------------------------------- */ struct testblock *test; /* * FUNCTIONAL DESCRIPTION: * * This routine reads a block of data from the TC. * * FORMAL PARAMETERS: * * test - pointer at the test description block to use * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { struct datablock *data; if ((data = malloc(sizeof(struct datablock))) == 0) { printf("[%d] error: failed to allocate a read block\n", test->unit); report_error (SS$_INSFMEM, test); } else { data->test = test; if ($error (status = SYS$QIO (ASYNC_EFN, test->channel, IO$_READVBLK, &(data->iosb), &read_ast, data, &(data->data), RANDOM$K_MAX_DATA_SIZE, 0, 0, 0, 0))) report_error (status, test); } /* end else allocated a data block */ } /* end routine readdata */ /* -------------------------------------------------------------------- */ void accept_ast(test) /* -------------------------------------------------------------------- */ struct testblock *test; /* * FUNCTIONAL DESCRIPTION: * * This ast routine checks the status of the connection * acceptence made and, if it worked, continues with the test. * * FORMAL PARAMETERS: * * test - pointer at a test block for this thread test code * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { /* * check to see if it worked */ if ($error (test->iosb [0])) report_error (test->iosb[0], test); else /* * display the output item list produced and perform a * write on the established channel */ { printf("[%d] inbound connection accepted\n", test->unit); printf ("\toutput item list for an inbound CR:\n"); display_list (test->output_list, test->iosb[1]); writedata (test); } } /* end routine accept_ast */ /* -------------------------------------------------------------------- */ unsigned int accept(test, in_desc) /* -------------------------------------------------------------------- */ struct testblock *test; struct dsc$descriptor *in_desc; /* * FUNCTIONAL DESCRIPTION: * * This routine accepts an inbound connection * * FORMAL PARAMETERS: * * test - pointer a testblock * in_desc - address of a descriptor of an item list describing the * inbound connection request * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { /* * accept the connection request */ test->out_desc.dsc$b_dtype = DSC$K_DTYPE_T; test->out_desc.dsc$b_class = DSC$K_CLASS_S; test->out_desc.dsc$w_length = OSIT$K_MAX_OUTPUT_ITEM_LIST; test->out_desc.dsc$a_pointer = (char *)&(test->output_list); printf ("[%d] accepting the inbound connection request\n", test->unit); status = SYS$QIO (0, test->channel, IO$_ACCESS, &(test->iosb), &accept_ast, test, in_desc, 0, &test->out_desc, 0, 0, 0); /* * return the status to the caller */ return (status); } /* end routine accept */ /* -------------------------------------------------------------------- */ unsigned int *add_string_item(list, code, string, size) /* -------------------------------------------------------------------- */ unsigned char *list,*string; unsigned int code, size; /* * FUNCTIONAL DESCRIPTION: * * This routine builds an input item list * * FORMAL PARAMETERS: * * list - a pointer to the list that we are building * code - the item code of the item that we're adding * string - a pointer to the string that we are adding * size - the size of "string" in bytes * * IMPLICIT INPUTS: * * in_desc and input_list * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * A pointer to the first byte following the item just added * * SIDE EFFECTS: * * None. */ { struct _osit_item *item; /* pointer at an individual item */ item = (struct _osit_item *)list; item -> osit$w_item_type = code; item -> osit$w_item_length = OSIT$K_ITEM_HEADER_SIZE + size; LIB$MOVC3 (&size,string,&(item->osit$r_item_value.osit$t_item_string[0])); return (unsigned int *)((unsigned int)list + size + OSIT$K_ITEM_HEADER_SIZE); } /* end routine add_string_item */ /* -------------------------------------------------------------------- */ void bldlst_ncb(in_desc, ncb) /* -------------------------------------------------------------------- */ struct dsc$descriptor *in_desc, *ncb; /* * FUNCTIONAL DESCRIPTION: * * This routine builds an input item list containing an NCB * * FORMAL PARAMETERS: * * None. * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { unsigned short int ncblist_length; unsigned int status; struct _osit_item *item; /* pointer at an individual item */ /* add in the ncb */ status = LIB$PARSE_NCB ( ncb, in_desc, &ncblist_length ); if $error (status) LIB$STOP (status); /* add in the protocol version - mandatory parameter */ item = (struct _osit_item *)((unsigned int)in_desc->dsc$a_pointer + ncblist_length); item -> osit$w_item_length = OSIT$K_ITEM_HEADER_SIZE + 4; item -> osit$w_item_type = OSIT$K_ITEM_PROTOCOL_TYPE; item -> osit$r_item_value.osit$l_item_long = OSIT$K_OSI_PROTOCOL; /* set up the length in the input item list */ in_desc->dsc$w_length = ncblist_length + OSIT$K_ITEM_HEADER_SIZE + 4; /* display the list */ printf ("\tinput item list to accept an inbound CR:\n"); display_list (in_desc->dsc$a_pointer, in_desc->dsc$w_length); } /* end routine bldlst_ncb */ /* -------------------------------------------------------------------- */ void bldlst_connect(in_desc) /* -------------------------------------------------------------------- */ struct dsc$descriptor *in_desc; /* * FUNCTIONAL DESCRIPTION: * * This routine builds an input item list for a connection request * * FORMAL PARAMETERS: * * None. * * IMPLICIT INPUTS: * * in_desc * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { int i; /* general */ int size; /* size of built list in bytes */ struct _osit_item *item; /* pointer at an individual item */ size = 0; item = (struct _osit_item *)in_desc->dsc$a_pointer; /* add in the protocol version - mandatory parameter */ item -> osit$w_item_length = OSIT$K_ITEM_HEADER_SIZE + 4; item -> osit$w_item_type = OSIT$K_ITEM_PROTOCOL_TYPE; item -> osit$r_item_value.osit$l_item_long = OSIT$K_OSI_PROTOCOL; item = (struct _osit_item *)((unsigned int)item + item->osit$w_item_length); /* add in the address of the request */ item = (struct _osit_item *)add_string_item ( item, OSIT$K_ITEM_ADDRESS, "TEST", 4 ); /* add in the called tsap */ item = (struct _osit_item *)add_string_item ( item, OSIT$K_ITEM_CALLED_TSAP, "RANDOM", 6 ); /* add in the calling tsap */ item = (struct _osit_item *)add_string_item ( item, OSIT$K_ITEM_CALLING_TSAP, "RANDOM-INITIATOR", 16 ); /* add in the prefered classes */ item -> osit$w_item_length = OSIT$K_ITEM_HEADER_SIZE + 4; item -> osit$w_item_type = OSIT$K_ITEM_CLASS; item -> osit$r_item_value.osit$l_item_long = OSIT$M_CLASS_0 + OSIT$M_CLASS_2 + OSIT$M_CLASS_4; item = (struct _osit_item *)((unsigned int)item + OSIT$K_ITEM_HEADER_SIZE + 4); /* add in the prefered options */ item -> osit$w_item_length = OSIT$K_ITEM_HEADER_SIZE + 4; item -> osit$w_item_type = OSIT$K_ITEM_OPTIONS; item -> osit$r_item_value.osit$l_item_long = OSIT$M_EXTENDED + OSIT$M_CHECKSUM + OSIT$M_EXPEDITED; item = (struct _osit_item *)((unsigned int)item + OSIT$K_ITEM_HEADER_SIZE + 4); /* set up the length in the input item list */ in_desc->dsc$w_length = (int)item - (int)in_desc->dsc$a_pointer; } /* end routine bldlst_connect */ /* -------------------------------------------------------------------- */ void display_list(list, size) /* -------------------------------------------------------------------- */ char *list; int size; /* * FUNCTIONAL DESCRIPTION: * * This routine dumps the contents of an output item list to * the console * * FORMAL PARAMETERS: * * list - a pointer to the list * size - the length of the list in bytes * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { struct _osit_item *item; /* pointer at an individual item */ unsigned char *ptr; /* byte pointer */ int offset; item = (struct _osit_item *)list; if (item -> osit$w_item_length == 0) printf ("\titem list is empty\n"); else { offset = 0; while (offset < size) { ptr = (unsigned char *)((unsigned int)list + offset); item = (struct _osit_item *)ptr; display_item (item); offset = offset + item -> osit$w_item_length; } /* end do while not end of list */ } /* item list has contents */ } /* end routine display_list */ /* -------------------------------------------------------------------- */ void display_item(item) /* -------------------------------------------------------------------- */ struct _osit_item *item; /* * FUNCTIONAL DESCRIPTION: * * This routine dumps the contents of an item in an item list * * FORMAL PARAMETERS: * * item - a pointer to the item * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { short int i, class, service; struct _osit_optmsk *mask; switch (item -> osit$w_item_type) { case OSIT$K_ITEM_PROTOCOL_TYPE : printf ("\tprotocol type - %d\n", item -> osit$r_item_value.osit$l_item_long); break; case OSIT$K_ITEM_TC_ID : printf ("\ttc id - %d\n", item -> osit$r_item_value.osit$l_item_long); break; case OSIT$K_ITEM_PROTOCOL_VERSION : printf ("\tprotocol version - %d\n", item -> osit$r_item_value.osit$l_item_long); break; case OSIT$K_ITEM_USER_DATA : printf ("\tuser data - %.*s\n", item -> osit$r_item_value.osit$r_item_wcs.osit$w_wcs_length, &(item -> osit$r_item_value.osit$r_item_wcs.osit$t_wcs_text)); break; case OSIT$K_ITEM_CLASS : class = item -> osit$r_item_value.osit$l_item_long; printf("\tclass - "); for (i=0;i<=4;i++) if (class & (1<osit$r_item_value.osit$l_item_long; printf("\tnetwork service - %d\n", item->osit$r_item_value.osit$l_item_long); break; case OSIT$K_ITEM_OPTIONS : printf ("\toptions - "); mask = (struct _osit_optmsk *)&(item->osit$r_item_value.osit$l_item_long); if (mask -> osit$v_extended) printf("extd format, "); else printf("normal format, "); printf("checksums "); if (mask -> osit$v_checksum) printf("on, "); else printf("off, "); if (!(mask -> osit$v_expedited)) printf("no "); printf("expd data, "); printf("flow cntrl "); if (mask -> osit$v_flow_control) printf("on.\n"); else printf("off.\n"); break; case OSIT$K_ITEM_ADDRESS : printf ("\taddress - %.*s\n", (item -> osit$w_item_length) - OSIT$K_ITEM_HEADER_SIZE, &(item -> osit$r_item_value)); break; case OSIT$K_ITEM_CALLED_TSAP : printf("\tcalled tsap - %.*s\n", (item -> osit$w_item_length) - OSIT$K_ITEM_HEADER_SIZE, &(item -> osit$r_item_value)); break; case OSIT$K_ITEM_CALLING_TSAP : printf("\tcalling tsap - %.*s\n", (item -> osit$w_item_length) - OSIT$K_ITEM_HEADER_SIZE, &(item -> osit$r_item_value)); break; case OSIT$K_ITEM_NETWORKPRIORITY_IN : case OSIT$K_ITEM_NETWORKPRIORITY_OUT : break; default : printf ("\tunrecognised type (%d)\n", item -> osit$w_item_type); } } /* end routine display_item */ /* -------------------------------------------------------------------- */ void report_error(code,test) /* -------------------------------------------------------------------- */ short int code; struct testblock *test; /* * FUNCTIONAL DESCRIPTION: * * This routine is called wheneverf an error is given from a QIO * call * * FORMAL PARAMETERS: * * code - error code causing consternation * test - testblock owning the error * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { short int i; printf ("[%d, %d] error: QIO failed:\n", test->unit); printf ("status\t%x\n", code); LIB$STOP (code); } /* end routine report_error */ /* -------------------------------------------------------------------- */ void post_mailbox_read(mail) /* -------------------------------------------------------------------- */ struct mailblock *mail; /* * FUNCTIONAL DESCRIPTION: * * This routine posts a read on the mailbox associated with the * mail block supplied. * * FORMAL PARAMETERS: * * mail - pointer to a mailblock * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { /* * post another read on the mailbox */ if ($error (status = SYS$QIO (ASYNC_EFN, mail->channel, IO$_READVBLK, &(mail->iosb), &mailbox_ast, mail, &(mail->msg.type), RANDOM$K_MBX_MSG_SIZE, 0, 0, 0, 0))) { printf("error, failed to post read on mailbox\n"); LIB$STOP (status); } } /* end routine post_mailbox_read */ /* -------------------------------------------------------------------- */ unsigned int process_mailbox_message(mail) /* -------------------------------------------------------------------- */ struct mailblock *mail; /* * FUNCTIONAL DESCRIPTION: * * This routine reports the message type and takes the appropriate * actions. * * FORMAL PARAMETERS: * * mail - pointer to a mailblock * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { unsigned char *info_size; struct testblock *test; info_size = &mail->msg.nam [mail->msg.nct]; /* * find the test block for the VOTS channel associated with * this mailbox message */ test = random$ga_tests; while (test->unit != mail->msg.unit) test = test->next; /* * print out the type of the message */ printf ("[%d] mailbox ", mail->msg.unit); switch (mail->msg.type) { case MSG$_DISCON: printf ("hangup message\n"); break; case MSG$_CONFIRM : printf ("confirmation message\n"); break; case MSG$_CONNECT : printf ("connect message\n"); break; case MSG$_ABORT : printf ("abort message\n"); break; case MSG$_PROTOCOL : printf ("protocol message\n"); break; case MSG$_PATHLOST : printf ("pathlost message\n"); break; case MSG$_TIMEOUT : printf ("timeout message\n"); break; case MSG$_THIRDPARTY : printf ("third party message\n"); break; case MSG$_REJECT : printf ("reject message\n"); break; case MSG$_EXIT : printf ("exit message\n"); break; case MSG$_INTMSG : printf ("expedited data message\n"); break; case MSG$_NETSHUT : printf ("network shutdown message\n"); break; default : printf ("unknown (id = %d)",mail->msg.type); } /* * our actions depend on our role, state and the message */ switch (mail->msg.type) { case MSG$_REJECT : case MSG$_CONFIRM : break; case MSG$_ABORT : case MSG$_DISCON : if (test->flags.wfdis) { disconnect (test); test->flags.wfdis = FALSE; break; } case MSG$_CONNECT : case MSG$_PROTOCOL : case MSG$_PATHLOST : case MSG$_TIMEOUT : case MSG$_THIRDPARTY : case MSG$_EXIT : case MSG$_INTMSG : case MSG$_NETSHUT : default : printf("error: unexpected message\n"); disconnect (test); return (FALSE); } return (TRUE); } /* end routine process_mailbox_message */ /* -------------------------------------------------------------------- */ void mailbox_ast(mail) /* -------------------------------------------------------------------- */ struct mailblock *mail; /* * FUNCTIONAL DESCRIPTION: * * This routine waits on the mailbox assigned to VOTS for a message * and then tells the user what the message was and posts another * read on the mailbox. * * FORMAL PARAMETERS: * * mail - pointer to a mailblock * * IMPLICIT INPUTS: * * None. * * IMPLICIT OUTPUTS: * * None. * * ROUTINE VALUE: * * None. * * SIDE EFFECTS: * * None. */ { /* ** If there are not any active tests, then don't bother processing the ** mailbox message. */ printf("[%d] mailbox read completed\n", mail->msg.unit); if (random$ga_tests != NULL) { /* * if we need to perform any more reads on the mailbox, then drain it * of any other reads in the pipeline */ if (process_mailbox_message (mail)) { do { if ($error (status = SYS$QIOW (ASYNC_EFN,mail->channel, IO$_READVBLK | IO$M_NOW, &(mail->iosb), 0, mail, &(mail->msg.type), RANDOM$K_MBX_MSG_SIZE, 0, 0, 0, 0))) { printf("error, failed to post mailbox read\n"); LIB$STOP (status); } else { if (mail->iosb [0] != SS$_ENDOFFILE) process_mailbox_message (mail); } } while (mail->iosb [0] != SS$_ENDOFFILE); post_mailbox_read (mail); } } } /* end routine mailbox_ast */