# -+- number -+- category -+- title -+- email -+- name -+- homepage -+- clickOnName -+- language -+- image -+- browser-used -+- security-cookie =0 -+- 2004-05-16:5 -+- Software Development -+- Implementation of a multithreaded RPC Server for Linux -+- derzhavets@hotmail.com -+- Boris A. Derzhavets -+- -+- email -+- English -+- -+- Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) -+- 2223

   Consider as an example (see. [1] chapter "Sun RPC")  
square_svc.c  for file square.x  to build multithreaded 
RPC Server for Linux. 

File square.x as in [1] Chapter "Sun RPC" follows bellow :

struct square_in {
 long arg1;
};
struct square_out {
 long res1;
};
program SQUARE_PROG {
  version SQUARE_VERS {
  square_out SQUAREPROC(square_in) = 1;
  } = 2 ;
} = 0x31230000;


Call rpcgen to generate server's , client's stubs,header file square.h
and square_xdr.c (remind key -A is not supported under Linux):

$ rpcgen -a -M square.x

Server's side procedures code:

/*
 *                                           ServerSideProc.c
*/
#include "square.h"
#include "stdio.h"
#include "stdlib.h"
#include "rpc/pmap_clnt.h"
#include "string.h"
#include "memory.h"
#include "sys/socket.h"
#include "netinet/in.h"

int request=0;

bool_t

squareproc_2_svc(square_in *inp,square_out *outp,struct svc_req *rqstp)
{
printf("Thread id = '%ld' started, arg = %d\n",pthread_self(),inp->arg1);
sleep(5);
outp->res1=inp->arg1*inp->arg1;
printf("Thread id = '%ld' is done %d \n",pthread_self(),outp->res1);
return(TRUE);
}
int 
square_prog_2_freeresult(SVCXPRT *transp,xdrproc_t xdr_result,
 caddr_t result)
{
xdr_free(xdr_result,result);
return(1);
}


Modified code square_svc.c:

/*                                                          square_svc.c
 * Please do not edit this file.
 * It was generated using rpcgen.
 */

#include "square.h"
#include "stdio.h"
#include "stdlib.h"
#include "rpc/pmap_clnt.h"
#include "string.h"
#include "memory.h"
#include "sys/socket.h"
#include "netinet/in.h"

#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif

pthread_t p_thread;
pthread_attr_t attr;

                                
/* Procedure to be run by thread */

void *
serv_request(void *data)
{
struct thr_data
{
struct svc_req *rqstp;
SVCXPRT *transp;
} *ptr_data;

{

   union {
                square_in squareproc_2_arg;
   } argument;
   union {
                square_out squareproc_2_res;
   } result;
   bool_t retval;
   xdrproc_t _xdr_argument, _xdr_result;
   bool_t (*local)(char *, void *, struct svc_req *);

/*
Unpack data from structure
*/

ptr_data = (struct thr_data  *)data;
struct svc_req *rqstp = ptr_data->rqstp;
register SVCXPRT *transp = ptr_data->transp;

                                                                                                   
        switch (rqstp-"rq_proc) {
        case NULLPROC:
                (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
                return;
                                                                                                   
        case SQUAREPROC:
                _xdr_argument = (xdrproc_t) xdr_square_in;
                _xdr_result = (xdrproc_t) xdr_square_out;
                local = (bool_t (*) (char *, void *,  struct svc_req *))squareproc_2_svc;
                break;
                                                                                                   
        default:
                svcerr_noproc (transp);
                return;
        }
        memset ((char *)&argument, 0, sizeof (argument));
        if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
                svcerr_decode (transp);
                return;
        }
      
/*
 Data are already prepared.
*/
        retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp);

 if (retval " 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result))      
   {
                svcerr_systemerr (transp);
       }
        if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
                fprintf (stderr, "%s", "unable to free arguments");
                exit (1);
        }
        if (!square_prog_2_freeresult (transp, _xdr_result, (caddr_t) &result))
                fprintf (stderr, "%s", "unable to free results");
        return;
}
}
                                
/* 

New code for square_prog_2

*/

static void
square_prog_2(struct svc_req *rqstp, register SVCXPRT *transp)
{
struct data_str 
{
struct svc_req *rqstp;
SVCXPRT *transp;
} *data_ptr=(struct data_str*)malloc(sizeof(struct data_str));

{

/*
Paking data into structure in order to pass pointer to structure
to pthread_create( ). Starting  thread as detached
*/

data_ptr->rqstp = rqstp;
data_ptr->transp = transp;
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); 
pthread_create(&p_thread,&attr,serv_request,(void *)data_ptr);
 }
}

int
main (int argc, char **argv)
{
	register SVCXPRT *transp;

	pmap_unset (SQUARE_PROG, SQUARE_VERS);

	transp = svcudp_create(RPC_ANYSOCK);
	if (transp == NULL) {
		fprintf (stderr, "%s", "cannot create udp service.");
		exit(1);
	}
	if (!svc_register(transp, SQUARE_PROG, SQUARE_VERS, square_prog_2, IPPROTO_UDP)) {
		fprintf (stderr, "%s", "unable to register (SQUARE_PROG, SQUARE_VERS, udp).");
		exit(1);
	}

	transp = svctcp_create(RPC_ANYSOCK, 0, 0);
	if (transp == NULL) {
		fprintf (stderr, "%s", "cannot create tcp service.");
		exit(1);
	}
	if (!svc_register(transp, SQUARE_PROG, SQUARE_VERS, square_prog_2, IPPROTO_TCP)) {
		fprintf (stderr, "%s", "unable to register (SQUARE_PROG, SQUARE_VERS, tcp).");
		exit(1);
	}

	svc_run ();
	fprintf (stderr, "%s", "svc_run returned");
	exit (1);
	/* NOTREACHED */
}

Compile  ServerSQUARE:

$ gcc -o ServerSQUARE  ServerSideProc.c  square_svc.c square_xdr.c \
-lprthread    -lnsl






Client's side code:

/*          
*                                  ClientSideProc.c
*/

#include "memory.h" /* for memset */
#include "square.h"
#include "stdio.h"
#include "stdlib.h"
#include "rpc/pmap_clnt.h"
#include "string.h"
#include "memory.h"
#include "sys/socket.h"
#include "netinet/in.h"

int 
main (int argc,char **argv)
{
CLIENT *cl;
square_in in;
square_out out;
if (argc != 3 )
{ printf ("Usage : client "hostname" "integer_valus=e"\n");
  exit(1);
}
cl = clnt_create(argv[1],SQUARE_PROG,SQUARE_VERS,"tcp");
 if (cl == NULL) {
                clnt_perror (cl, "call failed");
                exit (1);
        }
in.arg1 = atol(argv[2]);
if (squareproc_2(&in,&out,cl) != RPC_SUCCESS)
{
   printf ("%s\n" , clnt_perror (cl,argv[1] ));
   exit(1);
}
printf("result: %ld\n",out.res1);
exit(0);
}





Compile  ClientSQUARE:

$ gcc -o  ClientSQUARE  ClientSideProc.c  square_clnt.c  square_xdr.c \
   -lprthread     -lnsl

Testing  (see [1]  ,chapter "SUN RPC"):

[root@dell4500 SQWMT]# cat square.bsh

./ClientSQUARE dell4500.redhat 10 & ./ClientSQUARE dell4500.redhat 11 & \
./ClientSQUARE dell4500.redhat 12 & ./ClientSQUARE dell4500.redhat 21 & \
./ClientSQUARE dell4500.redhat 13 & ./ClientSQUARE dell4500.redhat 14 & \
./ClientSQUARE dell4500.redhat 15 & ./ClientSQUARE dell4500.redhat 16 & \
./ClientSQUARE dell4500.redhat 17 & ./ClientSQUARE dell4500.redhat 18 & \
./ClientSQUARE dell4500.redhat 19 & ./ClientSQUARE dell4500.redhat 20 &


Output on client's side:

[root@dell4500 SQWMT]# ./square.bsh
[root@dell4500 SQWMT]# result: 196
result: 225
result: 256
result: 289
result: 121
result: 144
result: 441
result: 169
result: 100
result: 324
result: 361
result: 400

Output on Server's side:

[root@dell4501 SQWMT]# ./ServerSQUARE

Thread id = '1082453184' started, arg = 14
Thread id = '1090841664' started, arg = 15
Thread id = '1099230144' started, arg = 16
Thread id = '1116941120' started, arg = 17
Thread id = '1125329600' started, arg = 11
Thread id = '1133718080' started, arg = 12
Thread id = '1142106560' started, arg = 21
Thread id = '1150495040' started, arg = 13
Thread id = '1158883520' started, arg = 10
Thread id = '1167272000' started, arg = 18
Thread id = '1175660480' started, arg = 19
Thread id = '1184048960' started, arg = 20
Thread id = '1082453184' is done 196
Thread id = '1090841664' is done 225
Thread id = '1099230144' is done 256
Thread id = '1116941120' is done 289
Thread id = '1125329600' is done 121
Thread id = '1133718080' is done 144
Thread id = '1142106560' is done 441
Thread id = '1150495040' is done 169
Thread id = '1158883520' is done 100
Thread id = '1167272000' is done 324
Thread id = '1175660480' is done 361
Thread id = '1184048960' is done 400

                             References:
 
1.W.Richard Stevens.UNIX: Network Programming v 2.Interprocess communications. 
  Prentice Hall,1999