/* V24 (RS232) Serial line Transport Service for RPC ts_v24.c ** ================================================= ** ** This module provides a transport service for the RPC system developed ** by CERN/DD Online group in 1986-90. ** ** This particular module uses RS232 lines (V24) with its own built-in ** protocol. ** See the RPC User Manual for details of address syntax. ** ** See also the RPC internals manual, which describes how modules ** similar to this one work, also giving flow charts and message formats, ** and describing the character encoding and protocol. ** ** Authors: ** Roberto Bagnara (CERN, PISA) wrote this in Pascal originally. ** Tim Berners-Lee (CERN/CN) translated into C and maintained it. ** ** History: ** 5 May 90 Code extracted from general ts.c module. (TBL) ** ** Compilation switches: ** */ /* Module parameters: ** ----------------- ** ** These may be undefined and redefined by syspec.h */ # define WILDCARD '*' /* Wildcard used in addressing */ # define INITIAL_RETRY_TIME 500 # define BACKOFF_LIMIT 3000 #include #include "syspec.h" #define TS /* Require visibility of TS interface */ #define TS_INTERNALS /* Require visibility of TS internals */ #include "rpcrts.h" /* Define all general RPC data structures */ #include "rpc_code.h" /* Coding convention macros */ /* ** Definitions for pointers */ #define NIL_MESSAGE (rpc_message *)0 extern char *malloc(); extern void free(); extern char *strncpy(); /* External Routines ** ----------------- */ extern void rpc_new(); /* Allocate rpc_message */ extern void rpc_dispose(); /* Deallocate rpc_message */ extern void rpc_get_string(); /* Get Pascal or C string parameter */ #ifdef AST /* Always used by CATS !!!!!! */ extern void sys_setast(); /* En/Disable ASTs */ rpc_status ts_when_receive(); /* forward (ASTs only) */ #endif /* Genuine module-global variables ** ---------------- */ PRIVATE v24_buffer send_buffer; PRIVATE v24_chan_info_array v24_chan_info; PRIVATE char * buffer_pointer; /* Global variables converted from Pascal intermediate level ** variables: */ rpc_message *G94_mes; /* All for V24 */ socket_type G88_socket; socket_type G92_socket; /* V24 routines ** ------------ */ /* Update Cyclic Redundancy Check or Checksum compute_block_check() ** ------------------------------------------ ** ** On entry, ** rpc_byte is the byte to be included in the check ** block-check_type indicates whether a checksum or CRC is used ** computed_block_check points to the running total ** ** On exit, ** *computed_block-check has been updated. */ #ifdef __STDC__ PRIVATE void compute_block_check( rpc_byte octet, block_check_type block_check_used, unsigned int *computed_block_check) #else PRIVATE void compute_block_check( octet, block_check_used, computed_block_check) rpc_byte octet; block_check_type block_check_used; unsigned int *computed_block_check; #endif { unsigned int q, c, crc; if (block_check_used == checksum) { (*computed_block_check) = ((*computed_block_check) + octet) & 0xFF; #ifdef BLOCK_CHECK_TRACE if (rpc_trace) UTRACE(tfp, " block_check = %lh %02x\n", (*computed_block_check), octet); #endif } else { c = octet; crc = *computed_block_check; q = (crc ^ c ) & 0xF; crc = (crc >> 4) ^ (q * 4225); q = (crc ^ (c >> 4)) & 0xF; crc = (crc >> 4) ^ ( q * 4225); *computed_block_check = crc; } return; } /* Open V24 physical channel ** ------------------------- ** */ /* mychannel is modified to path number (-JRR?) */ #ifdef __STDC__ PRIVATE rpc_status rpc_v24_open(channel mychannel) #else PRIVATE rpc_status rpc_v24_open(mychannel) channel mychannel; #endif { register v24_chan_info_type *cha = &v24_chan_info[mychannel]; if (!((cha->v24_usage)++)) { #ifdef OSK int istatus = v24_open(mychannel, cha->speed, cha->traffic, rpc_trace); if (istatus < 0) /* @@@ bug in OSK code */ return RPC_S_TS_INTERNAL_ERROR; else return RPC_S_NORMAL; #else return v24_open(mychannel, cha->speed, cha->traffic, rpc_trace); #endif } else return RPC_S_NORMAL; } /*__________________________________________________________________________ * * Procedure: Close V24 physical channel * */ void rpc_v24_close(mychannel, pstatus) channel mychannel; rpc_status *pstatus; { register v24_chan_info_type *chan = &v24_chan_info[mychannel]; if (--(chan->v24_usage) == 0) { *pstatus = v24_close(mychannel, rpc_trace); } else *pstatus = RPC_S_NORMAL; } /*__________________________________________________________________________ * * Function: Get byte from V24 channel * */ rpc_status get_byte(octet, chan, timeout) rpc_byte * octet; channel chan; int timeout; { int len, istat; (*octet) = 0; len =1; istat = v24_get(octet,len,timeout,chan,rpc_trace); if (istat <= 0) return RPC_S_TIMEOUT; else return RPC_S_NORMAL; } /*__________________________________________________________________________ * * Function: Send raw byte down a V24 channel * */ BOOLEAN send_byte(octet, chan) rpc_byte *octet; channel chan; { return (v24_send(octet, /* Buffer address */ 1, /* Buffer length */ chan, rpc_trace) >0); } /*__________________________________________________________________________ * * Procedure: Encode as necessary and send byte down V24 channel * */ void send_byte_encoded(octet, do_block_check) rpc_byte octet; BOOLEAN do_block_check; { { register v24_chan_info_type *chan = &v24_chan_info[(G88_socket)->mdp.v24.soc_chan]; if (do_block_check) compute_block_check(octet, chan->block_check_used, &(chan->computed_block_check)); if (chan->traffic == eight_bit) if ((octet == RPC_V24_STARTOFPACKET) || (octet == RPC_V24_ESC_7E)) { *buffer_pointer++ = RPC_V24_ESC_7E; *buffer_pointer++ = (octet ^ 64); } else { *buffer_pointer++ = octet; } else if ((octet <= 92)) { *buffer_pointer++ = octet + 32; } else if ((octet <= 185)) { *buffer_pointer++ = RPC_V24_ESC_7D; *buffer_pointer++ = octet - 61; } else { *buffer_pointer++ = RPC_V24_ESC_7E; *buffer_pointer++ = octet - 154; } } } /*__________________________________________________________________________ * * Procedure: * */ void rpc_v24_send_message(status, socket, pmessage, bufsize) rpc_status *status; socket_type socket; rpc_message_pointer pmessage; rpc_long bufsize; { register int d_index; int d_start; rpc_byte octet; G88_socket = socket; { register struct socket_struct *soc = socket; { register v24_chan_info_type *chan = &v24_chan_info[soc->mdp.v24.soc_chan]; /* channel tc; int ln; out */ *status = RPC_S_NORMAL; if (rpc_trace) { UTRACE(tfp, "Send V24 mess line %1d, link %1d, len %1d\n", soc->mdp.v24.soc_chan, soc->mdp.v24.soc_link_number, bufsize); } v24_clear(soc->mdp.v24.soc_chan); /* Request to Send/Clear to send character exchange */ if ((chan->rtscts_enabled)) do { if (!send_byte(RPC_V24_RTS, soc->mdp.v24.soc_chan)) goto L99; *status = get_byte(&octet, soc->mdp.v24.soc_chan, 100); if (*status == RPC_S_FRAMING) goto L99; else if ((*status == RPC_S_NORMAL) && (octet >= 32)) if ((octet != RPC_V24_CTS)) { *status = RPC_S_FRAMING; goto L99; } } while (!((*status == RPC_S_NORMAL) && (octet == RPC_V24_CTS))); chan->computed_block_check = 0; send_buffer[0] = RPC_V24_STARTOFPACKET; buffer_pointer = (char *)&send_buffer[1];/* Point to next empty byte */ if (bufsize < 128) { chan->block_check_used = checksum; send_byte_encoded((rpc_byte)(bufsize + 128), TRUE); } else { chan->block_check_used = crc_ccitt; send_byte_encoded((rpc_byte)(bufsize / 256), TRUE); send_byte_encoded((rpc_byte)(bufsize % 256), TRUE); } send_byte_encoded((rpc_byte)(soc->mdp.v24.soc_link_number), TRUE); { register rpc_message *mes = pmessage; if ((mes->body.which == CALL_MESSAGE) && (mes->body.cal.program_number.h.h == 0) && (mes->body.cal.program_number.h.l == 0) && (mes->body.cal.program_number.l.h == 0) && (mes->body.cal.program_number.l.l < 24) && (mes->body.cal.version_number.h == 0) && (mes->body.cal.version_number.l == 0) && (mes->body.cal.procedure_number.h == 0)) { send_byte_encoded((rpc_byte) ( ((mes->body.cal.program_number.l.l + 8) * 8) + mes->body.cal.call_transaction_id.l), TRUE); send_byte_encoded((rpc_byte)(mes->body.cal.procedure_number.l), TRUE); d_start = 12; } else { send_byte_encoded((rpc_byte) #ifdef LSBFIRST ((mes->body.which>>5) + mes->body.cal.call_transaction_id.l), #else ((mes->body.which<<3) + mes->body.cal.call_transaction_id.l), #endif TRUE); d_start = 4; } for (d_index = d_start; d_index<=bufsize-1 ; d_index++) send_byte_encoded(mes->body.rpc_b[d_index], TRUE); } if (chan->block_check_used == checksum) send_byte_encoded((rpc_byte)(chan->computed_block_check), FALSE); else { send_byte_encoded((rpc_byte)(chan->computed_block_check / 256), FALSE); send_byte_encoded((rpc_byte)(chan->computed_block_check % 256), FALSE); } v24_send( send_buffer, /* Address */ buffer_pointer - (char *)send_buffer, /* Length */ soc->mdp.v24.soc_chan, rpc_trace); L99: if (rpc_trace) if (*status == RPC_S_NORMAL) UTRACE(tfp, "RPC/TS: V24 message sent \n"); else UTRACE(tfp, "Error sending V24 message.\n"); } } } /*__________________________________________________________________________ * * Function: V24 Packet Reader State Machine * */ packet_reader_states rpc_v24_reader_automaton(octet) rpc_byte octet; { int V24_mess_type; register v24_chan_info_type *chan = &v24_chan_info[G92_socket->mdp.v24.soc_chan]; register rpc_message * mes = G94_mes; /* if ((chan->traffic == seven_bit)) octet = (unsigned)(octet & 127); */ if ((octet == RPC_V24_STARTOFPACKET)) { chan->data_index = 0; chan->block_check_enabled = FALSE; chan->packet_reader_state = got_marker; chan->byte_reader_state = cleared; } else if (((int)(chan->packet_reader_state) >= (int)(idle))) { chan->packet_reader_state = idle; if ((chan->rtscts_enabled) && (octet == RPC_V24_RTS)) if (!send_byte(RPC_V24_CTS, G92_socket->mdp.v24.soc_chan)) chan->packet_reader_state = C1_abort; } else { if ((chan->traffic == eight_bit)) if ((octet == RPC_V24_ESC_7E)) chan->byte_reader_state = got_escape_7e; else { if ((chan->byte_reader_state == got_escape_7e)) { octet = (unsigned)(octet ^ 64); chan->byte_reader_state = cleared; } } else { if ((octet == RPC_V24_ESC_7D)) chan->byte_reader_state = got_escape_7d; else if ((octet == RPC_V24_ESC_7E)) chan->byte_reader_state = got_escape_7e; else if ((chan->byte_reader_state == got_escape_7d)) { octet = octet + 61; chan->byte_reader_state = cleared; } else if ((chan->byte_reader_state == got_escape_7e)) { octet = octet + 154; chan->byte_reader_state = cleared; } else octet = octet - 32; } if ((chan->byte_reader_state == cleared)) { if ((chan->block_check_enabled)) compute_block_check(octet, chan->block_check_used, &chan->computed_block_check); switch ((int)(chan->packet_reader_state)) { case got_marker: if (octet & 0x80) { /* Bit 7 flags "short message" */ chan->block_check_used = checksum; chan->message_size = octet & 0x7f ; chan->packet_reader_state = got_length; } else { /* Long message */ chan->block_check_used = crc_ccitt; chan->message_size = octet << 8; chan->packet_reader_state = getting_length; } chan->computed_block_check = 0; chan->block_check_enabled = TRUE; compute_block_check(octet, chan->block_check_used, &chan->computed_block_check); break ; case getting_length: chan->message_size = chan->message_size + octet; if ((chan->message_size > RPC_BUFFER_SIZE)) chan->packet_reader_state = got_garbled_packet; else chan->packet_reader_state = got_length; break ; case got_length: chan->link_number = octet; chan->packet_reader_state = got_link_number; break ; case got_link_number: mes->body.cal.call_transaction_id.h = 0; mes->body.cal.call_transaction_id.l = (unsigned)(octet & 7); V24_mess_type = octet >> 3; if ((V24_mess_type >= 8)) { mes->body.which = CALL_MESSAGE; mes->body.cal.program_number.h.h = 0; mes->body.cal.program_number.h.l = 0; mes->body.cal.program_number.l.h = 0; mes->body.cal.program_number.l.l = V24_mess_type - 8; mes->body.cal.version_number.h = 0; mes->body.cal.version_number.l = 0; mes->body.cal.procedure_number.h = 0; chan->packet_reader_state = getting_proc_number; } else { #ifdef LSBFIRST mes->body.which = V24_mess_type<<8; #else mes->body.which = V24_mess_type; #endif if ((chan->message_size > 4)) { chan->data_index = 4; chan->packet_reader_state = getting_data; } else { chan->block_check_enabled = FALSE; chan->packet_reader_state = got_data; } } break ; case getting_proc_number: mes->body.cal.procedure_number.l = octet; if ((chan->message_size > 12)) { chan->data_index = 12; chan->packet_reader_state = getting_data; } else { chan->block_check_enabled = FALSE; chan->packet_reader_state = got_data; } break ; case getting_data: mes->body.rpc_b[chan->data_index] = octet; if ((chan->data_index == chan->message_size - 1)) { chan->block_check_enabled = FALSE; chan->packet_reader_state = got_data; } chan->data_index = chan->data_index + 1; break ; case got_data: if ((chan->block_check_used == checksum)) { chan->received_block_check = octet; if ((chan->received_block_check == chan->computed_block_check)) chan->packet_reader_state = got_good_packet; else chan->packet_reader_state = got_garbled_packet; } else { chan->received_block_check = octet * 256; chan->packet_reader_state = getting_block_check; } break ; case getting_block_check: chan->received_block_check = chan->received_block_check + octet; if ((chan->received_block_check == chan->computed_block_check)) chan->packet_reader_state = got_good_packet; else chan->packet_reader_state = got_garbled_packet; break ; } } } return chan->packet_reader_state; } /* Receive a mesaage v24_get_message() ** ----------------- ** ** This is a raw packet read on the RS232 channel, which may pick ** up a corruption or a timeout. */ #ifdef __STDC__ PRIVATE rpc_status rpc_v24_get_message( rpc_message *mes, int timeout) #else PRIVATE rpc_status rpc_v24_get_message(mes, timeout) rpc_message *mes; int timeout; #endif { rpc_byte octet; packet_reader_states automaton_state; BOOLEAN again; /* Set up global variables for automata to use */ socket_type soc = G92_socket = mes->m_socket; G94_mes = mes; CTRACE(tfp, "Waiting for V24 message...\n"); FLUSH_TRACE { register v24_chan_info_type *chan = &v24_chan_info[soc->mdp.v24.soc_chan]; do { again = FALSE; chan->packet_reader_state = idle; chan->byte_reader_state = cleared; chan->data_index = 0; chan->message_size = 0; automaton_state = idle; /* Get a packet: */ do { mes->m_status = get_byte(&octet, (G92_socket)->mdp.v24.soc_chan, timeout); if (mes->m_status == RPC_S_NORMAL) automaton_state = rpc_v24_reader_automaton(octet); } while (!((mes->m_status != RPC_S_NORMAL) || ((int)(automaton_state) >= (int)(got_good_packet)))); /* Decode status: */ if (mes->m_status == RPC_S_NORMAL) if ((automaton_state == got_garbled_packet) || (automaton_state == C1_abort)) mes->m_status = RPC_S_FRAMING; else if (soc->mdp.v24.soc_link_number != chan->link_number) again = TRUE; mes->m_index = chan->message_size; /* Print trace message: */ if (rpc_trace) if (mes->m_status == RPC_S_NORMAL) { UTRACE(tfp, "RPC/TS: V24 message received ok, link number %1d\n", chan->link_number); /* hex_message(mes, mes->m_index); see ts_receive*/ } else { UTRACE(tfp, "RPC/TS: Error receiving V24 message:\n"); if ((mes->m_status == RPC_S_TIMEOUT)) UTRACE(tfp, " Timeout Limit Expired\n"); else if ((automaton_state == got_garbled_packet)) if ((mes->m_index > RPC_BUFFER_SIZE)) UTRACE(tfp, " Illegal Length Received: %1d\n", mes->m_index); else { UTRACE(tfp, " Wrong Block Check Received, Computed: %4x, Received: %4x\n", chan->computed_block_check, chan->received_block_check); } else if ((automaton_state == C1_abort)) UTRACE(tfp, " Error Sending CTS\n"); else UTRACE(tfp, " Unknown Reason\n"); if ((mes->m_index > 0) && (mes->m_index <= RPC_BUFFER_SIZE)) { UTRACE(tfp, " Original packet length could be %1d\n", mes->m_index); } if ((chan->data_index > 0)) { UTRACE(tfp, " Incomplete message dump follows,"); hex_message(G94_mes, chan->data_index); } } /* end if trace, if not normal */ } while (again); } return mes->m_status; } /* Check for Duplicate Message duplicate_v24() ** --------------------------- */ PRIVATE BOOLEAN duplicate_v24(pmessage) rpc_message_pointer pmessage; { register rpc_message_pointer mes = pmessage; if ( (mes->body.which == RETURN_MESSAGE) || (mes->body.which == REJECT_MESSAGE)) { { register struct socket_struct *soc = mes->m_socket; if (soc->soc_last_call_sent) if ((mes->body.cal.call_transaction_id.l != soc->soc_last_call_sent->body.cal.call_transaction_id.l)) { CTRACE(tfp, "RPC/TS: *** Duplicated reply received: Discarded ***\n"); return TRUE; } } } else if ((mes->body.which == CALL_MESSAGE)) { { register struct socket_struct *soc = mes->m_socket; if (soc->soc_last_reply_sent) if (mes->body.cal.call_transaction_id.l) if (mes->body.cal.call_transaction_id.l == soc->soc_last_reply_sent-> body.ret.return_transaction_id.l) { rpc_v24_send_message( &mes->m_status, mes->m_socket, soc->soc_last_reply_sent, soc->soc_last_reply_sent->m_index); CTRACE(tfp, "RPC/TS: Duplicated call received, Last reply retransmitted ***\n"); return TRUE; } } } return FALSE; } /* Return RPC address of this socket v24_my_address() ** --------------------------------- ** ** This routine returns a string indicating the RPC address of the socket. ** ** On entry, ** soc should be a valid socket pointer ** addrstr points to a buffer to contain a string. ** addrlen indicates the length of the string buffer ** ** On exit, ** *addrstr has the contact address for an external node wishing to contact ** this socket written into it, zero terminated, without the ** protocol on the end. */ #ifdef __STDC__ PRIVATE rpc_status v24_my_address( socket_type soc, chr * addrstr, int addrlen) #else PRIVATE rpc_status v24_my_address(soc, addrstr, addrlen) socket_type soc; char * addrstr; int addrlen; #endif { return RPC_S_NOT_IMPLEMENTED; } /* Return RPC address of peer v24_peer_address() ** -------------------------- ** ** On entry, ** soc should be a valid socket pointer ** address points to a buffer to contain an rpc_name. ** ** On exit, ** *address has the contact address for the peer node. ** blank filled. ** 26 useful characters in the address. */ #ifdef __STDC__ PRIVATE rpc_status v24_peer_address( socket_type soc, char * addrstr, int addrlen) #else PRIVATE rpc_status v24_peer_address(soc, addrstr, addrlen) socket_type soc; char * addrstr; int addrlen; #endif { return RPC_S_NOT_IMPLEMENTED; } /* Send a message over the given socket v24_write() ** ------------------------------------ ** ** On entry, ** pmessage points to a pointer to the message, with fields: ** m_next (undefined) ** m_socket valid ** m_index Length of message to be sent in bytes, ** exclusing any bytes needed for the protocol. ** m_status (undefined) ** ** On exit, ** ** The pointer to the message may have been changed. In this case, ** it will point to a message with the m_socket and m_status fields ** set, but without the data. This routine is therefore DESTRUCTIVE. ** ** returns: Status of operation. */ #ifdef __STDC__ PRIVATE rpc_status v24_write(rpc_message_pointer *ppmessage) #else PRIVATE rpc_status v24_write(ppmessage) rpc_message_pointer *ppmessage; #endif { rpc_status status; register rpc_message *mes = *ppmessage; register struct socket_struct *soc = mes->m_socket; mes->m_status = check_socket(soc); if (BAD(mes->m_status)) return mes->m_status; if (rpc_trace) { UTRACE(tfp, "RPC/v24: Sending message, "); hex_message(mes, mes->m_index); } if ((mes->body.which == CALL_MESSAGE)) { mes->body.cal.call_transaction_id.l = soc->soc_next_call_tid; soc->soc_next_call_tid = soc->soc_next_call_tid % 7 + 1; } rpc_v24_send_message(&mes->m_status, mes->m_socket, mes, (rpc_long) RPC_BUFFER_SIZE); if (((*ppmessage)->body.which == RETURN_MESSAGE) || ((*ppmessage)->body.which == REJECT_MESSAGE)) { rpc_message_pointer temp_pointer; if ((soc->soc_last_reply_sent == NIL_MESSAGE)) { rpc_new(&soc->soc_last_reply_sent, RPC_BUFFER_SIZE); soc->soc_last_reply_sent->m_socket = soc; soc->soc_last_reply_sent->m_status = RPC_S_NORMAL; } temp_pointer = (*ppmessage); (*ppmessage) = soc->soc_last_reply_sent; soc->soc_last_reply_sent = temp_pointer; } else if ((*ppmessage)->body.which == CALL_MESSAGE) { register rpc_message_pointer temp_pointer; if ((soc->soc_last_call_sent == NIL_MESSAGE)) { rpc_new(&soc->soc_last_call_sent, RPC_BUFFER_SIZE); soc->soc_last_call_sent->m_socket = soc; soc->soc_last_call_sent->m_status = RPC_S_NORMAL; } temp_pointer = *ppmessage; *ppmessage = soc->soc_last_call_sent; soc->soc_last_call_sent = temp_pointer; } return (*ppmessage)->m_status; } /* Receive message v24_read() ** --------------- ** ** This procedure waits for a message to arrive on a socket and returns the ** message. A suitable message buffer is passed to the routine, but a ** different one may be returned. If the socket passed is the master socket ** for mutiple connections, then the message recieved will carry the socket ** number of the slave socket on which the message actually arrived. ** ** On entry: ** ppmessage is pointer to pointer to buffer, fields: ** m_socket The socket to be used - possibly a master socket ** m_index don't care ** m_status don't care ** m_next don't care ** ** timeout -1 for infinite, 0 for poll, else in units of 10ms ** ** On exit, ** returns The status of the operation. ** *pmessage may have been modified to point to another message ** from the pool. Fields: ** m_socket The (possible slave) socket the msg came on. ** m_status The status of the operation (= return value). ** m_index The number of bytes recieved if good status ** m_next junk. ** */ #ifdef __STDC__ PRIVATE rpc_status v24_read( rpc_message_pointer *ppmessage, int timeout) #else PRIVATE rpc_status v24_read(ppmessage, timeout) rpc_message_pointer *ppmessage; int timeout; #endif { int waited; int backoff; BOOLEAN again; rpc_status status; register struct socket_struct *soc = (*ppmessage)->m_socket; if (soc->soc_last_call_sent == NULL) backoff = timeout; else { waited = 0; backoff = 500; } do { again = FALSE; if (soc->soc_last_call_sent != NULL) { if ((timeout >= 0)) if ((waited + backoff > timeout)) backoff = timeout - waited; waited = waited + backoff; } status = rpc_v24_get_message(*ppmessage, backoff); if (status == RPC_S_FRAMING) { again = TRUE; CTRACE(tfp, "RPC/TS/v24: GARBLED PACKET RECEIVED, Waiting for retransmission ***\n"); } else if (status == RPC_S_TIMEOUT) { if (rpc_trace) UTRACE(tfp, "RPC/TS/V24: Timeout period expired\n"); if ((soc->soc_last_call_sent != NIL_MESSAGE)) if (((timeout < 0) || (waited < timeout))) { if ((backoff < BACKOFF_LIMIT / 2)) backoff = backoff + backoff; else backoff = BACKOFF_LIMIT; rpc_v24_send_message(&status, soc, soc->soc_last_call_sent, soc->soc_last_call_sent->m_index); CTRACE(tfp, "RPC/TS/v24: Last message retransmitted\n"); again = TRUE; } else CTRACE(tfp, "RPC/TS/V24: Total timeout expired: stop trying ***\n"); } else if (GOOD(status)) again = duplicate_v24((*ppmessage)); } while (again); /* If we have got a valid reply, we can dispose of the last call ** we sent out. */ if (soc->soc_last_call_sent != NULL) if (((*ppmessage)->body.which == RETURN_MESSAGE) || ((*ppmessage)->body.which == REJECT_MESSAGE)) { rpc_dispose(soc->soc_last_call_sent); soc->soc_last_call_sent = NULL; } (*ppmessage)->m_status = status; return status; } /* Asynchronous Receive ** -------------------- ** ** On entry, ** pmessage is the address of a suitable message buffer ** action is the address of the routine to be called ** user_1 is not used at the moment. ** ** On exit, ** the parameters are stored only. Exits immediately. ** ** On arrival of the next message: ** The routine *action() is called, and passed the message as a parameter. ** If the buffer *pmessage is not used, it will be reused elsewhere and ** a different buffer passed to *action(). */ #ifdef __STDC__ PRIVATE rpc_status v24_aread( rpc_message_pointer pmessage, rpc_pointer action, rpc_integer user_1) #else PRIVATE rpc_status v24_aread(pmessage, action, user_1) rpc_message_pointer pmessage; rpc_pointer action; rpc_integer user_1; #endif { return(RPC_S_NOT_IMPLEMENTED); } /* v24_aread */ /* Open a transport connection v24_open() ** --------------------------- ** ** On entry, ** soc points to a recently created socket, fields as follows: ** ** soc_last_call_sent NULL ** soc_last_reply_sent NULL ** soc_next-call_tid 0 ** soc_protocol valid pointer to protocol structure ** ** and otherwise uninitialised. ** ** tsap points to a zero-terminated string representing the address ** (with no .v24 on it) */ #ifdef __STDC__ PRIVATE rpc_status v24_open(socket_type soc, char * tsap) #else PRIVATE rpc_status v24_open(soc, tsap) socket_type soc; char *tsap; #endif { /* We have to put the values of some parameters into temporary variables ** because we do not yet know which channel to load them into. */ traffic_type tmp_traffic; BOOLEAN tmp_rtscts; int tmp_speed; char *p = tsap; /* Pointer to string */ rpc_status status = RPC_S_NORMAL; /* To be returned */ tmp_traffic = eight_bit; tmp_rtscts = FALSE; tmp_speed = 0; soc->mdp.v24.soc_link_number = 0; soc->mdp.v24.soc_chan = 0; { int a; /* Coerce all to uppercase */ for (a=0; tsap[a]; a++) tsap[a] = toupper(tsap[a]); } for (;*p;) { switch ((int)(*p++)) { case '0': break; case 'L': tmp_traffic = seven_bit; break ; case 'B': tmp_traffic = eight_bit; break ; case 'R': tmp_rtscts = TRUE; break ; case 'F': tmp_rtscts = FALSE; break ; case 'C': soc->mdp.v24.soc_link_number = parse_cardinal(&status, &p, 255); break ; case 'S': tmp_speed = parse_cardinal(&status, &p, 19200); break ; case 'T': /* Terminal number Tnnn */ if (*p != 'T') /* Allow TTnnn instead of Tnnn */ soc->mdp.v24.soc_chan = parse_cardinal( &status, &p, V24_CHANNELS-1); #ifdef __MSDOS__ /* For MSDOS, COMn: numbers start from 1, but our 'chan' numbers (and parameters to async_xxx) start at 0. */ soc->mdp.v24.soc_chan--; #endif break ; case ':': break ; case '_': break ; default: status = RPC_S_SYNTAX_4; /* Invalid option */ } /*switch*/ } /*for*/ { /*with*/ register v24_chan_info_type *chan = &v24_chan_info[soc->mdp.v24.soc_chan]; chan->traffic = tmp_traffic; chan->rtscts_enabled = tmp_rtscts; chan->speed = tmp_speed; } /*with*/ if (GOOD(status)) return rpc_v24_open(soc->mdp.v24.soc_chan); else return status; } /* Close a Transport Connection v24_close() ** ---------------------------- ** ** On entry, ** soc Must be a socket opened by v24_open(). ** ** On exit, ** returns a status of the close operation. */ #ifdef __STDC__ PRIVATE rpc_status v24_close(socket_type soc) #else PRIVATE rpc_status v24_close(soc) socket_type soc; #endif { rpc_status status; rpc_v24_close(soc->mdp.v24.soc_chan, &status); return status; } /* v24_close */ /* Data structure defining this medium: ** ----------------------------------- */ PRIVATE rpc_protocol v24_protocol = { 0, /* Link (not yet used) */ "v24", /* Name of medium used in address strings */ 0, /* No, not reliable */ v24_open, v24_close, v24_write, v24_read, v24_aread, v24_my_address, v24_peer_address, }; /* Register this protocol with the RPC system ** ------------------------------------------ */ #ifdef __STDC__ rpc_status use_v24(void) #else rpc_status use_v24() #endif { { register int s; for (s=0; sv24_usage = 0; chan->packet_reader_state = idle; chan->byte_reader_state = cleared; } } rpc_use(v24_protocol); }