# /* send_pro.c */ /* globals declared in this file: x_retries rst_buf functions declared in this file: mak_ldr send_pro rst_all chk_host qup_pro hw_s2b hw_rfc hw_cls hw_all hw_err hw_dwn pr_flush */ #include "files.h" #include "hstlnk.h" #include "kwrite.h" #include "globvar.h" #include "probuf.h" #include "hhi.h" #include "leader.h" #include "kread.h" #include "socket.h" #include "io_buf.h" /* SCCS PROGRAM IDENTIFICATION STRING */ char id_send_pro[] "~|^`send_pro.c\tV4.0E1\t7Jul78\n"; int x_retries 1; /* number of retries on protocol xmission */ /*name: mak_ldr function: constructs the common protions of the kernel, im, and host leaders for a "send" write to the kernel. algorithm: clears all the leader bytes to zero. fills in kernel opcode, host, and byte size. parameters: none. returns: nothing. globals: kw_buf= host calls: nothing. called by: send_pro rst_all fi_ssn history: initial coding 12/09/74 by G. R. Grossman. */ mak_ldr() { register char *byte_p; /* used in clearing all leader bytes */ for( byte_p= &kw_buf; /* clear leader bytes to zero */ byte_p != kw_buf.kw_data->l_data; *byte_p++ = 0 ); kw_buf.kw_op = kwi_send; /* kernel write opcode */ kw_buf.kw_data->l_host = host; /* imp leader host field */ kw_buf.kw_data->l_bysz = 8; /* host leader byte size field */ } /*name: send_pro function: if appropriate, accumulates up to 120 bytes of integral host_host protocol commands and sends them via the kernel "send" write instruction, setting appropriate flags and counters. algorithm: if there is a rfnm outstanding for the current host, return. set up leader via mak_ldr. copy the minimum of: (120) (number of bytes of available integral host-host command bytes) from probuf's in host's h_pb_q into kw_buf, incrementing h_pb_sent[host] for each probuf copied. set byte count in host leader. if host's h_pb_rtry = 0, set to x_retries. write kw_buf to the kernel. set host's rfnm bit in rfnm_bm. parameters: none. returns: nothing. globals: h_pb_sent= h_pb_q h_pb_rtry= rfnm_bm= pro2send= host kw_buf= x_retries calls: mak_ldr kw_write set_bit log_time printf called by: main chk_host history: initial coding 12/10/74 by G. R. Grossman. modified to check for something in proto queue and reset pro2send S. F. Holmgren 1/20/76 */ send_pro() { register char *byte_p, /* for copying into kw_buf */ *pb_bp; /* for copying out of probufs */ register int n; /* count for copying out of probufs */ int byte_cnt; /* counts down total bytes copied from 120 */ struct probuf *pb_p, /* for running thru host's probuf queue */ *stop; /* stopper for above */ /* check rfnm bit, return if set */ if ( bit_on(&rfnm_bm[0],host) ) /* rfnm outstanding for host? */ return; /* set up leader and initialize pointers */ mak_ldr(); byte_cnt = 120; /* maximun bytes of integral commands we may send */ byte_p = kw_buf.kw_data->l_data; /* point at data field in buffer */ if( h_pb_q[host] == 0 ) { log_time(); printf("Send_proto and no proto to send to host :%d\n",host); return; } pb_p = stop = h_pb_q[host]->pb_link; /* point at 1st probuf in hosts's q */ /* main loop: copy probufs into kw_buf */ do { if ( (byte_cnt =- pb_p->pb_count) >= 0) /* can we send this probuf? */ { pb_bp = pb_p->pb_text; /* point at text in probuf */ n = pb_p->pb_count; /* byte count for copy */ if( n <= 0 ) { log_err("send_pro: probuf with zero count \n"); return; } do /* copy loop */ { *byte_p++ = *pb_bp++; /* copy a byte */ } while (--n); /* do it (byte count) times */ h_pb_sent[host]++; /* inc probufs sent count */ } /* end of probuf ok branch */ else /* otherwise quit */ break; } while ( (pb_p = pb_p->pb_link) != stop ); /* loop til back at beginning of probuf q */ /* finish leader */ kw_buf.kw_data->l_bycnt = swab(byte_p - kw_buf.kw_data->l_data); /* host byte count is end of data - beginning of data */ /* set retry count if appropriate */ if ( h_pb_rtry[host] == 0 ) /* retries zero means they haven't been set */ h_pb_rtry[host] = x_retries; /* so set them */ /* write buffer to kernel */ kw_write(byte_p - &kw_buf.lo_byte); /* set rfnm bit */ set_bit(&rfnm_bm[0],host); /* reset pro2send */ pro2send = 0; } /*name: rst_all function: sends host-host resets to all possible (or only known) hosts on the network. algorithm: if there is protocol to send for the current host, sent it, cause we're going to change the host number if init_host zero if compile option RSTKNOWN is set open and scan the host name file, setting the known bit for each host we find else set the known bit for all hosts. do: find the next host; return if there are no more if there is protocol to send, send it so that it isn't forgotten when we change host number. while chk_host does not reset this new host; parameters: none. returns: nothing. globals: init_host= host= calls: chk_host fopen (lib) getl (lib) bit_on set_bit log_asc called by: ir_reset ir_rfnm ir_re_x history: initial coding 12/10/74 by G. R. Grossman. modifications for shutting off debugging and logging 1/9/75 by G. R. Grossman. modified to send prior protocol by Greg Noel on 8/31/77 modified to scan /usr/net/hnames file for known hosts (under compiletime switch) 25Jan78 by J.S.Goldberg at ill-nts modified to clean code and prevent the clobbering of the global host from causing the daemon to forget about queued up protocol. 1978/Jul/14 R. Balocca and B. Greiner notes: when the compiletime switch RSTKNOWN is defined, rst_all will scan the list of host names (/usr/net/hnames) and set a bit map if hosts that are known according to that scan. otherwise, the bitmap is completely filled with ones, to force reset attempts on all hosts. if the open of the file fails, all hosts are assumed to be known (e.g. the map is filled with ones). */ /* if RSTKNOWN is defined, only those hosts that are listed */ /* in /usr/net/hnames will get a reset sent to them. */ /* else, all hosts get one. */ #define RSTKNOWN on #define NUMHOSTS 256 /* move to probuf.h */ #ifdef RSTKNOWN rst_all() { register char *cp /* ptr for hnames parsing */ ; register int h /* for host number, and countr */ ; struct io_buf fbuf[1]; char line[100] /* generous line buffer */ ; static char h_kno_bm[NUMHOSTS / 8] /* map of known hosts */ ; /* N.B. could be external if other */ /* routines have need of the bitmap */ if (init_host == 0) { /* assumes initial value of 0 */ if (fopen("/usr/net/hnames", fbuf) < 0) { log_asc("rst_all: can't open /usr/net/hnames"); for (h = 0; h < NUMHOSTS / 8; h_kno_bm[h++] = 0377); } else { for (h = 0; h < NUMHOSTS / 8; h_kno_bm[h++] = 0); while ((h = getl(line, fbuf)) > 0) { line[h] = '\0'; cp = line; /* skip hostname, till get white space */ while (*cp != ' ' && *cp != '\t' && *cp) cp++; if (*cp == '\0') { /* paranoid of editable files */ log_asc("rst_all: bad line in hnames, viz:"); log_asc(line); continue; } if ((h = atoi(cp)) & ~0377) { /* host num too big */ log_asc("rst_all: bad host# in hnames, viz:"); log_asc(line); continue; } set_bit(h_kno_bm, h); } close(fbuf -> fid); } } /* endof if( init_host == 0 ) */ /* look for next host, while the host number is legal */ for (; ++init_host < NUMHOSTS;) { if (bit_on(h_kno_bm, init_host)) { if (pro2send) send_pro(); /* send any queued protocol */ host = (init_host & 0377); /* set host this host */ if (!chk_host()) /* host down? */ return; } } } #endif #ifndef RSTKNOWN rst_all() { /* look for next host, while the host number is legal */ for (; ++init_host < NUMHOSTS;) { if (pro2send) send_pro(); /* send any queued protocol */ host = (init_host & 0377); /* set host this host */ if (!chk_host()) /* host down? */ return; } } #endif /*name: chk_host function: checks if host is marked as up or if we are awaiting rfnm from host and, if neither is the case, sends a reset to the host. algorithm: save result of or'ing results of examining the host's up and rfnm bits; if = 0: send rst via qup_pro return result. parameters: none. returns: 0 if it sends a reset to the host. !=0 otherwise. globals: host h_up_bm rfnm_bm calls: bit_on qup_pro send_pro called by: kr_odrct rst_all kr_ouicp history: initial coding 1/17/75 by G. R. Grossman */ char rst_buf[]{hhi_rst}; /* buffer containing a host-host rst */ chk_host() { register int h; /* will hold host number */ register int res; /* holds result of test for return */ h = host; if ( (res = (bit_on(&h_up_bm[0],h) | bit_on(&rfnm_bm[0],h))) == 0 ) /* neither up nor awaiting rfnm? */ { qup_pro(&rst_buf[0],1); /* send rst */ send_pro(); } return(res); /* tell caller what we did */ } /*name: qup_pro function: queues up host-host protocol for sending. algorithm: an attempt is made to get a probuf from pb_fr_q via q_dlink; if this fails: allocate a new probuf via alloc. increment n_pb, which counts the existing probufs. set count in probuf to the size of the command. copy the command into the probuf. enter the probuf in the host's h_pb_q via q_enter. set pro2send to cause transmission at end of current major cycle. parameters: cmd_p pointer to char[] containing the command. n size of command in bytes. returns: nothing. globals: pb_fr_q= n_pb= pb_size h_pb_q= host calls: q_dlink q_enter alloc (sys) called by: hw_rfc hw_cls hw_all hw_err hr_rfc hr_eco hr_rst history: initial coding 12/29/74 by G. R. Grossman */ qup_pro(cmd_p,n) char *cmd_p; int n; { register struct probuf *pb_p; /* will point to the probuf we use */ register char *sbp, /* source pointer for copying cmd */ *dbp; /* dest " " " " */ if ( (pb_p = q_dlink(&pb_fr_q)) == 0 ) /* fail to get probuf? */ { pb_p = alloc(pb_size); /* get a new one */ ++n_pb; /* increment informational counter */ } pb_p->pb_count = n; /* set byte count in probuf */ dbp = &pb_p->pb_text[0]; /* destination for copy is text field of probuf */ for ( sbp = cmd_p; /* source is command */ n > 0; /* loop for n bytes */ n-- ) *dbp++ = *sbp++; /* copy a byte */ q_enter(&h_pb_q[host],pb_p); /* enter probuf in host's probuf q */ pro2send = 1; /* set send flag */ } /*name: hw_s2b function: copies socket numbers from socket struct to hw_buf for hw_rfc and hw_cls. algorithm: the source byte pointer is pointed at the local socket field in the socket struct. the destination byte pointer is pointed at the 2nd byte of hw_buf. two zero bytes are put in the destination to serve as the first two bytes of the local socket. the local and foreign sockets are copied from the socket struct. parameters: skt_p pointer to the socket struct containing the socket numbers to be copied. returns: nothing. globals: hw_buf= calls: nothing. called by: hw_rfc hw_cls history: initial coding 12/30/74 by G. R. Grossman */ hw_s2b(skt_p) struct socket *skt_p; { register char *sbp, /* source byte pointer for copying */ *dbp; /* dest " " " " */ register int n; /* counter for copying */ sbp = &skt_p->s_lskt[0]; /* source is local socket field */ dbp = &hw_buf[1]; /* dest is 2nd byte of command */ *dbp++ = 0; /* 1st byte of local socket */ *dbp++ = 0; /* "nd " " " " */ for (n = 6 ; n > 0 ; n-- ) /* now copy six bytes */ *dbp++ = *sbp++; /* one at a time */ } /*name: hw_rfc function: queues for sending the rfc appropriate to the socket struct specified. algorithm: if the socket represents a send connection: set opcode to str. set last byte of command to byte size of connection. otherwise (receive connection): set op code to rts. set last byte to link number. copy socket numbers via hw_s2b. queue for sending via qup_pro. parameters: skt_p points to the socket struct defining the rfc to be sent. returns: nothing. globals: hw_buf= hhi_rts hhi_str calls: hw_s2b qup_pro called by: lsint_q rfc_slsn so_uinit history: initial coding 12/30/74 by G. R. Grossman */ hw_rfc(skt_p) struct socket *skt_p; { register struct socket *s_p; /* points to socket struct */ s_p = skt_p; if ( s_p->s_lskt[1] & 1 ) /* send connection? */ { hw_buf[0] = hhi_str; /* op code is str */ hw_buf[9] = s_p->s_bysz; /* last byte is byte size */ } else /* receive connection */ { hw_buf[0] = hhi_rts; /* op code is rts */ hw_buf[9] = s_p->s_hstlnk.hl_link; /* last byte is link */ } hw_s2b(s_p); /* copy socket numbers */ qup_pro(&hw_buf[0],10); /* queue command for sending */ } /*name: hw_cls function: queues for sending the cls appropriate to the socket struct specified. algorithm: set op code to cls. copy socket numbers via hw_s2b. queue for sending via qup_pro. parameters: skt_p pointer to socket struct defining the cls. returns: nothing. globals: hw_buf= hhi_cls calls: hw_s2b qup_pro called by: cls_rfcw cls_q clo_rfop clo_c2cw su_ut3 tmo_q history: initial coding 12/30/74 by G. R. Grossman */ hw_cls(skt_p) struct socket *skt_p; { hw_buf[0] = hhi_cls; /* set op code */ hw_s2b(skt_p); /* copy socket numbers */ qup_pro(&hw_buf[0],9); /* queue for sending */ } /*name: hw_all function: queues for sending the all command determined by the socket struct specified and the speified number of messages and bits. algorithm: set op code to all. set link # from socket struct. copy message count, swapping bytes. set 1st 2 bytes of bits field to zero. copy 2nd word of bits field, swapping bytes. parameters: skt_p points to the socket struct descriibg the connection for which the all is being sent. msgs number of messages to be allocated. bits number of bits to be allocated. returns: nothing. globals: hw_buf= hhi_all calls: qup_pro called by: fi_sopn history: initial coding 12/30/74 by G. R. Grossman */ hw_all(skt_p,msgs,bits) struct socket *skt_p; int msgs,bits; { register char *bp; /* byte pointer for constructing command */ register char *BUG; /* to avoid compiler bug in optimization */ BUG = /* compiler incorrectly uses bp below, so we save copy */ bp = &hw_buf[0]; /* point at beginning of assembly buffer */ *bp++ = hhi_all; /* op code */ *bp++ = skt_p->s_hstlnk.hl_link; /* link number */ *bp++ = msgs.hi_byte; /* copy messages, swapping bytes */ *bp++ = msgs.lo_byte; *bp++ = 0; /* 1st 2 bytes of bits are zero */ *bp++ = 0; *bp++ = bits.hi_byte; /* copy bits, swapping bytes */ *bp++ = bits.lo_byte; qup_pro( BUG,8 ); /* compiler uses bp instead of recalculating qup_pro( &hw_buf[0],8 ); /* queue for sending */ } /*name: hw_err function: queues for sending an err command with the specified code and containing the command bytes specified; also logs the received message containing the erroneous command and the err command sent. algorithm: the op code is set to err. the error code is set as specified by the parameters. the specified command bytes are copied into the err command. if there were less than 10 command bytes, pad with zeroes. queue for sending via qup_pro. log the entire received message containing the ostensible error. log the err command just queued for sending. parameters: code the err code as specified by the host-host protocol. byte_p pointer to the command bytes to be included in the err. n_bytes number of command bytes to be included. returns: nothing. globals: hw_buf= hhi_err kr_buf kr_bytes kr_p calls: qup_pro log_bin called by: hr_rfc hr_cls history: initial coding 12/30/74 by G. R. Grossman */ hw_err(code,byte_p,n_bytes) int code,n_bytes; char *byte_p; { register char *sbp, /* source pointer for copying */ *dbp; /* dest " " " */ register int n; /* counter " " */ dbp = &hw_buf[0]; /* point at assembly buffer */ *dbp++ = hhi_err; /* set op code */ *dbp++ = code; /* set err code */ sbp = byte_p; /* pointer to command bytes to be copied */ for ( n = n_bytes; /* set counter */ n-- > 0 ; /* done when counter is zero */ *dbp++ = *sbp++ /* copy a byte each time */ ); while ( n_bytes++ < 10 ) /* pad with zero until have 10 bytes */ *dbp++ = 0; qup_pro(&hw_buf[0],12); /* queue for sending */ log_bin("hw_err: hh err detected;message", /* log bad message */ &kr_buf.krr_type, /* start at type field */ kr_p + kr_bytes - &kr_buf.krr_type ); /* size is current pointer + bytes left - start */ log_bin(".... err sent was",&hw_buf[0],12); /* log err sent */ } /*name: hw_dwn function: send an imp to host type 2 ( host going down ) message to the imp algorithm: clean up the buffer with mak_ldr stick in a type 2 message say we wont know when will be up this is an emergency restart parameters: none returns: nothing globals: kw_buf= calls: mak_ldr kwrite called by: daemon_dwn history: initial coding 6/23/76 by S. F. Holmgren */ hw_dwn() { register char *p; /* clean up hw_buf */ mak_ldr(); /* build a host going down message */ p = &kw_buf.kw_data[0]; *p++ = 2; /* host down op code */ *p++ = 0; /* no destination */ *p++ = 0377; /* we dont know when coming back */ *p++ = 0350; /* this is an emergency restart */ kw_write( p - &kw_buf.lo_byte ); } /*name: pr_flush function: flushes the protocol buffer queue for the current host. algorithm: while q_dlink yields a non-zero pointer on delinking a probuf from the host's h_pb_q, enter the probuf in the free probuf q, pb_fr_q. indicate that there is no protocol in flight parameters: none. returns: nothing. globals: host pro2send= h_pb_q[host]= pb_fr_q= h_pb_sent[host]= calls: q_dlink q_enter called by: h_dead history: initial coding 1/2/75 by G. R. Grossman modified to reset pro2send by S. F. Holmgren 1/20/76 modified to step on h_pb_sent by Greg Noel 8/31/77 */ pr_flush() { register struct probuf *p; /* holds pointer to probuf between its being delinked from host's h_pb_q and linked into pb_fr_q */ while ( p = q_dlink(&h_pb_q[host]) ) /* was q non-empty? */ q_enter(&pb_fr_q,p); /* put probuf in free q */ pro2send = 0; /* say no protocol to send */ h_pb_sent[host] = 0; }