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