/*		TCP/IP based Transport Service for RPC		        ts_tcp.c
**		======================================
**
**  This module provides a transport service for the RPC system developed
**  by CERN/DD Online group in 1986-90.
**
**  This particular module uses the xistsing TCP/IP 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.
**
**  History:
**	30 Apr 90   Code extracted from general ts.c module.
**
**  Compilation switches:
**
*/


/*	Module parameters:
**	-----------------
**
**  These may be undefined and redefined by syspec.h
*/
# define WILDCARD '*'	    /* Wildcard used in addressing */


#include <stdio.h>
#include "syspec.h"
#define TS			/*  Require visibility of TS data structures */
#include "rpcrts.h"		/*  Define all general RPC data structures   */
#include "rpc_code.h"		/* Coding convention macros */
#include "ts.h"			/* protocol type structure */
/*
**      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



/*	Return RPC address of this socket		        tcp_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 tcp_my_address(
    socket_type	    soc,
    chr *	    addrstr,
    int		    addrlen)
#else
PRIVATE rpc_status tcp_my_address(soc, addrstr, addrlen)
    socket_type	    soc;
    char *	    addrstr;
    int		    addrlen;
#endif
{
    @@@
}

/*	Return RPC address of peer		              tcp_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 tcp_peer_address(
    socket_type	    soc,
    char * 	    addrstr,
    int		    addrlen)
#else
PRIVATE rpc_status tcp_peer_address(soc, addrstr, addrlen)
    socket_type	    soc;
    char *	    addrstr;
    int		    addrlen;
#endif
{
    @@@
}

/*      Send a message over the given socket			     tcp_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 tcp_write(rpc_message_pointer *ppmessage)
#else
PRIVATE rpc_status tcp_write(ppmessage)
    rpc_message_pointer *ppmessage;
#endif
{
    rpc_status		status;

    register rpc_message *mes = *ppmessage;
    register struct socket_struct *soc = mes->m_socket;
 
    status = check_socket(soc);
    if (BAD(status)) return status;

    if (rpc_trace) {
	    UTRACE(tfp, "RPC/tcp: Sending message, ");
	    hex_message(mes, mes->m_index);
    }
    @@@
    return status;
} 

/*      Receive message						      tcp_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 tcp_read(
        rpc_message_pointer *ppmessage,
        int		    timeout)
#else
PRIVATE rpc_status tcp_read(ppmessage, timeout)
        rpc_message_pointer *ppmessage;
        int		    timeout;
#endif
{
    @@@
    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 tcp_aread(
        rpc_message_pointer     pmessage,
        rpc_pointer		action,
        rpc_integer		user_1)
#else
PRIVATE rpc_status tcp_aread(pmessage, action, user_1)
        rpc_message_pointer     pmessage;
        rpc_pointer		action;
        rpc_integer		user_1;
#endif
{
    return(RPC_S_NOT_IMPLEMENTED);
} /* tcp_aread */

/*	Open a transport connection				      tcp_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 .TCP on it)
*/

#ifdef __STDC__
PRIVATE rpc_status tcp_open(socket_type soc, char * tsap)
#else
PRIVATE rpc_status tcp_open(soc, tsap)
    socket_type	soc;
    char	*tsap;
#endif
{
    @@@
}

/*	Close a Transport Connection				     tcp_close()
**	----------------------------
**
**  On entry,
**	soc	Must be a socket opened by tcp_open().
**
**  On exit,
**	returns	a status of the close operation.
*/

#ifdef __STDC__
PRIVATE rpc_status tcp_close(socket_type soc)
#else
PRIVATE rpc_status tcp_close(soc)
    socket_type	soc;
#endif
{
    @@@
} /* tcp_close */

/*	Data structure defining this medium:
**	-----------------------------------
*/

PRIVATE rpc_protocol tcp_protocol = {
    0,				/* Link (not yet used) */
    "tcp",			/* Name of medium used in address strings */
    0,				/* No, not reliable */
    tcp_open,
    tcp_close,
    tcp_write,
    tcp_read,
    tcp_aread,
    tcp_my_address,
    tcp_peer_address,
};


/*	Register this protocol with the RPC system
**	------------------------------------------
*/

#ifdef __STDC__
rpc_status use_tcp(void)
#else
rpc_status use_tcp()
#endif
{
    rpc_tcp_init();		/* Initialise any machine-dependent stuff */
    rpc_use(tcp_protocol);
}