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