fixed some memory-related bug
[dyninst.git] / common / src / rpcUtil.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /*
43  * $Log: rpcUtil.C,v $
44  * Revision 1.53  1997/05/30 16:29:26  hseom
45  * fixed some memory-related bug
46  *
47  * Revision 1.52  1997/05/23 22:59:18  mjrg
48  * Windows NT port
49  *
50  * Revision 1.51  1997/05/20 15:18:57  lzheng
51  * Changes made to handle the comminication between different types of
52  * machines
53  *
54  * Revision 1.50  1997/05/17 20:01:30  lzheng
55  * Changes made for nonblocking write
56  *
57  * Revision 1.49  1997/04/21 16:57:56  hseom
58  * added support for trace data (in a byte array)
59  *
60  * Revision 1.48  1997/02/26 23:49:54  mjrg
61  * First part of WindowsNT commit: changes for compiling with VisualC++;
62  * moved includes to platform header files
63  *
64  * Revision 1.47  1997/01/21 20:09:59  mjrg
65  * Added support for unix domain sockets.
66  * Added getHostName function
67  *
68  * Revision 1.46  1997/01/16 20:52:21  tamches
69  * removed RPC_undo_arg_list (to paradynd)
70  *
71  * Revision 1.45  1996/11/26 16:09:37  naim
72  * Fixing asserts - naim
73  *
74  * Revision 1.44  1996/11/12 17:50:16  mjrg
75  * Removed warnings, changes for compiling with Visual C++ and xlc
76  *
77  * Revision 1.43  1996/08/16 21:32:02  tamches
78  * updated copyright for release 1.1
79  *
80  * Revision 1.42  1996/05/31 23:43:10  tamches
81  * removed pid from XDRrpc.  Modified handleRemoteConnect appropriately.
82  * Now paradynd doesn't try to send pid to paradyn (it wasn't being used
83  * and was one cause of paradyn UI freezing on UI startup).
84  *
85  * Revision 1.41  1995/11/22 00:06:20  mjrg
86  * Updates for paradyndPVM on solaris
87  * Fixed problem with wrong daemon getting connection to paradyn
88  * Removed -f and -t arguments to paradyn
89  * Added cleanUpAndExit to clean up and exit from pvm before we exit paradynd
90  * Fixed bug in my previous commit
91  *
92  * Revision 1.40  1995/11/12 00:44:28  newhall
93  * fix to execCmd: forked process closes it's copy of parent's file descriptors
94  *
95  * Revision 1.39  1995/08/24  15:14:29  hollings
96  * AIX/SP-2 port (including option for split instruction/data heaps)
97  * Tracing of rexec (correctly spawns a paradynd if needed)
98  * Added rtinst function to read getrusage stats (can now be used in metrics)
99  * Critical Path
100  * Improved Error reporting in MDL sematic checks
101  * Fixed MDL Function call statement
102  * Fixed bugs in TK usage (strings passed where UID expected)
103  *
104  * Revision 1.38  1995/05/18  11:12:15  markc
105  * Added flavor arg to RPC_undo_g_list
106  *
107 */
108
109 //
110 // This file defines a set of utility routines for RPC services.
111 //
112 //
113
114 // overcome malloc redefinition due to /usr/include/rpc/types.h declaring 
115 // malloc 
116 // This is ugly, and I hope to get rid of it -- mdc 2/2/95
117 #if defined(notdef)
118 /* prevents malloc from being redefined */
119 #ifdef MIPS
120 #define MALLOC_DEFINED_AS_VOID
121 #endif
122 #endif
123
124 #include <limits.h>
125 #include "util/h/rpcUtil.h"
126
127 const char *RSH_COMMAND="rsh";
128
129 int RPCdefaultXDRRead(const void* handle, char *buf, const u_int len)
130 {
131     int fd = (int) handle;
132     int ret;
133
134 #if defined(i386_unknown_nt4_0)
135     ret = recv(fd, buf, len, 0);
136 #else
137     do {
138         ret = P_read(fd, buf, len);
139     } while (ret < 0 && errno == EINTR);
140 #endif
141
142     if (ret <= 0) { return(-1); }
143     return (ret);
144 }
145
146 // one counter per file descriptor to record the sequnce no the message
147 // to be received
148 vector<int> counter_2;
149
150 // One partial message record for each file descriptor
151 vector<rpcBuffer *> partialMsgs;
152
153 int RPCasyncXDRRead(const void* handle, char *buf, const u_int len)
154 {
155     /* called when paradyn/xdr detects that it needs to read a message
156        from paradynd. */
157     int fd = (int) handle;
158     unsigned header;
159     int ret;
160     int needCopy = 0;
161     char *buffer = buf;
162     u_int internal_len = 0;
163     bool newfd = true;
164     unsigned i;
165
166     for (i = 0; i< partialMsgs.size(); i++) {
167         if (partialMsgs[i] -> fd == fd) {
168             newfd = false;
169             break;
170         }
171     }
172     
173     // If new connection, allocate a partial message record
174     if (newfd) {
175         rpcBuffer *partial = new rpcBuffer;
176         partial -> fd  = fd;
177         partial -> len = 0;
178         partial -> buf = NULL;
179         partialMsgs += partial;
180         i = partialMsgs.size() - 1;
181         
182         counter_2 += 0;
183     }
184
185     // There're two situations dealt with here: with partial message
186     // left by previous read, without. The 'len' field is zero if it is
187     // the first case, nonzero if it is the second case    
188     if (partialMsgs[i] -> len) needCopy = 1;
189
190     // Allocate buffer which is four more bytes than RPC buffer for the
191     // convenience of processing message headers.
192     buffer = new char[len + sizeof(int)];
193
194     if (needCopy) {
195         P_memcpy(buffer, partialMsgs[i]->buf , partialMsgs[i]->len); 
196         delete [] partialMsgs[i]->buf;
197         partialMsgs[i]->buf = NULL;
198     }
199
200 #if defined(i386_unknown_nt4_0)
201     ret = recv(fd, buffer+partialMsgs[i]->len,
202                len + sizeof(int) - partialMsgs[i]->len, 0);
203 #else
204     do {
205         ret = P_read(fd, buffer+partialMsgs[i]->len, 
206                      len + sizeof(int) -partialMsgs[i]->len);
207     } while (ret < 0 && errno == EINTR);
208 #endif
209
210     if (ret <= 0) { return(-1); }
211
212     ret += partialMsgs[i]->len;
213
214     char *pstart = buffer;
215     
216     // Processing the messages received: remove those message headers;
217     // check on deliminator and sequence no to ensure the correctness;
218     // save the partial message if any
219     char *tail = buffer;
220     int is_left = ret - sizeof(int);
221     while (is_left >= 0) {
222         P_memcpy((char *)&header, buffer, sizeof(int));
223 //printf(">> header=%x, header1=%x, len=%x\n", header, ntohl(header));
224         header = ntohl(header);
225         assert(0xf == ((header >> 12)&0xf));
226
227         short seq_no;
228         P_memcpy((char *)&(seq_no), buffer, sizeof(short));
229         seq_no = ntohs(seq_no);
230         header = (0x0fff&header);
231         
232         if (header <= is_left) {
233             P_memcpy(tail, buffer+sizeof(int), header);
234
235             counter_2[i] = ((counter_2[i]+1)%SHRT_MAX);
236             assert(seq_no == counter_2[i]);
237
238             internal_len += header;
239             if (internal_len > len) {
240                 abort();
241                 ret = ret - sizeof(int) - is_left;
242                 break;
243             }
244             tail += header;
245             buffer += header + sizeof(int);
246
247             is_left = is_left - header - sizeof(int);
248             ret -= sizeof(int);
249         } else {
250             ret = ret - sizeof(int) - is_left;
251             break;
252         }
253     }
254
255
256
257     if (is_left >= 0) {
258         
259         partialMsgs[i]->len = is_left + sizeof(int);
260         partialMsgs[i]->buf = new char[partialMsgs[i]->len+1];
261         P_memcpy(partialMsgs[i]->buf, buffer, partialMsgs[i]->len); 
262     } else {
263         partialMsgs[i]->len = 0;
264         assert(is_left == (0-(int)sizeof(int)));
265     }
266
267     // Copy back to internal RPC buffer
268     P_memcpy(buf, pstart, ret);
269
270     if (needCopy) {
271         buffer = pstart;
272         assert(buffer != buf); // make sure we aren't deleting the 2d param
273         delete [] buffer;
274     }
275     
276     return (ret);
277 }
278
279 int RPCdefaultXDRWrite(const void* handle, const char *buf, const u_int len)
280 {
281     int fd = (int) handle;
282     int ret;
283
284 #if defined(i386_unknown_nt4_0)
285     ret = send(fd, buf, len, 0);
286 #else
287     do {
288
289         ret = P_write(fd, buf, len);
290     } while (ret < 0 && errno == EINTR);
291 #endif
292
293     errno = 0;
294     if (ret != (int)len)
295       return(-1);
296     else 
297       return (ret);
298 }
299
300 vector<rpcBuffer *> rpcBuffers;
301 static short counter = 0;
302
303 int RPCasyncXDRWrite(const void* handle, const char *buf, const u_int len)
304 {
305     int ret;
306     int index = 0;
307     unsigned header = len;
308
309     rpcBuffer *rb = new rpcBuffer;
310     rb -> fd = (int) handle;
311     rb -> len = len+sizeof(int);
312     rb -> buf = new char[rb -> len];
313
314     counter = ((counter+1)%SHRT_MAX);
315
316     assert(len <= 4040);
317
318     // Adding a header to the messages sent   
319     header = ((counter << 16) | header | 0xf000); 
320
321     // Converting to network order
322     header = htonl(header);
323 //printf(">> header=%x, counter=%x, len=%x\n", header, counter, len);
324     
325     P_memcpy(rb -> buf, (char *)&header, sizeof(int));
326     P_memcpy(rb -> buf+sizeof(int), buf, len);
327
328     rpcBuffers += rb;
329
330     // Write the items to the other end if possible with asynchrous write
331     for (int i = 0; (i < (int)rpcBuffers.size()); i++) {
332
333 #if defined(i386_unknown_nt4_0)
334         u_long ioctlsock_arg = 1; // set non-blocking
335         if (ioctlsocket(rpcBuffers[i]->fd, FIONBIO, &ioctlsock_arg) == -1)
336             perror("ioctlsocket");
337
338         ret = (int) send(rpcBuffers[i]->fd, rpcBuffers[i]->buf, 
339                          rpcBuffers[i]->len, 0);
340
341         ioctlsock_arg = 0; // set blocking
342         if (ioctlsocket(rpcBuffers[i]->fd, FIONBIO, &ioctlsock_arg) == -1)
343             perror("ioctlsocket");
344 #else
345         if (P_fcntl (rpcBuffers[i]->fd, F_SETFL, FNONBLOCK) == -1)
346             perror("fcntl");
347
348         ret = (int)P_write(rpcBuffers[i]->fd, rpcBuffers[i]->buf,
349                            rpcBuffers[i]->len);
350
351         if (P_fcntl (rpcBuffers[i]->fd, F_SETFL, FSYNC) == -1)
352             perror("fcntl");
353 #endif
354
355         if (rpcBuffers[i]->len != ret) {
356
357             if (ret != -1) {
358                 assert(ret < rpcBuffers[i]->len);
359                 printf("Warning: a partial message sent!\n");
360                 P_memcpy(rpcBuffers[i]->buf, rpcBuffers[i]->buf+ret,
361                          rpcBuffers[i]->len-ret);
362                 rpcBuffers[i]->len -= ret;
363             }
364             break;
365         }
366         index++;
367         
368     }
369     
370     // Delete the items sent out
371     unsigned j;
372     for (j = 0; j < (unsigned)index; j++) {
373         delete [] rpcBuffers[j]->buf;
374     }    
375     
376     for (j = 0; j < rpcBuffers.size() - index; j++)
377         rpcBuffers[j] = rpcBuffers[j+index];
378     rpcBuffers.resize(rpcBuffers.size() - index);
379
380     return (ret = (int)len);
381 }
382
383 void
384 doDeferedRPCasyncXDRWrite() {
385
386     if (rpcBuffers.size() == 0)
387         return;
388
389     int ret, index = 0;
390
391     // Write the items to the other end if possible 
392     for (int i = 0; (i < (int)rpcBuffers.size()); i++) {
393
394 #if defined (i386_unknown_nt4_0)
395         u_long ioctlsock_arg = 1; // set non-blocking
396         if (ioctlsocket(rpcBuffers[i]->fd, FIONBIO, &ioctlsock_arg) == -1)
397             perror("ioctlsocket");
398
399         ret = (int) send(rpcBuffers[i]->fd, rpcBuffers[i]->buf,
400                          rpcBuffers[i]->len, 0);
401
402         ioctlsock_arg = 0; // set blocking
403         if (ioctlsocket(rpcBuffers[i]->fd, FIONBIO, &ioctlsock_arg) == -1)
404             perror("ioctlsocket");
405 #else
406         if (P_fcntl (rpcBuffers[i]->fd, F_SETFL, FNONBLOCK) == -1)
407             perror("fcntl");
408
409         ret = (int)P_write(rpcBuffers[i]->fd, rpcBuffers[i]->buf,
410                            rpcBuffers[i]->len);
411
412         if (P_fcntl (rpcBuffers[i]->fd, F_SETFL, FSYNC) == -1)
413             perror("fcntl");
414 #endif
415         
416         if (rpcBuffers[i]->len != ret) {
417
418             if (ret != -1) {
419                 assert(ret < rpcBuffers[i]->len);
420                 printf("Warning: a partial message sent!\n");
421                 P_memcpy(rpcBuffers[i]->buf, rpcBuffers[i]->buf+ret,
422                          rpcBuffers[i]->len-ret);
423                 rpcBuffers[i]->len -= ret;
424             }
425             break;
426         }
427         index++;
428
429     }
430     
431     // Delete the items sent out
432     unsigned j;
433     for (j = 0; j < (unsigned)index; j++) {
434         delete [] rpcBuffers[j]->buf;
435     }    
436
437     for (j = 0; j < rpcBuffers.size() - index; j++)
438         rpcBuffers[j] = rpcBuffers[j+index];
439     rpcBuffers.resize(rpcBuffers.size() - index);
440 }
441
442 XDRrpc::~XDRrpc()
443 {
444   if (fd >= 0)
445     {
446 #if !defined(i386_unknown_nt4_0)
447       P_fcntl (fd, F_SETFL, FNDELAY);
448 #endif
449       P_close(fd);
450       fd = -1;
451     }
452   if (xdrs) 
453     {
454       P_xdr_destroy (xdrs);
455       delete (xdrs);
456       xdrs = NULL;
457     }
458 }
459
460 //
461 // prepare for RPC's to be done/received on the passed fd.
462 //
463 XDRrpc::XDRrpc(const int f, xdr_rd_func readRoutine, xdr_wr_func writeRoutine, const int nblock)
464 : xdrs(NULL), fd(f)
465 {
466     assert(fd >= 0);
467     xdrs = new XDR;
468     assert(xdrs);
469     if (!readRoutine) {
470         if (nblock == 1) {
471             readRoutine = (xdr_rd_func) RPCasyncXDRRead;
472         } else { 
473             readRoutine = (xdr_rd_func) RPCdefaultXDRRead;
474         }
475     }   
476     if (!writeRoutine) {
477         if (nblock == 2) {
478             writeRoutine = (xdr_wr_func)RPCasyncXDRWrite;
479         } else {    
480             writeRoutine = (xdr_wr_func) RPCdefaultXDRWrite;
481         }
482     }   
483     P_xdrrec_create(xdrs, 0, 0, (char *) fd, readRoutine, writeRoutine);
484 }
485
486 //
487 // prepare for RPC's to be done/received on the passed fd.
488 //
489 XDRrpc::XDRrpc(const string &machine,
490                const string &user,
491                const string &program,
492                xdr_rd_func readRoutine, 
493                xdr_wr_func writeRoutine,
494                const vector<string> &arg_list,
495                const int nblock,
496                const int wellKnownPortFd)
497 : xdrs(NULL), fd(-1)
498 {
499     fd = RPCprocessCreate(machine, user, program, arg_list, wellKnownPortFd);
500     if (fd >= 0) {
501         xdrs = new XDR;
502         if (!readRoutine) {
503             if (nblock == 1) {
504                 readRoutine = (xdr_rd_func) RPCasyncXDRRead;
505             } else { 
506                 readRoutine = (xdr_rd_func) RPCdefaultXDRRead;
507             }
508         }
509         if (!writeRoutine) {
510             if (nblock == 2) {
511                 writeRoutine = (xdr_wr_func)RPCasyncXDRWrite;
512             } else { 
513                 writeRoutine = (xdr_wr_func) RPCdefaultXDRWrite;
514             }
515         }
516         P_xdrrec_create(xdrs, 0, 0, (char *) fd, readRoutine, writeRoutine);
517     }
518 }
519
520 bool
521 RPC_readReady (int fd, int timeout)
522 {
523   fd_set readfds;
524   struct timeval tvptr, *the_tv;
525
526   tvptr.tv_sec = timeout; tvptr.tv_usec = 0;
527   if (fd < 0) return false;
528   FD_ZERO(&readfds);
529   FD_SET (fd, &readfds);
530
531   // -1 timeout = blocking select
532   if (timeout == -1)
533      the_tv = 0;
534   else
535      the_tv = &tvptr;
536  
537   if (P_select (fd+1, &readfds, NULL, NULL, the_tv) == -1)
538     {
539       // if (errno == EBADF)
540         return false;
541     }
542   return (FD_ISSET (fd, &readfds));
543 }
544
545 /*
546  * Build an argument list starting at position 0.
547  * Note, this arg list will be used in an exec system call
548  * AND, the command name will have to be inserted at the head of the list
549  * But, a NULL space will NOT be left at the head of the list
550  */
551 bool RPC_make_arg_list(vector<string> &list,
552                        const int well_known_socket, const int flag, const int firstPVM,
553                        const string machine_name, const bool use_machine)
554 {
555   char arg_str[100];
556
557   list.resize(0);
558
559   sprintf(arg_str, "%s%d", "-p", well_known_socket);  
560   list += arg_str;
561   // arg_list[arg_count++] = strdup (arg_str);  // 0
562
563   if (!use_machine) {
564     list += string("-m") + getHostName();
565   } else {
566     list += string("-m") + machine_name;
567   }
568   // arg_list[arg_count++] = strdup (arg_str); // 3
569
570   sprintf(arg_str, "%s%d", "-l", flag);
571   list += arg_str;
572   //arg_list[arg_count++] = strdup (arg_str);  // 4
573
574   sprintf(arg_str, "%s%d", "-v", firstPVM);
575   list += arg_str;
576   // arg_list[arg_count++] = strdup (arg_str);  // 5 
577
578   return true;
579 }
580
581 // returns fd of socket that is listened on, or -1
582 // (actually, looks like it returns the port number listened on, or -1)
583 int
584 RPC_setup_socket (int &sfd,   // return file descriptor
585                   const int family, // AF_INET ...
586                   const int type)   // SOCK_STREAM ...
587 {
588   if ((sfd = P_socket(family, type, 0)) < 0)
589     return -1;
590
591   struct sockaddr_in serv_addr;
592   P_memset ((void*) &serv_addr, 0, sizeof(serv_addr));
593   serv_addr.sin_family = (short) family;
594   serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
595   serv_addr.sin_port = htons(0);
596   
597   size_t length = sizeof(serv_addr);
598
599   if (P_bind(sfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
600     return -1;
601
602   if (P_getsockname (sfd, (struct sockaddr *) &serv_addr, &length) < 0)
603     return -1;
604
605   if (P_listen(sfd, 5) < 0)
606     return -1;
607
608   return (ntohs (serv_addr.sin_port));
609 }
610
611 // setup a AF_UNIX domain socket of type SOCK_STREAM
612 bool
613 RPC_setup_socket_un (int &sfd,   // return file descriptor
614                      const char *path) // file path socket is bound to
615 {
616 #if defined(i386_unknown_nt4_0)
617   assert(0); // no unix domain sockets on Windows NT
618 #else
619   struct sockaddr_un saddr;
620
621   if ((sfd = P_socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
622     return false;
623
624   saddr.sun_family = AF_UNIX;
625   P_strcpy(saddr.sun_path, path);
626   
627   if (P_bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
628     return false;
629
630   if (P_listen(sfd, 5) < 0)
631     return false;
632 #endif
633
634   return true;
635 }
636
637 //
638 // connect to well known socket
639 //
640 XDRrpc::XDRrpc(int family,            
641                int req_port,             
642                int type,
643                const string machine, 
644                xdr_rd_func readRoutine,
645                xdr_wr_func writeRoutine,
646                const int nblock) : xdrs(NULL), fd(-1)
647      // socket, connect using machine
648 {
649   struct sockaddr_in serv_addr;
650   struct hostent *hostptr = 0;
651   struct in_addr *inadr = 0;
652   if (!(hostptr = P_gethostbyname(machine.string_of())))
653     return;
654
655   inadr = (struct in_addr *) ((void*) hostptr->h_addr_list[0]);
656   P_memset ((void*) &serv_addr, 0, sizeof(serv_addr));
657   serv_addr.sin_family = family;
658   serv_addr.sin_addr = *inadr;
659   serv_addr.sin_port = htons(req_port);
660
661   if ( (fd = P_socket(family, type, 0)) < 0)
662     { fd = -1; return; }
663
664   if (P_connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
665     { fd = -1; return; }
666
667     xdrs = new XDR;
668     assert(xdrs);
669     if (!readRoutine) {
670         if (nblock == 1) {
671             readRoutine = (xdr_rd_func) RPCasyncXDRRead;
672         } else {  
673             readRoutine = (xdr_rd_func) RPCdefaultXDRRead;
674         }
675         }
676     if (!writeRoutine) {
677         if (nblock == 2) {
678             writeRoutine = (xdr_wr_func)RPCasyncXDRWrite;
679         } else { 
680             writeRoutine = (xdr_wr_func) RPCdefaultXDRWrite;
681         }
682     }
683     P_xdrrec_create(xdrs, 0, 0, (char *) fd, readRoutine,writeRoutine);
684
685
686 //
687 // These xdr functions are not to be called with XDR_FREE
688 //
689 bool_t xdr_Boolean(XDR *xdrs, bool *bool_val) {
690    u_char i;
691    bool_t res;
692    switch (xdrs->x_op) {
693    case XDR_ENCODE:
694       i = (u_char) *bool_val;
695       return (P_xdr_u_char(xdrs, &i));
696    case XDR_DECODE:
697       res = P_xdr_u_char(xdrs, &i);
698       *bool_val = (bool) i;
699       return res;
700    case XDR_FREE:
701    default:
702       assert(0);
703       return FALSE;
704    }
705 }
706
707 // XDR_FREE not handled, free it yourself!
708 // our version of string encoding that does malloc as needed.
709 //
710 bool_t xdr_string_pd(XDR *xdrs, string *str)
711 {
712   unsigned int length = 0;
713   assert(str);
714
715   // if XDR_FREE, str's memory is freed
716   switch (xdrs->x_op) {
717   case XDR_ENCODE:
718     if ((length = str->length())) {
719       if (!P_xdr_u_int(xdrs, &length))
720         return FALSE;
721       else {
722         char *buffer = (char*) str->string_of(); 
723         bool_t res = P_xdr_string (xdrs, &buffer, str->length() + 1);
724         return res;
725       }
726     } else {
727       return (P_xdr_u_int(xdrs, &length));
728     }
729   case XDR_DECODE:
730     if (!P_xdr_u_int(xdrs, &length))
731       return FALSE;
732      else if (!length) {
733        *str = (char*) NULL;
734        return TRUE;
735      } else {
736        char *temp; 
737        bool newd = false;
738        unsigned max_len = 511;
739        char stat_buf[512];
740        if (length < 512) 
741           temp = (char*) stat_buf;
742        else {
743           temp = new char[length+1];
744           max_len = length;
745           newd = true;
746        }      
747        if (!P_xdr_string (xdrs, &temp, max_len)) {
748           if (newd) 
749             delete temp;
750           return FALSE;
751        } else {
752           *str = temp;
753           if (newd)
754             delete temp; 
755           return TRUE;
756        }
757      }
758   case XDR_FREE:
759   default:
760     // this should never occur  
761     assert(0);
762     return (FALSE);
763   }
764 }
765
766 // trace data streams
767 // XDR_FREE not handled, free it yourself!
768 // our version of string encoding that does malloc as needed.
769 //
770
771 bool_t xdr_byteArray_pd(XDR *xdrs, byteArray *bArray)
772 {
773   unsigned int length = 0;
774   assert(bArray);
775
776   // if XDR_FREE, str's memory is freed
777   switch (xdrs->x_op) {
778   case XDR_ENCODE:
779     if (length = bArray->length()) {
780       if (!P_xdr_u_int(xdrs, &length))
781         return FALSE;
782       else {
783         char *buffer = (char*) bArray->getArray();
784         bool_t res = P_xdr_byteArray (xdrs, &buffer, &length, (bArray->length()));
785         return res;
786       }
787     } else {
788       return (P_xdr_u_int(xdrs, &length));
789     }
790   case XDR_DECODE:
791     if (!P_xdr_u_int(xdrs, &length))
792       return FALSE;
793      else if (!length) {
794        *bArray = byteArray( (char *)NULL , 0);
795        return TRUE;
796      } else {
797        char *temp;
798        unsigned int act_len;
799        unsigned int max_len = length;
800        temp = new char[length];
801        if (!P_xdr_byteArray (xdrs, &temp, &act_len, max_len)) {
802           delete [] temp;
803           return FALSE;
804        } else if (act_len != length) {
805           delete [] temp;
806           return FALSE;
807        } else {
808           *bArray = byteArray(temp,act_len);
809           delete [] temp;
810           return TRUE;
811        }
812      }
813   case XDR_FREE:
814   default:
815     // this should never occur
816     assert(0);
817     return (FALSE);
818   }
819 }
820
821 //
822 // directly exec the command (local).
823 //
824
825 int execCmd(const string command, const vector<string> &arg_list, int /*portFd*/)
826 {
827 #if defined(i386_unknown_nt4_0)
828   // TODO
829   assert(0);
830   return 0;
831 #else
832   int ret;
833   int sv[2];
834   int execlERROR;
835
836   errno = 0;
837   ret = P_socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
838   if (ret==-1) return(ret);
839   execlERROR = 0;
840   int al_len = arg_list.size();
841   char **new_al = new char*[al_len+2];
842   // TODO argv[0] should not include path
843   new_al[0] = P_strdup(command.string_of());
844   new_al[al_len+1] = NULL;
845   for (int i=0; i<al_len; ++i)
846     new_al[i+1] = P_strdup(arg_list[i].string_of());
847   ret = -1;
848
849   int pid;
850   pid = vfork();
851   // close sv[0] after exec 
852   P_fcntl(sv[0],F_SETFD,1);  
853
854   if (pid == 0) {
855     if (P_close(sv[0])) { execlERROR = errno; _exit(-1);}
856     if (P_dup2(sv[1], 0)) { execlERROR = errno; _exit(-1);}
857     P_execvp(new_al[0], new_al);
858     execlERROR = errno;
859     _exit(-1);
860   } else if (pid > 0 && !execlERROR) {
861     P_close(sv[1]);
862     ret = sv[0];
863   }
864
865   al_len=0;
866   while (new_al[al_len]) {
867     delete (new_al[al_len]);
868     al_len++;
869   }
870   delete(new_al);
871   return ret;
872 #endif
873 }
874
875 int handleRemoteConnect(int fd, int portFd) {
876     // NOTE: This routine is not generic; it is very specific to paradyn
877     // (due to the sscanf(line, "PARADYND %d")...)
878     // Hence it makes absolutely no sense to put it in a so-called library.
879     // It should be put into the paradyn/src tree --ari
880
881     FILE *pfp = P_fdopen(fd, "r");
882     if (pfp == NULL) {
883        cerr << "handleRemoteConnect: fdopen of fd " << fd << " failed." << endl;
884        return -1;
885     }
886
887     int retFd = RPC_getConnect(portFd); // calls accept(), which blocks (sigh...)
888     return retFd;
889 }
890
891 //
892 // use rsh to get a remote process started.
893 //
894 // We do an rsh to start a process and them wait for the process 
895 // to do a connect. There is no guarantee that the process we are waiting for is
896 // the one that gets the connection. This can happen with paradyndPVM: the
897 // daemon that is started by a rshCommand will start other daemons, and one of 
898 // these daemons may get the connection that should be for the first daemon.
899 // Daemons should always get a connection before attempting to start other daemons.
900 //
901
902 int rshCommand(const string hostName, const string userName, 
903                const string command, const vector<string> &arg_list, int portFd)
904 {
905 #if defined(i386_unknown_nt4_0)
906     // TODO
907     assert(0);
908     return 0;
909 #else
910     int fd[2];
911     int shellPid;
912     int ret;
913
914     int total = command.length() + 2;
915     for (unsigned i=0; i<arg_list.size(); i++) {
916       total += arg_list[i].length() + 2;
917     }
918
919     string paradyndCommand = command + " ";
920
921     for (unsigned j=0; j < arg_list.size(); j++)
922         paradyndCommand += arg_list[j] + " ";
923
924     // need to rsh to machine and setup io path.
925
926     if (pipe(fd)) {
927         perror("pipe");
928         return (-1);
929     }
930
931     shellPid = vfork();
932     if (shellPid == 0) {
933         /* child */
934         bool aflag;
935         aflag=(-1 != dup2(fd[1], 1)); /* copy it onto stdout */
936         assert(aflag);
937         aflag=(-1 != close(fd[0]));
938         assert(aflag);
939         aflag=(-1 != close(fd[1]));
940         assert(aflag);
941         if (userName.length()) {
942             ret = execlp(RSH_COMMAND, RSH_COMMAND, hostName.string_of(), "-l", 
943                          userName.string_of(), "-n", paradyndCommand.string_of(),
944                          "-l0", NULL);
945             fprintf(stderr,"rshCommand: execlp failed (ret = %d)\n",ret);
946         } else {
947             ret = execlp(RSH_COMMAND, RSH_COMMAND, hostName.string_of(), "-n", 
948                          paradyndCommand.string_of(), "-l0", NULL);
949             fprintf(stderr,"rshCommand: execlp failed (ret = %d)\n",ret);
950         }
951         _exit(-1);
952     } else if (shellPid > 0) {
953         close(fd[1]);
954     } else {
955         // error situation
956     }
957
958     return(handleRemoteConnect(fd[0], portFd));
959 #endif
960 }
961
962 int rexecCommand(const string hostName, const string userName, 
963                  const string command, const vector<string> &arg_list, int portFd)
964 {
965 #if defined(i386_unknown_nt4_0)
966     // TODO
967     assert(0);
968     return 0;
969 #else
970     struct servent *inport;
971
972     int total = command.length() + 2;
973     for (unsigned i=0; i<arg_list.size(); i++) {
974       total += arg_list[i].length() + 2;
975     }
976
977     char *paradyndCommand = new char[total+2];
978     assert(paradyndCommand);
979
980     sprintf(paradyndCommand, "%s ", command.string_of());
981     for (unsigned j=0; j<arg_list.size(); j++) {
982         P_strcat(paradyndCommand, arg_list[j].string_of());
983         P_strcat(paradyndCommand, " ");
984     }
985
986     inport = P_getservbyname("exec",  "tcp");
987
988     char *hname = P_strdup(hostName.string_of());
989     char *uname = P_strdup(userName.string_of());
990     int fd = P_rexec(&hname, inport->s_port, uname, NULL,
991                    paradyndCommand, NULL);
992     delete hname; delete uname;
993
994     if (fd < 0) {
995         perror("rexec");
996         printf("rexec failed\n");
997     }
998     if (paradyndCommand)
999       delete paradyndCommand;
1000
1001     return(handleRemoteConnect(fd, portFd));
1002 #endif
1003 }
1004
1005 /*
1006  * 
1007  * "command" will be appended to the front of the arg list
1008  *
1009  * if arg_list == NULL, command is the only argument used
1010  */
1011
1012 int RPCprocessCreate(const string hostName, const string userName,
1013                      const string command, const vector<string> &arg_list,
1014                      int portFd, const bool useRexec)
1015 {
1016     int ret;
1017
1018     if ((hostName == "") || 
1019         (hostName == "localhost") ||
1020         (hostName == getHostName()))
1021       ret = execCmd(command, arg_list, portFd);
1022     else if (useRexec)
1023       ret = rexecCommand(hostName, userName, command, arg_list, portFd);
1024     else
1025       ret = rshCommand(hostName, userName, command, arg_list, portFd);
1026
1027     return(ret);
1028 }
1029
1030 int RPC_getConnect(const int fd) {
1031   if (fd == -1)
1032     return -1;
1033
1034   struct sockaddr cli_addr;
1035   size_t clilen = sizeof(cli_addr);
1036   int new_fd = P_accept (fd, (struct sockaddr *) &cli_addr, &clilen);
1037
1038   if (new_fd < 0)
1039     return -1;
1040   else
1041     return new_fd;
1042 }
1043
1044 // TODO -- use vectors and strings ?
1045 /*
1046  *  RPCgetArg - break a string into blank separated words
1047  *  Used to parse a command line.
1048  *  
1049  *  input --> a null terminated string, the command line
1050  *  argc --> returns the number of args found
1051  *  returns --> words (separated by blanks on command line)
1052  *  Note --> this allocates memory 
1053  */
1054 bool RPCgetArg(vector<string> &arg, const char *input)
1055 {
1056 #define BLANK ' '
1057
1058   int word_len;
1059   if (!input) 
1060     return false;
1061
1062   int length = strlen(input);
1063   int index = 0;
1064
1065   /* advance past blanks in input */
1066   while ((index < length) && (input[index] == BLANK))
1067     index++;
1068
1069   /* input is all blanks, or NULL */
1070   if (index >= length) 
1071     return true;
1072
1073   do {
1074     /* the start of each string */
1075     word_len = 0; const char *word_start = input + index;
1076
1077     /* find the next BLANK and the WORD size */
1078     while ((index < length) && (input[index] != BLANK)) {
1079       index++; word_len++;
1080     }
1081
1082     /* copy the word */
1083     char *temp = new char[word_len+1];
1084     strncpy(temp, word_start, word_len);
1085     temp[word_len] = (char) 0;
1086     arg += temp;
1087     delete temp;
1088
1089     /* skip past consecutive blanks */
1090     while ((index < length) && (input[index] == BLANK))
1091       index++;
1092   } while (index < length);
1093   return true;
1094 }
1095
1096
1097 string getHostName() {
1098 #if defined(i386_unknown_nt4_0)
1099     char nameBuf[1000];
1100     gethostname(nameBuf,999);
1101     return string(nameBuf);
1102 #else
1103     struct utsname un;
1104     P_uname(&un);
1105     return string(un.nodename);
1106 #endif
1107 }