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