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