/*
 * Copyright (C) 1992 WIlfried Koch, Palanterstr. 46, D-5000 Koeln 41 (Germany)
 * All rights reserved.
 *
 * This software may be freely copied, modified, and redistributed
 * provided that this copyright notice is preserved on all copies.
 *
 * You may not distribute this software, in whole or in part, as part of
 * any commercial product without the express consent of the authors.
 *
 * There is no warranty or other guarantee of fitness of this software
 * for any purpose.  It is provided solely "as is".
 * Initial version.
 */
#include <errno.h>
#include "rrloops.h"
#include "rpcspec.h"


#ifdef ONCRPC
void ServiceInfo();
void ClientInfo();
void ConnectionInfo();
static u_long ServicePrognum = NULL;
static u_long CallbackPrognum =NULL;
static CLIENT *client=NULL;
	
RRConnList
*RRFindConnection ( conn, connlist ) 
	RRConnection *conn;
	RRConnList *connlist;
	{
	RRConnList *tmp;
	tmp=connlist;
	while(tmp) {
		if((!strcmp(tmp->conn.clientname,conn->clientname)) &&
		   (!strcmp(tmp->conn.servername,conn->servername)) &&
		   (tmp->conn.clientno==conn->clientno) &&
		   (tmp->conn.servno==conn->servno) &&
		   (tmp->conn.transport==conn->transport)
		   ) {
			return(tmp);
		}
		
		tmp=tmp->next;
	}
	return NULL;
}
RRreqList *
FindReqByConn(requestlist,conn)
        RRreqList *requestlist;
        RRConnection *conn;
{
        RRreqList *curreq;
        curreq=requestlist;

        if((!requestlist) || (!conn) )
                return NULL;

        while(curreq) {
                if(
		   (!strcmp(curreq->rrreq.connect.clientname,conn->clientname)) &&
                   (!strcmp(curreq->rrreq.connect.servername,conn->servername)) &&
                   (curreq->rrreq.connect.clientno==conn->clientno) &&
                   (curreq->rrreq.connect.servno==conn->servno) &&
                   (curreq->rrreq.connect.transport==conn->transport)
                 ) {
                        break;
                }
        	curreq=curreq->next;
        }
        return curreq;
}
bool_t RRTryClient() 
{
	CLIENT *client;
        static time_t t=NULL;
        time_t tt;
	
	time(&tt);
	if( (tt-t) > 3)
       		time(&t);
	else
		return TRUE;
	if(!Conn.clientname)
		return TRUE;

		if(!(client=clnt_create(Conn.clientname, Conn.clientno,
                                 REMOTERENDERCALLBACKVERS, "udp"))) {
			if(ServeAndExit){
				fprintf(stderr,"\n");
            			ConnectionInfo(&Conn,stderr);
            			fprintf(stderr," Connection lost\n");
				RRUnRegisterService();
				exit(0);
			} else {
				RRFreeArgs();	
			}
            	} else {
			clnt_destroy(client);
		}	
	return TRUE;
}




bool_t RunService()                 /** Writing your own svc_run() in "The Art of     **/
                                /** Distributed Applications ",   John R. Corbin  **/
{
       CALLBACK_VAR             /** specific variables for RPC-Tool and           **/
                                /** and  underlaying network transport  layer     **/

       switch(LISTEN_TO_NETWORK){

               ERROR_LISTEN:    /** in netspec.h                                  **/
                        ACTION_ON_ERROR_LISTEN;
                        break;

               NO_MESSAGE:      /** in netspec.h                                  **/
			if(!RRTryClient())
				return (TRUE);

               GOT_CALLBACK:    /** in rpcspec.h                                  **/
                       ACTION_ON_CALLBACK;
       }
       return FALSE;
}

void ResolvePMExeString(exestring,conn) 
	char *exestring;
	RRConnection *conn;
{
	if(!isdigit(*exestring)){
		fprintf(stderr,"You must specify a Portmapper number\n",(int)*exestring);
		exit(1);
	}
 	conn->clientno=atoi(exestring)+0x40000000;
	while(isdigit(*exestring))
		exestring++;
	if(*exestring!='@') {
		fprintf(stderr,"You must add @ to Portmapper number\n");
		exit(1);
	}
	exestring++;
	if(!*exestring){
		fprintf(stderr,"You must specify hostname\n");
		exit(1);
	}
	conn->clientname=(char*)strsave(exestring);
	conn->servername=MyHostname;
	conn->servno=ServicePrognum;
	conn->transport= PORTMAPPER_TCPIP_ON_PORTMAPPER_TCPIP;
}
void RRUnRegisterService()
{
	int i;
	fprintf(stderr,"\n");
	ServiceInfo(stderr);
	i=pmap_unset(ServicePrognum,REMOTERENDERVERS);
	fprintf(stderr,"n unregistered %d\n",i);
	if(ServeAndExit)
	     exit(1);
	else
	     exit(0);
}
void RRUnRegisterServiceCore()
{
	int i;
	fprintf(stderr,"\n");
	ServiceInfo(stderr);
	i=pmap_unset(ServicePrognum,REMOTERENDERVERS);
	fprintf(stderr,"c unregistered %d\n",i);
	abort();
	exit(1);
}
void RRUnRegisterCallback(code)
	int code;
{
	int i;
	fprintf(stderr,"\n");
	ClientInfo(stderr);
	i=pmap_unset(CallbackPrognum,REMOTERENDERVERS);
	fprintf(stderr," n unregistered %d\n",i);
	if(code==-1000)
		exit(0);	
	else
		exit(1);
}
void RRUnRegisterCallbackCore()
{
	fprintf(stderr,"\n");
	ClientInfo(stderr);
	pmap_unset(CallbackPrognum,REMOTERENDERVERS);
	fprintf(stderr,"c unregistered\n");
	abort();
}
void RegisterPMService ( )
{

        SVCXPRT *transptcp;
        SVCXPRT *transpudp;
        u_long prognum = REMOTERENDER+1;

        transptcp = svctcp_create(RPC_ANYSOCK, 200000, 0);
        transpudp = svcudp_create(RPC_ANYSOCK);
        if ((transptcp == NULL) || transpudp==NULL) {
                fprintf(stderr, "cannot create tcp and udp service.");
                exit(1);
        }
	while (pmap_set(prognum, REMOTERENDERVERS, IPPROTO_TCP,transptcp->xp_port)==0 && prognum < REMOTERENDER+MAXPROGNUMS){
               prognum++;
        }
  	if(prognum < REMOTERENDER+MAXPROGNUMS){
               if( ! svc_register(transptcp,prognum,REMOTERENDERVERS,remoterender_1,IPPROTO_TCP )) {
                       	svc_unregister(prognum,REMOTERENDERVERS);
                	fprintf(stderr, "cannot create tcp service.");
                	exit(1);
               }
               if( ! svc_register(transpudp,prognum,REMOTERENDERVERS,remoterender_1,IPPROTO_UDP )) {
                       	svc_unregister(prognum,REMOTERENDERVERS);
                	fprintf(stderr, "cannot create udp service.");
                	exit(1);
               }
        } else {
                fprintf(stderr, "cannot create tcp and udp service.");
                exit(1);
	}
       ServicePrognum=prognum;
}

RegisterCallback( )
{
 SVCXPRT *tcptransp;
 SVCXPRT *udptransp;
        u_long prognum = 0x40000000;

        tcptransp = svctcp_create(RPC_ANYSOCK, 0, 200000);
        udptransp = svcudp_create(RPC_ANYSOCK);
        if (tcptransp == NULL) {
                fprintf(stderr, "cannot create tcp service.");
                exit(1);
        }
        if (udptransp == NULL) {
                fprintf(stderr, "cannot create udp service.");
                exit(1);
        }
        while (pmap_set(prognum, REMOTERENDERVERS, IPPROTO_TCP,tcptransp->xp_port)==0 && prognum < REMOTERENDER+MAXPROGNUMS){
               prognum++;
        }
        if(prognum < 0x50000000){
               if( ! svc_register(udptransp,prognum,REMOTERENDERCALLBACKVERS,DispatchCallback, IPPROTO_UDP )) {
                        svc_unregister(prognum,REMOTERENDERVERS);
                        fprintf(stderr, "cannot create udp service.");
                        exit(1);
               }
               if( ! svc_register(tcptransp,prognum,REMOTERENDERCALLBACKVERS,DispatchCallback,  IPPROTO_TCP)) {
                        svc_unregister(prognum,REMOTERENDERVERS);
                        fprintf(stderr, "cannot create tcp service.");
                        exit(1);
               }
        } else {
                fprintf(stderr, "cannot create tcp/udp service.");
                exit(1);
        }
       CallbackPrognum=prognum;

}
void TAPCat(s)
	char *s;
{
	sprintf(s,"%d@%s &",CallbackPrognum-0x40000000,MyHostname);
}
int _rpc_dtablesize()
{
       static int size;
       if(!size){
               size=getdtablesize();
       }
       return (size);
}

bool_t ConsultPortmapper(conn)
	RRConnection *conn;
{
	struct sockaddr_in server_addr;
        register struct hostent *hp;
	static struct pmaplist *curmap=NULL;
	static struct pmaplist *maphead=NULL;
        int socket;
        struct timeval minutetimeout;
	static u_long lastprognum = -1;
	socket = RPC_ANYSOCK;
	
	if(lastprognum!=-1)
		goto look;
  	bzero((char *)&server_addr, sizeof server_addr);
        server_addr.sin_family = AF_INET;
	if ((hp = gethostbyname(conn->servername)) != NULL){
		bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
                            hp->h_length);
	} else  {
		fprintf(stderr,"unreachable");
		return FALSE;
	}
  	minutetimeout.tv_sec  = 4;
        minutetimeout.tv_usec = 0;
        server_addr.sin_port = htons(PMAPPORT);
        if (! (client = clnttcp_create(&server_addr, PMAPPROG,
            PMAPVERS, &socket, 50, 500))) {
                fprintf(stderr,"portmapper not available");
		return FALSE;
        }
	SetServerTimeout(&minutetimeout);
	curmap=NULL;
        if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
            xdr_pmaplist, &maphead, minutetimeout) != RPC_SUCCESS) {
                fprintf(stderr, "portmapper did't send portmaplist");
		clnt_destroy(client);
                return FALSE;
        }
	clnt_destroy(client);
	fprintf(stderr," OK\n");
	curmap=maphead;

	look:

	if(lastprognum!=-1) {
		if(curmap)
			curmap=curmap->pml_next;
	}
	
	if(!curmap){
        	xdr_free(xdr_pmaplist,&maphead);
		maphead=NULL;
		lastprognum= - 1 ;
		return FALSE;
	}


	lastprognum=curmap->pml_map.pm_prog ;
	if((curmap->pml_map.pm_prog > REMOTERENDER) &&
		(curmap->pml_map.pm_prog < (REMOTERENDER + MAXPROGNUMS))  ) {
		if(curmap->pml_map.pm_prot == IPPROTO_UDP){
			fprintf(stderr,"\r       PrgNo %4d, trying : ",
               			 curmap->pml_map.pm_prog-REMOTERENDER);
		
			if((client=clnt_create(conn->servername,curmap->pml_map.pm_prog,
					REMOTERENDERVERS,"tcp"))){
				SetServerTimeout(&NOTIMEOUT);
				fprintf(stderr,"OK\n");
				conn->clientno=CallbackPrognum;
		        	clnt_call(client, RRINITSERVICE, xdr_RRConnection, conn, xdr_void, NULL, NOTIMEOUT);	
				ServicesOnServer++;
				ServicesInNetwork++;
				clnt_destroy(client);
				return TRUE;
			} else {
				fprintf(stderr,"Service unconnectable");
			}
		}
	}
	goto look;
}




bool_t
SetServerTimeout(timeout)
       struct timeval *timeout;
{
       if(!clnt_control(client,CLSET_TIMEOUT,timeout)){
               fprintf(stderr,"Failed in setting TIMEOUT sec %ld usec %ld",
                       timeout->tv_sec,timeout->tv_usec);
			clnt_destroy(client);
			client=NULL;
               return FALSE;
	} else {
               return TRUE;
	}
}
bool_t
SetServerRetryTimeout(timeout)
       struct timeval *timeout;
{
       if(!clnt_control(client,CLSET_RETRY_TIMEOUT,timeout)){
               fprintf(stderr,"Failed in setting TIMEOUT sec %ld usec %ld",
                       timeout->tv_sec,timeout->tv_usec);
			clnt_destroy(client);
			client=NULL;
               return FALSE;
	} else {
               return TRUE;
	}
}

RRStatus 
TryService(conn,timeout,retrytimeout) 
	RRConnection *conn;
	struct timeval *timeout;
	struct timeval *retrytimeout;
{
	enum clnt_stat status;
	CLIENT *tmpclient;
 
	if(!(client=clnt_create(conn->servername,conn->servno,REMOTERENDERVERS,"udp"))){
				client=NULL;
				return RRSERVICE_UNCONNECTABLE;
				}
 
	if( ! SetServerTimeout(timeout)) 
		return RRSERVICE_UNCONTROLLABLE;
	if( ! SetServerRetryTimeout(retrytimeout)) 
		return RRSERVICE_UNCONTROLLABLE;
        
	status=clnt_call(client,NULLPROC ,xdr_void,NULL,xdr_void,NULL,timeout);

	switch (status) { 
        	case RPC_TIMEDOUT: 
			clnt_destroy(client);
        		return RRSERVICE_TIMEDOUT; 

        	case RPC_SUCCESS: 
			tmpclient=clnt_create(conn->servername,conn->servno,
					REMOTERENDERVERS,"tcp");
			if(!tmpclient){
				clnt_destroy(client);
                                client=NULL;
                                return RRSERVICE_UNCONNECTABLE;
                        } else {
				clnt_destroy(client);
				client=tmpclient;
				return RRSERVICE_SUCCESS;
			}
        		break; 

        	default :
			clnt_destroy(client);
			client=NULL;    
        		return RRSERVICE_BROKENCONNECTION; 
	}
}
TryCallback(conn,timeout,retrytimeout)
        RRConnection *conn;
        struct timeval *timeout;
        struct timeval *retrytimeout;
{
        enum clnt_stat status;
        CLIENT *tmpclient;

        if(!(client=clnt_create(conn->clientname,conn->clientno,REMOTERENDERVERS,"udp"))){
                                client=NULL;
                                return RRSERVICE_UNCONNECTABLE;
                                }

        if( ! SetServerTimeout(timeout))
                return RRSERVICE_UNCONTROLLABLE;
        if( ! SetServerRetryTimeout(retrytimeout))
                return RRSERVICE_UNCONTROLLABLE;

        status=clnt_call(client,NULLPROC ,xdr_void,NULL,xdr_void,NULL,timeout);

        switch (status) {
                case RPC_TIMEDOUT:
                        clnt_destroy(client);
                        return RRSERVICE_TIMEDOUT;

                case RPC_SUCCESS:
                        tmpclient=clnt_create(conn->servername,conn->servno,
                                        REMOTERENDERVERS,"tcp");
                        if(!tmpclient){
                                clnt_destroy(client);
                                client=NULL;
                                return RRSERVICE_UNCONNECTABLE;
                        } else {
                                clnt_destroy(client);
                                client=tmpclient;
                                return RRSERVICE_SUCCESS;
                        }
                        break;

                default :
                        clnt_destroy(client);
                        client=NULL;
                        return RRSERVICE_BROKENCONNECTION;
        }
}




RRStatus
CallRRRequest(request,timeout,retrytimeout)
	RRreq  *request;
	struct timeval *timeout;
	struct timeval *retrytimeout;
{
	int ArgsOk;
	enum clnt_stat status;
	
	ArgsOk=NULL;

	status = TryService (&request->connect,timeout,retrytimeout);

	switch (status ) {

		case RRSERVICE_SUCCESS:
			break;
		default:
			return status;		
		
	}

	SetServerTimeout(&TIMEOUT);

	status=clnt_call(client, RRREQUEST, xdr_RRreq,request,xdr_int, &ArgsOk, TIMEOUT);

	switch (status) { 

		case RPC_TIMEDOUT: 
			clnt_destroy(client);
			client=NULL;
        		return RRSERVICE_TIMEDOUT; 

        	case RPC_SUCCESS: 
			if(ArgsOk){
				clnt_destroy(client);
				client=NULL;
        			return RRSERVICE_SUCCESS; 
			}
			if(clnt_call(client,RRMARSHALL,
					RRProg.RRxdr_fnct,
					RRProg.arg,
					xdr_int, &ArgsOk, *timeout) !=RPC_SUCCESS){
				fprintf(stderr,"no marshall");
				clnt_destroy(client);
                        	client=NULL;
        		        return RRSERVICE_BROKENCONNECTION; 
			}
			if(ArgsOk==FALSE){
				fprintf(stderr,"no marshall");
                                clnt_destroy(client);
                                client=NULL;
				return RRSERVICE_BROKENCONNECTION;
			}
 			clnt_destroy(client);
                        client=NULL;
			return RRSERVICE_ARGSMARSHALLED;

        	default :   
        		return RRSERVICE_BROKENCONNECTION; 
	}
}

void ClientInfo(out)
	FILE *out;
{
	fprintf(out,"CLIENT %s\t Transient No. %d",MyHostname,CallbackPrognum-0x40000000);
}
void ServiceInfo(out)
	FILE *out;
{
	fprintf(out,"SERVICE %s\t RR User No. %d ",MyHostname,ServicePrognum-REMOTERENDER);
}
void ConnectionInfo(conn,out)
	RRConnection *conn;
	FILE *out;
{
	fprintf(out,"CLIENT%9s No.%4d SERVICE%9s No.%4d Mode %d",
		conn->clientname,conn->clientno-0x40000000,conn->servername,conn->servno-REMOTERENDER,conn->transport);
}
void DispatchCallback(rqstp, transp)
       struct svc_req *rqstp;
       register SVCXPRT *transp;
{

       union {
               rpc_square rrsquare_1_arg;
 	       RRConnection rrnewservice_1_arg;

       } argument;
       char *result;
       bool_t (*xdr_argument)(), (*xdr_result)();
       char *(*local)();

       switch (rqstp->rq_proc) {
       case NULLPROC:
               (void) svc_sendreply(transp, xdr_void, (char *)NULL);
               return;

       case RRSQUARE:
                xdr_argument = xdr_rpc_op_square;
                xdr_result = xdr_void;
       		bzero((char *)&argument, sizeof(argument));
       		if (!svc_getargs(transp, xdr_argument, &argument)) {
               		svcerr_decode(transp);
               		return;
       		}
                if (!svc_sendreply(transp, xdr_void,NULL )) {
                       svcerr_systemerr(transp);
                }
                local = (char *(*)()) rrsquare_1;
       		result = (*local)(&argument, rqstp);
	        return;

	case RRNEWSERVICE:
                xdr_argument = xdr_RRConnection;
                xdr_result = xdr_void;
                local = (char *(*)()) rrnewservice_1;
		break;

       default:
               svcerr_noproc(transp);
               return;
       }
       bzero((char *)&argument, sizeof(argument));
       if (!svc_getargs(transp, xdr_argument, &argument)) {
               svcerr_decode(transp);
               return;
       }
       result = (*local)(&argument, rqstp);
       if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
                svcerr_systemerr(transp);
       }
       if (!svc_freeargs(transp, xdr_argument, &argument)) {
               fprintf(stderr, "unable to free arguments");
               exit(1);
       }
       return;
}

void *rrsquare_1(argp,rqstp)
       rpc_square *argp;
       struct svc_req *rqstp;
{
	RRSquare(argp);
	return (void*) TRUE;
}

void *rrinitservice_1(argp,rqstp)
	RRConnection *argp;
	struct svc_req *rqstp;
{
	enum clnt_stat status;
 	RRStatus rrstatus;

	switch (argp->transport) {
		
		case PORTMAPPER_TCPIP_PORTMAPPER_TCPIP:
		case PORTMAPPER_TCPIP_ON_PORTMAPPER_TCPIP:
			argp->servno=ServicePrognum;
			ConnectionInfo(argp,stderr);
			if(strcmp(RRProg.name,argp->progname)){
				fprintf(stderr,"Client is %s\n",RRProg.name);
				return(NULL);
			}
			client=NULL;
		 	while(!client) {
				client=clnt_create(argp->clientname,argp->clientno,
						REMOTERENDERCALLBACKVERS,"tcp");
				if(client) {
					SetServerTimeout(&NOTIMEOUT);
					status=clnt_call(client,RRNEWSERVICE,xdr_RRConnection,
							argp,xdr_void,NULL,TIMEOUT);
					clnt_destroy(client);
					client=NULL;
					return NULL;
				} else {
					 if(!(client=clnt_create(argp->clientname,argp->clientno,
               	                                 REMOTERENDERCALLBACKVERS,"udp")) ){
						 fprintf(stderr,"unconnectable\n");
					 	 client=NULL;
					 	 return NULL;
					} else {
						clnt_destroy(client);
						client=NULL;
					}
				}
			}
			break;
		default:
			ConnectionInfo(argp,stderr);
			fprintf(stderr,"Transport not supported by Service\n",argp->transport);
		}
	return NULL;
}
void *rrnewservice_1(argp,rqstp)
	RRConnection *argp;
	struct svc_req *rqstp;
{
	RRConnList *new;
	if(!(new=(RRConnList*) calloc(1,sizeof(RRConnList))))
                return NULL;
	bcopy(argp, &(new->conn), sizeof(RRConnection));
	new->conn.clientname=(char*)strsave(argp->clientname);
	new->conn.servername=(char*)strsave(argp->servername);
	return RRNewService(new);
}


void
remoterender_1(rqstp, transp)
       struct svc_req *rqstp;
       register SVCXPRT *transp;
{
       union {
               char rrmarshall_1_arg [MAXARGSIZE];
               RRreq rrrequest_1_arg;
               u_long rrfree_1_arg;
       } argument;
       char *result;
       bool_t (*xdr_argument)(), (*xdr_result)();
       char *(*local)();

       switch (rqstp->rq_proc) {
       case NULLPROC:
               (void) svc_sendreply(transp, xdr_void, (char *)NULL);
               return;

       case RRMARSHALL:
               xdr_argument = RRProg.RRxdr_fnct; 
               xdr_result = xdr_int;
               local = (char *(*)()) rrmarshall_1;
               break;

       case RRBLOCKED:
               xdr_argument = xdr_void;
               xdr_result = xdr_int;
               local = (char *(*)()) rrblocked_1;
               break;

       case RRREQUEST: {

		xdr_argument = xdr_RRreq;
                xdr_result = xdr_int;
                local = (char *(*)()) rrrequest_1;
		bzero((char *)&argument, sizeof(argument));
		if (!svc_getargs(transp, xdr_argument, &argument)) {
			svcerr_decode(transp);
			return;
		}
		result=(char*) rrrequest_1(((RRreq*)(&argument)),rqstp);
                if (!svc_sendreply(transp, xdr_result, result)) {
                       fprintf(stderr,"failure in rrequest\n");
                       svcerr_systemerr(transp);
                }
		if((*(int*)result)==TRUE) {
			(void) RenderSquare((RRreq*)(&argument));
		}
                return;
	}

       case RRFREE:
               xdr_argument = xdr_u_long;
               xdr_result = xdr_int;
               local = (char *(*)()) rrfree_1;
               break;

       case RRINFO:
               xdr_argument = xdr_void;
               xdr_result = xdr_wrapstring;
               local = (char *(*)()) rrinfo_1;
               break;
       case RRINITSERVICE:
                xdr_argument = xdr_RRConnection;
                xdr_result = xdr_void;
                local = (char *(*)()) rrinitservice_1;
                break;

       default:
               svcerr_noproc(transp);
               return;
       }
       bzero((char *)&argument, sizeof(argument));
       if (!svc_getargs(transp, xdr_argument, &argument)) {
               svcerr_decode(transp);
               return;
       }
       result = (*local)(&argument, rqstp);
       if(rqstp->rq_proc!=RRMARSHALL){
               if (!svc_freeargs(transp, xdr_argument, &argument)) {
                       fprintf(stderr, "unable to free arguments\n");
                       exit(1);
               }
       }
       if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
              svcerr_systemerr(transp);
       }
       return;
}
int *rrrequest_1(argp,rqstp)
	RRreq *argp;
	struct svc_req *rqstp;
{	
 	return 	RRRequest(argp);
}
int *rrmarshall_1(argp, rqstp)
	RRArg *argp;
	struct svc_req *rqstp;
{
	static int OK;
	OK=RRMarshall(argp);
	if(OK==FALSE)
		fprintf(stderr," No Memory for new argument");	
		
	return &OK;
}
RRStatus RRSendSquare(svc)
	rpc_square *svc;
{
	enum clnt_stat status;
	client=NULL;
	while(!client) {
		client=clnt_create(svc->req.connect.clientname,
			   svc->req.connect.clientno,
			   REMOTERENDERCALLBACKVERS,
			   "tcp");
		if(client) {
			SetServerTimeout(&NOTIMEOUT);
			status=clnt_call(client,RRSQUARE,xdr_rpc_op_square,svc,xdr_void,NULL,&NOTIMEOUT);
			clnt_destroy(client);
			client=NULL;
			switch (status) {
				case RPC_TIMEDOUT:
					return RRSERVICE_TIMEDOUT;
				case RPC_SUCCESS:
					return RRSERVICE_SUCCESS;
				default:
					fprintf(stderr,"ONCRPC fail clnt_stat: %d",status);
					return RRSERVICE_BROKENCONNECTION;
			}
			
		} else {
			if(!(client=clnt_create(svc->req.connect.clientname,
                           		svc->req.connect.clientno,
                           		REMOTERENDERCALLBACKVERS,
                           		"udp"))) {
				client=NULL;
				return RRSERVICE_UNCONNECTABLE;
			} else {
				clnt_destroy(client);
				client=NULL;
			}
		}
	}
}


#endif /** ONCRPC **/

