added well known port as a paramter to xdrRPC constructor.
[dyninst.git] / pdutil / src / rpcUtil.C
1 /*
2 $Log: rpcUtil.C,v $
3 Revision 1.15  1994/03/31 22:59:08  hollings
4 added well known port as a paramter to xdrRPC constructor.
5
6  * Revision 1.14  1994/03/31  22:45:04  markc
7  * Added Log for rcs.
8  *
9 */
10
11 //
12 // This file defines a set of utility routines for RPC services.
13 //
14 //
15
16 // overcome malloc redefinition due to /usr/include/rpc/types.h declaring 
17 // malloc 
18
19 #include <signal.h>
20 #include <sys/wait.h>
21 #include "util/h/rpcUtil.h"
22
23 #define RSH_COMMAND     "rsh"
24
25 int RPCdefaultXDRRead(int handle, char *buf, u_int len)
26 {
27     int ret;
28
29     do {
30         ret = read(handle, buf, len);
31     } while (ret < 0 && errno == EINTR);
32
33     if (ret <= 0) return(-1);
34     return (ret);
35 }
36
37 int RPCdefaultXDRWrite(int handle, char *buf, u_int len)
38 {
39     int ret;
40
41     do {
42         ret = write(handle, buf, len);
43     } while (ret < 0 && errno == EINTR);
44
45     if (ret != len) 
46         return(-1);
47     else
48         return (ret);
49 }
50
51 XDRrpc::~XDRrpc()
52 {
53   if (fd >= 0)
54     {
55       fcntl (fd, F_SETFL, FNDELAY);
56       close(fd);
57     }
58   if (__xdrs__) 
59     {
60       xdr_destroy (__xdrs__);
61       delete (__xdrs__);
62     }
63 }
64
65 //
66 // prepare for RPC's to be done/received on the passed fd.
67 //
68 XDRrpc::XDRrpc(int f, xdrIOFunc readRoutine, xdrIOFunc writeRoutine, int nblock)
69 {
70     fd = f;
71     __xdrs__ = new XDR;
72     if (!readRoutine) readRoutine = RPCdefaultXDRRead;
73     if (!writeRoutine) writeRoutine = RPCdefaultXDRWrite;
74     (void) xdrrec_create(__xdrs__, 0, 0, (char *) fd, readRoutine,writeRoutine);
75     if (nblock)
76       fcntl (fd, F_SETFL, FNDELAY);
77 }
78
79 //
80 // prepare for RPC's to be done/received on the passed fd.
81 //
82 XDRrpc::XDRrpc(char *machine,
83                char *user,
84                char *program,
85                xdrIOFunc readRoutine, 
86                xdrIOFunc writeRoutine,
87                char **arg_list,
88                int nblock,
89                int wellKnownPortFd)
90 {
91     fd = RPCprocessCreate(&pid, machine, user, program, arg_list, 
92         wellKnownPortFd);
93     if (fd >= 0) {
94         __xdrs__ = new XDR;
95         if (!readRoutine) readRoutine = RPCdefaultXDRRead;
96         if (!writeRoutine) writeRoutine = RPCdefaultXDRWrite;
97         (void) xdrrec_create(__xdrs__, 0, 0, (char *) fd, 
98                 readRoutine, writeRoutine);
99         if (nblock)
100           fcntl (fd, F_SETFL, FNDELAY);
101     } else {
102         __xdrs__ = NULL;
103         fd = -1;
104     }
105 }
106
107 int
108 RPC_readReady (int fd, int timeout)
109 {
110   fd_set readfds;
111   struct timeval tvptr;
112
113   tvptr.tv_sec = timeout; tvptr.tv_usec = 0;
114   if (fd < 0) return -1;
115   FD_ZERO(&readfds);
116   FD_SET (fd, &readfds);
117   if (select (fd+1, &readfds, NULL, NULL, &tvptr) == -1)
118     {
119       // if (errno == EBADF)
120         return -1;
121     }
122   return (FD_ISSET (fd, &readfds));
123 }
124
125 int 
126 RPC_undo_arg_list (int argc, char **arg_list, char **machine, int &family,
127                    int &type, int &well_known_socket, int &flag)
128 {
129   int loop;
130   char *ptr;
131   int sum = 0;
132
133   for (loop=0; loop < argc; ++loop)
134     {
135       if (!strncmp(arg_list[loop], "-p", 2))
136         {
137           well_known_socket = (int) strtol (arg_list[loop] + 2, &ptr, 10);
138           if (!ptr)
139             return(-1);
140           sum |= 1;
141         }
142       else if (!strncmp(arg_list[loop], "-f", 2))
143         {
144           family = (int) strtol (arg_list[loop] + 2, &ptr, 10);
145           if (!ptr)
146             return(-1);
147           sum |= 2;
148         }
149       else if (!strncmp(arg_list[loop], "-t", 2))
150         {
151           type = (int) strtol (arg_list[loop] + 2, &ptr, 10);
152           if (!ptr)
153             return(-1);
154           sum |= 4;
155         }
156       else if (!strncmp(arg_list[loop], "-m", 2))
157         {
158           *machine = strdup (arg_list[loop] + 2);
159           if (!(*machine)) return -1;
160           sum |= 8;
161         }
162       else if (!strncmp(arg_list[loop], "-l", 2))
163         {
164           flag = (int) strtol (arg_list[loop] + 2, &ptr, 10);
165           if (!ptr)
166             return(-1);
167           sum |= 16;
168         }
169     }
170   if (sum == (16 + 8 + 4 + 2 + 1))
171         return 0;
172   else
173         return -1;
174 }
175
176 char **
177 RPC_make_arg_list (char *program, int family, int type, int well_known_socket,
178                    int flag)
179 {
180   char arg_str[100];
181   int arg_count = 0;
182   char **arg_list;
183   char machine_name[50];
184
185   arg_list = new char*[7];
186   arg_list[arg_count++] = strdup (program);
187   sprintf(arg_str, "%s%d", "-p", well_known_socket);
188   arg_list[arg_count++] = strdup (arg_str);
189   sprintf(arg_str, "%s%d", "-f", family);
190   arg_list[arg_count++] = strdup (arg_str);
191   sprintf(arg_str, "%s%d", "-t", type);
192   arg_list[arg_count++] = strdup (arg_str);
193   gethostname (machine_name, 49);
194   sprintf(arg_str, "%s%s", "-m", machine_name);
195   arg_list[arg_count++] = strdup (arg_str);
196   sprintf(arg_str, "%s%d", "-l", flag);
197   arg_list[arg_count++] = strdup (arg_str);
198   arg_list[arg_count++] = 0;
199   return arg_list;
200 }
201
202 // returns fd of socket that is listened on, or -1
203 int
204 RPC_setup_socket (int *sfd,   // return file descriptor
205                   int family, // AF_INET ...
206                   int type)   // SOCK_STREAM ...
207 {
208   struct sockaddr_in serv_addr;
209   int length;
210   char machine[50];
211
212   if (gethostname(machine, 49) != 0)
213     return -1;
214
215   if ((*sfd = socket(family, type, 0)) < 0)
216     return -1;
217   
218   bzero ((char *) &serv_addr, sizeof(serv_addr));
219   serv_addr.sin_family = (short) family;
220   serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
221   serv_addr.sin_port = htons(0);
222   
223   length = sizeof(serv_addr);
224
225   if (bind(*sfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
226     return -1;
227
228   if (getsockname (*sfd, (struct sockaddr *) &serv_addr, &length) < 0)
229     return -1;
230
231   if (listen(*sfd, 5) < 0)
232     return -1;
233
234   return (ntohs (serv_addr.sin_port));
235 }
236
237 //
238 // connect to well known socket
239 //
240 XDRrpc::XDRrpc(int family,            
241                int req_port,             
242                int type,
243                char *machine, 
244                xdrIOFunc readRoutine,
245                xdrIOFunc writeRoutine,
246                int nblock)
247      // socket, connect using machine
248 {
249   int fd = 0;
250
251   struct sockaddr_in serv_addr;
252   struct hostent *hostptr = 0;
253   struct in_addr *inadr = 0;
254
255   __xdrs__ = 0;
256
257   if ( (hostptr = gethostbyname(machine)) == 0)
258     { fd = -1; return; }
259
260   inadr = (struct in_addr *) hostptr->h_addr_list[0];
261   bzero ((char *) &serv_addr, sizeof(serv_addr));
262   serv_addr.sin_family = family;
263   serv_addr.sin_addr = *inadr;
264   serv_addr.sin_port = htons(req_port);
265
266   if ( (fd = socket(family, type, 0)) < 0)
267     { fd = -1; return; }
268
269   if (connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
270     { fd = -1; return; }
271
272     __xdrs__ = new XDR;
273     if (!readRoutine) readRoutine = RPCdefaultXDRRead;
274     if (!writeRoutine) writeRoutine = RPCdefaultXDRWrite;
275     (void) xdrrec_create(__xdrs__, 0, 0, (char *) fd, readRoutine,writeRoutine);
276     if (nblock)
277       fcntl (fd, F_SETFL, FNDELAY);
278
279 }
280
281 //
282 // prepare for RPC's to be done/received on the passed thread id.
283 //
284 THREADrpc::THREADrpc(int thread)
285 {
286     tid = thread;
287 }
288
289 //
290 // This should never be called, it should be replaced by a virtual function
291 //    from the derived class created by igen.
292 //
293 void RPCUser::verifyProtocolAndVersion()
294 {
295     abort();
296 }
297
298 //
299 // our version of string encoding that does malloc as needed.
300 //
301 bool_t xdr_String(XDR *xdrs, String *str)
302 {
303     int len;
304
305         // if XDR_FREE, str's memory is freed
306     switch (xdrs->x_op) {
307         case XDR_ENCODE:
308                 len = strlen(*str)+1;
309                 break;
310         case XDR_DECODE:
311                 *str = NULL;
312                 break;
313         case XDR_FREE:
314                 // xdr_free (xdr_string, str);
315                 if (*str)
316                   free (*str);
317                 *str = NULL;
318                 return (TRUE);
319                 // return(TRUE);
320                 // free the memory
321         default:
322                 assert(0);
323                 // this should never occur      
324     }
325     // should we have a better max length ???. 
326     // xdr_bytes(xdrs, str, &len, 65536*32768);
327     // return(TRUE);
328     return (xdr_string (xdrs, str, 65536));
329 }
330
331 int RPCprocessCreate(int *pid, char *hostName, char *userName,
332                      char *command, char **arg_list, int portFd)
333 {
334     int ret;
335     int sv[2];
336     int execlERROR;
337     char local[50];
338
339     if (gethostname(local, 49))
340         strcpy (local, " ");
341
342     if (!hostName || 
343         !strcmp(hostName, "") || 
344         !strcmp(hostName, "localhost") ||
345         !strcmp(hostName, local)) {
346         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
347         if (ret) return(ret);
348         execlERROR = 0;
349         *pid = vfork();
350         if (*pid == 0) {
351             close(sv[0]);
352             dup2(sv[1], 0);
353             if (!arg_list)
354               execl(command, command);
355             else
356               execv(command, arg_list);
357             execlERROR = errno;
358             _exit(-1);
359         } else if (*pid > 0 && !execlERROR) {
360             close(sv[1]);
361             return(sv[0]);
362         } else {
363             return(-1);
364         }
365     } else {
366         int total;
367         int fd[2];
368         char *ret;
369         FILE *pfp;
370         char **curr;
371         int shellPid;
372         char line[256];
373         char *paradyndCommand;
374
375         total = strlen(command) + 2;
376         for (curr = arg_list+1; *curr; curr++) {
377             total += strlen(*curr) + 2;
378         }
379         paradyndCommand = (char *) malloc(total+2);
380
381         sprintf(paradyndCommand, "%s ", command);
382         for (curr = arg_list+1; *curr; curr++) {
383             strcat(paradyndCommand, *curr);
384             strcat(paradyndCommand, " ");
385         }
386
387         // need to rsh to machine and setup io path.
388
389         if (pipe(fd)) {
390             perror("pipe");
391             return (-1);
392         }
393
394         shellPid = vfork();
395         if (shellPid == 0) {
396             /* child */
397             dup2(fd[1], 1);                         /* copy it onto stdout */
398             close(fd[0]);
399             close(fd[1]);
400             if (userName) {
401                 execlp(RSH_COMMAND, RSH_COMMAND, hostName, "-l", 
402                     userName, "-n", paradyndCommand, "-l0", NULL);
403             } else {
404                 execlp(RSH_COMMAND, RSH_COMMAND, hostName, "-n", 
405                     paradyndCommand, "-l0", NULL);
406             }
407             _exit(-1);
408         } else if (shellPid > 0) {
409             close(fd[1]);
410         } else {
411             // error situation
412         }
413
414         pfp = fdopen(fd[0], "r");
415         do {
416             ret = fgets(line, sizeof(line)-1, pfp);
417             if (ret && !strncmp(line, "PARADYND", strlen("PARADYND"))) {
418                 // got the good stuff
419                 sscanf(line, "PARADYND %d", pid);
420
421                 // dump rsh process
422                 kill(shellPid, SIGTERM);
423                 while (wait(NULL) != shellPid);
424
425                 return(RPC_getConnect(portFd));
426             } else if (ret) {
427                 // some sort of error message from rsh.
428                 printf("%s", line);
429             }
430         }  while (ret);
431
432         return(-1);
433     }
434 }
435
436 //
437 // wait for an expected RPC responce, but also handle upcalls while waiting.
438 //    Should not be called directly !!!
439 //
440 void RPCUser::awaitResponce(int tag)
441 {
442     abort();
443 }
444
445 void
446 XDRrpc::setNonBlock()
447 {
448   if (fd >= 0)
449     fcntl (fd, F_SETFL, FNDELAY);
450 }
451
452 int
453 XDRrpc::readReady(int timeout)
454 {
455   return RPC_readReady (fd, timeout);
456 }
457
458 int
459 RPC_getConnect(int fd)
460 {
461   int clilen;
462   struct in_addr cli_addr;
463   int new_fd;
464
465   if (fd == -1)
466     return -1;
467
468   clilen = sizeof(cli_addr);
469
470   if ((new_fd = accept (fd, (struct sockaddr *) &cli_addr, &clilen)) < 0)
471     return -1;
472   else
473     return new_fd;
474 }
475