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