split tunable constant into Boolean and Float sub-classes.
[dyninst.git] / common / src / rpcUtil.C
1 /*
2  * $Log: rpcUtil.C,v $
3  * Revision 1.27  1994/07/28 22:22:04  krisna
4  * changed definitions of ReadFunc and WriteFunc to conform to prototypes
5  *
6  * Revision 1.26  1994/07/19  18:30:27  markc
7  * Made machineName default to zero as last parameter to RPC_make_arg_list.
8  * Added typecast to malloc call in RPC_make_arg_list.
9  *
10  * Added typecast to malloc call in RPC_make_arg_list.
11  *
12  * Revision 1.25  1994/07/18  19:08:25  hollings
13  * added extra arg to RPC_make_arg_list.
14  *
15  * Revision 1.24  1994/06/22  00:37:13  markc
16  * Fixed code to remove warnings.
17  *
18  * Revision 1.23  1994/06/02  23:36:58  markc
19  * Added support for igen error checking.
20  *
21  * Revision 1.22  1994/05/17  00:14:45  hollings
22  * added rcs log entry.
23  *
24  * Revision 1.21  1994/05/16  04:27:47  hollings
25  * Added inlcude of vfork.h on SUNS to prevent problem with optimizer.
26  *
27  * Revision 1.20  1994/05/12  18:47:51  jcargill
28  * Changed make args function to leave room for program name in arg_list[0],
29  * and added code to RPCprocessCreate to poke it in there before execv'ing.
30  *
31  * Revision 1.19  1994/04/21  23:23:49  hollings
32  * removed paradynd name from make args function.
33  *
34  * Revision 1.18  1994/04/06  22:46:12  markc
35  * Fixed bug in XDRrpc constructor that clobbered the fd value.  Added feature
36  * to RPC_readReady to do blocking select.
37  *
38  * Revision 1.17  1994/04/01  20:05:27  hollings
39  * Removed kill of rsh process (not needed and it causes a race condition).
40  *
41  * Revision 1.16  1994/04/01  04:59:13  markc
42  * Put in support to encode NULL ptrs to strings in xdr_String.
43  *
44  * Revision 1.15  1994/03/31  22:59:08  hollings
45  * added well known port as a paramter to xdrRPC constructor.
46  *
47  * Revision 1.14  1994/03/31  22:45:04  markc
48  * Added Log for rcs.
49  *
50 */
51
52 //
53 // This file defines a set of utility routines for RPC services.
54 //
55 //
56
57 // overcome malloc redefinition due to /usr/include/rpc/types.h declaring 
58 // malloc 
59
60 #include <signal.h>
61 #include <sys/wait.h>
62
63 /* prevents malloc from being redefined */
64 #ifdef MIPS
65 #define MALLOC_DEFINED_AS_VOID
66 #endif
67
68 #include "util/h/rpcUtil.h"
69
70 #include <stdio.h>
71 #include <string.h>
72 #include <stdlib.h>
73 #include <errno.h>
74 #include <assert.h>
75 #include <fcntl.h>
76 #include <memory.h>
77 #include <netinet/in.h>
78 #include <netdb.h>
79 #include <sys/types.h>
80 #include <sys/time.h>
81 #include <unistd.h>
82 #include <sys/file.h>
83
84 extern "C" {
85 #include <rpc/types.h>
86 #include <rpc/xdr.h>
87 }
88
89 // functions that g++-fixincludes missed
90 #ifdef MIPS
91 extern "C" {
92 void bzero (char*, int);
93 int select (int, fd_set*, fd_set*, fd_set*, struct timeval*);
94 char *strdup (char*);
95 int gethostname(char*, int);
96 int socket(int, int, int);
97 int bind(int s, struct sockaddr *, int);
98 int getsockname(int, struct sockaddr*, int *);
99 int listen(int, int);
100 int connect(int s, struct sockaddr*, int);
101 int socketpair(int, int, int, int sv[2]);
102 int vfork();
103 int accept(int, struct sockaddr *addr, int *); 
104 }
105 #elif SPARC
106 #include <sys/socket.h>
107 #include <vfork.h>
108 extern "C" {
109 void bzero (char*, int);
110 int select (int, fd_set*, fd_set*, fd_set*, struct timeval*);
111 int socket(int, int, int);
112 int gethostname(char*, int);
113 int bind(int s, struct sockaddr *, int);
114 int getsockname(int, struct sockaddr*, int *);
115 int listen(int, int);
116 int connect(int s, struct sockaddr*, int);
117 int socketpair(int, int, int, int sv[2]);
118 int accept(int, struct sockaddr *addr, int *); 
119 }
120 #endif
121
122
123 #define RSH_COMMAND     "rsh"
124
125 int RPCdefaultXDRRead(const void* handle, char *buf, u_int len)
126 {
127     int fd = (int) handle;
128     int ret;
129
130     do {
131         ret = read(fd, buf, len);
132     } while (ret < 0 && errno == EINTR);
133
134     if (ret <= 0) return(-1);
135     return (ret);
136 }
137
138 int RPCdefaultXDRWrite(const void* handle, char *buf, u_int len)
139 {
140     int fd = (int) handle;
141     int ret;
142
143     do {
144         ret = write(fd, buf, len);
145     } while (ret < 0 && errno == EINTR);
146
147     if (ret != len) 
148         return(-1);
149     else
150         return (ret);
151 }
152
153 XDRrpc::~XDRrpc()
154 {
155   if (fd >= 0)
156     {
157       fcntl (fd, F_SETFL, FNDELAY);
158       close(fd);
159     }
160   if (__xdrs__) 
161     {
162       xdr_destroy (__xdrs__);
163       delete (__xdrs__);
164     }
165 }
166
167 //
168 // prepare for RPC's to be done/received on the passed fd.
169 //
170 XDRrpc::XDRrpc(int f, xdrIOFunc readRoutine, xdrIOFunc writeRoutine, int nblock)
171 {
172     fd = f;
173     __xdrs__ = new XDR;
174     if (!readRoutine) readRoutine = (xdrIOFunc) RPCdefaultXDRRead;
175     if (!writeRoutine) writeRoutine = (xdrIOFunc) RPCdefaultXDRWrite;
176     (void) xdrrec_create(__xdrs__, 0, 0, (char *) fd, readRoutine,writeRoutine);
177     if (nblock)
178       fcntl (fd, F_SETFL, FNDELAY);
179 }
180
181 //
182 // prepare for RPC's to be done/received on the passed fd.
183 //
184 XDRrpc::XDRrpc(char *machine,
185                char *user,
186                char *program,
187                xdrIOFunc readRoutine, 
188                xdrIOFunc writeRoutine,
189                char **arg_list,
190                int nblock,
191                int wellKnownPortFd)
192 {
193     fd = RPCprocessCreate(&pid, machine, user, program, arg_list, 
194         wellKnownPortFd);
195     if (fd >= 0) {
196         __xdrs__ = new XDR;
197         if (!readRoutine) readRoutine = (xdrIOFunc) RPCdefaultXDRRead;
198         if (!writeRoutine) writeRoutine = (xdrIOFunc) RPCdefaultXDRWrite;
199         (void) xdrrec_create(__xdrs__, 0, 0, (char *) fd, 
200                 readRoutine, writeRoutine);
201         if (nblock)
202           fcntl (fd, F_SETFL, FNDELAY);
203     } else {
204         __xdrs__ = NULL;
205         fd = -1;
206     }
207 }
208
209 int
210 RPC_readReady (int fd, int timeout)
211 {
212   fd_set readfds;
213   struct timeval tvptr, *the_tv;
214
215   tvptr.tv_sec = timeout; tvptr.tv_usec = 0;
216   if (fd < 0) return -1;
217   FD_ZERO(&readfds);
218   FD_SET (fd, &readfds);
219
220   // -1 timeout = blocking select
221   if (timeout == -1)
222      the_tv = 0;
223   else
224      the_tv = &tvptr;
225  
226   if (select (fd+1, &readfds, NULL, NULL, the_tv) == -1)
227     {
228       // if (errno == EBADF)
229         return -1;
230     }
231   return (FD_ISSET (fd, &readfds));
232 }
233
234 int 
235 RPC_undo_arg_list (int argc, char **arg_list, char **machine, int &family,
236                    int &type, int &well_known_socket, int &flag)
237 {
238   int loop;
239   char *ptr;
240   int sum = 0;
241
242   for (loop=0; loop < argc; ++loop)
243     {
244       if (!strncmp(arg_list[loop], "-p", 2))
245         {
246           well_known_socket = (int) strtol (arg_list[loop] + 2, &ptr, 10);
247           if (ptr == (arg_list[loop] + 2))
248             return(-1);
249           sum |= 1;
250         }
251       else if (!strncmp(arg_list[loop], "-f", 2))
252         {
253           family = (int) strtol (arg_list[loop] + 2, &ptr, 10);
254           if (ptr == (arg_list[loop] + 2))
255             return(-1);
256           sum |= 2;
257         }
258       else if (!strncmp(arg_list[loop], "-t", 2))
259         {
260           type = (int) strtol (arg_list[loop] + 2, &ptr, 10);
261           if (ptr == (arg_list[loop] + 2))
262             return(-1);
263           sum |= 4;
264         }
265       else if (!strncmp(arg_list[loop], "-m", 2))
266         {
267           *machine = strdup (arg_list[loop] + 2);
268           if (!(*machine)) return -1;
269           sum |= 8;
270         }
271       else if (!strncmp(arg_list[loop], "-l", 2))
272         {
273           flag = (int) strtol (arg_list[loop] + 2, &ptr, 10);
274           if (ptr == (arg_list[loop] + 2))
275             return(-1);
276           sum |= 16;
277         }
278     }
279   if (sum == (16 + 8 + 4 + 2 + 1))
280         return 0;
281   else
282         return -1;
283 }
284
285 char **RPC_make_arg_list(int family, int type, int well_known_socket,
286                    int flag, char *machine_name)
287 {
288   char arg_str[100];
289   int arg_count = 1;
290   char **arg_list;
291
292   arg_list = new char*[8];
293   arg_list[0] = NULL;
294   sprintf(arg_str, "%s%d", "-p", well_known_socket);
295   arg_list[arg_count++] = strdup (arg_str);
296   sprintf(arg_str, "%s%d", "-f", family);
297   arg_list[arg_count++] = strdup (arg_str);
298   sprintf(arg_str, "%s%d", "-t", type);
299   arg_list[arg_count++] = strdup (arg_str);
300   if (!machine_name) {
301       machine_name = (char *) malloc(50);
302       gethostname (machine_name, 49);
303   }
304   sprintf(arg_str, "%s%s", "-m", machine_name);
305   arg_list[arg_count++] = strdup (arg_str);
306   sprintf(arg_str, "%s%d", "-l", flag);
307   arg_list[arg_count++] = strdup (arg_str);
308   arg_list[arg_count++] = 0;
309   return arg_list;
310 }
311
312 // returns fd of socket that is listened on, or -1
313 int
314 RPC_setup_socket (int *sfd,   // return file descriptor
315                   int family, // AF_INET ...
316                   int type)   // SOCK_STREAM ...
317 {
318   struct sockaddr_in serv_addr;
319   int length;
320   char machine[50];
321
322   if (gethostname(machine, 49) != 0)
323     return -1;
324
325   if ((*sfd = socket(family, type, 0)) < 0)
326     return -1;
327
328   memset ((char*) &serv_addr, 0, sizeof(serv_addr));
329   /* bzero ((char *) &serv_addr, sizeof(servaddr)); */
330   serv_addr.sin_family = (short) family;
331   serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
332   serv_addr.sin_port = htons(0);
333   
334   length = sizeof(serv_addr);
335
336   if (bind(*sfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
337     return -1;
338
339   if (getsockname (*sfd, (struct sockaddr *) &serv_addr, &length) < 0)
340     return -1;
341
342   if (listen(*sfd, 5) < 0)
343     return -1;
344
345   return (ntohs (serv_addr.sin_port));
346 }
347
348 //
349 // connect to well known socket
350 //
351 XDRrpc::XDRrpc(int family,            
352                int req_port,             
353                int type,
354                char *machine, 
355                xdrIOFunc readRoutine,
356                xdrIOFunc writeRoutine,
357                int nblock)
358      // socket, connect using machine
359 {
360   struct sockaddr_in serv_addr;
361   struct hostent *hostptr = 0;
362   struct in_addr *inadr = 0;
363
364   __xdrs__ = 0;
365
366   if ( (hostptr = gethostbyname(machine)) == 0)
367     { fd = -1; return; }
368
369   inadr = (struct in_addr *) hostptr->h_addr_list[0];
370   memset ((char*) &serv_addr, 0, sizeof(serv_addr));
371   /* bzero ((char *) &serv_addr, sizeof(serv_addr)); */
372   serv_addr.sin_family = family;
373   serv_addr.sin_addr = *inadr;
374   serv_addr.sin_port = htons(req_port);
375
376   if ( (fd = socket(family, type, 0)) < 0)
377     { fd = -1; return; }
378
379   if (connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
380     { fd = -1; return; }
381
382     __xdrs__ = new XDR;
383     if (!readRoutine) readRoutine = (xdrIOFunc) RPCdefaultXDRRead;
384     if (!writeRoutine) writeRoutine = (xdrIOFunc) RPCdefaultXDRWrite;
385     (void) xdrrec_create(__xdrs__, 0, 0, (char *) fd, readRoutine,writeRoutine);
386     if (nblock)
387       fcntl (fd, F_SETFL, FNDELAY);
388
389 }
390
391 //
392 // prepare for RPC's to be done/received on the passed thread id.
393 //
394 THREADrpc::THREADrpc(int thread)
395 {
396     tid = thread;
397 }
398
399 //
400 // This should never be called, it should be replaced by a virtual function
401 //    from the derived class created by igen.
402 //
403 void RPCUser::verifyProtocolAndVersion()
404 {
405     abort();
406 }
407
408 //
409 // our version of string encoding that does malloc as needed.
410 //
411 bool_t xdr_String(XDR *xdrs, String *str)
412 {
413     int len;
414     unsigned char isNull=0;
415
416         // if XDR_FREE, str's memory is freed
417     switch (xdrs->x_op) {
418         case XDR_ENCODE:
419                 if (*str) {
420                     len = strlen(*str)+1;
421                     if (!xdr_u_char(xdrs, &isNull))
422                         return FALSE;
423                 } else {
424                     isNull = (unsigned char) 1;
425                     if (!xdr_u_char(xdrs, &isNull))
426                         return FALSE;
427                     else
428                         return TRUE;
429                 }
430                 return (xdr_string (xdrs, str, 65536));
431         case XDR_DECODE:
432                 *str = NULL;
433                 if (!xdr_u_char(xdrs, &isNull))
434                     return FALSE;
435                 if (isNull)
436                     return TRUE;
437                 else
438                     return (xdr_string (xdrs, str, 65536));
439         case XDR_FREE:
440                 // xdr_free (xdr_string, str);
441                 if (*str)
442                   free (*str);
443                 *str = NULL;
444                 return (TRUE);
445                 // return(TRUE);
446                 // free the memory
447         default:
448                 return (FALSE);
449                 // this should never occur      
450     }
451 }
452
453 int RPCprocessCreate(int *pid, char *hostName, char *userName,
454                      char *command, char **arg_list, int portFd)
455 {
456     int ret;
457     int sv[2];
458     int execlERROR;
459     char local[50];
460
461     if (gethostname(local, 49))
462         strcpy (local, " ");
463
464     if (!hostName || 
465         !strcmp(hostName, "") || 
466         !strcmp(hostName, "localhost") ||
467         !strcmp(hostName, local)) {
468         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
469         if (ret) return(ret);
470         execlERROR = 0;
471         *pid = vfork();
472         if (*pid == 0) {
473             close(sv[0]);
474             dup2(sv[1], 0);
475             if (!arg_list)
476               execl(command, command);
477             else {
478                 arg_list[0] = command;
479                 execv(command, arg_list);
480             }
481             execlERROR = errno;
482             _exit(-1);
483         } else if (*pid > 0 && !execlERROR) {
484             close(sv[1]);
485             return(sv[0]);
486         } else {
487             return(-1);
488         }
489     } else {
490         int total;
491         int fd[2];
492         int retFd;
493         char *ret;
494         FILE *pfp;
495         char **curr;
496         int shellPid;
497         char line[256];
498         char *paradyndCommand;
499
500         total = strlen(command) + 2;
501         for (curr = arg_list+1; *curr; curr++) {
502             total += strlen(*curr) + 2;
503         }
504         paradyndCommand = (char *) malloc(total+2);
505
506         sprintf(paradyndCommand, "%s ", command);
507         for (curr = arg_list+1; *curr; curr++) {
508             strcat(paradyndCommand, *curr);
509             strcat(paradyndCommand, " ");
510         }
511
512         // need to rsh to machine and setup io path.
513
514         if (pipe(fd)) {
515             perror("pipe");
516             return (-1);
517         }
518
519         shellPid = vfork();
520         if (shellPid == 0) {
521             /* child */
522             dup2(fd[1], 1);                         /* copy it onto stdout */
523             close(fd[0]);
524             close(fd[1]);
525             if (userName) {
526                 execlp(RSH_COMMAND, RSH_COMMAND, hostName, "-l", 
527                     userName, "-n", paradyndCommand, "-l0", NULL);
528             } else {
529                 execlp(RSH_COMMAND, RSH_COMMAND, hostName, "-n", 
530                     paradyndCommand, "-l0", NULL);
531             }
532             _exit(-1);
533         } else if (shellPid > 0) {
534             close(fd[1]);
535         } else {
536             // error situation
537         }
538
539         pfp = fdopen(fd[0], "r");
540         do {
541             ret = fgets(line, sizeof(line)-1, pfp);
542             if (ret && !strncmp(line, "PARADYND", strlen("PARADYND"))) {
543                 // got the good stuff
544                 sscanf(line, "PARADYND %d", pid);
545
546                 retFd = RPC_getConnect(portFd);
547                 return(retFd);
548             } else if (ret) {
549                 // some sort of error message from rsh.
550                 printf("%s", line);
551                 return (-1);
552             }
553         }  while (ret);
554
555         return(-1);
556       }
557     return (-1);
558 }
559
560 //
561 // wait for an expected RPC responce, but also handle upcalls while waiting.
562 //    Should not be called directly !!!
563 //
564 void RPCUser::awaitResponce(int tag)
565 {
566     abort();
567 }
568
569 void
570 XDRrpc::setNonBlock()
571 {
572   if (fd >= 0)
573     fcntl (fd, F_SETFL, FNDELAY);
574 }
575
576 int
577 XDRrpc::readReady(int timeout)
578 {
579   return RPC_readReady (fd, timeout);
580 }
581
582 int
583 RPC_getConnect(int fd)
584 {
585   int clilen;
586   struct in_addr cli_addr;
587   int new_fd;
588
589   if (fd == -1)
590     return -1;
591
592   clilen = sizeof(cli_addr);
593
594   if ((new_fd = accept (fd, (struct sockaddr *) &cli_addr, &clilen)) < 0)
595     return -1;
596   else
597     return new_fd;
598 }
599
600 RPCUser::RPCUser(int st)
601 {
602   err_state = st;
603 }
604
605 RPCServer::RPCServer(int st)
606 {
607   err_state = st;
608 }